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