2446 lines
81 KiB
C++
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;
|
|
}
|