Files
test/intern/mantaflow/intern/MANTA_main.cpp

2446 lines
81 KiB
C++

/* SPDX-FileCopyrightText: 2016 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup intern_mantaflow
*/
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <zlib.h>
#include <Python.h>
#include <manta.h>
#include "MANTA_main.h"
#include "fluid_script.h"
#include "liquid_script.h"
#include "smoke_script.h"
#include "BLI_fileops.h"
#include "BLI_path_utils.hh"
#include "BLI_utildefines.h"
#include "DNA_fluid_types.h"
#include "DNA_modifier_types.h"
using std::cerr;
using std::cout;
using std::endl;
using std::ifstream;
using std::istringstream;
using std::ofstream;
using std::ostringstream;
using std::to_string;
atomic<int> MANTA::solverID(0);
int MANTA::with_debug(0);
MANTA::MANTA(int *res, FluidModifierData *fmd)
: mCurrentID(++solverID), mMaxRes(fmd->domain->maxres)
{
if (with_debug) {
cout << "FLUID: " << mCurrentID << " with res(" << res[0] << ", " << res[1] << ", " << res[2]
<< ")" << endl;
}
FluidDomainSettings *fds = fmd->domain;
fds->fluid = this;
mUsingLiquid = (fds->type == FLUID_DOMAIN_TYPE_LIQUID);
mUsingSmoke = (fds->type == FLUID_DOMAIN_TYPE_GAS);
mUsingNoise = (fds->flags & FLUID_DOMAIN_USE_NOISE) && mUsingSmoke;
mUsingFractions = (fds->flags & FLUID_DOMAIN_USE_FRACTIONS) && mUsingLiquid;
mUsingMesh = (fds->flags & FLUID_DOMAIN_USE_MESH) && mUsingLiquid;
mUsingDiffusion = (fds->flags & FLUID_DOMAIN_USE_DIFFUSION) && mUsingLiquid;
mUsingViscosity = (fds->flags & FLUID_DOMAIN_USE_VISCOSITY) && mUsingLiquid;
mUsingMVel = (fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) && mUsingLiquid;
mUsingGuiding = (fds->flags & FLUID_DOMAIN_USE_GUIDE);
mUsingDrops = (fds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) && mUsingLiquid;
mUsingBubbles = (fds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) && mUsingLiquid;
mUsingFloats = (fds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) && mUsingLiquid;
mUsingTracers = (fds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) && mUsingLiquid;
mUsingHeat = (fds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT) && mUsingSmoke;
mUsingFire = (fds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE) && mUsingSmoke;
mUsingColors = (fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) && mUsingSmoke;
mUsingObstacle = (fds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE);
mUsingInvel = (fds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL);
mUsingOutflow = (fds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW);
/* Simulation constants */
mResX = res[0]; /* Current size of domain (will adjust with adaptive domain). */
mResY = res[1];
mResZ = res[2];
mTotalCells = mResX * mResY * mResZ;
mResGuiding = fds->res;
/* Smoke low res grids. */
mDensity = nullptr;
mShadow = nullptr;
mHeat = nullptr;
mVelocityX = nullptr;
mVelocityY = nullptr;
mVelocityZ = nullptr;
mForceX = nullptr;
mForceY = nullptr;
mForceZ = nullptr;
mFlame = nullptr;
mFuel = nullptr;
mReact = nullptr;
mColorR = nullptr;
mColorG = nullptr;
mColorB = nullptr;
mFlags = nullptr;
mDensityIn = nullptr;
mHeatIn = nullptr;
mColorRIn = nullptr;
mColorGIn = nullptr;
mColorBIn = nullptr;
mFuelIn = nullptr;
mReactIn = nullptr;
mEmissionIn = nullptr;
mPressure = nullptr;
/* Smoke high res grids. */
mDensityHigh = nullptr;
mFlameHigh = nullptr;
mFuelHigh = nullptr;
mReactHigh = nullptr;
mColorRHigh = nullptr;
mColorGHigh = nullptr;
mColorBHigh = nullptr;
mTextureU = nullptr;
mTextureV = nullptr;
mTextureW = nullptr;
mTextureU2 = nullptr;
mTextureV2 = nullptr;
mTextureW2 = nullptr;
/* Fluid low res grids. */
mPhiIn = nullptr;
mPhiStaticIn = nullptr;
mPhiOutIn = nullptr;
mPhiOutStaticIn = nullptr;
mPhi = nullptr;
/* Mesh. */
mMeshNodes = nullptr;
mMeshTriangles = nullptr;
mMeshVelocities = nullptr;
/* Fluid obstacle. */
mPhiObsIn = nullptr;
mPhiObsStaticIn = nullptr;
mNumObstacle = nullptr;
mObVelocityX = nullptr;
mObVelocityY = nullptr;
mObVelocityZ = nullptr;
/* Fluid guiding. */
mPhiGuideIn = nullptr;
mNumGuide = nullptr;
mGuideVelocityX = nullptr;
mGuideVelocityY = nullptr;
mGuideVelocityZ = nullptr;
/* Fluid initial velocity. */
mInVelocityX = nullptr;
mInVelocityY = nullptr;
mInVelocityZ = nullptr;
/* Secondary particles. */
mFlipParticleData = nullptr;
mFlipParticleVelocity = nullptr;
mParticleData = nullptr;
mParticleVelocity = nullptr;
mParticleLife = nullptr;
/* Cache read success indicators. */
mFlipFromFile = false;
mMeshFromFile = false;
mParticlesFromFile = false;
/* Setup Mantaflow in Python. */
initializeMantaflow();
/* Initializa RNA map with values that Python will need. */
initializeRNAMap(fmd);
bool initSuccess = true;
/* Initialize Mantaflow variables in Python. */
/* Liquid. */
if (mUsingLiquid) {
initSuccess &= initDomain();
initSuccess &= initLiquid();
if (mUsingObstacle) {
initSuccess &= initObstacle();
}
if (mUsingInvel) {
initSuccess &= initInVelocity();
}
if (mUsingOutflow) {
initSuccess &= initOutflow();
}
if (mUsingDrops || mUsingBubbles || mUsingFloats || mUsingTracers) {
mUpresParticle = fds->particle_scale;
mResXParticle = mUpresParticle * mResX;
mResYParticle = mUpresParticle * mResY;
mResZParticle = mUpresParticle * mResZ;
mTotalCellsParticles = mResXParticle * mResYParticle * mResZParticle;
initSuccess &= initSndParts();
initSuccess &= initLiquidSndParts();
}
if (mUsingMesh) {
mUpresMesh = fds->mesh_scale;
mResXMesh = mUpresMesh * mResX;
mResYMesh = mUpresMesh * mResY;
mResZMesh = mUpresMesh * mResZ;
mTotalCellsMesh = mResXMesh * mResYMesh * mResZMesh;
/* Initialize Mantaflow variables in Python. */
initSuccess &= initMesh();
initSuccess &= initLiquidMesh();
}
if (mUsingViscosity) {
initSuccess &= initLiquidViscosity();
}
if (mUsingDiffusion) {
initSuccess &= initCurvature();
}
if (mUsingGuiding) {
mResGuiding = (fds->guide_parent) ? fds->guide_res : fds->res;
initSuccess &= initGuiding();
}
if (mUsingFractions) {
initSuccess &= initFractions();
}
}
/* Smoke. */
if (mUsingSmoke) {
initSuccess &= initDomain();
initSuccess &= initSmoke();
if (mUsingHeat) {
initSuccess &= initHeat();
}
if (mUsingFire) {
initSuccess &= initFire();
}
if (mUsingColors) {
initSuccess &= initColors();
}
if (mUsingObstacle) {
initSuccess &= initObstacle();
}
if (mUsingInvel) {
initSuccess &= initInVelocity();
}
if (mUsingOutflow) {
initSuccess &= initOutflow();
}
if (mUsingGuiding) {
mResGuiding = (fds->guide_parent) ? fds->guide_res : fds->res;
initSuccess &= initGuiding();
}
if (mUsingNoise) {
int amplify = fds->noise_scale;
mResXNoise = amplify * mResX;
mResYNoise = amplify * mResY;
mResZNoise = amplify * mResZ;
mTotalCellsHigh = mResXNoise * mResYNoise * mResZNoise;
/* Initialize Mantaflow variables in Python. */
initSuccess &= initNoise();
initSuccess &= initSmokeNoise();
if (mUsingFire) {
initSuccess &= initFireHigh();
}
if (mUsingColors) {
initSuccess &= initColorsHigh();
}
}
}
/* All requested initializations must not fail in constructor. */
BLI_assert(initSuccess);
(void)initSuccess; /* Ignored in release. */
updatePointers(fmd);
}
bool MANTA::initDomain(FluidModifierData *fmd)
{
/* Vector will hold all python commands that are to be executed. */
vector<string> pythonCommands;
/* Set manta debug level first. */
pythonCommands.push_back(manta_import + manta_debuglevel);
ostringstream ss;
ss << "set_manta_debuglevel(" << with_debug << ")";
pythonCommands.push_back(ss.str());
/* Now init basic fluid domain. */
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_pre_step + fluid_post_step +
fluid_adapt_time_step + fluid_time_stepping;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return runPythonString(pythonCommands);
}
bool MANTA::initNoise(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = fluid_variables_noise + fluid_solver_noise;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return runPythonString(pythonCommands);
}
bool MANTA::initSmoke(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = smoke_variables + smoke_alloc + smoke_adaptive_step + smoke_save_data +
smoke_load_data + smoke_step;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return runPythonString(pythonCommands);
}
bool MANTA::initSmokeNoise(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = smoke_variables_noise + smoke_alloc_noise + smoke_wavelet_noise +
smoke_save_noise + smoke_load_noise + smoke_step_noise;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingNoise = true;
return runPythonString(pythonCommands);
}
bool MANTA::initHeat(FluidModifierData *fmd)
{
if (!mHeat) {
vector<string> pythonCommands;
string tmpString = smoke_alloc_heat + smoke_with_heat;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingHeat = true;
return runPythonString(pythonCommands);
}
return false;
}
bool MANTA::initFire(FluidModifierData *fmd)
{
if (!mFuel) {
vector<string> pythonCommands;
string tmpString = smoke_alloc_fire + smoke_with_fire;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingFire = true;
return runPythonString(pythonCommands);
}
return false;
}
bool MANTA::initFireHigh(FluidModifierData *fmd)
{
if (!mFuelHigh) {
vector<string> pythonCommands;
string tmpString = smoke_alloc_fire_noise + smoke_with_fire;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingFire = true;
return runPythonString(pythonCommands);
}
return false;
}
bool MANTA::initColors(FluidModifierData *fmd)
{
if (!mColorR) {
vector<string> pythonCommands;
string tmpString = smoke_alloc_colors + smoke_init_colors + smoke_with_colors;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingColors = true;
return runPythonString(pythonCommands);
}
return false;
}
bool MANTA::initColorsHigh(FluidModifierData *fmd)
{
if (!mColorRHigh) {
vector<string> pythonCommands;
string tmpString = smoke_alloc_colors_noise + smoke_init_colors_noise + smoke_with_colors;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingColors = true;
return runPythonString(pythonCommands);
}
return false;
}
bool MANTA::initLiquid(FluidModifierData *fmd)
{
if (!mPhiIn) {
vector<string> pythonCommands;
string tmpString = liquid_variables + liquid_alloc + liquid_init_phi + liquid_save_data +
liquid_load_data + liquid_adaptive_step + liquid_step;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingLiquid = true;
return runPythonString(pythonCommands);
}
return false;
}
bool MANTA::initMesh(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = fluid_variables_mesh + fluid_solver_mesh + liquid_load_mesh;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingMesh = true;
return runPythonString(pythonCommands);
}
bool MANTA::initLiquidMesh(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = liquid_alloc_mesh + liquid_step_mesh + liquid_save_mesh;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingMesh = true;
return runPythonString(pythonCommands);
}
bool MANTA::initLiquidViscosity(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = fluid_variables_viscosity + fluid_solver_viscosity + liquid_alloc_viscosity;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
mUsingViscosity = true;
return runPythonString(pythonCommands);
}
bool MANTA::initCurvature(FluidModifierData *fmd)
{
std::vector<std::string> pythonCommands;
std::string finalString = parseScript(liquid_alloc_curvature, fmd);
pythonCommands.push_back(finalString);
mUsingDiffusion = true;
return runPythonString(pythonCommands);
}
bool MANTA::initObstacle(FluidModifierData *fmd)
{
if (!mPhiObsIn) {
vector<string> pythonCommands;
string tmpString = fluid_alloc_obstacle + fluid_with_obstacle;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return (mUsingObstacle = runPythonString(pythonCommands));
}
return false;
}
bool MANTA::initGuiding(FluidModifierData *fmd)
{
if (!mPhiGuideIn) {
vector<string> pythonCommands;
string tmpString = fluid_variables_guiding + fluid_solver_guiding + fluid_alloc_guiding +
fluid_save_guiding + fluid_load_vel + fluid_load_guiding;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return (mUsingGuiding = runPythonString(pythonCommands));
}
return false;
}
bool MANTA::initFractions(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = fluid_alloc_fractions + fluid_with_fractions;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return (mUsingFractions = runPythonString(pythonCommands));
}
bool MANTA::initInVelocity(FluidModifierData *fmd)
{
if (!mInVelocityX) {
vector<string> pythonCommands;
string tmpString = fluid_alloc_invel + fluid_with_invel;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return (mUsingInvel = runPythonString(pythonCommands));
}
return false;
}
bool MANTA::initOutflow(FluidModifierData *fmd)
{
if (!mPhiOutIn) {
vector<string> pythonCommands;
string tmpString = fluid_alloc_outflow + fluid_with_outflow;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return (mUsingOutflow = runPythonString(pythonCommands));
}
return false;
}
bool MANTA::initSndParts(FluidModifierData *fmd)
{
vector<string> pythonCommands;
string tmpString = fluid_variables_particles + fluid_solver_particles;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return runPythonString(pythonCommands);
}
bool MANTA::initLiquidSndParts(FluidModifierData *fmd)
{
if (!mParticleData) {
vector<string> pythonCommands;
string tmpString = liquid_alloc_particles + liquid_variables_particles +
liquid_step_particles + fluid_with_sndparts + liquid_load_particles +
liquid_save_particles;
string finalString = parseScript(tmpString, fmd);
pythonCommands.push_back(finalString);
return runPythonString(pythonCommands);
}
return false;
}
MANTA::~MANTA()
{
if (with_debug) {
cout << "~FLUID: " << mCurrentID << " with res(" << mResX << ", " << mResY << ", " << mResZ
<< ")" << endl;
}
/* Destruction string for Python. */
string tmpString;
vector<string> pythonCommands;
bool result = false;
tmpString += manta_import;
tmpString += fluid_delete_all;
/* Initializa RNA map with values that Python will need. */
initializeRNAMap();
/* Leave out fmd argument in parseScript since only looking up IDs. */
string finalString = parseScript(tmpString);
pythonCommands.push_back(finalString);
result = runPythonString(pythonCommands);
/* WARNING: this causes crash on exit in the `cycles_volume_cpu/smoke_color` test,
* freeing a single modifier ends up clearing the shared module.
* For this to be handled properly there would need to be a initialize/free
* function for global data. */
#if 0
MANTA::terminateMantaflow();
#endif
BLI_assert(result);
UNUSED_VARS(result);
}
/**
* Copied from `PyC_DefaultNameSpace` in Blender.
* with some differences:
* - Doesn't touch `sys.modules`, use #manta_python_main_module_activate instead.
* - Returns the module instead of the modules `dict`.
*/
static PyObject *manta_python_main_module_create(const char *filename)
{
PyObject *builtins = PyEval_GetBuiltins();
PyObject *mod_main = PyModule_New("__main__");
PyModule_AddStringConstant(mod_main, "__name__", "__main__");
if (filename) {
/* __file__ mainly for nice UI'ness
* NOTE: this won't map to a real file when executing text-blocks and buttons. */
PyModule_AddObject(mod_main, "__file__", PyUnicode_InternFromString(filename));
}
PyModule_AddObjectRef(mod_main, "__builtins__", builtins);
return mod_main;
}
static void manta_python_main_module_activate(PyObject *mod_main)
{
PyObject *modules = PyImport_GetModuleDict();
PyObject *main_mod_cmp = PyDict_GetItemString(modules, "__main__");
if (mod_main == main_mod_cmp) {
return;
}
/* NOTE: we could remove the reference to `mod_main` here, but as it's know to be removed
* accept that there is temporarily an extra reference. */
PyDict_SetItemString(modules, "__main__", mod_main);
}
static void manta_python_main_module_backup(PyObject **r_main_mod)
{
PyObject *modules = PyImport_GetModuleDict();
*r_main_mod = PyDict_GetItemString(modules, "__main__");
Py_XINCREF(*r_main_mod); /* don't free */
}
static void manta_python_main_module_restore(PyObject *main_mod)
{
PyObject *modules = PyImport_GetModuleDict();
PyDict_SetItemString(modules, "__main__", main_mod);
Py_XDECREF(main_mod);
}
/**
* Mantaflow stores many variables in the globals() dict of the __main__ module. To be able to
* access these variables, the same __main__ module has to be used every time.
*
* Unfortunately, we also depend on the fact that mantaflow dumps variables into this module using
* #PyRun_String. So we can't easily create a separate module without changing mantaflow.
*/
static PyObject *manta_main_module = nullptr;
static void manta_python_main_module_clear()
{
if (manta_main_module) {
Py_DECREF(manta_main_module);
manta_main_module = nullptr;
}
}
static PyObject *manta_python_main_module_ensure()
{
if (!manta_main_module) {
manta_main_module = manta_python_main_module_create("<manta_namespace>");
}
return manta_main_module;
}
bool MANTA::runPythonString(vector<string> commands)
{
bool success = true;
PyGILState_STATE gilstate = PyGILState_Ensure();
/* Temporarily set `sys.modules["__main__"]` as some Python modules expect this. */
PyObject *main_mod_backup;
manta_python_main_module_backup(&main_mod_backup);
/* If we never want to run this when the module isn't initialize,
* assign with `manta_python_main_module_ensure()`. */
BLI_assert(manta_main_module != nullptr);
manta_python_main_module_activate(manta_main_module);
for (vector<string>::iterator it = commands.begin(); it != commands.end(); ++it) {
string command = *it;
PyObject *globals_dict = PyModule_GetDict(manta_main_module);
PyObject *return_value = PyRun_String(
command.c_str(), Py_file_input, globals_dict, globals_dict);
if (return_value == nullptr) {
success = false;
if (PyErr_Occurred()) {
PyErr_Print();
}
}
else {
Py_DECREF(return_value);
}
}
manta_python_main_module_restore(main_mod_backup);
PyGILState_Release(gilstate);
BLI_assert(success);
return success;
}
void MANTA::initializeMantaflow()
{
if (with_debug) {
cout << "Fluid: Initializing Mantaflow framework" << endl;
}
string filename = "manta_scene_" + to_string(mCurrentID) + ".py";
vector<string> fill = vector<string>();
/* Initialize extension classes and wrappers. */
srand(0);
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *manta_main_module = manta_python_main_module_ensure();
PyObject *globals_dict = PyModule_GetDict(manta_main_module);
Pb::setup(false, filename, fill, globals_dict); /* Namespace from Mantaflow (registry). */
PyGILState_Release(gilstate);
}
void MANTA::terminateMantaflow()
{
if (with_debug) {
cout << "Fluid: Releasing Mantaflow framework" << endl;
}
PyGILState_STATE gilstate = PyGILState_Ensure();
Pb::finalize(false); /* Namespace from Mantaflow (registry). */
manta_python_main_module_clear();
PyGILState_Release(gilstate);
}
static string getCacheFileEnding(char cache_format)
{
if (MANTA::with_debug) {
cout << "MANTA::getCacheFileEnding()" << endl;
}
switch (cache_format) {
case FLUID_DOMAIN_FILE_UNI:
return FLUID_DOMAIN_EXTENSION_UNI;
case FLUID_DOMAIN_FILE_OPENVDB:
return FLUID_DOMAIN_EXTENSION_OPENVDB;
case FLUID_DOMAIN_FILE_RAW:
return FLUID_DOMAIN_EXTENSION_RAW;
case FLUID_DOMAIN_FILE_BIN_OBJECT:
return FLUID_DOMAIN_EXTENSION_BINOBJ;
case FLUID_DOMAIN_FILE_OBJECT:
return FLUID_DOMAIN_EXTENSION_OBJ;
default:
cerr << "Fluid Error -- Could not find file extension. Using default file extension."
<< endl;
return FLUID_DOMAIN_EXTENSION_UNI;
}
}
static string getBooleanString(int value)
{
return (value) ? "True" : "False";
}
void MANTA::initializeRNAMap(FluidModifierData *fmd)
{
if (with_debug) {
cout << "MANTA::initializeRNAMap()" << endl;
}
mRNAMap["ID"] = to_string(mCurrentID);
if (!fmd) {
if (with_debug) {
cout << "Fluid: No modifier data given in RNA map setup - returning early" << endl;
}
return;
}
FluidDomainSettings *fds = fmd->domain;
bool is2D = (fds->solver_res == 2);
string borderCollisions;
if ((fds->border_collisions & FLUID_DOMAIN_BORDER_LEFT) == 0) {
borderCollisions += "x";
}
if ((fds->border_collisions & FLUID_DOMAIN_BORDER_RIGHT) == 0) {
borderCollisions += "X";
}
if ((fds->border_collisions & FLUID_DOMAIN_BORDER_FRONT) == 0) {
borderCollisions += "y";
}
if ((fds->border_collisions & FLUID_DOMAIN_BORDER_BACK) == 0) {
borderCollisions += "Y";
}
if ((fds->border_collisions & FLUID_DOMAIN_BORDER_BOTTOM) == 0) {
borderCollisions += "z";
}
if ((fds->border_collisions & FLUID_DOMAIN_BORDER_TOP) == 0) {
borderCollisions += "Z";
}
string particleTypesStr;
if (fds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) {
particleTypesStr += "PtypeSpray";
}
if (fds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) {
if (!particleTypesStr.empty()) {
particleTypesStr += "|";
}
particleTypesStr += "PtypeBubble";
}
if (fds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) {
if (!particleTypesStr.empty()) {
particleTypesStr += "|";
}
particleTypesStr += "PtypeFoam";
}
if (fds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) {
if (!particleTypesStr.empty()) {
particleTypesStr += "|";
}
particleTypesStr += "PtypeTracer";
}
if (particleTypesStr.empty()) {
particleTypesStr = "0";
}
int particleTypes = (FLUID_DOMAIN_PARTICLE_SPRAY | FLUID_DOMAIN_PARTICLE_BUBBLE |
FLUID_DOMAIN_PARTICLE_FOAM | FLUID_DOMAIN_PARTICLE_TRACER);
string cacheDirectory(fds->cache_directory);
float viscosity = fds->viscosity_base * pow(10.0f, -fds->viscosity_exponent);
float domainSize = std::max({fds->global_size[0], fds->global_size[1], fds->global_size[2]});
string vdbCompressionMethod = "Compression_None";
if (fds->openvdb_compression == VDB_COMPRESSION_NONE) {
vdbCompressionMethod = "Compression_None";
}
else if (fds->openvdb_compression == VDB_COMPRESSION_ZIP) {
vdbCompressionMethod = "Compression_Zip";
}
else if (fds->openvdb_compression == VDB_COMPRESSION_BLOSC) {
vdbCompressionMethod = "Compression_Blosc";
}
string vdbPrecisionHalf = "Precision_Half";
if (fds->openvdb_data_depth == VDB_PRECISION_FULL_FLOAT) {
vdbPrecisionHalf = "Precision_Full";
}
else if (fds->openvdb_data_depth == VDB_PRECISION_HALF_FLOAT) {
vdbPrecisionHalf = "Precision_Half";
}
else if (fds->openvdb_data_depth == VDB_PRECISION_MINI_FLOAT) {
vdbPrecisionHalf = "Precision_Mini";
}
mRNAMap["USING_SMOKE"] = getBooleanString(fds->type == FLUID_DOMAIN_TYPE_GAS);
mRNAMap["USING_LIQUID"] = getBooleanString(fds->type == FLUID_DOMAIN_TYPE_LIQUID);
mRNAMap["USING_COLORS"] = getBooleanString(fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS);
mRNAMap["USING_HEAT"] = getBooleanString(fds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT);
mRNAMap["USING_FIRE"] = getBooleanString(fds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE);
mRNAMap["USING_NOISE"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_NOISE);
mRNAMap["USING_OBSTACLE"] = getBooleanString(fds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE);
mRNAMap["USING_GUIDING"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_GUIDE);
mRNAMap["USING_INVEL"] = getBooleanString(fds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL);
mRNAMap["USING_OUTFLOW"] = getBooleanString(fds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW);
mRNAMap["USING_LOG_DISSOLVE"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_DISSOLVE_LOG);
mRNAMap["USING_DISSOLVE"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_DISSOLVE);
mRNAMap["DOMAIN_CLOSED"] = getBooleanString(borderCollisions.compare("") == 0);
mRNAMap["CACHE_RESUMABLE"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE);
mRNAMap["USING_ADAPTIVETIME"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_ADAPTIVE_TIME);
mRNAMap["USING_SPEEDVECTORS"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS);
mRNAMap["USING_FRACTIONS"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_FRACTIONS);
mRNAMap["DELETE_IN_OBSTACLE"] = getBooleanString(fds->flags & FLUID_DOMAIN_DELETE_IN_OBSTACLE);
mRNAMap["USING_DIFFUSION"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_DIFFUSION);
mRNAMap["USING_MESH"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_MESH);
mRNAMap["USING_IMPROVED_MESH"] = getBooleanString(fds->mesh_generator ==
FLUID_DOMAIN_MESH_IMPROVED);
mRNAMap["USING_SNDPARTS"] = getBooleanString(fds->particle_type & particleTypes);
mRNAMap["SNDPARTICLE_BOUNDARY_DELETE"] = getBooleanString(fds->sndparticle_boundary ==
SNDPARTICLE_BOUNDARY_DELETE);
mRNAMap["SNDPARTICLE_BOUNDARY_PUSHOUT"] = getBooleanString(fds->sndparticle_boundary ==
SNDPARTICLE_BOUNDARY_PUSHOUT);
mRNAMap["SOLVER_DIM"] = to_string(fds->solver_res);
mRNAMap["BOUND_CONDITIONS"] = borderCollisions;
mRNAMap["BOUNDARY_WIDTH"] = to_string(fds->boundary_width);
mRNAMap["RES"] = to_string(mMaxRes);
mRNAMap["RESX"] = to_string(mResX);
mRNAMap["RESY"] = (is2D) ? to_string(mResZ) : to_string(mResY);
mRNAMap["RESZ"] = (is2D) ? to_string(1) : to_string(mResZ);
mRNAMap["TIME_SCALE"] = to_string(fds->time_scale);
mRNAMap["FRAME_LENGTH"] = to_string(fds->frame_length);
mRNAMap["CFL"] = to_string(fds->cfl_condition);
mRNAMap["DT"] = to_string(fds->dt);
mRNAMap["TIMESTEPS_MIN"] = to_string(fds->timesteps_minimum);
mRNAMap["TIMESTEPS_MAX"] = to_string(fds->timesteps_maximum);
mRNAMap["TIME_TOTAL"] = to_string(fds->time_total);
mRNAMap["TIME_PER_FRAME"] = to_string(fds->time_per_frame);
mRNAMap["VORTICITY"] = to_string(fds->vorticity);
mRNAMap["FLAME_VORTICITY"] = to_string(fds->flame_vorticity);
mRNAMap["NOISE_SCALE"] = to_string(fds->noise_scale);
mRNAMap["MESH_SCALE"] = to_string(fds->mesh_scale);
mRNAMap["PARTICLE_SCALE"] = to_string(fds->particle_scale);
mRNAMap["NOISE_RESX"] = to_string(mResXNoise);
mRNAMap["NOISE_RESY"] = (is2D) ? to_string(mResZNoise) : to_string(mResYNoise);
mRNAMap["NOISE_RESZ"] = (is2D) ? to_string(1) : to_string(mResZNoise);
mRNAMap["MESH_RESX"] = to_string(mResXMesh);
mRNAMap["MESH_RESY"] = (is2D) ? to_string(mResZMesh) : to_string(mResYMesh);
mRNAMap["MESH_RESZ"] = (is2D) ? to_string(1) : to_string(mResZMesh);
mRNAMap["PARTICLE_RESX"] = to_string(mResXParticle);
mRNAMap["PARTICLE_RESY"] = (is2D) ? to_string(mResZParticle) : to_string(mResYParticle);
mRNAMap["PARTICLE_RESZ"] = (is2D) ? to_string(1) : to_string(mResZParticle);
mRNAMap["GUIDING_RESX"] = to_string(mResGuiding[0]);
mRNAMap["GUIDING_RESY"] = (is2D) ? to_string(mResGuiding[2]) : to_string(mResGuiding[1]);
mRNAMap["GUIDING_RESZ"] = (is2D) ? to_string(1) : to_string(mResGuiding[2]);
mRNAMap["MIN_RESX"] = to_string(fds->res_min[0]);
mRNAMap["MIN_RESY"] = to_string(fds->res_min[1]);
mRNAMap["MIN_RESZ"] = to_string(fds->res_min[2]);
mRNAMap["BASE_RESX"] = to_string(fds->base_res[0]);
mRNAMap["BASE_RESY"] = to_string(fds->base_res[1]);
mRNAMap["BASE_RESZ"] = to_string(fds->base_res[2]);
mRNAMap["WLT_STR"] = to_string(fds->noise_strength);
mRNAMap["NOISE_POSSCALE"] = to_string(fds->noise_pos_scale);
mRNAMap["NOISE_TIMEANIM"] = to_string(fds->noise_time_anim);
mRNAMap["COLOR_R"] = to_string(fds->active_color[0]);
mRNAMap["COLOR_G"] = to_string(fds->active_color[1]);
mRNAMap["COLOR_B"] = to_string(fds->active_color[2]);
mRNAMap["BUOYANCY_ALPHA"] = to_string(fds->alpha);
mRNAMap["BUOYANCY_BETA"] = to_string(fds->beta);
mRNAMap["DISSOLVE_SPEED"] = to_string(fds->diss_speed);
mRNAMap["BURNING_RATE"] = to_string(fds->burning_rate);
mRNAMap["FLAME_SMOKE"] = to_string(fds->flame_smoke);
mRNAMap["IGNITION_TEMP"] = to_string(fds->flame_ignition);
mRNAMap["MAX_TEMP"] = to_string(fds->flame_max_temp);
mRNAMap["FLAME_SMOKE_COLOR_X"] = to_string(fds->flame_smoke_color[0]);
mRNAMap["FLAME_SMOKE_COLOR_Y"] = to_string(fds->flame_smoke_color[1]);
mRNAMap["FLAME_SMOKE_COLOR_Z"] = to_string(fds->flame_smoke_color[2]);
mRNAMap["CURRENT_FRAME"] = to_string(int(fmd->time));
mRNAMap["START_FRAME"] = to_string(fds->cache_frame_start);
mRNAMap["END_FRAME"] = to_string(fds->cache_frame_end);
mRNAMap["CACHE_DATA_FORMAT"] = getCacheFileEnding(fds->cache_data_format);
mRNAMap["CACHE_MESH_FORMAT"] = getCacheFileEnding(fds->cache_mesh_format);
mRNAMap["CACHE_NOISE_FORMAT"] = getCacheFileEnding(fds->cache_noise_format);
mRNAMap["CACHE_PARTICLE_FORMAT"] = getCacheFileEnding(fds->cache_particle_format);
mRNAMap["USING_APIC"] = getBooleanString(fds->simulation_method == FLUID_DOMAIN_METHOD_APIC);
mRNAMap["FLIP_RATIO"] = to_string(fds->flip_ratio);
mRNAMap["PARTICLE_RANDOMNESS"] = to_string(fds->particle_randomness);
mRNAMap["PARTICLE_NUMBER"] = to_string(fds->particle_number);
mRNAMap["PARTICLE_MINIMUM"] = to_string(fds->particle_minimum);
mRNAMap["PARTICLE_MAXIMUM"] = to_string(fds->particle_maximum);
mRNAMap["PARTICLE_RADIUS"] = to_string(fds->particle_radius);
mRNAMap["FRACTIONS_THRESHOLD"] = to_string(fds->fractions_threshold);
mRNAMap["FRACTIONS_DISTANCE"] = to_string(fds->fractions_distance);
mRNAMap["MESH_CONCAVE_UPPER"] = to_string(fds->mesh_concave_upper);
mRNAMap["MESH_CONCAVE_LOWER"] = to_string(fds->mesh_concave_lower);
mRNAMap["MESH_PARTICLE_RADIUS"] = to_string(fds->mesh_particle_radius);
mRNAMap["MESH_SMOOTHEN_POS"] = to_string(fds->mesh_smoothen_pos);
mRNAMap["MESH_SMOOTHEN_NEG"] = to_string(fds->mesh_smoothen_neg);
mRNAMap["PARTICLE_BAND_WIDTH"] = to_string(fds->particle_band_width);
mRNAMap["SNDPARTICLE_TAU_MIN_WC"] = to_string(fds->sndparticle_tau_min_wc);
mRNAMap["SNDPARTICLE_TAU_MAX_WC"] = to_string(fds->sndparticle_tau_max_wc);
mRNAMap["SNDPARTICLE_TAU_MIN_TA"] = to_string(fds->sndparticle_tau_min_ta);
mRNAMap["SNDPARTICLE_TAU_MAX_TA"] = to_string(fds->sndparticle_tau_max_ta);
mRNAMap["SNDPARTICLE_TAU_MIN_K"] = to_string(fds->sndparticle_tau_min_k);
mRNAMap["SNDPARTICLE_TAU_MAX_K"] = to_string(fds->sndparticle_tau_max_k);
mRNAMap["SNDPARTICLE_K_WC"] = to_string(fds->sndparticle_k_wc);
mRNAMap["SNDPARTICLE_K_TA"] = to_string(fds->sndparticle_k_ta);
mRNAMap["SNDPARTICLE_K_B"] = to_string(fds->sndparticle_k_b);
mRNAMap["SNDPARTICLE_K_D"] = to_string(fds->sndparticle_k_d);
mRNAMap["SNDPARTICLE_L_MIN"] = to_string(fds->sndparticle_l_min);
mRNAMap["SNDPARTICLE_L_MAX"] = to_string(fds->sndparticle_l_max);
mRNAMap["SNDPARTICLE_POTENTIAL_RADIUS"] = to_string(fds->sndparticle_potential_radius);
mRNAMap["SNDPARTICLE_UPDATE_RADIUS"] = to_string(fds->sndparticle_update_radius);
mRNAMap["LIQUID_SURFACE_TENSION"] = to_string(fds->surface_tension);
mRNAMap["FLUID_VISCOSITY"] = to_string(viscosity);
mRNAMap["FLUID_DOMAIN_SIZE"] = to_string(domainSize);
mRNAMap["FLUID_DOMAIN_SIZE_X"] = to_string(fds->global_size[0]);
mRNAMap["FLUID_DOMAIN_SIZE_Y"] = to_string(fds->global_size[1]);
mRNAMap["FLUID_DOMAIN_SIZE_Z"] = to_string(fds->global_size[2]);
mRNAMap["SNDPARTICLE_TYPES"] = particleTypesStr;
mRNAMap["GUIDING_ALPHA"] = to_string(fds->guide_alpha);
mRNAMap["GUIDING_BETA"] = to_string(fds->guide_beta);
mRNAMap["GUIDING_FACTOR"] = to_string(fds->guide_vel_factor);
mRNAMap["GRAVITY_X"] = to_string(fds->gravity_final[0]);
mRNAMap["GRAVITY_Y"] = to_string(fds->gravity_final[1]);
mRNAMap["GRAVITY_Z"] = to_string(fds->gravity_final[2]);
mRNAMap["CACHE_DIR"] = cacheDirectory;
mRNAMap["COMPRESSION_OPENVDB"] = vdbCompressionMethod;
mRNAMap["PRECISION_OPENVDB"] = vdbPrecisionHalf;
mRNAMap["CLIP_OPENVDB"] = to_string(fds->clipping);
mRNAMap["PP_PARTICLE_MAXIMUM"] = to_string(fds->sys_particle_maximum);
mRNAMap["USING_VISCOSITY"] = getBooleanString(fds->flags & FLUID_DOMAIN_USE_VISCOSITY);
mRNAMap["VISCOSITY_VALUE"] = to_string(fds->viscosity_value);
/* Fluid object names. */
mRNAMap["NAME_FLAGS"] = FLUID_NAME_FLAGS;
mRNAMap["NAME_VELOCITY"] = FLUID_NAME_VELOCITY;
mRNAMap["NAME_VELOCITYTMP"] = FLUID_NAME_VELOCITYTMP;
mRNAMap["NAME_VELOCITY_X"] = FLUID_NAME_VELOCITYX;
mRNAMap["NAME_VELOCITY_Y"] = FLUID_NAME_VELOCITYY;
mRNAMap["NAME_VELOCITY_Z"] = FLUID_NAME_VELOCITYZ;
mRNAMap["NAME_PRESSURE"] = FLUID_NAME_PRESSURE;
mRNAMap["NAME_PHIOBS"] = FLUID_NAME_PHIOBS;
mRNAMap["NAME_PHISIN"] = FLUID_NAME_PHISIN;
mRNAMap["NAME_PHIIN"] = FLUID_NAME_PHIIN;
mRNAMap["NAME_PHIOUT"] = FLUID_NAME_PHIOUT;
mRNAMap["NAME_FORCES"] = FLUID_NAME_FORCES;
mRNAMap["NAME_FORCES_X"] = FLUID_NAME_FORCE_X;
mRNAMap["NAME_FORCES_Y"] = FLUID_NAME_FORCE_Y;
mRNAMap["NAME_FORCES_Z"] = FLUID_NAME_FORCE_Z;
mRNAMap["NAME_NUMOBS"] = FLUID_NAME_NUMOBS;
mRNAMap["NAME_PHIOBSSIN"] = FLUID_NAME_PHIOBSSIN;
mRNAMap["NAME_PHIOBSIN"] = FLUID_NAME_PHIOBSIN;
mRNAMap["NAME_OBVEL"] = FLUID_NAME_OBVEL;
mRNAMap["NAME_OBVELC"] = FLUID_NAME_OBVELC;
mRNAMap["NAME_OBVEL_X"] = FLUID_NAME_OBVEL_X;
mRNAMap["NAME_OBVEL_Y"] = FLUID_NAME_OBVEL_Y;
mRNAMap["NAME_OBVEL_Z"] = FLUID_NAME_OBVEL_Z;
mRNAMap["NAME_FRACTIONS"] = FLUID_NAME_FRACTIONS;
mRNAMap["NAME_INVELC"] = FLUID_NAME_INVELC;
mRNAMap["NAME_INVEL_X"] = FLUID_NAME_INVEL_X;
mRNAMap["NAME_INVEL_Y"] = FLUID_NAME_INVEL_Y;
mRNAMap["NAME_INVEL_Z"] = FLUID_NAME_INVEL_Z;
mRNAMap["NAME_PHIOUTSIN"] = FLUID_NAME_PHIOUTSIN;
mRNAMap["NAME_PHIOUTIN"] = FLUID_NAME_PHIOUTIN;
/* Smoke object names. */
mRNAMap["NAME_SHADOW"] = FLUID_NAME_SHADOW;
mRNAMap["NAME_EMISSION"] = FLUID_NAME_EMISSION;
mRNAMap["NAME_EMISSIONIN"] = FLUID_NAME_EMISSIONIN;
mRNAMap["NAME_DENSITY"] = FLUID_NAME_DENSITY;
mRNAMap["NAME_DENSITYIN"] = FLUID_NAME_DENSITYIN;
mRNAMap["NAME_HEAT"] = FLUID_NAME_HEAT;
mRNAMap["NAME_HEATIN"] = FLUID_NAME_HEATIN;
mRNAMap["NAME_TEMPERATURE"] = FLUID_NAME_TEMPERATURE;
mRNAMap["NAME_TEMPERATUREIN"] = FLUID_NAME_TEMPERATUREIN;
mRNAMap["NAME_COLORR"] = FLUID_NAME_COLORR;
mRNAMap["NAME_COLORG"] = FLUID_NAME_COLORG;
mRNAMap["NAME_COLORB"] = FLUID_NAME_COLORB;
mRNAMap["NAME_COLORRIN"] = FLUID_NAME_COLORRIN;
mRNAMap["NAME_COLORGIN"] = FLUID_NAME_COLORGIN;
mRNAMap["NAME_COLORBIN"] = FLUID_NAME_COLORBIN;
mRNAMap["NAME_FLAME"] = FLUID_NAME_FLAME;
mRNAMap["NAME_FUEL"] = FLUID_NAME_FUEL;
mRNAMap["NAME_REACT"] = FLUID_NAME_REACT;
mRNAMap["NAME_FUELIN"] = FLUID_NAME_FUELIN;
mRNAMap["NAME_REACTIN"] = FLUID_NAME_REACTIN;
/* Liquid object names. */
mRNAMap["NAME_PHIPARTS"] = FLUID_NAME_PHIPARTS;
mRNAMap["NAME_PHI"] = FLUID_NAME_PHI;
mRNAMap["NAME_PHITMP"] = FLUID_NAME_PHITMP;
mRNAMap["NAME_VELOLD"] = FLUID_NAME_VELOCITYOLD;
mRNAMap["NAME_VELPARTS"] = FLUID_NAME_VELOCITYPARTS;
mRNAMap["NAME_MAPWEIGHTS"] = FLUID_NAME_MAPWEIGHTS;
mRNAMap["NAME_PP"] = FLUID_NAME_PP;
mRNAMap["NAME_PVEL"] = FLUID_NAME_PVEL;
mRNAMap["NAME_PARTS"] = FLUID_NAME_PARTS;
mRNAMap["NAME_PARTSVELOCITY"] = FLUID_NAME_PARTSVELOCITY;
mRNAMap["NAME_PINDEX"] = FLUID_NAME_PINDEX;
mRNAMap["NAME_GPI"] = FLUID_NAME_GPI;
mRNAMap["NAME_CURVATURE"] = FLUID_NAME_CURVATURE;
/* Noise object names. */
mRNAMap["NAME_VELOCITY_NOISE"] = FLUID_NAME_VELOCITY_NOISE;
mRNAMap["NAME_DENSITY_NOISE"] = FLUID_NAME_DENSITY_NOISE;
mRNAMap["NAME_PHIIN_NOISE"] = FLUID_NAME_PHIIN_NOISE;
mRNAMap["NAME_PHIOUT_NOISE"] = FLUID_NAME_PHIOUT_NOISE;
mRNAMap["NAME_PHIOBS_NOISE"] = FLUID_NAME_PHIOBS_NOISE;
mRNAMap["NAME_FLAGS_NOISE"] = FLUID_NAME_FLAGS_NOISE;
mRNAMap["NAME_TMPIN_NOISE"] = FLUID_NAME_TMPIN_NOISE;
mRNAMap["NAME_EMISSIONIN_NOISE"] = FLUID_NAME_EMISSIONIN_NOISE;
mRNAMap["NAME_ENERGY"] = FLUID_NAME_ENERGY;
mRNAMap["NAME_TMPFLAGS"] = FLUID_NAME_TMPFLAGS;
mRNAMap["NAME_TEXTURE_U"] = FLUID_NAME_TEXTURE_U;
mRNAMap["NAME_TEXTURE_V"] = FLUID_NAME_TEXTURE_V;
mRNAMap["NAME_TEXTURE_W"] = FLUID_NAME_TEXTURE_W;
mRNAMap["NAME_TEXTURE_U2"] = FLUID_NAME_TEXTURE_U2;
mRNAMap["NAME_TEXTURE_V2"] = FLUID_NAME_TEXTURE_V2;
mRNAMap["NAME_TEXTURE_W2"] = FLUID_NAME_TEXTURE_W2;
mRNAMap["NAME_UV0"] = FLUID_NAME_UV0;
mRNAMap["NAME_UV1"] = FLUID_NAME_UV1;
mRNAMap["NAME_COLORR_NOISE"] = FLUID_NAME_COLORR_NOISE;
mRNAMap["NAME_COLORG_NOISE"] = FLUID_NAME_COLORG_NOISE;
mRNAMap["NAME_COLORB_NOISE"] = FLUID_NAME_COLORB_NOISE;
mRNAMap["NAME_FLAME_NOISE"] = FLUID_NAME_FLAME_NOISE;
mRNAMap["NAME_FUEL_NOISE"] = FLUID_NAME_FUEL_NOISE;
mRNAMap["NAME_REACT_NOISE"] = FLUID_NAME_REACT_NOISE;
/* Mesh object names. */
mRNAMap["NAME_PHIPARTS_MESH"] = FLUID_NAME_PHIPARTS_MESH;
mRNAMap["NAME_PHI_MESH"] = FLUID_NAME_PHI_MESH;
mRNAMap["NAME_PP_MESH"] = FLUID_NAME_PP_MESH;
mRNAMap["NAME_FLAGS_MESH"] = FLUID_NAME_FLAGS_MESH;
mRNAMap["NAME_LMESH"] = FLUID_NAME_LMESH;
mRNAMap["NAME_VELOCITYVEC_MESH"] = FLUID_NAME_VELOCITYVEC_MESH;
mRNAMap["NAME_VELOCITY_MESH"] = FLUID_NAME_VELOCITY_MESH;
mRNAMap["NAME_PINDEX_MESH"] = FLUID_NAME_PINDEX_MESH;
mRNAMap["NAME_GPI_MESH"] = FLUID_NAME_GPI_MESH;
/* Particles object names. */
mRNAMap["NAME_PP_PARTICLES"] = FLUID_NAME_PP_PARTICLES;
mRNAMap["NAME_PVEL_PARTICLES"] = FLUID_NAME_PVEL_PARTICLES;
mRNAMap["NAME_PFORCE_PARTICLES"] = FLUID_NAME_PFORCE_PARTICLES;
mRNAMap["NAME_PLIFE_PARTICLES"] = FLUID_NAME_PLIFE_PARTICLES;
mRNAMap["NAME_PARTS_PARTICLES"] = FLUID_NAME_PARTS_PARTICLES;
mRNAMap["NAME_PARTSVEL_PARTICLES"] = FLUID_NAME_PARTSVEL_PARTICLES;
mRNAMap["NAME_PARTSFORCE_PARTICLES"] = FLUID_NAME_PARTSFORCE_PARTICLES;
mRNAMap["NAME_PARTSLIFE_PARTICLES"] = FLUID_NAME_PARTSLIFE_PARTICLES;
mRNAMap["NAME_VELOCITY_PARTICLES"] = FLUID_NAME_VELOCITY_PARTICLES;
mRNAMap["NAME_FLAGS_PARTICLES"] = FLUID_NAME_FLAGS_PARTICLES;
mRNAMap["NAME_PHI_PARTICLES"] = FLUID_NAME_PHI_PARTICLES;
mRNAMap["NAME_PHIOBS_PARTICLES"] = FLUID_NAME_PHIOBS_PARTICLES;
mRNAMap["NAME_PHIOUT_PARTICLES"] = FLUID_NAME_PHIOUT_PARTICLES;
mRNAMap["NAME_NORMAL_PARTICLES"] = FLUID_NAME_NORMAL_PARTICLES;
mRNAMap["NAME_NEIGHBORRATIO_PARTICLES"] = FLUID_NAME_NEIGHBORRATIO_PARTICLES;
mRNAMap["NAME_TRAPPEDAIR_PARTICLES"] = FLUID_NAME_TRAPPEDAIR_PARTICLES;
mRNAMap["NAME_WAVECREST_PARTICLES"] = FLUID_NAME_WAVECREST_PARTICLES;
mRNAMap["NAME_KINETICENERGY_PARTICLES"] = FLUID_NAME_KINETICENERGY_PARTICLES;
/* Guiding object names. */
mRNAMap["NAME_VELT"] = FLUID_NAME_VELT;
mRNAMap["NAME_WEIGHTGUIDE"] = FLUID_NAME_WEIGHTGUIDE;
mRNAMap["NAME_NUMGUIDES"] = FLUID_NAME_NUMGUIDES;
mRNAMap["NAME_PHIGUIDEIN"] = FLUID_NAME_PHIGUIDEIN;
mRNAMap["NAME_GUIDEVELC"] = FLUID_NAME_GUIDEVELC;
mRNAMap["NAME_GUIDEVEL_X"] = FLUID_NAME_GUIDEVEL_X;
mRNAMap["NAME_GUIDEVEL_Y"] = FLUID_NAME_GUIDEVEL_Y;
mRNAMap["NAME_GUIDEVEL_Z"] = FLUID_NAME_GUIDEVEL_Z;
mRNAMap["NAME_VELOCITY_GUIDE"] = FLUID_NAME_VELOCITY_GUIDE;
/* Cache file names. */
mRNAMap["NAME_CONFIG"] = FLUID_NAME_CONFIG;
mRNAMap["NAME_DATA"] = FLUID_NAME_DATA;
mRNAMap["NAME_NOISE"] = FLUID_NAME_NOISE;
mRNAMap["NAME_MESH"] = FLUID_NAME_MESH;
mRNAMap["NAME_PARTICLES"] = FLUID_NAME_PARTICLES;
mRNAMap["NAME_GUIDING"] = FLUID_NAME_GUIDING;
}
string MANTA::getRealValue(const string &varName)
{
unordered_map<string, string>::iterator it;
it = mRNAMap.find(varName);
if (it == mRNAMap.end()) {
cerr << "Fluid Error -- variable " << varName << " not found in RNA map " << it->second
<< endl;
return "";
}
return it->second;
}
string MANTA::parseLine(const string &line)
{
if (line.size() == 0) {
return "";
}
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));
}
currPos++;
}
res += line.substr(end_del + 1, line.size() - end_del);
return res;
}
string MANTA::parseScript(const string &setup_string, FluidModifierData *fmd)
{
if (MANTA::with_debug) {
cout << "MANTA::parseScript()" << endl;
}
istringstream f(setup_string);
ostringstream res;
string line;
/* Update RNA map if modifier data is handed over. */
if (fmd) {
initializeRNAMap(fmd);
}
while (getline(f, line)) {
res << parseLine(line) << "\n";
}
return res.str();
}
/** Dirty hack: Needed to format paths from python code that is run via #PyRun_String. */
static string escapePath(string const &s)
{
string result;
for (char c : s) {
if (c == '\\') {
result += "\\\\";
}
else if (c == '\'') {
result += "\\\'";
}
else {
result += c;
}
}
return result;
}
bool MANTA::writeConfiguration(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::writeConfiguration()" << endl;
}
FluidDomainSettings *fds = fmd->domain;
string directory = getDirectory(fmd, FLUID_DOMAIN_DIR_CONFIG);
string format = FLUID_DOMAIN_EXTENSION_UNI;
string file = getFile(fmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_NAME_CONFIG, format, framenr);
/* Create 'config' subdir if it does not exist already. */
BLI_dir_create_recursive(directory.c_str());
/* Open new file with some compression. */
gzFile gzf = (gzFile)BLI_gzopen(file.c_str(), "wb1");
if (!gzf) {
cerr << "Fluid Error -- Cannot open file " << file << endl;
return false;
}
gzwrite(gzf, &fds->active_fields, sizeof(int));
gzwrite(gzf, &fds->res, 3 * sizeof(int));
gzwrite(gzf, &fds->dx, sizeof(float));
gzwrite(gzf, &fds->dt, sizeof(float));
gzwrite(gzf, &fds->p0, 3 * sizeof(float));
gzwrite(gzf, &fds->p1, 3 * sizeof(float));
gzwrite(gzf, &fds->dp0, 3 * sizeof(float));
gzwrite(gzf, &fds->shift, 3 * sizeof(int));
gzwrite(gzf, &fds->obj_shift_f, 3 * sizeof(float));
gzwrite(gzf, &fds->obmat, 16 * sizeof(float));
gzwrite(gzf, &fds->base_res, 3 * sizeof(int));
gzwrite(gzf, &fds->res_min, 3 * sizeof(int));
gzwrite(gzf, &fds->res_max, 3 * sizeof(int));
gzwrite(gzf, &fds->active_color, 3 * sizeof(float));
gzwrite(gzf, &fds->time_total, sizeof(int));
gzwrite(gzf, &FLUID_CACHE_VERSION, 4 * sizeof(char));
return (gzclose(gzf) == Z_OK);
}
bool MANTA::writeData(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::writeData()" << endl;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
string directory = getDirectory(fmd, FLUID_DOMAIN_DIR_DATA);
string volume_format = getCacheFileEnding(fds->cache_data_format);
string resumable_cache = !(fds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE) ? "False" : "True";
if (mUsingSmoke) {
ss.str("");
ss << "smoke_save_data_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
}
if (mUsingLiquid) {
ss.str("");
ss << "liquid_save_data_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
}
return runPythonString(pythonCommands);
}
bool MANTA::writeNoise(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::writeNoise()" << endl;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
string directory = getDirectory(fmd, FLUID_DOMAIN_DIR_NOISE);
string volume_format = getCacheFileEnding(fds->cache_data_format);
string resumable_cache = !(fds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE) ? "False" : "True";
if (mUsingSmoke && mUsingNoise) {
ss.str("");
ss << "smoke_save_noise_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
}
return runPythonString(pythonCommands);
}
bool MANTA::readConfiguration(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::readConfiguration()" << endl;
}
FluidDomainSettings *fds = fmd->domain;
float dummy;
string directory = getDirectory(fmd, FLUID_DOMAIN_DIR_CONFIG);
string format = FLUID_DOMAIN_EXTENSION_UNI;
string file = getFile(fmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_NAME_CONFIG, format, framenr);
if (!hasConfig(fmd, framenr)) {
return false;
}
gzFile gzf = (gzFile)BLI_gzopen(file.c_str(), "rb"); /* Do some compression. */
if (!gzf) {
cerr << "Fluid Error -- Cannot open file " << file << endl;
return false;
}
gzread(gzf, &fds->active_fields, sizeof(int));
gzread(gzf, &fds->res, 3 * sizeof(int));
gzread(gzf, &fds->dx, sizeof(float));
gzread(gzf, &dummy, sizeof(float)); /* dt not needed right now. */
gzread(gzf, &fds->p0, 3 * sizeof(float));
gzread(gzf, &fds->p1, 3 * sizeof(float));
gzread(gzf, &fds->dp0, 3 * sizeof(float));
gzread(gzf, &fds->shift, 3 * sizeof(int));
gzread(gzf, &fds->obj_shift_f, 3 * sizeof(float));
gzread(gzf, &fds->obmat, 16 * sizeof(float));
gzread(gzf, &fds->base_res, 3 * sizeof(int));
gzread(gzf, &fds->res_min, 3 * sizeof(int));
gzread(gzf, &fds->res_max, 3 * sizeof(int));
gzread(gzf, &fds->active_color, 3 * sizeof(float));
gzread(gzf, &fds->time_total, sizeof(int));
gzread(gzf, &fds->cache_id, 4 * sizeof(char)); /* Older caches might have no id. */
fds->total_cells = fds->res[0] * fds->res[1] * fds->res[2];
return (gzclose(gzf) == Z_OK);
}
bool MANTA::readData(FluidModifierData *fmd, int framenr, bool resumable)
{
if (with_debug) {
cout << "MANTA::readData()" << endl;
}
if (!mUsingSmoke && !mUsingLiquid) {
return false;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
bool result = true;
string directory = getDirectory(fmd, FLUID_DOMAIN_DIR_DATA);
string volume_format = getCacheFileEnding(fds->cache_data_format);
string resumable_cache = (!resumable) ? "False" : "True";
/* Sanity check: Are cache files present? */
if (!hasData(fmd, framenr)) {
return false;
}
if (mUsingSmoke) {
ss.str("");
ss << "smoke_load_data_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
result &= runPythonString(pythonCommands);
return (mSmokeFromFile = result);
}
if (mUsingLiquid) {
ss.str("");
ss << "liquid_load_data_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
result &= runPythonString(pythonCommands);
return (mFlipFromFile = result);
}
return result;
}
bool MANTA::readNoise(FluidModifierData *fmd, int framenr, bool resumable)
{
if (with_debug) {
cout << "MANTA::readNoise()" << endl;
}
if (!mUsingSmoke || !mUsingNoise) {
return false;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
string directory = getDirectory(fmd, FLUID_DOMAIN_DIR_NOISE);
string resumable_cache = (!resumable) ? "False" : "True";
/* Support older caches which had more granular file format control. */
char format = (!strcmp(fds->cache_id, FLUID_CACHE_VERSION)) ? fds->cache_data_format :
fds->cache_noise_format;
string volume_format = getCacheFileEnding(format);
/* Sanity check: Are cache files present? */
if (!hasNoise(fmd, framenr)) {
return false;
}
ss.str("");
ss << "smoke_load_noise_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
return (mNoiseFromFile = runPythonString(pythonCommands));
}
bool MANTA::readMesh(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::readMesh()" << endl;
}
if (!mUsingLiquid || !mUsingMesh) {
return false;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
string directory = getDirectory(fmd, FLUID_DOMAIN_DIR_MESH);
string mesh_format = getCacheFileEnding(fds->cache_mesh_format);
string volume_format = getCacheFileEnding(fds->cache_data_format);
/* Sanity check: Are cache files present? */
if (!hasMesh(fmd, framenr)) {
return false;
}
ss.str("");
ss << "liquid_load_mesh_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << mesh_format << "')";
pythonCommands.push_back(ss.str());
if (mUsingMVel) {
ss.str("");
ss << "liquid_load_meshvel_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "')";
pythonCommands.push_back(ss.str());
}
return (mMeshFromFile = runPythonString(pythonCommands));
}
bool MANTA::readParticles(FluidModifierData *fmd, int framenr, bool resumable)
{
if (with_debug) {
cout << "MANTA::readParticles()" << endl;
}
if (!mUsingLiquid) {
return false;
}
if (!mUsingDrops && !mUsingBubbles && !mUsingFloats && !mUsingTracers) {
return false;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
string directory = getDirectory(fmd, FLUID_DOMAIN_DIR_PARTICLES);
string resumable_cache = (!resumable) ? "False" : "True";
/* Support older caches which had more granular file format control. */
char format = (!strcmp(fds->cache_id, FLUID_CACHE_VERSION)) ? fds->cache_data_format :
fds->cache_particle_format;
string volume_format = getCacheFileEnding(format);
/* Sanity check: Are cache files present? */
if (!hasParticles(fmd, framenr)) {
return false;
}
ss.str("");
ss << "liquid_load_particles_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
return (mParticlesFromFile = runPythonString(pythonCommands));
}
bool MANTA::readGuiding(FluidModifierData *fmd, int framenr, bool sourceDomain)
{
if (with_debug) {
cout << "MANTA::readGuiding()" << endl;
}
if (!mUsingGuiding) {
return false;
}
if (!fmd) {
return false;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
string directory = (sourceDomain) ? getDirectory(fmd, FLUID_DOMAIN_DIR_DATA) :
getDirectory(fmd, FLUID_DOMAIN_DIR_GUIDE);
string volume_format = getCacheFileEnding(fds->cache_data_format);
/* Sanity check: Are cache files present? */
if (!hasGuiding(fmd, framenr, sourceDomain)) {
return false;
}
if (sourceDomain) {
ss.str("");
ss << "fluid_load_vel_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "')";
}
else {
ss.str("");
ss << "fluid_load_guiding_" << mCurrentID << "('" << escapePath(directory) << "', " << framenr
<< ", '" << volume_format << "')";
}
pythonCommands.push_back(ss.str());
return runPythonString(pythonCommands);
}
bool MANTA::bakeData(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::bakeData()" << endl;
}
string tmpString, finalString;
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
char cacheDirData[FILE_MAX], cacheDirGuiding[FILE_MAX];
cacheDirData[0] = '\0';
cacheDirGuiding[0] = '\0';
string volume_format = getCacheFileEnding(fds->cache_data_format);
BLI_path_join(cacheDirData, sizeof(cacheDirData), fds->cache_directory, FLUID_DOMAIN_DIR_DATA);
BLI_path_join(
cacheDirGuiding, sizeof(cacheDirGuiding), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_make_safe(cacheDirData);
BLI_path_make_safe(cacheDirGuiding);
ss.str("");
ss << "bake_fluid_data_" << mCurrentID << "('" << escapePath(cacheDirData) << "', " << framenr
<< ", '" << volume_format << "')";
pythonCommands.push_back(ss.str());
return runPythonString(pythonCommands);
}
bool MANTA::bakeNoise(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::bakeNoise()" << endl;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
char cacheDirNoise[FILE_MAX];
cacheDirNoise[0] = '\0';
string volume_format = getCacheFileEnding(fds->cache_data_format);
BLI_path_join(
cacheDirNoise, sizeof(cacheDirNoise), fds->cache_directory, FLUID_DOMAIN_DIR_NOISE);
BLI_path_make_safe(cacheDirNoise);
ss.str("");
ss << "bake_noise_" << mCurrentID << "('" << escapePath(cacheDirNoise) << "', " << framenr
<< ", '" << volume_format << "')";
pythonCommands.push_back(ss.str());
return runPythonString(pythonCommands);
}
bool MANTA::bakeMesh(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::bakeMesh()" << endl;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
char cacheDirMesh[FILE_MAX];
cacheDirMesh[0] = '\0';
string volume_format = getCacheFileEnding(fds->cache_data_format);
string mesh_format = getCacheFileEnding(fds->cache_mesh_format);
BLI_path_join(cacheDirMesh, sizeof(cacheDirMesh), fds->cache_directory, FLUID_DOMAIN_DIR_MESH);
BLI_path_make_safe(cacheDirMesh);
ss.str("");
ss << "bake_mesh_" << mCurrentID << "('" << escapePath(cacheDirMesh) << "', " << framenr << ", '"
<< volume_format << "', '" << mesh_format << "')";
pythonCommands.push_back(ss.str());
return runPythonString(pythonCommands);
}
bool MANTA::bakeParticles(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::bakeParticles()" << endl;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
char cacheDirParticles[FILE_MAX];
cacheDirParticles[0] = '\0';
string volume_format = getCacheFileEnding(fds->cache_data_format);
string resumable_cache = !(fds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE) ? "False" : "True";
BLI_path_join(cacheDirParticles,
sizeof(cacheDirParticles),
fds->cache_directory,
FLUID_DOMAIN_DIR_PARTICLES);
BLI_path_make_safe(cacheDirParticles);
ss.str("");
ss << "bake_particles_" << mCurrentID << "('" << escapePath(cacheDirParticles) << "', "
<< framenr << ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
return runPythonString(pythonCommands);
}
bool MANTA::bakeGuiding(FluidModifierData *fmd, int framenr)
{
if (with_debug) {
cout << "MANTA::bakeGuiding()" << endl;
}
ostringstream ss;
vector<string> pythonCommands;
FluidDomainSettings *fds = fmd->domain;
char cacheDirGuiding[FILE_MAX];
cacheDirGuiding[0] = '\0';
string volume_format = getCacheFileEnding(fds->cache_data_format);
string resumable_cache = !(fds->flags & FLUID_DOMAIN_USE_RESUMABLE_CACHE) ? "False" : "True";
BLI_path_join(
cacheDirGuiding, sizeof(cacheDirGuiding), fds->cache_directory, FLUID_DOMAIN_DIR_GUIDE);
BLI_path_make_safe(cacheDirGuiding);
ss.str("");
ss << "bake_guiding_" << mCurrentID << "('" << escapePath(cacheDirGuiding) << "', " << framenr
<< ", '" << volume_format << "', " << resumable_cache << ")";
pythonCommands.push_back(ss.str());
return runPythonString(pythonCommands);
}
bool MANTA::updateVariables(FluidModifierData *fmd)
{
string tmpString, finalString;
vector<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, fmd);
pythonCommands.push_back(finalString);
return runPythonString(pythonCommands);
}
bool MANTA::exportSmokeScript(FluidModifierData *fmd)
{
if (with_debug) {
cout << "MANTA::exportSmokeScript()" << endl;
}
char cacheDir[FILE_MAX] = "\0";
char cacheDirScript[FILE_MAX] = "\0";
FluidDomainSettings *fds = fmd->domain;
BLI_path_join(cacheDir, sizeof(cacheDir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_make_safe(cacheDir);
/* Create 'script' subdir if it does not exist already */
BLI_dir_create_recursive(cacheDir);
BLI_path_join(cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_SMOKE_SCRIPT);
BLI_path_make_safe(cacheDir);
bool noise = fds->flags & FLUID_DOMAIN_USE_NOISE;
bool heat = fds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT;
bool colors = fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS;
bool fire = fds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE;
bool obstacle = fds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
bool guiding = fds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
bool invel = fds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
bool outflow = fds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW;
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;
}
if (outflow) {
manta_script += fluid_alloc_outflow;
}
/* 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 + 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. */
string final_script = MANTA::parseScript(manta_script, fmd);
/* Write script. */
ofstream myfile;
myfile.open(cacheDirScript);
myfile << final_script;
myfile.close();
if (!myfile) {
cerr << "Fluid Error -- Could not export standalone Mantaflow smoke domain script";
return false;
}
return true;
}
bool MANTA::exportLiquidScript(FluidModifierData *fmd)
{
if (with_debug) {
cout << "MANTA::exportLiquidScript()" << endl;
}
char cacheDir[FILE_MAX] = "\0";
char cacheDirScript[FILE_MAX] = "\0";
FluidDomainSettings *fds = fmd->domain;
BLI_path_join(cacheDir, sizeof(cacheDir), fds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT);
BLI_path_make_safe(cacheDir);
/* Create 'script' subdir if it does not exist already */
BLI_dir_create_recursive(cacheDir);
BLI_path_join(cacheDirScript, sizeof(cacheDirScript), cacheDir, FLUID_DOMAIN_LIQUID_SCRIPT);
BLI_path_make_safe(cacheDirScript);
bool mesh = fds->flags & FLUID_DOMAIN_USE_MESH;
bool drops = fds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY;
bool bubble = fds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
bool floater = fds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
bool tracer = fds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER;
bool obstacle = fds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
bool fractions = fds->flags & FLUID_DOMAIN_USE_FRACTIONS;
bool guiding = fds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
bool invel = fds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
bool outflow = fds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW;
bool viscosity = fds->flags & FLUID_DOMAIN_USE_VISCOSITY;
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;
}
if (viscosity) {
manta_script += fluid_variables_viscosity;
}
/* 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;
}
if (viscosity) {
manta_script += fluid_solver_viscosity;
}
/* Grids. */
manta_script += header_grids + fluid_alloc + liquid_alloc;
if (mesh) {
manta_script += liquid_alloc_mesh;
}
if (drops || bubble || floater || tracer) {
manta_script += liquid_alloc_particles;
}
if (guiding) {
manta_script += fluid_alloc_guiding;
}
if (obstacle) {
manta_script += fluid_alloc_obstacle;
}
if (fractions) {
manta_script += fluid_alloc_fractions;
}
if (invel) {
manta_script += fluid_alloc_invel;
}
if (outflow) {
manta_script += fluid_alloc_outflow;
}
if (viscosity) {
manta_script += liquid_alloc_viscosity;
}
/* 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 + liquid_load_data;
if (mesh) {
manta_script += liquid_load_mesh;
}
if (drops || bubble || floater || tracer) {
manta_script += 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. */
string final_script = MANTA::parseScript(manta_script, fmd);
/* Write script. */
ofstream myfile;
myfile.open(cacheDirScript);
myfile << final_script;
myfile.close();
if (!myfile) {
cerr << "Fluid Error -- Could not export standalone Mantaflow liquid domain script";
return false;
}
return true;
}
/* 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) or
* grid.getDataPointer (here 's' is varname, 'getDataPointer' functionName, and isAttribute
* false)
*
* Important! Return value: New reference or nullptr
* Caller of this function needs to handle reference count of returned object. */
static PyObject *callPythonFunction(string varName, string functionName, bool isAttribute = false)
{
if ((varName == "") || (functionName == "")) {
if (MANTA::with_debug) {
cout << "Fluid: Missing Python variable name and/or function name -- name is: " << varName
<< ", function name is: " << functionName << endl;
}
return nullptr;
}
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *var = nullptr, *func = nullptr, *returnedValue = nullptr;
/* Be sure to initialize Python before using it. */
Py_Initialize();
/* Get pyobject that holds result value. */
if (!manta_main_module) {
PyGILState_Release(gilstate);
return nullptr;
}
/* Ensure that requested variable is present in module - avoid attribute errors later on. */
if (!PyObject_HasAttrString(manta_main_module, varName.c_str())) {
PyGILState_Release(gilstate);
return nullptr;
}
var = PyObject_GetAttrString(manta_main_module, varName.c_str());
if (!var) {
PyGILState_Release(gilstate);
return nullptr;
}
func = PyObject_GetAttrString(var, functionName.c_str());
Py_DECREF(var);
if (!func) {
PyGILState_Release(gilstate);
return nullptr;
}
if (!isAttribute) {
returnedValue = PyObject_CallObject(func, nullptr);
Py_DECREF(func);
}
PyGILState_Release(gilstate);
return (!isAttribute) ? returnedValue : func;
}
/* Argument of this function may be a nullptr.
* If it's not function will handle the reference count decrement of that argument. */
static void *pyObjectToPointer(PyObject *inputObject)
{
if (!inputObject) {
return nullptr;
}
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *encoded = PyUnicode_AsUTF8String(inputObject);
char *result = PyBytes_AsString(encoded);
Py_DECREF(inputObject);
string str(result);
istringstream in(str);
void *dataPointer = nullptr;
in >> dataPointer;
Py_DECREF(encoded);
PyGILState_Release(gilstate);
return dataPointer;
}
/* Argument of this function may be a nullptr.
* If it's not function will handle the reference count decrement of that argument. */
static double pyObjectToDouble(PyObject *inputObject)
{
if (!inputObject) {
return 0.0;
}
PyGILState_STATE gilstate = PyGILState_Ensure();
/* Cannot use PyFloat_AsDouble() since its error check crashes.
* Likely because of typedef 'Real' for 'float' types in Mantaflow. */
double result = PyFloat_AS_DOUBLE(inputObject);
Py_DECREF(inputObject);
PyGILState_Release(gilstate);
return result;
}
/* Argument of this function may be a nullptr.
* If it's not function will handle the reference count decrement of that argument. */
static long pyObjectToLong(PyObject *inputObject)
{
if (!inputObject) {
return 0;
}
PyGILState_STATE gilstate = PyGILState_Ensure();
long result = PyLong_AsLong(inputObject);
Py_DECREF(inputObject);
PyGILState_Release(gilstate);
return result;
}
template<class T> static T *getPointer(string pyObjectName, string pyFunctionName)
{
return static_cast<T *>(pyObjectToPointer(callPythonFunction(pyObjectName, pyFunctionName)));
}
int MANTA::getFrame()
{
if (with_debug) {
cout << "MANTA::getFrame()" << endl;
}
string func = "frame";
string id = to_string(mCurrentID);
string solver = "s" + id;
return pyObjectToLong(callPythonFunction(solver, func, true));
}
float MANTA::getTimestep()
{
if (with_debug) {
cout << "MANTA::getTimestep()" << endl;
}
string func = "timestep";
string id = to_string(mCurrentID);
string solver = "s" + id;
return (float)pyObjectToDouble(callPythonFunction(solver, func, true));
}
bool MANTA::needsRealloc(FluidModifierData *fmd)
{
FluidDomainSettings *fds = fmd->domain;
return ((fds->res_max[0] - fds->res_min[0]) != mResX ||
(fds->res_max[1] - fds->res_min[1]) != mResY ||
(fds->res_max[2] - fds->res_min[2]) != mResZ);
}
void MANTA::adaptTimestep()
{
if (with_debug) {
cout << "MANTA::adaptTimestep()" << endl;
}
vector<string> pythonCommands;
ostringstream ss;
ss << "fluid_adapt_time_step_" << mCurrentID << "()";
pythonCommands.push_back(ss.str());
runPythonString(pythonCommands);
}
void MANTA::updatePointers(FluidModifierData *fmd, bool flush)
{
if (with_debug) {
cout << "MANTA::updatePointers()" << endl;
}
FluidDomainSettings *fds = fmd->domain;
bool liquid = !flush && (fds->type == FLUID_DOMAIN_TYPE_LIQUID);
bool smoke = !flush && (fds->type == FLUID_DOMAIN_TYPE_GAS);
bool noise = !flush && smoke && fds->flags & FLUID_DOMAIN_USE_NOISE;
bool heat = !flush && smoke && fds->active_fields & FLUID_DOMAIN_ACTIVE_HEAT;
bool colors = !flush && smoke && fds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS;
bool fire = !flush && smoke && fds->active_fields & FLUID_DOMAIN_ACTIVE_FIRE;
bool obstacle = !flush && fds->active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE;
bool guiding = !flush && fds->active_fields & FLUID_DOMAIN_ACTIVE_GUIDE;
bool invel = !flush && fds->active_fields & FLUID_DOMAIN_ACTIVE_INVEL;
bool outflow = !flush && fds->active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW;
bool drops = !flush && liquid && fds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY;
bool bubble = !flush && liquid && fds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE;
bool floater = !flush && liquid && fds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM;
bool tracer = !flush && liquid && fds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER;
bool parts = !flush && liquid && (drops | bubble | floater | tracer);
bool mesh = !flush && liquid && fds->flags & FLUID_DOMAIN_USE_MESH;
bool meshvel = !flush && liquid && mesh && fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
string func = "getDataPointer";
string funcNodes = "getNodesDataPointer";
string funcTris = "getTrisDataPointer";
string id = to_string(mCurrentID);
string s_ext = "_s" + id;
string pp_ext = "_pp" + id;
string snd_ext = "_sp" + id;
string sm_ext = "_sm" + id;
string mesh_ext = "_mesh" + id;
string sn_ext = "_sn" + id;
mFlags = (smoke || liquid) ? getPointer<int>("flags" + s_ext, func) : nullptr;
mPhiIn = (smoke || liquid) ? getPointer<float>("phiIn" + s_ext, func) : nullptr;
mPhiStaticIn = (smoke || liquid) ? getPointer<float>("phiSIn" + s_ext, func) : nullptr;
mVelocityX = (smoke || liquid) ? getPointer<float>("x_vel" + s_ext, func) : nullptr;
mVelocityY = (smoke || liquid) ? getPointer<float>("y_vel" + s_ext, func) : nullptr;
mVelocityZ = (smoke || liquid) ? getPointer<float>("z_vel" + s_ext, func) : nullptr;
mForceX = (smoke || liquid) ? getPointer<float>("x_force" + s_ext, func) : nullptr;
mForceY = (smoke || liquid) ? getPointer<float>("y_force" + s_ext, func) : nullptr;
mForceZ = (smoke || liquid) ? getPointer<float>("z_force" + s_ext, func) : nullptr;
mPressure = (smoke || liquid) ? getPointer<float>("pressure" + s_ext, func) : nullptr;
/* Outflow. */
mPhiOutIn = (outflow) ? getPointer<float>("phiOutIn" + s_ext, func) : nullptr;
mPhiOutStaticIn = (outflow) ? getPointer<float>("phiOutSIn" + s_ext, func) : nullptr;
/* Obstacles. */
mPhiObsIn = (obstacle) ? getPointer<float>("phiObsIn" + s_ext, func) : nullptr;
mPhiObsStaticIn = (obstacle) ? getPointer<float>("phiObsSIn" + s_ext, func) : nullptr;
mObVelocityX = (obstacle) ? getPointer<float>("x_obvel" + s_ext, func) : nullptr;
mObVelocityY = (obstacle) ? getPointer<float>("y_obvel" + s_ext, func) : nullptr;
mObVelocityZ = (obstacle) ? getPointer<float>("z_obvel" + s_ext, func) : nullptr;
mNumObstacle = (obstacle) ? getPointer<float>("numObs" + s_ext, func) : nullptr;
/* Guiding. */
mPhiGuideIn = (guiding) ? getPointer<float>("phiGuideIn" + s_ext, func) : nullptr;
mGuideVelocityX = (guiding) ? getPointer<float>("x_guidevel" + s_ext, func) : nullptr;
mGuideVelocityY = (guiding) ? getPointer<float>("y_guidevel" + s_ext, func) : nullptr;
mGuideVelocityZ = (guiding) ? getPointer<float>("z_guidevel" + s_ext, func) : nullptr;
mNumGuide = (guiding) ? getPointer<float>("numGuides" + s_ext, func) : nullptr;
/* Initial velocities. */
mInVelocityX = (invel) ? getPointer<float>("x_invel" + s_ext, func) : nullptr;
mInVelocityY = (invel) ? getPointer<float>("y_invel" + s_ext, func) : nullptr;
mInVelocityZ = (invel) ? getPointer<float>("z_invel" + s_ext, func) : nullptr;
/* Smoke. */
mDensity = (smoke) ? getPointer<float>("density" + s_ext, func) : nullptr;
mDensityIn = (smoke) ? getPointer<float>("densityIn" + s_ext, func) : nullptr;
mShadow = (smoke) ? getPointer<float>("shadow" + s_ext, func) : nullptr;
mEmissionIn = (smoke) ? getPointer<float>("emissionIn" + s_ext, func) : nullptr;
/* Heat. */
mHeat = (heat) ? getPointer<float>("heat" + s_ext, func) : nullptr;
mHeatIn = (heat) ? getPointer<float>("heatIn" + s_ext, func) : nullptr;
/* Fire. */
mFlame = (fire) ? getPointer<float>("flame" + s_ext, func) : nullptr;
mFuel = (fire) ? getPointer<float>("fuel" + s_ext, func) : nullptr;
mReact = (fire) ? getPointer<float>("react" + s_ext, func) : nullptr;
mFuelIn = (fire) ? getPointer<float>("fuelIn" + s_ext, func) : nullptr;
mReactIn = (fire) ? getPointer<float>("reactIn" + s_ext, func) : nullptr;
/* Colors. */
mColorR = (colors) ? getPointer<float>("color_r" + s_ext, func) : nullptr;
mColorG = (colors) ? getPointer<float>("color_g" + s_ext, func) : nullptr;
mColorB = (colors) ? getPointer<float>("color_b" + s_ext, func) : nullptr;
mColorRIn = (colors) ? getPointer<float>("color_r_in" + s_ext, func) : nullptr;
mColorGIn = (colors) ? getPointer<float>("color_g_in" + s_ext, func) : nullptr;
mColorBIn = (colors) ? getPointer<float>("color_b_in" + s_ext, func) : nullptr;
/* Noise. */
mDensityHigh = (noise) ? getPointer<float>("density" + sn_ext, func) : nullptr;
mTextureU = (noise) ? getPointer<float>("texture_u" + s_ext, func) : nullptr;
mTextureV = (noise) ? getPointer<float>("texture_v" + s_ext, func) : nullptr;
mTextureW = (noise) ? getPointer<float>("texture_w" + s_ext, func) : nullptr;
mTextureU2 = (noise) ? getPointer<float>("texture_u2" + s_ext, func) : nullptr;
mTextureV2 = (noise) ? getPointer<float>("texture_v2" + s_ext, func) : nullptr;
mTextureW2 = (noise) ? getPointer<float>("texture_w2" + s_ext, func) : nullptr;
/* Fire with noise. */
mFlameHigh = (noise && fire) ? getPointer<float>("flame" + sn_ext, func) : nullptr;
mFuelHigh = (noise && fire) ? getPointer<float>("fuel" + sn_ext, func) : nullptr;
mReactHigh = (noise && fire) ? getPointer<float>("react" + sn_ext, func) : nullptr;
/* Colors with noise. */
mColorRHigh = (noise && colors) ? getPointer<float>("color_r" + sn_ext, func) : nullptr;
mColorGHigh = (noise && colors) ? getPointer<float>("color_g" + sn_ext, func) : nullptr;
mColorBHigh = (noise && colors) ? getPointer<float>("color_b" + sn_ext, func) : nullptr;
/* Liquid. */
mPhi = (liquid) ? getPointer<float>("phi" + s_ext, func) : nullptr;
mFlipParticleData = (liquid) ? getPointer<vector<pData>>("pp" + s_ext, func) : nullptr;
mFlipParticleVelocity = (liquid) ? getPointer<vector<pVel>>("pVel" + pp_ext, func) : nullptr;
/* Mesh. */
mMeshNodes = (mesh) ? getPointer<vector<Node>>("mesh" + sm_ext, funcNodes) : nullptr;
mMeshTriangles = (mesh) ? getPointer<vector<Triangle>>("mesh" + sm_ext, funcTris) : nullptr;
/* Mesh velocities. */
mMeshVelocities = (meshvel) ? getPointer<vector<pVel>>("mVel" + mesh_ext, func) : nullptr;
/* Secondary particles. */
mParticleData = (parts) ? getPointer<vector<pData>>("ppSnd" + snd_ext, func) : nullptr;
mParticleVelocity = (parts) ? getPointer<vector<pVel>>("pVelSnd" + pp_ext, func) : nullptr;
mParticleLife = (parts) ? getPointer<vector<float>>("pLifeSnd" + pp_ext, func) : nullptr;
mFlipFromFile = false;
mMeshFromFile = false;
mParticlesFromFile = false;
mSmokeFromFile = false;
mNoiseFromFile = false;
}
bool MANTA::hasConfig(FluidModifierData *fmd, int framenr)
{
string extension = FLUID_DOMAIN_EXTENSION_UNI;
return BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_CONFIG, FLUID_NAME_CONFIG, extension, framenr).c_str());
}
bool MANTA::hasData(FluidModifierData *fmd, int framenr)
{
string extension = getCacheFileEnding(fmd->domain->cache_data_format);
bool exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_DATA, FLUID_NAME_DATA, extension, framenr).c_str());
/* Check single file naming. */
if (!exists) {
string filename = (mUsingSmoke) ? FLUID_NAME_DENSITY : FLUID_NAME_PP;
exists = BLI_exists(getFile(fmd, FLUID_DOMAIN_DIR_DATA, filename, extension, framenr).c_str());
}
if (with_debug) {
cout << "Fluid: Has Data: " << exists << endl;
}
return exists;
}
bool MANTA::hasNoise(FluidModifierData *fmd, int framenr)
{
string extension = getCacheFileEnding(fmd->domain->cache_data_format);
bool exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_NOISE, FLUID_NAME_NOISE, extension, framenr).c_str());
/* Check single file naming. */
if (!exists) {
extension = getCacheFileEnding(fmd->domain->cache_data_format);
exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_NOISE, FLUID_NAME_DENSITY_NOISE, extension, framenr)
.c_str());
}
/* Check single file naming with deprecated extension. */
if (!exists) {
extension = getCacheFileEnding(fmd->domain->cache_noise_format);
exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_NOISE, FLUID_NAME_DENSITY_NOISE, extension, framenr)
.c_str());
}
if (with_debug) {
cout << "Fluid: Has Noise: " << exists << endl;
}
return exists;
}
bool MANTA::hasMesh(FluidModifierData *fmd, int framenr)
{
string extension = getCacheFileEnding(fmd->domain->cache_mesh_format);
bool exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_MESH, FLUID_NAME_MESH, extension, framenr).c_str());
/* Check old file naming. */
if (!exists) {
exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_MESH, FLUID_NAME_LMESH, extension, framenr).c_str());
}
if (with_debug) {
cout << "Fluid: Has Mesh: " << exists << endl;
}
return exists;
}
bool MANTA::hasParticles(FluidModifierData *fmd, int framenr)
{
string extension = getCacheFileEnding(fmd->domain->cache_data_format);
bool exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_NAME_PARTICLES, extension, framenr).c_str());
/* Check single file naming. */
if (!exists) {
extension = getCacheFileEnding(fmd->domain->cache_data_format);
exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_NAME_PP_PARTICLES, extension, framenr)
.c_str());
}
/* Check single file naming with deprecated extension. */
if (!exists) {
extension = getCacheFileEnding(fmd->domain->cache_particle_format);
exists = BLI_exists(
getFile(fmd, FLUID_DOMAIN_DIR_PARTICLES, FLUID_NAME_PP_PARTICLES, extension, framenr)
.c_str());
}
if (with_debug) {
cout << "Fluid: Has Particles: " << exists << endl;
}
return exists;
}
bool MANTA::hasGuiding(FluidModifierData *fmd, int framenr, bool sourceDomain)
{
string subdirectory = (sourceDomain) ? FLUID_DOMAIN_DIR_DATA : FLUID_DOMAIN_DIR_GUIDE;
string filename = (sourceDomain) ? FLUID_NAME_DATA : FLUID_NAME_GUIDING;
string extension = getCacheFileEnding(fmd->domain->cache_data_format);
bool exists = BLI_exists(getFile(fmd, subdirectory, filename, extension, framenr).c_str());
/* Check old file naming. */
if (!exists) {
filename = (sourceDomain) ? FLUID_NAME_VEL : FLUID_NAME_GUIDEVEL;
exists = BLI_exists(getFile(fmd, subdirectory, filename, extension, framenr).c_str());
}
if (with_debug) {
cout << "Fluid: Has Guiding: " << exists << endl;
}
return exists;
}
string MANTA::getDirectory(FluidModifierData *fmd, string subdirectory)
{
char directory[FILE_MAX];
BLI_path_join(directory, sizeof(directory), fmd->domain->cache_directory, subdirectory.c_str());
BLI_path_make_safe(directory);
return directory;
}
string MANTA::getFile(
FluidModifierData *fmd, string subdirectory, string fname, string extension, int framenr)
{
char targetFile[FILE_MAX];
string path = getDirectory(fmd, subdirectory);
string filename = fname + "_####" + extension;
BLI_path_join(targetFile, sizeof(targetFile), path.c_str(), filename.c_str());
BLI_path_frame(targetFile, sizeof(targetFile), framenr, 0);
return targetFile;
}