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