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