Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/physics')
-rw-r--r--source/blender/editors/physics/physics_fluid.c1661
1 files changed, 624 insertions, 1037 deletions
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 44858e36fab..2642f000762 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -1,4 +1,6 @@
/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -15,10 +17,16 @@
*
* The Original Code is Copyright (C) Blender Foundation
* All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
*/
-/** \file
- * \ingroup edphys
+/** \file blender/editors/physics/physics_fluid.c
+ * \ingroup edphys
*/
#include <math.h>
@@ -31,1219 +39,798 @@
/* types */
#include "DNA_action_types.h"
#include "DNA_object_types.h"
-#include "DNA_object_fluidsim_types.h"
+#include "BLI_blenlib.h"
+#include "BLI_path_util.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_fluidsim.h"
+#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_fluid.h"
+#include "BKE_global.h"
#include "DEG_depsgraph.h"
#include "ED_screen.h"
-#include "ED_object.h"
+#include "PIL_time.h"
#include "WM_types.h"
#include "WM_api.h"
#include "physics_intern.h" // own include
+#include "manta_fluid_API.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_fluid_types.h"
+#include "DNA_mesh_types.h"
+
+#define FLUID_JOB_BAKE_ALL "FLUID_OT_bake_all"
+#define FLUID_JOB_BAKE_DATA "FLUID_OT_bake_data"
+#define FLUID_JOB_BAKE_NOISE "FLUID_OT_bake_noise"
+#define FLUID_JOB_BAKE_MESH "FLUID_OT_bake_mesh"
+#define FLUID_JOB_BAKE_PARTICLES "FLUID_OT_bake_particles"
+#define FLUID_JOB_BAKE_GUIDING "FLUID_OT_bake_guiding"
+#define FLUID_JOB_FREE_ALL "FLUID_OT_free_all"
+#define FLUID_JOB_FREE_DATA "FLUID_OT_free_data"
+#define FLUID_JOB_FREE_NOISE "FLUID_OT_free_noise"
+#define FLUID_JOB_FREE_MESH "FLUID_OT_free_mesh"
+#define FLUID_JOB_FREE_PARTICLES "FLUID_OT_free_particles"
+#define FLUID_JOB_FREE_GUIDING "FLUID_OT_free_guiding"
+#define FLUID_JOB_BAKE_PAUSE "FLUID_OT_pause_bake"
+
+typedef struct FluidJob {
+ /* from wmJob */
+ void *owner;
+ short *stop, *do_update;
+ float *progress;
+ const char *type;
+ const char *name;
-/* enable/disable overall compilation */
-#ifdef WITH_MOD_FLUID
-
-# include "LBM_fluidsim.h"
-
-# include "BLI_blenlib.h"
-# include "BLI_path_util.h"
-# include "BLI_math.h"
+ struct Main *bmain;
+ Scene *scene;
+ Depsgraph *depsgraph;
+ Object *ob;
-# include "BKE_global.h"
-# include "BKE_main.h"
+ FluidModifierData *mmd;
-# include "WM_api.h"
+ int success;
+ double start;
-# include "DNA_scene_types.h"
-# include "DNA_mesh_types.h"
+ int *pause_frame;
+} FluidJob;
-static float get_fluid_viscosity(FluidsimSettings *settings)
-{
- return (1.0f / powf(10.0f, settings->viscosityExponent)) * settings->viscosityValue;
+static inline bool fluid_is_bake_all(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_BAKE_ALL));
}
-
-static float get_fluid_rate(FluidsimSettings *settings)
-{
- float rate = 1.0f; /* default rate if not animated... */
-
- rate = settings->animRate;
-
- if (rate < 0.0f) {
- rate = 0.0f;
- }
-
- return rate;
+static inline bool fluid_is_bake_data(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_BAKE_DATA));
}
-
-static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fss)
-{
- if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, scene->physics_settings.gravity);
- }
- else {
- copy_v3_v3(gravity, fss->grav);
- }
+static inline bool fluid_is_bake_noise(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_BAKE_NOISE));
+}
+static inline bool fluid_is_bake_mesh(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_BAKE_MESH));
+}
+static inline bool fluid_is_bake_particle(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_BAKE_PARTICLES));
+}
+static inline bool fluid_is_bake_guiding(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_BAKE_GUIDING));
+}
+static inline bool fluid_is_free_all(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_FREE_ALL));
+}
+static inline bool fluid_is_free_data(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_FREE_DATA));
+}
+static inline bool fluid_is_free_noise(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_FREE_NOISE));
+}
+static inline bool fluid_is_free_mesh(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_FREE_MESH));
+}
+static inline bool fluid_is_free_particles(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_FREE_PARTICLES));
+}
+static inline bool fluid_is_free_guiding(FluidJob *job) {
+ return (STREQ(job->type, FLUID_JOB_FREE_GUIDING));
}
-static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss)
+static bool fluid_initjob(
+ bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size)
{
- if (!scene->unit.system) {
- return fss->realsize;
- }
- else {
- float dim[3];
- float longest_axis;
-
- BKE_object_dimensions_get(domainob, dim);
- longest_axis = max_fff(dim[0], dim[1], dim[2]);
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
- return longest_axis * scene->unit.scale_length;
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
+ return false;
+ }
+ mds = mmd->domain;
+ if (!mds) {
+ BLI_strncpy(error_msg, N_("Bake failed: invalid domain"), error_size);
+ return false;
}
-}
-static bool fluid_is_animated_mesh(FluidsimSettings *fss)
-{
- return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen);
-}
+ job->bmain = CTX_data_main(C);
+ job->scene = CTX_data_scene(C);
+ job->depsgraph = CTX_data_depsgraph_pointer(C);
+ job->ob = CTX_data_active_object(C);
+ job->mmd = mmd;
+ job->type = op->type->idname;
+ job->name = op->type->name;
-/* ********************** fluid sim settings struct functions ********************** */
+ return true;
+}
-# if 0
-/* helper function */
-void fluidsimGetGeometryObjFilename(Object *ob, char *dst) //, char *srcname)
+static bool fluid_initpaths(FluidJob *job, ReportList *reports)
{
- //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
+ FluidDomainSettings *mds = job->mmd->domain;
+ char tmpDir[FILE_MAX];
+ tmpDir[0] = '\0';
-/* ********************** fluid sim channel helper functions ********************** */
+ const char *relbase = modifier_path_relbase(job->bmain, job->ob);
-typedef struct FluidAnimChannels {
- int length;
+ /* We do not accept empty paths, they can end in random places silently, see T51176. */
+ if (mds->cache_directory[0] == '\0') {
+ modifier_path_init(
+ mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT);
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Fluid: Empty cache path, reset to default '%s'",
+ mds->cache_directory);
+ }
- double aniFrameTime;
+ BLI_strncpy(tmpDir, mds->cache_directory, FILE_MAXDIR);
+ BLI_path_abs(tmpDir, relbase);
- float *timeAtFrame;
- float *DomainTime;
- float *DomainGravity;
- float *DomainViscosity;
-} FluidAnimChannels;
+ /* Ensure whole path exists */
+ const bool dir_exists = BLI_dir_create_recursive(tmpDir);
-typedef struct FluidObject {
- struct FluidObject *next, *prev;
+ /* We change path to some presumably valid default value, but do not allow bake process to
+ * continue, this gives user chance to set manually another path. */
+ if (!dir_exists) {
+ modifier_path_init(
+ mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT);
- struct Object *object;
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Fluid: Could not create cache directory '%s', reset to default '%s'",
+ tmpDir,
+ mds->cache_directory);
- float *Translation;
- float *Rotation;
- float *Scale;
- float *Active;
+ BLI_strncpy(tmpDir, mds->cache_directory, FILE_MAXDIR);
+ BLI_path_abs(tmpDir, relbase);
- float *InitialVelocity;
+ /* Ensure whole path exists and is writable. */
+ if (!BLI_dir_create_recursive(tmpDir)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Fluid: Could not use default cache directory '%s', "
+ "please define a valid cache path manually",
+ tmpDir);
+ }
+ /* Copy final dir back into domain settings */
+ BLI_strncpy(mds->cache_directory, tmpDir, FILE_MAXDIR);
- float *AttractforceStrength;
- float *AttractforceRadius;
- float *VelocityforceStrength;
- float *VelocityforceRadius;
+ return false;
+ }
- float *VertexCache;
- int numVerts, numTris;
-} FluidObject;
+ /* Copy final dir back into domain settings */
+ BLI_strncpy(mds->cache_directory, tmpDir, FILE_MAXDIR);
+ return true;
+}
-// no. of entries for the two channel sizes
-# define CHANNEL_FLOAT 1
-# define CHANNEL_VEC 3
+static void fluid_bake_free(void *customdata)
+{
+ FluidJob *job = customdata;
+ MEM_freeN(job);
+}
-// simplify channels before printing
-// for API this is done anyway upon init
-# if 0
-static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries)
+static void fluid_bake_sequence(FluidJob *job)
{
- int i, j;
- int channelSize = paramsize;
+ FluidDomainSettings *mds = job->mmd->domain;
+ Scene *scene = job->scene;
+ int frame = 1, orig_frame;
+ int frames;
+ int *pause_frame = NULL;
+ bool is_first_frame;
- if (entries == 3) {
- elbeemSimplifyChannelVec3(channel, &channelSize);
- }
- else if (entries == 1) {
- elbeemSimplifyChannelFloat(channel, &channelSize);
- }
- else {
- /* invalid, cant happen? */
- }
+ frames = mds->cache_frame_end - mds->cache_frame_start + 1;
- fprintf(file, " CHANNEL %s =\n", str);
- for (i = 0; i < channelSize; i++) {
- fprintf(file, " ");
- for (j = 0; j <= entries; j++) { // also print time value
- fprintf(file, " %f ", channel[i * (entries + 1) + j]);
- if (j == entries - 1) {
- fprintf(file, " ");
- }
- }
- fprintf(file, "\n");
+ if (frames <= 0) {
+ BLI_strncpy(mds->error, N_("No frames to bake"), sizeof(mds->error));
+ return;
}
- fprintf(file, " ;\n");
-}
-# endif
+ /* Show progress bar. */
+ if (job->do_update)
+ *(job->do_update) = true;
-/* Note: fluid anim channel data layout
- * ------------------------------------
- * CHANNEL_FLOAT:
- * frame 1 |frame 2
- * [dataF][time][dataF][time]
- *
- * CHANNEL_VEC:
- * frame 1 |frame 2
- * [dataX][dataY][dataZ][time][dataX][dataY][dataZ][time]
- */
+ /* Get current pause frame (pointer) - depending on bake type */
+ pause_frame = job->pause_frame;
-static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels)
-{
- int i;
+ /* Set frame to start point (depending on current pause frame value) */
+ is_first_frame = ((*pause_frame) == 0);
+ frame = is_first_frame ? mds->cache_frame_start : (*pause_frame);
- channels->timeAtFrame = MEM_callocN((channels->length + 1) * sizeof(float),
- "timeAtFrame channel");
+ /* Save orig frame and update scene frame */
+ orig_frame = CFRA;
+ CFRA = frame;
- channels->timeAtFrame[0] = channels->timeAtFrame[1] =
- domainSettings->animStart; // start at index 1
+ /* Loop through selected frames */
+ for (; frame <= mds->cache_frame_end; frame++) {
+ const float progress = (frame - mds->cache_frame_start) / (float)frames;
- for (i = 2; i <= channels->length; i++) {
- channels->timeAtFrame[i] = channels->timeAtFrame[i - 1] + (float)channels->aniFrameTime;
- }
-}
+ /* Keep track of pause frame - needed to init future loop */
+ (*pause_frame) = frame;
-/* if this is slow, can replace with faster, less readable code */
-static void set_channel(float *channel, float time, float *value, int i, int size)
-{
- if (size == CHANNEL_FLOAT) {
- channel[(i * 2) + 0] = value[0];
- channel[(i * 2) + 1] = time;
- }
- else if (size == CHANNEL_VEC) {
- channel[(i * 4) + 0] = value[0];
- channel[(i * 4) + 1] = value[1];
- channel[(i * 4) + 2] = value[2];
- channel[(i * 4) + 3] = time;
- }
-}
-
-static void set_vertex_channel(Depsgraph *depsgraph,
- float *channel,
- float time,
- struct Scene *scene,
- struct FluidObject *fobj,
- int i)
-{
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- float *verts;
- int *tris = NULL, numVerts = 0, numTris = 0;
- int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
- int framesize = (3 * fobj->numVerts) + 1;
- int j;
-
- if (channel == NULL) {
- return;
- }
+ /* If user requested stop, quit baking */
+ if (G.is_break) {
+ job->success = 0;
+ return;
+ }
- initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex);
+ /* Update progress bar */
+ if (job->do_update)
+ *(job->do_update) = true;
+ if (job->progress)
+ *(job->progress) = progress;
- /* don't allow mesh to change number of verts in anim sequence */
- if (numVerts != fobj->numVerts) {
- MEM_freeN(channel);
- channel = NULL;
- return;
- }
+ CFRA = frame;
- /* fill frame of channel with vertex locations */
- for (j = 0; j < (3 * numVerts); j++) {
- channel[i * framesize + j] = verts[j];
+ /* Update animation system */
+ ED_update_for_newframe(job->bmain, job->depsgraph);
}
- channel[i * framesize + framesize - 1] = time;
- MEM_freeN(verts);
- MEM_freeN(tris);
+ /* Restore frame position that we were on before bake */
+ CFRA = orig_frame;
}
-static void free_domain_channels(FluidAnimChannels *channels)
+static void fluid_bake_endjob(void *customdata)
{
- if (!channels->timeAtFrame) {
- return;
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+
+ if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_NOISE;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_NOISE;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE;
+ }
+ if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_MESH;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_MESH;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_MESH;
+ }
+ if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_PARTICLES;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_PARTICLES;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES;
+ }
+ if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_GUIDING;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_GUIDING;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDING;
+ }
+ if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
+ mds->cache_flag &= ~FLUID_DOMAIN_BAKING_DATA;
+ mds->cache_flag |= FLUID_DOMAIN_BAKED_DATA;
+ mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA;
+ }
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+
+ /* Bake was successful:
+ * Report for ended bake and how long it took */
+ if (job->success) {
+ /* Show bake info */
+ WM_reportf(RPT_INFO,
+ "Fluid: %s complete! (%.2f)",
+ job->name,
+ PIL_check_seconds_timer() - job->start);
}
- MEM_freeN(channels->timeAtFrame);
- channels->timeAtFrame = NULL;
- MEM_freeN(channels->DomainGravity);
- channels->DomainGravity = NULL;
- MEM_freeN(channels->DomainViscosity);
- channels->DomainViscosity = NULL;
- MEM_freeN(channels->DomainTime);
- channels->DomainTime = NULL;
-}
-
-static void free_all_fluidobject_channels(ListBase *fobjects)
-{
- FluidObject *fobj;
-
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- if (fobj->Translation) {
- MEM_freeN(fobj->Translation);
- fobj->Translation = NULL;
- MEM_freeN(fobj->Rotation);
- fobj->Rotation = NULL;
- MEM_freeN(fobj->Scale);
- fobj->Scale = NULL;
- MEM_freeN(fobj->Active);
- fobj->Active = NULL;
- MEM_freeN(fobj->InitialVelocity);
- fobj->InitialVelocity = NULL;
- }
-
- if (fobj->AttractforceStrength) {
- MEM_freeN(fobj->AttractforceStrength);
- fobj->AttractforceStrength = NULL;
- MEM_freeN(fobj->AttractforceRadius);
- fobj->AttractforceRadius = NULL;
- MEM_freeN(fobj->VelocityforceStrength);
- fobj->VelocityforceStrength = NULL;
- MEM_freeN(fobj->VelocityforceRadius);
- fobj->VelocityforceRadius = NULL;
+ else {
+ if (mds->error != NULL && mds->error[0] != '\0') {
+ WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
-
- if (fobj->VertexCache) {
- MEM_freeN(fobj->VertexCache);
- fobj->VertexCache = NULL;
+ else { /* User canceled the bake */
+ WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name);
}
}
}
-static void fluid_init_all_channels(bContext *C,
- Depsgraph *depsgraph,
- Object *UNUSED(fsDomain),
- FluidsimSettings *domainSettings,
- FluidAnimChannels *channels,
- ListBase *fobjects)
+static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Base *base;
- int i;
- int length = channels->length;
- float eval_time;
-
- /* init time values (assuming that time moves at a constant speed; may be overridden later) */
- init_time(domainSettings, channels);
-
- /* allocate domain animation channels */
- channels->DomainGravity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "channel DomainGravity");
- channels->DomainViscosity = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "channel DomainViscosity");
- channels->DomainTime = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "channel DomainTime");
-
- /* allocate fluid objects */
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- Object *ob = base->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- if (fluidmd) {
- FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object");
- fobj->object = ob;
-
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- BLI_addtail(fobjects, fobj);
- continue;
- }
-
- fobj->Translation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject Translation");
- fobj->Rotation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject Rotation");
- fobj->Scale = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), "fluidobject Scale");
- fobj->Active = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject Active");
- fobj->InitialVelocity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float),
- "fluidobject InitialVelocity");
-
- if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
- fobj->AttractforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject AttractforceStrength");
- fobj->AttractforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject AttractforceRadius");
- fobj->VelocityforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject VelocityforceStrength");
- fobj->VelocityforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float),
- "fluidobject VelocityforceRadius");
- }
-
- if (fluid_is_animated_mesh(fluidmd->fss)) {
- float *verts = NULL;
- int *tris = NULL, modifierIndex = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd);
-
- initElbeemMesh(depsgraph,
- scene,
- ob,
- &fobj->numVerts,
- &verts,
- &fobj->numTris,
- &tris,
- 0,
- modifierIndex);
- fobj->VertexCache = MEM_callocN(length * ((fobj->numVerts * CHANNEL_VEC) + 1) *
- sizeof(float),
- "fluidobject VertexCache");
-
- MEM_freeN(verts);
- MEM_freeN(tris);
- }
-
- BLI_addtail(fobjects, fobj);
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+
+ char tmpDir[FILE_MAX];
+ tmpDir[0] = '\0';
+
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
+
+ G.is_break = false;
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
+
+ if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) {
+ tmpDir[0] = '\0';
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'noise' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_NOISE;
+ job->pause_frame = &mds->cache_frame_pause_noise;
+ }
+ if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) {
+ tmpDir[0] = '\0';
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'mesh' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_MESH;
+ job->pause_frame = &mds->cache_frame_pause_mesh;
+ }
+ if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) {
+ tmpDir[0] = '\0';
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'particles' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_OUTDATED_PARTICLES);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_PARTICLES;
+ job->pause_frame = &mds->cache_frame_pause_particles;
+ }
+ if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) {
+ tmpDir[0] = '\0';
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDING, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'guiding' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDING | FLUID_DOMAIN_OUTDATED_GUIDING);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_GUIDING;
+ job->pause_frame = &mds->cache_frame_pause_guiding;
+ }
+ if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) {
+ tmpDir[0] = '\0';
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'config' subdir if it does not exist already */
+ tmpDir[0] = '\0';
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'data' subdir if it does not exist already */
+ mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA);
+ mds->cache_flag |= FLUID_DOMAIN_BAKING_DATA;
+ job->pause_frame = &mds->cache_frame_pause_data;
+
+ if (mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) {
+ BLI_path_join(tmpDir, sizeof(tmpDir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL);
+ BLI_dir_create_recursive(tmpDir); /* Create 'script' subdir if it does not exist already */
}
}
+ DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY);
- /* now we loop over the frames and fill the allocated channels with data */
- for (i = 0; i < channels->length; i++) {
- FluidObject *fobj;
- float viscosity, gravity[3];
- float timeAtFrame, time;
-
- eval_time = domainSettings->bakeStart + i;
+ fluid_bake_sequence(job);
- /* 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(CTX_data_main(C), depsgraph);
-
- /* now scene data should be current according to animation system, so we fill the channels */
-
- /* Domain time */
- /* TODO: have option for not running sim, time mangling,
- * in which case second case comes in handy. */
- if (channels->DomainTime) {
- time = get_fluid_rate(domainSettings) * (float)channels->aniFrameTime;
- timeAtFrame = channels->timeAtFrame[i] + time;
+ if (do_update)
+ *do_update = true;
+ if (stop)
+ *stop = 0;
+}
- channels->timeAtFrame[i + 1] = timeAtFrame;
- set_channel(channels->DomainTime, i, &time, i, CHANNEL_FLOAT);
- }
- else {
- timeAtFrame = channels->timeAtFrame[i + 1];
+static void fluid_free_endjob(void *customdata)
+{
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+
+ G.is_rendering = false;
+ BKE_spacedata_draw_locks(false);
+ WM_set_locked_interface(G_MAIN->wm.first, false);
+
+ /* Free was successful:
+ * Report for ended free job and how long it took */
+ if (job->success) {
+ /* Show free job info */
+ WM_reportf(RPT_INFO,
+ "Fluid: %s complete! (%.2f)",
+ job->name,
+ PIL_check_seconds_timer() - job->start);
+ }
+ else {
+ if (mds->error != NULL && mds->error[0] != '\0') {
+ WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
-
- /* Domain properties - gravity/viscosity */
- get_fluid_gravity(gravity, scene, domainSettings);
- set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC);
- viscosity = get_fluid_viscosity(domainSettings);
- set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT);
-
- /* object movement */
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- float active = (float)((fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE) ? 1 : 0);
- 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 */
- /* 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, (float)-M_PI / 180.f);
- }
-
- mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat);
- mul_v3_fl(rot_d, -180.0f / (float)M_PI);
-
- set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC);
- set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC);
- set_channel(fobj->Scale, timeAtFrame, ob->scale, i, CHANNEL_VEC);
- set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT);
- set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC);
-
- // printf("Active: %f, Frame: %f\n", active, timeAtFrame);
-
- if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) {
- set_channel(fobj->AttractforceStrength,
- timeAtFrame,
- &fluidmd->fss->attractforceStrength,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->AttractforceRadius,
- timeAtFrame,
- &fluidmd->fss->attractforceRadius,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->VelocityforceStrength,
- timeAtFrame,
- &fluidmd->fss->velocityforceStrength,
- i,
- CHANNEL_FLOAT);
- set_channel(fobj->VelocityforceRadius,
- timeAtFrame,
- &fluidmd->fss->velocityforceRadius,
- i,
- CHANNEL_FLOAT);
- }
-
- if (fluid_is_animated_mesh(fluidmd->fss)) {
- set_vertex_channel(depsgraph, fobj->VertexCache, timeAtFrame, scene, fobj, i);
- }
+ else { /* User canceled the free job */
+ WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name);
}
}
}
-static void export_fluid_objects(Depsgraph *depsgraph,
- ListBase *fobjects,
- Scene *scene,
- int length)
+static void fluid_free_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
- FluidObject *fobj;
-
- for (fobj = fobjects->first; fobj; fobj = fobj->next) {
- Object *ob = fobj->object;
- FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
- int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd);
+ FluidJob *job = customdata;
+ FluidDomainSettings *mds = job->mmd->domain;
+ Scene *scene = job->scene;
- float *verts = NULL;
- int *tris = NULL;
- int numVerts = 0, numTris = 0;
- bool deform = fluid_is_animated_mesh(fluidmd->fss);
+ char tmpDir[FILE_MAX];
+ tmpDir[0] = '\0';
- elbeemMesh fsmesh;
+ job->stop = stop;
+ job->do_update = do_update;
+ job->progress = progress;
+ job->start = PIL_check_seconds_timer();
+ job->success = 1;
- if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- continue;
- }
+ G.is_break = false;
+ G.is_rendering = true;
+ BKE_spacedata_draw_locks(true);
- elbeemResetMesh(&fsmesh);
+ int cache_map = 0;
- fsmesh.type = fluidmd->fss->type;
- fsmesh.name = ob->id.name;
+ if (fluid_is_free_data(job) || fluid_is_free_all(job)) {
+ cache_map |= (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE |
+ FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES);
+ }
+ if (fluid_is_free_noise(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_NOISE;
+ }
+ if (fluid_is_free_mesh(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_MESH;
+ }
+ if (fluid_is_free_particles(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_PARTICLES;
+ }
+ if (fluid_is_free_guiding(job) || fluid_is_free_all(job)) {
+ cache_map |= FLUID_DOMAIN_OUTDATED_GUIDING;
+ }
+ BKE_fluid_cache_free(mds, job->ob, cache_map);
- initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex);
+ *do_update = true;
+ *stop = 0;
- fsmesh.numVertices = numVerts;
- fsmesh.numTriangles = numTris;
- fsmesh.vertices = verts;
- fsmesh.triangles = tris;
+ /* Reset scene frame to cache frame start */
+ CFRA = mds->cache_frame_start;
- fsmesh.channelSizeTranslation = fsmesh.channelSizeRotation = fsmesh.channelSizeScale =
- fsmesh.channelSizeInitialVel = fsmesh.channelSizeActive = length;
+ /* Update scene so that viewport shows freed up scene */
+ ED_update_for_newframe(job->bmain, job->depsgraph);
+}
- fsmesh.channelTranslation = fobj->Translation;
- fsmesh.channelRotation = fobj->Rotation;
- fsmesh.channelScale = fobj->Scale;
- fsmesh.channelActive = fobj->Active;
+/***************************** Operators ******************************/
- if (ELEM(fsmesh.type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
- fsmesh.channelInitialVel = fobj->InitialVelocity;
- fsmesh.localInivelCoords = ((fluidmd->fss->typeFlags & OB_FSINFLOW_LOCALCOORD) ? 1 : 0);
- }
+static int fluid_bake_exec(struct bContext *C, struct wmOperator *op)
+{
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ char error_msg[256] = "\0";
- if (fluidmd->fss->typeFlags & OB_FSBND_NOSLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- else if (fluidmd->fss->typeFlags & OB_FSBND_PARTSLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP;
- }
- else if (fluidmd->fss->typeFlags & OB_FSBND_FREESLIP) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP;
+ if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
}
+ fluid_bake_free(job);
+ return OPERATOR_CANCELLED;
+ }
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ fluid_bake_startjob(job, NULL, NULL, NULL);
+ fluid_bake_endjob(job);
+ fluid_bake_free(job);
- fsmesh.obstaclePartslip = fluidmd->fss->partSlipValue;
- fsmesh.volumeInitType = fluidmd->fss->volumeInitType;
- fsmesh.obstacleImpactFactor = fluidmd->fss->surfaceSmoothing; // misused value
-
- if (fsmesh.type == OB_FLUIDSIM_CONTROL) {
- fsmesh.cpsTimeStart = fluidmd->fss->cpsTimeStart;
- fsmesh.cpsTimeEnd = fluidmd->fss->cpsTimeEnd;
- fsmesh.cpsQuality = fluidmd->fss->cpsQuality;
- fsmesh.obstacleType = (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE);
+ return OPERATOR_FINISHED;
+}
- fsmesh.channelSizeAttractforceRadius = fsmesh.channelSizeVelocityforceStrength =
- fsmesh.channelSizeVelocityforceRadius = fsmesh.channelSizeAttractforceStrength = length;
+static int fluid_bake_invoke(struct bContext *C,
+ struct wmOperator *op,
+ const wmEvent *UNUSED(_event))
+{
+ Scene *scene = CTX_data_scene(C);
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ char error_msg[256] = "\0";
- fsmesh.channelAttractforceStrength = fobj->AttractforceStrength;
- fsmesh.channelAttractforceRadius = fobj->AttractforceRadius;
- fsmesh.channelVelocityforceStrength = fobj->VelocityforceStrength;
- fsmesh.channelVelocityforceRadius = fobj->VelocityforceRadius;
- }
- else {
- fsmesh.channelAttractforceStrength = fsmesh.channelAttractforceRadius =
- fsmesh.channelVelocityforceStrength = fsmesh.channelVelocityforceRadius = NULL;
+ if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) {
+ if (error_msg[0]) {
+ BKE_report(op->reports, RPT_ERROR, error_msg);
}
+ fluid_bake_free(job);
+ return OPERATOR_CANCELLED;
+ }
- /* animated meshes */
- if (deform) {
- fsmesh.channelSizeVertices = length;
- fsmesh.channelVertices = fobj->VertexCache;
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
- /* remove channels */
- fsmesh.channelTranslation = fsmesh.channelRotation = fsmesh.channelScale = NULL;
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Fluid Bake",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_OBJECT_SIM_FLUID);
- /* Override user settings, only noslip is supported here! */
- if (fsmesh.type != OB_FLUIDSIM_CONTROL) {
- fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- }
+ WM_jobs_customdata_set(wm_job, job, fluid_bake_free);
+ WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, fluid_bake_startjob, NULL, NULL, fluid_bake_endjob);
- elbeemAddMesh(&fsmesh);
+ WM_set_locked_interface(CTX_wm_manager(C), true);
- if (verts) {
- MEM_freeN(verts);
- }
- if (tris) {
- MEM_freeN(tris);
- }
- }
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
}
-static int fluid_validate_scene(ReportList *reports, ViewLayer *view_layer, Object *fsDomain)
+static int fluid_bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- Base *base;
- Object *newdomain = NULL;
- int channelObjCount = 0;
- int fluidInputCount = 0;
-
- for (base = FIRSTBASE(view_layer); base; base = base->next) {
- Object *ob = base->object;
- FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType(
- ob, eModifierType_Fluidsim);
-
- /* only find objects with fluid modifiers */
- if (!fluidmdtmp || ob->type != OB_MESH) {
- continue;
- }
-
- if (fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) {
- /* if no initial domain object given, find another potential domain */
- if (!fsDomain) {
- newdomain = ob;
- }
- /* 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");
- return 0;
- }
- }
-
- /* count number of objects needed for animation channels */
- if (!ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) {
- channelObjCount++;
- }
+ /* no running blender, remove handler and pass through */
+ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID))
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
- /* count number of fluid input objects */
- if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) {
- fluidInputCount++;
- }
+ switch (event->type) {
+ case ESCKEY:
+ return OPERATOR_RUNNING_MODAL;
}
+ return OPERATOR_PASS_THROUGH;
+}
- if (newdomain) {
- fsDomain = newdomain;
- }
+static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
+{
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
- if (!fsDomain) {
- BKE_report(reports, RPT_ERROR, "No domain object found");
- return 0;
+ /*
+ * Get modifier data
+ */
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
+ return OPERATOR_CANCELLED;
}
-
- if (channelObjCount >= 255) {
- BKE_report(reports, RPT_ERROR, "Cannot bake with more than 256 objects");
- return 0;
+ mds = mmd->domain;
+ if (!mds) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
+ return OPERATOR_CANCELLED;
}
- if (fluidInputCount == 0) {
- BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene");
- return 0;
+ /* Cannot free data if other bakes currently working */
+ if (mmd->domain->cache_flag & (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE |
+ FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKING_PARTICLES)) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: pending bake jobs found");
+ return OPERATOR_CANCELLED;
}
- return 1;
-}
-
-# define FLUID_SUFFIX_CONFIG "fluidsim.cfg"
-# define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp")
-# define FLUID_SUFFIX_SURFACE "fluidsurface"
-
-static bool fluid_init_filepaths(Main *bmain,
- ReportList *reports,
- FluidsimSettings *domainSettings,
- Object *fsDomain,
- char *targetDir,
- char *targetFile)
-{
- const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
-
- /* prepare names... */
- const char *relbase = modifier_path_relbase(bmain, fsDomain);
+ FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob");
+ job->bmain = CTX_data_main(C);
+ job->scene = scene;
+ job->depsgraph = CTX_data_depsgraph_pointer(C);
+ job->ob = ob;
+ job->mmd = mmd;
+ job->type = op->type->idname;
+ job->name = op->type->name;
- /* We do not accept empty paths, they can end in random places silently, see T51176. */
- if (domainSettings->surfdataPath[0] == '\0') {
- modifier_path_init(domainSettings->surfdataPath,
- sizeof(domainSettings->surfdataPath),
- OB_FLUIDSIM_SURF_DIR_DEFAULT);
- BKE_reportf(reports,
- RPT_WARNING,
- "Fluidsim: empty cache path, reset to default '%s'",
- domainSettings->surfdataPath);
+ if (!fluid_initpaths(job, op->reports)) {
+ return OPERATOR_CANCELLED;
}
- BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, relbase);
-
- /* .tmp: don't overwrite/delete original file */
- BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
-
- /* Ensure whole path exists and is writeable. */
- const bool dir_exists = BLI_dir_create_recursive(targetDir);
- const bool is_writable = BLI_file_is_writable(targetFile);
-
- /* We change path to some presumably valid default value,
- * but do not allow bake process to continue,
- * this gives user chance to set manually another path. */
- if (!dir_exists || !is_writable) {
- modifier_path_init(domainSettings->surfdataPath,
- sizeof(domainSettings->surfdataPath),
- OB_FLUIDSIM_SURF_DIR_DEFAULT);
-
- if (!dir_exists) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: could not create cache directory '%s', reset to default '%s'",
- targetDir,
- domainSettings->surfdataPath);
- }
- else {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: cache directory '%s' is not writable, reset to default '%s'",
- targetDir,
- domainSettings->surfdataPath);
- }
+ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
+ CTX_wm_window(C),
+ scene,
+ "Fluid Free",
+ WM_JOB_PROGRESS,
+ WM_JOB_TYPE_OBJECT_SIM_FLUID);
- BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
- BLI_path_abs(targetDir, relbase);
+ WM_jobs_customdata_set(wm_job, job, fluid_bake_free);
+ WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER);
+ WM_jobs_callbacks(wm_job, fluid_free_startjob, NULL, NULL, fluid_free_endjob);
- /* .tmp: don't overwrite/delete original file */
- BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp);
+ WM_set_locked_interface(CTX_wm_manager(C), true);
- /* Ensure whole path exists and is writeable. */
- if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Fluidsim: could not use default cache directory '%s', "
- "please define a valid cache path manually",
- targetDir);
- }
- return false;
- }
+ /* Free Fluid Geometry */
+ WM_jobs_start(CTX_wm_manager(C), wm_job);
- return true;
+ return OPERATOR_FINISHED;
}
-/* ******************************************************************************** */
-/* ********************** write fluidsim config to file ************************* */
-/* ******************************************************************************** */
+static int fluid_pause_exec(struct bContext *C, struct wmOperator *op)
+{
+ FluidModifierData *mmd = NULL;
+ FluidDomainSettings *mds;
+ Object *ob = CTX_data_active_object(C);
+
+ /*
+ * Get modifier data
+ */
+ mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ if (!mmd) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
+ return OPERATOR_CANCELLED;
+ }
+ mds = mmd->domain;
+ if (!mds) {
+ BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain");
+ return OPERATOR_CANCELLED;
+ }
-typedef struct FluidBakeJob {
- /* from wmJob */
- void *owner;
- short *stop, *do_update;
- float *progress;
- int current_frame;
- elbeemSimulationSettings *settings;
-} FluidBakeJob;
+ G.is_break = true;
-static void fluidbake_free(void *customdata)
-{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
- MEM_freeN(fb);
+ return OPERATOR_FINISHED;
}
-/* called by fluidbake, only to check job 'stop' value */
-static int fluidbake_breakjob(void *customdata)
+void FLUID_OT_bake_all(wmOperatorType *ot)
{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
-
- if (fb->stop && *(fb->stop)) {
- return 1;
- }
+ /* identifiers */
+ ot->name = "Bake All";
+ ot->description = "Bake Entire Fluid Simulation";
+ ot->idname = FLUID_JOB_BAKE_ALL;
- /* this is not nice yet, need to make the jobs list template better
- * for identifying/acting upon various different jobs */
- /* but for now we'll reuse the render break... */
- return (G.is_break);
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-/* called by fluidbake, wmJob sends notifier */
-static void fluidbake_updatejob(void *customdata, float progress)
+void FLUID_OT_free_all(wmOperatorType *ot)
{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+ /* identifiers */
+ ot->name = "Free All";
+ ot->description = "Free Entire Fluid Simulation";
+ ot->idname = FLUID_JOB_FREE_ALL;
- *(fb->do_update) = true;
- *(fb->progress) = progress;
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress)
+void FLUID_OT_bake_data(wmOperatorType *ot)
{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
-
- fb->stop = stop;
- fb->do_update = do_update;
- fb->progress = progress;
-
- G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
+ /* identifiers */
+ ot->name = "Bake Data";
+ ot->description = "Bake Fluid Data";
+ ot->idname = FLUID_JOB_BAKE_DATA;
- elbeemSimulate();
- *do_update = true;
- *stop = 0;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-static void fluidbake_endjob(void *customdata)
+void FLUID_OT_free_data(wmOperatorType *ot)
{
- FluidBakeJob *fb = (FluidBakeJob *)customdata;
+ /* identifiers */
+ ot->name = "Free Data";
+ ot->description = "Free Fluid Data";
+ ot->idname = FLUID_JOB_FREE_DATA;
- if (fb->settings) {
- MEM_freeN(fb->settings);
- fb->settings = NULL;
- }
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-static int runSimulationCallback(void *data, int status, int frame)
+void FLUID_OT_bake_noise(wmOperatorType *ot)
{
- FluidBakeJob *fb = (FluidBakeJob *)data;
- elbeemSimulationSettings *settings = fb->settings;
-
- if (status == FLUIDSIM_CBSTATUS_NEWFRAME) {
- fluidbake_updatejob(fb, frame / (float)settings->noOfFrames);
-# if 0
- printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d\n",
- status,
- frame,
- settings->domainId,
- settings->noOfFrames); // DEBUG
-# endif
- }
-
- if (fluidbake_breakjob(fb)) {
- return FLUIDSIM_CBRET_ABORT;
- }
+ /* identifiers */
+ ot->name = "Bake Noise";
+ ot->description = "Bake Fluid Noise";
+ ot->idname = FLUID_JOB_BAKE_NOISE;
- return FLUIDSIM_CBRET_CONTINUE;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-static void fluidbake_free_data(FluidAnimChannels *channels,
- ListBase *fobjects,
- elbeemSimulationSettings *fsset,
- FluidBakeJob *fb)
+void FLUID_OT_free_noise(wmOperatorType *ot)
{
- free_domain_channels(channels);
- MEM_freeN(channels);
- channels = NULL;
-
- free_all_fluidobject_channels(fobjects);
- BLI_freelistN(fobjects);
- MEM_freeN(fobjects);
- fobjects = NULL;
-
- if (fsset) {
- MEM_freeN(fsset);
- fsset = NULL;
- }
+ /* identifiers */
+ ot->name = "Free Noise";
+ ot->description = "Free Fluid Noise";
+ ot->idname = FLUID_JOB_FREE_NOISE;
- if (fb) {
- MEM_freeN(fb);
- fb = NULL;
- }
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-/* copied from rna_fluidsim.c: fluidsim_find_lastframe() */
-static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase)
+void FLUID_OT_bake_mesh(wmOperatorType *ot)
{
- 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, false, false);
- BLI_delete(targetFileVel, false, false);
- BLI_delete(previewFile, false, false);
- }
- } while (exists);
+ /* identifiers */
+ ot->name = "Bake Mesh";
+ ot->description = "Bake Fluid Mesh";
+ ot->idname = FLUID_JOB_BAKE_MESH;
- return;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job)
+void FLUID_OT_free_mesh(wmOperatorType *ot)
{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- int i;
- FluidsimSettings *domainSettings;
-
- char debugStrBuffer[256];
-
- int gridlevels = 0;
- const char *relbase = modifier_path_relbase(bmain, fsDomain);
- const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
- const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP;
- const char *suffixSurface = FLUID_SUFFIX_SURFACE;
-
- char targetDir[FILE_MAX]; // store & modify output settings
- char targetFile[FILE_MAX]; // temp. store filename from targetDir for access
-
- float domainMat[4][4];
- float invDomMat[4][4];
-
- int noFrames;
- int origFrame = scene->r.cfra;
-
- FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels),
- "fluid domain animation channels");
- ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects");
- FluidsimModifierData *fluidmd = NULL;
- Mesh *mesh = NULL;
-
- FluidBakeJob *fb;
- elbeemSimulationSettings *fsset = MEM_callocN(sizeof(elbeemSimulationSettings),
- "Fluid sim settings");
-
- fb = MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
-
- if (BLI_getenv(strEnvName)) {
- int dlevel = atoi(BLI_getenv(strEnvName));
- elbeemSetDebugLevel(dlevel);
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "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)");
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
-
- /* check scene for sane object/modifier settings */
- if (!fluid_validate_scene(reports, view_layer, fsDomain)) {
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
-
- /* these both have to be valid, otherwise we wouldn't be here */
- fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim);
- domainSettings = fluidmd->fss;
- mesh = fsDomain->data;
-
- domainSettings->bakeStart = 1;
- domainSettings->bakeEnd = scene->r.efra;
-
- // calculate bounding box
- fluid_get_bb(mesh->mvert,
- mesh->totvert,
- fsDomain->obmat,
- domainSettings->bbStart,
- domainSettings->bbSize);
-
- // 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) {
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n",
- domainSettings->previewresxyz,
- domainSettings->resolutionxyz);
- elbeemDebugOut(debugStrBuffer);
- domainSettings->previewresxyz = domainSettings->resolutionxyz;
- }
- // set adaptive coarsening according to resolutionxyz
- // this should do as an approximation, with in/outflow
- // doing this more accurate would be overkill
- // perhaps add manual setting?
- if (domainSettings->maxRefine < 0) {
- if (domainSettings->resolutionxyz > 128) {
- gridlevels = 2;
- }
- else if (domainSettings->resolutionxyz > 64) {
- gridlevels = 1;
- }
- else {
- gridlevels = 0;
- }
- }
- else {
- gridlevels = domainSettings->maxRefine;
- }
- BLI_snprintf(debugStrBuffer,
- sizeof(debugStrBuffer),
- "fluidsimBake::msg: Baking %s, refine: %d\n",
- fsDomain->id.name,
- gridlevels);
- elbeemDebugOut(debugStrBuffer);
-
- /* ******** prepare output file paths ******** */
- if (!fluid_init_filepaths(bmain, reports, domainSettings, fsDomain, targetDir, targetFile)) {
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return false;
- }
-
- /* DG TODO: why using endframe and not "noFrames" here?
- * because "noFrames" is buggy too? (not using sfra) */
- channels->length = scene->r.efra;
- channels->aniFrameTime = (double)((double)domainSettings->animEnd -
- (double)domainSettings->animStart) /
- (double)noFrames;
-
- /* ******** initialize and allocate animation channels ******** */
- fluid_init_all_channels(C, depsgraph, fsDomain, domainSettings, channels, fobjects);
-
- /* reset to original current frame */
- scene->r.cfra = origFrame;
- ED_update_for_newframe(CTX_data_main(C), CTX_data_depsgraph_pointer(C));
-
- /* ******** init domain object's matrix ******** */
- copy_m4_m4(domainMat, fsDomain->obmat);
- if (!invert_m4_m4(invDomMat, domainMat)) {
- BLI_snprintf(
- debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n");
- elbeemDebugOut(debugStrBuffer);
- BKE_report(reports, RPT_ERROR, "Invalid object matrix");
-
- fluidbake_free_data(channels, fobjects, fsset, fb);
- return 0;
- }
-
- /* ******** start writing / exporting ******** */
- // use .tmp, don't overwrite/delete original file
- BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp);
-
- /* ******** export domain to elbeem ******** */
- elbeemResetSettings(fsset);
- fsset->version = 1;
- fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) :
- domainSettings->threads;
- // setup global settings
- copy_v3_v3(fsset->geoStart, domainSettings->bbStart);
- copy_v3_v3(fsset->geoSize, domainSettings->bbSize);
-
- // simulate with 50^3
- fsset->resolutionxyz = (int)domainSettings->resolutionxyz;
- fsset->previewresxyz = (int)domainSettings->previewresxyz;
-
- fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings);
- fsset->viscosity = get_fluid_viscosity(domainSettings);
- get_fluid_gravity(fsset->gravity, scene, domainSettings);
-
- // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
- fsset->animStart = domainSettings->animStart;
- fsset->aniFrameTime = channels->aniFrameTime;
- fsset->noOfFrames = noFrames; // is otherwise subtracted in parser
-
- BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface);
-
- // defaults for compressibility and adaptive grids
- fsset->gstar = domainSettings->gstar;
- fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels
- fsset->generateParticles = domainSettings->generateParticles;
- fsset->numTracerParticles = domainSettings->generateTracers;
- fsset->surfaceSmoothing = domainSettings->surfaceSmoothing;
- fsset->surfaceSubdivs = domainSettings->surfaceSubdivs;
- fsset->farFieldSize = domainSettings->farFieldSize;
- BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath));
-
- // domain channels
- fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity =
- channels->length;
- fsset->channelFrameTime = channels->DomainTime;
- fsset->channelViscosity = channels->DomainViscosity;
- fsset->channelGravity = channels->DomainGravity;
-
- fsset->runsimCallback = &runSimulationCallback;
- fsset->runsimUserData = fb;
-
- if (domainSettings->typeFlags & OB_FSBND_NOSLIP) {
- fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
- }
- 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
- {
- int j;
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- fsset->surfaceTrafo[i * 4 + j] = invDomMat[j][i];
- }
- }
- }
-
- /* ******** init solver with settings ******** */
- elbeemInit();
- elbeemAddDomain(fsset);
-
- /* ******** export all fluid objects to elbeem ******** */
- export_fluid_objects(depsgraph, fobjects, scene, channels->length);
-
- /* custom data for fluid bake job */
- fb->settings = fsset;
-
- if (do_job) {
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
- CTX_wm_window(C),
- scene,
- "Fluid Simulation",
- WM_JOB_PROGRESS,
- WM_JOB_TYPE_OBJECT_SIM_FLUID);
-
- /* setup job */
- WM_jobs_customdata_set(wm_job, fb, fluidbake_free);
- WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME);
- WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
-
- WM_jobs_start(CTX_wm_manager(C), wm_job);
- }
- else {
- short dummy_stop = 0, dummy_do_update = 0;
- float dummy_progress = 0.0f;
-
- /* 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);
+ /* identifiers */
+ ot->name = "Free Mesh";
+ ot->description = "Free Fluid Mesh";
+ ot->idname = FLUID_JOB_FREE_MESH;
- // elbeemFree();
- return 1;
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-static void UNUSED_FUNCTION(fluidsimFreeBake)(Object *UNUSED(ob))
+void FLUID_OT_bake_particles(wmOperatorType *ot)
{
- /* not implemented yet */
-}
-
-#else /* WITH_MOD_FLUID */
+ /* identifiers */
+ ot->name = "Bake Particles";
+ ot->description = "Bake Fluid Particles";
+ ot->idname = FLUID_JOB_BAKE_PARTICLES;
-/* only compile dummy functions */
-static int fluidsimBake(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
- Object *UNUSED(ob),
- short UNUSED(do_job))
-{
- return 0;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-#endif /* WITH_MOD_FLUID */
+void FLUID_OT_free_particles(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Free Particles";
+ ot->description = "Free Fluid Particles";
+ ot->idname = FLUID_JOB_FREE_PARTICLES;
-/***************************** Operators ******************************/
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
+}
-static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+void FLUID_OT_bake_guiding(wmOperatorType *ot)
{
- /* only one bake job at a time */
- if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) {
- return OPERATOR_CANCELLED;
- }
-
- if (!fluidsimBake(C, op->reports, ED_object_context(C), true)) {
- return OPERATOR_CANCELLED;
- }
+ /* identifiers */
+ ot->name = "Bake Guiding";
+ ot->description = "Bake Fluid Guiding";
+ ot->idname = FLUID_JOB_BAKE_GUIDING;
- return OPERATOR_FINISHED;
+ /* api callbacks */
+ ot->exec = fluid_bake_exec;
+ ot->invoke = fluid_bake_invoke;
+ ot->modal = fluid_bake_modal;
+ ot->poll = ED_operator_object_active_editable;
}
-static int fluid_bake_exec(bContext *C, wmOperator *op)
+void FLUID_OT_free_guiding(wmOperatorType *ot)
{
- if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), false)) {
- return OPERATOR_CANCELLED;
- }
+ /* identifiers */
+ ot->name = "Free Guiding";
+ ot->description = "Free Fluid Guiding";
+ ot->idname = FLUID_JOB_FREE_GUIDING;
- return OPERATOR_FINISHED;
+ /* api callbacks */
+ ot->exec = fluid_free_exec;
+ ot->poll = ED_operator_object_active_editable;
}
-void FLUID_OT_bake(wmOperatorType *ot)
+void FLUID_OT_pause_bake(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Fluid Simulation Bake";
- ot->description = "Bake fluid simulation";
- ot->idname = "FLUID_OT_bake";
+ ot->name = "Pause Bake";
+ ot->description = "Pause Bake";
+ ot->idname = FLUID_JOB_BAKE_PAUSE;
/* api callbacks */
- ot->invoke = fluid_bake_invoke;
- ot->exec = fluid_bake_exec;
+ ot->exec = fluid_pause_exec;
ot->poll = ED_operator_object_active_editable;
}