5 * ***** BEGIN GPL LICENSE BLOCK *****
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * The Original Code is Copyright (C) Blender Foundation
22 * All rights reserved.
24 * The Original Code is: all of this file.
26 * Contributor(s): none yet.
28 * ***** END GPL LICENSE BLOCK *****
31 #include "MEM_guardedalloc.h"
33 #include "DNA_mesh_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_object_force.h" // for pointcache
36 #include "DNA_particle_types.h"
37 #include "DNA_scene_types.h" // N_T
39 #include "BLI_arithb.h"
40 #include "BLI_blenlib.h"
42 #include "BKE_cdderivedmesh.h"
43 #include "BKE_customdata.h"
44 #include "BKE_DerivedMesh.h"
45 #include "BKE_fluidsim.h"
46 #include "BKE_global.h"
47 #include "BKE_modifier.h"
49 #include "BKE_pointcache.h"
50 #include "BKE_utildefines.h"
52 // headers for fluidsim bobj meshes
54 #include "LBM_fluidsim.h"
60 /* ************************* fluidsim bobj file handling **************************** */
62 #ifndef DISABLE_ELBEEM
64 // -----------------------------------------
65 // forward decleration
66 // -----------------------------------------
68 // -----------------------------------------
70 void fluidsim_init(FluidsimModifierData *fluidmd)
74 FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings");
82 fss->show_advancedoptions = 0;
84 fss->resolutionxyz = 50;
85 fss->previewresxyz = 25;
87 fss->guiDisplayMode = 2; // preview
88 fss->renderDisplayMode = 3; // render
90 fss->viscosityMode = 2; // default to water
91 fss->viscosityValue = 1.0;
92 fss->viscosityExponent = 6;
94 // dg TODO: change this to []
100 fss->gstar = 0.005; // used as normgstar
102 // maxRefine is set according to resolutionxyz during bake
104 // fluid/inflow settings
105 // fss->iniVel --> automatically set to 0
107 /* elubie: changed this to default to the same dir as the render output
108 to prevent saving to C:\ on Windows */
109 BLI_strncpy(fss->surfdataPath, btempdir, FILE_MAX);
111 // first init of bounding box
112 // no bounding box needed
114 // todo - reuse default init from elbeem!
116 fss->domainNovecgen = 0;
117 fss->volumeInitType = 1; // volume
118 fss->partSlipValue = 0.0;
120 fss->generateTracers = 0;
121 fss->generateParticles = 0.0;
122 fss->surfaceSmoothing = 1.0;
123 fss->surfaceSubdivs = 1.0;
124 fss->particleInfSize = 0.0;
125 fss->particleInfAlpha = 0.0;
127 // init fluid control settings
128 fss->attractforceStrength = 0.2;
129 fss->attractforceRadius = 0.75;
130 fss->velocityforceStrength = 0.2;
131 fss->velocityforceRadius = 0.75;
132 fss->cpsTimeStart = fss->animStart;
133 fss->cpsTimeEnd = fss->animEnd;
134 fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width
137 BAD TODO: this is done in buttons_object.c in the moment
138 Mesh *mesh = ob->data;
139 // calculate bounding box
140 fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize);
143 fss->lastgoodframe = -1;
150 void fluidsim_free(FluidsimModifierData *fluidmd)
154 MEM_freeN(fluidmd->fss);
160 DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
162 DerivedMesh *result = NULL;
164 FluidsimSettings *fss = NULL;
166 framenr= (int)G.scene->r.cfra;
168 // only handle fluidsim domains
169 if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
173 if(!fluidmd || (fluidmd && !fluidmd->fss))
178 // timescale not supported yet
179 // clmd->sim_parms->timescale= timescale;
181 /* try to read from cache */
182 if((result = fluidsim_read_cache(ob, fluidmd, framenr, useRenderParams)))
184 fss->lastgoodframe = framenr;
189 // display last known good frame
190 if(fss->lastgoodframe >= 0)
192 if((result = fluidsim_read_cache(ob, fluidmd, fss->lastgoodframe, useRenderParams)))
198 result = CDDM_copy(dm);
209 /* read .bobj.gz file into a fluidsimDerivedMesh struct */
210 static DerivedMesh *fluidsim_read_obj(char *filename)
216 int numverts = 0, numfaces = 0, numedges = 0;
217 DerivedMesh *dm = NULL;
222 // ------------------------------------------------
223 // get numverts + numfaces first
224 // ------------------------------------------------
225 gzf = gzopen(filename, "rb");
232 gotBytes = gzread(gzf, &wri, sizeof(wri));
236 for(i=0; i<numverts*3; i++)
238 gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
241 // read number of normals
242 gotBytes = gzread(gzf, &wri, sizeof(wri));
245 for(i=0; i<numverts*3; i++)
247 gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
250 /* get no. of triangles */
251 gotBytes = gzread(gzf, &wri, sizeof(wri));
255 // ------------------------------------------------
257 if(!numfaces || !numverts)
260 gzf = gzopen(filename, "rb");
266 dm = CDDM_new(numverts, 0, numfaces);
275 gotBytes = gzread(gzf, &wri, sizeof(wri));
277 // read vertex position from file
278 mvert = CDDM_get_verts(dm);
279 for(i=0; i<numverts; i++)
281 MVert *mv = &mvert[i];
285 gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
290 // should be the same as numverts
291 gotBytes = gzread(gzf, &wri, sizeof(wri));
300 normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );
309 // read normals from file (but don't save them yet)
310 for(i=0; i<numverts*3; i++)
312 gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
313 normals[i] = (short)(wrf*32767.0f);
316 /* read no. of triangles */
317 gotBytes = gzread(gzf, &wri, sizeof(wri));
320 printf("Fluidsim: error in reading data from file.\n");
322 // read triangles from file
323 mface = CDDM_get_faces(dm);
324 for(i=0; i<numfaces; i++)
327 MFace *mf = &mface[i];
329 gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] ));
330 gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] ));
331 gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] ));
334 // check if 3rd vertex has index 0 (not allowed in blender)
349 test_index_face(mf, NULL, 0, 3);
356 CDDM_apply_vert_normals(dm, (short (*)[3])normals);
359 // CDDM_calc_normals(result);
364 DerivedMesh *fluidsim_read_cache(Object *ob, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
367 int curFrame = framenr - 1 /*G.scene->r.sfra*/; /* start with 0 at start frame */
368 char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
369 FluidsimSettings *fss = fluidmd->fss;
370 DerivedMesh *dm = NULL;
372 if(!useRenderParams) {
373 displaymode = fss->guiDisplayMode;
375 displaymode = fss->renderDisplayMode;
378 strncpy(targetDir, fss->surfdataPath, FILE_MAXDIR);
380 // use preview or final mesh?
383 // just display original object
386 else if(displaymode==2)
388 strcat(targetDir,"fluidsurface_preview_####");
392 strcat(targetDir,"fluidsurface_final_####");
395 BLI_convertstringcode(targetDir, G.sce);
396 BLI_convertstringframe(targetDir, curFrame); // fixed #frame-no
398 strcpy(targetFile,targetDir);
399 strcat(targetFile, ".bobj.gz");
401 dm = fluidsim_read_obj(targetFile);
405 // switch, abort background rendering when fluidsim mesh is missing
406 const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
408 if(G.background==1) {
409 if(getenv(strEnvName2)) {
410 int elevel = atoi(getenv(strEnvName2));
412 printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
418 // display org. object upon failure which is in dm
422 // load vertex velocities, if they exist...
423 // TODO? use generate flag as loading flag as well?
424 // warning, needs original .bobj.gz mesh loading filename
428 readVelgz(targetFile, srcob);
432 // no data for preview, only clear...
434 for(i=0; i<mesh->totvert;i++) { for(j=0; j<3; j++) { srcob->fluidsimSettings->meshSurfNormals[i].co[j] = 0.; }}
440 void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
441 /*RET*/ float start[3], /*RET*/ float size[3] )
443 float bbsx=0.0, bbsy=0.0, bbsz=0.0;
444 float bbex=1.0, bbey=1.0, bbez=1.0;
448 VECCOPY(vec, mvert[0].co);
449 Mat4MulVecfl(obmat, vec);
450 bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
451 bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
453 for(i = 1; i < totvert; i++) {
454 VECCOPY(vec, mvert[i].co);
455 Mat4MulVecfl(obmat, vec);
457 if(vec[0] < bbsx){ bbsx= vec[0]; }
458 if(vec[1] < bbsy){ bbsy= vec[1]; }
459 if(vec[2] < bbsz){ bbsz= vec[2]; }
460 if(vec[0] > bbex){ bbex= vec[0]; }
461 if(vec[1] > bbey){ bbey= vec[1]; }
462 if(vec[2] > bbez){ bbez= vec[2]; }
478 //-------------------------------------------------------------------------------
480 //-------------------------------------------------------------------------------
484 //-------------------------------------------------------------------------------
486 //-------------------------------------------------------------------------------
489 /* write .bobj.gz file for a mesh object */
490 void writeBobjgz(char *filename, struct Object *ob, int useGlobalCoords, int append, float time)
492 int wri,i,j,totvert,totface;
500 //if(append)return; // DEBUG
502 if(!ob->data || (ob->type!=OB_MESH))
506 if((ob->size[0]<0.0) || (ob->size[0]<0.0) || (ob->size[0]<0.0) )
511 if(append) gzf = gzopen(filename, "a+b9");
512 else gzf = gzopen(filename, "wb9");
517 dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH);
518 //dm = mesh_create_derived_no_deform(ob,NULL);
520 mvert = dm->getVertArray(dm);
521 mface = dm->getFaceArray(dm);
522 totvert = dm->getNumVerts(dm);
523 totface = dm->getNumFaces(dm);
525 // write time value for appended anim mesh
528 gzwrite(gzf, &time, sizeof(time));
531 // continue with verts/norms
532 if(sizeof(wri)!=4) { return; } // paranoia check
533 wri = dm->getNumVerts(dm);
534 mvert = dm->getVertArray(dm);
535 gzwrite(gzf, &wri, sizeof(wri));
538 VECCOPY(vec, mvert[i].co);
539 if(useGlobalCoords) { Mat4MulVecfl(ob->obmat, vec); }
542 gzwrite(gzf, &wrf, sizeof( wrf ));
546 // should be the same as Vertices.size
548 gzwrite(gzf, &wri, sizeof(wri));
549 EulToMat3(ob->rot, rotmat);
552 VECCOPY(vec, mvert[i].no);
554 if(useGlobalCoords) { Mat3MulVecfl(rotmat, vec); }
557 gzwrite(gzf, &wrf, sizeof( wrf ));
561 // append only writes verts&norms
563 // compute no. of triangles
565 for(i=0; i<totface; i++)
568 if(mface[i].v4) { wri++; }
570 gzwrite(gzf, &wri, sizeof(wri));
571 for(i=0; i<totface; i++)
575 face[0] = mface[i].v1;
576 face[1] = mface[i].v2;
577 face[2] = mface[i].v3;
578 face[3] = mface[i].v4;
580 gzwrite(gzf, &(face[0]), sizeof( face[0] ));
581 gzwrite(gzf, &(face[1]), sizeof( face[1] ));
582 gzwrite(gzf, &(face[2]), sizeof( face[2] ));
585 gzwrite(gzf, &(face[0]), sizeof( face[0] ));
586 gzwrite(gzf, &(face[2]), sizeof( face[2] ));
587 gzwrite(gzf, &(face[3]), sizeof( face[3] ));
596 void initElbeemMesh(struct Object *ob,
597 int *numVertices, float **vertices,
598 int *numTriangles, int **triangles,
601 DerivedMesh *dm = NULL;
604 int countTris=0, i, totvert, totface;
608 dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH);
609 //dm = mesh_create_derived_no_deform(ob,NULL);
611 mvert = dm->getVertArray(dm);
612 mface = dm->getFaceArray(dm);
613 totvert = dm->getNumVerts(dm);
614 totface = dm->getNumFaces(dm);
616 *numVertices = totvert;
617 verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices");
618 for(i=0; i<totvert; i++) {
619 VECCOPY( &verts[i*3], mvert[i].co);
620 if(useGlobalCoords) { Mat4MulVecfl(ob->obmat, &verts[i*3]); }
624 for(i=0; i<totface; i++) {
626 if(mface[i].v4) { countTris++; }
628 *numTriangles = countTris;
629 tris = MEM_callocN( countTris*3*sizeof(int), "elbeemmesh_triangles");
631 for(i=0; i<totface; i++) {
633 face[0] = mface[i].v1;
634 face[1] = mface[i].v2;
635 face[2] = mface[i].v3;
636 face[3] = mface[i].v4;
638 tris[countTris*3+0] = face[0];
639 tris[countTris*3+1] = face[1];
640 tris[countTris*3+2] = face[2];
643 tris[countTris*3+0] = face[0];
644 tris[countTris*3+1] = face[2];
645 tris[countTris*3+2] = face[3];
654 /* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
655 void readVelgz(char *filename, Object *srcob)
660 MVert *vverts = srcob->fluidsimSettings->meshSurfNormals;
661 int len = strlen(filename);
662 Mesh *mesh = srcob->data;
663 // mesh and vverts have to be valid from loading...
665 // clean up in any case
666 for(i=0; i<mesh->totvert;i++)
670 vverts[i].co[j] = 0.;
673 if(srcob->fluidsimSettings->domainNovecgen>0) return;
680 // .bobj.gz , correct filename
682 filename[len-6] = 'v';
683 filename[len-5] = 'e';
684 filename[len-4] = 'l';
686 gzf = gzopen(filename, "rb");
690 gzread(gzf, &wri, sizeof( wri ));
691 if(wri != mesh->totvert)
696 for(i=0; i<mesh->totvert;i++)
700 gzread(gzf, &wrf, sizeof( wrf ));
701 vverts[i].co[j] = wrf;
709 #endif // DISABLE_ELBEEM