Bugfix for [#17879] Speed vectors/velocity data not working on ALL fluids.
[blender.git] / source / blender / blenkernel / intern / fluidsim.c
1 /**
2  * fluidsim.c
3  * 
4  *
5  * ***** BEGIN GPL LICENSE BLOCK *****
6  *
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.
11  *
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.
16  *
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.
20  *
21  * The Original Code is Copyright (C) Blender Foundation
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30
31 #include "MEM_guardedalloc.h"
32
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
38
39 #include "BLI_arithb.h"
40 #include "BLI_blenlib.h"
41
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"
48 #include "BKE_mesh.h"
49 #include "BKE_pointcache.h"
50 #include "BKE_utildefines.h"
51
52 // headers for fluidsim bobj meshes
53 #include <stdlib.h>
54 #include "LBM_fluidsim.h"
55 #include "elbeem.h"
56 #include <zlib.h>
57 #include <string.h>
58 #include <stdio.h>
59
60 /* ************************* fluidsim bobj file handling **************************** */
61
62 // -----------------------------------------
63 // forward decleration
64 // -----------------------------------------
65
66 // -----------------------------------------
67
68 void fluidsim_init(FluidsimModifierData *fluidmd)
69 {
70 #ifndef DISABLE_ELBEEM
71         if(fluidmd)
72         {
73                 FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings");
74                 
75                 fluidmd->fss = fss;
76                 
77                 if(!fss)
78                         return;
79                 
80                 fss->type = OB_FSBND_NOSLIP;
81                 fss->show_advancedoptions = 0;
82
83                 fss->resolutionxyz = 50;
84                 fss->previewresxyz = 25;
85                 fss->realsize = 0.03;
86                 fss->guiDisplayMode = 2; // preview
87                 fss->renderDisplayMode = 3; // render
88
89                 fss->viscosityMode = 2; // default to water
90                 fss->viscosityValue = 1.0;
91                 fss->viscosityExponent = 6;
92                 
93                 // dg TODO: change this to []
94                 fss->gravx = 0.0;
95                 fss->gravy = 0.0;
96                 fss->gravz = -9.81;
97                 fss->animStart = 0.0; 
98                 fss->animEnd = 0.30;
99                 fss->gstar = 0.005; // used as normgstar
100                 fss->maxRefine = -1;
101                 // maxRefine is set according to resolutionxyz during bake
102
103                 // fluid/inflow settings
104                 // fss->iniVel --> automatically set to 0
105
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);
109
110                 // first init of bounding box
111                 // no bounding box needed
112                 
113                 // todo - reuse default init from elbeem!
114                 fss->typeFlags = 0;
115                 fss->domainNovecgen = 0;
116                 fss->volumeInitType = 1; // volume
117                 fss->partSlipValue = 0.0;
118
119                 fss->generateTracers = 0;
120                 fss->generateParticles = 0.0;
121                 fss->surfaceSmoothing = 1.0;
122                 fss->surfaceSubdivs = 1.0;
123                 fss->particleInfSize = 0.0;
124                 fss->particleInfAlpha = 0.0;
125         
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
134                 
135                 /*
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); 
140                 */
141                 
142                 // (ab)used to store velocities
143                 fss->meshSurfNormals = NULL;
144                 
145                 fss->lastgoodframe = -1;
146                 
147                 fss->flag = 0;
148
149         }
150 #endif
151         return;
152 }
153
154 void fluidsim_free(FluidsimModifierData *fluidmd)
155 {
156 #ifndef DISABLE_ELBEEM
157         if(fluidmd)
158         {
159                 if(fluidmd->fss->meshSurfNormals)
160                 {
161                         MEM_freeN(fluidmd->fss->meshSurfNormals);
162                         fluidmd->fss->meshSurfNormals = NULL;
163                 }
164                 MEM_freeN(fluidmd->fss);
165         }
166 #endif
167         return;
168 }
169
170 DerivedMesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
171 {
172 #ifndef DISABLE_ELBEEM
173         DerivedMesh *result = NULL;
174         int framenr;
175         FluidsimSettings *fss = NULL;
176
177         framenr= (int)G.scene->r.cfra;
178         
179         // only handle fluidsim domains
180         if(fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN))
181                 return dm;
182         
183         // sanity check
184         if(!fluidmd || (fluidmd && !fluidmd->fss))
185                 return dm;
186         
187         fss = fluidmd->fss;
188         
189         // timescale not supported yet
190         // clmd->sim_parms->timescale= timescale;
191         
192         // support reversing of baked fluid frames here
193         if((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0))
194         {
195                 framenr = fss->lastgoodframe - framenr + 1;
196                 CLAMP(framenr, 1, fss->lastgoodframe);
197         }
198         
199         /* try to read from cache */
200         if(((fss->lastgoodframe >= framenr) || (fss->lastgoodframe < 0)) && (result = fluidsim_read_cache(ob, dm, fluidmd, framenr, useRenderParams)))
201         {
202                 // fss->lastgoodframe = framenr; // set also in src/fluidsim.c
203                 return result;
204         }
205         else
206         {       
207                 // display last known good frame
208                 if(fss->lastgoodframe >= 0)
209                 {
210                         if((result = fluidsim_read_cache(ob, dm, fluidmd, fss->lastgoodframe, useRenderParams))) 
211                         {
212                                 return result;
213                         }
214                         
215                         // it was supposed to be a valid frame but it isn't!
216                         fss->lastgoodframe = framenr - 1;
217                         
218                         
219                         // this could be likely the case when you load an old fluidsim
220                         if((result = fluidsim_read_cache(ob, dm, fluidmd, fss->lastgoodframe, useRenderParams))) 
221                         {
222                                 return result;
223                         }
224                 }
225                 
226                 result = CDDM_copy(dm);
227
228                 if(result) 
229                 {
230                         return result;
231                 }
232         }
233         
234         return dm;
235 #else
236         return NULL;
237 #endif
238 }
239
240 #ifndef DISABLE_ELBEEM
241 /* read .bobj.gz file into a fluidsimDerivedMesh struct */
242 static DerivedMesh *fluidsim_read_obj(char *filename)
243 {
244         int wri,i,j;
245         float wrf;
246         int gotBytes;
247         gzFile gzf;
248         int numverts = 0, numfaces = 0;
249         DerivedMesh *dm = NULL;
250         MFace *mface;
251         MVert *mvert;
252         short *normals;
253                 
254         // ------------------------------------------------
255         // get numverts + numfaces first
256         // ------------------------------------------------
257         gzf = gzopen(filename, "rb");
258         if (!gzf) 
259         {
260                 return NULL;
261         }
262
263         // read numverts
264         gotBytes = gzread(gzf, &wri, sizeof(wri));
265         numverts = wri;
266         
267         // skip verts
268         for(i=0; i<numverts*3; i++) 
269         {       
270                 gotBytes = gzread(gzf, &wrf, sizeof( wrf )); 
271         }
272         
273         // read number of normals
274         gotBytes = gzread(gzf, &wri, sizeof(wri));
275         
276         // skip normals
277         for(i=0; i<numverts*3; i++) 
278         {       
279                 gotBytes = gzread(gzf, &wrf, sizeof( wrf )); 
280         }
281         
282         /* get no. of triangles */
283         gotBytes = gzread(gzf, &wri, sizeof(wri));
284         numfaces = wri;
285         
286         gzclose( gzf );
287         // ------------------------------------------------
288         
289         if(!numfaces || !numverts)
290                 return NULL;
291         
292         gzf = gzopen(filename, "rb");
293         if (!gzf) 
294         {
295                 return NULL;
296         }
297         
298         dm = CDDM_new(numverts, 0, numfaces);
299         
300         if(!dm)
301         {
302                 gzclose( gzf );
303                 return NULL;
304         }
305         
306         // read numverts
307         gotBytes = gzread(gzf, &wri, sizeof(wri));
308
309         // read vertex position from file
310         mvert = CDDM_get_verts(dm);
311         for(i=0; i<numverts; i++) 
312         {
313                 MVert *mv = &mvert[i];
314                 
315                 for(j=0; j<3; j++) 
316                 {
317                         gotBytes = gzread(gzf, &wrf, sizeof( wrf )); 
318                         mv->co[j] = wrf;
319                 }
320         }
321
322         // should be the same as numverts
323         gotBytes = gzread(gzf, &wri, sizeof(wri));
324         if(wri != numverts) 
325         {
326                 if(dm)
327                         dm->release(dm);
328                 gzclose( gzf );
329                 return NULL;
330         }
331         
332         normals = MEM_callocN(sizeof(short) * numverts * 3, "fluid_tmp_normals" );      
333         if(!normals)
334         {
335                 if(dm)
336                         dm->release(dm);
337                 gzclose( gzf );
338                 return NULL;
339         }       
340         
341         // read normals from file (but don't save them yet)
342         for(i=0; i<numverts*3; i++) 
343         { 
344                 gotBytes = gzread(gzf, &wrf, sizeof( wrf )); 
345                 normals[i] = (short)(wrf*32767.0f);
346         }
347         
348         /* read no. of triangles */
349         gotBytes = gzread(gzf, &wri, sizeof(wri));
350         
351         if(wri!=numfaces)
352                 printf("Fluidsim: error in reading data from file.\n");
353         
354         // read triangles from file
355         mface = CDDM_get_faces(dm);
356         for(i=0; i<numfaces; i++) 
357         {
358                 int face[4];
359                 MFace *mf = &mface[i];
360
361                 gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] )); 
362                 gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] )); 
363                 gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] )); 
364                 face[3] = 0;
365
366                 // check if 3rd vertex has index 0 (not allowed in blender)
367                 if(face[2])
368                 {
369                         mf->v1 = face[0];
370                         mf->v2 = face[1];
371                         mf->v3 = face[2];
372                 }
373                 else
374                 {
375                         mf->v1 = face[1];
376                         mf->v2 = face[2];
377                         mf->v3 = face[0];
378                 }
379                 mf->v4 = face[3];
380                 
381                 test_index_face(mf, NULL, 0, 3);
382         }
383         
384         gzclose( gzf );
385         
386         CDDM_calc_edges(dm);
387         
388         CDDM_apply_vert_normals(dm, (short (*)[3])normals);
389         MEM_freeN(normals);
390         
391         // CDDM_calc_normals(result);
392
393         return dm;
394 }
395
396 DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams)
397 {
398         int displaymode = 0;
399         int curFrame = framenr - 1 /*G.scene->r.sfra*/; /* start with 0 at start frame */
400         char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
401         FluidsimSettings *fss = fluidmd->fss;
402         DerivedMesh *dm = NULL;
403         MFace *mface;
404         int numfaces;
405         int mat_nr, flag, i;
406         
407         if(!useRenderParams) {
408                 displaymode = fss->guiDisplayMode;
409         } else {
410                 displaymode = fss->renderDisplayMode;
411         }
412
413         strncpy(targetDir, fss->surfdataPath, FILE_MAXDIR);
414         
415         // use preview or final mesh?
416         if(displaymode==1) 
417         {
418                 // just display original object
419                 return NULL;
420         } 
421         else if(displaymode==2) 
422         {
423                 strcat(targetDir,"fluidsurface_preview_####");
424         } 
425         else 
426         { // 3
427                 strcat(targetDir,"fluidsurface_final_####");
428         }
429         
430         BLI_convertstringcode(targetDir, G.sce);
431         BLI_convertstringframe(targetDir, curFrame); // fixed #frame-no 
432         
433         strcpy(targetFile,targetDir);
434         strcat(targetFile, ".bobj.gz");
435
436         dm = fluidsim_read_obj(targetFile);
437         
438         if(!dm) 
439         {       
440                 // switch, abort background rendering when fluidsim mesh is missing
441                 const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
442                 
443                 if(G.background==1) {
444                         if(getenv(strEnvName2)) {
445                                 int elevel = atoi(getenv(strEnvName2));
446                                 if(elevel>0) {
447                                         printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
448                                         exit(1);
449                                 }
450                         }
451                 }
452                 
453                 // display org. object upon failure which is in dm
454                 return NULL;
455         }
456         
457         // assign material + flags to new dm
458         mface = orgdm->getFaceArray(orgdm);
459         mat_nr = mface[0].mat_nr;
460         flag = mface[0].flag;
461         
462         mface = dm->getFaceArray(dm);
463         numfaces = dm->getNumFaces(dm);
464         for(i=0; i<numfaces; i++) 
465         {
466                 mface[i].mat_nr = mat_nr;
467                 mface[i].flag = flag;
468         }
469
470         // load vertex velocities, if they exist...
471         // TODO? use generate flag as loading flag as well?
472         // warning, needs original .bobj.gz mesh loading filename
473         if(displaymode==3) 
474         {
475                 fluidsim_read_vel_cache(fluidmd, dm, targetFile);
476         } 
477         else 
478         {
479                 if(fss->meshSurfNormals)
480                         MEM_freeN(fss->meshSurfNormals); 
481                         
482                 fss->meshSurfNormals = NULL;
483         }
484         
485         return dm;
486 }
487
488
489 /* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
490 void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh *dm, char *filename)
491 {
492         int wri, i, j;
493         float wrf;
494         gzFile gzf;
495         FluidsimSettings *fss = fluidmd->fss;
496         int len = strlen(filename);
497         int totvert = dm->getNumVerts(dm);
498         float *velarray = NULL;
499         
500         // mesh and vverts have to be valid from loading...
501         
502         if(fss->meshSurfNormals)
503                 MEM_freeN(fss->meshSurfNormals);
504                 
505         if(len<7) 
506         { 
507                 return; 
508         }
509         
510         if(fss->domainNovecgen>0) return;
511         
512         // abusing pointer to hold an array of 3d-velocities
513         fss->meshSurfNormals = MEM_callocN(sizeof(float)*3*dm->getNumVerts(dm), "Fluidsim_velocities");
514         // abusing pointer to hold an INT
515         fss->meshSurface = SET_INT_IN_POINTER(totvert);
516         
517         velarray = (float *)fss->meshSurfNormals;
518         
519         // .bobj.gz , correct filename
520         // 87654321
521         filename[len-6] = 'v';
522         filename[len-5] = 'e';
523         filename[len-4] = 'l';
524
525         gzf = gzopen(filename, "rb");
526         if (!gzf)
527         {
528                 MEM_freeN(fss->meshSurfNormals);
529                 fss->meshSurfNormals = NULL;    
530                 return;
531         }
532
533         gzread(gzf, &wri, sizeof( wri ));
534         if(wri != totvert) 
535         {
536                 MEM_freeN(fss->meshSurfNormals);
537                 fss->meshSurfNormals = NULL;
538                 return; 
539         }
540
541         for(i=0; i<totvert;i++) 
542         {
543                 for(j=0; j<3; j++) 
544                 {
545                         gzread(gzf, &wrf, sizeof( wrf )); 
546                         velarray[3*i + j] = wrf;
547                 }
548         }
549
550         gzclose(gzf);
551 }
552
553 void fluid_get_bb(MVert *mvert, int totvert, float obmat[][4],
554                  /*RET*/ float start[3], /*RET*/ float size[3] )
555 {
556         float bbsx=0.0, bbsy=0.0, bbsz=0.0;
557         float bbex=1.0, bbey=1.0, bbez=1.0;
558         int i;
559         float vec[3];
560
561         VECCOPY(vec, mvert[0].co); 
562         Mat4MulVecfl(obmat, vec);
563         bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
564         bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
565
566         for(i = 1; i < totvert; i++) {
567                 VECCOPY(vec, mvert[i].co);
568                 Mat4MulVecfl(obmat, vec);
569
570                 if(vec[0] < bbsx){ bbsx= vec[0]; }
571                 if(vec[1] < bbsy){ bbsy= vec[1]; }
572                 if(vec[2] < bbsz){ bbsz= vec[2]; }
573                 if(vec[0] > bbex){ bbex= vec[0]; }
574                 if(vec[1] > bbey){ bbey= vec[1]; }
575                 if(vec[2] > bbez){ bbez= vec[2]; }
576         }
577
578         // return values...
579         if(start) {
580                 start[0] = bbsx;
581                 start[1] = bbsy;
582                 start[2] = bbsz;
583         } 
584         if(size) {
585                 size[0] = bbex-bbsx;
586                 size[1] = bbey-bbsy;
587                 size[2] = bbez-bbsz;
588         }
589 }
590
591 //-------------------------------------------------------------------------------
592 // old interface
593 //-------------------------------------------------------------------------------
594
595
596
597 //-------------------------------------------------------------------------------
598 // file handling
599 //-------------------------------------------------------------------------------
600
601 void initElbeemMesh(struct Object *ob, 
602                     int *numVertices, float **vertices, 
603       int *numTriangles, int **triangles,
604       int useGlobalCoords, int modifierIndex) 
605 {
606         DerivedMesh *dm = NULL;
607         MVert *mvert;
608         MFace *mface;
609         int countTris=0, i, totvert, totface;
610         float *verts;
611         int *tris;
612
613         dm = mesh_create_derived_index_render(ob, CD_MASK_BAREMESH, modifierIndex);
614         //dm = mesh_create_derived_no_deform(ob,NULL);
615
616         mvert = dm->getVertArray(dm);
617         mface = dm->getFaceArray(dm);
618         totvert = dm->getNumVerts(dm);
619         totface = dm->getNumFaces(dm);
620
621         *numVertices = totvert;
622         verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices");
623         for(i=0; i<totvert; i++) {
624                 VECCOPY( &verts[i*3], mvert[i].co);
625                 if(useGlobalCoords) { Mat4MulVecfl(ob->obmat, &verts[i*3]); }
626         }
627         *vertices = verts;
628
629         for(i=0; i<totface; i++) {
630                 countTris++;
631                 if(mface[i].v4) { countTris++; }
632         }
633         *numTriangles = countTris;
634         tris = MEM_callocN( countTris*3*sizeof(int), "elbeemmesh_triangles");
635         countTris = 0;
636         for(i=0; i<totface; i++) {
637                 int face[4];
638                 face[0] = mface[i].v1;
639                 face[1] = mface[i].v2;
640                 face[2] = mface[i].v3;
641                 face[3] = mface[i].v4;
642
643                 tris[countTris*3+0] = face[0]; 
644                 tris[countTris*3+1] = face[1]; 
645                 tris[countTris*3+2] = face[2]; 
646                 countTris++;
647                 if(face[3]) { 
648                         tris[countTris*3+0] = face[0]; 
649                         tris[countTris*3+1] = face[2]; 
650                         tris[countTris*3+2] = face[3]; 
651                         countTris++;
652                 }
653         }
654         *triangles = tris;
655
656         dm->release(dm);
657 }
658
659 #endif // DISABLE_ELBEEM
660