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