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