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:
authorSebastián Barschkis <sebbas@sebbas.org>2019-12-16 17:46:47 +0300
committerSebastián Barschkis <sebbas@sebbas.org>2019-12-16 18:33:54 +0300
commit829a83262f8fc537652f40f1210cb9db6c349ad4 (patch)
tree18ab3eeb11e522b313047fa4a780a6cb9062522d /source/blender/editors/physics/physics_fluid.c
parent41fd60db16fcc95a94789e6c6857cad8d5c73938 (diff)
Mantaflow [Part 7]: Added bake configuration
Similarly to physics_fluid.c (in same directory) which handled the baking process for Elbeem, there is now physics_manta.c which handles it for Mantaflow. There are two types of jobs: one for baking and another for freeing. The generic jobs will be used to bake / free specific parts of the simulation (e.g. bake mesh, free particles, etc.). The jobs are only being used in the "modular" cache mode where the simulation has to be baked in parts. Reviewed By: sergey Maniphest Tasks: T59995 Differential Revision: https://developer.blender.org/D3856
Diffstat (limited to 'source/blender/editors/physics/physics_fluid.c')
-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;
}