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:41:07 +0300
committerSebastián Barschkis <sebbas@sebbas.org>2019-12-16 18:29:08 +0300
commit2aa4301c88aac15d81e08b1f5ac24da2a9279243 (patch)
treefc4819b647d7bd229abfb71efe2cdc11b88334be /intern/mantaflow
parent4ff7c5eed6b546ae42692f3a869a5ccc095a9cb4 (diff)
Mantaflow [Part 2]: Added fluid wrapper files
Files from /intern/mantaflow handle the communication between core Blender code and Mantaflow itself. It's the bridge to communicate with Mantas Python functions. Code from /intern/mantaflow/intern/strings/ is pure Manta code and would likely need less attention in the review. Reviewed By: sergey Maniphest Tasks: T59995 Differential Revision: https://developer.blender.org/D3851
Diffstat (limited to 'intern/mantaflow')
-rw-r--r--intern/mantaflow/CMakeLists.txt67
-rw-r--r--intern/mantaflow/extern/manta_fluid_API.h232
-rw-r--r--intern/mantaflow/extern/manta_python_API.h45
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp2679
-rw-r--r--intern/mantaflow/intern/MANTA_main.h850
-rw-r--r--intern/mantaflow/intern/manta_fluid_API.cpp872
-rw-r--r--intern/mantaflow/intern/manta_python_API.cpp36
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h805
-rw-r--r--intern/mantaflow/intern/strings/liquid_script.h462
-rw-r--r--intern/mantaflow/intern/strings/smoke_script.h581
10 files changed, 6629 insertions, 0 deletions
diff --git a/intern/mantaflow/CMakeLists.txt b/intern/mantaflow/CMakeLists.txt
new file mode 100644
index 00000000000..9fdd8b59aca
--- /dev/null
+++ b/intern/mantaflow/CMakeLists.txt
@@ -0,0 +1,67 @@
+# ***** 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
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2019, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Sebastian Barschkis (sebbas)
+#
+# ***** END GPL LICENSE BLOCK *****
+
+add_definitions(-DWITH_FLUID=1)
+
+if(WITH_OPENVDB)
+ add_definitions(-DOPENVDB=1)
+endif()
+
+set(INC
+ extern
+ intern/strings
+ ../../source/blender/makesdna
+ ../../source/blender/blenlib
+)
+
+# Python is always required
+add_definitions(-DWITH_PYTHON)
+
+set(INC_SYS
+ ../../extern/mantaflow/helper/util
+ ../../extern/mantaflow/helper/pwrapper
+ ../../extern/mantaflow/preprocessed
+ ${PYTHON_INCLUDE_DIRS}
+ ${ZLIB_INCLUDE_DIRS}
+)
+
+set(SRC
+ intern/manta_python_API.cpp
+ intern/manta_fluid_API.cpp
+ intern/MANTA_main.cpp
+
+ extern/manta_python_API.h
+ extern/manta_fluid_API.h
+ intern/MANTA_main.h
+ intern/strings/fluid_script.h
+ intern/strings/smoke_script.h
+ intern/strings/liquid_script.h
+)
+
+set(LIB
+ extern_mantaflow
+)
+
+blender_add_lib(bf_intern_mantaflow "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/mantaflow/extern/manta_fluid_API.h b/intern/mantaflow/extern/manta_fluid_API.h
new file mode 100644
index 00000000000..9e0bd2d9a3e
--- /dev/null
+++ b/intern/mantaflow/extern/manta_fluid_API.h
@@ -0,0 +1,232 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/extern/manta_smoke_API.h
+ * \ingroup mantaflow
+ */
+
+#ifndef MANTA_API_H
+#define MANTA_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct MANTA;
+
+/* Fluid functions */
+struct MANTA *manta_init(int *res, struct FluidModifierData *mmd);
+void manta_free(struct MANTA *fluid);
+void manta_ensure_obstacle(struct MANTA *fluid, struct FluidModifierData *mmd);
+void manta_ensure_guiding(struct MANTA *fluid, struct FluidModifierData *mmd);
+void manta_ensure_invelocity(struct MANTA *fluid, struct FluidModifierData *mmd);
+void manta_ensure_outflow(struct MANTA *fluid, struct FluidModifierData *mmd);
+int manta_write_config(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_write_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_config(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_noise(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_mesh(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_particles(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_read_guiding(struct MANTA *fluid,
+ struct FluidModifierData *mmd,
+ int framenr,
+ bool sourceDomain);
+int manta_update_liquid_structures(struct MANTA *fluid,
+ struct FluidModifierData *mmd,
+ int framenr);
+int manta_update_mesh_structures(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_update_particle_structures(struct MANTA *fluid,
+ struct FluidModifierData *mmd,
+ int framenr);
+int manta_bake_data(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_bake_noise(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_bake_mesh(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_bake_particles(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+int manta_bake_guiding(struct MANTA *fluid, struct FluidModifierData *mmd, int framenr);
+void manta_update_variables(struct MANTA *fluid, struct FluidModifierData *mmd);
+int manta_get_frame(struct MANTA *fluid);
+float manta_get_timestep(struct MANTA *fluid);
+void manta_adapt_timestep(struct MANTA *fluid);
+bool manta_needs_realloc(struct MANTA *fluid, struct FluidModifierData *mmd);
+
+/* Fluid accessors */
+size_t manta_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */);
+size_t manta_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */);
+float *manta_get_velocity_x(struct MANTA *fluid);
+float *manta_get_velocity_y(struct MANTA *fluid);
+float *manta_get_velocity_z(struct MANTA *fluid);
+float *manta_get_ob_velocity_x(struct MANTA *fluid);
+float *manta_get_ob_velocity_y(struct MANTA *fluid);
+float *manta_get_ob_velocity_z(struct MANTA *fluid);
+float *manta_get_guide_velocity_x(struct MANTA *fluid);
+float *manta_get_guide_velocity_y(struct MANTA *fluid);
+float *manta_get_guide_velocity_z(struct MANTA *fluid);
+float *manta_get_in_velocity_x(struct MANTA *fluid);
+float *manta_get_in_velocity_y(struct MANTA *fluid);
+float *manta_get_in_velocity_z(struct MANTA *fluid);
+float *manta_get_force_x(struct MANTA *fluid);
+float *manta_get_force_y(struct MANTA *fluid);
+float *manta_get_force_z(struct MANTA *fluid);
+float *manta_get_phiguide_in(struct MANTA *fluid);
+int *manta_get_num_obstacle(struct MANTA *fluid);
+int *manta_get_num_guide(struct MANTA *fluid);
+int manta_get_res_x(struct MANTA *fluid);
+int manta_get_res_y(struct MANTA *fluid);
+int manta_get_res_z(struct MANTA *fluid);
+float *manta_get_phi_in(struct MANTA *fluid);
+float *manta_get_phiobs_in(struct MANTA *fluid);
+float *manta_get_phiout_in(struct MANTA *fluid);
+
+/* Smoke functions */
+void manta_smoke_export_script(struct MANTA *smoke, struct FluidModifierData *mmd);
+void manta_smoke_export(struct MANTA *smoke,
+ float *dt,
+ float *dx,
+ float **dens,
+ float **react,
+ float **flame,
+ float **fuel,
+ float **heat,
+ float **vx,
+ float **vy,
+ float **vz,
+ float **r,
+ float **g,
+ float **b,
+ int **obstacles,
+ float **shadow);
+void manta_smoke_turbulence_export(struct MANTA *smoke,
+ float **dens,
+ float **react,
+ float **flame,
+ float **fuel,
+ float **r,
+ float **g,
+ float **b,
+ float **tcu,
+ float **tcv,
+ float **tcw,
+ float **tcu2,
+ float **tcv2,
+ float **tcw2);
+void manta_smoke_get_rgba(struct MANTA *smoke, float *data, int sequential);
+void manta_smoke_turbulence_get_rgba(struct MANTA *smoke, float *data, int sequential);
+void manta_smoke_get_rgba_from_density(struct MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential);
+void manta_smoke_turbulence_get_rgba_from_density(struct MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential);
+void manta_smoke_ensure_heat(struct MANTA *smoke, struct FluidModifierData *mmd);
+void manta_smoke_ensure_fire(struct MANTA *smoke, struct FluidModifierData *mmd);
+void manta_smoke_ensure_colors(struct MANTA *smoke, struct FluidModifierData *mmd);
+
+/* Smoke accessors */
+float *manta_smoke_get_density(struct MANTA *smoke);
+float *manta_smoke_get_fuel(struct MANTA *smoke);
+float *manta_smoke_get_react(struct MANTA *smoke);
+float *manta_smoke_get_heat(struct MANTA *smoke);
+float *manta_smoke_get_flame(struct MANTA *smoke);
+float *manta_smoke_get_shadow(struct MANTA *fluid);
+float *manta_smoke_get_color_r(struct MANTA *smoke);
+float *manta_smoke_get_color_g(struct MANTA *smoke);
+float *manta_smoke_get_color_b(struct MANTA *smoke);
+int *manta_smoke_get_obstacle(struct MANTA *smoke);
+float *manta_smoke_get_density_in(struct MANTA *smoke);
+float *manta_smoke_get_heat_in(struct MANTA *smoke);
+float *manta_smoke_get_color_r_in(struct MANTA *smoke);
+float *manta_smoke_get_color_g_in(struct MANTA *smoke);
+float *manta_smoke_get_color_b_in(struct MANTA *smoke);
+float *manta_smoke_get_fuel_in(struct MANTA *smoke);
+float *manta_smoke_get_react_in(struct MANTA *smoke);
+float *manta_smoke_get_emission_in(struct MANTA *smoke);
+int manta_smoke_has_heat(struct MANTA *smoke);
+int manta_smoke_has_fuel(struct MANTA *smoke);
+int manta_smoke_has_colors(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_density(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_fuel(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_react(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_color_r(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_color_g(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_color_b(struct MANTA *smoke);
+float *manta_smoke_turbulence_get_flame(struct MANTA *smoke);
+int manta_smoke_turbulence_has_fuel(struct MANTA *smoke);
+int manta_smoke_turbulence_has_colors(struct MANTA *smoke);
+void manta_smoke_turbulence_get_res(struct MANTA *smoke, int *res);
+int manta_smoke_turbulence_get_cells(struct MANTA *smoke);
+
+/* Liquid functions */
+void manta_liquid_export_script(struct MANTA *smoke, struct FluidModifierData *mmd);
+void manta_liquid_ensure_sndparts(struct MANTA *fluid, struct FluidModifierData *mmd);
+
+/* Liquid accessors */
+int manta_liquid_get_particle_res_x(struct MANTA *liquid);
+int manta_liquid_get_particle_res_y(struct MANTA *liquid);
+int manta_liquid_get_particle_res_z(struct MANTA *liquid);
+int manta_liquid_get_mesh_res_x(struct MANTA *liquid);
+int manta_liquid_get_mesh_res_y(struct MANTA *liquid);
+int manta_liquid_get_mesh_res_z(struct MANTA *liquid);
+int manta_liquid_get_particle_upres(struct MANTA *liquid);
+int manta_liquid_get_mesh_upres(struct MANTA *liquid);
+int manta_liquid_get_num_verts(struct MANTA *liquid);
+int manta_liquid_get_num_normals(struct MANTA *liquid);
+int manta_liquid_get_num_triangles(struct MANTA *liquid);
+float manta_liquid_get_vertex_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertex_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertex_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_normal_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_normal_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_normal_z_at(struct MANTA *liquid, int i);
+int manta_liquid_get_triangle_x_at(struct MANTA *liquid, int i);
+int manta_liquid_get_triangle_y_at(struct MANTA *liquid, int i);
+int manta_liquid_get_triangle_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertvel_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertvel_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_vertvel_z_at(struct MANTA *liquid, int i);
+int manta_liquid_get_num_flip_particles(struct MANTA *liquid);
+int manta_liquid_get_num_snd_particles(struct MANTA *liquid);
+int manta_liquid_get_flip_particle_flag_at(struct MANTA *liquid, int i);
+int manta_liquid_get_snd_particle_flag_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_position_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_position_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_position_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_velocity_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_velocity_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_flip_particle_velocity_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_position_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_position_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_position_z_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_velocity_x_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_velocity_y_at(struct MANTA *liquid, int i);
+float manta_liquid_get_snd_particle_velocity_z_at(struct MANTA *liquid, int i);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MANTA_API_H_ */
diff --git a/intern/mantaflow/extern/manta_python_API.h b/intern/mantaflow/extern/manta_python_API.h
new file mode 100644
index 00000000000..9ed795bedaf
--- /dev/null
+++ b/intern/mantaflow/extern/manta_python_API.h
@@ -0,0 +1,45 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/extern/manta_python_API.h
+ * \ingroup mantaflow
+ */
+
+#ifndef MANTA_PYTHON_API_H
+#define MANTA_PYTHON_API_H
+
+#include "Python.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PyObject *Manta_initPython(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
new file mode 100644
index 00000000000..70b6f98d97b
--- /dev/null
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -0,0 +1,2679 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/intern/MANTA.cpp
+ * \ingroup mantaflow
+ */
+
+#include <sstream>
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <zlib.h>
+
+#include "MANTA_main.h"
+#include "manta.h"
+#include "Python.h"
+#include "fluid_script.h"
+#include "smoke_script.h"
+#include "liquid_script.h"
+
+#include "BLI_path_util.h"
+#include "BLI_utildefines.h"
+#include "BLI_fileops.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_fluid_types.h"
+
+std::atomic<bool> MANTA::mantaInitialized(false);
+std::atomic<int> MANTA::solverID(0);
+int MANTA::with_debug(0);
+
+MANTA::MANTA(int *res, FluidModifierData *mmd) : mCurrentID(++solverID)
+{
+ if (with_debug)
+ std::cout << "MANTA: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", "
+ << res[2] << ")" << std::endl;
+
+ mmd->domain->fluid = this;
+
+ mUsingLiquid = (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID);
+ mUsingSmoke = (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS);
+ mUsingHeat = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) && mUsingSmoke;
+ mUsingFire = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) && mUsingSmoke;
+ mUsingColors = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) && mUsingSmoke;
+ mUsingNoise = (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke;
+ mUsingFractions = (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid;
+ mUsingDrops = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid;
+ mUsingBubbles = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && mUsingLiquid;
+ mUsingFloats = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && mUsingLiquid;
+ mUsingTracers = (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) && mUsingLiquid;
+ mUsingMesh = (mmd->domain->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid;
+ mUsingMVel = (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid;
+ mUsingObstacle = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE);
+ mUsingInvel = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL);
+ mUsingOutflow = (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW);
+ mUsingGuiding = (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDING);
+
+ // Simulation constants
+ mTempAmb = 0; // TODO: Maybe use this later for buoyancy calculation
+ mResX = res[0];
+ mResY = res[1];
+ mResZ = res[2];
+ mMaxRes = MAX3(mResX, mResY, mResZ);
+ mConstantScaling = 64.0f / mMaxRes;
+ mConstantScaling = (mConstantScaling < 1.0f) ? 1.0f : mConstantScaling;
+ mTotalCells = mResX * mResY * mResZ;
+ mResGuiding = mmd->domain->res;
+
+ // Smoke low res grids
+ mDensity = NULL;
+ mShadow = NULL;
+ mHeat = NULL;
+ mVelocityX = NULL;
+ mVelocityY = NULL;
+ mVelocityZ = NULL;
+ mForceX = NULL;
+ mForceY = NULL;
+ mForceZ = NULL;
+ mFlame = NULL;
+ mFuel = NULL;
+ mReact = NULL;
+ mColorR = NULL;
+ mColorG = NULL;
+ mColorB = NULL;
+ mObstacle = NULL;
+ mDensityIn = NULL;
+ mHeatIn = NULL;
+ mColorRIn = NULL;
+ mColorGIn = NULL;
+ mColorBIn = NULL;
+ mFuelIn = NULL;
+ mReactIn = NULL;
+ mEmissionIn = NULL;
+
+ // Smoke high res grids
+ mDensityHigh = NULL;
+ mFlameHigh = NULL;
+ mFuelHigh = NULL;
+ mReactHigh = NULL;
+ mColorRHigh = NULL;
+ mColorGHigh = NULL;
+ mColorBHigh = NULL;
+ mTextureU = NULL;
+ mTextureV = NULL;
+ mTextureW = NULL;
+ mTextureU2 = NULL;
+ mTextureV2 = NULL;
+ mTextureW2 = NULL;
+
+ // Fluid low res grids
+ mPhiIn = NULL;
+ mPhiOutIn = NULL;
+ mPhi = NULL;
+
+ // Mesh
+ mMeshNodes = NULL;
+ mMeshTriangles = NULL;
+ mMeshVelocities = NULL;
+
+ // Fluid obstacle
+ mPhiObsIn = NULL;
+ mNumObstacle = NULL;
+ mObVelocityX = NULL;
+ mObVelocityY = NULL;
+ mObVelocityZ = NULL;
+
+ // Fluid guiding
+ mPhiGuideIn = NULL;
+ mNumGuide = NULL;
+ mGuideVelocityX = NULL;
+ mGuideVelocityY = NULL;
+ mGuideVelocityZ = NULL;
+
+ // Fluid initial velocity
+ mInVelocityX = NULL;
+ mInVelocityY = NULL;
+ mInVelocityZ = NULL;
+
+ // Secondary particles
+ mFlipParticleData = NULL;
+ mFlipParticleVelocity = NULL;
+ mSndParticleData = NULL;
+ mSndParticleVelocity = NULL;
+ mSndParticleLife = NULL;
+
+ // Only start Mantaflow once. No need to start whenever new FLUID objected is allocated
+ if (!mantaInitialized)
+ initializeMantaflow();
+
+ // Initialize Mantaflow variables in Python
+ // Liquid
+ if (mUsingLiquid) {
+ initDomain(mmd);
+ initLiquid(mmd);
+ if (mUsingObstacle)
+ initObstacle(mmd);
+ if (mUsingInvel)
+ initInVelocity(mmd);
+ if (mUsingOutflow)
+ initOutflow(mmd);
+
+ if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
+ mUpresParticle = mmd->domain->particle_scale;
+ mResXParticle = mUpresParticle * mResX;
+ mResYParticle = mUpresParticle * mResY;
+ mResZParticle = mUpresParticle * mResZ;
+ mTotalCellsParticles = mResXParticle * mResYParticle * mResZParticle;
+
+ initSndParts(mmd);
+ initLiquidSndParts(mmd);
+ }
+
+ if (mUsingMesh) {
+ mUpresMesh = mmd->domain->mesh_scale;
+ mResXMesh = mUpresMesh * mResX;
+ mResYMesh = mUpresMesh * mResY;
+ mResZMesh = mUpresMesh * mResZ;
+ mTotalCellsMesh = mResXMesh * mResYMesh * mResZMesh;
+
+ // Initialize Mantaflow variables in Python
+ initMesh(mmd);
+ initLiquidMesh(mmd);
+ }
+
+ if (mUsingGuiding) {
+ mResGuiding = (mmd->domain->guiding_parent) ? mmd->domain->guide_res : mmd->domain->res;
+ initGuiding(mmd);
+ }
+ if (mUsingFractions) {
+ initFractions(mmd);
+ }
+ }
+
+ // Smoke
+ if (mUsingSmoke) {
+ initDomain(mmd);
+ initSmoke(mmd);
+ if (mUsingHeat)
+ initHeat(mmd);
+ if (mUsingFire)
+ initFire(mmd);
+ if (mUsingColors)
+ initColors(mmd);
+ if (mUsingObstacle)
+ initObstacle(mmd);
+ if (mUsingInvel)
+ initInVelocity(mmd);
+ if (mUsingOutflow)
+ initOutflow(mmd);
+
+ if (mUsingGuiding) {
+ mResGuiding = (mmd->domain->guiding_parent) ? mmd->domain->guide_res : mmd->domain->res;
+ initGuiding(mmd);
+ }
+
+ if (mUsingNoise) {
+ int amplify = mmd->domain->noise_scale;
+ mResXNoise = amplify * mResX;
+ mResYNoise = amplify * mResY;
+ mResZNoise = amplify * mResZ;
+ mTotalCellsHigh = mResXNoise * mResYNoise * mResZNoise;
+
+ // Initialize Mantaflow variables in Python
+ initNoise(mmd);
+ initSmokeNoise(mmd);
+ if (mUsingFire)
+ initFireHigh(mmd);
+ if (mUsingColors)
+ initColorsHigh(mmd);
+ }
+ }
+ updatePointers();
+}
+
+void MANTA::initDomain(FluidModifierData *mmd)
+{
+ // Vector will hold all python commands that are to be executed
+ std::vector<std::string> pythonCommands;
+
+ // Set manta debug level first
+ pythonCommands.push_back(manta_import + manta_debuglevel);
+
+ std::ostringstream ss;
+ ss << "set_manta_debuglevel(" << with_debug << ")";
+ pythonCommands.push_back(ss.str());
+
+ // Now init basic fluid domain
+ std::string tmpString = fluid_variables + fluid_solver + fluid_alloc + fluid_cache_helper +
+ fluid_bake_multiprocessing + fluid_bake_data + fluid_bake_noise +
+ fluid_bake_mesh + fluid_bake_particles + fluid_bake_guiding +
+ fluid_file_import + fluid_file_export + fluid_save_data +
+ fluid_load_data + fluid_pre_step + fluid_post_step +
+ fluid_adapt_time_step + fluid_time_stepping;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initNoise(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_noise + fluid_solver_noise;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initSmoke(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_variables + smoke_alloc + smoke_adaptive_step + smoke_save_data +
+ smoke_load_data + smoke_step;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initSmokeNoise(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_variables_noise + smoke_alloc_noise + smoke_wavelet_noise +
+ smoke_save_noise + smoke_load_noise + smoke_step_noise;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingNoise = true;
+}
+
+void MANTA::initHeat(FluidModifierData *mmd)
+{
+ if (!mHeat) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_heat + smoke_with_heat;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingHeat = true;
+ }
+}
+
+void MANTA::initFire(FluidModifierData *mmd)
+{
+ if (!mFuel) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_fire + smoke_with_fire;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingFire = true;
+ }
+}
+
+void MANTA::initFireHigh(FluidModifierData *mmd)
+{
+ if (!mFuelHigh) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_fire_noise + smoke_with_fire;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingFire = true;
+ }
+}
+
+void MANTA::initColors(FluidModifierData *mmd)
+{
+ if (!mColorR) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_colors + smoke_init_colors + smoke_with_colors;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingColors = true;
+ }
+}
+
+void MANTA::initColorsHigh(FluidModifierData *mmd)
+{
+ if (!mColorRHigh) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = smoke_alloc_colors_noise + smoke_init_colors_noise + smoke_with_colors;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingColors = true;
+ }
+}
+
+void MANTA::initLiquid(FluidModifierData *mmd)
+{
+ if (!mPhiIn) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = liquid_variables + liquid_alloc + liquid_init_phi + liquid_save_data +
+ liquid_save_flip + liquid_load_data + liquid_load_flip +
+ liquid_adaptive_step + liquid_step;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingLiquid = true;
+ }
+}
+
+void MANTA::initMesh(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_mesh + fluid_solver_mesh + liquid_load_mesh +
+ liquid_load_meshvel;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingMesh = true;
+}
+
+void MANTA::initLiquidMesh(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = liquid_alloc_mesh + liquid_step_mesh + liquid_save_mesh +
+ liquid_save_meshvel;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingMesh = true;
+}
+
+void MANTA::initObstacle(FluidModifierData *mmd)
+{
+ if (!mPhiObsIn) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_obstacle + fluid_with_obstacle;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingObstacle = true;
+ }
+}
+
+void MANTA::initGuiding(FluidModifierData *mmd)
+{
+ if (!mPhiGuideIn) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_guiding + fluid_solver_guiding + fluid_alloc_guiding +
+ fluid_save_guiding + fluid_load_vel + fluid_load_guiding;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingGuiding = true;
+ }
+}
+
+void MANTA::initFractions(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_fractions + fluid_with_fractions;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingFractions = true;
+}
+
+void MANTA::initInVelocity(FluidModifierData *mmd)
+{
+ if (!mInVelocityX) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_invel + fluid_with_invel;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingInvel = true;
+ }
+}
+
+void MANTA::initOutflow(FluidModifierData *mmd)
+{
+ if (!mPhiOutIn) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_outflow + fluid_with_outflow;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ mUsingOutflow = true;
+ }
+}
+
+void MANTA::initSndParts(FluidModifierData *mmd)
+{
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_variables_particles + fluid_solver_particles +
+ fluid_load_particles + fluid_save_particles;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::initLiquidSndParts(FluidModifierData *mmd)
+{
+ if (!mSndParticleData) {
+ std::vector<std::string> pythonCommands;
+ std::string tmpString = fluid_alloc_sndparts + liquid_alloc_particles +
+ liquid_variables_particles + liquid_step_particles +
+ fluid_with_sndparts + liquid_load_particles + liquid_save_particles;
+ std::string finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+ }
+}
+
+MANTA::~MANTA()
+{
+ if (with_debug)
+ std::cout << "~FLUID: " << mCurrentID << " with res(" << mResX << ", " << mResY << ", "
+ << mResZ << ")" << std::endl;
+
+ // Destruction string for Python
+ std::string tmpString = "";
+ std::vector<std::string> pythonCommands;
+
+ tmpString += manta_import;
+ tmpString += fluid_delete_all;
+
+ // Leave out mmd argument in parseScript since only looking up IDs
+ std::string finalString = parseScript(tmpString);
+ pythonCommands.push_back(finalString);
+ runPythonString(pythonCommands);
+}
+
+void MANTA::runPythonString(std::vector<std::string> commands)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ for (std::vector<std::string>::iterator it = commands.begin(); it != commands.end(); ++it) {
+ std::string command = *it;
+
+#ifdef WIN32
+ // special treatment for windows when running python code
+ size_t cmdLength = command.length();
+ char *buffer = new char[cmdLength + 1];
+ memcpy(buffer, command.data(), cmdLength);
+
+ buffer[cmdLength] = '\0';
+ PyRun_SimpleString(buffer);
+ delete[] buffer;
+#else
+ PyRun_SimpleString(command.c_str());
+#endif
+ }
+ PyGILState_Release(gilstate);
+}
+
+void MANTA::initializeMantaflow()
+{
+ if (with_debug)
+ std::cout << "Initializing Mantaflow" << std::endl;
+
+ std::string filename = "manta_scene_" + std::to_string(mCurrentID) + ".py";
+ std::vector<std::string> fill = std::vector<std::string>();
+
+ // Initialize extension classes and wrappers
+ srand(0);
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ Pb::setup(filename, fill); // Namespace from Mantaflow (registry)
+ PyGILState_Release(gilstate);
+ mantaInitialized = true;
+}
+
+void MANTA::terminateMantaflow()
+{
+ if (with_debug)
+ std::cout << "Terminating Mantaflow" << std::endl;
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ Pb::finalize(); // Namespace from Mantaflow (registry)
+ PyGILState_Release(gilstate);
+ mantaInitialized = false;
+}
+
+std::string MANTA::getRealValue(const std::string &varName, FluidModifierData *mmd)
+{
+ std::ostringstream ss;
+ bool is2D = false;
+ int tmpVar;
+ float tmpFloat;
+
+ if (varName == "ID") {
+ ss << mCurrentID;
+ return ss.str();
+ }
+
+ if (!mmd) {
+ if (with_debug)
+ std::cout << "Invalid modifier data in getRealValue()" << std::endl;
+ ss << "ERROR - INVALID MODIFIER DATA";
+ return ss.str();
+ }
+
+ is2D = (mmd->domain->solver_res == 2);
+
+ if (varName == "USING_SMOKE")
+ ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) ? "True" : "False");
+ else if (varName == "USING_LIQUID")
+ ss << ((mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) ? "True" : "False");
+ else if (varName == "USING_COLORS")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS ? "True" : "False");
+ else if (varName == "USING_HEAT")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT ? "True" : "False");
+ else if (varName == "USING_FIRE")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE ? "True" : "False");
+ else if (varName == "USING_NOISE")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_NOISE ? "True" : "False");
+ else if (varName == "USING_OBSTACLE")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE ? "True" : "False");
+ else if (varName == "USING_GUIDING")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_GUIDING ? "True" : "False");
+ else if (varName == "USING_INVEL")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL ? "True" : "False");
+ else if (varName == "USING_OUTFLOW")
+ ss << (mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW ? "True" : "False");
+ else if (varName == "USING_LOG_DISSOLVE")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG ? "True" : "False");
+ else if (varName == "USING_DISSOLVE")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_DISSOLVE ? "True" : "False");
+ else if (varName == "SOLVER_DIM")
+ ss << mmd->domain->solver_res;
+ else if (varName == "DO_OPEN") {
+ tmpVar = (FLUID_DOMAIN_BORDER_BACK | FLUID_DOMAIN_BORDER_FRONT | FLUID_DOMAIN_BORDER_LEFT |
+ FLUID_DOMAIN_BORDER_RIGHT | FLUID_DOMAIN_BORDER_BOTTOM | FLUID_DOMAIN_BORDER_TOP);
+ ss << (((mmd->domain->border_collisions & tmpVar) == tmpVar) ? "False" : "True");
+ }
+ else if (varName == "BOUND_CONDITIONS") {
+ if (mmd->domain->solver_res == 2) {
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0)
+ ss << "x";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0)
+ ss << "X";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0)
+ ss << "y";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0)
+ ss << "Y";
+ }
+ if (mmd->domain->solver_res == 3) {
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0)
+ ss << "x";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0)
+ ss << "X";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0)
+ ss << "y";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0)
+ ss << "Y";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_BOTTOM) == 0)
+ ss << "z";
+ if ((mmd->domain->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0)
+ ss << "Z";
+ }
+ }
+ else if (varName == "BOUNDARY_WIDTH")
+ ss << mmd->domain->boundary_width;
+ else if (varName == "RES")
+ ss << mMaxRes;
+ else if (varName == "RESX")
+ ss << mResX;
+ else if (varName == "RESY")
+ if (is2D) {
+ ss << mResZ;
+ }
+ else {
+ ss << mResY;
+ }
+ else if (varName == "RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResZ;
+ }
+ }
+ else if (varName == "FRAME_LENGTH")
+ ss << mmd->domain->frame_length;
+ else if (varName == "CFL")
+ ss << mmd->domain->cfl_condition;
+ else if (varName == "DT")
+ ss << mmd->domain->dt;
+ else if (varName == "TIMESTEPS_MIN")
+ ss << mmd->domain->timesteps_minimum;
+ else if (varName == "TIMESTEPS_MAX")
+ ss << mmd->domain->timesteps_maximum;
+ else if (varName == "TIME_TOTAL")
+ ss << mmd->domain->time_total;
+ else if (varName == "TIME_PER_FRAME")
+ ss << mmd->domain->time_per_frame;
+ else if (varName == "VORTICITY")
+ ss << mmd->domain->vorticity / mConstantScaling;
+ else if (varName == "FLAME_VORTICITY")
+ ss << mmd->domain->flame_vorticity / mConstantScaling;
+ else if (varName == "NOISE_SCALE")
+ ss << mmd->domain->noise_scale;
+ else if (varName == "MESH_SCALE")
+ ss << mmd->domain->mesh_scale;
+ else if (varName == "PARTICLE_SCALE")
+ ss << mmd->domain->particle_scale;
+ else if (varName == "NOISE_RESX")
+ ss << mResXNoise;
+ else if (varName == "NOISE_RESY") {
+ if (is2D) {
+ ss << mResZNoise;
+ }
+ else {
+ ss << mResYNoise;
+ }
+ }
+ else if (varName == "NOISE_RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResZNoise;
+ }
+ }
+ else if (varName == "MESH_RESX")
+ ss << mResXMesh;
+ else if (varName == "MESH_RESY") {
+ if (is2D) {
+ ss << mResZMesh;
+ }
+ else {
+ ss << mResYMesh;
+ }
+ }
+ else if (varName == "MESH_RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResZMesh;
+ }
+ }
+ else if (varName == "PARTICLE_RESX")
+ ss << mResXParticle;
+ else if (varName == "PARTICLE_RESY") {
+ if (is2D) {
+ ss << mResZParticle;
+ }
+ else {
+ ss << mResYParticle;
+ }
+ }
+ else if (varName == "PARTICLE_RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResZParticle;
+ }
+ }
+ else if (varName == "GUIDING_RESX")
+ ss << mResGuiding[0];
+ else if (varName == "GUIDING_RESY") {
+ if (is2D) {
+ ss << mResGuiding[2];
+ }
+ else {
+ ss << mResGuiding[1];
+ }
+ }
+ else if (varName == "GUIDING_RESZ") {
+ if (is2D) {
+ ss << 1;
+ }
+ else {
+ ss << mResGuiding[2];
+ }
+ }
+ else if (varName == "MIN_RESX")
+ ss << mmd->domain->res_min[0];
+ else if (varName == "MIN_RESY")
+ ss << mmd->domain->res_min[1];
+ else if (varName == "MIN_RESZ")
+ ss << mmd->domain->res_min[2];
+ else if (varName == "BASE_RESX")
+ ss << mmd->domain->base_res[0];
+ else if (varName == "BASE_RESY")
+ ss << mmd->domain->base_res[1];
+ else if (varName == "BASE_RESZ")
+ ss << mmd->domain->base_res[2];
+ else if (varName == "WLT_STR")
+ ss << mmd->domain->noise_strength;
+ else if (varName == "NOISE_POSSCALE")
+ ss << mmd->domain->noise_pos_scale;
+ else if (varName == "NOISE_TIMEANIM")
+ ss << mmd->domain->noise_time_anim;
+ else if (varName == "COLOR_R")
+ ss << mmd->domain->active_color[0];
+ else if (varName == "COLOR_G")
+ ss << mmd->domain->active_color[1];
+ else if (varName == "COLOR_B")
+ ss << mmd->domain->active_color[2];
+ else if (varName == "BUOYANCY_ALPHA")
+ ss << mmd->domain->alpha;
+ else if (varName == "BUOYANCY_BETA")
+ ss << mmd->domain->beta;
+ else if (varName == "DISSOLVE_SPEED")
+ ss << mmd->domain->diss_speed;
+ else if (varName == "BURNING_RATE")
+ ss << mmd->domain->burning_rate;
+ else if (varName == "FLAME_SMOKE")
+ ss << mmd->domain->flame_smoke;
+ else if (varName == "IGNITION_TEMP")
+ ss << mmd->domain->flame_ignition;
+ else if (varName == "MAX_TEMP")
+ ss << mmd->domain->flame_max_temp;
+ else if (varName == "FLAME_SMOKE_COLOR_X")
+ ss << mmd->domain->flame_smoke_color[0];
+ else if (varName == "FLAME_SMOKE_COLOR_Y")
+ ss << mmd->domain->flame_smoke_color[1];
+ else if (varName == "FLAME_SMOKE_COLOR_Z")
+ ss << mmd->domain->flame_smoke_color[2];
+ else if (varName == "CURRENT_FRAME")
+ ss << mmd->time;
+ else if (varName == "END_FRAME")
+ ss << mmd->domain->cache_frame_end;
+ else if (varName == "SIMULATION_METHOD") {
+ if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_FLIP) {
+ ss << "'FLIP'";
+ }
+ else if (mmd->domain->simulation_method & FLUID_DOMAIN_METHOD_APIC) {
+ ss << "'APIC'";
+ }
+ else {
+ ss << "'NONE'";
+ }
+ }
+ else if (varName == "FLIP_RATIO")
+ ss << mmd->domain->flip_ratio;
+ else if (varName == "PARTICLE_RANDOMNESS")
+ ss << mmd->domain->particle_randomness;
+ else if (varName == "PARTICLE_NUMBER")
+ ss << mmd->domain->particle_number;
+ else if (varName == "PARTICLE_MINIMUM")
+ ss << mmd->domain->particle_minimum;
+ else if (varName == "PARTICLE_MAXIMUM")
+ ss << mmd->domain->particle_maximum;
+ else if (varName == "PARTICLE_RADIUS")
+ ss << mmd->domain->particle_radius;
+ else if (varName == "FRACTIONS_THRESHOLD")
+ ss << mmd->domain->fractions_threshold;
+ else if (varName == "MESH_CONCAVE_UPPER")
+ ss << mmd->domain->mesh_concave_upper;
+ else if (varName == "MESH_CONCAVE_LOWER")
+ ss << mmd->domain->mesh_concave_lower;
+ else if (varName == "MESH_PARTICLE_RADIUS")
+ ss << mmd->domain->mesh_particle_radius;
+ else if (varName == "MESH_SMOOTHEN_POS")
+ ss << mmd->domain->mesh_smoothen_pos;
+ else if (varName == "MESH_SMOOTHEN_NEG")
+ ss << mmd->domain->mesh_smoothen_neg;
+ else if (varName == "USING_MESH")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_MESH ? "True" : "False");
+ else if (varName == "USING_IMPROVED_MESH")
+ ss << (mmd->domain->mesh_generator == FLUID_DOMAIN_MESH_IMPROVED ? "True" : "False");
+ else if (varName == "PARTICLE_BAND_WIDTH")
+ ss << mmd->domain->particle_band_width;
+ else if (varName == "SNDPARTICLE_TAU_MIN_WC")
+ ss << mmd->domain->sndparticle_tau_min_wc;
+ else if (varName == "SNDPARTICLE_TAU_MAX_WC")
+ ss << mmd->domain->sndparticle_tau_max_wc;
+ else if (varName == "SNDPARTICLE_TAU_MIN_TA")
+ ss << mmd->domain->sndparticle_tau_min_ta;
+ else if (varName == "SNDPARTICLE_TAU_MAX_TA")
+ ss << mmd->domain->sndparticle_tau_max_ta;
+ else if (varName == "SNDPARTICLE_TAU_MIN_K")
+ ss << mmd->domain->sndparticle_tau_min_k;
+ else if (varName == "SNDPARTICLE_TAU_MAX_K")
+ ss << mmd->domain->sndparticle_tau_max_k;
+ else if (varName == "SNDPARTICLE_K_WC")
+ ss << mmd->domain->sndparticle_k_wc;
+ else if (varName == "SNDPARTICLE_K_TA")
+ ss << mmd->domain->sndparticle_k_ta;
+ else if (varName == "SNDPARTICLE_K_B")
+ ss << mmd->domain->sndparticle_k_b;
+ else if (varName == "SNDPARTICLE_K_D")
+ ss << mmd->domain->sndparticle_k_d;
+ else if (varName == "SNDPARTICLE_L_MIN")
+ ss << mmd->domain->sndparticle_l_min;
+ else if (varName == "SNDPARTICLE_L_MAX")
+ ss << mmd->domain->sndparticle_l_max;
+ else if (varName == "SNDPARTICLE_BOUNDARY_DELETE")
+ ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_DELETE);
+ else if (varName == "SNDPARTICLE_BOUNDARY_PUSHOUT")
+ ss << (mmd->domain->sndparticle_boundary == SNDPARTICLE_BOUNDARY_PUSHOUT);
+ else if (varName == "SNDPARTICLE_POTENTIAL_RADIUS")
+ ss << mmd->domain->sndparticle_potential_radius;
+ else if (varName == "SNDPARTICLE_UPDATE_RADIUS")
+ ss << mmd->domain->sndparticle_update_radius;
+ else if (varName == "LIQUID_SURFACE_TENSION")
+ ss << mmd->domain->surface_tension;
+ else if (varName == "FLUID_VISCOSITY")
+ ss << mmd->domain->viscosity_base * pow(10.0f, -mmd->domain->viscosity_exponent);
+ else if (varName == "FLUID_DOMAIN_SIZE") {
+ tmpFloat = MAX3(
+ mmd->domain->global_size[0], mmd->domain->global_size[1], mmd->domain->global_size[2]);
+ ss << tmpFloat;
+ }
+ else if (varName == "SNDPARTICLE_TYPES") {
+ if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) {
+ ss << "PtypeSpray";
+ }
+ if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) {
+ if (!ss.str().empty())
+ ss << "|";
+ ss << "PtypeBubble";
+ }
+ if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) {
+ if (!ss.str().empty())
+ ss << "|";
+ ss << "PtypeFoam";
+ }
+ if (mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) {
+ if (!ss.str().empty())
+ ss << "|";
+ ss << "PtypeTracer";
+ }
+ if (ss.str().empty())
+ ss << "0";
+ }
+ else if (varName == "USING_SNDPARTS") {
+ tmpVar = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE |
+ FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER);
+ ss << (((mmd->domain->particle_type & tmpVar)) ? "True" : "False");
+ }
+ else if (varName == "GUIDING_ALPHA")
+ ss << mmd->domain->guiding_alpha;
+ else if (varName == "GUIDING_BETA")
+ ss << mmd->domain->guiding_beta;
+ else if (varName == "GUIDING_FACTOR")
+ ss << mmd->domain->guiding_vel_factor;
+ else if (varName == "GRAVITY_X")
+ ss << mmd->domain->gravity[0];
+ else if (varName == "GRAVITY_Y")
+ ss << mmd->domain->gravity[1];
+ else if (varName == "GRAVITY_Z")
+ ss << mmd->domain->gravity[2];
+ else if (varName == "CACHE_DIR")
+ ss << mmd->domain->cache_directory;
+ else if (varName == "USING_ADAPTIVETIME")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME ? "True" : "False");
+ else if (varName == "USING_SPEEDVECTORS")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_SPEED_VECTORS ? "True" : "False");
+ else if (varName == "USING_FRACTIONS")
+ ss << (mmd->domain->flags & FLUID_DOMAIN_USE_FRACTIONS ? "True" : "False");
+ else
+ std::cout << "ERROR: Unknown option: " << varName << std::endl;
+ return ss.str();
+}
+
+std::string MANTA::parseLine(const std::string &line, FluidModifierData *mmd)
+{
+ if (line.size() == 0)
+ return "";
+ std::string res = "";
+ int currPos = 0, start_del = 0, end_del = -1;
+ bool readingVar = false;
+ const char delimiter = '$';
+ while (currPos < line.size()) {
+ if (line[currPos] == delimiter && !readingVar) {
+ readingVar = true;
+ start_del = currPos + 1;
+ res += line.substr(end_del + 1, currPos - end_del - 1);
+ }
+ else if (line[currPos] == delimiter && readingVar) {
+ readingVar = false;
+ end_del = currPos;
+ res += getRealValue(line.substr(start_del, currPos - start_del), mmd);
+ }
+ currPos++;
+ }
+ res += line.substr(end_del + 1, line.size() - end_del);
+ return res;
+}
+
+std::string MANTA::parseScript(const std::string &setup_string, FluidModifierData *mmd)
+{
+ std::istringstream f(setup_string);
+ std::ostringstream res;
+ std::string line = "";
+ while (getline(f, line)) {
+ res << parseLine(line, mmd) << "\n";
+ }
+ return res.str();
+}
+
+static std::string getCacheFileEnding(char cache_format)
+{
+ if (MANTA::with_debug)
+ std::cout << "MANTA::getCacheFileEnding()" << std::endl;
+
+ switch (cache_format) {
+ case FLUID_DOMAIN_FILE_UNI:
+ return ".uni";
+ case FLUID_DOMAIN_FILE_OPENVDB:
+ return ".vdb";
+ case FLUID_DOMAIN_FILE_RAW:
+ return ".raw";
+ case FLUID_DOMAIN_FILE_BIN_OBJECT:
+ return ".bobj.gz";
+ case FLUID_DOMAIN_FILE_OBJECT:
+ return ".obj";
+ default:
+ if (MANTA::with_debug)
+ std::cout << "Error: Could not find file extension" << std::endl;
+ return ".uni";
+ }
+}
+
+int MANTA::updateFlipStructures(FluidModifierData *mmd, int framenr)
+{
+ if (MANTA::with_debug)
+ std::cout << "MANTA::updateFlipStructures()" << std::endl;
+
+ // Ensure empty data structures at start
+ if (mFlipParticleData)
+ mFlipParticleData->clear();
+ if (mFlipParticleVelocity)
+ mFlipParticleVelocity->clear();
+
+ if (!mUsingLiquid)
+ return 0;
+ if (BLI_path_is_rel(mmd->domain->cache_directory))
+ return 0;
+
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL);
+
+ // TODO (sebbas): Use pp_xl and pVel_xl when using upres simulation?
+
+ ss << "pp_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, false, false);
+ }
+
+ ss.str("");
+ ss << "pVel_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, false, true);
+ }
+ return 1;
+}
+
+int MANTA::updateMeshStructures(FluidModifierData *mmd, int framenr)
+{
+ if (MANTA::with_debug)
+ std::cout << "MANTA::updateMeshStructures()" << std::endl;
+
+ if (!mUsingMesh)
+ return 0;
+ if (BLI_path_is_rel(mmd->domain->cache_directory))
+ return 0;
+
+ // Ensure empty data structures at start
+ if (mMeshNodes)
+ mMeshNodes->clear();
+ if (mMeshTriangles)
+ mMeshTriangles->clear();
+ if (mMeshVelocities)
+ mMeshVelocities->clear();
+
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL);
+
+ ss << "lMesh_####" << mformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateMeshFromFile(targetFile);
+ }
+
+ if (mUsingMVel) {
+ ss.str("");
+ ss << "lVelMesh_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateMeshFromFile(targetFile);
+ }
+ }
+ return 1;
+}
+
+int MANTA::updateParticleStructures(FluidModifierData *mmd, int framenr)
+{
+ if (MANTA::with_debug)
+ std::cout << "MANTA::updateParticleStructures()" << std::endl;
+
+ if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers)
+ return 0;
+ if (BLI_path_is_rel(mmd->domain->cache_directory))
+ return 0;
+
+ // Ensure empty data structures at start
+ if (mSndParticleData)
+ mSndParticleData->clear();
+ if (mSndParticleVelocity)
+ mSndParticleVelocity->clear();
+ if (mSndParticleLife)
+ mSndParticleLife->clear();
+
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL);
+
+ ss << "ppSnd_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, true, false);
+ }
+
+ ss.str("");
+ ss << "pVelSnd_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, true, true);
+ }
+
+ ss.str("");
+ ss << "pLifeSnd_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (BLI_exists(targetFile)) {
+ updateParticlesFromFile(targetFile, true, false);
+ }
+ return 1;
+}
+
+/* Dirty hack: Needed to format paths from python code that is run via PyRun_SimpleString */
+static std::string escapeSlashes(std::string const &s)
+{
+ std::string result = "";
+ for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) {
+ unsigned char c = *i;
+ if (c == '\\')
+ result += "\\\\";
+ else
+ result += c;
+ }
+ return result;
+}
+
+int MANTA::writeConfiguration(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::writeConfiguration()" << std::endl;
+
+ FluidDomainSettings *mds = mmd->domain;
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ ;
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_make_safe(cacheDir);
+ BLI_dir_create_recursive(cacheDir); /* Create 'config' subdir if it does not exist already */
+
+ ss.str("");
+ ss << "config_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ gzFile gzf = gzopen(targetFile, "wb1"); // do some compression
+ if (!gzf)
+ std::cerr << "writeConfiguration: can't open file: " << targetFile << std::endl;
+
+ gzwrite(gzf, &mds->active_fields, sizeof(int));
+ gzwrite(gzf, &mds->res, 3 * sizeof(int));
+ gzwrite(gzf, &mds->dx, sizeof(float));
+ gzwrite(gzf, &mds->dt, sizeof(float));
+ gzwrite(gzf, &mds->p0, 3 * sizeof(float));
+ gzwrite(gzf, &mds->p1, 3 * sizeof(float));
+ gzwrite(gzf, &mds->dp0, 3 * sizeof(float));
+ gzwrite(gzf, &mds->shift, 3 * sizeof(int));
+ gzwrite(gzf, &mds->obj_shift_f, 3 * sizeof(float));
+ gzwrite(gzf, &mds->obmat, 16 * sizeof(float));
+ gzwrite(gzf, &mds->base_res, 3 * sizeof(int));
+ gzwrite(gzf, &mds->res_min, 3 * sizeof(int));
+ gzwrite(gzf, &mds->res_max, 3 * sizeof(int));
+ gzwrite(gzf, &mds->active_color, 3 * sizeof(float));
+
+ gzclose(gzf);
+
+ return 1;
+}
+
+int MANTA::writeData(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::writeData()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX];
+ cacheDirData[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+
+ ss.str("");
+ ss << "fluid_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', " << framenr
+ << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ if (mUsingSmoke) {
+ ss.str("");
+ ss << "smoke_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ if (mUsingLiquid) {
+ ss.str("");
+ ss << "liquid_save_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "liquid_save_flip_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readConfiguration(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readConfiguration()" << std::endl;
+
+ FluidDomainSettings *mds = mmd->domain;
+ std::ostringstream ss;
+ char cacheDir[FILE_MAX], targetFile[FILE_MAX];
+ cacheDir[0] = '\0';
+ targetFile[0] = '\0';
+ float dummy;
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+
+ BLI_path_join(
+ cacheDir, sizeof(cacheDir), mmd->domain->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL);
+ BLI_path_make_safe(cacheDir);
+
+ ss.str("");
+ ss << "config_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDir, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ gzFile gzf = gzopen(targetFile, "rb"); // do some compression
+ if (!gzf)
+ std::cerr << "readConfiguration: can't open file: " << targetFile << std::endl;
+
+ gzread(gzf, &mds->active_fields, sizeof(int));
+ gzread(gzf, &mds->res, 3 * sizeof(int));
+ gzread(gzf, &mds->dx, sizeof(float));
+ gzread(gzf, &dummy, sizeof(float)); // dt not needed right now
+ gzread(gzf, &mds->p0, 3 * sizeof(float));
+ gzread(gzf, &mds->p1, 3 * sizeof(float));
+ gzread(gzf, &mds->dp0, 3 * sizeof(float));
+ gzread(gzf, &mds->shift, 3 * sizeof(int));
+ gzread(gzf, &mds->obj_shift_f, 3 * sizeof(float));
+ gzread(gzf, &mds->obmat, 16 * sizeof(float));
+ gzread(gzf, &mds->base_res, 3 * sizeof(int));
+ gzread(gzf, &mds->res_min, 3 * sizeof(int));
+ gzread(gzf, &mds->res_max, 3 * sizeof(int));
+ gzread(gzf, &mds->active_color, 3 * sizeof(float));
+ mds->total_cells = mds->res[0] * mds->res[1] * mds->res[2];
+
+ gzclose(gzf);
+ return 1;
+}
+
+int MANTA::readData(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readData()" << std::endl;
+
+ if (!mUsingSmoke && !mUsingLiquid)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirData[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+
+ if (mUsingSmoke) {
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "density_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirData, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ ss.str("");
+ ss << "fluid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "smoke_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ if (mUsingLiquid) {
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "phiIn_####" << dformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirData, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ ss.str("");
+ ss << "fluid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "liquid_load_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << dformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "liquid_load_flip_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', "
+ << framenr << ", '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readNoise(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readNoise()" << std::endl;
+
+ if (!mUsingNoise)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirNoise[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirNoise[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format);
+
+ BLI_path_join(cacheDirNoise,
+ sizeof(cacheDirNoise),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_NOISE,
+ NULL);
+ BLI_path_make_safe(cacheDirNoise);
+
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "density_noise_####" << nformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirNoise, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ if (mUsingSmoke && mUsingNoise) {
+ ss.str("");
+ ss << "smoke_load_noise_" << mCurrentID << "('" << escapeSlashes(cacheDirNoise) << "', "
+ << framenr << ", '" << nformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readMesh(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readMesh()" << std::endl;
+
+ if (!mUsingMesh)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirMesh[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirMesh[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
+
+ BLI_path_join(cacheDirMesh,
+ sizeof(cacheDirMesh),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_MESH,
+ NULL);
+ BLI_path_make_safe(cacheDirMesh);
+
+ if (mUsingLiquid) {
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "lMesh_####" << mformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirMesh, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ ss.str("");
+ ss << "liquid_load_mesh_" << mCurrentID << "('" << escapeSlashes(cacheDirMesh) << "', "
+ << framenr << ", '" << mformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ if (mUsingMVel) {
+ ss.str("");
+ ss << "liquid_load_meshvel_" << mCurrentID << "('" << escapeSlashes(cacheDirMesh) << "', "
+ << framenr << ", '" << mformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readParticles(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::readParticles()" << std::endl;
+
+ if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirParticles[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirParticles[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirParticles,
+ sizeof(cacheDirParticles),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_PARTICLES,
+ NULL);
+ BLI_path_make_safe(cacheDirParticles);
+
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "ppSnd_####" << pformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirParticles, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
+ ss.str("");
+ ss << "fluid_load_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirParticles)
+ << "', " << framenr << ", '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+ ss.str("");
+ ss << "liquid_load_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirParticles)
+ << "', " << framenr << ", '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+ }
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain)
+{
+ if (with_debug)
+ std::cout << "MANTA::readGuiding()" << std::endl;
+
+ if (!mUsingGuiding)
+ return 0;
+ if (!mmd->domain)
+ return 0;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirGuiding[FILE_MAX], targetFile[FILE_MAX];
+ cacheDirGuiding[0] = '\0';
+ targetFile[0] = '\0';
+
+ std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ const char *subdir = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDING;
+
+ BLI_path_join(
+ cacheDirGuiding, sizeof(cacheDirGuiding), mmd->domain->cache_directory, subdir, NULL);
+ BLI_path_make_safe(cacheDirGuiding);
+
+ /* Exit early if there is nothing present in the cache for this frame */
+ ss.str("");
+ ss << "guidevel_####" << gformat;
+ BLI_join_dirfile(targetFile, sizeof(targetFile), cacheDirGuiding, ss.str().c_str());
+ BLI_path_frame(targetFile, framenr, 0);
+ if (!BLI_exists(targetFile))
+ return 0;
+
+ if (sourceDomain) {
+ ss.str("");
+ ss << "fluid_load_vel_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', "
+ << framenr << ", '" << gformat << "')";
+ }
+ else {
+ ss.str("");
+ ss << "fluid_load_guiding_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', "
+ << framenr << ", '" << gformat << "')";
+ }
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeData(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeData()" << std::endl;
+
+ std::string tmpString, finalString;
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], cacheDirGuiding[FILE_MAX];
+ cacheDirData[0] = '\0';
+ cacheDirGuiding[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+ std::string gformat = dformat; // Use same data format for guiding format
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_join(cacheDirGuiding,
+ sizeof(cacheDirGuiding),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_GUIDING,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+ BLI_path_make_safe(cacheDirGuiding);
+
+ ss.str("");
+ ss << "bake_fluid_data_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirGuiding) << "', " << framenr << ", '" << dformat << "', '" << pformat
+ << "', '" << gformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeNoise(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeNoise()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], cacheDirNoise[FILE_MAX];
+ cacheDirData[0] = '\0';
+ cacheDirNoise[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string nformat = getCacheFileEnding(mmd->domain->cache_noise_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_join(cacheDirNoise,
+ sizeof(cacheDirNoise),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_NOISE,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+ BLI_path_make_safe(cacheDirNoise);
+
+ ss.str("");
+ ss << "bake_noise_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirNoise) << "', " << framenr << ", '" << dformat << "', '" << nformat
+ << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeMesh(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeMesh()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], cacheDirMesh[FILE_MAX];
+ cacheDirData[0] = '\0';
+ cacheDirMesh[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string mformat = getCacheFileEnding(mmd->domain->cache_mesh_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_join(cacheDirMesh,
+ sizeof(cacheDirMesh),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_MESH,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+ BLI_path_make_safe(cacheDirMesh);
+
+ ss.str("");
+ ss << "bake_mesh_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirMesh) << "', " << framenr << ", '" << dformat << "', '" << mformat
+ << "', '" << pformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeParticles(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeParticles()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirData[FILE_MAX], cacheDirParticles[FILE_MAX];
+ cacheDirData[0] = '\0';
+ cacheDirParticles[0] = '\0';
+
+ std::string dformat = getCacheFileEnding(mmd->domain->cache_data_format);
+ std::string pformat = getCacheFileEnding(mmd->domain->cache_particle_format);
+
+ BLI_path_join(cacheDirData,
+ sizeof(cacheDirData),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_DATA,
+ NULL);
+ BLI_path_join(cacheDirParticles,
+ sizeof(cacheDirParticles),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_PARTICLES,
+ NULL);
+ BLI_path_make_safe(cacheDirData);
+ BLI_path_make_safe(cacheDirParticles);
+
+ ss.str("");
+ ss << "bake_particles_" << mCurrentID << "('" << escapeSlashes(cacheDirData) << "', '"
+ << escapeSlashes(cacheDirParticles) << "', " << framenr << ", '" << dformat << "', '"
+ << pformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+int MANTA::bakeGuiding(FluidModifierData *mmd, int framenr)
+{
+ if (with_debug)
+ std::cout << "MANTA::bakeGuiding()" << std::endl;
+
+ std::ostringstream ss;
+ std::vector<std::string> pythonCommands;
+
+ char cacheDirGuiding[FILE_MAX];
+ cacheDirGuiding[0] = '\0';
+
+ std::string gformat = getCacheFileEnding(mmd->domain->cache_data_format);
+
+ BLI_path_join(cacheDirGuiding,
+ sizeof(cacheDirGuiding),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_GUIDING,
+ NULL);
+ BLI_path_make_safe(cacheDirGuiding);
+
+ ss.str("");
+ ss << "bake_guiding_" << mCurrentID << "('" << escapeSlashes(cacheDirGuiding) << "', " << framenr
+ << ", '" << gformat << "')";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+ return 1;
+}
+
+void MANTA::updateVariables(FluidModifierData *mmd)
+{
+ std::string tmpString, finalString;
+ std::vector<std::string> pythonCommands;
+
+ tmpString += fluid_variables;
+ if (mUsingSmoke)
+ tmpString += smoke_variables;
+ if (mUsingLiquid)
+ tmpString += liquid_variables;
+ if (mUsingGuiding)
+ tmpString += fluid_variables_guiding;
+ if (mUsingNoise) {
+ tmpString += fluid_variables_noise;
+ tmpString += smoke_variables_noise;
+ tmpString += smoke_wavelet_noise;
+ }
+ if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
+ tmpString += fluid_variables_particles;
+ tmpString += liquid_variables_particles;
+ }
+ if (mUsingMesh)
+ tmpString += fluid_variables_mesh;
+
+ finalString = parseScript(tmpString, mmd);
+ pythonCommands.push_back(finalString);
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::exportSmokeScript(FluidModifierData *mmd)
+{
+ if (with_debug)
+ std::cout << "MANTA::exportSmokeScript()" << std::endl;
+
+ char cacheDirScript[FILE_MAX];
+ cacheDirScript[0] = '\0';
+
+ BLI_path_join(cacheDirScript,
+ sizeof(cacheDirScript),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_SCRIPT,
+ NULL);
+ BLI_path_make_safe(cacheDirScript);
+ BLI_dir_create_recursive(
+ cacheDirScript); /* Create 'script' subdir if it does not exist already */
+ BLI_path_join(
+ cacheDirScript, sizeof(cacheDirScript), cacheDirScript, FLUID_DOMAIN_SMOKE_SCRIPT, NULL);
+ BLI_path_make_safe(cacheDirScript);
+
+ bool noise = mmd->domain->flags & FLUID_DOMAIN_USE_NOISE;
+ bool heat = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_HEAT;
+ bool colors = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_COLORS;
+ bool fire = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_FIRE;
+ bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
+ bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDING;
+ bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
+
+ std::string manta_script;
+
+ // Libraries
+ manta_script += header_libraries + manta_import;
+
+ // Variables
+ manta_script += header_variables + fluid_variables + smoke_variables;
+ if (noise) {
+ manta_script += fluid_variables_noise + smoke_variables_noise;
+ }
+ if (guiding)
+ manta_script += fluid_variables_guiding;
+
+ // Solvers
+ manta_script += header_solvers + fluid_solver;
+ if (noise)
+ manta_script += fluid_solver_noise;
+ if (guiding)
+ manta_script += fluid_solver_guiding;
+
+ // Grids
+ manta_script += header_grids + fluid_alloc + smoke_alloc;
+ if (noise) {
+ manta_script += smoke_alloc_noise;
+ if (colors)
+ manta_script += smoke_alloc_colors_noise;
+ if (fire)
+ manta_script += smoke_alloc_fire_noise;
+ }
+ if (heat)
+ manta_script += smoke_alloc_heat;
+ if (colors)
+ manta_script += smoke_alloc_colors;
+ if (fire)
+ manta_script += smoke_alloc_fire;
+ if (guiding)
+ manta_script += fluid_alloc_guiding;
+ if (obstacle)
+ manta_script += fluid_alloc_obstacle;
+ if (invel)
+ manta_script += fluid_alloc_invel;
+
+ // Noise field
+ if (noise)
+ manta_script += smoke_wavelet_noise;
+
+ // Time
+ manta_script += header_time + fluid_time_stepping + fluid_adapt_time_step;
+
+ // Import
+ manta_script += header_import + fluid_file_import + fluid_cache_helper + fluid_load_data +
+ smoke_load_data;
+ if (noise)
+ manta_script += smoke_load_noise;
+ if (guiding)
+ manta_script += fluid_load_guiding;
+
+ // Pre/Post Steps
+ manta_script += header_prepost + fluid_pre_step + fluid_post_step;
+
+ // Steps
+ manta_script += header_steps + smoke_adaptive_step + smoke_step;
+ if (noise) {
+ manta_script += smoke_step_noise;
+ }
+
+ // Main
+ manta_script += header_main + smoke_standalone + fluid_standalone;
+
+ // Fill in missing variables in script
+ std::string final_script = MANTA::parseScript(manta_script, mmd);
+
+ // Write script
+ std::ofstream myfile;
+ myfile.open(cacheDirScript);
+ myfile << final_script;
+ myfile.close();
+}
+
+void MANTA::exportLiquidScript(FluidModifierData *mmd)
+{
+ if (with_debug)
+ std::cout << "MANTA::exportLiquidScript()" << std::endl;
+
+ char cacheDirScript[FILE_MAX];
+ cacheDirScript[0] = '\0';
+
+ BLI_path_join(cacheDirScript,
+ sizeof(cacheDirScript),
+ mmd->domain->cache_directory,
+ FLUID_DOMAIN_DIR_SCRIPT,
+ NULL);
+ BLI_path_make_safe(cacheDirScript);
+ BLI_dir_create_recursive(
+ cacheDirScript); /* Create 'script' subdir if it does not exist already */
+ BLI_path_join(
+ cacheDirScript, sizeof(cacheDirScript), cacheDirScript, FLUID_DOMAIN_LIQUID_SCRIPT, NULL);
+ BLI_path_make_safe(cacheDirScript);
+
+ bool mesh = mmd->domain->flags & FLUID_DOMAIN_USE_MESH;
+ bool drops = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY;
+ bool bubble = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
+ bool floater = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
+ bool tracer = mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_TRACER;
+ bool obstacle = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
+ bool guiding = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_GUIDING;
+ bool invel = mmd->domain->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
+
+ std::string manta_script;
+
+ // Libraries
+ manta_script += header_libraries + manta_import;
+
+ // Variables
+ manta_script += header_variables + fluid_variables + liquid_variables;
+ if (mesh)
+ manta_script += fluid_variables_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += fluid_variables_particles + liquid_variables_particles;
+ if (guiding)
+ manta_script += fluid_variables_guiding;
+
+ // Solvers
+ manta_script += header_solvers + fluid_solver;
+ if (mesh)
+ manta_script += fluid_solver_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += fluid_solver_particles;
+ if (guiding)
+ manta_script += fluid_solver_guiding;
+
+ // Grids
+ manta_script += header_grids + fluid_alloc + liquid_alloc;
+ if (mesh)
+ manta_script += liquid_alloc_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += fluid_alloc_sndparts + liquid_alloc_particles;
+ if (guiding)
+ manta_script += fluid_alloc_guiding;
+ if (obstacle)
+ manta_script += fluid_alloc_obstacle;
+ if (invel)
+ manta_script += fluid_alloc_invel;
+
+ // Domain init
+ manta_script += header_gridinit + liquid_init_phi;
+
+ // Time
+ manta_script += header_time + fluid_time_stepping + fluid_adapt_time_step;
+
+ // Import
+ manta_script += header_import + fluid_file_import + fluid_cache_helper + fluid_load_data +
+ liquid_load_data + liquid_load_flip;
+ if (mesh)
+ manta_script += liquid_load_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += fluid_load_particles + liquid_load_particles;
+ if (guiding)
+ manta_script += fluid_load_guiding;
+
+ // Pre/Post Steps
+ manta_script += header_prepost + fluid_pre_step + fluid_post_step;
+
+ // Steps
+ manta_script += header_steps + liquid_adaptive_step + liquid_step;
+ if (mesh)
+ manta_script += liquid_step_mesh;
+ if (drops || bubble || floater || tracer)
+ manta_script += liquid_step_particles;
+
+ // Main
+ manta_script += header_main + liquid_standalone + fluid_standalone;
+
+ // Fill in missing variables in script
+ std::string final_script = MANTA::parseScript(manta_script, mmd);
+
+ // Write script
+ std::ofstream myfile;
+ myfile.open(cacheDirScript);
+ myfile << final_script;
+ myfile.close();
+}
+
+/* Call Mantaflow python functions through this function. Use isAttribute for object attributes,
+ * e.g. s.cfl (here 's' is varname, 'cfl' functionName, and isAttribute true) */
+static PyObject *callPythonFunction(std::string varName,
+ std::string functionName,
+ bool isAttribute = false)
+{
+ if ((varName == "") || (functionName == "")) {
+ if (MANTA::with_debug)
+ std::cout << "Missing Python variable name and/or function name -- name is: " << varName
+ << ", function name is: " << functionName << std::endl;
+ return NULL;
+ }
+
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+ PyObject *main = NULL, *var = NULL, *func = NULL, *returnedValue = NULL;
+
+ /* Be sure to initialise Python before importing main. */
+ Py_Initialize();
+
+ // Get pyobject that holds result value
+ main = PyImport_ImportModule("__main__");
+ if (!main)
+ return NULL;
+
+ var = PyObject_GetAttrString(main, varName.c_str());
+ if (!var)
+ return NULL;
+
+ func = PyObject_GetAttrString(var, functionName.c_str());
+
+ Py_DECREF(var);
+ if (!func)
+ return NULL;
+
+ if (!isAttribute) {
+ returnedValue = PyObject_CallObject(func, NULL);
+ Py_DECREF(func);
+ }
+
+ PyGILState_Release(gilstate);
+ return (!isAttribute) ? returnedValue : func;
+}
+
+static char *pyObjectToString(PyObject *inputObject)
+{
+ PyObject *encoded = PyUnicode_AsUTF8String(inputObject);
+ char *result = PyBytes_AsString(encoded);
+ Py_DECREF(encoded);
+ Py_DECREF(inputObject);
+ return result;
+}
+
+static double pyObjectToDouble(PyObject *inputObject)
+{
+ // Cannot use PyFloat_AsDouble() since its error check crashes - likely because of Real (aka
+ // float) type in Mantaflow
+ return PyFloat_AS_DOUBLE(inputObject);
+}
+
+static long pyObjectToLong(PyObject *inputObject)
+{
+ return PyLong_AsLong(inputObject);
+}
+
+static void *stringToPointer(char *inputString)
+{
+ std::string str(inputString);
+ std::istringstream in(str);
+ void *dataPointer = NULL;
+ in >> dataPointer;
+ return dataPointer;
+}
+
+int MANTA::getFrame()
+{
+ if (with_debug)
+ std::cout << "MANTA::getFrame()" << std::endl;
+
+ std::string func = "frame";
+ std::string id = std::to_string(mCurrentID);
+ std::string solver = "s" + id;
+
+ return pyObjectToLong(callPythonFunction(solver, func, true));
+}
+
+float MANTA::getTimestep()
+{
+ if (with_debug)
+ std::cout << "MANTA::getTimestep()" << std::endl;
+
+ std::string func = "timestep";
+ std::string id = std::to_string(mCurrentID);
+ std::string solver = "s" + id;
+
+ return pyObjectToDouble(callPythonFunction(solver, func, true));
+}
+
+bool MANTA::needsRealloc(FluidModifierData *mmd)
+{
+ FluidDomainSettings *mds = mmd->domain;
+ return (mds->res[0] != mResX || mds->res[1] != mResY || mds->res[2] != mResZ);
+}
+
+void MANTA::adaptTimestep()
+{
+ if (with_debug)
+ std::cout << "MANTA::adaptTimestep()" << std::endl;
+
+ std::vector<std::string> pythonCommands;
+ std::ostringstream ss;
+
+ ss << "fluid_adapt_time_step_" << mCurrentID << "()";
+ pythonCommands.push_back(ss.str());
+
+ runPythonString(pythonCommands);
+}
+
+void MANTA::updateMeshFromFile(const char *filename)
+{
+ std::string fname(filename);
+ std::string::size_type idx;
+
+ idx = fname.rfind('.');
+ if (idx != std::string::npos) {
+ std::string extension = fname.substr(idx + 1);
+
+ if (extension.compare("gz") == 0)
+ updateMeshFromBobj(filename);
+ else if (extension.compare("obj") == 0)
+ updateMeshFromObj(filename);
+ else if (extension.compare("uni") == 0)
+ updateMeshFromUni(filename);
+ else
+ std::cerr << "updateMeshFromFile: invalid file extension in file: " << filename << std::endl;
+ }
+ else {
+ std::cerr << "updateMeshFromFile: unable to open file: " << filename << std::endl;
+ }
+}
+
+void MANTA::updateMeshFromBobj(const char *filename)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateMeshFromBobj()" << std::endl;
+
+ gzFile gzf;
+ float fbuffer[3];
+ int ibuffer[3];
+ int numBuffer = 0;
+
+ gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression
+ if (!gzf)
+ std::cerr << "updateMeshData: unable to open file: " << filename << std::endl;
+
+ // Num vertices
+ gzread(gzf, &numBuffer, sizeof(int));
+
+ if (with_debug)
+ std::cout << "read mesh , num verts: " << numBuffer << " , in file: " << filename << std::endl;
+
+ if (numBuffer) {
+ // Vertices
+ mMeshNodes->resize(numBuffer);
+ for (std::vector<Node>::iterator it = mMeshNodes->begin(); it != mMeshNodes->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3);
+ it->pos[0] = fbuffer[0];
+ it->pos[1] = fbuffer[1];
+ it->pos[2] = fbuffer[2];
+ }
+ }
+
+ // Num normals
+ gzread(gzf, &numBuffer, sizeof(int));
+
+ if (with_debug)
+ std::cout << "read mesh , num normals : " << numBuffer << " , in file: " << filename
+ << std::endl;
+
+ if (numBuffer) {
+ // Normals
+ if (!getNumVertices())
+ mMeshNodes->resize(numBuffer);
+ for (std::vector<Node>::iterator it = mMeshNodes->begin(); it != mMeshNodes->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3);
+ it->normal[0] = fbuffer[0];
+ it->normal[1] = fbuffer[1];
+ it->normal[2] = fbuffer[2];
+ }
+ }
+
+ // Num triangles
+ gzread(gzf, &numBuffer, sizeof(int));
+
+ if (with_debug)
+ std::cout << "read mesh , num triangles : " << numBuffer << " , in file: " << filename
+ << std::endl;
+
+ if (numBuffer) {
+ // Triangles
+ mMeshTriangles->resize(numBuffer);
+ MANTA::Triangle *bufferTriangle;
+ for (std::vector<Triangle>::iterator it = mMeshTriangles->begin(); it != mMeshTriangles->end();
+ ++it) {
+ gzread(gzf, ibuffer, sizeof(int) * 3);
+ bufferTriangle = (MANTA::Triangle *)ibuffer;
+ it->c[0] = bufferTriangle->c[0];
+ it->c[1] = bufferTriangle->c[1];
+ it->c[2] = bufferTriangle->c[2];
+ }
+ }
+ gzclose(gzf);
+}
+
+void MANTA::updateMeshFromObj(const char *filename)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateMeshFromObj()" << std::endl;
+
+ std::ifstream ifs(filename);
+ float fbuffer[3];
+ int ibuffer[3];
+ int cntVerts = 0, cntNormals = 0, cntTris = 0;
+
+ if (!ifs.good())
+ std::cerr << "updateMeshDataFromObj: unable to open file: " << filename << std::endl;
+
+ while (ifs.good() && !ifs.eof()) {
+ std::string id;
+ ifs >> id;
+
+ if (id[0] == '#') {
+ // comment
+ getline(ifs, id);
+ continue;
+ }
+ if (id == "vt") {
+ // tex coord, ignore
+ }
+ else if (id == "vn") {
+ // normals
+ if (getNumVertices() != cntVerts)
+ std::cerr << "updateMeshDataFromObj: invalid amount of mesh nodes" << std::endl;
+
+ ifs >> fbuffer[0] >> fbuffer[1] >> fbuffer[2];
+ MANTA::Node *node = &mMeshNodes->at(cntNormals);
+ (*node).normal[0] = fbuffer[0];
+ (*node).normal[1] = fbuffer[1];
+ (*node).normal[2] = fbuffer[2];
+ cntNormals++;
+ }
+ else if (id == "v") {
+ // vertex
+ ifs >> fbuffer[0] >> fbuffer[1] >> fbuffer[2];
+ MANTA::Node node;
+ node.pos[0] = fbuffer[0];
+ node.pos[1] = fbuffer[1];
+ node.pos[2] = fbuffer[2];
+ mMeshNodes->push_back(node);
+ cntVerts++;
+ }
+ else if (id == "g") {
+ // group
+ std::string group;
+ ifs >> group;
+ }
+ else if (id == "f") {
+ // face
+ std::string face;
+ for (int i = 0; i < 3; i++) {
+ ifs >> face;
+ if (face.find('/') != std::string::npos)
+ face = face.substr(0, face.find('/')); // ignore other indices
+ int idx = atoi(face.c_str()) - 1;
+ if (idx < 0)
+ std::cerr << "updateMeshDataFromObj: invalid face encountered" << std::endl;
+ ibuffer[i] = idx;
+ }
+ MANTA::Triangle triangle;
+ triangle.c[0] = ibuffer[0];
+ triangle.c[1] = ibuffer[1];
+ triangle.c[2] = ibuffer[2];
+ mMeshTriangles->push_back(triangle);
+ cntTris++;
+ }
+ else {
+ // whatever, ignore
+ }
+ // kill rest of line
+ getline(ifs, id);
+ }
+ ifs.close();
+}
+
+void MANTA::updateMeshFromUni(const char *filename)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateMeshFromUni()" << std::endl;
+
+ gzFile gzf;
+ float fbuffer[4];
+ int ibuffer[4];
+
+ gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression
+ if (!gzf)
+ std::cout << "updateMeshFromUni: unable to open file" << std::endl;
+
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ std::vector<pVel> *velocityPointer = mMeshVelocities;
+
+ // mdata uni header
+ const int STR_LEN_PDATA = 256;
+ int elementType, bytesPerElement, numParticles;
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+
+ // read mesh header
+ gzread(gzf, &ibuffer, sizeof(int) * 4); // num particles, dimX, dimY, dimZ
+ gzread(gzf, &elementType, sizeof(int));
+ gzread(gzf, &bytesPerElement, sizeof(int));
+ gzread(gzf, &info, sizeof(info));
+ gzread(gzf, &timestamp, sizeof(unsigned long long));
+
+ if (with_debug)
+ std::cout << "read " << ibuffer[0] << " vertices in file: " << filename << std::endl;
+
+ // Sanity checks
+ const int meshSize = sizeof(float) * 3 + sizeof(int);
+ if (!(bytesPerElement == meshSize) && (elementType == 0)) {
+ std::cout << "particle type doesn't match" << std::endl;
+ }
+ if (!ibuffer[0]) { // Any vertices present?
+ if (with_debug)
+ std::cout << "no vertices present yet" << std::endl;
+ return;
+ }
+
+ // Reading mesh
+ if (!strcmp(ID, "MB01")) {
+ // TODO (sebbas): Future update could add uni mesh support
+ }
+ // Reading mesh data file v1 with vec3
+ else if (!strcmp(ID, "MD01")) {
+ numParticles = ibuffer[0];
+
+ velocityPointer->resize(numParticles);
+ MANTA::pVel *bufferPVel;
+ for (std::vector<pVel>::iterator it = velocityPointer->begin(); it != velocityPointer->end();
+ ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3);
+ bufferPVel = (MANTA::pVel *)fbuffer;
+ it->pos[0] = bufferPVel->pos[0];
+ it->pos[1] = bufferPVel->pos[1];
+ it->pos[2] = bufferPVel->pos[2];
+ }
+ }
+
+ gzclose(gzf);
+}
+
+void MANTA::updateParticlesFromFile(const char *filename, bool isSecondarySys, bool isVelData)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateParticlesFromFile()" << std::endl;
+
+ std::string fname(filename);
+ std::string::size_type idx;
+
+ idx = fname.rfind('.');
+ if (idx != std::string::npos) {
+ std::string extension = fname.substr(idx + 1);
+
+ if (extension.compare("uni") == 0)
+ updateParticlesFromUni(filename, isSecondarySys, isVelData);
+ else
+ std::cerr << "updateParticlesFromFile: invalid file extension in file: " << filename
+ << std::endl;
+ }
+ else {
+ std::cerr << "updateParticlesFromFile: unable to open file: " << filename << std::endl;
+ }
+}
+
+void MANTA::updateParticlesFromUni(const char *filename, bool isSecondarySys, bool isVelData)
+{
+ if (with_debug)
+ std::cout << "MANTA::updateParticlesFromUni()" << std::endl;
+
+ gzFile gzf;
+ float fbuffer[4];
+ int ibuffer[4];
+
+ gzf = (gzFile)BLI_gzopen(filename, "rb1"); // do some compression
+ if (!gzf)
+ std::cout << "updateParticlesFromUni: unable to open file" << std::endl;
+
+ char ID[5] = {0, 0, 0, 0, 0};
+ gzread(gzf, ID, 4);
+
+ if (!strcmp(ID, "PB01")) {
+ std::cout << "particle uni file format v01 not supported anymore" << std::endl;
+ return;
+ }
+
+ // Pointer to FLIP system or to secondary particle system
+ std::vector<pData> *dataPointer = NULL;
+ std::vector<pVel> *velocityPointer = NULL;
+ std::vector<float> *lifePointer = NULL;
+
+ if (isSecondarySys) {
+ dataPointer = mSndParticleData;
+ velocityPointer = mSndParticleVelocity;
+ lifePointer = mSndParticleLife;
+ }
+ else {
+ dataPointer = mFlipParticleData;
+ velocityPointer = mFlipParticleVelocity;
+ }
+
+ // pdata uni header
+ const int STR_LEN_PDATA = 256;
+ int elementType, bytesPerElement, numParticles;
+ char info[STR_LEN_PDATA]; // mantaflow build information
+ unsigned long long timestamp; // creation time
+
+ // read particle header
+ gzread(gzf, &ibuffer, sizeof(int) * 4); // num particles, dimX, dimY, dimZ
+ gzread(gzf, &elementType, sizeof(int));
+ gzread(gzf, &bytesPerElement, sizeof(int));
+ gzread(gzf, &info, sizeof(info));
+ gzread(gzf, &timestamp, sizeof(unsigned long long));
+
+ if (with_debug)
+ std::cout << "read " << ibuffer[0] << " particles in file: " << filename << std::endl;
+
+ // Sanity checks
+ const int partSysSize = sizeof(float) * 3 + sizeof(int);
+ if (!(bytesPerElement == partSysSize) && (elementType == 0)) {
+ std::cout << "particle type doesn't match" << std::endl;
+ }
+ if (!ibuffer[0]) { // Any particles present?
+ if (with_debug)
+ std::cout << "no particles present yet" << std::endl;
+ return;
+ }
+
+ numParticles = ibuffer[0];
+
+ // Reading base particle system file v2
+ if (!strcmp(ID, "PB02")) {
+ dataPointer->resize(numParticles);
+ MANTA::pData *bufferPData;
+ for (std::vector<pData>::iterator it = dataPointer->begin(); it != dataPointer->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3 + sizeof(int));
+ bufferPData = (MANTA::pData *)fbuffer;
+ it->pos[0] = bufferPData->pos[0];
+ it->pos[1] = bufferPData->pos[1];
+ it->pos[2] = bufferPData->pos[2];
+ it->flag = bufferPData->flag;
+ }
+ }
+ // Reading particle data file v1 with velocities
+ else if (!strcmp(ID, "PD01") && isVelData) {
+ velocityPointer->resize(numParticles);
+ MANTA::pVel *bufferPVel;
+ for (std::vector<pVel>::iterator it = velocityPointer->begin(); it != velocityPointer->end();
+ ++it) {
+ gzread(gzf, fbuffer, sizeof(float) * 3);
+ bufferPVel = (MANTA::pVel *)fbuffer;
+ it->pos[0] = bufferPVel->pos[0];
+ it->pos[1] = bufferPVel->pos[1];
+ it->pos[2] = bufferPVel->pos[2];
+ }
+ }
+ // Reading particle data file v1 with lifetime
+ else if (!strcmp(ID, "PD01")) {
+ lifePointer->resize(numParticles);
+ float *bufferPLife;
+ for (std::vector<float>::iterator it = lifePointer->begin(); it != lifePointer->end(); ++it) {
+ gzread(gzf, fbuffer, sizeof(float));
+ bufferPLife = (float *)fbuffer;
+ *it = *bufferPLife;
+ }
+ }
+
+ gzclose(gzf);
+}
+
+template<typename T>
+void MANTA::setPointers(std::vector<std::tuple<T **, std::string, std::string, bool>> objects)
+{
+ PyObject *mantaObject = NULL;
+
+ for (typename std::vector<std::tuple<T **, std::string, std::string, bool>>::iterator it =
+ objects.begin();
+ it != objects.end();
+ ++it) {
+ if (!std::get<3>(*it))
+ continue;
+ mantaObject = callPythonFunction(std::get<1>(*it), std::get<2>(*it));
+ if (mantaObject) {
+ (*std::get<0>(*it)) = (T *)stringToPointer(pyObjectToString(mantaObject));
+ }
+ else {
+ (*std::get<0>(*it)) = NULL;
+ }
+ }
+}
+
+void MANTA::updatePointers()
+{
+ if (with_debug)
+ std::cout << "MANTA::updatePointers()" << std::endl;
+
+ std::string func = "getDataPointer";
+ std::string funcNodes = "getNodesDataPointer";
+ std::string funcTris = "getTrisDataPointer";
+
+ std::string id = std::to_string(mCurrentID);
+ std::string solver = "s" + id;
+ std::string parts = "pp" + id;
+ std::string snd = "sp" + id;
+ std::string mesh = "sm" + id;
+ std::string mesh2 = "mesh" + id;
+ std::string noise = "sn" + id;
+ std::string solver_ext = "_" + solver;
+ std::string parts_ext = "_" + parts;
+ std::string snd_ext = "_" + snd;
+ std::string mesh_ext = "_" + mesh;
+ std::string mesh_ext2 = "_" + mesh2;
+ std::string noise_ext = "_" + noise;
+
+ std::vector<std::tuple<int **, std::string, std::string, bool>> mantaIntObjects;
+ mantaIntObjects.push_back(std::make_tuple(&mObstacle, "flags" + solver_ext, func, true));
+ mantaIntObjects.push_back(
+ std::make_tuple(&mNumObstacle, "numObs" + solver_ext, func, mUsingObstacle));
+ mantaIntObjects.push_back(
+ std::make_tuple(&mNumGuide, "numGuides" + solver_ext, func, mUsingGuiding));
+
+ std::vector<std::tuple<float **, std::string, std::string, bool>> mantaFloatObjects;
+ mantaFloatObjects.push_back(std::make_tuple(&mPhiIn, "phiIn" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mVelocityX, "x_vel" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mVelocityY, "y_vel" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mVelocityZ, "z_vel" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mForceX, "x_force" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mForceY, "y_force" + solver_ext, func, true));
+ mantaFloatObjects.push_back(std::make_tuple(&mForceZ, "z_force" + solver_ext, func, true));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mPhiOutIn, "phiOutIn" + solver_ext, func, mUsingOutflow));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mPhiObsIn, "phiObsIn" + solver_ext, func, mUsingObstacle));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mObVelocityX, "x_obvel" + solver_ext, func, mUsingObstacle));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mObVelocityY, "y_obvel" + solver_ext, func, mUsingObstacle));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mObVelocityZ, "z_obvel" + solver_ext, func, mUsingObstacle));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mPhiGuideIn, "phiGuideIn" + solver_ext, func, mUsingGuiding));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mGuideVelocityX, "x_guidevel" + solver_ext, func, mUsingGuiding));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mGuideVelocityY, "y_guidevel" + solver_ext, func, mUsingGuiding));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mGuideVelocityZ, "z_guidevel" + solver_ext, func, mUsingGuiding));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mInVelocityX, "x_invel" + solver_ext, func, mUsingInvel));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mInVelocityY, "y_invel" + solver_ext, func, mUsingInvel));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mInVelocityZ, "z_invel" + solver_ext, func, mUsingInvel));
+
+ mantaFloatObjects.push_back(std::make_tuple(&mPhi, "phi" + solver_ext, func, mUsingLiquid));
+
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mDensity, "density" + solver_ext, func, mUsingSmoke));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mDensityIn, "densityIn" + solver_ext, func, mUsingSmoke));
+ mantaFloatObjects.push_back(std::make_tuple(&mShadow, "shadow" + solver_ext, func, mUsingSmoke));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mEmissionIn, "emissionIn" + solver_ext, func, mUsingSmoke));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mHeat, "heat" + solver_ext, func, mUsingSmoke & mUsingHeat));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mHeatIn, "heatIn" + solver_ext, func, mUsingSmoke & mUsingHeat));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mFlame, "flame" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mFuel, "fuel" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mReact, "react" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mFuelIn, "fuelIn" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mReactIn, "reactIn" + solver_ext, func, mUsingSmoke & mUsingFire));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorR, "color_r" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorG, "color_g" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorB, "color_b" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorRIn, "color_r_in" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorGIn, "color_g_in" + solver_ext, func, mUsingSmoke & mUsingColors));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mColorBIn, "color_b_in" + solver_ext, func, mUsingSmoke & mUsingColors));
+
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mDensityHigh, "density" + noise_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureU, "texture_u" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureV, "texture_v" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureW, "texture_w" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureU2, "texture_u2" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureV2, "texture_v2" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(
+ std::make_tuple(&mTextureW2, "texture_w2" + solver_ext, func, mUsingSmoke & mUsingNoise));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mFlameHigh, "flame" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mFuelHigh, "fuel" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mReactHigh, "react" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingFire));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mColorRHigh, "color_r" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mColorGHigh, "color_g" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors));
+ mantaFloatObjects.push_back(std::make_tuple(
+ &mColorRHigh, "color_b" + noise_ext, func, mUsingSmoke & mUsingNoise & mUsingColors));
+
+ std::vector<std::tuple<std::vector<pData> **, std::string, std::string, bool>> mantaPDataObjects;
+ mantaPDataObjects.push_back(
+ std::make_tuple(&mFlipParticleData, "pp" + solver_ext, func, mUsingLiquid));
+ mantaPDataObjects.push_back(std::make_tuple(
+ &mSndParticleData,
+ "ppSnd" + snd_ext,
+ func,
+ mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers)));
+
+ std::vector<std::tuple<std::vector<pVel> **, std::string, std::string, bool>> mantaPVelObjects;
+ mantaPVelObjects.push_back(
+ std::make_tuple(&mFlipParticleVelocity, "pVel" + parts_ext, func, mUsingLiquid));
+ mantaPVelObjects.push_back(std::make_tuple(
+ &mMeshVelocities, "mVel" + mesh_ext2, func, mUsingLiquid & mUsingMesh & mUsingMVel));
+ mantaPVelObjects.push_back(std::make_tuple(
+ &mSndParticleVelocity,
+ "pVelSnd" + parts_ext,
+ func,
+ mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers)));
+
+ std::vector<std::tuple<std::vector<Node> **, std::string, std::string, bool>> mantaNodeObjects;
+ mantaNodeObjects.push_back(
+ std::make_tuple(&mMeshNodes, "mesh" + mesh_ext, funcNodes, mUsingLiquid & mUsingMesh));
+
+ std::vector<std::tuple<std::vector<Triangle> **, std::string, std::string, bool>>
+ mantaTriangleObjects;
+ mantaTriangleObjects.push_back(
+ std::make_tuple(&mMeshTriangles, "mesh" + mesh_ext, funcTris, mUsingLiquid & mUsingMesh));
+
+ std::vector<std::tuple<std::vector<float> **, std::string, std::string, bool>>
+ mantaFloatVecObjects;
+ mantaFloatVecObjects.push_back(std::make_tuple(
+ &mSndParticleLife,
+ "pLifeSnd" + parts_ext,
+ func,
+ mUsingLiquid & (mUsingDrops | mUsingBubbles | mUsingFloats | mUsingTracers)));
+
+ setPointers(mantaIntObjects);
+ setPointers(mantaFloatObjects);
+ setPointers(mantaPDataObjects);
+ setPointers(mantaPVelObjects);
+ setPointers(mantaNodeObjects);
+ setPointers(mantaTriangleObjects);
+ setPointers(mantaFloatVecObjects);
+}
diff --git a/intern/mantaflow/intern/MANTA_main.h b/intern/mantaflow/intern/MANTA_main.h
new file mode 100644
index 00000000000..276770de07a
--- /dev/null
+++ b/intern/mantaflow/intern/MANTA_main.h
@@ -0,0 +1,850 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/intern/MANTA.h
+ * \ingroup mantaflow
+ */
+
+#ifndef MANTA_A_H
+#define MANTA_A_H
+
+#include <string>
+#include <vector>
+#include <atomic>
+#include <cassert>
+
+struct MANTA {
+ public:
+ MANTA(int *res, struct FluidModifierData *mmd);
+ MANTA(){};
+ virtual ~MANTA();
+
+ // Mirroring Mantaflow structures for particle data (pVel also used for mesh vert vels)
+ typedef struct PData {
+ float pos[3];
+ int flag;
+ } pData;
+ typedef struct PVel {
+ float pos[3];
+ } pVel;
+
+ // Mirroring Mantaflow structures for meshes
+ typedef struct Node {
+ int flags;
+ float pos[3], normal[3];
+ } Node;
+ typedef struct Triangle {
+ int c[3];
+ int flags;
+ } Triangle;
+
+ // Manta step, handling everything
+ void step(struct FluidModifierData *mmd, int startFrame);
+
+ // Grid initialization functions
+ void initHeat(struct FluidModifierData *mmd);
+ void initFire(struct FluidModifierData *mmd);
+ void initColors(struct FluidModifierData *mmd);
+ void initFireHigh(struct FluidModifierData *mmd);
+ void initColorsHigh(struct FluidModifierData *mmd);
+ void initLiquid(FluidModifierData *mmd);
+ void initLiquidMesh(FluidModifierData *mmd);
+ void initObstacle(FluidModifierData *mmd);
+ void initGuiding(FluidModifierData *mmd);
+ void initFractions(FluidModifierData *mmd);
+ void initInVelocity(FluidModifierData *mmd);
+ void initOutflow(FluidModifierData *mmd);
+ void initSndParts(FluidModifierData *mmd);
+ void initLiquidSndParts(FluidModifierData *mmd);
+
+ // Pointer transfer: Mantaflow -> Blender
+ void updatePointers();
+
+ // Write cache
+ int writeConfiguration(FluidModifierData *mmd, int framenr);
+ int writeData(FluidModifierData *mmd, int framenr);
+ // write call for noise, mesh and particles were left in bake calls for now
+
+ // Read cache (via Manta save/load)
+ int readConfiguration(FluidModifierData *mmd, int framenr);
+ int readData(FluidModifierData *mmd, int framenr);
+ int readNoise(FluidModifierData *mmd, int framenr);
+ int readMesh(FluidModifierData *mmd, int framenr);
+ int readParticles(FluidModifierData *mmd, int framenr);
+ int readGuiding(FluidModifierData *mmd, int framenr, bool sourceDomain);
+
+ // Read cache (via file read functions in MANTA - e.g. read .bobj.gz meshes, .uni particles)
+ int updateMeshStructures(FluidModifierData *mmd, int framenr);
+ int updateFlipStructures(FluidModifierData *mmd, int framenr);
+ int updateParticleStructures(FluidModifierData *mmd, int framenr);
+ void updateVariables(FluidModifierData *mmd);
+
+ // Bake cache
+ int bakeData(FluidModifierData *mmd, int framenr);
+ int bakeNoise(FluidModifierData *mmd, int framenr);
+ int bakeMesh(FluidModifierData *mmd, int framenr);
+ int bakeParticles(FluidModifierData *mmd, int framenr);
+ int bakeGuiding(FluidModifierData *mmd, int framenr);
+
+ // IO for Mantaflow scene script
+ void exportSmokeScript(struct FluidModifierData *mmd);
+ void exportLiquidScript(struct FluidModifierData *mmd);
+
+ inline size_t getTotalCells()
+ {
+ return mTotalCells;
+ }
+ inline size_t getTotalCellsHigh()
+ {
+ return mTotalCellsHigh;
+ }
+ inline bool usingNoise()
+ {
+ return mUsingNoise;
+ }
+ inline int getResX()
+ {
+ return mResX;
+ }
+ inline int getResY()
+ {
+ return mResY;
+ }
+ inline int getResZ()
+ {
+ return mResZ;
+ }
+ inline int getParticleResX()
+ {
+ return mResXParticle;
+ }
+ inline int getParticleResY()
+ {
+ return mResYParticle;
+ }
+ inline int getParticleResZ()
+ {
+ return mResZParticle;
+ }
+ inline int getMeshResX()
+ {
+ return mResXMesh;
+ }
+ inline int getMeshResY()
+ {
+ return mResYMesh;
+ }
+ inline int getMeshResZ()
+ {
+ return mResZMesh;
+ }
+ inline int getResXHigh()
+ {
+ return mResXNoise;
+ }
+ inline int getResYHigh()
+ {
+ return mResYNoise;
+ }
+ inline int getResZHigh()
+ {
+ return mResZNoise;
+ }
+ inline int getMeshUpres()
+ {
+ return mUpresMesh;
+ }
+ inline int getParticleUpres()
+ {
+ return mUpresParticle;
+ }
+
+ // Smoke getters
+ inline float *getDensity()
+ {
+ return mDensity;
+ }
+ inline float *getHeat()
+ {
+ return mHeat;
+ }
+ inline float *getVelocityX()
+ {
+ return mVelocityX;
+ }
+ inline float *getVelocityY()
+ {
+ return mVelocityY;
+ }
+ inline float *getVelocityZ()
+ {
+ return mVelocityZ;
+ }
+ inline float *getObVelocityX()
+ {
+ return mObVelocityX;
+ }
+ inline float *getObVelocityY()
+ {
+ return mObVelocityY;
+ }
+ inline float *getObVelocityZ()
+ {
+ return mObVelocityZ;
+ }
+ inline float *getGuideVelocityX()
+ {
+ return mGuideVelocityX;
+ }
+ inline float *getGuideVelocityY()
+ {
+ return mGuideVelocityY;
+ }
+ inline float *getGuideVelocityZ()
+ {
+ return mGuideVelocityZ;
+ }
+ inline float *getInVelocityX()
+ {
+ return mInVelocityX;
+ }
+ inline float *getInVelocityY()
+ {
+ return mInVelocityY;
+ }
+ inline float *getInVelocityZ()
+ {
+ return mInVelocityZ;
+ }
+ inline float *getForceX()
+ {
+ return mForceX;
+ }
+ inline float *getForceY()
+ {
+ return mForceY;
+ }
+ inline float *getForceZ()
+ {
+ return mForceZ;
+ }
+ inline int *getObstacle()
+ {
+ return mObstacle;
+ }
+ inline int *getNumObstacle()
+ {
+ return mNumObstacle;
+ }
+ inline int *getNumGuide()
+ {
+ return mNumGuide;
+ }
+ inline float *getFlame()
+ {
+ return mFlame;
+ }
+ inline float *getFuel()
+ {
+ return mFuel;
+ }
+ inline float *getReact()
+ {
+ return mReact;
+ }
+ inline float *getColorR()
+ {
+ return mColorR;
+ }
+ inline float *getColorG()
+ {
+ return mColorG;
+ }
+ inline float *getColorB()
+ {
+ return mColorB;
+ }
+ inline float *getShadow()
+ {
+ return mShadow;
+ }
+ inline float *getDensityIn()
+ {
+ return mDensityIn;
+ }
+ inline float *getHeatIn()
+ {
+ return mHeatIn;
+ }
+ inline float *getColorRIn()
+ {
+ return mColorRIn;
+ }
+ inline float *getColorGIn()
+ {
+ return mColorGIn;
+ }
+ inline float *getColorBIn()
+ {
+ return mColorBIn;
+ }
+ inline float *getFuelIn()
+ {
+ return mFuelIn;
+ }
+ inline float *getReactIn()
+ {
+ return mReactIn;
+ }
+ inline float *getEmissionIn()
+ {
+ return mEmissionIn;
+ }
+
+ inline float *getDensityHigh()
+ {
+ return mDensityHigh;
+ }
+ inline float *getFlameHigh()
+ {
+ return mFlameHigh;
+ }
+ inline float *getFuelHigh()
+ {
+ return mFuelHigh;
+ }
+ inline float *getReactHigh()
+ {
+ return mReactHigh;
+ }
+ inline float *getColorRHigh()
+ {
+ return mColorRHigh;
+ }
+ inline float *getColorGHigh()
+ {
+ return mColorGHigh;
+ }
+ inline float *getColorBHigh()
+ {
+ return mColorBHigh;
+ }
+ inline float *getTextureU()
+ {
+ return mTextureU;
+ }
+ inline float *getTextureV()
+ {
+ return mTextureV;
+ }
+ inline float *getTextureW()
+ {
+ return mTextureW;
+ }
+ inline float *getTextureU2()
+ {
+ return mTextureU2;
+ }
+ inline float *getTextureV2()
+ {
+ return mTextureV2;
+ }
+ inline float *getTextureW2()
+ {
+ return mTextureW2;
+ }
+
+ inline float *getPhiIn()
+ {
+ return mPhiIn;
+ }
+ inline float *getPhiObsIn()
+ {
+ return mPhiObsIn;
+ }
+ inline float *getPhiGuideIn()
+ {
+ return mPhiGuideIn;
+ }
+ inline float *getPhiOutIn()
+ {
+ return mPhiOutIn;
+ }
+ inline float *getPhi()
+ {
+ return mPhi;
+ }
+
+ static std::atomic<bool> mantaInitialized;
+ static std::atomic<int> solverID;
+ static int with_debug; // on or off (1 or 0), also sets manta debug level
+
+ // Mesh getters
+ inline int getNumVertices()
+ {
+ return (mMeshNodes && !mMeshNodes->empty()) ? mMeshNodes->size() : 0;
+ }
+ inline int getNumNormals()
+ {
+ return (mMeshNodes && !mMeshNodes->empty()) ? mMeshNodes->size() : 0;
+ }
+ inline int getNumTriangles()
+ {
+ return (mMeshTriangles && !mMeshTriangles->empty()) ? mMeshTriangles->size() : 0;
+ }
+
+ inline float getVertexXAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getVertexYAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getVertexZAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float getNormalXAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].normal[0];
+ }
+ return 0.0f;
+ }
+ inline float getNormalYAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].normal[1];
+ }
+ return 0.0f;
+ }
+ inline float getNormalZAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshNodes && !mMeshNodes->empty()) {
+ assert(i < mMeshNodes->size());
+ return (*mMeshNodes)[i].normal[2];
+ }
+ return 0.0f;
+ }
+
+ inline int getTriangleXAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshTriangles && !mMeshTriangles->empty()) {
+ assert(i < mMeshTriangles->size());
+ return (*mMeshTriangles)[i].c[0];
+ }
+ return 0;
+ }
+ inline int getTriangleYAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshTriangles && !mMeshTriangles->empty()) {
+ assert(i < mMeshTriangles->size());
+ return (*mMeshTriangles)[i].c[1];
+ }
+ return 0;
+ }
+ inline int getTriangleZAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshTriangles && !mMeshTriangles->empty()) {
+ assert(i < mMeshTriangles->size());
+ return (*mMeshTriangles)[i].c[2];
+ }
+ return 0;
+ }
+
+ inline float getVertVelXAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshVelocities && !mMeshVelocities->empty()) {
+ assert(i < mMeshVelocities->size());
+ return (*mMeshVelocities)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getVertVelYAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshVelocities && !mMeshVelocities->empty()) {
+ assert(i < mMeshVelocities->size());
+ return (*mMeshVelocities)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getVertVelZAt(int i)
+ {
+ assert(i >= 0);
+ if (mMeshVelocities && !mMeshVelocities->empty()) {
+ assert(i < mMeshVelocities->size());
+ return (*mMeshVelocities)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ // Particle getters
+ inline int getFlipParticleFlagAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleData && !mFlipParticleData->empty()) {
+ assert(i < mFlipParticleData->size());
+ return (*mFlipParticleData)[i].flag;
+ }
+ return 0;
+ }
+ inline int getSndParticleFlagAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleData && !mSndParticleData->empty()) {
+ assert(i < mSndParticleData->size());
+ return (*mSndParticleData)[i].flag;
+ }
+ return 0;
+ }
+
+ inline float getFlipParticlePositionXAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleData && !mFlipParticleData->empty()) {
+ assert(i < mFlipParticleData->size());
+ return (*mFlipParticleData)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getFlipParticlePositionYAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleData && !mFlipParticleData->empty()) {
+ assert(i < mFlipParticleData->size());
+ return (*mFlipParticleData)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getFlipParticlePositionZAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleData && !mFlipParticleData->empty()) {
+ assert(i < mFlipParticleData->size());
+ return (*mFlipParticleData)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float getSndParticlePositionXAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleData && !mSndParticleData->empty()) {
+ assert(i < mSndParticleData->size());
+ return (*mSndParticleData)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getSndParticlePositionYAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleData && !mSndParticleData->empty()) {
+ assert(i < mSndParticleData->size());
+ return (*mSndParticleData)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getSndParticlePositionZAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleData && !mSndParticleData->empty()) {
+ assert(i < mSndParticleData->size());
+ return (*mSndParticleData)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float getFlipParticleVelocityXAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) {
+ assert(i < mFlipParticleVelocity->size());
+ return (*mFlipParticleVelocity)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getFlipParticleVelocityYAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) {
+ assert(i < mFlipParticleVelocity->size());
+ return (*mFlipParticleVelocity)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getFlipParticleVelocityZAt(int i)
+ {
+ assert(i >= 0);
+ if (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) {
+ assert(i < mFlipParticleVelocity->size());
+ return (*mFlipParticleVelocity)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float getSndParticleVelocityXAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleVelocity && !mSndParticleVelocity->empty()) {
+ assert(i < mSndParticleVelocity->size());
+ return (*mSndParticleVelocity)[i].pos[0];
+ }
+ return 0.0f;
+ }
+ inline float getSndParticleVelocityYAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleVelocity && !mSndParticleVelocity->empty()) {
+ assert(i < mSndParticleVelocity->size());
+ return (*mSndParticleVelocity)[i].pos[1];
+ }
+ return 0.0f;
+ }
+ inline float getSndParticleVelocityZAt(int i)
+ {
+ assert(i >= 0);
+ if (mSndParticleVelocity && !mSndParticleVelocity->empty()) {
+ assert(i < mSndParticleVelocity->size());
+ return (*mSndParticleVelocity)[i].pos[2];
+ }
+ return 0.0f;
+ }
+
+ inline float *getFlipParticleData()
+ {
+ return (mFlipParticleData && !mFlipParticleData->empty()) ?
+ (float *)&mFlipParticleData->front() :
+ NULL;
+ }
+ inline float *getSndParticleData()
+ {
+ return (mSndParticleData && !mSndParticleData->empty()) ? (float *)&mSndParticleData->front() :
+ NULL;
+ }
+
+ inline float *getFlipParticleVelocity()
+ {
+ return (mFlipParticleVelocity && !mFlipParticleVelocity->empty()) ?
+ (float *)&mFlipParticleVelocity->front() :
+ NULL;
+ }
+ inline float *getSndParticleVelocity()
+ {
+ return (mSndParticleVelocity && !mSndParticleVelocity->empty()) ?
+ (float *)&mSndParticleVelocity->front() :
+ NULL;
+ }
+ inline float *getSndParticleLife()
+ {
+ return (mSndParticleLife && !mSndParticleLife->empty()) ? (float *)&mSndParticleLife->front() :
+ NULL;
+ }
+
+ inline int getNumFlipParticles()
+ {
+ return (mFlipParticleData && !mFlipParticleData->empty()) ? mFlipParticleData->size() : 0;
+ }
+ inline int getNumSndParticles()
+ {
+ return (mSndParticleData && !mSndParticleData->empty()) ? mSndParticleData->size() : 0;
+ }
+
+ // Direct access to solver time attributes
+ int getFrame();
+ float getTimestep();
+ void adaptTimestep();
+
+ bool needsRealloc(FluidModifierData *mmd);
+
+ private:
+ // simulation constants
+ size_t mTotalCells;
+ size_t mTotalCellsHigh;
+ size_t mTotalCellsMesh;
+ size_t mTotalCellsParticles;
+
+ int mCurrentID;
+
+ bool mUsingHeat;
+ bool mUsingColors;
+ bool mUsingFire;
+ bool mUsingObstacle;
+ bool mUsingGuiding;
+ bool mUsingFractions;
+ bool mUsingInvel;
+ bool mUsingOutflow;
+ bool mUsingNoise;
+ bool mUsingMesh;
+ bool mUsingMVel;
+ bool mUsingLiquid;
+ bool mUsingSmoke;
+ bool mUsingDrops;
+ bool mUsingBubbles;
+ bool mUsingFloats;
+ bool mUsingTracers;
+
+ int mResX;
+ int mResY;
+ int mResZ;
+ int mMaxRes;
+
+ int mResXNoise;
+ int mResYNoise;
+ int mResZNoise;
+ int mResXMesh;
+ int mResYMesh;
+ int mResZMesh;
+ int mResXParticle;
+ int mResYParticle;
+ int mResZParticle;
+ int *mResGuiding;
+
+ int mUpresMesh;
+ int mUpresParticle;
+
+ float mTempAmb; /* ambient temperature */
+ float mConstantScaling;
+
+ // Fluid grids
+ float *mVelocityX;
+ float *mVelocityY;
+ float *mVelocityZ;
+ float *mObVelocityX;
+ float *mObVelocityY;
+ float *mObVelocityZ;
+ float *mGuideVelocityX;
+ float *mGuideVelocityY;
+ float *mGuideVelocityZ;
+ float *mInVelocityX;
+ float *mInVelocityY;
+ float *mInVelocityZ;
+ float *mForceX;
+ float *mForceY;
+ float *mForceZ;
+ int *mObstacle;
+ int *mNumObstacle;
+ int *mNumGuide;
+
+ // Smoke grids
+ float *mDensity;
+ float *mHeat;
+ float *mFlame;
+ float *mFuel;
+ float *mReact;
+ float *mColorR;
+ float *mColorG;
+ float *mColorB;
+ float *mShadow;
+ float *mDensityIn;
+ float *mHeatIn;
+ float *mFuelIn;
+ float *mReactIn;
+ float *mEmissionIn;
+ float *mColorRIn;
+ float *mColorGIn;
+ float *mColorBIn;
+ float *mDensityHigh;
+ float *mFlameHigh;
+ float *mFuelHigh;
+ float *mReactHigh;
+ float *mColorRHigh;
+ float *mColorGHigh;
+ float *mColorBHigh;
+ float *mTextureU;
+ float *mTextureV;
+ float *mTextureW;
+ float *mTextureU2;
+ float *mTextureV2;
+ float *mTextureW2;
+
+ // Liquid grids
+ float *mPhiIn;
+ float *mPhiObsIn;
+ float *mPhiGuideIn;
+ float *mPhiOutIn;
+ float *mPhi;
+
+ // Mesh fields
+ std::vector<Node> *mMeshNodes;
+ std::vector<Triangle> *mMeshTriangles;
+ std::vector<pVel> *mMeshVelocities;
+
+ // Particle fields
+ std::vector<pData> *mFlipParticleData;
+ std::vector<pVel> *mFlipParticleVelocity;
+
+ std::vector<pData> *mSndParticleData;
+ std::vector<pVel> *mSndParticleVelocity;
+ std::vector<float> *mSndParticleLife;
+
+ void initDomain(struct FluidModifierData *mmd);
+ void initNoise(struct FluidModifierData *mmd);
+ void initMesh(struct FluidModifierData *mmd);
+ void initSmoke(struct FluidModifierData *mmd);
+ void initSmokeNoise(struct FluidModifierData *mmd);
+ void initializeMantaflow();
+ void terminateMantaflow();
+ void runPythonString(std::vector<std::string> commands);
+ std::string getRealValue(const std::string &varName, FluidModifierData *mmd);
+ std::string parseLine(const std::string &line, FluidModifierData *mmd);
+ std::string parseScript(const std::string &setup_string, FluidModifierData *mmd = NULL);
+ void updateMeshFromBobj(const char *filename);
+ void updateMeshFromObj(const char *filename);
+ void updateMeshFromUni(const char *filename);
+ void updateParticlesFromUni(const char *filename, bool isSecondarySys, bool isVelData);
+ void updateMeshFromFile(const char *filename);
+ void updateParticlesFromFile(const char *filename, bool isSecondarySys, bool isVelData);
+ template<class T>
+ void setPointers(std::vector<std::tuple<T **, std::string, std::string, bool>>);
+};
+
+#endif
diff --git a/intern/mantaflow/intern/manta_fluid_API.cpp b/intern/mantaflow/intern/manta_fluid_API.cpp
new file mode 100644
index 00000000000..107d7134d87
--- /dev/null
+++ b/intern/mantaflow/intern/manta_fluid_API.cpp
@@ -0,0 +1,872 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/intern/manta_smoke_API.cpp
+ * \ingroup mantaflow
+ */
+
+#include <cmath>
+
+#include "MANTA_main.h"
+#include "manta_fluid_API.h"
+
+/* Fluid functions */
+MANTA *manta_init(int *res, struct FluidModifierData *mmd)
+{
+ return new MANTA(res, mmd);
+}
+void manta_free(MANTA *fluid)
+{
+ delete fluid;
+ fluid = nullptr;
+}
+
+void manta_ensure_obstacle(MANTA *fluid, struct FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->initObstacle(mmd);
+ fluid->updatePointers();
+}
+void manta_ensure_guiding(MANTA *fluid, struct FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->initGuiding(mmd);
+ fluid->updatePointers();
+}
+void manta_ensure_invelocity(MANTA *fluid, struct FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->initInVelocity(mmd);
+ fluid->updatePointers();
+}
+void manta_ensure_outflow(MANTA *fluid, struct FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->initOutflow(mmd);
+ fluid->updatePointers();
+}
+
+int manta_write_config(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->writeConfiguration(mmd, framenr);
+}
+
+int manta_write_data(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->writeData(mmd, framenr);
+}
+
+int manta_read_config(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readConfiguration(mmd, framenr);
+}
+
+int manta_read_data(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readData(mmd, framenr);
+}
+
+int manta_read_noise(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readNoise(mmd, framenr);
+}
+
+int manta_read_mesh(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readMesh(mmd, framenr);
+}
+
+int manta_read_particles(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readParticles(mmd, framenr);
+}
+
+int manta_read_guiding(MANTA *fluid, FluidModifierData *mmd, int framenr, bool sourceDomain)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->readGuiding(mmd, framenr, sourceDomain);
+}
+
+int manta_update_liquid_structures(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateFlipStructures(mmd, framenr);
+}
+
+int manta_update_mesh_structures(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateMeshStructures(mmd, framenr);
+}
+
+int manta_update_particle_structures(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->updateParticleStructures(mmd, framenr);
+}
+
+int manta_bake_data(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeData(mmd, framenr);
+}
+
+int manta_bake_noise(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeNoise(mmd, framenr);
+}
+
+int manta_bake_mesh(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeMesh(mmd, framenr);
+}
+
+int manta_bake_particles(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeParticles(mmd, framenr);
+}
+
+int manta_bake_guiding(MANTA *fluid, FluidModifierData *mmd, int framenr)
+{
+ if (!fluid || !mmd)
+ return 0;
+ return fluid->bakeGuiding(mmd, framenr);
+}
+
+void manta_update_variables(MANTA *fluid, FluidModifierData *mmd)
+{
+ if (!fluid)
+ return;
+ fluid->updateVariables(mmd);
+}
+
+int manta_get_frame(MANTA *fluid)
+{
+ if (!fluid)
+ return 0;
+ return fluid->getFrame();
+}
+
+float manta_get_timestep(MANTA *fluid)
+{
+ if (!fluid)
+ return 0;
+ return fluid->getTimestep();
+}
+
+void manta_adapt_timestep(MANTA *fluid)
+{
+ if (!fluid)
+ return;
+ fluid->adaptTimestep();
+}
+
+bool manta_needs_realloc(MANTA *fluid, FluidModifierData *mmd)
+{
+ if (!fluid)
+ return false;
+ return fluid->needsRealloc(mmd);
+}
+
+/* Fluid accessors */
+size_t manta_get_index(int x, int max_x, int y, int max_y, int z /*, int max_z */)
+{
+ return x + y * max_x + z * max_x * max_y;
+}
+size_t manta_get_index2d(int x, int max_x, int y /*, int max_y, int z, int max_z */)
+{
+ return x + y * max_x;
+}
+float *manta_get_velocity_x(MANTA *fluid)
+{
+ return fluid->getVelocityX();
+}
+float *manta_get_velocity_y(MANTA *fluid)
+{
+ return fluid->getVelocityY();
+}
+float *manta_get_velocity_z(MANTA *fluid)
+{
+ return fluid->getVelocityZ();
+}
+
+float *manta_get_ob_velocity_x(MANTA *fluid)
+{
+ return fluid->getObVelocityX();
+}
+float *manta_get_ob_velocity_y(MANTA *fluid)
+{
+ return fluid->getObVelocityY();
+}
+float *manta_get_ob_velocity_z(MANTA *fluid)
+{
+ return fluid->getObVelocityZ();
+}
+
+float *manta_get_guide_velocity_x(MANTA *fluid)
+{
+ return fluid->getGuideVelocityX();
+}
+float *manta_get_guide_velocity_y(MANTA *fluid)
+{
+ return fluid->getGuideVelocityY();
+}
+float *manta_get_guide_velocity_z(MANTA *fluid)
+{
+ return fluid->getGuideVelocityZ();
+}
+
+float *manta_get_in_velocity_x(MANTA *fluid)
+{
+ return fluid->getInVelocityX();
+}
+float *manta_get_in_velocity_y(MANTA *fluid)
+{
+ return fluid->getInVelocityY();
+}
+float *manta_get_in_velocity_z(MANTA *fluid)
+{
+ return fluid->getInVelocityZ();
+}
+
+float *manta_get_force_x(MANTA *fluid)
+{
+ return fluid->getForceX();
+}
+float *manta_get_force_y(MANTA *fluid)
+{
+ return fluid->getForceY();
+}
+float *manta_get_force_z(MANTA *fluid)
+{
+ return fluid->getForceZ();
+}
+
+float *manta_get_phiguide_in(MANTA *fluid)
+{
+ return fluid->getPhiGuideIn();
+}
+
+int *manta_get_num_obstacle(MANTA *fluid)
+{
+ return fluid->getNumObstacle();
+}
+int *manta_get_num_guide(MANTA *fluid)
+{
+ return fluid->getNumGuide();
+}
+
+int manta_get_res_x(MANTA *fluid)
+{
+ return fluid->getResX();
+}
+int manta_get_res_y(MANTA *fluid)
+{
+ return fluid->getResY();
+}
+int manta_get_res_z(MANTA *fluid)
+{
+ return fluid->getResZ();
+}
+
+float *manta_get_phi_in(MANTA *fluid)
+{
+ return fluid->getPhiIn();
+}
+float *manta_get_phiobs_in(MANTA *fluid)
+{
+ return fluid->getPhiObsIn();
+}
+float *manta_get_phiout_in(MANTA *fluid)
+{
+ return fluid->getPhiOutIn();
+}
+
+/* Smoke functions */
+void manta_smoke_export_script(MANTA *smoke, FluidModifierData *mmd)
+{
+ if (!smoke || !mmd)
+ return;
+ smoke->exportSmokeScript(mmd);
+}
+
+void manta_smoke_export(MANTA *smoke,
+ float *dt,
+ float *dx,
+ float **dens,
+ float **react,
+ float **flame,
+ float **fuel,
+ float **heat,
+ float **vx,
+ float **vy,
+ float **vz,
+ float **r,
+ float **g,
+ float **b,
+ int **obstacle,
+ float **shadow)
+{
+ if (dens)
+ *dens = smoke->getDensity();
+ if (fuel)
+ *fuel = smoke->getFuel();
+ if (react)
+ *react = smoke->getReact();
+ if (flame)
+ *flame = smoke->getFlame();
+ if (heat)
+ *heat = smoke->getHeat();
+ *vx = smoke->getVelocityX();
+ *vy = smoke->getVelocityY();
+ *vz = smoke->getVelocityZ();
+ if (r)
+ *r = smoke->getColorR();
+ if (g)
+ *g = smoke->getColorG();
+ if (b)
+ *b = smoke->getColorB();
+ *obstacle = smoke->getObstacle();
+ *shadow = smoke->getShadow();
+ *dt = 1; // dummy value, not needed for smoke
+ *dx = 1; // dummy value, not needed for smoke
+}
+
+void manta_smoke_turbulence_export(MANTA *smoke,
+ float **dens,
+ float **react,
+ float **flame,
+ float **fuel,
+ float **r,
+ float **g,
+ float **b,
+ float **tcu,
+ float **tcv,
+ float **tcw,
+ float **tcu2,
+ float **tcv2,
+ float **tcw2)
+{
+ if (!smoke && !(smoke->usingNoise()))
+ return;
+
+ *dens = smoke->getDensityHigh();
+ if (fuel)
+ *fuel = smoke->getFuelHigh();
+ if (react)
+ *react = smoke->getReactHigh();
+ if (flame)
+ *flame = smoke->getFlameHigh();
+ if (r)
+ *r = smoke->getColorRHigh();
+ if (g)
+ *g = smoke->getColorGHigh();
+ if (b)
+ *b = smoke->getColorBHigh();
+ *tcu = smoke->getTextureU();
+ *tcv = smoke->getTextureV();
+ *tcw = smoke->getTextureW();
+
+ *tcu2 = smoke->getTextureU2();
+ *tcv2 = smoke->getTextureV2();
+ *tcw2 = smoke->getTextureW2();
+}
+
+static void get_rgba(
+ float *r, float *g, float *b, float *a, int total_cells, float *data, int sequential)
+{
+ int i;
+ /* Use offsets to map RGB grids to to correct location in data grid. */
+ int m = 4, i_g = 1, i_b = 2, i_a = 3;
+ if (sequential) {
+ m = 1;
+ i_g *= total_cells;
+ i_b *= total_cells;
+ i_a *= total_cells;
+ }
+
+ for (i = 0; i < total_cells; i++) {
+ float alpha = a[i];
+ if (alpha) {
+ data[i * m] = r[i];
+ data[i * m + i_g] = g[i];
+ data[i * m + i_b] = b[i];
+ }
+ else {
+ data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f;
+ }
+ data[i * m + i_a] = alpha;
+ }
+}
+
+void manta_smoke_get_rgba(MANTA *smoke, float *data, int sequential)
+{
+ get_rgba(smoke->getColorR(),
+ smoke->getColorG(),
+ smoke->getColorB(),
+ smoke->getDensity(),
+ smoke->getTotalCells(),
+ data,
+ sequential);
+}
+
+void manta_smoke_turbulence_get_rgba(MANTA *smoke, float *data, int sequential)
+{
+ get_rgba(smoke->getColorRHigh(),
+ smoke->getColorGHigh(),
+ smoke->getColorBHigh(),
+ smoke->getDensityHigh(),
+ smoke->getTotalCellsHigh(),
+ data,
+ sequential);
+}
+
+static void get_rgba_from_density(
+ float color[3], float *a, int total_cells, float *data, int sequential)
+{
+ int i;
+ int m = 4, i_g = 1, i_b = 2, i_a = 3;
+ if (sequential) {
+ m = 1;
+ i_g *= total_cells;
+ i_b *= total_cells;
+ i_a *= total_cells;
+ }
+
+ for (i = 0; i < total_cells; i++) {
+ float alpha = a[i];
+ if (alpha) {
+ data[i * m] = color[0] * alpha;
+ data[i * m + i_g] = color[1] * alpha;
+ data[i * m + i_b] = color[2] * alpha;
+ }
+ else {
+ data[i * m] = data[i * m + i_g] = data[i * m + i_b] = 0.0f;
+ }
+ data[i * m + i_a] = alpha;
+ }
+}
+
+void manta_smoke_get_rgba_from_density(MANTA *smoke, float color[3], float *data, int sequential)
+{
+ get_rgba_from_density(color, smoke->getDensity(), smoke->getTotalCells(), data, sequential);
+}
+
+void manta_smoke_turbulence_get_rgba_from_density(MANTA *smoke,
+ float color[3],
+ float *data,
+ int sequential)
+{
+ get_rgba_from_density(
+ color, smoke->getDensityHigh(), smoke->getTotalCellsHigh(), data, sequential);
+}
+
+void manta_smoke_ensure_heat(MANTA *smoke, struct FluidModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initHeat(mmd);
+ smoke->updatePointers();
+ }
+}
+
+void manta_smoke_ensure_fire(MANTA *smoke, struct FluidModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initFire(mmd);
+ if (smoke->usingNoise()) {
+ smoke->initFireHigh(mmd);
+ }
+ smoke->updatePointers();
+ }
+}
+
+void manta_smoke_ensure_colors(MANTA *smoke, struct FluidModifierData *mmd)
+{
+ if (smoke) {
+ smoke->initColors(mmd);
+ if (smoke->usingNoise()) {
+ smoke->initColorsHigh(mmd);
+ }
+ smoke->updatePointers();
+ }
+}
+
+/* Smoke accessors */
+float *manta_smoke_get_density(MANTA *smoke)
+{
+ return smoke->getDensity();
+}
+float *manta_smoke_get_fuel(MANTA *smoke)
+{
+ return smoke->getFuel();
+}
+float *manta_smoke_get_react(MANTA *smoke)
+{
+ return smoke->getReact();
+}
+float *manta_smoke_get_heat(MANTA *smoke)
+{
+ return smoke->getHeat();
+}
+float *manta_smoke_get_flame(MANTA *smoke)
+{
+ return smoke->getFlame();
+}
+float *manta_smoke_get_shadow(MANTA *fluid)
+{
+ return fluid->getShadow();
+}
+
+float *manta_smoke_get_color_r(MANTA *smoke)
+{
+ return smoke->getColorR();
+}
+float *manta_smoke_get_color_g(MANTA *smoke)
+{
+ return smoke->getColorG();
+}
+float *manta_smoke_get_color_b(MANTA *smoke)
+{
+ return smoke->getColorB();
+}
+
+int *manta_smoke_get_obstacle(MANTA *smoke)
+{
+ return smoke->getObstacle();
+}
+
+float *manta_smoke_get_density_in(MANTA *smoke)
+{
+ return smoke->getDensityIn();
+}
+float *manta_smoke_get_heat_in(MANTA *smoke)
+{
+ return smoke->getHeatIn();
+}
+float *manta_smoke_get_color_r_in(MANTA *smoke)
+{
+ return smoke->getColorRIn();
+}
+float *manta_smoke_get_color_g_in(MANTA *smoke)
+{
+ return smoke->getColorGIn();
+}
+float *manta_smoke_get_color_b_in(MANTA *smoke)
+{
+ return smoke->getColorBIn();
+}
+float *manta_smoke_get_fuel_in(MANTA *smoke)
+{
+ return smoke->getFuelIn();
+}
+float *manta_smoke_get_react_in(MANTA *smoke)
+{
+ return smoke->getReactIn();
+}
+float *manta_smoke_get_emission_in(MANTA *smoke)
+{
+ return smoke->getEmissionIn();
+}
+
+int manta_smoke_has_heat(MANTA *smoke)
+{
+ return (smoke->getHeat()) ? 1 : 0;
+}
+int manta_smoke_has_fuel(MANTA *smoke)
+{
+ return (smoke->getFuel()) ? 1 : 0;
+}
+int manta_smoke_has_colors(MANTA *smoke)
+{
+ return (smoke->getColorR() && smoke->getColorG() && smoke->getColorB()) ? 1 : 0;
+}
+
+float *manta_smoke_turbulence_get_density(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getDensityHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_fuel(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getFuelHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_react(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getReactHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_color_r(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorRHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_color_g(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorGHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_color_b(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getColorBHigh() : nullptr;
+}
+float *manta_smoke_turbulence_get_flame(MANTA *smoke)
+{
+ return (smoke && smoke->usingNoise()) ? smoke->getFlameHigh() : nullptr;
+}
+
+int manta_smoke_turbulence_has_fuel(MANTA *smoke)
+{
+ return (smoke->getFuelHigh()) ? 1 : 0;
+}
+int manta_smoke_turbulence_has_colors(MANTA *smoke)
+{
+ return (smoke->getColorRHigh() && smoke->getColorGHigh() && smoke->getColorBHigh()) ? 1 : 0;
+}
+
+void manta_smoke_turbulence_get_res(MANTA *smoke, int *res)
+{
+ if (smoke && smoke->usingNoise()) {
+ res[0] = smoke->getResXHigh();
+ res[1] = smoke->getResYHigh();
+ res[2] = smoke->getResZHigh();
+ }
+}
+int manta_smoke_turbulence_get_cells(MANTA *smoke)
+{
+ int total_cells_high = smoke->getResXHigh() * smoke->getResYHigh() * smoke->getResZHigh();
+ return (smoke && smoke->usingNoise()) ? total_cells_high : 0;
+}
+
+/* Liquid functions */
+void manta_liquid_export_script(MANTA *liquid, FluidModifierData *mmd)
+{
+ if (!liquid || !mmd)
+ return;
+ liquid->exportLiquidScript(mmd);
+}
+
+void manta_liquid_ensure_sndparts(MANTA *liquid, struct FluidModifierData *mmd)
+{
+ if (liquid) {
+ liquid->initLiquidSndParts(mmd);
+ liquid->updatePointers();
+ }
+}
+
+/* Liquid accessors */
+int manta_liquid_get_particle_res_x(MANTA *liquid)
+{
+ return liquid->getParticleResX();
+}
+int manta_liquid_get_particle_res_y(MANTA *liquid)
+{
+ return liquid->getParticleResY();
+}
+int manta_liquid_get_particle_res_z(MANTA *liquid)
+{
+ return liquid->getParticleResZ();
+}
+
+int manta_liquid_get_mesh_res_x(MANTA *liquid)
+{
+ return liquid->getMeshResX();
+}
+int manta_liquid_get_mesh_res_y(MANTA *liquid)
+{
+ return liquid->getMeshResY();
+}
+int manta_liquid_get_mesh_res_z(MANTA *liquid)
+{
+ return liquid->getMeshResZ();
+}
+
+int manta_liquid_get_particle_upres(MANTA *liquid)
+{
+ return liquid->getParticleUpres();
+}
+int manta_liquid_get_mesh_upres(MANTA *liquid)
+{
+ return liquid->getMeshUpres();
+}
+
+int manta_liquid_get_num_verts(MANTA *liquid)
+{
+ return liquid->getNumVertices();
+}
+int manta_liquid_get_num_normals(MANTA *liquid)
+{
+ return liquid->getNumNormals();
+}
+int manta_liquid_get_num_triangles(MANTA *liquid)
+{
+ return liquid->getNumTriangles();
+}
+
+float manta_liquid_get_vertex_x_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexXAt(i);
+}
+float manta_liquid_get_vertex_y_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexYAt(i);
+}
+float manta_liquid_get_vertex_z_at(MANTA *liquid, int i)
+{
+ return liquid->getVertexZAt(i);
+}
+
+float manta_liquid_get_normal_x_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalXAt(i);
+}
+float manta_liquid_get_normal_y_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalYAt(i);
+}
+float manta_liquid_get_normal_z_at(MANTA *liquid, int i)
+{
+ return liquid->getNormalZAt(i);
+}
+
+int manta_liquid_get_triangle_x_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleXAt(i);
+}
+int manta_liquid_get_triangle_y_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleYAt(i);
+}
+int manta_liquid_get_triangle_z_at(MANTA *liquid, int i)
+{
+ return liquid->getTriangleZAt(i);
+}
+
+float manta_liquid_get_vertvel_x_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelXAt(i);
+}
+float manta_liquid_get_vertvel_y_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelYAt(i);
+}
+float manta_liquid_get_vertvel_z_at(MANTA *liquid, int i)
+{
+ return liquid->getVertVelZAt(i);
+}
+
+int manta_liquid_get_num_flip_particles(MANTA *liquid)
+{
+ return liquid->getNumFlipParticles();
+}
+int manta_liquid_get_num_snd_particles(MANTA *liquid)
+{
+ return liquid->getNumSndParticles();
+}
+
+int manta_liquid_get_flip_particle_flag_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleFlagAt(i);
+}
+int manta_liquid_get_snd_particle_flag_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleFlagAt(i);
+}
+
+float manta_liquid_get_flip_particle_position_x_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionXAt(i);
+}
+float manta_liquid_get_flip_particle_position_y_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionYAt(i);
+}
+float manta_liquid_get_flip_particle_position_z_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticlePositionZAt(i);
+}
+
+float manta_liquid_get_flip_particle_velocity_x_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityXAt(i);
+}
+float manta_liquid_get_flip_particle_velocity_y_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityYAt(i);
+}
+float manta_liquid_get_flip_particle_velocity_z_at(MANTA *liquid, int i)
+{
+ return liquid->getFlipParticleVelocityZAt(i);
+}
+
+float manta_liquid_get_snd_particle_position_x_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionXAt(i);
+}
+float manta_liquid_get_snd_particle_position_y_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionYAt(i);
+}
+float manta_liquid_get_snd_particle_position_z_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticlePositionZAt(i);
+}
+
+float manta_liquid_get_snd_particle_velocity_x_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityXAt(i);
+}
+float manta_liquid_get_snd_particle_velocity_y_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityYAt(i);
+}
+float manta_liquid_get_snd_particle_velocity_z_at(MANTA *liquid, int i)
+{
+ return liquid->getSndParticleVelocityZAt(i);
+}
diff --git a/intern/mantaflow/intern/manta_python_API.cpp b/intern/mantaflow/intern/manta_python_API.cpp
new file mode 100644
index 00000000000..66b4a4082c5
--- /dev/null
+++ b/intern/mantaflow/intern/manta_python_API.cpp
@@ -0,0 +1,36 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/intern/manta_python_API.cpp
+ * \ingroup mantaflow
+ */
+
+#include "manta_python_API.h"
+#include "manta.h"
+
+PyObject *Manta_initPython(void)
+{
+ return Pb::PyInit_Main();
+}
diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h
new file mode 100644
index 00000000000..b2a709ac4c1
--- /dev/null
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -0,0 +1,805 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/intern/strings/shared_script.h
+ * \ingroup mantaflow
+ */
+
+#include <string>
+
+//////////////////////////////////////////////////////////////////////
+// LIBRARIES
+//////////////////////////////////////////////////////////////////////
+
+const std::string manta_import =
+ "\
+from manta import *\n\
+import os.path, shutil, math, sys, gc, multiprocessing, platform, time\n\
+\n\
+withMPBake = False # Bake files asynchronously\n\
+withMPSave = True # Save files asynchronously\n\
+isWindows = platform.system() != 'Darwin' and platform.system() != 'Linux'\n\
+# TODO (sebbas): Use this to simulate Windows multiprocessing (has default mode spawn)\n\
+#try:\n\
+# multiprocessing.set_start_method('spawn')\n\
+#except:\n\
+# pass\n\
+\n\
+bpy = sys.modules.get('bpy')\n\
+if bpy is not None:\n\
+ sys.executable = bpy.app.binary_path_python\n";
+
+//////////////////////////////////////////////////////////////////////
+// DEBUG
+//////////////////////////////////////////////////////////////////////
+
+const std::string manta_debuglevel =
+ "\n\
+def set_manta_debuglevel(level):\n\
+ setDebugLevel(level=level)\n # level 0 = mute all output from manta\n";
+
+//////////////////////////////////////////////////////////////////////
+// SOLVERS
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_solver =
+ "\n\
+mantaMsg('Solver base')\n\
+s$ID$ = Solver(name='solver_base$ID$', gridSize=gs_s$ID$, dim=dim_s$ID$)\n";
+
+const std::string fluid_solver_noise =
+ "\n\
+mantaMsg('Solver noise')\n\
+sn$ID$ = Solver(name='solver_noise$ID$', gridSize=gs_sn$ID$)\n";
+
+const std::string fluid_solver_mesh =
+ "\n\
+mantaMsg('Solver mesh')\n\
+sm$ID$ = Solver(name='solver_mesh$ID$', gridSize=gs_sm$ID$)\n";
+
+const std::string fluid_solver_particles =
+ "\n\
+mantaMsg('Solver particles')\n\
+sp$ID$ = Solver(name='solver_particles$ID$', gridSize=gs_sp$ID$)\n";
+
+const std::string fluid_solver_guiding =
+ "\n\
+mantaMsg('Solver guiding')\n\
+sg$ID$ = Solver(name='solver_guiding$ID$', gridSize=gs_sg$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// VARIABLES
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_variables =
+ "\n\
+mantaMsg('Fluid variables')\n\
+dim_s$ID$ = $SOLVER_DIM$\n\
+res_s$ID$ = $RES$\n\
+gravity_s$ID$ = vec3($GRAVITY_X$, $GRAVITY_Y$, $GRAVITY_Z$)\n\
+gs_s$ID$ = vec3($RESX$, $RESY$, $RESZ$)\n\
+maxVel_s$ID$ = 0\n\
+\n\
+doOpen_s$ID$ = $DO_OPEN$\n\
+boundConditions_s$ID$ = '$BOUND_CONDITIONS$'\n\
+boundaryWidth_s$ID$ = $BOUNDARY_WIDTH$\n\
+\n\
+using_smoke_s$ID$ = $USING_SMOKE$\n\
+using_liquid_s$ID$ = $USING_LIQUID$\n\
+using_noise_s$ID$ = $USING_NOISE$\n\
+using_adaptTime_s$ID$ = $USING_ADAPTIVETIME$\n\
+using_obstacle_s$ID$ = $USING_OBSTACLE$\n\
+using_guiding_s$ID$ = $USING_GUIDING$\n\
+using_fractions_s$ID$ = $USING_FRACTIONS$\n\
+using_invel_s$ID$ = $USING_INVEL$\n\
+using_outflow_s$ID$ = $USING_OUTFLOW$\n\
+using_sndparts_s$ID$ = $USING_SNDPARTS$\n\
+using_speedvectors_s$ID$ = $USING_SPEEDVECTORS$\n\
+\n\
+# Fluid time params\n\
+timeTotal_s$ID$ = $TIME_TOTAL$\n\
+timePerFrame_s$ID$ = $TIME_PER_FRAME$\n\
+frameLength_s$ID$ = $FRAME_LENGTH$\n\
+dt0_s$ID$ = $DT$\n\
+cflCond_s$ID$ = $CFL$\n\
+timestepsMin_s$ID$ = $TIMESTEPS_MIN$\n\
+timestepsMax_s$ID$ = $TIMESTEPS_MAX$\n\
+\n\
+# Fluid diffusion / viscosity\n\
+domainSize_s$ID$ = $FLUID_DOMAIN_SIZE$ # longest domain side in meters\n\
+viscosity_s$ID$ = $FLUID_VISCOSITY$ / (domainSize_s$ID$*domainSize_s$ID$) # kinematic viscosity in m^2/s\n\
+\n\
+# Factor to convert blender velocities to manta velocities\n\
+toMantaUnitsFac_s$ID$ = (1.0 / (1.0 / res_s$ID$))\n # = dt/dx * 1/dt ";
+
+const std::string fluid_variables_noise =
+ "\n\
+mantaMsg('Fluid variables noise')\n\
+upres_sn$ID$ = $NOISE_SCALE$\n\
+gs_sn$ID$ = vec3(upres_sn$ID$*gs_s$ID$.x, upres_sn$ID$*gs_s$ID$.y, upres_sn$ID$*gs_s$ID$.z)\n";
+
+const std::string fluid_variables_mesh =
+ "\n\
+mantaMsg('Fluid variables mesh')\n\
+upres_sm$ID$ = $MESH_SCALE$\n\
+gs_sm$ID$ = vec3(upres_sm$ID$*gs_s$ID$.x, upres_sm$ID$*gs_s$ID$.y, upres_sm$ID$*gs_s$ID$.z)\n";
+
+const std::string fluid_variables_particles =
+ "\n\
+mantaMsg('Fluid variables particles')\n\
+upres_sp$ID$ = $PARTICLE_SCALE$\n\
+gs_sp$ID$ = vec3(upres_sp$ID$*gs_s$ID$.x, upres_sp$ID$*gs_s$ID$.y, upres_sp$ID$*gs_s$ID$.z)\n";
+
+const std::string fluid_variables_guiding =
+ "\n\
+mantaMsg('Fluid variables guiding')\n\
+gs_sg$ID$ = vec3($GUIDING_RESX$, $GUIDING_RESY$, $GUIDING_RESZ$)\n\
+\n\
+alpha_sg$ID$ = $GUIDING_ALPHA$\n\
+beta_sg$ID$ = $GUIDING_BETA$\n\
+gamma_sg$ID$ = $GUIDING_FACTOR$\n\
+tau_sg$ID$ = 1.0\n\
+sigma_sg$ID$ = 0.99/tau_sg$ID$\n\
+theta_sg$ID$ = 1.0\n";
+
+const std::string fluid_with_obstacle =
+ "\n\
+using_obstacle_s$ID$ = True\n";
+
+const std::string fluid_with_guiding =
+ "\n\
+using_guiding_s$ID$ = True\n";
+
+const std::string fluid_with_fractions =
+ "\n\
+using_fractions_s$ID$ = True\n";
+
+const std::string fluid_with_invel =
+ "\n\
+using_invel_s$ID$ = True\n";
+
+const std::string fluid_with_outflow =
+ "\n\
+using_outflow_s$ID$ = True\n";
+
+const std::string fluid_with_sndparts =
+ "\n\
+using_sndparts_s$ID$ = True\n";
+
+//////////////////////////////////////////////////////////////////////
+// ADAPTIVE TIME STEPPING
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_time_stepping =
+ "\n\
+mantaMsg('Fluid adaptive time stepping')\n\
+s$ID$.frameLength = frameLength_s$ID$\n\
+s$ID$.timestepMin = s$ID$.frameLength / max(1, timestepsMax_s$ID$)\n\
+s$ID$.timestepMax = s$ID$.frameLength / max(1, timestepsMin_s$ID$)\n\
+s$ID$.cfl = cflCond_s$ID$\n\
+s$ID$.timePerFrame = timePerFrame_s$ID$\n\
+s$ID$.timestep = dt0_s$ID$\n\
+s$ID$.timeTotal = timeTotal_s$ID$\n\
+#mantaMsg('timestep: ' + str(s$ID$.timestep) + ' // timPerFrame: ' + str(s$ID$.timePerFrame) + ' // frameLength: ' + str(s$ID$.frameLength) + ' // timeTotal: ' + str(s$ID$.timeTotal) )\n";
+
+const std::string fluid_adapt_time_step =
+ "\n\
+def fluid_adapt_time_step_$ID$():\n\
+ mantaMsg('Fluid adapt time step')\n\
+ \n\
+ # time params are animatable\n\
+ s$ID$.frameLength = frameLength_s$ID$\n\
+ s$ID$.cfl = cflCond_s$ID$\n\
+ \n\
+ # ensure that vel grid is full (remember: adaptive domain can reallocate solver)\n\
+ copyRealToVec3(sourceX=x_vel_s$ID$, sourceY=y_vel_s$ID$, sourceZ=z_vel_s$ID$, target=vel_s$ID$)\n\
+ maxVel_s$ID$ = vel_s$ID$.getMax() if vel_s$ID$ else 0\n\
+ if using_adaptTime_s$ID$:\n\
+ mantaMsg('Adapt timestep, maxvel: ' + str(maxVel_s$ID$))\n\
+ s$ID$.adaptTimestep(maxVel_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// GRIDS
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_alloc =
+ "\n\
+mantaMsg('Fluid alloc data')\n\
+flags_s$ID$ = s$ID$.create(FlagGrid)\n\
+vel_s$ID$ = s$ID$.create(MACGrid)\n\
+velC_s$ID$ = s$ID$.create(MACGrid)\n\
+x_vel_s$ID$ = s$ID$.create(RealGrid)\n\
+y_vel_s$ID$ = s$ID$.create(RealGrid)\n\
+z_vel_s$ID$ = s$ID$.create(RealGrid)\n\
+pressure_s$ID$ = s$ID$.create(RealGrid)\n\
+phiObs_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+phiIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+phiOut_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+forces_s$ID$ = s$ID$.create(Vec3Grid)\n\
+x_force_s$ID$ = s$ID$.create(RealGrid)\n\
+y_force_s$ID$ = s$ID$.create(RealGrid)\n\
+z_force_s$ID$ = s$ID$.create(RealGrid)\n\
+obvel_s$ID$ = None\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+fluid_data_dict_s$ID$ = dict(vel=vel_s$ID$, phiObs=phiObs_s$ID$, phiIn=phiIn_s$ID$, phiOut=phiOut_s$ID$, flags=flags_s$ID$)\n";
+
+const std::string fluid_alloc_obstacle =
+ "\n\
+mantaMsg('Allocating obstacle data')\n\
+numObs_s$ID$ = s$ID$.create(IntGrid)\n\
+phiObsIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+obvel_s$ID$ = s$ID$.create(MACGrid)\n\
+obvelC_s$ID$ = s$ID$.create(Vec3Grid)\n\
+x_obvel_s$ID$ = s$ID$.create(RealGrid)\n\
+y_obvel_s$ID$ = s$ID$.create(RealGrid)\n\
+z_obvel_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+tmpDict_s$ID$ = dict(phiObsIn=phiObsIn_s$ID$)\n\
+fluid_data_dict_s$ID$.update(tmpDict_s$ID$)\n";
+
+const std::string fluid_alloc_guiding =
+ "\n\
+mantaMsg('Allocating guiding data')\n\
+velT_s$ID$ = s$ID$.create(MACGrid)\n\
+weightGuide_s$ID$ = s$ID$.create(RealGrid)\n\
+numGuides_s$ID$ = s$ID$.create(IntGrid)\n\
+phiGuideIn_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+guidevelC_s$ID$ = s$ID$.create(Vec3Grid)\n\
+x_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\
+y_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\
+z_guidevel_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+# Final guide vel grid needs to have independent size\n\
+guidevel_sg$ID$ = sg$ID$.create(MACGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+fluid_guiding_dict_s$ID$ = dict(guidevel=guidevel_sg$ID$)\n";
+
+const std::string fluid_alloc_fractions =
+ "\n\
+mantaMsg('Allocating fractions data')\n\
+fractions_s$ID$ = s$ID$.create(MACGrid)\n";
+
+const std::string fluid_alloc_invel =
+ "\n\
+mantaMsg('Allocating initial velocity data')\n\
+invelC_s$ID$ = s$ID$.create(VecGrid)\n\
+invel_s$ID$ = s$ID$.create(MACGrid)\n\
+x_invel_s$ID$ = s$ID$.create(RealGrid)\n\
+y_invel_s$ID$ = s$ID$.create(RealGrid)\n\
+z_invel_s$ID$ = s$ID$.create(RealGrid)\n";
+
+const std::string fluid_alloc_outflow =
+ "\n\
+mantaMsg('Allocating outflow data')\n\
+phiOutIn_s$ID$ = s$ID$.create(LevelsetGrid)\n";
+
+const std::string fluid_alloc_sndparts =
+ "\n\
+mantaMsg('Allocating snd parts low')\n\
+ppSnd_sp$ID$ = sp$ID$.create(BasicParticleSystem)\n\
+pVelSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataVec3)\n\
+pForceSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataVec3)\n\
+pLifeSnd_pp$ID$ = ppSnd_sp$ID$.create(PdataReal)\n\
+vel_sp$ID$ = sp$ID$.create(MACGrid)\n\
+flags_sp$ID$ = sp$ID$.create(FlagGrid)\n\
+phi_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+phiIn_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+phiObs_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+phiObsIn_sp$ID$ = sp$ID$.create(LevelsetGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+fluid_particles_dict_s$ID$ = dict(ppSnd=ppSnd_sp$ID$, pVelSnd=pVelSnd_pp$ID$, pLifeSnd=pLifeSnd_pp$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// PRE / POST STEP
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_pre_step =
+ "\n\
+def fluid_pre_step_$ID$():\n\
+ mantaMsg('Fluid pre step')\n\
+ \n\
+ phiObs_s$ID$.setConst(9999)\n\
+ phiOut_s$ID$.setConst(9999)\n\
+ \n\
+ # Main vel grid is copied in adapt time step function\n\
+ \n\
+ # translate obvels (world space) to grid space\n\
+ if using_obstacle_s$ID$:\n\
+ x_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ y_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ z_obvel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ copyRealToVec3(sourceX=x_obvel_s$ID$, sourceY=y_obvel_s$ID$, sourceZ=z_obvel_s$ID$, target=obvelC_s$ID$)\n\
+ \n\
+ # translate invels (world space) to grid space\n\
+ if using_invel_s$ID$:\n\
+ x_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ y_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ z_invel_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ copyRealToVec3(sourceX=x_invel_s$ID$, sourceY=y_invel_s$ID$, sourceZ=z_invel_s$ID$, target=invelC_s$ID$)\n\
+ \n\
+ if using_guiding_s$ID$:\n\
+ weightGuide_s$ID$.multConst(0)\n\
+ weightGuide_s$ID$.addConst(alpha_sg$ID$)\n\
+ interpolateMACGrid(source=guidevel_sg$ID$, target=velT_s$ID$)\n\
+ velT_s$ID$.multConst(vec3(gamma_sg$ID$))\n\
+ \n\
+ # translate external forces (world space) to grid space\n\
+ x_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ y_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ z_force_s$ID$.multConst(toMantaUnitsFac_s$ID$)\n\
+ copyRealToVec3(sourceX=x_force_s$ID$, sourceY=y_force_s$ID$, sourceZ=z_force_s$ID$, target=forces_s$ID$)\n\
+ \n\
+ # If obstacle has velocity, i.e. is a moving obstacle, switch to dynamic preconditioner\n\
+ if using_smoke_s$ID$ and using_obstacle_s$ID$ and obvelC_s$ID$.getMax() > 0:\n\
+ mantaMsg('Using dynamic preconditioner')\n\
+ preconditioner_s$ID$ = PcMGDynamic\n\
+ else:\n\
+ mantaMsg('Using static preconditioner')\n\
+ preconditioner_s$ID$ = PcMGStatic\n";
+
+const std::string fluid_post_step =
+ "\n\
+def fluid_post_step_$ID$():\n\
+ mantaMsg('Fluid post step')\n\
+ forces_s$ID$.clear()\n\
+ x_force_s$ID$.clear()\n\
+ y_force_s$ID$.clear()\n\
+ z_force_s$ID$.clear()\n\
+ \n\
+ if using_guiding_s$ID$:\n\
+ weightGuide_s$ID$.clear()\n\
+ if using_invel_s$ID$:\n\
+ x_invel_s$ID$.clear()\n\
+ y_invel_s$ID$.clear()\n\
+ z_invel_s$ID$.clear()\n\
+ invel_s$ID$.clear()\n\
+ invelC_s$ID$.clear()\n\
+ \n\
+ # Copy vel grid to reals grids (which Blender internal will in turn use for vel access)\n\
+ copyVec3ToReal(source=vel_s$ID$, targetX=x_vel_s$ID$, targetY=y_vel_s$ID$, targetZ=z_vel_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// DESTRUCTION
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_delete_all =
+ "\n\
+mantaMsg('Deleting fluid')\n\
+# Clear all helper dictionaries first\n\
+mantaMsg('Clear helper dictionaries')\n\
+if 'liquid_data_dict_s$ID$' in globals(): liquid_data_dict_s$ID$.clear()\n\
+if 'liquid_flip_dict_s$ID$' in globals(): liquid_flip_dict_s$ID$.clear()\n\
+if 'liquid_mesh_dict_s$ID$' in globals(): liquid_mesh_dict_s$ID$.clear()\n\
+if 'liquid_meshvel_dict_s$ID$' in globals(): liquid_meshvel_dict_s$ID$.clear()\n\
+if 'liquid_particles_dict_s$ID$' in globals(): liquid_particles_dict_s$ID$.clear()\n\
+if 'smoke_data_dict_s$ID$' in globals(): smoke_data_dict_s$ID$.clear()\n\
+if 'smoke_noise_dict_s$ID$' in globals(): smoke_noise_dict_s$ID$.clear()\n\
+if 'fluid_particles_dict_s$ID$' in globals(): fluid_particles_dict_s$ID$.clear()\n\
+if 'fluid_guiding_dict_s$ID$' in globals(): fluid_guiding_dict_s$ID$.clear()\n\
+if 'fluid_data_dict_s$ID$' in globals(): fluid_data_dict_s$ID$.clear()\n\
+if 'fluid_vel_dict_s$ID$' in globals(): fluid_vel_dict_s$ID$.clear()\n\
+\n\
+# Delete all childs from objects (e.g. pdata for particles)\n\
+mantaMsg('Release solver childs childs')\n\
+for var in list(globals()):\n\
+ if var.endswith('_pp$ID$') or var.endswith('_mesh$ID$'):\n\
+ del globals()[var]\n\
+\n\
+# Now delete childs from solver objects\n\
+mantaMsg('Release solver childs')\n\
+for var in list(globals()):\n\
+ if var.endswith('_s$ID$') or var.endswith('_sn$ID$') or var.endswith('_sm$ID$') or var.endswith('_sp$ID$') or var.endswith('_sg$ID$'):\n\
+ del globals()[var]\n\
+\n\
+# Extra cleanup for multigrid and fluid guiding\n\
+mantaMsg('Release multigrid')\n\
+if 's$ID$' in globals(): releaseMG(s$ID$)\n\
+if 'sn$ID$' in globals(): releaseMG(sn$ID$)\n\
+mantaMsg('Release fluid guiding')\n\
+releaseBlurPrecomp()\n\
+\n\
+# Release unreferenced memory (if there is some left, can in fact happen)\n\
+gc.collect()\n\
+\n\
+# Now it is safe to delete solver objects (always need to be deleted last)\n\
+mantaMsg('Delete base solver')\n\
+if 's$ID$' in globals(): del s$ID$\n\
+mantaMsg('Delete noise solver')\n\
+if 'sn$ID$' in globals(): del sn$ID$\n\
+mantaMsg('Delete mesh solver')\n\
+if 'sm$ID$' in globals(): del sm$ID$\n\
+mantaMsg('Delete particle solver')\n\
+if 'sp$ID$' in globals(): del sp$ID$\n\
+mantaMsg('Delete guiding solver')\n\
+if 'sg$ID$' in globals(): del sg$ID$\n\
+\n\
+# Release unreferenced memory (if there is some left)\n\
+gc.collect()\n";
+
+//////////////////////////////////////////////////////////////////////
+// BAKE
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_cache_helper =
+ "\n\
+def fluid_cache_get_framenr_formatted_$ID$(framenr):\n\
+ return str(framenr).zfill(4) # framenr with leading zeroes\n";
+
+const std::string fluid_bake_multiprocessing =
+ "\n\
+def fluid_cache_multiprocessing_start_$ID$(function, framenr, format_data=None, format_noise=None, format_mesh=None, format_particles=None, format_guiding=None, path_data=None, path_noise=None, path_mesh=None, path_particles=None, path_guiding=None, dict=None, do_join=True):\n\
+ mantaMsg('Multiprocessing cache')\n\
+ if __name__ == '__main__':\n\
+ args = (framenr,)\n\
+ if format_data:\n\
+ args += (format_data,)\n\
+ if format_noise:\n\
+ args += (format_noise,)\n\
+ if format_mesh:\n\
+ args += (format_mesh,)\n\
+ if format_particles:\n\
+ args += (format_particles,)\n\
+ if format_guiding:\n\
+ args += (format_guiding,)\n\
+ if path_data:\n\
+ args += (path_data,)\n\
+ if path_noise:\n\
+ args += (path_noise,)\n\
+ if path_mesh:\n\
+ args += (path_mesh,)\n\
+ if path_particles:\n\
+ args += (path_particles,)\n\
+ if path_guiding:\n\
+ args += (path_guiding,)\n\
+ if dict:\n\
+ args += (dict,)\n\
+ p$ID$ = multiprocessing.Process(target=function, args=args)\n\
+ p$ID$.start()\n\
+ if do_join:\n\
+ p$ID$.join()\n";
+
+const std::string fluid_bake_data =
+ "\n\
+def bake_fluid_process_data_$ID$(framenr, format_data, format_particles, format_guiding, path_data, path_guiding):\n\
+ mantaMsg('Bake fluid data')\n\
+ \n\
+ s$ID$.frame = framenr\n\
+ # Must not set 'timeTotal' here. Remember, this function is called from manta.c while-loop\n\
+ \n\
+ start_time = time.time()\n\
+ if using_smoke_s$ID$:\n\
+ smoke_adaptive_step_$ID$(framenr)\n\
+ if using_liquid_s$ID$:\n\
+ liquid_adaptive_step_$ID$(framenr)\n\
+ mantaMsg('--- Step: %s seconds ---' % (time.time() - start_time))\n\
+\n\
+def bake_fluid_data_$ID$(path_data, path_guiding, framenr, format_data, format_particles, format_guiding):\n\
+ if not withMPBake or isWindows:\n\
+ bake_fluid_process_data_$ID$(framenr, format_data, format_particles, format_guiding, path_data, path_guiding)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_fluid_process_data_$ID$, framenr=framenr, format_data=format_data, format_particles=format_particles, format_guiding=format_guiding, path_data=path_data, path_guiding=path_guiding, do_join=False)\n";
+
+const std::string fluid_bake_noise =
+ "\n\
+def bake_noise_process_$ID$(framenr, format_data, format_noise, path_data, path_noise):\n\
+ mantaMsg('Bake fluid noise')\n\
+ \n\
+ sn$ID$.frame = framenr\n\
+ sn$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
+ sn$ID$.timestep = dt0_s$ID$\n\
+ mantaMsg('sn$ID$.timeTotal: ' + str(sn$ID$.timeTotal))\n\
+ \n\
+ smoke_step_noise_$ID$(framenr)\n\
+ smoke_save_noise_$ID$(path_noise, framenr, format_noise)\n\
+\n\
+def bake_noise_$ID$(path_data, path_noise, framenr, format_data, format_noise):\n\
+ if not withMPBake or isWindows:\n\
+ bake_noise_process_$ID$(framenr, format_data, format_noise, path_data, path_noise)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_noise_process_$ID$, framenr=framenr, format_data=format_data, format_noise=format_noise, path_data=path_data, path_noise=path_noise)\n";
+
+const std::string fluid_bake_mesh =
+ "\n\
+def bake_mesh_process_$ID$(framenr, format_data, format_mesh, format_particles, path_data, path_mesh):\n\
+ mantaMsg('Bake fluid mesh')\n\
+ \n\
+ sm$ID$.frame = framenr\n\
+ sm$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
+ sm$ID$.timestep = dt0_s$ID$\n\
+ \n\
+ #if using_smoke_s$ID$:\n\
+ # TODO (sebbas): Future update could include smoke mesh (vortex sheets)\n\
+ if using_liquid_s$ID$:\n\
+ liquid_step_mesh_$ID$()\n\
+ liquid_save_mesh_$ID$(path_mesh, framenr, format_mesh)\n\
+ if using_speedvectors_s$ID$:\n\
+ liquid_save_meshvel_$ID$(path_mesh, framenr, format_data)\n\
+\n\
+def bake_mesh_$ID$(path_data, path_mesh, framenr, format_data, format_mesh, format_particles):\n\
+ if not withMPBake or isWindows:\n\
+ bake_mesh_process_$ID$(framenr, format_data, format_mesh, format_particles, path_data, path_mesh)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_mesh_process_$ID$, framenr=framenr, format_data=format_data, format_mesh=format_mesh, format_particles=format_particles, path_data=path_data, path_mesh=path_mesh)\n";
+
+const std::string fluid_bake_particles =
+ "\n\
+def bake_particles_process_$ID$(framenr, format_data, format_particles, path_data, path_particles):\n\
+ mantaMsg('Bake secondary particles')\n\
+ \n\
+ sp$ID$.frame = framenr\n\
+ sp$ID$.timeTotal = (framenr-1) * frameLength_s$ID$\n\
+ sp$ID$.timestep = dt0_s$ID$\n\
+ \n\
+ fluid_load_data_$ID$(path_data, framenr, format_data)\n\
+ #if using_smoke_s$ID$:\n\
+ # TODO (sebbas): Future update could include smoke particles (e.g. fire sparks)\n\
+ if using_liquid_s$ID$:\n\
+ liquid_load_data_$ID$(path_data, framenr, format_data)\n\
+ liquid_step_particles_$ID$()\n\
+ fluid_save_particles_$ID$(path_particles, framenr, format_particles)\n\
+ liquid_save_particles_$ID$(path_particles, framenr, format_particles)\n\
+\n\
+def bake_particles_$ID$(path_data, path_particles, framenr, format_data, format_particles):\n\
+ if not withMPBake or isWindows:\n\
+ bake_particles_process_$ID$(framenr, format_data, format_particles, path_data, path_particles)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_particles_process_$ID$, framenr=framenr, format_data=format_data, format_particles=format_particles, path_data=path_data, path_particles=path_particles)\n";
+
+const std::string fluid_bake_guiding =
+ "\n\
+def bake_guiding_process_$ID$(framenr, format_guiding, path_guiding):\n\
+ mantaMsg('Bake fluid guiding')\n\
+ \n\
+ if framenr>1:\n\
+ fluid_load_guiding_$ID$(path_guiding, framenr-1, format_guiding)\n\
+ \n\
+ x_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
+ y_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
+ z_guidevel_s$ID$.multConst(Real(toMantaUnitsFac_s$ID$))\n\
+ copyRealToVec3(sourceX=x_guidevel_s$ID$, sourceY=y_guidevel_s$ID$, sourceZ=z_guidevel_s$ID$, target=guidevelC_s$ID$)\n\
+ \n\
+ mantaMsg('Extrapolating guiding velocity')\n\
+ # ensure velocities inside of guiding object, slightly add guiding vels outside of object too\n\
+ extrapolateVec3Simple(vel=guidevelC_s$ID$, phi=phiGuideIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateVec3Simple(vel=guidevelC_s$ID$, phi=phiGuideIn_s$ID$, distance=4, inside=False)\n\
+ resampleVec3ToMac(source=guidevelC_s$ID$, target=guidevel_sg$ID$)\n\
+ \n\
+ fluid_save_guiding_$ID$(path_guiding, framenr, format_guiding)\n\
+\n\
+def bake_guiding_$ID$(path_guiding, framenr, format_guiding):\n\
+ if not withMPBake or isWindows:\n\
+ bake_guiding_process_$ID$(framenr, format_guiding, path_guiding)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=bake_guiding_process_$ID$, framenr=framenr, format_guiding=format_guiding, path_guiding=path_guiding)\n";
+
+//////////////////////////////////////////////////////////////////////
+// IMPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_file_import =
+ "\n\
+def fluid_file_import_s$ID$(dict, path, framenr, file_format):\n\
+ try:\n\
+ framenr = fluid_cache_get_framenr_formatted_$ID$(framenr)\n\
+ for name, object in dict.items():\n\
+ file = os.path.join(path, name + '_' + framenr + file_format)\n\
+ if os.path.isfile(file):\n\
+ object.load(file)\n\
+ else:\n\
+ mantaMsg('Could not load file ' + str(file))\n\
+ except:\n\
+ mantaMsg('exception found')\n\
+ #mantaMsg(str(e))\n\
+ pass # Just skip file load errors for now\n";
+
+const std::string fluid_load_particles =
+ "\n\
+def fluid_load_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid load particles, frame ' + str(framenr))\n\
+ fluid_file_import_s$ID$(dict=fluid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string fluid_load_data =
+ "\n\
+def fluid_load_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid load data, frame ' + str(framenr))\n\
+ fluid_file_import_s$ID$(dict=fluid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ \n\
+ # When adaptive domain bake is resumed we need correct values in xyz vel grids\n\
+ copyVec3ToReal(source=vel_s$ID$, targetX=x_vel_s$ID$, targetY=y_vel_s$ID$, targetZ=z_vel_s$ID$)\n";
+
+const std::string fluid_load_guiding =
+ "\n\
+def fluid_load_guiding_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid load guiding, frame ' + str(framenr))\n\
+ fluid_file_import_s$ID$(dict=fluid_guiding_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string fluid_load_vel =
+ "\n\
+def fluid_load_vel_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid load vel, frame ' + str(framenr))\n\
+ fluid_vel_dict = dict(vel=guidevel_sg$ID$)\n\
+ fluid_file_import_s$ID$(dict=fluid_vel_dict, path=path, framenr=framenr, file_format=file_format)\n";
+
+//////////////////////////////////////////////////////////////////////
+// EXPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_file_export =
+ "\n\
+def fluid_file_export_s$ID$(framenr, file_format, path, dict, mode_override=True, skip_subframes=True):\n\
+ if skip_subframes and ((timePerFrame_s$ID$ + dt0_s$ID$) < frameLength_s$ID$):\n\
+ return\n\
+ mantaMsg('Fluid file export, frame: ' + str(framenr))\n\
+ try:\n\
+ framenr = fluid_cache_get_framenr_formatted_$ID$(framenr)\n\
+ if not os.path.exists(path):\n\
+ os.makedirs(path)\n\
+ for name, object in dict.items():\n\
+ file = os.path.join(path, name + '_' + framenr + file_format)\n\
+ if not os.path.isfile(file) or mode_override: object.save(file)\n\
+ except Exception as e:\n\
+ mantaMsg(str(e))\n\
+ pass # Just skip file save errors for now\n";
+
+const std::string fluid_save_particles =
+ "\n\
+def fluid_save_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save particles, frame ' + str(framenr))\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=fluid_particles_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_particles_dict_s$ID$, do_join=False)\n";
+
+const std::string fluid_save_data =
+ "\n\
+def fluid_save_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid save data, frame ' + str(framenr))\n\
+ start_time = time.time()\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(framenr=framenr, file_format=file_format, path=path, dict=fluid_data_dict_s$ID$)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_data_dict_s$ID$, do_join=False)\n\
+ mantaMsg('--- Save: %s seconds ---' % (time.time() - start_time))\n";
+
+const std::string fluid_save_guiding =
+ "\n\
+def fluid_save_guiding_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Fluid save guiding, frame ' + str(framenr))\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=fluid_guiding_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=fluid_guiding_dict_s$ID$, do_join=False)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STANDALONE MODE
+//////////////////////////////////////////////////////////////////////
+
+const std::string fluid_standalone =
+ "\n\
+gui = None\n\
+if (GUI):\n\
+ gui=Gui()\n\
+ gui.show()\n\
+ gui.pause()\n\
+\n\
+cache_dir = '$CACHE_DIR$'\n\
+file_format_data = '.uni'\n\
+file_format_noise = '.uni'\n\
+file_format_particles = '.uni'\n\
+file_format_mesh = '.bobj.gz'\n\
+\n\
+# Start and stop for simulation\n\
+current_frame = $CURRENT_FRAME$\n\
+end_frame = $END_FRAME$\n\
+\n\
+# How many frame to load from cache\n\
+from_cache_cnt = 100\n\
+\n\
+loop_cnt = 0\n\
+while current_frame <= end_frame:\n\
+ \n\
+ # Load already simulated data from cache:\n\
+ if loop_cnt < from_cache_cnt:\n\
+ load(current_frame)\n\
+ \n\
+ # Otherwise simulate new data\n\
+ else:\n\
+ while(s$ID$.frame <= current_frame):\n\
+ if using_adaptTime_s$ID$:\n\
+ fluid_adapt_time_step_$ID$()\n\
+ step(current_frame)\n\
+ \n\
+ current_frame += 1\n\
+ loop_cnt += 1\n\
+ \n\
+ if gui:\n\
+ gui.pause()\n";
+
+//////////////////////////////////////////////////////////////////////
+// SCRIPT SECTION HEADERS
+//////////////////////////////////////////////////////////////////////
+
+const std::string header_libraries =
+ "\n\
+######################################################################\n\
+## LIBRARIES\n\
+######################################################################\n";
+
+const std::string header_main =
+ "\n\
+######################################################################\n\
+## MAIN\n\
+######################################################################\n";
+
+const std::string header_prepost =
+ "\n\
+######################################################################\n\
+## PRE/POST STEPS\n\
+######################################################################\n";
+
+const std::string header_steps =
+ "\n\
+######################################################################\n\
+## STEPS\n\
+######################################################################\n";
+
+const std::string header_import =
+ "\n\
+######################################################################\n\
+## IMPORT\n\
+######################################################################\n";
+
+const std::string header_grids =
+ "\n\
+######################################################################\n\
+## GRIDS\n\
+######################################################################\n";
+
+const std::string header_solvers =
+ "\n\
+######################################################################\n\
+## SOLVERS\n\
+######################################################################\n";
+
+const std::string header_variables =
+ "\n\
+######################################################################\n\
+## VARIABLES\n\
+######################################################################\n";
+
+const std::string header_time =
+ "\n\
+######################################################################\n\
+## ADAPTIVE TIME\n\
+######################################################################\n";
+
+const std::string header_gridinit =
+ "\n\
+######################################################################\n\
+## DOMAIN INIT\n\
+######################################################################\n";
diff --git a/intern/mantaflow/intern/strings/liquid_script.h b/intern/mantaflow/intern/strings/liquid_script.h
new file mode 100644
index 00000000000..0569dfc6810
--- /dev/null
+++ b/intern/mantaflow/intern/strings/liquid_script.h
@@ -0,0 +1,462 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ * Georg Kohl
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/intern/strings/liquid.h
+ * \ingroup mantaflow
+ */
+
+#include <string>
+
+//////////////////////////////////////////////////////////////////////
+// VARIABLES
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_variables =
+ "\n\
+mantaMsg('Liquid variables')\n\
+narrowBandWidth_s$ID$ = 3\n\
+combineBandWidth_s$ID$ = narrowBandWidth_s$ID$ - 1\n\
+adjustedNarrowBandWidth_s$ID$ = $PARTICLE_BAND_WIDTH$ # only used in adjustNumber to control band width\n\
+particleNumber_s$ID$ = $PARTICLE_NUMBER$\n\
+minParticles_s$ID$ = $PARTICLE_MINIMUM$\n\
+maxParticles_s$ID$ = $PARTICLE_MAXIMUM$\n\
+radiusFactor_s$ID$ = $PARTICLE_RADIUS$\n\
+using_mesh_s$ID$ = $USING_MESH$\n\
+using_final_mesh_s$ID$ = $USING_IMPROVED_MESH$\n\
+using_fractions_s$ID$ = $USING_FRACTIONS$\n\
+fracThreshold_s$ID$ = $FRACTIONS_THRESHOLD$\n\
+flipRatio_s$ID$ = $FLIP_RATIO$\n\
+concaveUpper_s$ID$ = $MESH_CONCAVE_UPPER$\n\
+concaveLower_s$ID$ = $MESH_CONCAVE_LOWER$\n\
+meshRadiusFactor_s$ID$ = $MESH_PARTICLE_RADIUS$\n\
+smoothenPos_s$ID$ = $MESH_SMOOTHEN_POS$\n\
+smoothenNeg_s$ID$ = $MESH_SMOOTHEN_NEG$\n\
+randomness_s$ID$ = $PARTICLE_RANDOMNESS$\n\
+surfaceTension_s$ID$ = $LIQUID_SURFACE_TENSION$\n";
+
+const std::string liquid_variables_particles =
+ "\n\
+tauMin_wc_sp$ID$ = $SNDPARTICLE_TAU_MIN_WC$\n\
+tauMax_wc_sp$ID$ = $SNDPARTICLE_TAU_MAX_WC$\n\
+tauMin_ta_sp$ID$ = $SNDPARTICLE_TAU_MIN_TA$\n\
+tauMax_ta_sp$ID$ = $SNDPARTICLE_TAU_MAX_TA$\n\
+tauMin_k_sp$ID$ = $SNDPARTICLE_TAU_MIN_K$\n\
+tauMax_k_sp$ID$ = $SNDPARTICLE_TAU_MAX_K$\n\
+k_wc_sp$ID$ = $SNDPARTICLE_K_WC$\n\
+k_ta_sp$ID$ = $SNDPARTICLE_K_TA$\n\
+k_b_sp$ID$ = $SNDPARTICLE_K_B$\n\
+k_d_sp$ID$ = $SNDPARTICLE_K_D$\n\
+lMin_sp$ID$ = $SNDPARTICLE_L_MIN$\n\
+lMax_sp$ID$ = $SNDPARTICLE_L_MAX$\n\
+c_s_sp$ID$ = 0.4 # classification constant for snd parts\n\
+c_b_sp$ID$ = 0.77 # classification constant for snd parts\n\
+pot_radius_sp$ID$ = $SNDPARTICLE_POTENTIAL_RADIUS$\n\
+update_radius_sp$ID$ = $SNDPARTICLE_UPDATE_RADIUS$\n\
+scaleFromManta_sp$ID$ = $FLUID_DOMAIN_SIZE$ / float(res_s$ID$) # resize factor for snd parts\n";
+
+//////////////////////////////////////////////////////////////////////
+// GRIDS & MESH & PARTICLESYSTEM
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_alloc =
+ "\n\
+mantaMsg('Liquid alloc')\n\
+phiParts_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+phi_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+phiTmp_s$ID$ = s$ID$.create(LevelsetGrid)\n\
+curvature_s$ID$ = s$ID$.create(RealGrid)\n\
+velOld_s$ID$ = s$ID$.create(MACGrid)\n\
+velParts_s$ID$ = s$ID$.create(MACGrid)\n\
+mapWeights_s$ID$ = s$ID$.create(MACGrid)\n\
+fractions_s$ID$ = None # allocated dynamically\n\
+\n\
+pp_s$ID$ = s$ID$.create(BasicParticleSystem)\n\
+pVel_pp$ID$ = pp_s$ID$.create(PdataVec3)\n\
+\n\
+# Acceleration data for particle nbs\n\
+pindex_s$ID$ = s$ID$.create(ParticleIndexSystem)\n\
+gpi_s$ID$ = s$ID$.create(IntGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+liquid_data_dict_s$ID$ = dict(phiParts=phiParts_s$ID$, phi=phi_s$ID$, phiTmp=phiTmp_s$ID$)\n\
+liquid_flip_dict_s$ID$ = dict(pp=pp_s$ID$, pVel=pVel_pp$ID$)\n";
+
+const std::string liquid_alloc_mesh =
+ "\n\
+mantaMsg('Liquid alloc mesh')\n\
+phiParts_sm$ID$ = sm$ID$.create(LevelsetGrid)\n\
+phi_sm$ID$ = sm$ID$.create(LevelsetGrid)\n\
+pp_sm$ID$ = sm$ID$.create(BasicParticleSystem)\n\
+flags_sm$ID$ = sm$ID$.create(FlagGrid)\n\
+mesh_sm$ID$ = sm$ID$.create(Mesh)\n\
+\n\
+if using_speedvectors_s$ID$:\n\
+ mVel_mesh$ID$ = mesh_sm$ID$.create(MdataVec3)\n\
+ vel_sm$ID$ = sm$ID$.create(MACGrid)\n\
+\n\
+# Acceleration data for particle nbs\n\
+pindex_sm$ID$ = sm$ID$.create(ParticleIndexSystem)\n\
+gpi_sm$ID$ = sm$ID$.create(IntGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+liquid_mesh_dict_s$ID$ = dict(lMesh=mesh_sm$ID$)\n\
+\n\
+if using_speedvectors_s$ID$:\n\
+ liquid_meshvel_dict_s$ID$ = dict(lVelMesh=mVel_mesh$ID$)\n";
+
+const std::string liquid_alloc_particles =
+ "\n\
+normal_sp$ID$ = sp$ID$.create(VecGrid)\n\
+neighborRatio_sp$ID$ = sp$ID$.create(RealGrid)\n\
+trappedAir_sp$ID$ = sp$ID$.create(RealGrid)\n\
+waveCrest_sp$ID$ = sp$ID$.create(RealGrid)\n\
+kineticEnergy_sp$ID$ = sp$ID$.create(RealGrid)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+liquid_particles_dict_s$ID$ = dict(trappedAir=trappedAir_sp$ID$, waveCrest=waveCrest_sp$ID$, kineticEnergy=kineticEnergy_sp$ID$)\n";
+
+const std::string liquid_init_phi =
+ "\n\
+# Prepare domain\n\
+phi_s$ID$.initFromFlags(flags_s$ID$)\n\
+phiIn_s$ID$.initFromFlags(flags_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STEP FUNCTIONS
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_adaptive_step =
+ "\n\
+def liquid_adaptive_step_$ID$(framenr):\n\
+ mantaMsg('Manta step, frame ' + str(framenr))\n\
+ s$ID$.frame = framenr\n\
+ \n\
+ fluid_pre_step_$ID$()\n\
+ \n\
+ flags_s$ID$.initDomain(boundaryWidth=1 if using_fractions_s$ID$ else 0, phiWalls=phiObs_s$ID$, outflow=boundConditions_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Initializing obstacle levelset')\n\
+ phiObsIn_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\
+ extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ phiObs_s$ID$.join(phiObsIn_s$ID$)\n\
+ \n\
+ # Using boundaryWidth=2 to not search beginning from walls (just a performance optimization)\n\
+ # Additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\
+ phiObs_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ \n\
+ mantaMsg('Initializing fluid levelset')\n\
+ extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ phi_s$ID$.join(phiIn_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ phi_s$ID$.subtract(phiObsIn_s$ID$)\n\
+ \n\
+ if using_outflow_s$ID$:\n\
+ phiOut_s$ID$.join(phiOutIn_s$ID$)\n\
+ \n\
+ if using_fractions_s$ID$:\n\
+ updateFractions(flags=flags_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$, boundaryWidth=boundaryWidth_s$ID$, fracThreshold=fracThreshold_s$ID$)\n\
+ setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, fractions=fractions_s$ID$, phiIn=phiIn_s$ID$)\n\
+ \n\
+ # add initial velocity: set invel as source grid to ensure const vels in inflow region, sampling makes use of this\n\
+ if using_invel_s$ID$:\n\
+ extrapolateVec3Simple(vel=invelC_s$ID$, phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ resampleVec3ToMac(source=invelC_s$ID$, target=invel_s$ID$)\n\
+ pVel_pp$ID$.setSource(invel_s$ID$, isMAC=True)\n\
+ \n\
+ sampleLevelsetWithParticles(phi=phiIn_s$ID$, flags=flags_s$ID$, parts=pp_s$ID$, discretization=particleNumber_s$ID$, randomness=randomness_s$ID$)\n\
+ flags_s$ID$.updateFromLevelset(phi_s$ID$)\n\
+ \n\
+ mantaMsg('Liquid step / s$ID$.frame: ' + str(s$ID$.frame))\n\
+ liquid_step_$ID$()\n\
+ \n\
+ s$ID$.step()\n\
+ \n\
+ fluid_post_step_$ID$()\n";
+
+const std::string liquid_step =
+ "\n\
+def liquid_step_$ID$():\n\
+ mantaMsg('Liquid step')\n\
+ \n\
+ mantaMsg('Advecting particles')\n\
+ pp_s$ID$.advectInGrid(flags=flags_s$ID$, vel=vel_s$ID$, integrationMode=IntRK4, deleteInObstacle=False, stopInObstacle=False)\n\
+ \n\
+ mantaMsg('Pushing particles out of obstacles')\n\
+ pushOutofObs(parts=pp_s$ID$, flags=flags_s$ID$, phiObs=phiObs_s$ID$)\n\
+ \n\
+ mantaMsg('Advecting phi')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=phi_s$ID$, order=1) # first order is usually enough\n\
+ mantaMsg('Advecting velocity')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=vel_s$ID$, order=2)\n\
+ \n\
+ phiTmp_s$ID$.copyFrom(phi_s$ID$) # save original phi for later use in mesh creation\n\
+ \n\
+ # create level set of particles\n\
+ gridParticleIndex(parts=pp_s$ID$, flags=flags_s$ID$, indexSys=pindex_s$ID$, index=gpi_s$ID$)\n\
+ unionParticleLevelset(parts=pp_s$ID$, indexSys=pindex_s$ID$, flags=flags_s$ID$, index=gpi_s$ID$, phi=phiParts_s$ID$, radiusFactor=radiusFactor_s$ID$)\n\
+ \n\
+ # combine level set of particles with grid level set\n\
+ phi_s$ID$.addConst(1.) # shrink slightly\n\
+ phi_s$ID$.join(phiParts_s$ID$)\n\
+ extrapolateLsSimple(phi=phi_s$ID$, distance=narrowBandWidth_s$ID$+2, inside=True)\n\
+ extrapolateLsSimple(phi=phi_s$ID$, distance=3)\n\
+ phi_s$ID$.setBoundNeumann(0) # make sure no particles are placed at outer boundary\n\
+ \n\
+ if doOpen_s$ID$ or using_outflow_s$ID$:\n\
+ resetOutflow(flags=flags_s$ID$, phi=phi_s$ID$, parts=pp_s$ID$, index=gpi_s$ID$, indexSys=pindex_s$ID$)\n\
+ flags_s$ID$.updateFromLevelset(phi_s$ID$)\n\
+ \n\
+ # combine particles velocities with advected grid velocities\n\
+ mapPartsToMAC(vel=velParts_s$ID$, flags=flags_s$ID$, velOld=velOld_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, weight=mapWeights_s$ID$)\n\
+ extrapolateMACFromWeight(vel=velParts_s$ID$, distance=2, weight=mapWeights_s$ID$)\n\
+ combineGridVel(vel=velParts_s$ID$, weight=mapWeights_s$ID$, combineVel=vel_s$ID$, phi=phi_s$ID$, narrowBand=combineBandWidth_s$ID$, thresh=0)\n\
+ velOld_s$ID$.copyFrom(vel_s$ID$)\n\
+ \n\
+ # forces & pressure solve\n\
+ addGravity(flags=flags_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$)\n\
+ \n\
+ mantaMsg('Adding external forces')\n\
+ addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Extrapolating object velocity')\n\
+ # ensure velocities inside of obs object, slightly add obvels outside of obs object\n\
+ extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=3, inside=False)\n\
+ resampleVec3ToMac(source=obvelC_s$ID$, target=obvel_s$ID$)\n\
+ \n\
+ extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=2, intoObs=True if using_fractions_s$ID$ else False)\n\
+ \n\
+ # vel diffusion / viscosity!\n\
+ if viscosity_s$ID$ > 0.:\n\
+ mantaMsg('Viscosity')\n\
+ # diffusion param for solve = const * dt / dx^2\n\
+ alphaV = viscosity_s$ID$ * s$ID$.timestep * float(res_s$ID$*res_s$ID$)\n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
+ cgSolveDiffusion(flags_s$ID$, vel_s$ID$, alphaV)\n\
+ \n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
+ \n\
+ mantaMsg('Calculating curvature')\n\
+ getLaplacian(laplacian=curvature_s$ID$, grid=phi_s$ID$)\n\
+ \n\
+ if using_guiding_s$ID$:\n\
+ mantaMsg('Guiding and pressure')\n\
+ PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, zeroPressureFixing=not doOpen_s$ID$)\n\
+ else:\n\
+ mantaMsg('Pressure')\n\
+ solvePressure(flags=flags_s$ID$, vel=vel_s$ID$, pressure=pressure_s$ID$, phi=phi_s$ID$, curv=curvature_s$ID$, surfTens=surfaceTension_s$ID$, fractions=fractions_s$ID$, obvel=obvel_s$ID$ if using_fractions_s$ID$ else None)\n\
+ \n\
+ extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=4, intoObs=True if using_fractions_s$ID$ else False)\n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=None if using_fractions_s$ID$ else obvel_s$ID$, phiObs=phiObs_s$ID$, fractions=fractions_s$ID$)\n\
+ \n\
+ if not using_fractions_s$ID$:\n\
+ extrapolateMACSimple(flags=flags_s$ID$, vel=vel_s$ID$, distance=(int(maxVel_s$ID$*1.25)))\n\
+ \n\
+ # set source grids for resampling, used in adjustNumber!\n\
+ pVel_pp$ID$.setSource(vel_s$ID$, isMAC=True)\n\
+ adjustNumber(parts=pp_s$ID$, vel=vel_s$ID$, flags=flags_s$ID$, minParticles=minParticles_s$ID$, maxParticles=maxParticles_s$ID$, phi=phi_s$ID$, exclude=phiObs_s$ID$, radiusFactor=radiusFactor_s$ID$, narrowBand=adjustedNarrowBandWidth_s$ID$)\n\
+ flipVelocityUpdate(vel=vel_s$ID$, velOld=velOld_s$ID$, flags=flags_s$ID$, parts=pp_s$ID$, partVel=pVel_pp$ID$, flipRatio=flipRatio_s$ID$)\n";
+
+const std::string liquid_step_mesh =
+ "\n\
+def liquid_step_mesh_$ID$():\n\
+ mantaMsg('Liquid step mesh')\n\
+ \n\
+ interpolateGrid(target=phi_sm$ID$, source=phiTmp_s$ID$)\n\
+ \n\
+ # create surface\n\
+ pp_sm$ID$.readParticles(pp_s$ID$)\n\
+ gridParticleIndex(parts=pp_sm$ID$, flags=flags_sm$ID$, indexSys=pindex_sm$ID$, index=gpi_sm$ID$)\n\
+ \n\
+ if using_final_mesh_s$ID$:\n\
+ mantaMsg('Liquid using improved particle levelset')\n\
+ improvedParticleLevelset(pp_sm$ID$, pindex_sm$ID$, flags_sm$ID$, gpi_sm$ID$, phiParts_sm$ID$, meshRadiusFactor_s$ID$, smoothenPos_s$ID$, smoothenNeg_s$ID$, concaveLower_s$ID$, concaveUpper_s$ID$)\n\
+ else:\n\
+ mantaMsg('Liquid using union particle levelset')\n\
+ unionParticleLevelset(pp_sm$ID$, pindex_sm$ID$, flags_sm$ID$, gpi_sm$ID$, phiParts_sm$ID$, meshRadiusFactor_s$ID$)\n\
+ \n\
+ phi_sm$ID$.addConst(1.) # shrink slightly\n\
+ phi_sm$ID$.join(phiParts_sm$ID$)\n\
+ extrapolateLsSimple(phi=phi_sm$ID$, distance=narrowBandWidth_s$ID$+2, inside=True)\n\
+ extrapolateLsSimple(phi=phi_sm$ID$, distance=3)\n\
+ phi_sm$ID$.setBoundNeumann(0) # make sure no particles are placed at outer boundary\n\
+ \n\
+ # Vert vel vector needs to pull data from vel grid with correct dim\n\
+ if using_speedvectors_s$ID$:\n\
+ interpolateMACGrid(target=vel_sm$ID$, source=vel_s$ID$)\n\
+ mVel_mesh$ID$.setSource(vel_sm$ID$, isMAC=True)\n\
+ \n\
+ phi_sm$ID$.setBound(0.5,int(((upres_sm$ID$)*2)-2) )\n\
+ phi_sm$ID$.createMesh(mesh_sm$ID$)\n";
+
+const std::string liquid_step_particles =
+ "\n\
+def liquid_step_particles_$ID$():\n\
+ mantaMsg('Secondary particles step')\n\
+ \n\
+ # no upres: just use the loaded grids\n\
+ if upres_sp$ID$ <= 1:\n\
+ flags_sp$ID$.copyFrom(flags_s$ID$)\n\
+ vel_sp$ID$.copyFrom(vel_s$ID$)\n\
+ phiObs_sp$ID$.copyFrom(phiObs_s$ID$)\n\
+ phi_sp$ID$.copyFrom(phi_s$ID$)\n\
+ \n\
+ # with upres: recreate grids\n\
+ else:\n\
+ # create highres grids by interpolation\n\
+ interpolateMACGrid(target=vel_sp$ID$, source=vel_s$ID$)\n\
+ interpolateGrid(target=phi_sp$ID$, source=phi_s$ID$)\n\
+ flags_sp$ID$.initDomain(boundaryWidth=boundaryWidth_s$ID$, phiWalls=phiObs_sp$ID$, outflow=boundConditions_s$ID$)\n\
+ flags_sp$ID$.updateFromLevelset(levelset=phi_sp$ID$)\n\
+ \n\
+ # actual secondary simulation\n\
+ #extrapolateLsSimple(phi=phi_sp$ID$, distance=radius+1, inside=True)\n\
+ flipComputeSecondaryParticlePotentials(potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, normal=normal_sp$ID$, phi=phi_sp$ID$, radius=pot_radius_sp$ID$, tauMinTA=tauMin_ta_sp$ID$, tauMaxTA=tauMax_ta_sp$ID$, tauMinWC=tauMin_wc_sp$ID$, tauMaxWC=tauMax_wc_sp$ID$, tauMinKE=tauMin_k_sp$ID$, tauMaxKE=tauMax_k_sp$ID$, scaleFromManta=scaleFromManta_sp$ID$)\n\
+ flipSampleSecondaryParticles(mode='single', flags=flags_sp$ID$, v=vel_sp$ID$, pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, lMin=lMin_sp$ID$, lMax=lMax_sp$ID$, potTA=trappedAir_sp$ID$, potWC=waveCrest_sp$ID$, potKE=kineticEnergy_sp$ID$, neighborRatio=neighborRatio_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, k_ta=k_ta_sp$ID$, k_wc=k_wc_sp$ID$, dt=s$ID$.frameLength)\n\
+ flipUpdateSecondaryParticles(mode='linear', pts_sec=ppSnd_sp$ID$, v_sec=pVelSnd_pp$ID$, l_sec=pLifeSnd_pp$ID$, f_sec=pForceSnd_pp$ID$, flags=flags_sp$ID$, v=vel_sp$ID$, neighborRatio=neighborRatio_sp$ID$, radius=update_radius_sp$ID$, gravity=gravity_s$ID$, k_b=k_b_sp$ID$, k_d=k_d_sp$ID$, c_s=c_s_sp$ID$, c_b=c_b_sp$ID$, dt=s$ID$.frameLength)\n\
+ if $SNDPARTICLE_BOUNDARY_PUSHOUT$:\n\
+ pushOutofObs(parts = ppSnd_sp$ID$, flags = flags_sp$ID$, phiObs = phiObs_sp$ID$, shift = 1.0)\n\
+ flipDeleteParticlesInObstacle(pts=ppSnd_sp$ID$, flags=flags_sp$ID$)\n\
+ #debugGridInfo(flags = flags_sp$ID$, grid = trappedAir_sp$ID$, name = 'Trapped Air')\n\
+ #debugGridInfo(flags = flags_sp$ID$, grid = waveCrest_sp$ID$, name = 'Wave Crest')\n\
+ #debugGridInfo(flags = flags_sp$ID$, grid = kineticEnergy_sp$ID$, name = 'Kinetic Energy')\n";
+
+//////////////////////////////////////////////////////////////////////
+// IMPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_load_data =
+ "\n\
+def liquid_load_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load data')\n\
+ fluid_file_import_s$ID$(dict=liquid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_load_flip =
+ "\n\
+def liquid_load_flip_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load flip')\n\
+ fluid_file_import_s$ID$(dict=liquid_flip_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_load_mesh =
+ "\n\
+def liquid_load_mesh_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load mesh')\n\
+ fluid_file_import_s$ID$(dict=liquid_mesh_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_load_meshvel =
+ "\n\
+def liquid_load_meshvel_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load meshvel')\n\
+ fluid_file_import_s$ID$(dict=liquid_meshvel_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string liquid_load_particles =
+ "\n\
+def liquid_load_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid load particles')\n\
+ fluid_file_import_s$ID$(dict=liquid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+//////////////////////////////////////////////////////////////////////
+// EXPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_save_data =
+ "\n\
+def liquid_save_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save data')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_data_dict_s$ID$, do_join=False)\n";
+
+const std::string liquid_save_flip =
+ "\n\
+def liquid_save_flip_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save flip')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_flip_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_flip_dict_s$ID$, do_join=False)\n";
+
+const std::string liquid_save_mesh =
+ "\n\
+def liquid_save_mesh_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save mesh')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_mesh_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_mesh_dict_s$ID$, do_join=False)\n";
+
+const std::string liquid_save_meshvel =
+ "\n\
+def liquid_save_meshvel_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save mesh vel')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_meshvel_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_meshvel_dict_s$ID$, do_join=False)\n";
+
+const std::string liquid_save_particles =
+ "\n\
+def liquid_save_particles_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Liquid save particles')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=liquid_particles_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=liquid_particles_dict_s$ID$, do_join=False)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STANDALONE MODE
+//////////////////////////////////////////////////////////////////////
+
+const std::string liquid_standalone =
+ "\n\
+# Helper function to call cache load functions\n\
+def load(frame):\n\
+ fluid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\
+ liquid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\
+ liquid_load_flip_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_particles)\n\
+ if using_sndparts_s$ID$:\n\
+ fluid_load_particles_$ID$(os.path.join(cache_dir, 'particles'), frame, file_format_particles)\n\
+ liquid_load_particles_$ID$(os.path.join(cache_dir, 'particles'), frame, file_format_particles)\n\
+ if using_mesh_s$ID$:\n\
+ liquid_load_mesh_$ID$(os.path.join(cache_dir, 'mesh'), frame, file_format_mesh)\n\
+ if using_guiding_s$ID$:\n\
+ fluid_load_guiding_$ID$(os.path.join(cache_dir, 'guiding'), frame, file_format_data)\n\
+\n\
+# Helper function to call step functions\n\
+def step(frame):\n\
+ liquid_adaptive_step_$ID$(frame)\n\
+ if using_mesh_s$ID$:\n\
+ liquid_step_mesh_$ID$()\n\
+ if using_sndparts_s$ID$:\n\
+ liquid_step_particles_$ID$()\n";
diff --git a/intern/mantaflow/intern/strings/smoke_script.h b/intern/mantaflow/intern/strings/smoke_script.h
new file mode 100644
index 00000000000..ef300fc5c17
--- /dev/null
+++ b/intern/mantaflow/intern/strings/smoke_script.h
@@ -0,0 +1,581 @@
+/*
+ * ***** 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
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sebastian Barschkis (sebbas)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file mantaflow/intern/strings/smoke.h
+ * \ingroup mantaflow
+ */
+
+#include <string>
+
+//////////////////////////////////////////////////////////////////////
+// VARIABLES
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_variables =
+ "\n\
+mantaMsg('Smoke variables low')\n\
+preconditioner_s$ID$ = PcMGDynamic\n\
+using_colors_s$ID$ = $USING_COLORS$\n\
+using_heat_s$ID$ = $USING_HEAT$\n\
+using_fire_s$ID$ = $USING_FIRE$\n\
+using_noise_s$ID$ = $USING_NOISE$\n\
+vorticity_s$ID$ = $VORTICITY$\n\
+buoyancy_dens_s$ID$ = float($BUOYANCY_ALPHA$) / float($FLUID_DOMAIN_SIZE$)\n\
+buoyancy_heat_s$ID$ = float($BUOYANCY_BETA$) / float($FLUID_DOMAIN_SIZE$)\n\
+dissolveSpeed_s$ID$ = $DISSOLVE_SPEED$\n\
+using_logdissolve_s$ID$ = $USING_LOG_DISSOLVE$\n\
+using_dissolve_s$ID$ = $USING_DISSOLVE$\n\
+flameVorticity_s$ID$ = $FLAME_VORTICITY$\n\
+burningRate_s$ID$ = $BURNING_RATE$\n\
+flameSmoke_s$ID$ = $FLAME_SMOKE$\n\
+ignitionTemp_s$ID$ = $IGNITION_TEMP$\n\
+maxTemp_s$ID$ = $MAX_TEMP$\n\
+flameSmokeColor_s$ID$ = vec3($FLAME_SMOKE_COLOR_X$,$FLAME_SMOKE_COLOR_Y$,$FLAME_SMOKE_COLOR_Z$)\n";
+
+const std::string smoke_variables_noise =
+ "\n\
+mantaMsg('Smoke variables noise')\n\
+wltStrength_s$ID$ = $WLT_STR$\n\
+uvs_s$ID$ = 2\n\
+uvs_offset_s$ID$ = vec3($MIN_RESX$, $MIN_RESY$, $MIN_RESZ$)\n\
+octaves_s$ID$ = int(math.log(upres_sn$ID$) / math.log(2.0) + 0.5) if (upres_sn$ID$ > 1) else 1\n";
+
+const std::string smoke_wavelet_noise =
+ "\n\
+# wavelet noise params\n\
+wltnoise_sn$ID$.posScale = vec3(int($BASE_RESX$), int($BASE_RESY$), int($BASE_RESZ$)) * (1. / $NOISE_POSSCALE$)\n\
+wltnoise_sn$ID$.timeAnim = $NOISE_TIMEANIM$\n";
+
+const std::string smoke_with_heat =
+ "\n\
+using_heat_s$ID$ = True\n";
+
+const std::string smoke_with_colors =
+ "\n\
+using_colors_s$ID$ = True\n";
+
+const std::string smoke_with_fire =
+ "\n\
+using_fire_s$ID$ = True\n";
+
+//////////////////////////////////////////////////////////////////////
+// GRIDS
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_alloc =
+ "\n\
+mantaMsg('Smoke alloc')\n\
+shadow_s$ID$ = s$ID$.create(RealGrid)\n\
+emissionIn_s$ID$ = s$ID$.create(RealGrid)\n\
+density_s$ID$ = s$ID$.create(RealGrid)\n\
+densityIn_s$ID$ = s$ID$.create(RealGrid)\n\
+heat_s$ID$ = None # allocated dynamically\n\
+heatIn_s$ID$ = None\n\
+flame_s$ID$ = None\n\
+fuel_s$ID$ = None\n\
+react_s$ID$ = None\n\
+fuelIn_s$ID$ = None\n\
+reactIn_s$ID$ = None\n\
+color_r_s$ID$ = None\n\
+color_g_s$ID$ = None\n\
+color_b_s$ID$ = None\n\
+color_r_in_s$ID$ = None\n\
+color_g_in_s$ID$ = None\n\
+color_b_in_s$ID$ = None\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+smoke_data_dict_s$ID$ = dict(density=density_s$ID$, shadow=shadow_s$ID$, densityIn=densityIn_s$ID$, emissionIn=emissionIn_s$ID$)\n";
+
+const std::string smoke_alloc_noise =
+ "\n\
+mantaMsg('Smoke alloc noise')\n\
+vel_sn$ID$ = sn$ID$.create(MACGrid)\n\
+density_sn$ID$ = sn$ID$.create(RealGrid)\n\
+phiIn_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\
+phiOut_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\
+phiObs_sn$ID$ = sn$ID$.create(LevelsetGrid)\n\
+flags_sn$ID$ = sn$ID$.create(FlagGrid)\n\
+tmpIn_sn$ID$ = sn$ID$.create(RealGrid)\n\
+emissionIn_sn$ID$ = sn$ID$.create(RealGrid)\n\
+energy_s$ID$ = s$ID$.create(RealGrid)\n\
+tempFlag_s$ID$ = s$ID$.create(FlagGrid)\n\
+texture_u_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_v_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_w_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_u2_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_v2_s$ID$ = s$ID$.create(RealGrid)\n\
+texture_w2_s$ID$ = s$ID$.create(RealGrid)\n\
+flame_sn$ID$ = None\n\
+fuel_sn$ID$ = None\n\
+react_sn$ID$ = None\n\
+color_r_sn$ID$ = None\n\
+color_g_sn$ID$ = None\n\
+color_b_sn$ID$ = None\n\
+wltnoise_sn$ID$ = sn$ID$.create(NoiseField, fixedSeed=265, loadFromFile=True)\n\
+\n\
+mantaMsg('Initializing UV Grids')\n\
+uvGrid0_s$ID$ = s$ID$.create(VecGrid)\n\
+uvGrid1_s$ID$ = s$ID$.create(VecGrid)\n\
+resetUvGrid(target=uvGrid0_s$ID$, offset=uvs_offset_s$ID$)\n\
+resetUvGrid(target=uvGrid1_s$ID$, offset=uvs_offset_s$ID$)\n\
+\n\
+# Sync UV and texture grids\n\
+copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\
+copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n\
+\n\
+# Keep track of important objects in dict to load them later on\n\
+smoke_noise_dict_s$ID$ = dict(density_noise=density_sn$ID$, uv0_noise=uvGrid0_s$ID$, uv1_noise=uvGrid1_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// ADDITIONAL GRIDS
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_alloc_colors =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'color_r_s$ID$' in globals(): del color_r_s$ID$\n\
+if 'color_g_s$ID$' in globals(): del color_g_s$ID$\n\
+if 'color_b_s$ID$' in globals(): del color_b_s$ID$\n\
+\n\
+mantaMsg('Allocating colors')\n\
+color_r_s$ID$ = s$ID$.create(RealGrid)\n\
+color_g_s$ID$ = s$ID$.create(RealGrid)\n\
+color_b_s$ID$ = s$ID$.create(RealGrid)\n\
+color_r_in_s$ID$ = s$ID$.create(RealGrid)\n\
+color_g_in_s$ID$ = s$ID$.create(RealGrid)\n\
+color_b_in_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_data_dict_s$ID$' in globals():\n\
+ smoke_data_dict_s$ID$.update(color_r=color_r_s$ID$, color_g=color_g_s$ID$, color_b=color_b_s$ID$)\n\
+ smoke_data_dict_s$ID$.update(color_r_in=color_r_in_s$ID$, color_g_in=color_g_in_s$ID$, color_b_in=color_b_in_s$ID$)\n";
+
+const std::string smoke_alloc_colors_noise =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'color_r_sn$ID$' in globals(): del color_r_sn$ID$\n\
+if 'color_g_sn$ID$' in globals(): del color_g_sn$ID$\n\
+if 'color_b_sn$ID$' in globals(): del color_b_sn$ID$\n\
+\n\
+mantaMsg('Allocating colors noise')\n\
+color_r_sn$ID$ = sn$ID$.create(RealGrid)\n\
+color_g_sn$ID$ = sn$ID$.create(RealGrid)\n\
+color_b_sn$ID$ = sn$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_noise_dict_s$ID$' in globals():\n\
+ smoke_noise_dict_s$ID$.update(color_r_noise=color_r_sn$ID$, color_g_noise=color_g_sn$ID$, color_b_noise=color_b_sn$ID$)\n";
+
+const std::string smoke_init_colors =
+ "\n\
+mantaMsg('Initializing colors')\n\
+color_r_s$ID$.copyFrom(density_s$ID$) \n\
+color_r_s$ID$.multConst($COLOR_R$) \n\
+color_g_s$ID$.copyFrom(density_s$ID$) \n\
+color_g_s$ID$.multConst($COLOR_G$) \n\
+color_b_s$ID$.copyFrom(density_s$ID$) \n\
+color_b_s$ID$.multConst($COLOR_B$)\n";
+
+const std::string smoke_init_colors_noise =
+ "\n\
+mantaMsg('Initializing colors noise')\n\
+color_r_sn$ID$.copyFrom(density_sn$ID$) \n\
+color_r_sn$ID$.multConst($COLOR_R$) \n\
+color_g_sn$ID$.copyFrom(density_sn$ID$) \n\
+color_g_sn$ID$.multConst($COLOR_G$) \n\
+color_b_sn$ID$.copyFrom(density_sn$ID$) \n\
+color_b_sn$ID$.multConst($COLOR_B$)\n";
+
+const std::string smoke_alloc_heat =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'heat_s$ID$' in globals(): del heat_s$ID$\n\
+if 'heatIn_s$ID$' in globals(): del heatIn_s$ID$\n\
+\n\
+mantaMsg('Allocating heat')\n\
+heat_s$ID$ = s$ID$.create(RealGrid)\n\
+heatIn_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_data_dict_s$ID$' in globals():\n\
+ smoke_data_dict_s$ID$.update(heat=heat_s$ID$, heatIn=heatIn_s$ID$)\n";
+
+const std::string smoke_alloc_fire =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'flame_s$ID$' in globals(): del flame_s$ID$\n\
+if 'fuel_s$ID$' in globals(): del fuel_s$ID$\n\
+if 'react_s$ID$' in globals(): del react_s$ID$\n\
+if 'fuelIn_s$ID$' in globals(): del fuelIn_s$ID$\n\
+if 'reactIn_s$ID$' in globals(): del reactIn_s$ID$\n\
+\n\
+mantaMsg('Allocating fire')\n\
+flame_s$ID$ = s$ID$.create(RealGrid)\n\
+fuel_s$ID$ = s$ID$.create(RealGrid)\n\
+react_s$ID$ = s$ID$.create(RealGrid)\n\
+fuelIn_s$ID$ = s$ID$.create(RealGrid)\n\
+reactIn_s$ID$ = s$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_data_dict_s$ID$' in globals():\n\
+ smoke_data_dict_s$ID$.update(flame=flame_s$ID$, fuel=fuel_s$ID$, react=react_s$ID$)\n\
+ smoke_data_dict_s$ID$.update(fuelIn=fuelIn_s$ID$, reactIn=reactIn_s$ID$)\n";
+
+const std::string smoke_alloc_fire_noise =
+ "\n\
+# Sanity check, clear grids first\n\
+if 'flame_sn$ID$' in globals(): del flame_sn$ID$\n\
+if 'fuel_sn$ID$' in globals(): del fuel_sn$ID$\n\
+if 'react_sn$ID$' in globals(): del react_sn$ID$\n\
+\n\
+mantaMsg('Allocating fire noise')\n\
+flame_sn$ID$ = sn$ID$.create(RealGrid)\n\
+fuel_sn$ID$ = sn$ID$.create(RealGrid)\n\
+react_sn$ID$ = sn$ID$.create(RealGrid)\n\
+\n\
+# Add objects to dict to load them later on\n\
+if 'smoke_noise_dict_s$ID$' in globals():\n\
+ smoke_noise_dict_s$ID$.update(flame_noise=flame_sn$ID$, fuel_noise=fuel_sn$ID$, react_noise=react_sn$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STEP FUNCTIONS
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_adaptive_step =
+ "\n\
+def smoke_adaptive_step_$ID$(framenr):\n\
+ mantaMsg('Manta step, frame ' + str(framenr))\n\
+ s$ID$.frame = framenr\n\
+ \n\
+ fluid_pre_step_$ID$()\n\
+ \n\
+ flags_s$ID$.initDomain(boundaryWidth=0, phiWalls=phiObs_s$ID$, outflow=boundConditions_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Initializing obstacle levelset')\n\
+ phiObsIn_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\
+ extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ phiObs_s$ID$.join(phiObsIn_s$ID$)\n\
+ \n\
+ # Using boundaryWidth=2 to not search beginning from walls (just a performance optimization)\n\
+ # Additional sanity check: fill holes in phiObs which can result after joining with phiObsIn\n\
+ phiObs_s$ID$.fillHoles(maxDepth=int(res_s$ID$), boundaryWidth=2)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiObs_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ \n\
+ mantaMsg('Initializing fluid levelset')\n\
+ extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateLsSimple(phi=phiIn_s$ID$, distance=int(res_s$ID$/2), inside=False)\n\
+ \n\
+ if using_outflow_s$ID$:\n\
+ phiOut_s$ID$.join(phiOutIn_s$ID$)\n\
+ \n\
+ setObstacleFlags(flags=flags_s$ID$, phiObs=phiObs_s$ID$, phiOut=phiOut_s$ID$, phiIn=phiIn_s$ID$)\n\
+ flags_s$ID$.fillGrid()\n\
+ \n\
+ if timePerFrame_s$ID$ == 0: # Only apply inflow once per frame\n\
+ mantaMsg('Smoke inflow at frame: ' + str(framenr))\n\
+ applyEmission(flags=flags_s$ID$, target=density_s$ID$, source=densityIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ if using_heat_s$ID$:\n\
+ applyEmission(flags=flags_s$ID$, target=heat_s$ID$, source=heatIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ if using_colors_s$ID$:\n\
+ applyEmission(flags=flags_s$ID$, target=color_r_s$ID$, source=color_r_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ applyEmission(flags=flags_s$ID$, target=color_g_s$ID$, source=color_g_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ applyEmission(flags=flags_s$ID$, target=color_b_s$ID$, source=color_b_in_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ if using_fire_s$ID$:\n\
+ applyEmission(flags=flags_s$ID$, target=fuel_s$ID$, source=fuelIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ applyEmission(flags=flags_s$ID$, target=react_s$ID$, source=reactIn_s$ID$, emissionTexture=emissionIn_s$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ mantaMsg('Smoke step / s$ID$.frame: ' + str(s$ID$.frame))\n\
+ if using_fire_s$ID$:\n\
+ process_burn_$ID$()\n\
+ smoke_step_$ID$()\n\
+ if using_fire_s$ID$:\n\
+ update_flame_$ID$()\n\
+ \n\
+ s$ID$.step()\n\
+ \n\
+ fluid_post_step_$ID$()\n";
+
+const std::string smoke_step =
+ "\n\
+def smoke_step_$ID$():\n\
+ mantaMsg('Smoke step low')\n\
+ \n\
+ if using_dissolve_s$ID$:\n\
+ mantaMsg('Dissolving smoke')\n\
+ dissolveSmoke(flags=flags_s$ID$, density=density_s$ID$, heat=heat_s$ID$, red=color_r_s$ID$, green=color_g_s$ID$, blue=color_b_s$ID$, speed=dissolveSpeed_s$ID$, logFalloff=using_logdissolve_s$ID$)\n\
+ \n\
+ mantaMsg('Advecting density')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=density_s$ID$, order=2)\n\
+ \n\
+ if using_heat_s$ID$:\n\
+ mantaMsg('Advecting heat')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=heat_s$ID$, order=2)\n\
+ \n\
+ if using_fire_s$ID$:\n\
+ mantaMsg('Advecting fire')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=fuel_s$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=react_s$ID$, order=2)\n\
+ \n\
+ if using_colors_s$ID$:\n\
+ mantaMsg('Advecting colors')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_r_s$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_g_s$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=color_b_s$ID$, order=2)\n\
+ \n\
+ mantaMsg('Advecting velocity')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=vel_s$ID$, order=2)\n\
+ \n\
+ if doOpen_s$ID$ or using_outflow_s$ID$:\n\
+ resetOutflow(flags=flags_s$ID$, real=density_s$ID$)\n\
+ \n\
+ mantaMsg('Vorticity')\n\
+ if using_fire_s$ID$:\n\
+ flame_s$ID$.copyFrom(fuel_s$ID$) # temporarily misuse flame grid as vorticity storage\n\
+ flame_s$ID$.multConst(flameVorticity_s$ID$)\n\
+ vorticityConfinement(vel=vel_s$ID$, flags=flags_s$ID$, strengthGlobal=vorticity_s$ID$, strengthCell=flame_s$ID$ if using_fire_s$ID$ else None)\n\
+ \n\
+ if using_heat_s$ID$:\n\
+ mantaMsg('Adding heat buoyancy')\n\
+ addBuoyancy(flags=flags_s$ID$, density=heat_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_heat_s$ID$)\n\
+ mantaMsg('Adding buoyancy')\n\
+ addBuoyancy(flags=flags_s$ID$, density=density_s$ID$, vel=vel_s$ID$, gravity=gravity_s$ID$, coefficient=buoyancy_dens_s$ID$)\n\
+ \n\
+ mantaMsg('Adding forces')\n\
+ addForceField(flags=flags_s$ID$, vel=vel_s$ID$, force=forces_s$ID$)\n\
+ \n\
+ if using_obstacle_s$ID$:\n\
+ mantaMsg('Extrapolating object velocity')\n\
+ # ensure velocities inside of obs object, slightly add obvels outside of obs object\n\
+ extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=int(res_s$ID$/2), inside=True)\n\
+ extrapolateVec3Simple(vel=obvelC_s$ID$, phi=phiObsIn_s$ID$, distance=3, inside=False)\n\
+ resampleVec3ToMac(source=obvelC_s$ID$, target=obvel_s$ID$)\n\
+ \n\
+ # add initial velocity\n\
+ if using_invel_s$ID$:\n\
+ resampleVec3ToMac(source=invelC_s$ID$, target=invel_s$ID$)\n\
+ setInitialVelocity(flags=flags_s$ID$, vel=vel_s$ID$, invel=invel_s$ID$)\n\
+ \n\
+ mantaMsg('Walls')\n\
+ setWallBcs(flags=flags_s$ID$, vel=vel_s$ID$, obvel=obvel_s$ID$ if using_obstacle_s$ID$ else None)\n\
+ \n\
+ if using_guiding_s$ID$:\n\
+ mantaMsg('Guiding and pressure')\n\
+ PD_fluid_guiding(vel=vel_s$ID$, velT=velT_s$ID$, flags=flags_s$ID$, weight=weightGuide_s$ID$, blurRadius=beta_sg$ID$, pressure=pressure_s$ID$, tau=tau_sg$ID$, sigma=sigma_sg$ID$, theta=theta_sg$ID$, preconditioner=preconditioner_s$ID$, zeroPressureFixing=not doOpen_s$ID$)\n\
+ else:\n\
+ mantaMsg('Pressure')\n\
+ solvePressure(flags=flags_s$ID$, vel=vel_s$ID$, pressure=pressure_s$ID$, preconditioner=preconditioner_s$ID$, zeroPressureFixing=not doOpen_s$ID$) # closed domains require pressure fixing\n\
+\n\
+def process_burn_$ID$():\n\
+ mantaMsg('Process burn')\n\
+ processBurn(fuel=fuel_s$ID$, density=density_s$ID$, react=react_s$ID$, red=color_r_s$ID$ if using_colors_s$ID$ else None, green=color_g_s$ID$ if using_colors_s$ID$ else None, blue=color_b_s$ID$ if using_colors_s$ID$ else None, heat=heat_s$ID$ if using_heat_s$ID$ else None, burningRate=burningRate_s$ID$, flameSmoke=flameSmoke_s$ID$, ignitionTemp=ignitionTemp_s$ID$, maxTemp=maxTemp_s$ID$, flameSmokeColor=flameSmokeColor_s$ID$)\n\
+\n\
+def update_flame_$ID$():\n\
+ mantaMsg('Update flame')\n\
+ updateFlame(react=react_s$ID$, flame=flame_s$ID$)\n";
+
+const std::string smoke_step_noise =
+ "\n\
+def smoke_step_noise_$ID$(framenr):\n\
+ mantaMsg('Manta step noise, frame ' + str(framenr))\n\
+ sn$ID$.frame = framenr\n\
+ \n\
+ copyRealToVec3(sourceX=texture_u_s$ID$, sourceY=texture_v_s$ID$, sourceZ=texture_w_s$ID$, target=uvGrid0_s$ID$)\n\
+ copyRealToVec3(sourceX=texture_u2_s$ID$, sourceY=texture_v2_s$ID$, sourceZ=texture_w2_s$ID$, target=uvGrid1_s$ID$)\n\
+ \n\
+ flags_sn$ID$.initDomain(boundaryWidth=0, phiWalls=phiObs_sn$ID$, outflow=boundConditions_s$ID$)\n\
+ \n\
+ mantaMsg('Interpolating grids')\n\
+ # Join big obstacle levelset after initDomain() call as it overwrites everything in phiObs\n\
+ if using_obstacle_s$ID$:\n\
+ interpolateGrid(target=phiIn_sn$ID$, source=phiObsIn_s$ID$) # mis-use phiIn_sn\n\
+ phiObs_sn$ID$.join(phiIn_sn$ID$)\n\
+ if using_outflow_s$ID$:\n\
+ interpolateGrid(target=phiOut_sn$ID$, source=phiOut_s$ID$)\n\
+ interpolateGrid(target=phiIn_sn$ID$, source=phiIn_s$ID$)\n\
+ interpolateMACGrid(target=vel_sn$ID$, source=vel_s$ID$)\n\
+ \n\
+ setObstacleFlags(flags=flags_sn$ID$, phiObs=phiObs_sn$ID$, phiOut=phiOut_sn$ID$, phiIn=phiIn_sn$ID$)\n\
+ flags_sn$ID$.fillGrid()\n\
+ \n\
+ # Interpolate emission grids and apply them to big noise grids\n\
+ interpolateGrid(source=densityIn_s$ID$, target=tmpIn_sn$ID$)\n\
+ interpolateGrid(source=emissionIn_s$ID$, target=emissionIn_sn$ID$)\n\
+ \n\
+ # Higher-res noise grid needs scaled emission values\n\
+ tmpIn_sn$ID$.multConst(float(upres_sn$ID$))\n\
+ applyEmission(flags=flags_sn$ID$, target=density_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ if using_colors_s$ID$:\n\
+ interpolateGrid(source=color_r_in_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=color_r_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ interpolateGrid(source=color_g_in_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=color_g_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ interpolateGrid(source=color_b_in_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=color_b_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ if using_fire_s$ID$:\n\
+ interpolateGrid(source=fuelIn_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=fuel_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ interpolateGrid(source=reactIn_s$ID$, target=tmpIn_sn$ID$)\n\
+ applyEmission(flags=flags_sn$ID$, target=react_sn$ID$, source=tmpIn_sn$ID$, emissionTexture=emissionIn_sn$ID$, type=FlagInflow|FlagOutflow)\n\
+ \n\
+ mantaMsg('Noise step / sn$ID$.frame: ' + str(sn$ID$.frame))\n\
+ if using_fire_s$ID$:\n\
+ process_burn_noise_$ID$()\n\
+ step_noise_$ID$()\n\
+ if using_fire_s$ID$:\n\
+ update_flame_noise_$ID$()\n\
+ \n\
+ sn$ID$.step()\n\
+ \n\
+ copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\
+ copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n\
+\n\
+def step_noise_$ID$():\n\
+ mantaMsg('Smoke step noise')\n\
+ \n\
+ if using_dissolve_s$ID$:\n\
+ mantaMsg('Dissolving noise')\n\
+ dissolveSmoke(flags=flags_sn$ID$, density=density_sn$ID$, heat=None, red=color_r_sn$ID$, green=color_g_sn$ID$, blue=color_b_sn$ID$, speed=dissolveSpeed_s$ID$, logFalloff=using_logdissolve_s$ID$)\n\
+ \n\
+ mantaMsg('Advecting UVs and updating UV weight')\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=uvGrid0_s$ID$, order=2)\n\
+ updateUvWeight(resetTime=sn$ID$.timestep*10.0 , index=0, numUvs=uvs_s$ID$, uv=uvGrid0_s$ID$, offset=uvs_offset_s$ID$)\n\
+ advectSemiLagrange(flags=flags_s$ID$, vel=vel_s$ID$, grid=uvGrid1_s$ID$, order=2)\n\
+ updateUvWeight(resetTime=sn$ID$.timestep*10.0 , index=1, numUvs=uvs_s$ID$, uv=uvGrid1_s$ID$, offset=uvs_offset_s$ID$)\n\
+ \n\
+ mantaMsg('Energy')\n\
+ computeEnergy(flags=flags_s$ID$, vel=vel_s$ID$, energy=energy_s$ID$)\n\
+ \n\
+ tempFlag_s$ID$.copyFrom(flags_s$ID$)\n\
+ extrapolateSimpleFlags(flags=flags_s$ID$, val=tempFlag_s$ID$, distance=2, flagFrom=FlagObstacle, flagTo=FlagFluid)\n\
+ extrapolateSimpleFlags(flags=tempFlag_s$ID$, val=energy_s$ID$, distance=6, flagFrom=FlagFluid, flagTo=FlagObstacle)\n\
+ computeWaveletCoeffs(energy_s$ID$)\n\
+ \n\
+ sStr_s$ID$ = 1.0 * wltStrength_s$ID$\n\
+ sPos_s$ID$ = 2.0\n\
+ \n\
+ mantaMsg('Applying noise vec')\n\
+ for o in range(octaves_s$ID$):\n\
+ uvWeight_s$ID$ = getUvWeight(uvGrid0_s$ID$)\n\
+ applyNoiseVec3(flags=flags_sn$ID$, target=vel_sn$ID$, noise=wltnoise_sn$ID$, scale=sStr_s$ID$ * uvWeight_s$ID$, scaleSpatial=sPos_s$ID$ , weight=energy_s$ID$, uv=uvGrid0_s$ID$)\n\
+ uvWeight_s$ID$ = getUvWeight(uvGrid1_s$ID$)\n\
+ applyNoiseVec3(flags=flags_sn$ID$, target=vel_sn$ID$, noise=wltnoise_sn$ID$, scale=sStr_s$ID$ * uvWeight_s$ID$, scaleSpatial=sPos_s$ID$ , weight=energy_s$ID$, uv=uvGrid1_s$ID$)\n\
+ \n\
+ sStr_s$ID$ *= 0.06 # magic kolmogorov factor \n\
+ sPos_s$ID$ *= 2.0 \n\
+ \n\
+ for substep in range(int(upres_sn$ID$)):\n\
+ if using_colors_s$ID$: \n\
+ mantaMsg('Advecting colors noise')\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_r_sn$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_g_sn$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=color_b_sn$ID$, order=2)\n\
+ \n\
+ if using_fire_s$ID$: \n\
+ mantaMsg('Advecting fire noise')\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=fuel_sn$ID$, order=2)\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=react_sn$ID$, order=2)\n\
+ \n\
+ mantaMsg('Advecting density noise')\n\
+ advectSemiLagrange(flags=flags_sn$ID$, vel=vel_sn$ID$, grid=density_sn$ID$, order=2)\n\
+\n\
+def process_burn_noise_$ID$():\n\
+ mantaMsg('Process burn noise')\n\
+ processBurn(fuel=fuel_sn$ID$, density=density_sn$ID$, react=react_sn$ID$, red=color_r_sn$ID$ if using_colors_s$ID$ else None, green=color_g_sn$ID$ if using_colors_s$ID$ else None, blue=color_b_sn$ID$ if using_colors_s$ID$ else None, burningRate=burningRate_s$ID$, flameSmoke=flameSmoke_s$ID$, ignitionTemp=ignitionTemp_s$ID$, maxTemp=maxTemp_s$ID$, flameSmokeColor=flameSmokeColor_s$ID$)\n\
+\n\
+def update_flame_noise_$ID$():\n\
+ mantaMsg('Update flame noise')\n\
+ updateFlame(react=react_sn$ID$, flame=flame_sn$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// IMPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_load_data =
+ "\n\
+def smoke_load_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke load data')\n\
+ fluid_file_import_s$ID$(dict=smoke_data_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n";
+
+const std::string smoke_load_noise =
+ "\n\
+def smoke_load_noise_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke load noise')\n\
+ fluid_file_import_s$ID$(dict=smoke_noise_dict_s$ID$, path=path, framenr=framenr, file_format=file_format)\n\
+ \n\
+ # Fill up xyz texture grids, important when resuming a bake\n\
+ copyVec3ToReal(source=uvGrid0_s$ID$, targetX=texture_u_s$ID$, targetY=texture_v_s$ID$, targetZ=texture_w_s$ID$)\n\
+ copyVec3ToReal(source=uvGrid1_s$ID$, targetX=texture_u2_s$ID$, targetY=texture_v2_s$ID$, targetZ=texture_w2_s$ID$)\n";
+
+//////////////////////////////////////////////////////////////////////
+// EXPORT
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_save_data =
+ "\n\
+def smoke_save_data_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke save data')\n\
+ start_time = time.time()\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(framenr=framenr, file_format=file_format, path=path, dict=smoke_data_dict_s$ID$,)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=smoke_data_dict_s$ID$, do_join=False)\n\
+ mantaMsg('--- Save: %s seconds ---' % (time.time() - start_time))\n";
+
+const std::string smoke_save_noise =
+ "\n\
+def smoke_save_noise_$ID$(path, framenr, file_format):\n\
+ mantaMsg('Smoke save noise')\n\
+ if not withMPSave or isWindows:\n\
+ fluid_file_export_s$ID$(dict=smoke_noise_dict_s$ID$, framenr=framenr, file_format=file_format, path=path)\n\
+ else:\n\
+ fluid_cache_multiprocessing_start_$ID$(function=fluid_file_export_s$ID$, framenr=framenr, format_data=file_format, path_data=path, dict=smoke_noise_dict_s$ID$, do_join=False)\n";
+
+//////////////////////////////////////////////////////////////////////
+// STANDALONE MODE
+//////////////////////////////////////////////////////////////////////
+
+const std::string smoke_standalone =
+ "\n\
+# Helper function to call cache load functions\n\
+def load(frame):\n\
+ fluid_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\
+ smoke_load_data_$ID$(os.path.join(cache_dir, 'data'), frame, file_format_data)\n\
+ if using_noise_s$ID$:\n\
+ smoke_load_noise_$ID$(os.path.join(cache_dir, 'noise'), frame, file_format_noise)\n\
+ if using_guiding_s$ID$:\n\
+ fluid_load_guiding_$ID$(os.path.join(cache_dir, 'guiding'), frame, file_format_data)\n\
+\n\
+# Helper function to call step functions\n\
+def step(frame):\n\
+ smoke_adaptive_step_$ID$(frame)\n\
+ if using_noise_s$ID$:\n\
+ smoke_step_noise_$ID$(frame)\n";