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 *****
33 /** \file blender/modifiers/intern/MOD_fluidsim_util.c
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_mesh_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_object_fluidsim.h"
48 #include "BLI_blenlib.h"
50 #include "BLI_utildefines.h"
53 #include "BKE_fluidsim.h" /* ensure definitions here match */
54 #include "BKE_cdderivedmesh.h"
56 #include "BKE_utildefines.h"
57 #include "BKE_global.h" /* G.main->name only */
59 #include "MOD_fluidsim_util.h"
60 #include "MOD_modifiertypes.h"
62 #include "MEM_guardedalloc.h"
64 // headers for fluidsim bobj meshes
65 #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 fss->meshVelocities = NULL;
144 fss->lastgoodframe = -1;
146 fss->flag |= OB_FLUIDSIM_ACTIVE;
150 (void)fluidmd; /* unused */
155 void fluidsim_free(FluidsimModifierData *fluidmd)
157 #ifndef DISABLE_ELBEEM
160 if(fluidmd->fss->meshVelocities)
162 MEM_freeN(fluidmd->fss->meshVelocities);
163 fluidmd->fss->meshVelocities = NULL;
165 MEM_freeN(fluidmd->fss);
168 (void)fluidmd; /* unused */
174 #ifndef DISABLE_ELBEEM
175 /* read .bobj.gz file into a fluidsimDerivedMesh struct */
176 static DerivedMesh *fluidsim_read_obj(const char *filename)
181 int numverts = 0, numfaces = 0;
182 DerivedMesh *dm = NULL;
185 short *normals, *no_s;
188 // ------------------------------------------------
189 // get numverts + numfaces first
190 // ------------------------------------------------
191 gzf = gzopen(filename, "rb");
198 gotBytes = gzread(gzf, &wri, sizeof(wri));
202 gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
205 // read number of normals
207 gotBytes = gzread(gzf, &wri, sizeof(wri));
210 gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
212 /* get no. of triangles */
214 gotBytes = gzread(gzf, &wri, sizeof(wri));
218 // ------------------------------------------------
220 if(!numfaces || !numverts || !gotBytes)
223 gzf = gzopen(filename, "rb");
229 dm = CDDM_new(numverts, 0, numfaces, 0, 0);
238 gotBytes = gzread(gzf, &wri, sizeof(wri));
240 // read vertex position from file
241 mv = CDDM_get_verts(dm);
243 for(i=0; i<numverts; i++, mv++)
244 gotBytes = gzread(gzf, mv->co, sizeof(float) * 3);
246 // should be the same as numverts
247 gotBytes = gzread(gzf, &wri, sizeof(wri));
256 normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );
265 // read normals from file (but don't save them yet)
266 for(i=numverts, no_s= normals; i>0; i--, no_s += 3)
268 gotBytes = gzread(gzf, no, sizeof(float) * 3);
269 normal_float_to_short_v3(no_s, no);
272 /* read no. of triangles */
273 gotBytes = gzread(gzf, &wri, sizeof(wri));
276 printf("Fluidsim: error in reading data from file.\n");
284 // read triangles from file
285 mf = CDDM_get_tessfaces(dm);
286 for(i=numfaces; i>0; i--, mf++)
290 gotBytes = gzread(gzf, face, sizeof(int) * 3);
292 // check if 3rd vertex has index 0 (not allowed in blender)
307 test_index_face(mf, NULL, 0, 3);
314 CDDM_apply_vert_normals(dm, (short (*)[3])normals);
317 // CDDM_calc_normals(result);
323 void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
324 /*RET*/ float start[3], /*RET*/ float size[3] )
326 float bbsx=0.0, bbsy=0.0, bbsz=0.0;
327 float bbex=1.0, bbey=1.0, bbez=1.0;
337 copy_v3_v3(vec, mvert[0].co);
338 mul_m4_v3(obmat, vec);
339 bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
340 bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
342 for(i = 1; i < totvert; i++) {
343 copy_v3_v3(vec, mvert[i].co);
344 mul_m4_v3(obmat, vec);
346 if(vec[0] < bbsx){ bbsx= vec[0]; }
347 if(vec[1] < bbsy){ bbsy= vec[1]; }
348 if(vec[2] < bbsz){ bbsz= vec[2]; }
349 if(vec[0] > bbex){ bbex= vec[0]; }
350 if(vec[1] > bbey){ bbey= vec[1]; }
351 if(vec[2] > bbez){ bbez= vec[2]; }
367 //-------------------------------------------------------------------------------
369 //-------------------------------------------------------------------------------
371 void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value)
377 if(ob->type == OB_MESH) {
378 /* use mesh bounding box and object scaling */
381 fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
382 elbeemEstimateMemreq(fss->resolutionxyz, fss->bbSize[0],fss->bbSize[1],fss->bbSize[2], fss->maxRefine, value);
387 /* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
388 static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *dm, char *filename)
393 FluidsimSettings *fss = fluidmd->fss;
394 int len = strlen(filename);
395 int totvert = dm->getNumVerts(dm);
396 FluidVertexVelocity *velarray = NULL;
398 // mesh and vverts have to be valid from loading...
400 if(fss->meshVelocities)
401 MEM_freeN(fss->meshVelocities);
408 if(fss->domainNovecgen>0) return;
410 fss->meshVelocities = MEM_callocN(sizeof(FluidVertexVelocity)*dm->getNumVerts(dm), "Fluidsim_velocities");
411 fss->totvert = totvert;
413 velarray = fss->meshVelocities;
415 // .bobj.gz , correct filename
417 filename[len-6] = 'v';
418 filename[len-5] = 'e';
419 filename[len-4] = 'l';
421 gzf = gzopen(filename, "rb");
424 MEM_freeN(fss->meshVelocities);
425 fss->meshVelocities = NULL;
429 gzread(gzf, &wri, sizeof( wri ));
432 MEM_freeN(fss->meshVelocities);
433 fss->meshVelocities = NULL;
437 for(i=0; i<totvert;i++)
441 gzread(gzf, &wrf, sizeof( wrf ));
442 velarray[i].vel[j] = wrf;
449 static DerivedMesh *fluidsim_read_cache(DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
452 int curFrame = framenr - 1 /*scene->r.sfra*/; /* start with 0 at start frame */
453 char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
454 FluidsimSettings *fss = fluidmd->fss;
455 DerivedMesh *dm = NULL;
460 if(!useRenderParams) {
461 displaymode = fss->guiDisplayMode;
463 displaymode = fss->renderDisplayMode;
466 BLI_strncpy(targetDir, fss->surfdataPath, sizeof(targetDir));
468 // use preview or final mesh?
471 // just display original object
474 else if(displaymode==2)
476 strcat(targetDir,"fluidsurface_preview_####");
480 strcat(targetDir,"fluidsurface_final_####");
483 BLI_path_abs(targetDir, G.main->name);
484 BLI_path_frame(targetDir, curFrame, 0); // fixed #frame-no
486 BLI_snprintf(targetFile, sizeof(targetFile), "%s.bobj.gz", targetDir);
488 dm = fluidsim_read_obj(targetFile);
492 // switch, abort background rendering when fluidsim mesh is missing
493 const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
495 if(G.background==1) {
496 if(getenv(strEnvName2)) {
497 int elevel = atoi(getenv(strEnvName2));
499 printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
505 // display org. object upon failure which is in dm
509 // assign material + flags to new dm
510 mface = orgdm->getTessFaceArray(orgdm);
511 mat_nr = mface[0].mat_nr;
512 flag = mface[0].flag;
514 mface = dm->getTessFaceArray(dm);
515 numfaces = dm->getNumTessFaces(dm);
516 for(i=0; i<numfaces; i++)
518 mface[i].mat_nr = mat_nr;
519 mface[i].flag = flag;
522 // load vertex velocities, if they exist...
523 // TODO? use generate flag as loading flag as well?
524 // warning, needs original .bobj.gz mesh loading filename
527 fluidsim_read_vel_cache(fluidmd, dm, targetFile);
531 if(fss->meshVelocities)
532 MEM_freeN(fss->meshVelocities);
534 fss->meshVelocities = NULL;
539 #endif // DISABLE_ELBEEM
541 DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Scene *scene,
544 int useRenderParams, int UNUSED(isFinalCalc))
546 #ifndef DISABLE_ELBEEM
547 DerivedMesh *result = NULL;
549 FluidsimSettings *fss = NULL;
551 framenr= (int)scene->r.cfra;
553 // only handle fluidsim domains
554 if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
558 if(!fluidmd || (fluidmd && !fluidmd->fss))
563 // timescale not supported yet
564 // clmd->sim_parms->timescale= timescale;
566 // support reversing of baked fluid frames here
567 if((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0))
569 framenr = fss->lastgoodframe - framenr + 1;
570 CLAMP(framenr, 1, fss->lastgoodframe);
573 /* try to read from cache */
574 /* if the frame is there, fine, otherwise don't do anything */
575 if((result = fluidsim_read_cache(dm, fluidmd, framenr, useRenderParams)))
584 (void)useRenderParams;