use BLI_strncpy and BLI_snprintf when the size of the string is known.
[blender.git] / source / blender / editors / physics / physics_fluid.c
index 6dc4684..0bb5dbe 100644 (file)
@@ -1,7 +1,6 @@
-/**
+/*
  * fluidsim.c
  * 
- * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/physics/physics_fluid.c
+ *  \ingroup edphys
+ */
+
+
 
 
 #include <math.h>
 #include <string.h>
 #include <sys/stat.h>
 
-#ifdef WIN32   /* Windos */
-#ifndef snprintf
-#define snprintf _snprintf
-#endif
-#endif
-
 #include "MEM_guardedalloc.h"
 
 /* types */
@@ -53,6 +51,7 @@
 #include "BLI_blenlib.h"
 #include "BLI_threads.h"
 #include "BLI_math.h"
+#include "BLI_utildefines.h"
 
 #include "BKE_animsys.h"
 #include "BKE_armature.h"
 
 #include "LBM_fluidsim.h"
 
-
 #include "ED_screen.h"
+#include "ED_fluidsim.h"
 
 #include "WM_types.h"
+#include "WM_api.h"
 
 #include "physics_intern.h" // own include
 
 /* enable/disable overall compilation */
-#ifndef DISABLE_ELBEEM
+#ifdef WITH_MOD_FLUID
 
 #include "WM_api.h"
 
@@ -118,7 +118,7 @@ static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fs
        if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
                copy_v3_v3(gravity, scene->physics_settings.gravity);
        } else {
-               copy_v3_v3(gravity, &fss->gravx);
+               copy_v3_v3(gravity, fss->grav);
        }
 }
 
@@ -146,9 +146,10 @@ static int fluid_is_animated_mesh(FluidsimSettings *fss)
 
 #if 0
 /* helper function */
-void fluidsimGetGeometryObjFilename(Object *ob, char *dst) { //, char *srcname) {
-       //snprintf(dst,FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
-       snprintf(dst,FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name);
+void fluidsimGetGeometryObjFilename(Object *ob, char *dst) { //, char *srcname)
+{
+       //BLI_snprintf(dst,FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
+       BLI_snprintf(dst,FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name);
 }
 #endif
 
@@ -420,7 +421,7 @@ static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), Fluid
                /* Modifying the global scene isn't nice, but we can do it in 
                 * this part of the process before a threaded job is created */
                scene->r.cfra = (int)eval_time;
-               ED_update_for_newframe(C, 1);
+               ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1);
                
                /* now scene data should be current according to animation system, so we fill the channels */
                
@@ -436,15 +437,20 @@ static void fluid_init_all_channels(bContext *C, Object *UNUSED(fsDomain), Fluid
                        Object *ob = fobj->object;
                        FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim);
                        float active= (float)(fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE);
-                       float rot_d[3], rot_360[3] = {360.f, 360.f, 360.f};
+                       float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f};
                        
                        if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE))
                                continue;
                        
                        /* init euler rotation values and convert to elbeem format */
-                       BKE_rotMode_change_values(ob->quat, ob->rot, ob->rotAxis, &ob->rotAngle, ob->rotmode, ROT_MODE_EUL);
-                       mul_v3_v3fl(rot_d, ob->rot, 180.f/M_PI);
-                       sub_v3_v3v3(rot_d, rot_360, rot_d);
+                       /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */
+                       if(i) {
+                               copy_v3_v3(old_rot, fobj->Rotation + 4*(i-1));
+                               mul_v3_fl(old_rot, -M_PI/180.f);
+                       }
+
+                       mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat);
+                       mul_v3_fl(rot_d, -180.f/M_PI);
                        
                        set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC);
                        set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC);
@@ -587,7 +593,7 @@ static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDom
                        }
                        /* if there's more than one domain, cancel */
                        else if (fsDomain && ob != fsDomain) {
-                               BKE_report(reports, RPT_ERROR, "There should be only one domain object.");
+                               BKE_report(reports, RPT_ERROR, "There should be only one domain object");
                                return 0;
                        }
                }
@@ -605,17 +611,17 @@ static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDom
                fsDomain = newdomain;
        
        if (!fsDomain) {
-               BKE_report(reports, RPT_ERROR, "No domain object found.");
+               BKE_report(reports, RPT_ERROR, "No domain object found");
                return 0;
        }
        
        if (channelObjCount>=255) {
-               BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects.");
+               BKE_report(reports, RPT_ERROR, "Cannot bake with more then 256 objects");
                return 0;
        }
        
        if (fluidInputCount == 0) {
-               BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene.");
+               BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene");
                return 0;
        }
        
@@ -632,18 +638,21 @@ static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetF
        FluidsimSettings *domainSettings= fluidmd->fss; 
        FILE *fileCfg;
        int dirExist = 0;
-       char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings
-       char *suffixConfig = FLUID_SUFFIX_CONFIG;
+       char newSurfdataPath[FILE_MAX]; // modified output settings
+       const char *suffixConfig = FLUID_SUFFIX_CONFIG;
        int outStringsChanged = 0;
-       
+
        // prepare names...
-       strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
-       strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR);
-       BLI_path_abs(targetDir, G.sce); // fixed #frame-no 
-       
-       strcpy(targetFile, targetDir);
-       strcat(targetFile, suffixConfig);
-       strcat(targetFile,".tmp"); // dont overwrite/delete original file
+       const char *relbase= modifier_path_relbase(fsDomain);
+
+       BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
+       BLI_strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); /* if 0'd out below, this value is never used! */
+       BLI_path_abs(targetDir, relbase); // fixed #frame-no
+
+       BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfig);
+       /* .tmp: dont overwrite/delete original file */
+       strncat(targetFile, ".tmp", FILE_MAX);
+
        // make sure all directories exist
        // as the bobjs use the same dir, this only needs to be checked
        // for the cfg output
@@ -658,24 +667,18 @@ static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetF
                BLI_delete(targetFile, 0,0);
        }
        
-       if((strlen(targetDir)<1) || (!dirExist)) {
-               char blendDir[FILE_MAXDIR+FILE_MAXFILE];
-               char blendFile[FILE_MAXDIR+FILE_MAXFILE];
+       if(targetDir[0] == '\0' || (!dirExist)) {
+               char blendDir[FILE_MAX];
+               char blendFile[FILE_MAX];
                
                // invalid dir, reset to current/previous
-               strcpy(blendDir, G.sce);
+               BLI_strncpy(blendDir, G.main->name, FILE_MAX);
                BLI_splitdirstring(blendDir, blendFile);
-               if(strlen(blendFile)>6){
-                       int len = strlen(blendFile);
-                       if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&&
-                          (blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){
-                               blendFile[len-6] = '\0';
-                       }
-               }
-               // todo... strip .blend ?
-               snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
+               BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */
+
+               BLI_snprintf(newSurfdataPath, FILE_MAX ,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
                
-               snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
+               BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
                elbeemDebugOut(debugStrBuffer);
                outStringsChanged=1;
        }
@@ -683,18 +686,18 @@ static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetF
        // check if modified output dir is ok
 #if 0
        if(outStringsChanged) {
-               char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256];
+               char dispmsg[FILE_MAX+256];
                int  selection=0;
-               strcpy(dispmsg,"Output settings set to: '");
+               BLI_strncpy(dispmsg,"Output settings set to: '", sizeof(dispmsg));
                strcat(dispmsg, newSurfdataPath);
                strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0");
                
                // ask user if thats what he/she wants...
                selection = pupmenu(dispmsg);
                if(selection<1) return 0; // 0 from menu, or -1 aborted
-               strcpy(targetDir, newSurfdataPath);
+               BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir));
                strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
-               BLI_path_abs(targetDir, G.sce); // fixed #frame-no 
+               BLI_path_abs(targetDir, G.main->name); // fixed #frame-no 
        }
 #endif 
        return outStringsChanged;
@@ -715,15 +718,17 @@ typedef struct FluidBakeJob {
 
 static void fluidbake_free(void *customdata)
 {
-       FluidBakeJob *fb= customdata;
+       FluidBakeJob *fb= (FluidBakeJob *)customdata;
        MEM_freeN(fb);
 }
 
 /* called by fluidbake, only to check job 'stop' value */
-static int fluidbake_breakjob(void *UNUSED(customdata))
+static int fluidbake_breakjob(void *customdata)
 {
-       //FluidBakeJob *fb= (FluidBakeJob *)customdata;
-       //return *(fb->stop);
+       FluidBakeJob *fb= (FluidBakeJob *)customdata;
+
+       if(fb->stop && *(fb->stop))
+               return 1;
        
        /* this is not nice yet, need to make the jobs list template better 
         * for identifying/acting upon various different jobs */
@@ -734,7 +739,7 @@ static int fluidbake_breakjob(void *UNUSED(customdata))
 /* called by fluidbake, wmJob sends notifier */
 static void fluidbake_updatejob(void *customdata, float progress)
 {
-       FluidBakeJob *fb= customdata;
+       FluidBakeJob *fb= (FluidBakeJob *)customdata;
        
        *(fb->do_update)= 1;
        *(fb->progress)= progress;
@@ -742,7 +747,7 @@ static void fluidbake_updatejob(void *customdata, float progress)
 
 static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress)
 {
-       FluidBakeJob *fb= customdata;
+       FluidBakeJob *fb= (FluidBakeJob *)customdata;
        
        fb->stop= stop;
        fb->do_update = do_update;
@@ -757,7 +762,7 @@ static void fluidbake_startjob(void *customdata, short *stop, short *do_update,
 
 static void fluidbake_endjob(void *customdata)
 {
-       FluidBakeJob *fb= customdata;
+       FluidBakeJob *fb= (FluidBakeJob *)customdata;
        
        if (fb->settings) {
                MEM_freeN(fb->settings);
@@ -765,7 +770,8 @@ static void fluidbake_endjob(void *customdata)
        }
 }
 
-int runSimulationCallback(void *data, int status, int frame) {
+int runSimulationCallback(void *data, int status, int frame)
+{
        FluidBakeJob *fb = (FluidBakeJob *)data;
        elbeemSimulationSettings *settings = fb->settings;
        
@@ -803,7 +809,45 @@ static void fluidbake_free_data(FluidAnimChannels *channels, ListBase *fobjects,
        }
 }
 
-int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
+/* copied from rna_fluidsim.c: fluidsim_find_lastframe() */
+static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase)
+{
+       char targetDir[FILE_MAX], targetFile[FILE_MAX];
+       char targetDirVel[FILE_MAX], targetFileVel[FILE_MAX];
+       char previewDir[FILE_MAX], previewFile[FILE_MAX];
+       int curFrame = 1, exists = 0;
+
+       BLI_join_dirfile(targetDir,    sizeof(targetDir),    fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME);
+       BLI_join_dirfile(targetDirVel, sizeof(targetDirVel), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_VEL_FNAME);
+       BLI_join_dirfile(previewDir,   sizeof(previewDir),   fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME);
+
+       BLI_path_abs(targetDir,    relbase);
+       BLI_path_abs(targetDirVel, relbase);
+       BLI_path_abs(previewDir,   relbase);
+
+       do {
+               BLI_strncpy(targetFile, targetDir, sizeof(targetFile));
+               BLI_strncpy(targetFileVel, targetDirVel, sizeof(targetFileVel));
+               BLI_strncpy(previewFile, previewDir, sizeof(previewFile));
+
+               BLI_path_frame(targetFile, curFrame, 0);
+               BLI_path_frame(targetFileVel, curFrame, 0);
+               BLI_path_frame(previewFile, curFrame, 0);
+
+               curFrame++;
+
+               if((exists = BLI_exists(targetFile)))
+               {
+                       BLI_delete(targetFile, 0, 0);
+                       BLI_delete(targetFileVel, 0, 0);
+                       BLI_delete(previewFile, 0, 0);
+               }
+       } while(exists);
+
+       return;
+}
+
+static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
 {
        Scene *scene= CTX_data_scene(C);
        int i;
@@ -812,12 +856,13 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        char debugStrBuffer[256];
        
        int gridlevels = 0;
+       const char *relbase= modifier_path_relbase(fsDomain);
        const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
-       char *suffixConfig = FLUID_SUFFIX_CONFIG;
-       char *suffixSurface = FLUID_SUFFIX_SURFACE;
+       const char *suffixConfig = FLUID_SUFFIX_CONFIG;
+       const char *suffixSurface = FLUID_SUFFIX_SURFACE;
 
-       char targetDir[FILE_MAXDIR+FILE_MAXFILE];  // store & modify output settings
-       char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // temp. store filename from targetDir for access
+       char targetDir[FILE_MAX];  // store & modify output settings
+       char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
        int  outStringsChanged = 0;             // modified? copy back before baking
 
        float domainMat[4][4];
@@ -830,25 +875,23 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects");
        FluidsimModifierData *fluidmd = NULL;
        Mesh *mesh = NULL;
-       
-       wmJob *steve;
+
        FluidBakeJob *fb;
        elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings");
-       
-       steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS);
+
        fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
        
        if(getenv(strEnvName)) {
                int dlevel = atoi(getenv(strEnvName));
                elbeemSetDebugLevel(dlevel);
-               snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName); 
+               BLI_snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName); 
                elbeemDebugOut(debugStrBuffer);
        }
        
        /* make sure it corresponds to startFrame setting (old: noFrames = scene->r.efra - scene->r.sfra +1) */;
        noFrames = scene->r.efra - 0;
        if(noFrames<=0) {
-               BKE_report(reports, RPT_ERROR, "No frames to export - check your animation range settings.");
+               BKE_report(reports, RPT_ERROR, "No frames to export - check your animation range settings");
                fluidbake_free_data(channels, fobjects, fsset, fb);
                return 0;
        }
@@ -872,10 +915,13 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        
        // reset last valid frame
        domainSettings->lastgoodframe = -1;
+
+       /* delete old baked files */
+       fluidsim_delete_until_lastframe(domainSettings, relbase);
        
        /* rough check of settings... */
        if(domainSettings->previewresxyz > domainSettings->resolutionxyz) {
-               snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz ,  domainSettings->resolutionxyz); 
+               BLI_snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz ,  domainSettings->resolutionxyz); 
                elbeemDebugOut(debugStrBuffer);
                domainSettings->previewresxyz = domainSettings->resolutionxyz;
        }
@@ -895,7 +941,7 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        } else {
                gridlevels = domainSettings->maxRefine;
        }
-       snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); 
+       BLI_snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels ); 
        elbeemDebugOut(debugStrBuffer);
        
        
@@ -910,7 +956,7 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
 
        /* reset to original current frame */
        scene->r.cfra = origFrame;
-       ED_update_for_newframe(C, 1);
+       ED_update_for_newframe(CTX_data_main(C), scene, CTX_wm_screen(C), 1);
        
        
        /* ---- XXX: No Time animation curve for now, leaving this code here for reference 
@@ -947,18 +993,18 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        /* ******** init domain object's matrix ******** */
        copy_m4_m4(domainMat, fsDomain->obmat);
        if(!invert_m4_m4(invDomMat, domainMat)) {
-               snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); 
+               BLI_snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n"); 
                elbeemDebugOut(debugStrBuffer);
-               BKE_report(reports, RPT_ERROR, "Invalid object matrix."); 
+               BKE_report(reports, RPT_ERROR, "Invalid object matrix"); 
 
                fluidbake_free_data(channels, fobjects, fsset, fb);
                return 0;
        }
 
        /* ********  start writing / exporting ******** */
-       strcpy(targetFile, targetDir);
-       strcat(targetFile, suffixConfig);
-       strcat(targetFile,".tmp");  // dont overwrite/delete original file
+       // use .tmp, dont overwrite/delete original file
+       BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfig);
+       strncat(targetFile, ".tmp", sizeof(targetFile));
        
        // make sure these directories exist as well
        if(outStringsChanged) {
@@ -986,8 +1032,8 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        fsset->aniFrameTime = channels->aniFrameTime;
        fsset->noOfFrames = noFrames; // is otherwise subtracted in parser
 
-       strcpy(targetFile, targetDir);
-       strcat(targetFile, suffixSurface);
+       BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface);
+
        // defaults for compressibility and adaptive grids
        fsset->gstar = domainSettings->gstar;
        fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels
@@ -996,7 +1042,7 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; 
        fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; 
        fsset->farFieldSize = domainSettings->farFieldSize; 
-       strcpy( fsset->outputPath, targetFile);
+       BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath));
 
        // domain channels
        fsset->channelSizeFrameTime = 
@@ -1013,6 +1059,13 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP)   fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
        else if (domainSettings->typeFlags&OB_FSBND_FREESLIP)   fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
        fsset->domainobsPartslip = domainSettings->partSlipValue;
+
+       /* use domainobsType also for surface generation flag (bit: >=64) */
+       if(domainSettings->typeFlags & OB_FSSG_NOOBS)
+               fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS;
+       else
+               fsset->mFsSurfGenSetting = 0; // "normal" mode
+
        fsset->generateVertexVectors = (domainSettings->domainNovecgen==0);
 
        // init blender domain transform matrix
@@ -1033,12 +1086,25 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        /* custom data for fluid bake job */
        fb->settings = fsset;
        
-       /* setup job */
-       WM_jobs_customdata(steve, fb, fluidbake_free);
-       WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME);
-       WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
-       
-       WM_jobs_start(CTX_wm_manager(C), steve);
+       if(do_job) {
+               wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS);
+
+               /* setup job */
+               WM_jobs_customdata(steve, fb, fluidbake_free);
+               WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME);
+               WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
+
+               WM_jobs_start(CTX_wm_manager(C), steve);
+       }
+       else {
+               short dummy_stop, dummy_do_update;
+               float dummy_progress;
+
+               /* blocking, use with exec() */
+               fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress);
+               fluidbake_endjob((void *)fb);
+               fluidbake_free((void *)fb);
+       }
 
        /* ******** free stored animation data ******** */
        fluidbake_free_data(channels, fobjects, NULL, NULL);
@@ -1052,7 +1118,7 @@ void fluidsimFreeBake(Object *UNUSED(ob))
        /* not implemented yet */
 }
 
-#else /* DISABLE_ELBEEM */
+#else /* WITH_MOD_FLUID */
 
 /* compile dummy functions for disabled fluid sim */
 
@@ -1071,24 +1137,30 @@ FluidsimSettings* fluidsimSettingsCopy(FluidsimSettings *UNUSED(fss))
 }
 
 /* only compile dummy functions */
-int fluidsimBake(bContext *UNUSED(C), ReportList *UNUSED(reports), Object *UNUSED(ob))
+static int fluidsimBake(bContext *UNUSED(C), ReportList *UNUSED(reports), Object *UNUSED(ob), short UNUSED(do_job))
 {
        return 0;
 }
 
-void fluidsimFreeBake(Object *UNUSED(ob))
+#endif /* WITH_MOD_FLUID */
+
+/***************************** Operators ******************************/
+
+static int fluid_bake_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 {
-}
+       /* only one bake job at a time */
+       if(WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
+               return OPERATOR_CANCELLED;
 
-#endif /* DISABLE_ELBEEM */
+       if(!fluidsimBake(C, op->reports, CTX_data_active_object(C), TRUE))
+               return OPERATOR_CANCELLED;
 
-/***************************** Operators ******************************/
+       return OPERATOR_FINISHED;
+}
 
 static int fluid_bake_exec(bContext *C, wmOperator *op)
 {
-       Object *ob= CTX_data_active_object(C);
-
-       if(!fluidsimBake(C, op->reports, ob))
+       if(!fluidsimBake(C, op->reports, CTX_data_active_object(C), FALSE))
                return OPERATOR_CANCELLED;
 
        return OPERATOR_FINISHED;
@@ -1102,6 +1174,7 @@ void FLUID_OT_bake(wmOperatorType *ot)
        ot->idname= "FLUID_OT_bake";
        
        /* api callbacks */
+       ot->invoke= fluid_bake_invoke;
        ot->exec= fluid_bake_exec;
        ot->poll= ED_operator_object_active_editable;
 }