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