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