use BLI_strncpy and BLI_snprintf when the size of the string is known.
[blender.git] / source / blender / editors / physics / physics_fluid.c
index b573c77..0bb5dbe 100644 (file)
@@ -1,7 +1,6 @@
 /*
  * fluidsim.c
  * 
- * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
 #include <string.h>
 #include <sys/stat.h>
 
-#ifdef WIN32   /* Windos */
-#ifndef snprintf
-#define snprintf _snprintf
-#endif
-#endif
-
 #include "MEM_guardedalloc.h"
 
 /* types */
@@ -56,7 +49,6 @@
 #include "DNA_object_fluidsim.h"       
 
 #include "BLI_blenlib.h"
-#include "BLI_fileops.h"
 #include "BLI_threads.h"
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
@@ -93,7 +85,7 @@
 #include "physics_intern.h" // own include
 
 /* enable/disable overall compilation */
-#ifndef DISABLE_ELBEEM
+#ifdef WITH_MOD_FLUID
 
 #include "WM_api.h"
 
@@ -154,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
 
@@ -600,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;
                        }
                }
@@ -618,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;
        }
        
@@ -645,17 +638,20 @@ 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 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.main->name); // fixed #frame-no 
+       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
 
-       // .tmp: dont overwrite/delete original file
-       BLI_snprintf(targetFile, FILE_MAXDIR+FILE_MAXFILE, "%s%s.tmp", targetDir, suffixConfig);
+       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
@@ -671,16 +667,16 @@ 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
-               BLI_strncpy(blendDir, G.main->name, FILE_MAXDIR+FILE_MAXFILE);
+               BLI_strncpy(blendDir, G.main->name, FILE_MAX);
                BLI_splitdirstring(blendDir, blendFile);
-               BLI_replace_extension(blendFile, FILE_MAXDIR+FILE_MAXFILE, ""); /* strip .blend */
+               BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */
 
-               BLI_snprintf(newSurfdataPath, FILE_MAXDIR+FILE_MAXFILE ,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
+               BLI_snprintf(newSurfdataPath, FILE_MAX ,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
                
                BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
                elbeemDebugOut(debugStrBuffer);
@@ -690,7 +686,7 @@ 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;
                BLI_strncpy(dispmsg,"Output settings set to: '", sizeof(dispmsg));
                strcat(dispmsg, newSurfdataPath);
@@ -722,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 */
@@ -741,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;
@@ -749,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;
@@ -764,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);
@@ -772,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;
        
@@ -811,20 +810,20 @@ static void fluidbake_free_data(FluidAnimChannels *channels, ListBase *fobjects,
 }
 
 /* copied from rna_fluidsim.c: fluidsim_find_lastframe() */
-static void fluidsim_delete_until_lastframe(FluidsimSettings *fss)
+static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase)
 {
-       char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
-       char targetDirVel[FILE_MAXFILE+FILE_MAXDIR], targetFileVel[FILE_MAXFILE+FILE_MAXDIR];
-       char previewDir[FILE_MAXFILE+FILE_MAXDIR], previewFile[FILE_MAXFILE+FILE_MAXDIR];
+       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_snprintf(targetDir, sizeof(targetDir), "%sfluidsurface_final_####.bobj.gz", fss->surfdataPath);
-       BLI_snprintf(targetDirVel, sizeof(targetDir), "%sfluidsurface_final_####.bvel.gz", fss->surfdataPath);
-       BLI_snprintf(previewDir, sizeof(targetDir), "%sfluidsurface_preview_####.bobj.gz", fss->surfdataPath);
+       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, G.main->name);
-       BLI_path_abs(targetDirVel, G.main->name);
-       BLI_path_abs(previewDir, G.main->name);
+       BLI_path_abs(targetDir,    relbase);
+       BLI_path_abs(targetDirVel, relbase);
+       BLI_path_abs(previewDir,   relbase);
 
        do {
                BLI_strncpy(targetFile, targetDir, sizeof(targetFile));
@@ -837,7 +836,7 @@ static void fluidsim_delete_until_lastframe(FluidsimSettings *fss)
 
                curFrame++;
 
-               if((exists = BLI_exist(targetFile)))
+               if((exists = BLI_exists(targetFile)))
                {
                        BLI_delete(targetFile, 0, 0);
                        BLI_delete(targetFileVel, 0, 0);
@@ -848,7 +847,7 @@ static void fluidsim_delete_until_lastframe(FluidsimSettings *fss)
        return;
 }
 
-static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
+static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
 {
        Scene *scene= CTX_data_scene(C);
        int i;
@@ -857,12 +856,13 @@ static 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
        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];
@@ -875,25 +875,23 @@ static 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;
        }
@@ -919,11 +917,11 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        domainSettings->lastgoodframe = -1;
 
        /* delete old baked files */
-       fluidsim_delete_until_lastframe(domainSettings);
+       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;
        }
@@ -943,7 +941,7 @@ static 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);
        
        
@@ -995,9 +993,9 @@ static 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;
@@ -1005,7 +1003,8 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
 
        /* ********  start writing / exporting ******** */
        // use .tmp, dont overwrite/delete original file
-       BLI_snprintf(targetFile, 240, "%s%s.tmp", targetDir, suffixConfig);
+       BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfig);
+       strncat(targetFile, ".tmp", sizeof(targetFile));
        
        // make sure these directories exist as well
        if(outStringsChanged) {
@@ -1033,7 +1032,7 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        fsset->aniFrameTime = channels->aniFrameTime;
        fsset->noOfFrames = noFrames; // is otherwise subtracted in parser
 
-       BLI_snprintf(targetFile, 240, "%s%s", targetDir, suffixSurface);
+       BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface);
 
        // defaults for compressibility and adaptive grids
        fsset->gstar = domainSettings->gstar;
@@ -1043,7 +1042,7 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
        fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; 
        fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; 
        fsset->farFieldSize = domainSettings->farFieldSize; 
-       BLI_strncpy(fsset->outputPath, targetFile, 240);
+       BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath));
 
        // domain channels
        fsset->channelSizeFrameTime = 
@@ -1087,12 +1086,25 @@ static 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);
@@ -1106,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 */
 
@@ -1125,22 +1137,30 @@ FluidsimSettings* fluidsimSettingsCopy(FluidsimSettings *UNUSED(fss))
 }
 
 /* only compile dummy functions */
-static 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;
 }
 
-#endif /* DISABLE_ELBEEM */
+#endif /* WITH_MOD_FLUID */
 
 /***************************** Operators ******************************/
 
-static int fluid_bake_exec(bContext *C, wmOperator *op)
+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 0;
+               return OPERATOR_CANCELLED;
 
-       if(!fluidsimBake(C, op->reports, CTX_data_active_object(C)))
+       if(!fluidsimBake(C, op->reports, CTX_data_active_object(C), TRUE))
+               return OPERATOR_CANCELLED;
+
+       return OPERATOR_FINISHED;
+}
+
+static int fluid_bake_exec(bContext *C, wmOperator *op)
+{
+       if(!fluidsimBake(C, op->reports, CTX_data_active_object(C), FALSE))
                return OPERATOR_CANCELLED;
 
        return OPERATOR_FINISHED;
@@ -1154,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;
 }