4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2005 by the Blender Foundation.
21 * All rights reserved.
23 * Contributor(s): Daniel Dunbar
29 * ***** END GPL LICENSE BLOCK *****
40 #include "BLI_blenlib.h"
43 #include "MEM_guardedalloc.h"
45 #include "BKE_cdderivedmesh.h"
46 #include "BKE_DerivedMesh.h"
47 #include "BKE_global.h"
49 #include "BKE_utildefines.h"
51 #include "DNA_mesh_types.h"
52 #include "DNA_meshdata_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_object_fluidsim.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_space_types.h"
58 #include "MOD_modifiertypes.h"
59 #include "MOD_fluidsim_util.h"
61 // headers for fluidsim bobj meshes
63 #include "LBM_fluidsim.h"
67 void fluidsim_init(FluidsimModifierData *fluidmd)
69 #ifndef DISABLE_ELBEEM
72 FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings");
80 fss->type = OB_FLUIDSIM_ENABLE;
81 fss->show_advancedoptions = 0;
83 fss->resolutionxyz = 65;
84 fss->previewresxyz = 45;
86 fss->guiDisplayMode = 2; // preview
87 fss->renderDisplayMode = 3; // render
89 fss->viscosityMode = 2; // default to water
90 fss->viscosityValue = 1.0;
91 fss->viscosityExponent = 6;
93 // dg TODO: change this to []
99 fss->gstar = 0.005; // used as normgstar
101 // maxRefine is set according to resolutionxyz during bake
103 // fluid/inflow settings
104 // fss->iniVel --> automatically set to 0
106 /* elubie: changed this to default to the same dir as the render output
107 to prevent saving to C:\ on Windows */
108 BLI_strncpy(fss->surfdataPath, btempdir, FILE_MAX);
110 // first init of bounding box
111 // no bounding box needed
113 // todo - reuse default init from elbeem!
114 fss->typeFlags = OB_FSBND_PARTSLIP;
115 fss->domainNovecgen = 0;
116 fss->volumeInitType = 1; // volume
117 fss->partSlipValue = 0.2;
119 fss->generateTracers = 0;
120 fss->generateParticles = 0.0;
121 fss->surfaceSmoothing = 1.0;
122 fss->surfaceSubdivs = 0.0;
123 fss->particleInfSize = 0.0;
124 fss->particleInfAlpha = 0.0;
126 // init fluid control settings
127 fss->attractforceStrength = 0.2;
128 fss->attractforceRadius = 0.75;
129 fss->velocityforceStrength = 0.2;
130 fss->velocityforceRadius = 0.75;
131 fss->cpsTimeStart = fss->animStart;
132 fss->cpsTimeEnd = fss->animEnd;
133 fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width
136 BAD TODO: this is done in buttons_object.c in the moment
137 Mesh *mesh = ob->data;
138 // calculate bounding box
139 fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
142 // (ab)used to store velocities
143 fss->meshSurfNormals = NULL;
145 fss->lastgoodframe = -1;
147 fss->flag |= OB_FLUIDSIM_ACTIVE;
154 void fluidsim_free(FluidsimModifierData *fluidmd)
156 #ifndef DISABLE_ELBEEM
159 if(fluidmd->fss->meshSurfNormals)
161 MEM_freeN(fluidmd->fss->meshSurfNormals);
162 fluidmd->fss->meshSurfNormals = NULL;
164 MEM_freeN(fluidmd->fss);
170 #ifndef DISABLE_ELBEEM
171 /* read .bobj.gz file into a fluidsimDerivedMesh struct */
172 DerivedMesh *fluidsim_read_obj(char *filename)
178 int numverts = 0, numfaces = 0;
179 DerivedMesh *dm = NULL;
184 // ------------------------------------------------
185 // get numverts + numfaces first
186 // ------------------------------------------------
187 gzf = gzopen(filename, "rb");
194 gotBytes = gzread(gzf, &wri, sizeof(wri));
198 for(i=0; i<numverts*3; i++)
200 gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
203 // read number of normals
204 gotBytes = gzread(gzf, &wri, sizeof(wri));
207 for(i=0; i<numverts*3; i++)
209 gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
212 /* get no. of triangles */
213 gotBytes = gzread(gzf, &wri, sizeof(wri));
217 // ------------------------------------------------
219 if(!numfaces || !numverts)
222 gzf = gzopen(filename, "rb");
228 dm = CDDM_new(numverts, 0, numfaces);
237 gotBytes = gzread(gzf, &wri, sizeof(wri));
239 // read vertex position from file
240 mvert = CDDM_get_verts(dm);
241 for(i=0; i<numverts; i++)
243 MVert *mv = &mvert[i];
247 gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
252 // should be the same as numverts
253 gotBytes = gzread(gzf, &wri, sizeof(wri));
262 normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );
271 // read normals from file (but don't save them yet)
272 for(i=0; i<numverts*3; i++)
274 gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
275 normals[i] = (short)(wrf*32767.0f);
278 /* read no. of triangles */
279 gotBytes = gzread(gzf, &wri, sizeof(wri));
282 printf("Fluidsim: error in reading data from file.\n");
284 // read triangles from file
285 mface = CDDM_get_faces(dm);
286 for(i=0; i<numfaces; i++)
289 MFace *mf = &mface[i];
291 gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] ));
292 gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] ));
293 gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] ));
296 // check if 3rd vertex has index 0 (not allowed in blender)
311 test_index_face(mf, NULL, 0, 3);
318 CDDM_apply_vert_normals(dm, (short (*)[3])normals);
321 // CDDM_calc_normals(result);
327 void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
328 /*RET*/ float start[3], /*RET*/ float size[3] )
330 float bbsx=0.0, bbsy=0.0, bbsz=0.0;
331 float bbex=1.0, bbey=1.0, bbez=1.0;
341 copy_v3_v3(vec, mvert[0].co);
342 mul_m4_v3(obmat, vec);
343 bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
344 bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
346 for(i = 1; i < totvert; i++) {
347 copy_v3_v3(vec, mvert[i].co);
348 mul_m4_v3(obmat, vec);
350 if(vec[0] < bbsx){ bbsx= vec[0]; }
351 if(vec[1] < bbsy){ bbsy= vec[1]; }
352 if(vec[2] < bbsz){ bbsz= vec[2]; }
353 if(vec[0] > bbex){ bbex= vec[0]; }
354 if(vec[1] > bbey){ bbey= vec[1]; }
355 if(vec[2] > bbez){ bbez= vec[2]; }
371 //-------------------------------------------------------------------------------
373 //-------------------------------------------------------------------------------
375 void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value)
381 if(ob->type == OB_MESH) {
382 /* use mesh bounding box and object scaling */
385 fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
386 elbeemEstimateMemreq(fss->resolutionxyz, fss->bbSize[0],fss->bbSize[1],fss->bbSize[2], fss->maxRefine, value);
391 /* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
392 void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *dm, char *filename)
397 FluidsimSettings *fss = fluidmd->fss;
398 int len = strlen(filename);
399 int totvert = dm->getNumVerts(dm);
400 float *velarray = NULL;
402 // mesh and vverts have to be valid from loading...
404 if(fss->meshSurfNormals)
405 MEM_freeN(fss->meshSurfNormals);
412 if(fss->domainNovecgen>0) return;
414 // abusing pointer to hold an array of 3d-velocities
415 fss->meshSurfNormals = MEM_callocN(sizeof(float)*3*dm->getNumVerts(dm), "Fluidsim_velocities");
416 // abusing pointer to hold an INT
417 fss->meshSurface = SET_INT_IN_POINTER(totvert);
419 velarray = (float *)fss->meshSurfNormals;
421 // .bobj.gz , correct filename
423 filename[len-6] = 'v';
424 filename[len-5] = 'e';
425 filename[len-4] = 'l';
427 gzf = gzopen(filename, "rb");
430 MEM_freeN(fss->meshSurfNormals);
431 fss->meshSurfNormals = NULL;
435 gzread(gzf, &wri, sizeof( wri ));
438 MEM_freeN(fss->meshSurfNormals);
439 fss->meshSurfNormals = NULL;
443 for(i=0; i<totvert;i++)
447 gzread(gzf, &wrf, sizeof( wrf ));
448 velarray[3*i + j] = wrf;
455 DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
458 int curFrame = framenr - 1 /*scene->r.sfra*/; /* start with 0 at start frame */
459 char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
460 FluidsimSettings *fss = fluidmd->fss;
461 DerivedMesh *dm = NULL;
466 if(!useRenderParams) {
467 displaymode = fss->guiDisplayMode;
469 displaymode = fss->renderDisplayMode;
472 strncpy(targetDir, fss->surfdataPath, FILE_MAXDIR);
474 // use preview or final mesh?
477 // just display original object
480 else if(displaymode==2)
482 strcat(targetDir,"fluidsurface_preview_####");
486 strcat(targetDir,"fluidsurface_final_####");
489 BLI_path_abs(targetDir, G.sce);
490 BLI_path_frame(targetDir, curFrame, 0); // fixed #frame-no
492 strcpy(targetFile,targetDir);
493 strcat(targetFile, ".bobj.gz");
495 dm = fluidsim_read_obj(targetFile);
499 // switch, abort background rendering when fluidsim mesh is missing
500 const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
502 if(G.background==1) {
503 if(getenv(strEnvName2)) {
504 int elevel = atoi(getenv(strEnvName2));
506 printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
512 // display org. object upon failure which is in dm
516 // assign material + flags to new dm
517 mface = orgdm->getFaceArray(orgdm);
518 mat_nr = mface[0].mat_nr;
519 flag = mface[0].flag;
521 mface = dm->getFaceArray(dm);
522 numfaces = dm->getNumFaces(dm);
523 for(i=0; i<numfaces; i++)
525 mface[i].mat_nr = mat_nr;
526 mface[i].flag = flag;
529 // load vertex velocities, if they exist...
530 // TODO? use generate flag as loading flag as well?
531 // warning, needs original .bobj.gz mesh loading filename
534 fluidsim_read_vel_cache(fluidmd, dm, targetFile);
538 if(fss->meshSurfNormals)
539 MEM_freeN(fss->meshSurfNormals);
541 fss->meshSurfNormals = NULL;
547 #endif // DISABLE_ELBEEM
549 DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
551 #ifndef DISABLE_ELBEEM
552 DerivedMesh *result = NULL;
554 FluidsimSettings *fss = NULL;
556 framenr= (int)scene->r.cfra;
558 // only handle fluidsim domains
559 if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
563 if(!fluidmd || (fluidmd && !fluidmd->fss))
568 // timescale not supported yet
569 // clmd->sim_parms->timescale= timescale;
571 // support reversing of baked fluid frames here
572 if((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0))
574 framenr = fss->lastgoodframe - framenr + 1;
575 CLAMP(framenr, 1, fss->lastgoodframe);
578 /* try to read from cache */
579 if(((fss->lastgoodframe >= framenr) || (fss->lastgoodframe < 0)) && (result = fluidsim_read_cache(ob, dm, fluidmd, framenr, useRenderParams)))
581 // fss->lastgoodframe = framenr; // set also in src/fluidsim.c
586 // display last known good frame
587 if(fss->lastgoodframe >= 0)
589 if((result = fluidsim_read_cache(ob, dm, fluidmd, fss->lastgoodframe, useRenderParams)))
594 // it was supposed to be a valid frame but it isn't!
595 fss->lastgoodframe = framenr - 1;
598 // this could be likely the case when you load an old fluidsim
599 if((result = fluidsim_read_cache(ob, dm, fluidmd, fss->lastgoodframe, useRenderParams)))
605 result = CDDM_copy(dm);