Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2005 by the Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * Contributor(s): Daniel Dunbar 00022 * Ton Roosendaal, 00023 * Ben Batt, 00024 * Brecht Van Lommel, 00025 * Campbell Barton 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 * 00029 */ 00030 00036 #include <stddef.h> 00037 #include <zlib.h> 00038 00039 #include "DNA_object_types.h" 00040 #include "DNA_scene_types.h" 00041 #include "DNA_mesh_types.h" 00042 #include "DNA_meshdata_types.h" 00043 #include "DNA_object_types.h" 00044 #include "DNA_object_fluidsim.h" 00045 00046 #include "BLI_blenlib.h" 00047 #include "BLI_math.h" 00048 #include "BLI_utildefines.h" 00049 00050 #include "BKE_main.h" 00051 #include "BKE_fluidsim.h" /* ensure definitions here match */ 00052 #include "BKE_cdderivedmesh.h" 00053 #include "BKE_mesh.h" 00054 #include "BKE_utildefines.h" 00055 #include "BKE_global.h" /* G.main->name only */ 00056 00057 #include "MOD_fluidsim_util.h" 00058 #include "MOD_modifiertypes.h" 00059 00060 #include "MEM_guardedalloc.h" 00061 00062 // headers for fluidsim bobj meshes 00063 #include "LBM_fluidsim.h" 00064 00065 00066 void fluidsim_init(FluidsimModifierData *fluidmd) 00067 { 00068 #ifdef WITH_MOD_FLUID 00069 if(fluidmd) 00070 { 00071 FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings"); 00072 00073 fluidmd->fss = fss; 00074 00075 if(!fss) 00076 return; 00077 00078 fss->fmd = fluidmd; 00079 fss->type = OB_FLUIDSIM_ENABLE; 00080 fss->show_advancedoptions = 0; 00081 00082 fss->resolutionxyz = 65; 00083 fss->previewresxyz = 45; 00084 fss->realsize = 0.5; 00085 fss->guiDisplayMode = 2; // preview 00086 fss->renderDisplayMode = 3; // render 00087 00088 fss->viscosityMode = 2; // default to water 00089 fss->viscosityValue = 1.0; 00090 fss->viscosityExponent = 6; 00091 00092 fss->grav[0] = 0.0; 00093 fss->grav[1] = 0.0; 00094 fss->grav[2] = -9.81; 00095 00096 fss->animStart = 0.0; 00097 fss->animEnd = 4.0; 00098 fss->gstar = 0.005; // used as normgstar 00099 fss->maxRefine = -1; 00100 // maxRefine is set according to resolutionxyz during bake 00101 00102 // fluid/inflow settings 00103 // fss->iniVel --> automatically set to 0 00104 00105 modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), "cache_fluid"); 00106 00107 // first init of bounding box 00108 // no bounding box needed 00109 00110 // todo - reuse default init from elbeem! 00111 fss->typeFlags = OB_FSBND_PARTSLIP | OB_FSSG_NOOBS; 00112 fss->domainNovecgen = 0; 00113 fss->volumeInitType = 1; // volume 00114 fss->partSlipValue = 0.2; 00115 00116 fss->generateTracers = 0; 00117 fss->generateParticles = 0.0; 00118 fss->surfaceSmoothing = 1.0; 00119 fss->surfaceSubdivs = 0.0; 00120 fss->particleInfSize = 0.0; 00121 fss->particleInfAlpha = 0.0; 00122 00123 // init fluid control settings 00124 fss->attractforceStrength = 0.2; 00125 fss->attractforceRadius = 0.75; 00126 fss->velocityforceStrength = 0.2; 00127 fss->velocityforceRadius = 0.75; 00128 fss->cpsTimeStart = fss->animStart; 00129 fss->cpsTimeEnd = fss->animEnd; 00130 fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width 00131 00132 /* 00133 BAD TODO: this is done in buttons_object.c in the moment 00134 Mesh *mesh = ob->data; 00135 // calculate bounding box 00136 fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); 00137 */ 00138 00139 fss->meshVelocities = NULL; 00140 00141 fss->lastgoodframe = -1; 00142 00143 fss->flag |= OB_FLUIDSIM_ACTIVE; 00144 00145 } 00146 #else 00147 (void)fluidmd; /* unused */ 00148 #endif 00149 return; 00150 } 00151 00152 void fluidsim_free(FluidsimModifierData *fluidmd) 00153 { 00154 #ifdef WITH_MOD_FLUID 00155 if(fluidmd) 00156 { 00157 if(fluidmd->fss->meshVelocities) 00158 { 00159 MEM_freeN(fluidmd->fss->meshVelocities); 00160 fluidmd->fss->meshVelocities = NULL; 00161 } 00162 MEM_freeN(fluidmd->fss); 00163 } 00164 #else 00165 (void)fluidmd; /* unused */ 00166 #endif 00167 00168 return; 00169 } 00170 00171 #ifdef WITH_MOD_FLUID 00172 /* read .bobj.gz file into a fluidsimDerivedMesh struct */ 00173 static DerivedMesh *fluidsim_read_obj(const char *filename) 00174 { 00175 int wri = 0,i; 00176 int gotBytes; 00177 gzFile gzf; 00178 int numverts = 0, numfaces = 0; 00179 DerivedMesh *dm = NULL; 00180 MFace *mf; 00181 MVert *mv; 00182 short *normals, *no_s; 00183 float no[3]; 00184 00185 // ------------------------------------------------ 00186 // get numverts + numfaces first 00187 // ------------------------------------------------ 00188 gzf = gzopen(filename, "rb"); 00189 if (!gzf) 00190 { 00191 return NULL; 00192 } 00193 00194 // read numverts 00195 gotBytes = gzread(gzf, &wri, sizeof(wri)); 00196 numverts = wri; 00197 00198 // skip verts 00199 gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; 00200 00201 00202 // read number of normals 00203 if(gotBytes) 00204 gotBytes = gzread(gzf, &wri, sizeof(wri)); 00205 00206 // skip normals 00207 gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; 00208 00209 /* get no. of triangles */ 00210 if(gotBytes) 00211 gotBytes = gzread(gzf, &wri, sizeof(wri)); 00212 numfaces = wri; 00213 00214 gzclose( gzf ); 00215 // ------------------------------------------------ 00216 00217 if(!numfaces || !numverts || !gotBytes) 00218 return NULL; 00219 00220 gzf = gzopen(filename, "rb"); 00221 if (!gzf) 00222 { 00223 return NULL; 00224 } 00225 00226 dm = CDDM_new(numverts, 0, numfaces); 00227 00228 if(!dm) 00229 { 00230 gzclose( gzf ); 00231 return NULL; 00232 } 00233 00234 // read numverts 00235 gotBytes = gzread(gzf, &wri, sizeof(wri)); 00236 00237 // read vertex position from file 00238 mv = CDDM_get_verts(dm); 00239 00240 for(i=0; i<numverts; i++, mv++) 00241 gotBytes = gzread(gzf, mv->co, sizeof(float) * 3); 00242 00243 // should be the same as numverts 00244 gotBytes = gzread(gzf, &wri, sizeof(wri)); 00245 if(wri != numverts) 00246 { 00247 if(dm) 00248 dm->release(dm); 00249 gzclose( gzf ); 00250 return NULL; 00251 } 00252 00253 normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" ); 00254 if(!normals) 00255 { 00256 if(dm) 00257 dm->release(dm); 00258 gzclose( gzf ); 00259 return NULL; 00260 } 00261 00262 // read normals from file (but don't save them yet) 00263 for(i=numverts, no_s= normals; i>0; i--, no_s += 3) 00264 { 00265 gotBytes = gzread(gzf, no, sizeof(float) * 3); 00266 normal_float_to_short_v3(no_s, no); 00267 } 00268 00269 /* read no. of triangles */ 00270 gotBytes = gzread(gzf, &wri, sizeof(wri)); 00271 00272 if(wri!=numfaces) { 00273 printf("Fluidsim: error in reading data from file.\n"); 00274 if(dm) 00275 dm->release(dm); 00276 gzclose( gzf ); 00277 MEM_freeN(normals); 00278 return NULL; 00279 } 00280 00281 // read triangles from file 00282 mf = CDDM_get_faces(dm); 00283 for(i=numfaces; i>0; i--, mf++) 00284 { 00285 int face[3]; 00286 00287 gotBytes = gzread(gzf, face, sizeof(int) * 3); 00288 00289 // check if 3rd vertex has index 0 (not allowed in blender) 00290 if(face[2]) 00291 { 00292 mf->v1 = face[0]; 00293 mf->v2 = face[1]; 00294 mf->v3 = face[2]; 00295 } 00296 else 00297 { 00298 mf->v1 = face[1]; 00299 mf->v2 = face[2]; 00300 mf->v3 = face[0]; 00301 } 00302 mf->v4 = 0; 00303 00304 test_index_face(mf, NULL, 0, 3); 00305 } 00306 00307 gzclose( gzf ); 00308 00309 CDDM_calc_edges(dm); 00310 00311 CDDM_apply_vert_normals(dm, (short (*)[3])normals); 00312 MEM_freeN(normals); 00313 00314 // CDDM_calc_normals(result); 00315 00316 return dm; 00317 } 00318 00319 00320 void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4], 00321 /*RET*/ float start[3], /*RET*/ float size[3] ) 00322 { 00323 float bbsx=0.0, bbsy=0.0, bbsz=0.0; 00324 float bbex=1.0, bbey=1.0, bbez=1.0; 00325 int i; 00326 float vec[3]; 00327 00328 if(totvert == 0) { 00329 zero_v3(start); 00330 zero_v3(size); 00331 return; 00332 } 00333 00334 copy_v3_v3(vec, mvert[0].co); 00335 mul_m4_v3(obmat, vec); 00336 bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2]; 00337 bbex = vec[0]; bbey = vec[1]; bbez = vec[2]; 00338 00339 for(i = 1; i < totvert; i++) { 00340 copy_v3_v3(vec, mvert[i].co); 00341 mul_m4_v3(obmat, vec); 00342 00343 if(vec[0] < bbsx){ bbsx= vec[0]; } 00344 if(vec[1] < bbsy){ bbsy= vec[1]; } 00345 if(vec[2] < bbsz){ bbsz= vec[2]; } 00346 if(vec[0] > bbex){ bbex= vec[0]; } 00347 if(vec[1] > bbey){ bbey= vec[1]; } 00348 if(vec[2] > bbez){ bbez= vec[2]; } 00349 } 00350 00351 // return values... 00352 if(start) { 00353 start[0] = bbsx; 00354 start[1] = bbsy; 00355 start[2] = bbsz; 00356 } 00357 if(size) { 00358 size[0] = bbex-bbsx; 00359 size[1] = bbey-bbsy; 00360 size[2] = bbez-bbsz; 00361 } 00362 } 00363 00364 //------------------------------------------------------------------------------- 00365 // old interface 00366 //------------------------------------------------------------------------------- 00367 00368 void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value) 00369 { 00370 Mesh *mesh; 00371 00372 value[0]= '\0'; 00373 00374 if(ob->type == OB_MESH) { 00375 /* use mesh bounding box and object scaling */ 00376 mesh= ob->data; 00377 00378 fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); 00379 elbeemEstimateMemreq(fss->resolutionxyz, fss->bbSize[0],fss->bbSize[1],fss->bbSize[2], fss->maxRefine, value); 00380 } 00381 } 00382 00383 00384 /* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */ 00385 static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *dm, char *filename) 00386 { 00387 int wri, i, j; 00388 float wrf; 00389 gzFile gzf; 00390 FluidsimSettings *fss = fluidmd->fss; 00391 int len = strlen(filename); 00392 int totvert = dm->getNumVerts(dm); 00393 FluidVertexVelocity *velarray = NULL; 00394 00395 // mesh and vverts have to be valid from loading... 00396 00397 if(fss->meshVelocities) 00398 MEM_freeN(fss->meshVelocities); 00399 00400 if(len<7) 00401 { 00402 return; 00403 } 00404 00405 if(fss->domainNovecgen>0) return; 00406 00407 fss->meshVelocities = MEM_callocN(sizeof(FluidVertexVelocity)*dm->getNumVerts(dm), "Fluidsim_velocities"); 00408 fss->totvert = totvert; 00409 00410 velarray = fss->meshVelocities; 00411 00412 // .bobj.gz , correct filename 00413 // 87654321 00414 filename[len-6] = 'v'; 00415 filename[len-5] = 'e'; 00416 filename[len-4] = 'l'; 00417 00418 gzf = gzopen(filename, "rb"); 00419 if (!gzf) 00420 { 00421 MEM_freeN(fss->meshVelocities); 00422 fss->meshVelocities = NULL; 00423 return; 00424 } 00425 00426 gzread(gzf, &wri, sizeof( wri )); 00427 if(wri != totvert) 00428 { 00429 MEM_freeN(fss->meshVelocities); 00430 fss->meshVelocities = NULL; 00431 return; 00432 } 00433 00434 for(i=0; i<totvert;i++) 00435 { 00436 for(j=0; j<3; j++) 00437 { 00438 gzread(gzf, &wrf, sizeof( wrf )); 00439 velarray[i].vel[j] = wrf; 00440 } 00441 } 00442 00443 gzclose(gzf); 00444 } 00445 00446 static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams) 00447 { 00448 int displaymode = 0; 00449 int curFrame = framenr - 1 /*scene->r.sfra*/; /* start with 0 at start frame */ 00450 char targetFile[FILE_MAX]; 00451 FluidsimSettings *fss = fluidmd->fss; 00452 DerivedMesh *dm = NULL; 00453 MFace *mface; 00454 int numfaces; 00455 int mat_nr, flag, i; 00456 00457 if(!useRenderParams) { 00458 displaymode = fss->guiDisplayMode; 00459 } else { 00460 displaymode = fss->renderDisplayMode; 00461 } 00462 00463 switch (displaymode) { 00464 case 1: 00465 /* just display original object */ 00466 return NULL; 00467 case 2: 00468 /* use preview mesh */ 00469 BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME); 00470 break; 00471 default: /* 3 */ 00472 /* 3. use final mesh */ 00473 BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); 00474 break; 00475 } 00476 00477 BLI_path_abs(targetFile, modifier_path_relbase(ob)); 00478 BLI_path_frame(targetFile, curFrame, 0); // fixed #frame-no 00479 00480 dm = fluidsim_read_obj(targetFile); 00481 00482 if(!dm) 00483 { 00484 // switch, abort background rendering when fluidsim mesh is missing 00485 const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp 00486 00487 if(G.background==1) { 00488 if(getenv(strEnvName2)) { 00489 int elevel = atoi(getenv(strEnvName2)); 00490 if(elevel>0) { 00491 printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile); 00492 exit(1); 00493 } 00494 } 00495 } 00496 00497 // display org. object upon failure which is in dm 00498 return NULL; 00499 } 00500 00501 // assign material + flags to new dm 00502 // if there's no faces in original dm, keep materials and flags unchanged 00503 mface = orgdm->getFaceArray(orgdm); 00504 00505 if(mface) { 00506 mat_nr = mface[0].mat_nr; 00507 flag = mface[0].flag; 00508 00509 mface = dm->getFaceArray(dm); 00510 numfaces = dm->getNumFaces(dm); 00511 for(i=0; i<numfaces; i++) 00512 { 00513 mface[i].mat_nr = mat_nr; 00514 mface[i].flag = flag; 00515 } 00516 } 00517 00518 // load vertex velocities, if they exist... 00519 // TODO? use generate flag as loading flag as well? 00520 // warning, needs original .bobj.gz mesh loading filename 00521 if(displaymode==3) 00522 { 00523 fluidsim_read_vel_cache(fluidmd, dm, targetFile); 00524 } 00525 else 00526 { 00527 if(fss->meshVelocities) 00528 MEM_freeN(fss->meshVelocities); 00529 00530 fss->meshVelocities = NULL; 00531 } 00532 00533 return dm; 00534 } 00535 #endif // WITH_MOD_FLUID 00536 00537 DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Scene *scene, 00538 Object *ob, 00539 DerivedMesh *dm, 00540 int useRenderParams, int UNUSED(isFinalCalc)) 00541 { 00542 #ifdef WITH_MOD_FLUID 00543 DerivedMesh *result = NULL; 00544 int framenr; 00545 FluidsimSettings *fss = NULL; 00546 00547 framenr= (int)scene->r.cfra; 00548 00549 // only handle fluidsim domains 00550 if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN)) 00551 return dm; 00552 00553 // sanity check 00554 if(!fluidmd || (fluidmd && !fluidmd->fss)) 00555 return dm; 00556 00557 fss = fluidmd->fss; 00558 00559 // timescale not supported yet 00560 // clmd->sim_parms->timescale= timescale; 00561 00562 // support reversing of baked fluid frames here 00563 if((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0)) 00564 { 00565 framenr = fss->lastgoodframe - framenr + 1; 00566 CLAMP(framenr, 1, fss->lastgoodframe); 00567 } 00568 00569 /* try to read from cache */ 00570 /* if the frame is there, fine, otherwise don't do anything */ 00571 if((result = fluidsim_read_cache(ob, dm, fluidmd, framenr, useRenderParams))) 00572 return result; 00573 00574 return dm; 00575 #else 00576 /* unused */ 00577 (void)fluidmd; 00578 (void)scene; 00579 (void)ob; 00580 (void)dm; 00581 (void)useRenderParams; 00582 return NULL; 00583 #endif 00584 }