The occosional warning cleanup;
[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 #include "DNA_space_types.h"
56 #include "DNA_ipo_types.h"
57 #include "DNA_key_types.h" 
58
59 #include "BLI_blenlib.h"
60 #include "BLI_arithb.h"
61 #include "MTC_matrixops.h"
62
63 #include "BKE_displist.h"
64 #include "BKE_effect.h"
65 #include "BKE_global.h"
66 #include "BKE_main.h"
67 #include "BKE_key.h"
68 #include "BKE_scene.h"
69 #include "BKE_object.h"
70 #include "BKE_softbody.h"
71 #include "BKE_utildefines.h"
72 #include "BKE_DerivedMesh.h"
73 #include "BKE_ipo.h"
74 #include "LBM_fluidsim.h"
75 // warning - double elbeem.h in intern/extern...
76 #include "elbeem.h"
77
78 #include "BLI_editVert.h"
79 #include "BIF_editdeform.h"
80 #include "BIF_gl.h"
81 #include "BIF_screen.h"
82 #include "BIF_space.h"
83 #include "BIF_cursors.h"
84 #include "BIF_interface.h"
85 #include "BSE_headerbuttons.h"
86
87 #include "mydevice.h"
88 #include "blendef.h"
89 #include "SDL.h"
90 #include "SDL_thread.h"
91 #include "SDL_mutex.h"
92 #include <sys/stat.h>
93
94 #ifdef WIN32    /* Windos */
95 //#include "BLI_winstuff.h"
96 #ifndef snprintf
97 #define snprintf _snprintf
98 #endif
99 #endif
100 // SDL redefines main for SDL_main, not needed here...
101 #undef main
102
103 #ifdef __APPLE__        /* MacOS X */
104 #undef main
105 #endif
106
107 // from DerivedMesh.c
108 void initElbeemMesh(struct Object *ob, int *numVertices, float **vertices, int *numTriangles, int **triangles, int useGlobalCoords);
109
110 /* from header info.c */
111 extern int start_progress_bar(void);
112 extern void end_progress_bar(void);
113 extern int progress_bar(float done, char *busy_info);
114
115 double fluidsimViscosityPreset[6] = {
116         -1.0,   /* unused */
117         -1.0,   /* manual */
118         1.0e-6, /* water */
119         5.0e-5, /* some (thick) oil */
120         2.0e-3, /* ca. honey */
121         -1.0    /* end */
122 };
123
124 char* fluidsimViscosityPresetString[6] = {
125         "UNUSED",       /* unused */
126         "UNUSED",       /* manual */
127         "  = 1.0 * 10^-6", /* water */
128         "  = 5.0 * 10^-5", /* some (thick) oil */
129         "  = 2.0 * 10^-3", /* ca. honey */
130         "INVALID"       /* end */
131 };
132
133 typedef struct {
134         DerivedMesh dm;
135
136         // similar to MeshDerivedMesh
137         struct Object *ob;      // pointer to parent object
138         float *extverts, *nors; // face normals, colors?
139         Mesh *fsmesh;   // mesh struct to display (either surface, or original one)
140         char meshFree;  // free the mesh afterwards? (boolean)
141 } fluidsimDerivedMesh;
142
143
144
145 /* enable/disable overall compilation */
146 #ifndef DISABLE_ELBEEM
147
148
149 /* ********************** fluid sim settings struct functions ********************** */
150
151 /* allocates and initializes general main data */
152 FluidsimSettings *fluidsimSettingsNew(struct Object *srcob)
153 {
154         //char blendDir[FILE_MAXDIR], blendFile[FILE_MAXFILE];
155         FluidsimSettings *fss;
156         
157         /* this call uses derivedMesh methods... */
158         if(srcob->type!=OB_MESH) return NULL;
159         
160         fss= MEM_callocN( sizeof(FluidsimSettings), "fluidsimsettings memory");
161         
162         fss->type = 0;
163         fss->show_advancedoptions = 0;
164
165         fss->resolutionxyz = 50;
166         fss->previewresxyz = 25;
167         fss->realsize = 0.03;
168         fss->guiDisplayMode = 2; // preview
169         fss->renderDisplayMode = 3; // render
170
171         fss->viscosityMode = 2; // default to water
172         fss->viscosityValue = 1.0;
173         fss->viscosityExponent = 6;
174         fss->gravx = 0.0;
175         fss->gravy = 0.0;
176         fss->gravz = -9.81;
177         fss->animStart = 0.0; 
178         fss->animEnd = 0.30;
179         fss->gstar = 0.005; // used as normgstar
180         fss->maxRefine = -1;
181         // maxRefine is set according to resolutionxyz during bake
182
183         // fluid/inflow settings
184         fss->iniVelx = 
185         fss->iniVely = 
186         fss->iniVelz = 0.0;
187
188         strcpy(fss->surfdataPath,""); // leave blank, init upon first bake
189         fss->orgMesh = (Mesh *)srcob->data;
190         fss->meshSurface = NULL;
191         fss->meshBB = NULL;
192         fss->meshSurfNormals = NULL;
193
194         // first init of bounding box
195         fss->bbStart[0] = 0.0;
196         fss->bbStart[1] = 0.0;
197         fss->bbStart[2] = 0.0;
198         fss->bbSize[0] = 1.0;
199         fss->bbSize[1] = 1.0;
200         fss->bbSize[2] = 1.0;
201         fluidsimGetAxisAlignedBB(srcob->data, srcob->obmat, fss->bbStart, fss->bbSize, &fss->meshBB);
202         
203         // todo - reuse default init from elbeem!
204         fss->typeFlags = 0;
205         fss->domainNovecgen = 0;
206         fss->volumeInitType = 1; // volume
207         fss->partSlipValue = 0.0;
208
209         fss->generateTracers = 0;
210         fss->generateParticles = 0.0;
211         fss->surfaceSmoothing = 1.0;
212         fss->surfaceSubdivs = 1.0;
213         fss->particleInfSize = 0.0;
214         fss->particleInfAlpha = 0.0;
215
216         return fss;
217 }
218
219 /* duplicate struct, analogous to free */
220 FluidsimSettings* fluidsimSettingsCopy(FluidsimSettings *fss)
221 {
222         FluidsimSettings *dupfss;
223         Mesh *dupFsMesh = NULL;
224
225         if(!fss) return NULL;
226         dupfss = MEM_dupallocN(fss);
227
228         dupFsMesh = fss->meshSurface;
229         if(dupFsMesh) {
230                 dupfss->meshSurface = MEM_dupallocN(dupFsMesh);
231                 if(dupFsMesh->mvert) dupfss->meshSurface->mvert = MEM_dupallocN(dupFsMesh->mvert);
232                 if(dupFsMesh->medge) dupfss->meshSurface->medge = MEM_dupallocN(dupFsMesh->medge);
233                 if(dupFsMesh->mface) dupfss->meshSurface->mface = MEM_dupallocN(dupFsMesh->mface);
234         }
235
236         dupFsMesh = fss->meshBB;
237         if(dupFsMesh) {
238                 dupfss->meshBB = MEM_dupallocN(dupFsMesh);
239                 if(dupFsMesh->mvert) dupfss->meshBB->mvert = MEM_dupallocN(dupFsMesh->mvert);
240                 if(dupFsMesh->medge) dupfss->meshBB->medge = MEM_dupallocN(dupFsMesh->medge);
241                 if(dupFsMesh->mface) dupfss->meshBB->mface = MEM_dupallocN(dupFsMesh->mface);
242         }
243
244         if(fss->meshSurfNormals) dupfss->meshSurfNormals = MEM_dupallocN(fss->meshSurfNormals);
245
246         return dupfss;
247 }
248
249
250 /* free struct */
251 void fluidsimSettingsFree(FluidsimSettings *fss)
252 {
253         Mesh *freeFsMesh = fss->meshSurface;
254         if(freeFsMesh) {
255                 if(freeFsMesh->mvert){ MEM_freeN(freeFsMesh->mvert); freeFsMesh->mvert=NULL; }
256                 if(freeFsMesh->medge){ MEM_freeN(freeFsMesh->medge); freeFsMesh->medge=NULL; }
257                 if(freeFsMesh->mface){ MEM_freeN(freeFsMesh->mface); freeFsMesh->mface=NULL; }
258                 MEM_freeN(freeFsMesh);
259                 fss->meshSurface = NULL;
260         }
261
262         freeFsMesh = fss->meshBB;
263         if(freeFsMesh) { // same as before...
264                 if(freeFsMesh->mvert){ MEM_freeN(freeFsMesh->mvert); freeFsMesh->mvert=NULL; }
265                 if(freeFsMesh->medge){ MEM_freeN(freeFsMesh->medge); freeFsMesh->medge=NULL; }
266                 if(freeFsMesh->mface){ MEM_freeN(freeFsMesh->mface); freeFsMesh->mface=NULL; }
267                 MEM_freeN(freeFsMesh);
268                 fss->meshBB = NULL;
269         }
270
271         if(fss->meshSurfNormals){ MEM_freeN(fss->meshSurfNormals); fss->meshSurfNormals=NULL; } 
272
273         MEM_freeN(fss);
274 }
275
276
277 /* helper function */
278 void fluidsimGetGeometryObjFilename(struct Object *ob, char *dst) { //, char *srcname) {
279         //snprintf(dst,FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
280         snprintf(dst,FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name);
281 }
282
283
284
285
286 /* ******************************************************************************** */
287 /* ********************** fluid sim channel helper functions ********************** */
288 /* ******************************************************************************** */
289
290 // no. of entries for the two channel sizes
291 #define CHANNEL_FLOAT 1
292 #define CHANNEL_VEC   3
293
294 #define FS_FREE_ONECHANNEL(c,str) { \
295         if(c){ MEM_freeN(c); c=NULL; } \
296 } // end ONE CHANN, debug: fprintf(stderr,"freeing " str " \n"); 
297
298 #define FS_FREE_CHANNELS { \
299         FS_FREE_ONECHANNEL(timeAtIndex,"timeAtIndex");\
300         FS_FREE_ONECHANNEL(timeAtFrame,"timeAtFrame");\
301         FS_FREE_ONECHANNEL(channelDomainTime,"channelDomainTime"); \
302         FS_FREE_ONECHANNEL(channelDomainGravity,"channelDomainGravity");\
303         FS_FREE_ONECHANNEL(channelDomainViscosity,"channelDomainViscosity");\
304         for(i=0;i<256;i++) { \
305                 FS_FREE_ONECHANNEL(channelObjMove[i][0],"channelObjMove0"); \
306                 FS_FREE_ONECHANNEL(channelObjMove[i][1],"channelObjMove1"); \
307                 FS_FREE_ONECHANNEL(channelObjMove[i][2],"channelObjMove2"); \
308                 FS_FREE_ONECHANNEL(channelObjInivel[i],"channelObjInivel"); \
309                 FS_FREE_ONECHANNEL(channelObjActive[i],"channelObjActive"); \
310         }  \
311 } // end FS FREE CHANNELS
312
313
314 // simplify channels before printing
315 // for API this is done anyway upon init
316 #if 0
317 static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries) 
318
319         int i,j; 
320         int channelSize = paramsize; 
321
322         if(entries==3) {
323                 elbeemSimplifyChannelVec3( channel, &channelSize); 
324         } else if(entries==1) {
325                 elbeemSimplifyChannelFloat( channel, &channelSize); 
326         } else {
327                 // invalid, cant happen?
328         }
329
330         fprintf(file, "      CHANNEL %s = \n", str); 
331         for(i=0; i<channelSize;i++) { 
332                 fprintf(file,"        ");  
333                 for(j=0;j<=entries;j++) {  // also print time value
334                         fprintf(file," %f ", channel[i*(entries+1)+j] ); 
335                         if(j==entries-1){ fprintf(file,"  "); }
336                 } 
337                 fprintf(file," \n");  
338         } 
339
340         fprintf(file,  "      ; \n" ); 
341 }
342 #endif
343
344 static void fluidsimInitChannel(float **setchannel, int size, float *time, 
345                 int *icuIds, float *defaults, Ipo* ipo, int entries) {
346         int i,j;
347         IpoCurve* icus[3];
348         char *cstr = NULL;
349         float *channel = NULL;
350         float aniFrlen = G.scene->r.framelen;
351         if((entries<1) || (entries>3)) {
352                 printf("fluidsimInitChannel::Error - invalid no. of entries: %d\n",entries);
353                 entries = 1;
354         }
355
356         cstr = "fluidsiminit_channelfloat";
357         if(entries>1) cstr = "fluidsiminit_channelvec";
358         channel = MEM_callocN( size* (entries+1)* sizeof(float), cstr );
359         
360         if(ipo) {
361                 for(j=0; j<entries; j++) icus[j]  = find_ipocurve(ipo, icuIds[j] );
362         } else {
363                 for(j=0; j<entries; j++) icus[j]  = NULL; 
364         }
365         
366         for(j=0; j<entries; j++) {
367                 if(icus[j]) { 
368                         for(i=1; i<=size; i++) {
369                                 calc_icu(icus[j], aniFrlen*((float)i) );
370                                 channel[(i-1)*(entries+1) + j] = icus[j]->curval;
371                         }
372                 }  else {
373                         for(i=1; i<=size; i++) { channel[(i-1)*(entries+1) + j] = defaults[j]; }
374                 }
375                 //printf("fluidsimInitChannel entry:%d , ",j); for(i=1; i<=size; i++) { printf(" val%d:%f ",i, channel[(i-1)*(entries+1) + j] ); } printf(" \n"); // DEBUG
376         }
377         // set time values
378         for(i=1; i<=size; i++) {
379                 channel[(i-1)*(entries+1) + entries] = time[i];
380         }
381
382         *setchannel = channel;
383 }
384
385 static void fluidsimInitMeshChannel(float **setchannel, int size, Object *obm, int vertices, float *time) {
386         float *channel = NULL;
387         int mallsize = size* (3*vertices+1);
388         int frame,i;
389         int numVerts=0, numTris=0;
390         int setsize = 3*vertices+1;
391
392         channel = MEM_callocN( mallsize* sizeof(float), "fluidsim_meshchannel" );
393
394         //fprintf(stderr,"\n\nfluidsimInitMeshChannel size%d verts%d mallsize%d \n\n\n",size,vertices,mallsize);
395         for(frame=1; frame<=size; frame++) {
396                 float *verts=NULL;
397                 int *tris=NULL;
398                 G.scene->r.cfra = frame;
399                 scene_update_for_newframe(G.scene, G.scene->lay);
400
401                 initElbeemMesh(obm, &numVerts, &verts, &numTris, &tris, 1);
402                 //fprintf(stderr,"\nfluidsimInitMeshChannel frame%d verts%d/%d \n\n",frame,vertices,numVerts);
403                 for(i=0; i<3*vertices;i++) {
404                         channel[(frame-1)*setsize + i] = verts[i];
405                         //fprintf(stdout," frame%d vert%d=%f \n",frame,i,verts[i]);
406                         //if(i%3==2) fprintf(stdout,"\n");
407                 }
408                 channel[(frame-1)*setsize + setsize-1] = time[frame];
409
410                 MEM_freeN(verts);
411                 MEM_freeN(tris);
412         }
413         *setchannel = channel;
414 }
415
416
417 /* ******************************************************************************** */
418 /* ********************** simulation thread             ************************* */
419 /* ******************************************************************************** */
420
421 SDL_mutex       *globalBakeLock=NULL;
422 int                     globalBakeState = 0; // 0 everything ok, -1 abort simulation, -2 sim error, 1 sim done
423 int                     globalBakeFrame = 0;
424
425 // run simulation in seperate thread
426 static int fluidsimSimulateThread(void *unused) { // *ptr) {
427         //char* fnameCfgPath = (char*)(ptr);
428         int ret=0;
429         
430         ret = elbeemSimulate();
431         SDL_mutexP(globalBakeLock);
432         if(globalBakeState==0) {
433                 if(ret==0) {
434                         // if no error, set to normal exit
435                         globalBakeState = 1;
436                 } else {
437                         // simulation failed, display error
438                         globalBakeState = -2;
439                 }
440         }
441         SDL_mutexV(globalBakeLock);
442         return ret;
443 }
444
445 // called by simulation to set frame no.
446 // TODO deprecate...
447 void simulateThreadIncreaseFrame(void) {
448         /*if(!globalBakeLock) return;
449         if(globalBakeState!=0) return; // this means abort...
450         SDL_mutexP(globalBakeLock);
451         globalBakeFrame++;
452         SDL_mutexV(globalBakeLock);*/
453 }
454
455 int runSimulationCallback(void *data, int status, int frame) {
456         //elbeemSimulationSettings *settings = (elbeemSimulationSettings*)data;
457         //printf("elbeem blender cb s%d, f%d, domainid:%d \n", status,frame, settings->domainId ); // DEBUG
458         
459         if(!globalBakeLock) return FLUIDSIM_CBRET_ABORT;
460         if(status==FLUIDSIM_CBSTATUS_NEWFRAME) {
461                 SDL_mutexP(globalBakeLock);
462                 globalBakeFrame = frame-1;
463                 SDL_mutexV(globalBakeLock);
464         }
465         
466         //if((frameCounter==3) && (!frameStop)) { frameStop=1; return 1; }
467                 
468         SDL_mutexP(globalBakeLock);
469         if(globalBakeState!=0) {
470                 return FLUIDSIM_CBRET_ABORT;
471         }
472         SDL_mutexV(globalBakeLock);
473         return FLUIDSIM_CBRET_CONTINUE;
474 }
475
476
477 /* ******************************************************************************** */
478 /* ********************** write fluidsim config to file ************************* */
479 /* ******************************************************************************** */
480
481 void fluidsimBake(struct Object *ob)
482 {
483         FILE *fileCfg;
484         int i;
485         struct Object *fsDomain = NULL;
486         FluidsimSettings *domainSettings;
487         struct Object *obit = NULL; /* object iterator */
488         int origFrame = G.scene->r.cfra;
489         char debugStrBuffer[256];
490         int dirExist = 0;
491         int gridlevels = 0;
492         int simAborted = 0; // was the simulation aborted by user?
493         int  doExportOnly = 0;
494         char *exportEnvStr = "BLENDER_ELBEEMEXPORTONLY";
495         const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
496         //char *channelNames[3] = { "translation","rotation","scale" };
497
498         char *suffixConfig = "fluidsim.cfg";
499         char *suffixSurface = "fluidsurface";
500         char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings
501         char targetDir[FILE_MAXDIR+FILE_MAXFILE];  // store & modify output settings
502         char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // temp. store filename from targetDir for access
503         int  outStringsChanged = 0;             // modified? copy back before baking
504         int  haveSomeFluid = 0;                 // check if any fluid objects are set
505
506         // config vars, inited before either export or run...
507         double calcViscosity = 0.0;
508         int noFrames;
509         double aniFrameTime;
510         float aniFrlen;
511         int   channelObjCount;
512         float *bbStart = NULL;
513         float *bbSize = NULL;
514         float domainMat[4][4];
515         float invDomMat[4][4];
516         // channel data
517         int   allchannelSize; // fixed by no. of frames
518         int   startFrame = 1;  // dont use G.scene->r.sfra here, always start with frame 1
519         // easy frame -> sim time calc
520         float *timeAtFrame=NULL, *timeAtIndex=NULL;
521         // domain
522         float *channelDomainTime = NULL;
523         float *channelDomainViscosity = NULL; 
524         float *channelDomainGravity = NULL;
525         // objects (currently max. 256 objs)
526         float *channelObjMove[256][3]; // object movments , 0=trans, 1=rot, 2=scale
527         float *channelObjInivel[256];    // initial velocities
528         float *channelObjActive[256];    // obj active channel
529
530         if(getenv(strEnvName)) {
531                 int dlevel = atoi(getenv(strEnvName));
532                 elbeemSetDebugLevel(dlevel);
533                 snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName); 
534                 elbeemDebugOut(debugStrBuffer);
535         }
536         if(getenv(exportEnvStr)) {
537                 doExportOnly = atoi(getenv(exportEnvStr));
538                 snprintf(debugStrBuffer,256,"fluidsimBake::msg: Exporting mode set to '%d' due to envvar '%s'\n",doExportOnly, exportEnvStr); 
539                 elbeemDebugOut(debugStrBuffer);
540         }
541
542         // make sure it corresponds to startFrame setting
543         // old: noFrames = G.scene->r.efra - G.scene->r.sfra +1;
544         noFrames = G.scene->r.efra - 0;
545         if(noFrames<=0) {
546                 pupmenu("Fluidsim Bake Error%t|No frames to export - check your animation range settings. Aborted%x0");
547                 return;
548         }
549
550         /* no object pointer, find in selected ones.. */
551         if(!ob) {
552                 Base *base;
553                 for(base=G.scene->base.first; base; base= base->next) {
554                         if ( ((base)->flag & SELECT) 
555                                         // ignore layer setting for now? && ((base)->lay & G.vd->lay) 
556                                  ) {
557                                 if((!ob)&&(base->object->fluidsimFlag & OB_FLUIDSIM_ENABLE)&&(base->object->type==OB_MESH)) {
558                                         if(base->object->fluidsimSettings->type == OB_FLUIDSIM_DOMAIN) {
559                                                 ob = base->object;
560                                         }
561                                 }
562                         }
563                 }
564                 // no domains found?
565                 if(!ob) return;
566         }
567
568         /* check if there's another domain... */
569         for(obit= G.main->object.first; obit; obit= obit->id.next) {
570                 if((obit->fluidsimFlag & OB_FLUIDSIM_ENABLE)&&(obit->type==OB_MESH)) {
571                         if(obit->fluidsimSettings->type == OB_FLUIDSIM_DOMAIN) {
572                                 if(obit != ob) {
573                                         //snprintf(debugStrBuffer,256,"fluidsimBake::warning - More than one domain!\n"); elbeemDebugOut(debugStrBuffer);
574                                         pupmenu("Fluidsim Bake Error%t|There should be only one domain object! Aborted%x0");
575                                         return;
576                                 }
577                         }
578                 }
579         }
580         /* these both have to be valid, otherwise we wouldnt be here */
581         /* dont use ob here after...*/
582         fsDomain = ob;
583         domainSettings = ob->fluidsimSettings;
584         ob = NULL;
585         /* rough check of settings... */
586         if(domainSettings->previewresxyz > domainSettings->resolutionxyz) {
587                 snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz ,  domainSettings->resolutionxyz); 
588                 elbeemDebugOut(debugStrBuffer);
589                 domainSettings->previewresxyz = domainSettings->resolutionxyz;
590         }
591         // set adaptive coarsening according to resolutionxyz
592         // this should do as an approximation, with in/outflow
593         // doing this more accurate would be overkill
594         // perhaps add manual setting?
595         if(domainSettings->maxRefine <0) {
596                 if(domainSettings->resolutionxyz>128) {
597                         gridlevels = 2;
598                 } else
599                 if(domainSettings->resolutionxyz>64) {
600                         gridlevels = 1;
601                 } else {
602                         gridlevels = 0;
603                 }
604         } else {
605                 gridlevels = domainSettings->maxRefine;
606         }
607         snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); 
608         elbeemDebugOut(debugStrBuffer);
609         
610         // check if theres any fluid
611         // abort baking if not...
612         for(obit= G.main->object.first; obit; obit= obit->id.next) {
613                 if( (obit->fluidsimFlag & OB_FLUIDSIM_ENABLE) && 
614                                 (obit->type==OB_MESH) && (
615                           (obit->fluidsimSettings->type == OB_FLUIDSIM_FLUID) ||
616                           (obit->fluidsimSettings->type == OB_FLUIDSIM_INFLOW) )
617                                 ) {
618                         haveSomeFluid = 1;
619                 }
620         }
621         if(!haveSomeFluid) {
622                 pupmenu("Fluidsim Bake Error%t|No fluid objects in scene... Aborted%x0");
623                 return;
624         }
625
626         // prepare names...
627         strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
628         strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR);
629         BLI_convertstringcode(targetDir, G.sce, 0); // fixed #frame-no 
630
631         strcpy(targetFile, targetDir);
632         strcat(targetFile, suffixConfig);
633         if(!doExportOnly) { strcat(targetFile,".tmp"); }  // dont overwrite/delete original file
634         // make sure all directories exist
635         // as the bobjs use the same dir, this only needs to be checked
636         // for the cfg output
637         BLI_make_existing_file(targetFile);
638
639         // check selected directory
640         // simply try to open cfg file for writing to test validity of settings
641         fileCfg = fopen(targetFile, "w");
642         if(fileCfg) { 
643                 dirExist = 1; fclose(fileCfg); 
644                 // remove cfg dummy from  directory test
645                 if(!doExportOnly) { BLI_delete(targetFile, 0,0); }
646         }
647
648         if((strlen(targetDir)<1) || (!dirExist)) {
649                 char blendDir[FILE_MAXDIR+FILE_MAXFILE], blendFile[FILE_MAXDIR+FILE_MAXFILE];
650                 // invalid dir, reset to current/previous
651                 strcpy(blendDir, G.sce);
652                 BLI_splitdirstring(blendDir, blendFile);
653                 if(strlen(blendFile)>6){
654                         int len = strlen(blendFile);
655                         if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&&
656                                         (blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){
657                                 blendFile[len-6] = '\0';
658                         }
659                 }
660                 // todo... strip .blend ?
661                 snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
662
663                 snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
664                 elbeemDebugOut(debugStrBuffer);
665                 outStringsChanged=1;
666         }
667
668         // check if modified output dir is ok
669         if(outStringsChanged) {
670                 char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256];
671                 int  selection=0;
672                 strcpy(dispmsg,"Output settings set to: '");
673                 strcat(dispmsg, newSurfdataPath);
674                 strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0");
675
676                 // ask user if thats what he/she wants...
677                 selection = pupmenu(dispmsg);
678                 if(selection<1) return; // 0 from menu, or -1 aborted
679                 strcpy(targetDir, newSurfdataPath);
680                 strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
681                 BLI_convertstringcode(targetDir, G.sce, 0); // fixed #frame-no 
682         }
683         
684         // --------------------------------------------------------------------------------------------
685         // dump data for start frame 
686         // CHECK more reasonable to number frames according to blender?
687         // dump data for frame 0
688   G.scene->r.cfra = startFrame;
689   scene_update_for_newframe(G.scene, G.scene->lay);
690         
691         // init common export vars for both file export and run
692         for(i=0; i<256; i++) {
693                 channelObjMove[i][0] = channelObjMove[i][1] = channelObjMove[i][2] = NULL;
694                 channelObjInivel[i] = NULL;
695                 channelObjActive[i] = NULL;
696         }
697         allchannelSize = G.scene->r.efra; // always use till last frame
698         aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames;
699         // blender specific - scale according to map old/new settings in anim panel:
700         aniFrlen = G.scene->r.framelen;
701         if(domainSettings->viscosityMode==1) {
702                 /* manual mode, visc=value/(10^-vexp) */
703                 calcViscosity = (1.0/pow(10.0,domainSettings->viscosityExponent)) * domainSettings->viscosityValue;
704         } else {
705                 calcViscosity = fluidsimViscosityPreset[ domainSettings->viscosityMode ];
706         }
707
708         bbStart = fsDomain->fluidsimSettings->bbStart; 
709         bbSize = fsDomain->fluidsimSettings->bbSize;
710         fluidsimGetAxisAlignedBB(fsDomain->data, fsDomain->obmat, bbStart, bbSize, &domainSettings->meshBB);
711
712         // always init
713         { int timeIcu[1] = { FLUIDSIM_TIME };
714                 float timeDef[1] = { 1. };
715                 int gravIcu[3] = { FLUIDSIM_GRAV_X, FLUIDSIM_GRAV_Y, FLUIDSIM_GRAV_Z };
716                 float gravDef[3];
717                 int viscIcu[1] = { FLUIDSIM_VISC };
718                 float viscDef[1] = { 1. };
719
720                 gravDef[0] = domainSettings->gravx;
721                 gravDef[1] = domainSettings->gravy;
722                 gravDef[2] = domainSettings->gravz;
723
724                 // time channel is a bit special, init by hand...
725                 timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex");
726                 for(i=0; i<=G.scene->r.efra; i++) {
727                         timeAtIndex[i] = (float)(i-startFrame);
728                 }
729                 fluidsimInitChannel( &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB
730                 // time channel is a multiplicator for aniFrameTime
731                 if(channelDomainTime) {
732                         for(i=0; i<allchannelSize; i++) { 
733                                 channelDomainTime[i*2+0] = aniFrameTime * channelDomainTime[i*2+0]; 
734                                 if(channelDomainTime[i*2+0]<0.) channelDomainTime[i*2+0] = 0.;
735                         }
736                 }
737                 timeAtFrame = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatframe");
738                 timeAtFrame[0] = timeAtFrame[1] = domainSettings->animStart; // start at index 1
739                 if(channelDomainTime) {
740                         for(i=2; i<=allchannelSize; i++) {
741                                 timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0];
742                         }
743                 } else {
744                         for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; }
745                 }
746
747                 fluidsimInitChannel( &channelDomainViscosity, allchannelSize, timeAtFrame, viscIcu,viscDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB
748                 if(channelDomainViscosity) {
749                         for(i=0; i<allchannelSize; i++) { channelDomainViscosity[i*2+0] = calcViscosity * channelDomainViscosity[i*2+0]; }
750                 }
751                 fluidsimInitChannel( &channelDomainGravity, allchannelSize, timeAtFrame, gravIcu,gravDef, domainSettings->ipo, CHANNEL_VEC );
752         } // domain channel init
753         
754         // init obj movement channels
755         channelObjCount=0;
756         for(obit= G.main->object.first; obit; obit= obit->id.next) {
757                 //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG
758                 if( (obit->fluidsimFlag & OB_FLUIDSIM_ENABLE) && 
759                                 (obit->type==OB_MESH) &&
760                                 (obit->fluidsimSettings->type != OB_FLUIDSIM_DOMAIN) &&  // if has to match 3 places! // CHECKMATCH
761                                 (obit->fluidsimSettings->type != OB_FLUIDSIM_PARTICLE) ) {
762
763                         //  cant use fluidsimInitChannel for obj channels right now, due
764                         //  to the special DXXX channels, and the rotation specialities
765                         IpoCurve *icuex[3][3];
766                         //IpoCurve *par_icuex[3][3];
767                         int icuIds[3][3] = { 
768                                 {OB_LOC_X,  OB_LOC_Y,  OB_LOC_Z},
769                                 {OB_ROT_X,  OB_ROT_Y,  OB_ROT_Z},
770                                 {OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z} 
771                         };
772                         // relative ipos
773                         IpoCurve *icudex[3][3];
774                         //IpoCurve *par_icudex[3][3];
775                         int icudIds[3][3] = { 
776                                 {OB_DLOC_X,  OB_DLOC_Y,  OB_DLOC_Z},
777                                 {OB_DROT_X,  OB_DROT_Y,  OB_DROT_Z},
778                                 {OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z} 
779                         };
780                         int j,k;
781                         float vals[3] = {0.0,0.0,0.0}; 
782                         int o = channelObjCount;
783                         int   inivelIcu[3] =  { FLUIDSIM_VEL_X, FLUIDSIM_VEL_Y, FLUIDSIM_VEL_Z };
784                         float inivelDefs[3];
785                         int   activeIcu[1] =  { FLUIDSIM_ACTIVE };
786                         float activeDefs[1] = { 1 }; // default to on
787
788                         inivelDefs[0] = obit->fluidsimSettings->iniVelx;
789                         inivelDefs[1] = obit->fluidsimSettings->iniVely;
790                         inivelDefs[2] = obit->fluidsimSettings->iniVelz;
791
792                         // check & init loc,rot,size
793                         for(j=0; j<3; j++) {
794                                 for(k=0; k<3; k++) {
795                                         icuex[j][k]  = find_ipocurve(obit->ipo, icuIds[j][k] );
796                                         icudex[j][k] = find_ipocurve(obit->ipo, icudIds[j][k] );
797                                         //if(obit->parent) {
798                                                 //par_icuex[j][k]  = find_ipocurve(obit->parent->ipo, icuIds[j][k] );
799                                                 //par_icudex[j][k] = find_ipocurve(obit->parent->ipo, icudIds[j][k] );
800                                         //}
801                                 }
802                         }
803
804                         for(j=0; j<3; j++) {
805                                 channelObjMove[o][j] = MEM_callocN( allchannelSize*4*sizeof(float), "fluidsiminit_objmovchannel");
806                                 for(i=1; i<=allchannelSize; i++) {
807
808                                         for(k=0; k<3; k++) {
809                                                 if(icuex[j][k]) { 
810                                                         // IPO exists, use it ...
811                                                         calc_icu(icuex[j][k], aniFrlen*((float)i) );
812                                                         vals[k] = icuex[j][k]->curval; 
813                                                         if(obit->parent) {
814                                                                 // add parent transform, multiply scaling, add trafo&rot
815                                                                 //calc_icu(par_icuex[j][k], aniFrlen*((float)i) );
816                                                                 //if(j==2) { vals[k] *= par_icuex[j][k]->curval; }
817                                                                 //else { vals[k] += par_icuex[j][k]->curval; }
818                                                         }
819                                                 } else {
820                                                         // use defaults from static values
821                                                         float setval=0.0;
822                                                         if(j==0) { 
823                                                                 setval = obit->loc[k];
824                                                                 if(obit->parent){ setval += obit->parent->loc[k]; }
825                                                         } else if(j==1) { 
826                                                                 setval = ( 180.0*obit->rot[k] )/( 10.0*M_PI );
827                                                                 if(obit->parent){ setval = ( 180.0*(obit->rot[k]+obit->parent->rot[k]) )/( 10.0*M_PI ); }
828                                                         } else { 
829                                                                 setval = obit->size[k]; 
830                                                                 if(obit->parent){ setval *= obit->parent->size[k]; }
831                                                         }
832                                                         vals[k] = setval;
833                                                 }
834                                                 if(icudex[j][k]) { 
835                                                         calc_icu(icudex[j][k], aniFrlen*((float)i) );
836                                                         //vals[k] += icudex[j][k]->curval; 
837                                                         // add transform, multiply scaling, add trafo&rot
838                                                         if(j==2) { vals[k] *= icudex[j][k]->curval; }
839                                                         else { vals[k] += icudex[j][k]->curval; }
840                                                         if(obit->parent) {
841                                                                 // add parent transform, multiply scaling, add trafo&rot
842                                                                 //calc_icu(par_icuex[j][k], aniFrlen*((float)i) );
843                                                                 //if(j==2) { vals[k] *= par_icudex[j][k]->curval; }
844                                                                 //else { vals[k] += par_icudex[j][k]->curval; }
845                                                         }
846                                                 } 
847                                         } // k
848
849                                         for(k=0; k<3; k++) {
850                                                 float set = vals[k];
851                                                 if(j==1) { // rot is downscaled by 10 for ipo !?
852                                                         set = 360.0 - (10.0*set);
853                                                 }
854                                                 channelObjMove[o][j][(i-1)*4 + k] = set;
855                                         } // k
856                                         channelObjMove[o][j][(i-1)*4 + 3] = timeAtFrame[i];
857                                 }
858                         }
859
860                         fluidsimInitChannel( &channelObjInivel[o], allchannelSize, timeAtFrame, inivelIcu,inivelDefs, obit->fluidsimSettings->ipo, CHANNEL_VEC );
861                         fluidsimInitChannel( &channelObjActive[o], allchannelSize, timeAtFrame, activeIcu,activeDefs, obit->fluidsimSettings->ipo, CHANNEL_FLOAT );
862
863                         channelObjCount++;
864
865                 }
866         }
867
868         // init trafo matrix
869         MTC_Mat4CpyMat4(domainMat, fsDomain->obmat);
870         if(!Mat4Invert(invDomMat, domainMat)) {
871                 snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); 
872                 elbeemDebugOut(debugStrBuffer);
873                 // FIXME add fatal msg
874                 FS_FREE_CHANNELS;
875                 return;
876         }
877
878
879         // --------------------------------------------------------------------------------------------
880         // start writing / exporting
881         strcpy(targetFile, targetDir);
882         strcat(targetFile, suffixConfig);
883         if(!doExportOnly) { strcat(targetFile,".tmp"); }  // dont overwrite/delete original file
884         // make sure these directories exist as well
885         if(outStringsChanged) {
886                 BLI_make_existing_file(targetFile);
887         }
888
889         if(!doExportOnly) {
890                 SDL_Thread *simthr = NULL;
891
892                 // perform simulation with El'Beem api and SDL threads
893                 elbeemSimulationSettings fsset;
894                 elbeemResetSettings(&fsset);
895                 fsset.version = 1;
896
897                 // setup global settings
898                 for(i=0 ; i<3; i++) fsset.geoStart[i] = bbStart[i];
899                 for(i=0 ; i<3; i++) fsset.geoSize[i] = bbSize[i];
900                 // simulate with 50^3
901                 fsset.resolutionxyz = (int)domainSettings->resolutionxyz;
902                 fsset.previewresxyz = (int)domainSettings->previewresxyz;
903                 // 10cm water domain
904                 fsset.realsize = domainSettings->realsize;
905                 fsset.viscosity = calcViscosity;
906                 // earth gravity
907                 fsset.gravity[0] = domainSettings->gravx;
908                 fsset.gravity[1] = domainSettings->gravy;
909                 fsset.gravity[2] = domainSettings->gravz;
910                 // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
911                 fsset.animStart = domainSettings->animStart;
912                 fsset.aniFrameTime = aniFrameTime;
913                 fsset.noOfFrames = noFrames - 1; // is otherwise subtracted in parser
914                 strcpy(targetFile, targetDir);
915                 strcat(targetFile, suffixSurface);
916                 // defaults for compressibility and adaptive grids
917                 fsset.gstar = domainSettings->gstar;
918                 fsset.maxRefine = domainSettings->maxRefine; // check <-> gridlevels
919                 fsset.generateParticles = domainSettings->generateParticles; 
920                 fsset.numTracerParticles = domainSettings->generateTracers; 
921                 fsset.surfaceSmoothing = domainSettings->surfaceSmoothing; 
922                 fsset.surfaceSubdivs = domainSettings->surfaceSubdivs; 
923                 fsset.farFieldSize = domainSettings->farFieldSize; 
924                 strcpy( fsset.outputPath, targetFile);
925
926                 // domain channels
927                 fsset.channelSizeFrameTime = 
928                 fsset.channelSizeViscosity = 
929                 fsset.channelSizeGravity =  allchannelSize;
930                 fsset.channelFrameTime = channelDomainTime;
931                 fsset.channelViscosity = channelDomainViscosity;
932                 fsset.channelGravity = channelDomainGravity;
933
934                 fsset.runsimCallback = &runSimulationCallback;
935                 fsset.runsimUserData = &fsset;
936
937                 if(     (domainSettings->typeFlags&OB_FSBND_NOSLIP))   fsset.domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
938                 else if((domainSettings->typeFlags&OB_FSBND_PARTSLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
939                 else if((domainSettings->typeFlags&OB_FSBND_FREESLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
940                 fsset.domainobsPartslip = domainSettings->partSlipValue;
941                 fsset.generateVertexVectors = (domainSettings->domainNovecgen==0);
942
943                 // init blender trafo matrix
944                 // fprintf(stderr,"elbeemInit - mpTrafo:\n");
945                 { int j; 
946                 for(i=0; i<4; i++) {
947                         for(j=0; j<4; j++) {
948                                 fsset.surfaceTrafo[i*4+j] = invDomMat[j][i];
949                                 // fprintf(stderr,"elbeemInit - mpTrafo %d %d = %f (%d) \n", i,j, fsset.surfaceTrafo[i*4+j] , (i*4+j) );
950                         }
951                 } }
952
953           // init solver with settings
954                 elbeemInit();
955                 elbeemAddDomain(&fsset);
956                 
957                 // init objects
958                 channelObjCount = 0;
959                 for(obit= G.main->object.first; obit; obit= obit->id.next) {
960                         //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG
961                         if( (obit->fluidsimFlag & OB_FLUIDSIM_ENABLE) &&  // if has to match 3 places! // CHECKMATCH
962                                         (obit->type==OB_MESH) &&
963                                         (obit->fluidsimSettings->type != OB_FLUIDSIM_DOMAIN) &&
964                                         (obit->fluidsimSettings->type != OB_FLUIDSIM_PARTICLE)
965                                 ) {
966                                 float *verts=NULL;
967                                 int *tris=NULL;
968                                 int numVerts=0, numTris=0;
969                                 int o = channelObjCount;
970                                 int     deform = (obit->fluidsimSettings->domainNovecgen); // misused value
971                                 elbeemMesh fsmesh;
972                                 elbeemResetMesh( &fsmesh );
973                                 fsmesh.type = obit->fluidsimSettings->type;;
974                                 // get name of object for debugging solver
975                                 fsmesh.name = obit->id.name; 
976
977                                 initElbeemMesh(obit, &numVerts, &verts, &numTris, &tris, 0);
978                                 fsmesh.numVertices   = numVerts;
979                                 fsmesh.numTriangles  = numTris;
980                                 fsmesh.vertices      = verts;
981                                 fsmesh.triangles     = tris;
982
983                                 fsmesh.channelSizeTranslation  = 
984                                 fsmesh.channelSizeRotation     = 
985                                 fsmesh.channelSizeScale        = 
986                                 fsmesh.channelSizeInitialVel   = 
987                                 fsmesh.channelSizeActive       = allchannelSize;
988
989                                 fsmesh.channelTranslation      = channelObjMove[o][0];
990                                 fsmesh.channelRotation         = channelObjMove[o][1];
991                                 fsmesh.channelScale            = channelObjMove[o][2];
992                                 fsmesh.channelActive           = channelObjActive[o];
993                                 if( (fsmesh.type == OB_FLUIDSIM_FLUID) ||
994                                                 (fsmesh.type == OB_FLUIDSIM_INFLOW) ) {
995                                         fsmesh.channelInitialVel       = channelObjInivel[o];
996                                   fsmesh.localInivelCoords = ((obit->fluidsimSettings->typeFlags&OB_FSINFLOW_LOCALCOORD)?1:0);
997                                 } 
998
999                                 if(     (obit->fluidsimSettings->typeFlags&OB_FSBND_NOSLIP))   fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
1000                                 else if((obit->fluidsimSettings->typeFlags&OB_FSBND_PARTSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP;
1001                                 else if((obit->fluidsimSettings->typeFlags&OB_FSBND_FREESLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP;
1002                                 fsmesh.obstaclePartslip = obit->fluidsimSettings->partSlipValue;
1003                                 fsmesh.volumeInitType = obit->fluidsimSettings->volumeInitType;
1004                                 fsmesh.obstacleImpactFactor = obit->fluidsimSettings->surfaceSmoothing; // misused value
1005
1006                                 // animated meshes
1007                                 if(deform) {
1008                                         fsmesh.channelSizeVertices = allchannelSize;
1009                                         fluidsimInitMeshChannel( &fsmesh.channelVertices, allchannelSize, obit, numVerts, timeAtFrame);
1010                                         G.scene->r.cfra = startFrame;
1011                                         scene_update_for_newframe(G.scene, G.scene->lay);
1012                                         // remove channels
1013                                         fsmesh.channelTranslation      = 
1014                                         fsmesh.channelRotation         = 
1015                                         fsmesh.channelScale            = NULL; 
1016                                 } 
1017
1018                                 elbeemAddMesh(&fsmesh);
1019
1020                                 if(verts) MEM_freeN(verts);
1021                                 if(tris) MEM_freeN(tris);
1022                                 if(fsmesh.channelVertices) MEM_freeN(fsmesh.channelVertices);
1023                                 channelObjCount++;
1024                         } // valid mesh
1025                 } // objects
1026                 //domainSettings->type = OB_FLUIDSIM_DOMAIN; // enable for bake display again
1027                 //fsDomain->fluidsimFlag = OB_FLUIDSIM_ENABLE; // disable during bake
1028                 
1029                 globalBakeLock = SDL_CreateMutex();
1030                 // set to neutral, -1 means user abort, -2 means init error
1031                 globalBakeState = 0;
1032                 globalBakeFrame = 0;
1033                 simthr = SDL_CreateThread(fluidsimSimulateThread, targetFile);
1034
1035                 if(!simthr) {
1036                         snprintf(debugStrBuffer,256,"fluidsimBake::error: Unable to create thread... running without one.\n"); 
1037                         elbeemDebugOut(debugStrBuffer);
1038                         set_timecursor(0);
1039                         elbeemSimulate();
1040                 } else {
1041                         int done = 0;
1042                         unsigned short event=0;
1043                         short val;
1044                         float noFramesf = (float)noFrames;
1045                         float percentdone = 0.0;
1046                         int lastRedraw = -1;
1047                         
1048                         start_progress_bar();
1049
1050                         while(done==0) {            
1051                                 char busy_mess[80];
1052                                 
1053                                 waitcursor(1);
1054                                 
1055                                 // lukep we add progress bar as an interim mesure
1056                                 percentdone = globalBakeFrame / noFramesf;
1057                                 sprintf(busy_mess, "baking fluids %d / %d       |||", globalBakeFrame, (int) noFramesf);
1058                                 progress_bar(percentdone, busy_mess );
1059                                 
1060                                 SDL_Delay(2000); // longer delay to prevent frequent redrawing
1061                                 SDL_mutexP(globalBakeLock);
1062                                 if(globalBakeState != 0) done = 1; // 1=ok, <0=error/abort
1063                                 SDL_mutexV(globalBakeLock);
1064
1065                                 while(qtest()) {
1066                                         event = extern_qread(&val);
1067                                         if(event == ESCKEY) {
1068                                                 // abort...
1069                                                 SDL_mutexP(globalBakeLock);
1070                                                 done = -1;
1071                                                 globalBakeFrame = 0;
1072                                                 globalBakeState = -1;
1073                                                 simAborted = 1;
1074                                                 SDL_mutexV(globalBakeLock);
1075                                                 break;
1076                                         }
1077                                 } 
1078
1079                                 // redraw the 3D for showing progress once in a while...
1080                                 if(lastRedraw!=globalBakeFrame) {
1081                                         ScrArea *sa;
1082                                         G.scene->r.cfra = startFrame+globalBakeFrame;
1083                                         lastRedraw = globalBakeFrame;
1084                                         update_for_newframe_muted();
1085                                         sa= G.curscreen->areabase.first;
1086                                         while(sa) {
1087                                                 if(sa->spacetype == SPACE_VIEW3D) { scrarea_do_windraw(sa); }
1088                                                 sa= sa->next;   
1089                                         } 
1090                                         screen_swapbuffers();
1091                                 } // redraw
1092                         }
1093                         SDL_WaitThread(simthr,NULL);
1094                         end_progress_bar();
1095                 }
1096                 SDL_DestroyMutex(globalBakeLock);
1097                 globalBakeLock = NULL;
1098         } // El'Beem API init, thread creation 
1099         // --------------------------------------------------------------------------------------------
1100         else
1101         { // write config file to be run with command line simulator
1102                 pupmenu("Fluidsim Bake Message%t|Config file export not supported.%x0");
1103         } // config file export done!
1104
1105         // --------------------------------------------------------------------------------------------
1106         FS_FREE_CHANNELS;
1107
1108         // go back to "current" blender time
1109         waitcursor(0);
1110   G.scene->r.cfra = origFrame;
1111   scene_update_for_newframe(G.scene, G.scene->lay);
1112         allqueue(REDRAWVIEW3D, 0);
1113         allqueue(REDRAWBUTSOBJECT, 0);
1114
1115         if(!simAborted) {
1116                 char fsmessage[512];
1117                 char elbeemerr[256];
1118                 strcpy(fsmessage,"Fluidsim Bake Error: ");
1119                 // check if some error occurred
1120                 if(globalBakeState==-2) {
1121                         strcat(fsmessage,"Failed to initialize [Msg: ");
1122
1123                         elbeemGetErrorString(elbeemerr);
1124                         strcat(fsmessage,elbeemerr);
1125
1126                         strcat(fsmessage,"] |OK%x0");
1127                         pupmenu(fsmessage);
1128                 } // init error
1129         }
1130 }
1131
1132
1133 #else /* DISABLE_ELBEEM */
1134
1135 /* compile dummy functions for disabled fluid sim */
1136
1137 FluidsimSettings *fluidsimSettingsNew(struct Object *srcob) {
1138         return NULL;
1139 }
1140
1141 void fluidsimSettingsFree(FluidsimSettings *fss) {
1142 }
1143
1144 FluidsimSettings* fluidsimSettingsCopy(FluidsimSettings *fss) {
1145         return NULL;
1146 }
1147
1148 /* only compile dummy functions */
1149 void fluidsimBake(struct Object *ob) {
1150 }
1151
1152 #endif /* DISABLE_ELBEEM */
1153