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