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