047cbc0a4f13d31b67b3c47a4dffb57fa078f940
[blender.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->dummy1 = 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.0; // unused FIXME remove? old=0.0005;
160         fss->maxRefine = 0;
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
232         const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
233         if(getenv(strEnvName)) {
234                 int dlevel = atoi(getenv(strEnvName));
235                 elbeemSetDebugLevel(dlevel);
236                 //if((dlevel>0) && (dlevel<=10)) debugBake = 1;
237                 snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to  envvar '%s'\n",strEnvName); 
238                 elbeemDebugOut(debugStrBuffer);
239         }
240
241         /* check if there's another domain... */
242         for(obit= G.main->object.first; obit; obit= obit->id.next) {
243                 if((obit->fluidsimFlag & OB_FLUIDSIM_ENABLE)&&(obit->type==OB_MESH)) {
244                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_DOMAIN) {
245                                 if(obit != ob) {
246                                         snprintf(debugStrBuffer,256,"fluidsimBake::warning - More than one domain!\n"); 
247                                         elbeemDebugOut(debugStrBuffer);
248                                 }
249                         }
250                 }
251         }
252         /* these both have to be valid, otherwise we wouldnt be here...*/
253         fsDomain = ob;
254         fssDomain = ob->fluidsimSettings;
255         /* rough check of settings... */
256         if(fssDomain->resolutionxyz>maxRes) {
257                 fssDomain->resolutionxyz = maxRes;
258                 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); 
259                 elbeemDebugOut(debugStrBuffer);
260         }
261         if(fssDomain->previewresxyz > fssDomain->resolutionxyz) {
262                 snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", fssDomain->previewresxyz ,  fssDomain->resolutionxyz); 
263                 elbeemDebugOut(debugStrBuffer);
264                 fssDomain->previewresxyz = fssDomain->resolutionxyz;
265         }
266         // set adaptive coarsening according to resolutionxyz
267         // this should do as an approximation, with in/outflow
268         // doing this more accurate would be overkill
269         // perhaps add manual setting?
270         if(fssDomain->resolutionxyz>128) {
271                 fssDomain->maxRefine = 2;
272         } else
273         if(fssDomain->resolutionxyz>64) {
274                 fssDomain->maxRefine = 1;
275         } else {
276                 fssDomain->maxRefine = 0;
277         }
278         snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , fssDomain->maxRefine ); 
279         elbeemDebugOut(debugStrBuffer);
280         
281         // prepare names...
282         strcpy(curWd, G.sce);
283         BLI_splitdirstring(curWd, blendFile);
284         if(strlen(curWd)<1) {
285                 BLI_getwdN(curWd);
286         }
287         if((strlen(fsDomain->fluidsimSettings->surfdataPrefix)<1) || (strlen(fsDomain->fluidsimSettings->surfdataDir)<1)){
288                 // make new from current .blend filename , and domain object name
289                 strcpy(blendDir, G.sce);
290                 BLI_splitdirstring(blendDir, blendFile);
291                 // todo... strip .blend 
292                 snprintf(fsDomain->fluidsimSettings->surfdataPrefix,FILE_MAXFILE,"%s_%s", blendFile, fsDomain->id.name);
293                 snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output prefix to '%s'\n", fsDomain->fluidsimSettings->surfdataPrefix); 
294                 elbeemDebugOut(debugStrBuffer);
295         }
296
297         // check selected directory
298 #ifdef WIN32
299         // windows workaroung because stat seems to be broken...
300         // simply try to open cfg file for writing
301         snprintf(fnameCfg,FILE_MAXFILE,"%s.cfg", fsDomain->fluidsimSettings->surfdataPrefix);
302         BLI_make_file_string(curWd, fnameCfgPath, fsDomain->fluidsimSettings->surfdataDir, fnameCfg);
303         fileCfg = fopen(fnameCfgPath, "w");
304         if(fileCfg) {
305                 dirExist = 1;
306                 fclose(fileCfg);
307         }
308 #else // WIN32
309         BLI_make_file_string(curWd, fnameCfgPath, fsDomain->fluidsimSettings->surfdataDir, "");
310         if(S_ISDIR(BLI_exist(fnameCfgPath))) dirExist = 1;
311 #endif // WIN32
312
313         if((strlen(fsDomain->fluidsimSettings->surfdataDir)<1) || (!dirExist)) {
314                 // invalid dir, reset to current
315                 strcpy(fsDomain->fluidsimSettings->surfdataDir, "//");
316                 snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", fsDomain->fluidsimSettings->surfdataDir);
317                 elbeemDebugOut(debugStrBuffer);
318         }
319         
320         // dump data for frame 0
321   G.scene->r.cfra = 0;
322   scene_update_for_newframe(G.scene, G.scene->lay);
323
324         snprintf(fnameCfg,FILE_MAXFILE,"%s.cfg", fsDomain->fluidsimSettings->surfdataPrefix);
325         BLI_make_file_string(curWd, fnameCfgPath, fsDomain->fluidsimSettings->surfdataDir, fnameCfg);
326
327         // start writing
328         fileCfg = fopen(fnameCfgPath, "w");
329         if(!fileCfg) {
330                 snprintf(debugStrBuffer,256,"fluidsimBake::error - Unable to open file for writing '%s'\n", fnameCfgPath); 
331                 elbeemDebugOut(debugStrBuffer);
332                 return;
333         }
334
335         fprintf(fileCfg, "# Blender ElBeem File , Source %s , Frame %d, to %s \n\n\n", G.sce, -1, fnameCfg );
336
337         // FIXME set aniframetime from no. frames and duration
338         /* output simulation  settings */
339         {
340                 int noFrames = G.scene->r.efra - G.scene->r.sfra;
341                 double calcViscosity = 0.0;
342                 double animFrameTime = (fssDomain->animEnd - fssDomain->animStart)/(double)noFrames;
343                 char *simString = "\n"
344                 "attribute \"simulation1\" { \n" 
345                 
346                 "  p_domainsize  = " "%f" /* 0 realsize */ "; \n" 
347                 "  p_anistart    = " "%f" /* 1 aniStart*/ "; #cfgset \n" 
348                 "  p_aniframetime = " "%f" /* 2 aniFrameTime*/ "; #cfgset \n" 
349                 "  solver = \"fsgr\"; \n"  "\n" 
350                 "  initsurfsmooth = 0; \n"  "\n" 
351                 "  debugvelscale = 0.005; \n"  "\n" 
352                 "  isovalue =  0.4900; \n" 
353                 "  isoweightmethod = 1; \n"  "\n" 
354                 "  disable_stfluidinit = 0; \n"  "\n" 
355                 
356                 "  geoinit   = 1; \n" 
357                 "  geoinitid = 1;  \n"  "\n" 
358                 "  p_gravity = " "%f %f %f" /* 3,4,5 pGravity*/ "; #cfgset \n"  "\n" 
359                 
360                 "  timeadap = 1;  \n" 
361                 "  p_tadapmaxomega = 2.0; \n" 
362                 "  p_normgstar = 0.005; \n"  // FIXME param?
363                 "  p_viscosity = " "%f" /* 7 pViscosity*/ "; #cfgset \n"  "\n" 
364                 
365                 "  maxrefine = " "%d" /* 8 maxRefine*/ "; #cfgset  \n" 
366                 "  size = " "%d" /* 9 gridSize*/ "; #cfgset  \n" 
367                 "  surfacepreview = " "%d" /* 10 previewSize*/ "; #cfgset \n" 
368                 "  smoothsurface = 1.0;  \n"
369                 "\n" 
370                 //"  //forcetadaprefine = 0; maxrefine = 0; \n" 
371                 "} \n" ;
372     
373                 if(fssDomain->viscosityMode==1) {
374                         /* manual mode */
375                         calcViscosity = (1.0/(fssDomain->viscosityExponent*10)) * fssDomain->viscosityValue;
376                 } else {
377                         calcViscosity = fluidsimViscosityPreset[ fssDomain->viscosityMode ];
378                 }
379                 fprintf(fileCfg, simString,
380                                 (double)fssDomain->realsize, 
381                                 (double)fssDomain->animStart, animFrameTime ,
382                                 (double)fssDomain->gravx, (double)fssDomain->gravy, (double)fssDomain->gravz,
383                                 calcViscosity,
384                                 (int)fssDomain->maxRefine, (int)fssDomain->resolutionxyz, (int)fssDomain->previewresxyz 
385                                 );
386         }
387
388         // output blender object transformation
389         {
390                 float domainMat[4][4];
391                 float invDomMat[4][4];
392                 char* blendattrString = "\n" 
393                         "attribute \"btrafoattr\" { \n"
394                         "  transform = %f %f %f %f   "
395                                    "   %f %f %f %f   "
396                                    "   %f %f %f %f   "
397                                    "   %f %f %f %f ;\n"
398                         "} \n";
399
400                 MTC_Mat4CpyMat4(domainMat, fsDomain->obmat);
401                 if(!Mat4Invert(invDomMat, domainMat)) {
402                         snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); 
403                         elbeemDebugOut(debugStrBuffer);
404                         // FIXME add fatal msg
405                         return;
406                 }
407
408                 fprintf(fileCfg, blendattrString,
409                                 invDomMat[0][0],invDomMat[1][0],invDomMat[2][0],invDomMat[3][0], 
410                                 invDomMat[0][1],invDomMat[1][1],invDomMat[2][1],invDomMat[3][1], 
411                                 invDomMat[0][2],invDomMat[1][2],invDomMat[2][2],invDomMat[3][2], 
412                                 invDomMat[0][3],invDomMat[1][3],invDomMat[2][3],invDomMat[3][3] );
413         }
414
415
416
417         fprintf(fileCfg, "raytracing {\n");
418
419         /* output picture settings for preview renders */
420         {
421                 char *rayString = "\n" 
422                         "  anistart=     0; \n" 
423                         "  aniframes=    " "%d" /*1 frameEnd-frameStart+0*/ "; #cfgset \n" 
424                         "  frameSkip=    false; \n" 
425                         "  filename=     \"" "%s" /* rayPicFilename*/  "\"; #cfgset \n" 
426                         "  aspect      1.0; \n" 
427                         "  resolution  " "%d %d" /*2,3 blendResx,blendResy*/ "; #cfgset \n" 
428                         "  antialias       1; \n" 
429                         "  ambientlight    (1, 1, 1); \n" 
430                         "  maxRayDepth       6; \n" 
431                         "  treeMaxDepth     25; \n" 
432                         "  treeMaxTriangles  8; \n" 
433                         "  background  (0.08,  0.08, 0.20); \n" 
434                         "  eyepoint= (" "%f %f %f"/*4,5,6 eyep*/ "); #cfgset  \n" 
435                         "  lookat= (" "%f %f %f"/*7,8,9 lookatp*/ "); #cfgset  \n" 
436                         "  upvec= (0 0 1);  \n" 
437                         "  fovy=  " "%f" /*blendFov*/ "; #cfgset \n" 
438                         "  blenderattr= \"btrafoattr\"; \n"
439                         "\n\n";
440
441                 char *lightString = "\n" 
442                         "  light { \n" 
443                         "    type= omni; \n" 
444                         "    active=     1; \n" 
445                         "    color=      (1.0,  1.0,  1.0); \n" 
446                         "    position=   (" "%f %f %f"/*1,2,3 eyep*/ "); #cfgset \n" 
447                         "    castShadows= 1; \n"  
448                         "  } \n\n" ;
449
450                 int noFrames = (G.scene->r.efra - G.scene->r.sfra) +1; // FIXME - check no. of frames...
451                 struct Object *cam = G.scene->camera;
452                 float  eyex=2.0, eyey=2.0, eyez=2.0;
453                 int    resx = 200, resy=200;
454                 float  lookatx=0.0, lookaty=0.0, lookatz=0.0;
455                 float  fov = 45.0;
456                 char   fnamePreview[FILE_MAXFILE];
457                 char   fnamePreviewPath[FILE_MAXFILE+FILE_MAXDIR];
458
459                 snprintf(fnamePreview,FILE_MAXFILE,"%s_surface", fsDomain->fluidsimSettings->surfdataPrefix );
460                 BLI_make_file_string(curWd, fnamePreviewPath, fsDomain->fluidsimSettings->surfdataDir, fnamePreview);
461                 resx = G.scene->r.xsch;
462                 resy = G.scene->r.ysch;
463                 if((cam) && (cam->type == OB_CAMERA)) {
464                         Camera *camdata= G.scene->camera->data;
465                         double lens = camdata->lens;
466                         double imgRatio = (double)resx/(double)resy;
467                         fov = 360.0 * atan(16.0*imgRatio/lens) / M_PI;
468                         //R.near= camdata->clipsta; R.far= camdata->clipend;
469
470                         eyex = cam->loc[0];
471                         eyey = cam->loc[1];
472                         eyez = cam->loc[2];
473                         // TODO - place lookat in middle of domain?
474                 }
475
476                 fprintf(fileCfg, rayString,
477                                 noFrames, fnamePreviewPath, resx,resy,
478                                 eyex, eyey, eyez ,
479                                 lookatx, lookaty, lookatz,
480                                 fov
481                                 );
482                 fprintf(fileCfg, lightString, 
483                                 eyex, eyey, eyez );
484         }
485
486
487         /* output fluid domain */
488         {
489                 float bbsx=0.0, bbsy=0.0, bbsz=0.0;
490                 float bbex=1.0, bbey=1.0, bbez=1.0;
491                 char * domainString = "\n" 
492                         "  geometry { \n" 
493                         "    type= fluidlbm; \n" 
494                         "    name = \""   "%s" /*name*/   "\"; #cfgset \n" 
495                         "    visible=  1; \n" 
496                         "    attributes=  \"simulation1\"; \n" 
497                         //"    define { material_surf  = \"fluidblue\"; } \n" 
498                         "    start= " "%f %f %f" /*bbstart*/ "; #cfgset \n" 
499                         "    end  = " "%f %f %f" /*bbend  */ "; #cfgset \n" 
500                         "  } \n" 
501                         "\n";
502                 Mesh *mesh = fsDomain->data; 
503                 //BoundBox *bb = fsDomain->bb;
504                 //if(!bb) { bb = mesh->bb; }
505                 //bb = NULL; // TODO test existing bounding box...
506
507                 //if(!bb && (mesh->totvert>0) ) 
508                 { 
509                         int i;
510                         float vec[3];
511                         VECCOPY(vec, mesh->mvert[0].co); 
512                         Mat4MulVecfl(fsDomain->obmat, vec);
513                         bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
514                         bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
515                         for(i=1; i<mesh->totvert;i++) {
516                                 VECCOPY(vec, mesh->mvert[i].co); /* get transformed point */
517                                 Mat4MulVecfl(fsDomain->obmat, vec);
518
519                                 if(vec[0] < bbsx){ bbsx= vec[0]; }
520                                 if(vec[1] < bbsy){ bbsy= vec[1]; }
521                                 if(vec[2] < bbsz){ bbsz= vec[2]; }
522                                 if(vec[0] > bbex){ bbex= vec[0]; }
523                                 if(vec[1] > bbey){ bbey= vec[1]; }
524                                 if(vec[2] > bbez){ bbez= vec[2]; }
525                         }
526                 }
527                 fprintf(fileCfg, domainString,
528                         fsDomain->id.name, 
529                         bbsx, bbsy, bbsz,
530                         bbex, bbey, bbez
531                 );
532         }
533
534     
535         /* setup geometry */
536         {
537                 char *objectStringStart = 
538                         "  geometry { \n" 
539                         "    type= objmodel; \n" 
540                         "    name = \""   "%s" /* name */   "\"; #cfgset \n" 
541                         // DEBUG , also obs invisible?
542                         "    visible=  0; \n" 
543                         "    define { \n" ;
544                 char *obstacleString = 
545                         "      geoinittype= \"" "%s" /* type */  "\"; #cfgset \n" 
546                         "      geoinit_intersect = 1; \n" 
547                         "      filename= \""   "%s" /* data  filename */  "\"; #cfgset \n" ;
548                 char *fluidString = 
549                         "      geoinittype= \"" "%s" /* type */  "\"; \n" 
550                         "      filename= \""   "%s" /* data  filename */  "\"; #cfgset \n" 
551                         "      initial_velocity= "   "%f %f %f" /* vel vector */  "; #cfgset \n" ;
552                 char *objectStringEnd = 
553                         "      geoinitid= 1; \n" 
554                         "    } \n" 
555                         "  } \n" 
556                         "\n" ;
557                 char fnameObjdat[FILE_MAXFILE];
558                 char bobjPath[FILE_MAXFILE+FILE_MAXDIR];
559         
560                 for(obit= G.main->object.first; obit; obit= obit->id.next) {
561                         //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG
562                         if( (obit->fluidsimFlag & OB_FLUIDSIM_ENABLE) && 
563                                         (obit->type==OB_MESH) &&
564                                   (obit->fluidsimSettings->type != OB_FLUIDSIM_DOMAIN)
565                                 ) {
566                                         getGeometryObjFilename(obit, fnameObjdat, fsDomain->fluidsimSettings->surfdataPrefix);
567                                         BLI_make_file_string(curWd, bobjPath, fsDomain->fluidsimSettings->surfdataDir, fnameObjdat);
568                                         fprintf(fileCfg, objectStringStart, obit->id.name ); // abs path
569                                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_FLUID) {
570                                                 fprintf(fileCfg, fluidString, "fluid", bobjPath, // do use absolute paths?
571                                                         (double)obit->fluidsimSettings->iniVelx, (double)obit->fluidsimSettings->iniVely, (double)obit->fluidsimSettings->iniVelz );
572                                         }
573                                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_OBSTACLE) {
574                                                 fprintf(fileCfg, obstacleString, "bnd_no" , bobjPath); // abs path
575                                         }
576                                         fprintf(fileCfg, objectStringEnd ); // abs path
577                                         writeBobjgz(bobjPath, obit);
578                         }
579                 }
580         }
581   
582         /* fluid material */
583         fprintf(fileCfg, 
584                 "  material { \n"
585                 "    type= phong; \n"
586                 "    name=          \"fluidblue\"; \n"
587                 "    diffuse=       0.3 0.5 0.9; \n"
588                 "    ambient=       0.1 0.1 0.1; \n"
589                 "    specular=      0.2  10.0; \n"
590                 "  } \n" );
591
592
593
594         fprintf(fileCfg, "} // end raytracing\n");
595         fclose(fileCfg);
596         snprintf(debugStrBuffer,256,"fluidsimBake::msg: Wrote %s\n", fnameCfg); 
597         elbeemDebugOut(debugStrBuffer);
598
599         // perform simulation
600         {
601                 SDL_Thread *simthr = NULL;
602                 globalBakeLock = SDL_CreateMutex();
603                 globalBakeState = 0;
604                 globalBakeFrame = 1;
605                 simthr = SDL_CreateThread(simulateThread, fnameCfgPath);
606 #ifndef WIN32
607                 // DEBUG for win32 debugging, dont use threads...
608 #endif // WIN32
609                 if(!simthr) {
610                         snprintf(debugStrBuffer,256,"fluidsimBake::error: Unable to create thread... running without one.\n"); 
611                         elbeemDebugOut(debugStrBuffer);
612                         set_timecursor(0);
613                         performElbeemSimulation(fnameCfgPath);
614                 } else {
615                         int done = 0;
616                         unsigned short event=0;
617                         short val;
618                         float noFramesf = G.scene->r.efra - G.scene->r.sfra;
619                         float percentdone = 0.0;
620                         int lastRedraw = -1;
621                         
622                         start_progress_bar();
623
624                         while(done==0) {            
625                                 char busy_mess[80];
626                                 
627                                 waitcursor(1);
628                                 
629                                 // lukep we add progress bar as an interim mesure
630                                 percentdone = globalBakeFrame / noFramesf;
631                                 sprintf(busy_mess, "baking fluids %d / %d       |||", globalBakeFrame, (int) noFramesf);
632                                 progress_bar(percentdone, busy_mess );
633                                 
634                                 SDL_Delay(2000); // longer delay to prevent frequent redrawing
635                                 SDL_mutexP(globalBakeLock);
636                                 if(globalBakeState == 1) done = 1;
637                                 SDL_mutexV(globalBakeLock);
638
639                                 while(qtest()) {
640                                         event = extern_qread(&val);
641                                         if(event == ESCKEY) {
642                                                 // abort...
643                                                 SDL_mutexP(globalBakeLock);
644                                                 done = -1;
645                                                 globalBakeFrame = 0;
646                                                 globalBakeState = -1;
647                                                 SDL_mutexV(globalBakeLock);
648                                                 break;
649                                         }
650                                 } 
651
652                                 // redraw the 3D for showing progress once in a while...
653                                 if(lastRedraw!=globalBakeFrame) {
654                                         ScrArea *sa;
655                                         G.scene->r.cfra = lastRedraw = globalBakeFrame;
656                                         update_for_newframe_muted();
657                                         sa= G.curscreen->areabase.first;
658                                         while(sa) {
659                                                 if(sa->spacetype == SPACE_VIEW3D) { scrarea_do_windraw(sa); }
660                                                 sa= sa->next;   
661                                         } 
662                                         screen_swapbuffers();
663                                 } // redraw
664                         }
665                         SDL_WaitThread(simthr,NULL);
666                         end_progress_bar();
667                 }
668                 SDL_DestroyMutex(globalBakeLock);
669                 globalBakeLock = NULL;
670         } // thread creation
671
672         // go back to "current" blender time
673         waitcursor(0);
674   G.scene->r.cfra = origFrame;
675   scene_update_for_newframe(G.scene, G.scene->lay);
676         allqueue(REDRAWVIEW3D, 0);
677         allqueue(REDRAWBUTSOBJECT, 0);
678 }
679
680