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 // (ab)used to store velocities
143 fss->meshSurfNormals = NULL;
145 fss->lastgoodframe = -1;
147 fss->flag |= OB_FLUIDSIM_ACTIVE;
151 (void)fluidmd; /* unused */
156 void fluidsim_free(FluidsimModifierData *fluidmd)
158 #ifndef DISABLE_ELBEEM
161 if(fluidmd->fss->meshSurfNormals)
163 MEM_freeN(fluidmd->fss->meshSurfNormals);
164 fluidmd->fss->meshSurfNormals = NULL;
166 MEM_freeN(fluidmd->fss);
169 (void)fluidmd; /* unused */
175 #ifndef DISABLE_ELBEEM
176 /* read .bobj.gz file into a fluidsimDerivedMesh struct */
177 static DerivedMesh *fluidsim_read_obj(const char *filename)
182 int numverts = 0, numfaces = 0;
183 DerivedMesh *dm = NULL;
186 short *normals, *no_s;
189 // ------------------------------------------------
190 // get numverts + numfaces first
191 // ------------------------------------------------
192 gzf = gzopen(filename, "rb");
199 gotBytes = gzread(gzf, &wri, sizeof(wri));
203 gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
206 // read number of normals
208 gotBytes = gzread(gzf, &wri, sizeof(wri));
211 gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1;
213 /* get no. of triangles */
215 gotBytes = gzread(gzf, &wri, sizeof(wri));
219 // ------------------------------------------------
221 if(!numfaces || !numverts || !gotBytes)
224 gzf = gzopen(filename, "rb");
230 dm = CDDM_new(numverts, 0, numfaces);
239 gotBytes = gzread(gzf, &wri, sizeof(wri));
241 // read vertex position from file
242 mv = CDDM_get_verts(dm);
244 for(i=0; i<numverts; i++, mv++)
245 gotBytes = gzread(gzf, mv->co, sizeof(float) * 3);
247 // should be the same as numverts
248 gotBytes = gzread(gzf, &wri, sizeof(wri));
257 normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );
266 // read normals from file (but don't save them yet)
267 for(i=numverts, no_s= normals; i>0; i--, no_s += 3)
269 gotBytes = gzread(gzf, no, sizeof(float) * 3);
270 normal_float_to_short_v3(no_s, no);
273 /* read no. of triangles */
274 gotBytes = gzread(gzf, &wri, sizeof(wri));
277 printf("Fluidsim: error in reading data from file.\n");
285 // read triangles from file
286 mf = CDDM_get_faces(dm);
287 for(i=numfaces; i>0; i--, mf++)
291 gotBytes = gzread(gzf, face, sizeof(int) * 3);
293 // check if 3rd vertex has index 0 (not allowed in blender)
308 test_index_face(mf, NULL, 0, 3);
315 CDDM_apply_vert_normals(dm, (short (*)[3])normals);
318 // CDDM_calc_normals(result);
324 void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
325 /*RET*/ float start[3], /*RET*/ float size[3] )
327 float bbsx=0.0, bbsy=0.0, bbsz=0.0;
328 float bbex=1.0, bbey=1.0, bbez=1.0;
338 copy_v3_v3(vec, mvert[0].co);
339 mul_m4_v3(obmat, vec);
340 bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
341 bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
343 for(i = 1; i < totvert; i++) {
344 copy_v3_v3(vec, mvert[i].co);
345 mul_m4_v3(obmat, vec);
347 if(vec[0] < bbsx){ bbsx= vec[0]; }
348 if(vec[1] < bbsy){ bbsy= vec[1]; }
349 if(vec[2] < bbsz){ bbsz= vec[2]; }
350 if(vec[0] > bbex){ bbex= vec[0]; }
351 if(vec[1] > bbey){ bbey= vec[1]; }
352 if(vec[2] > bbez){ bbez= vec[2]; }
368 //-------------------------------------------------------------------------------
370 //-------------------------------------------------------------------------------
372 void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value)
378 if(ob->type == OB_MESH) {
379 /* use mesh bounding box and object scaling */
382 fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
383 elbeemEstimateMemreq(fss->resolutionxyz, fss->bbSize[0],fss->bbSize[1],fss->bbSize[2], fss->maxRefine, value);
388 /* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
389 static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *dm, char *filename)
394 FluidsimSettings *fss = fluidmd->fss;
395 int len = strlen(filename);
396 int totvert = dm->getNumVerts(dm);
397 float *velarray = NULL;
399 // mesh and vverts have to be valid from loading...
401 if(fss->meshSurfNormals)
402 MEM_freeN(fss->meshSurfNormals);
409 if(fss->domainNovecgen>0) return;
411 // abusing pointer to hold an array of 3d-velocities
412 fss->meshSurfNormals = MEM_callocN(sizeof(float)*3*dm->getNumVerts(dm), "Fluidsim_velocities");
413 // abusing pointer to hold an INT
414 fss->meshSurface = SET_INT_IN_POINTER(totvert);
416 velarray = (float *)fss->meshSurfNormals;
418 // .bobj.gz , correct filename
420 filename[len-6] = 'v';
421 filename[len-5] = 'e';
422 filename[len-4] = 'l';
424 gzf = gzopen(filename, "rb");
427 MEM_freeN(fss->meshSurfNormals);
428 fss->meshSurfNormals = NULL;
432 gzread(gzf, &wri, sizeof( wri ));
435 MEM_freeN(fss->meshSurfNormals);
436 fss->meshSurfNormals = NULL;
440 for(i=0; i<totvert;i++)
444 gzread(gzf, &wrf, sizeof( wrf ));
445 velarray[3*i + j] = wrf;
452 static DerivedMesh *fluidsim_read_cache(DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
455 int curFrame = framenr - 1 /*scene->r.sfra*/; /* start with 0 at start frame */
456 char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
457 FluidsimSettings *fss = fluidmd->fss;
458 DerivedMesh *dm = NULL;
463 if(!useRenderParams) {
464 displaymode = fss->guiDisplayMode;
466 displaymode = fss->renderDisplayMode;
469 BLI_strncpy(targetDir, fss->surfdataPath, sizeof(targetDir));
471 // use preview or final mesh?
474 // just display original object
477 else if(displaymode==2)
479 strcat(targetDir,"fluidsurface_preview_####");
483 strcat(targetDir,"fluidsurface_final_####");
486 BLI_path_abs(targetDir, G.main->name);
487 BLI_path_frame(targetDir, curFrame, 0); // fixed #frame-no
489 BLI_snprintf(targetFile, sizeof(targetFile), "%s.bobj.gz", targetDir);
491 dm = fluidsim_read_obj(targetFile);
495 // switch, abort background rendering when fluidsim mesh is missing
496 const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
498 if(G.background==1) {
499 if(getenv(strEnvName2)) {
500 int elevel = atoi(getenv(strEnvName2));
502 printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
508 // display org. object upon failure which is in dm
512 // assign material + flags to new dm
513 mface = orgdm->getFaceArray(orgdm);
514 mat_nr = mface[0].mat_nr;
515 flag = mface[0].flag;
517 mface = dm->getFaceArray(dm);
518 numfaces = dm->getNumFaces(dm);
519 for(i=0; i<numfaces; i++)
521 mface[i].mat_nr = mat_nr;
522 mface[i].flag = flag;
525 // load vertex velocities, if they exist...
526 // TODO? use generate flag as loading flag as well?
527 // warning, needs original .bobj.gz mesh loading filename
530 fluidsim_read_vel_cache(fluidmd, dm, targetFile);
534 if(fss->meshSurfNormals)
535 MEM_freeN(fss->meshSurfNormals);
537 fss->meshSurfNormals = NULL;
542 #endif // DISABLE_ELBEEM
544 DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Scene *scene,
547 int useRenderParams, int UNUSED(isFinalCalc))
549 #ifndef DISABLE_ELBEEM
550 DerivedMesh *result = NULL;
552 FluidsimSettings *fss = NULL;
554 framenr= (int)scene->r.cfra;
556 // only handle fluidsim domains
557 if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
561 if(!fluidmd || (fluidmd && !fluidmd->fss))
566 // timescale not supported yet
567 // clmd->sim_parms->timescale= timescale;
569 // support reversing of baked fluid frames here
570 if((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0))
572 framenr = fss->lastgoodframe - framenr + 1;
573 CLAMP(framenr, 1, fss->lastgoodframe);
576 /* try to read from cache */
577 /* if the frame is there, fine, otherwise don't do anything */
578 if((result = fluidsim_read_cache(dm, fluidmd, framenr, useRenderParams)))
587 (void)useRenderParams;