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