- added option to switch off compiling elbeem to scons files (set USE_FLUIDSIM=true)
[blender-staging.git] / source / blender / src / fluidsim.c
1 /**
2  * fluidsim.c
3  * 
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) Blender Foundation
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35
36
37 #include <math.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41
42 #include "MEM_guardedalloc.h"
43
44 /* types */
45 #include "DNA_curve_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_object_fluidsim.h"        
48 #include "DNA_key_types.h"
49 #include "DNA_mesh_types.h"
50 #include "DNA_meshdata_types.h"
51 #include "DNA_lattice_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_camera_types.h"
54 #include "DNA_screen_types.h"
55
56 #include "BLI_blenlib.h"
57 #include "BLI_arithb.h"
58 #include "MTC_matrixops.h"
59
60 #include "BKE_displist.h"
61 #include "BKE_effect.h"
62 #include "BKE_global.h"
63 #include "BKE_main.h"
64 #include "BKE_key.h"
65 #include "BKE_scene.h"
66 #include "BKE_object.h"
67 #include "BKE_softbody.h"
68 #include "BKE_utildefines.h"
69 #include "BKE_DerivedMesh.h"
70 #include "LBM_fluidsim.h"
71
72 #include "BLI_editVert.h"
73 #include "BIF_editdeform.h"
74 #include "BIF_gl.h"
75 #include "BIF_screen.h"
76 #include "BIF_space.h"
77 #include "BIF_cursors.h"
78
79 #include "mydevice.h"
80
81 #include "SDL.h"
82 #include "SDL_thread.h"
83 #include "SDL_mutex.h"
84 #include <sys/stat.h>
85
86 #ifdef WIN32    /* Windos */
87 //#include "BLI_winstuff.h"
88 #ifndef snprintf
89 #define snprintf _snprintf
90 #endif
91 #endif
92 // SDL redefines main for SDL_main, not needed here...
93 #undef main
94
95 #ifdef __APPLE__        /* MacOS X */
96 #undef main
97 #endif
98
99 /* from header info.c */
100 extern int start_progress_bar(void);
101 extern void end_progress_bar(void);
102 extern int progress_bar(float done, char *busy_info);
103
104 double fluidsimViscosityPreset[6] = {
105         -1.0,   /* unused */
106         -1.0,   /* manual */
107         1.0e-6, /* water */
108         5.0e-5, /* some (thick) oil */
109         2.0e-3, /* ca. honey */
110         -1.0    /* end */
111 };
112
113 char* fluidsimViscosityPresetString[6] = {
114         "UNUSED",       /* unused */
115         "UNUSED",       /* manual */
116         "  = 1.0 * 10^-6", /* water */
117         "  = 5.0 * 10^-5", /* some (thick) oil */
118         "  = 2.0 * 10^-3", /* ca. honey */
119         "INVALID"       /* end */
120 };
121
122 typedef struct {
123         DerivedMesh dm;
124
125         // similar to MeshDerivedMesh
126         struct Object *ob;      // pointer to parent object
127         float *extverts, *nors; // face normals, colors?
128         Mesh *fsmesh;   // mesh struct to display (either surface, or original one)
129         char meshFree;  // free the mesh afterwards? (boolean)
130 } fluidsimDerivedMesh;
131
132
133 /* ********************** fluid sim settings struct functions ********************** */
134
135 /* allocates and initializes general main data */
136 FluidsimSettings *fluidsimSettingsNew(struct Object *srcob)
137 {
138         char blendDir[FILE_MAXDIR], blendFile[FILE_MAXFILE];
139         FluidsimSettings *fss;
140         fss= MEM_callocN( sizeof(FluidsimSettings), "fluidsimsettings memory");
141         
142         fss->type = 0;
143         fss->show_advancedoptions = 0;
144
145         fss->resolutionxyz = 50;
146         fss->previewresxyz = 25;
147         fss->realsize = 0.03;
148         fss->guiDisplayMode = 2; // preview
149         fss->renderDisplayMode = 3; // render
150
151         fss->viscosityMode = 2; // default to water
152         fss->viscosityValue = 0.1;
153         fss->viscosityExponent = 6;
154         fss->gravx = 0.0;
155         fss->gravy = 0.0;
156         fss->gravz = -9.81;
157         fss->animStart = 0.0; 
158         fss->animEnd = 0.30;
159         fss->gstar = 0.005; // used as normgstar
160         fss->maxRefine = -1;
161         // maxRefine is set according to resolutionxyz during bake
162
163         // fluid settings
164         fss->iniVelx = 
165         fss->iniVely = 
166         fss->iniVelz = 0.0;
167
168         strcpy(fss->surfdataDir,"//"); // current dir
169         // fss->surfdataPrefix take from .blend filename
170         strcpy(blendDir, G.sce);
171         BLI_splitdirstring(blendDir, blendFile);
172         snprintf(fss->surfdataPrefix,FILE_MAXFILE,"%s_%s", blendFile, srcob->id.name);
173         
174         fss->orgMesh = (Mesh *)srcob->data;
175         return fss;
176 }
177
178 /* free struct */
179 void fluidsimSettingsFree(FluidsimSettings *fss)
180 {
181         MEM_freeN(fss);
182 }
183
184
185 /* helper function */
186 void getGeometryObjFilename(struct Object *ob, char *dst, char *srcname) {
187         snprintf(dst,FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
188 }
189
190
191 /* ********************** simulation thread             ************************* */
192 SDL_mutex       *globalBakeLock=NULL;
193 int                     globalBakeState = 0; // 0 everything ok, -1 abort simulation, 1 sim done
194 int                     globalBakeFrame = 0;
195
196 // run simulation in seperate thread
197 int simulateThread(void *ptr) {
198         char* fnameCfgPath = (char*)(ptr);
199         int ret;
200         
201         ret = performElbeemSimulation(fnameCfgPath);
202         SDL_mutexP(globalBakeLock);
203         globalBakeState = 1;
204         SDL_mutexV(globalBakeLock);
205         return ret;
206 }
207
208 // called by simulation to set frame no.
209 void simulateThreadIncreaseFrame(void) {
210         if(!globalBakeLock) return;
211         if(globalBakeState<0) return; // this means abort...
212         SDL_mutexP(globalBakeLock);
213         globalBakeFrame++;
214         SDL_mutexV(globalBakeLock);
215 }
216
217 /* ********************** write fluidsim config to file ************************* */
218 void fluidsimBake(struct Object *ob)
219 {
220         char fnameCfg[FILE_MAXFILE], fnameCfgPath[FILE_MAXFILE+FILE_MAXDIR];
221         FILE *fileCfg;
222         struct Object *fsDomain = NULL;
223         FluidsimSettings *fssDomain;
224         struct Object *obit = NULL; /* object iterator */
225         int origFrame = G.scene->r.cfra;
226         char blendDir[FILE_MAXDIR], blendFile[FILE_MAXFILE];
227         char curWd[FILE_MAXDIR];
228         char debugStrBuffer[256];
229         int dirExist = 0;
230         const int maxRes = 200;
231         int gridlevels = 0;
232
233         const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
234
235         // test section
236         // int nr= pupmenu("Continue?%t|Yes%x1|No%x0");
237         // if(nr==0) return;
238
239         if(getenv(strEnvName)) {
240                 int dlevel = atoi(getenv(strEnvName));
241                 elbeemSetDebugLevel(dlevel);
242                 //if((dlevel>0) && (dlevel<=10)) debugBake = 1;
243                 snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to  envvar '%s'\n",strEnvName); 
244                 elbeemDebugOut(debugStrBuffer);
245         }
246
247         /* check if there's another domain... */
248         for(obit= G.main->object.first; obit; obit= obit->id.next) {
249                 if((obit->fluidsimFlag & OB_FLUIDSIM_ENABLE)&&(obit->type==OB_MESH)) {
250                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_DOMAIN) {
251                                 if(obit != ob) {
252                                         snprintf(debugStrBuffer,256,"fluidsimBake::warning - More than one domain!\n"); 
253                                         elbeemDebugOut(debugStrBuffer);
254                                 }
255                         }
256                 }
257         }
258         /* these both have to be valid, otherwise we wouldnt be here...*/
259         fsDomain = ob;
260         fssDomain = ob->fluidsimSettings;
261         /* rough check of settings... */
262         if(fssDomain->resolutionxyz>maxRes) {
263                 fssDomain->resolutionxyz = maxRes;
264                 snprintf(debugStrBuffer,256,"fluidsimBake::warning - Resolution (%d) > %d^3, this requires more than 600MB of memory... restricting to %d^3 for now.\n",  fssDomain->resolutionxyz, maxRes, maxRes); 
265                 elbeemDebugOut(debugStrBuffer);
266         }
267         if(fssDomain->previewresxyz > fssDomain->resolutionxyz) {
268                 snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", fssDomain->previewresxyz ,  fssDomain->resolutionxyz); 
269                 elbeemDebugOut(debugStrBuffer);
270                 fssDomain->previewresxyz = fssDomain->resolutionxyz;
271         }
272         // set adaptive coarsening according to resolutionxyz
273         // this should do as an approximation, with in/outflow
274         // doing this more accurate would be overkill
275         // perhaps add manual setting?
276         if(fssDomain->maxRefine <0) {
277                 if(fssDomain->resolutionxyz>128) {
278                         gridlevels = 2;
279                 } else
280                 if(fssDomain->resolutionxyz>64) {
281                         gridlevels = 1;
282                 } else {
283                         gridlevels = 0;
284                 }
285         } else {
286                 gridlevels = fssDomain->maxRefine;
287         }
288         snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); 
289         elbeemDebugOut(debugStrBuffer);
290         
291
292         // prepare names...
293         strcpy(curWd, G.sce);
294         BLI_splitdirstring(curWd, blendFile);
295         if(strlen(curWd)<1) {
296                 BLI_getwdN(curWd);
297         }
298         if(strlen(fsDomain->fluidsimSettings->surfdataPrefix)<1) {
299                 // make new from current .blend filename , and domain object name
300                 strcpy(blendDir, G.sce);
301                 BLI_splitdirstring(blendDir, blendFile);
302                 // todo... strip .blend 
303                 snprintf(fsDomain->fluidsimSettings->surfdataPrefix,FILE_MAXFILE,"%s_%s", blendFile, fsDomain->id.name);
304                 snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output prefix to '%s'\n", fsDomain->fluidsimSettings->surfdataPrefix); 
305                 elbeemDebugOut(debugStrBuffer);
306         }
307
308         // check selected directory
309 #ifdef WIN32
310         // windows workaroung because stat seems to be broken...
311         // simply try to open cfg file for writing
312         snprintf(fnameCfg,FILE_MAXFILE,"%s.cfg", fsDomain->fluidsimSettings->surfdataPrefix);
313         BLI_make_file_string(curWd, fnameCfgPath, fsDomain->fluidsimSettings->surfdataDir, fnameCfg);
314         fileCfg = fopen(fnameCfgPath, "w");
315         if(fileCfg) {
316                 dirExist = 1;
317                 fclose(fileCfg);
318         }
319 #else // WIN32
320         BLI_make_file_string(curWd, fnameCfgPath, fsDomain->fluidsimSettings->surfdataDir, "");
321         if(S_ISDIR(BLI_exist(fnameCfgPath))) dirExist = 1;
322 #endif // WIN32
323
324         if((strlen(fsDomain->fluidsimSettings->surfdataDir)<1) || (!dirExist)) {
325                 // invalid dir, reset to current
326                 strcpy(fsDomain->fluidsimSettings->surfdataDir, "//");
327                 snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", fsDomain->fluidsimSettings->surfdataDir);
328                 elbeemDebugOut(debugStrBuffer);
329         }
330         
331         // dump data for frame 0
332   G.scene->r.cfra = 0;
333   scene_update_for_newframe(G.scene, G.scene->lay);
334
335         snprintf(fnameCfg,FILE_MAXFILE,"%s.cfg", fsDomain->fluidsimSettings->surfdataPrefix);
336         BLI_make_file_string(curWd, fnameCfgPath, fsDomain->fluidsimSettings->surfdataDir, fnameCfg);
337
338         // start writing
339         fileCfg = fopen(fnameCfgPath, "w");
340         if(!fileCfg) {
341                 snprintf(debugStrBuffer,256,"fluidsimBake::error - Unable to open file for writing '%s'\n", fnameCfgPath); 
342                 elbeemDebugOut(debugStrBuffer);
343                 return;
344         }
345
346         fprintf(fileCfg, "# Blender ElBeem File , Source %s , Frame %d, to %s \n\n\n", G.sce, -1, fnameCfg );
347
348         // FIXME set aniframetime from no. frames and duration
349         /* output simulation  settings */
350         {
351                 int noFrames = G.scene->r.efra - G.scene->r.sfra;
352                 double calcViscosity = 0.0;
353                 double animFrameTime = (fssDomain->animEnd - fssDomain->animStart)/(double)noFrames;
354                 char *simString = "\n"
355                 "attribute \"simulation1\" { \n" 
356                 
357                 "  p_domainsize  = " "%f" /* 0 realsize */ "; \n" 
358                 "  p_anistart    = " "%f" /* 1 aniStart*/ "; #cfgset \n" 
359                 "  p_aniframetime = " "%f" /* 2 aniFrameTime*/ "; #cfgset \n" 
360                 "  solver = \"fsgr\"; \n"  "\n" 
361                 "  initsurfsmooth = 0; \n"  "\n" 
362                 "  debugvelscale = 0.005; \n"  "\n" 
363                 "  isovalue =  0.4900; \n" 
364                 "  isoweightmethod = 1; \n"  "\n" 
365                 "  disable_stfluidinit = 0; \n"  "\n" 
366                 
367                 "  geoinit   = 1; \n" 
368                 "  geoinitid = 1;  \n"  "\n" 
369                 "  p_gravity = " "%f %f %f" /* 3,4,5 pGravity*/ "; #cfgset \n"  "\n" 
370                 
371                 "  timeadap = 1;  \n" 
372                 "  p_tadapmaxomega = 2.0; \n" 
373                 "  p_normgstar = %f; \n"  /* 6b use gstar param? */
374                 "  p_viscosity = " "%f" /* 7 pViscosity*/ "; #cfgset \n"  "\n" 
375                 
376                 "  maxrefine = " "%d" /* 8 maxRefine*/ "; #cfgset  \n" 
377                 "  size = " "%d" /* 9 gridSize*/ "; #cfgset  \n" 
378                 "  surfacepreview = " "%d" /* 10 previewSize*/ "; #cfgset \n" 
379                 "  smoothsurface = 1.0;  \n"
380                 "\n" 
381                 //"  //forcetadaprefine = 0; maxrefine = 0; \n" 
382                 "} \n" ;
383     
384                 if(fssDomain->viscosityMode==1) {
385                         /* manual mode */
386                         calcViscosity = (1.0/(fssDomain->viscosityExponent*10)) * fssDomain->viscosityValue;
387                 } else {
388                         calcViscosity = fluidsimViscosityPreset[ fssDomain->viscosityMode ];
389                 }
390                 fprintf(fileCfg, simString,
391                                 (double)fssDomain->realsize, 
392                                 (double)fssDomain->animStart, animFrameTime ,
393                                 (double)fssDomain->gravx, (double)fssDomain->gravy, (double)fssDomain->gravz,
394                                 (double)fssDomain->gstar,
395                                 calcViscosity,
396                                 gridlevels, (int)fssDomain->resolutionxyz, (int)fssDomain->previewresxyz 
397                                 );
398         }
399
400         // output blender object transformation
401         {
402                 float domainMat[4][4];
403                 float invDomMat[4][4];
404                 char* blendattrString = "\n" 
405                         "attribute \"btrafoattr\" { \n"
406                         "  transform = %f %f %f %f   "
407                                    "   %f %f %f %f   "
408                                    "   %f %f %f %f   "
409                                    "   %f %f %f %f ;\n"
410                         "} \n";
411
412                 MTC_Mat4CpyMat4(domainMat, fsDomain->obmat);
413                 if(!Mat4Invert(invDomMat, domainMat)) {
414                         snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); 
415                         elbeemDebugOut(debugStrBuffer);
416                         // FIXME add fatal msg
417                         return;
418                 }
419
420                 fprintf(fileCfg, blendattrString,
421                                 invDomMat[0][0],invDomMat[1][0],invDomMat[2][0],invDomMat[3][0], 
422                                 invDomMat[0][1],invDomMat[1][1],invDomMat[2][1],invDomMat[3][1], 
423                                 invDomMat[0][2],invDomMat[1][2],invDomMat[2][2],invDomMat[3][2], 
424                                 invDomMat[0][3],invDomMat[1][3],invDomMat[2][3],invDomMat[3][3] );
425         }
426
427
428
429         fprintf(fileCfg, "raytracing {\n");
430
431         /* output picture settings for preview renders */
432         {
433                 char *rayString = "\n" 
434                         "  anistart=     0; \n" 
435                         "  aniframes=    " "%d" /*1 frameEnd-frameStart+0*/ "; #cfgset \n" 
436                         "  frameSkip=    false; \n" 
437                         "  filename=     \"" "%s" /* rayPicFilename*/  "\"; #cfgset \n" 
438                         "  aspect      1.0; \n" 
439                         "  resolution  " "%d %d" /*2,3 blendResx,blendResy*/ "; #cfgset \n" 
440                         "  antialias       1; \n" 
441                         "  ambientlight    (1, 1, 1); \n" 
442                         "  maxRayDepth       6; \n" 
443                         "  treeMaxDepth     25; \n" 
444                         "  treeMaxTriangles  8; \n" 
445                         "  background  (0.08,  0.08, 0.20); \n" 
446                         "  eyepoint= (" "%f %f %f"/*4,5,6 eyep*/ "); #cfgset  \n" 
447                         "  lookat= (" "%f %f %f"/*7,8,9 lookatp*/ "); #cfgset  \n" 
448                         "  upvec= (0 0 1);  \n" 
449                         "  fovy=  " "%f" /*blendFov*/ "; #cfgset \n" 
450                         "  blenderattr= \"btrafoattr\"; \n"
451                         "\n\n";
452
453                 char *lightString = "\n" 
454                         "  light { \n" 
455                         "    type= omni; \n" 
456                         "    active=     1; \n" 
457                         "    color=      (1.0,  1.0,  1.0); \n" 
458                         "    position=   (" "%f %f %f"/*1,2,3 eyep*/ "); #cfgset \n" 
459                         "    castShadows= 1; \n"  
460                         "  } \n\n" ;
461
462                 int noFrames = (G.scene->r.efra - G.scene->r.sfra) +1; // FIXME - check no. of frames...
463                 struct Object *cam = G.scene->camera;
464                 float  eyex=2.0, eyey=2.0, eyez=2.0;
465                 int    resx = 200, resy=200;
466                 float  lookatx=0.0, lookaty=0.0, lookatz=0.0;
467                 float  fov = 45.0;
468                 char   fnamePreview[FILE_MAXFILE];
469                 char   fnamePreviewPath[FILE_MAXFILE+FILE_MAXDIR];
470
471                 snprintf(fnamePreview,FILE_MAXFILE,"%s_surface", fsDomain->fluidsimSettings->surfdataPrefix );
472                 BLI_make_file_string(curWd, fnamePreviewPath, fsDomain->fluidsimSettings->surfdataDir, fnamePreview);
473                 resx = G.scene->r.xsch;
474                 resy = G.scene->r.ysch;
475                 if((cam) && (cam->type == OB_CAMERA)) {
476                         Camera *camdata= G.scene->camera->data;
477                         double lens = camdata->lens;
478                         double imgRatio = (double)resx/(double)resy;
479                         fov = 360.0 * atan(16.0*imgRatio/lens) / M_PI;
480                         //R.near= camdata->clipsta; R.far= camdata->clipend;
481
482                         eyex = cam->loc[0];
483                         eyey = cam->loc[1];
484                         eyez = cam->loc[2];
485                         // TODO - place lookat in middle of domain?
486                 }
487
488                 fprintf(fileCfg, rayString,
489                                 noFrames, fnamePreviewPath, resx,resy,
490                                 eyex, eyey, eyez ,
491                                 lookatx, lookaty, lookatz,
492                                 fov
493                                 );
494                 fprintf(fileCfg, lightString, 
495                                 eyex, eyey, eyez );
496         }
497
498
499         /* output fluid domain */
500         {
501                 float bbsx=0.0, bbsy=0.0, bbsz=0.0;
502                 float bbex=1.0, bbey=1.0, bbez=1.0;
503                 char * domainString = "\n" 
504                         "  geometry { \n" 
505                         "    type= fluidlbm; \n" 
506                         "    name = \""   "%s" /*name*/   "\"; #cfgset \n" 
507                         "    visible=  1; \n" 
508                         "    attributes=  \"simulation1\"; \n" 
509                         //"    define { material_surf  = \"fluidblue\"; } \n" 
510                         "    start= " "%f %f %f" /*bbstart*/ "; #cfgset \n" 
511                         "    end  = " "%f %f %f" /*bbend  */ "; #cfgset \n" 
512                         "  } \n" 
513                         "\n";
514                 Mesh *mesh = fsDomain->data; 
515                 //BoundBox *bb = fsDomain->bb;
516                 //if(!bb) { bb = mesh->bb; }
517                 //bb = NULL; // TODO test existing bounding box...
518
519                 //if(!bb && (mesh->totvert>0) ) 
520                 { 
521                         int i;
522                         float vec[3];
523                         VECCOPY(vec, mesh->mvert[0].co); 
524                         Mat4MulVecfl(fsDomain->obmat, vec);
525                         bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
526                         bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
527                         for(i=1; i<mesh->totvert;i++) {
528                                 VECCOPY(vec, mesh->mvert[i].co); /* get transformed point */
529                                 Mat4MulVecfl(fsDomain->obmat, vec);
530
531                                 if(vec[0] < bbsx){ bbsx= vec[0]; }
532                                 if(vec[1] < bbsy){ bbsy= vec[1]; }
533                                 if(vec[2] < bbsz){ bbsz= vec[2]; }
534                                 if(vec[0] > bbex){ bbex= vec[0]; }
535                                 if(vec[1] > bbey){ bbey= vec[1]; }
536                                 if(vec[2] > bbez){ bbez= vec[2]; }
537                         }
538                 }
539                 fprintf(fileCfg, domainString,
540                         fsDomain->id.name, 
541                         bbsx, bbsy, bbsz,
542                         bbex, bbey, bbez
543                 );
544         }
545
546     
547         /* setup geometry */
548         {
549                 char *objectStringStart = 
550                         "  geometry { \n" 
551                         "    type= objmodel; \n" 
552                         "    name = \""   "%s" /* name */   "\"; #cfgset \n" 
553                         // DEBUG , also obs invisible?
554                         "    visible=  0; \n" 
555                         "    define { \n" ;
556                 char *obstacleString = 
557                         "      geoinittype= \"" "%s" /* type */  "\"; #cfgset \n" 
558                         "      geoinit_intersect = 1; \n" 
559                         "      filename= \""   "%s" /* data  filename */  "\"; #cfgset \n" ;
560                 char *fluidString = 
561                         "      geoinittype= \"" "%s" /* type */  "\"; \n" 
562                         "      filename= \""   "%s" /* data  filename */  "\"; #cfgset \n" 
563                         "      initial_velocity= "   "%f %f %f" /* vel vector */  "; #cfgset \n" ;
564                 char *objectStringEnd = 
565                         "      geoinitid= 1; \n" 
566                         "    } \n" 
567                         "  } \n" 
568                         "\n" ;
569                 char fnameObjdat[FILE_MAXFILE];
570                 char bobjPath[FILE_MAXFILE+FILE_MAXDIR];
571         
572                 for(obit= G.main->object.first; obit; obit= obit->id.next) {
573                         //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG
574                         if( (obit->fluidsimFlag & OB_FLUIDSIM_ENABLE) && 
575                                         (obit->type==OB_MESH) &&
576                                   (obit->fluidsimSettings->type != OB_FLUIDSIM_DOMAIN)
577                                 ) {
578                                         getGeometryObjFilename(obit, fnameObjdat, fsDomain->fluidsimSettings->surfdataPrefix);
579                                         BLI_make_file_string(curWd, bobjPath, fsDomain->fluidsimSettings->surfdataDir, fnameObjdat);
580                                         fprintf(fileCfg, objectStringStart, obit->id.name ); // abs path
581                                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_FLUID) {
582                                                 fprintf(fileCfg, fluidString, "fluid", bobjPath, // do use absolute paths?
583                                                         (double)obit->fluidsimSettings->iniVelx, (double)obit->fluidsimSettings->iniVely, (double)obit->fluidsimSettings->iniVelz );
584                                         }
585                                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_INFLOW) {
586                                                 fprintf(fileCfg, fluidString, "inflow", bobjPath, // do use absolute paths?
587                                                         (double)obit->fluidsimSettings->iniVelx, (double)obit->fluidsimSettings->iniVely, (double)obit->fluidsimSettings->iniVelz );
588                                         }
589                                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_OUTFLOW) {
590                                                 fprintf(fileCfg, fluidString, "outflow", bobjPath, // do use absolute paths?
591                                                         (double)obit->fluidsimSettings->iniVelx, (double)obit->fluidsimSettings->iniVely, (double)obit->fluidsimSettings->iniVelz );
592                                         }
593                                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_OBSTACLE) {
594                                                 fprintf(fileCfg, obstacleString, "bnd_no" , bobjPath); // abs path
595                                         }
596                                         fprintf(fileCfg, objectStringEnd ); // abs path
597                                         writeBobjgz(bobjPath, obit);
598                         }
599                 }
600         }
601   
602         /* fluid material */
603         fprintf(fileCfg, 
604                 "  material { \n"
605                 "    type= phong; \n"
606                 "    name=          \"fluidblue\"; \n"
607                 "    diffuse=       0.3 0.5 0.9; \n"
608                 "    ambient=       0.1 0.1 0.1; \n"
609                 "    specular=      0.2  10.0; \n"
610                 "  } \n" );
611
612
613
614         fprintf(fileCfg, "} // end raytracing\n");
615         fclose(fileCfg);
616         snprintf(debugStrBuffer,256,"fluidsimBake::msg: Wrote %s\n", fnameCfg); 
617         elbeemDebugOut(debugStrBuffer);
618
619         // perform simulation
620         {
621                 SDL_Thread *simthr = NULL;
622                 globalBakeLock = SDL_CreateMutex();
623                 globalBakeState = 0;
624                 globalBakeFrame = 1;
625                 simthr = SDL_CreateThread(simulateThread, fnameCfgPath);
626 #ifndef WIN32
627                 // DEBUG for win32 debugging, dont use threads...
628 #endif // WIN32
629                 if(!simthr) {
630                         snprintf(debugStrBuffer,256,"fluidsimBake::error: Unable to create thread... running without one.\n"); 
631                         elbeemDebugOut(debugStrBuffer);
632                         set_timecursor(0);
633                         performElbeemSimulation(fnameCfgPath);
634                 } else {
635                         int done = 0;
636                         unsigned short event=0;
637                         short val;
638                         float noFramesf = G.scene->r.efra - G.scene->r.sfra +1;
639                         float percentdone = 0.0;
640                         int lastRedraw = -1;
641                         
642                         start_progress_bar();
643
644                         while(done==0) {            
645                                 char busy_mess[80];
646                                 
647                                 waitcursor(1);
648                                 
649                                 // lukep we add progress bar as an interim mesure
650                                 percentdone = globalBakeFrame / noFramesf;
651                                 sprintf(busy_mess, "baking fluids %d / %d       |||", globalBakeFrame, (int) noFramesf);
652                                 progress_bar(percentdone, busy_mess );
653                                 
654                                 SDL_Delay(2000); // longer delay to prevent frequent redrawing
655                                 SDL_mutexP(globalBakeLock);
656                                 if(globalBakeState == 1) done = 1;
657                                 SDL_mutexV(globalBakeLock);
658
659                                 while(qtest()) {
660                                         event = extern_qread(&val);
661                                         if(event == ESCKEY) {
662                                                 // abort...
663                                                 SDL_mutexP(globalBakeLock);
664                                                 done = -1;
665                                                 globalBakeFrame = 0;
666                                                 globalBakeState = -1;
667                                                 SDL_mutexV(globalBakeLock);
668                                                 break;
669                                         }
670                                 } 
671
672                                 // redraw the 3D for showing progress once in a while...
673                                 if(lastRedraw!=globalBakeFrame) {
674                                         ScrArea *sa;
675                                         G.scene->r.cfra = lastRedraw = globalBakeFrame;
676                                         update_for_newframe_muted();
677                                         sa= G.curscreen->areabase.first;
678                                         while(sa) {
679                                                 if(sa->spacetype == SPACE_VIEW3D) { scrarea_do_windraw(sa); }
680                                                 sa= sa->next;   
681                                         } 
682                                         screen_swapbuffers();
683                                 } // redraw
684                         }
685                         SDL_WaitThread(simthr,NULL);
686                         end_progress_bar();
687                 }
688                 SDL_DestroyMutex(globalBakeLock);
689                 globalBakeLock = NULL;
690         } // thread creation
691
692         // go back to "current" blender time
693         waitcursor(0);
694   G.scene->r.cfra = origFrame;
695   scene_update_for_newframe(G.scene, G.scene->lay);
696         allqueue(REDRAWVIEW3D, 0);
697         allqueue(REDRAWBUTSOBJECT, 0);
698 }
699
700