diff options
author | Jacques Lucke <mail@jlucke.com> | 2019-12-17 11:34:13 +0300 |
---|---|---|
committer | Jacques Lucke <mail@jlucke.com> | 2019-12-17 11:34:13 +0300 |
commit | 9a3b3700615e21fd84ec4204962f010e14b2fc43 (patch) | |
tree | 1b073a2a0cd8de2829cf22561b964fd9791acaed /source | |
parent | 2b84a7d5b07ff7883997f520b16b467da74515c4 (diff) | |
parent | 7d2d2ffa76647871836f779f013c99e474228f3d (diff) |
Merge branch 'master' into functions
Diffstat (limited to 'source')
149 files changed, 10506 insertions, 9638 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 9de4c901a3e..22ed2eff2a9 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -32,12 +32,14 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_constraint_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curve_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curveprofile_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_customdata_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defs.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_dynamicpaint_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_effect_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fileglobal_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fluid_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_freestyle_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_genfile.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h @@ -68,14 +70,12 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_outliner_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_packedFile_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_particle_types.h - ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curveprofile_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_rigidbody_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_scene_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_screen_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sdna_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sequence_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_shader_fx_types.h - ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_smoke_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_sound_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_space_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_speaker_types.h diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index d422a3c023e..5d9f92432d1 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -42,6 +42,7 @@ extern "C" { #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" /* for FILE_MAX */ +#include "DNA_fluid_types.h" #include "BLI_string.h" @@ -105,11 +106,12 @@ ExportSettings::ExportSettings() static bool object_is_smoke_sim(Object *ob) { - ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke); + ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid); if (md) { - SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md); - return (smd->type == MOD_SMOKE_TYPE_DOMAIN); + FluidModifierData *smd = reinterpret_cast<FluidModifierData *>(md); + return (smd->type == MOD_FLUID_TYPE_DOMAIN && smd->domain && + smd->domain->type == FLUID_DOMAIN_TYPE_GAS); } return false; @@ -553,7 +555,10 @@ void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *x m_settings.export_child_hairs = true; m_shapes.push_back(new AbcHairWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); } - else if (m_settings.export_particles && psys->part->type == PART_EMITTER) { + else if (m_settings.export_particles && + (psys->part->type & PART_EMITTER || psys->part->type & PART_FLUID_FLIP || + psys->part->type & PART_FLUID_SPRAY || psys->part->type & PART_FLUID_BUBBLE || + psys->part->type & PART_FLUID_FOAM || psys->part->type & PART_FLUID_TRACER)) { m_shapes.push_back(new AbcPointsWriter(ob, xform, m_shape_sampling_index, m_settings, psys)); } } diff --git a/source/blender/blenkernel/BKE_fluid.h b/source/blender/blenkernel/BKE_fluid.h new file mode 100644 index 00000000000..3e389cfec58 --- /dev/null +++ b/source/blender/blenkernel/BKE_fluid.h @@ -0,0 +1,69 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + */ + +#ifndef __BKE_FLUID_H__ +#define __BKE_FLUID_H__ + +/** \file + * \ingroup bke + */ + +struct FluidDomainSettings; +struct FluidModifierData; +struct Scene; + +typedef float (*BKE_Fluid_BresenhamFn)( + float *result, float *input, int res[3], int *pixel, float *tRay, float correct); + +struct Mesh *BKE_fluid_modifier_do(struct FluidModifierData *mmd, + struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + struct Mesh *me); + +void BKE_fluid_modifier_free(struct FluidModifierData *mmd); +void BKE_fluid_modifier_reset(struct FluidModifierData *mmd); +void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd); +void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd, + struct FluidModifierData *tmmd, + const int flag); + +void BKE_fluid_reallocate_fluid(struct FluidDomainSettings *mds, int res[3], int free_old); +void BKE_fluid_reallocate_copy_fluid(struct FluidDomainSettings *mds, + int o_res[3], + int n_res[3], + int o_min[3], + int n_min[3], + int o_max[3], + int o_shift[3], + int n_shift[3]); +void BKE_fluid_cache_free(struct FluidDomainSettings *mds, struct Object *ob, int cache_map); + +float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]); +int BKE_fluid_get_data_flags(struct FluidDomainSettings *mds); + +void BKE_fluid_particle_system_create(struct Main *bmain, + struct Object *ob, + const char *pset_name, + const char *parts_name, + const char *psys_name, + const int psys_type); +void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type); + +#endif /* __BKE_FLUID_H__ */ diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h deleted file mode 100644 index d44c88c30a9..00000000000 --- a/source/blender/blenkernel/BKE_fluidsim.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation - * All rights reserved. - */ - -#ifndef __BKE_FLUIDSIM_H__ -#define __BKE_FLUIDSIM_H__ - -/** \file - * \ingroup bke - */ - -struct Depsgraph; -struct FluidsimSettings; -struct MVert; -struct Object; -struct Scene; - -/* old interface */ - -void initElbeemMesh(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - int *numVertices, - float **vertices, - int *numTriangles, - int **triangles, - int useGlobalCoords, - int modifierIndex); - -/* bounding box & memory estimate */ -void fluid_get_bb( - struct MVert *mvert, int totvert, float obmat[4][4], float start[3], float size[3]); - -void fluid_estimate_memory(struct Object *ob, struct FluidsimSettings *fss, char *value); - -#endif diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 570203081fe..9eb10d296de 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -40,15 +40,14 @@ struct CustomData; struct DMFlagMat; struct GPU_PBVH_Buffers; struct IsectRayPrecalc; -struct Mesh; struct MLoop; struct MLoopTri; struct MPoly; struct MVert; +struct Mesh; struct PBVH; struct PBVHNode; struct SubdivCCG; -struct TaskParallelSettings; struct TaskParallelTLS; typedef struct PBVH PBVH; diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 6ce60081f5b..fd29480cac7 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -75,6 +75,7 @@ /* Structs */ struct ClothModifierData; +struct FluidModifierData; struct ListBase; struct Main; struct Object; @@ -83,7 +84,6 @@ struct ParticleSystem; struct PointCache; struct RigidBodyWorld; struct Scene; -struct SmokeModifierData; struct SoftBody; struct ViewLayer; @@ -286,7 +286,7 @@ void BKE_ptcache_make_particle_key(struct ParticleKey *key, int index, void **da void BKE_ptcache_id_from_softbody(PTCacheID *pid, struct Object *ob, struct SoftBody *sb); void BKE_ptcache_id_from_particles(PTCacheID *pid, struct Object *ob, struct ParticleSystem *psys); void BKE_ptcache_id_from_cloth(PTCacheID *pid, struct Object *ob, struct ClothModifierData *clmd); -void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd); +void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *mmd); void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface); diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h deleted file mode 100644 index 10632d47203..00000000000 --- a/source/blender/blenkernel/BKE_smoke.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation. - * All rights reserved. - */ - -#ifndef __BKE_SMOKE_H__ -#define __BKE_SMOKE_H__ - -/** \file - * \ingroup bke - */ - -struct Scene; -struct SmokeDomainSettings; -struct SmokeModifierData; - -typedef float (*bresenham_callback)( - float *result, float *input, int res[3], int *pixel, float *tRay, float correct); - -struct Mesh *smokeModifier_do(struct SmokeModifierData *smd, - struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - struct Mesh *me); - -void smokeModifier_free(struct SmokeModifierData *smd); -void smokeModifier_reset(struct SmokeModifierData *smd); -void smokeModifier_reset_turbulence(struct SmokeModifierData *smd); -void smokeModifier_createType(struct SmokeModifierData *smd); -void smokeModifier_copy(const struct SmokeModifierData *smd, - struct SmokeModifierData *tsmd, - const int flag); - -void BKE_smoke_reallocate_fluid(struct SmokeDomainSettings *sds, - float dx, - int res[3], - int free_old); -void BKE_smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, - float dx, - int res[3], - int free_old); - -float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]); -int BKE_smoke_get_data_flags(struct SmokeDomainSettings *sds); - -bool BKE_smoke_show_highres(struct Scene *scene, struct SmokeDomainSettings *sds); - -#endif /* __BKE_SMOKE_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 3c912a4da70..053d9c17e1a 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -45,11 +45,11 @@ set(INC ../../../intern/atomic ../../../intern/clog ../../../intern/libmv + ../../../intern/mantaflow/extern ../../../intern/memutil ../../../intern/mikktspace ../../../intern/opensubdiv ../../../extern/curve_fit_nd - ../../../intern/smoke/extern # dna_type_offsets.h ${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern @@ -114,7 +114,7 @@ set(SRC intern/editmesh_tangent.c intern/effect.c intern/fcurve.c - intern/fluidsim.c + intern/fluid.c intern/fmodifier.c intern/font.c intern/freestyle.c @@ -201,7 +201,6 @@ set(SRC intern/sequencer.c intern/shader_fx.c intern/shrinkwrap.c - intern/smoke.c intern/softbody.c intern/sound.c intern/speaker.c @@ -286,7 +285,7 @@ set(SRC BKE_editmesh_tangent.h BKE_effect.h BKE_fcurve.h - BKE_fluidsim.h + BKE_fluid.h BKE_font.h BKE_freestyle.h BKE_global.h @@ -349,7 +348,6 @@ set(SRC BKE_sequencer.h BKE_shader_fx.h BKE_shrinkwrap.h - BKE_smoke.h BKE_softbody.h BKE_sound.h BKE_speaker.h @@ -536,20 +534,10 @@ if(WITH_PYTHON) endif() if(WITH_MOD_FLUID) - list(APPEND INC - ../../../intern/elbeem/extern - ) - list(APPEND LIB - bf_intern_elbeem - ) - add_definitions(-DWITH_MOD_FLUID) -endif() - -if(WITH_MOD_SMOKE) list(APPEND LIB - bf_intern_smoke + bf_intern_mantaflow ) - add_definitions(-DWITH_SMOKE) + add_definitions(-DWITH_FLUID) endif() if(WITH_MOD_OCEANSIM) diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index de7837cdd90..90b26f8c288 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -59,7 +59,7 @@ #include "DNA_texture_types.h" #include "DNA_vfont_types.h" #include "DNA_scene_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_freestyle_types.h" #include "BLI_blenlib.h" @@ -498,10 +498,10 @@ void BKE_bpath_traverse_id( rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data); } } - else if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]); + else if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) { + rewrite_path_fixed(mmd->domain->cache_directory, visit_cb, absbase, bpath_user_data); } } else if (md->type == eModifierType_Cloth) { diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 91b169590ac..74a523bfbdc 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -6278,7 +6278,14 @@ static int dynamicPaint_doStep(Depsgraph *depsgraph, /* Apply brush on the surface depending on it's collision type */ if (brush->psys && brush->psys->part && - ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) && + ELEM(brush->psys->part->type, + PART_EMITTER, + PART_FLUID, + PART_FLUID_FLIP, + PART_FLUID_SPRAY, + PART_FLUID_BUBBLE, + PART_FLUID_FOAM, + PART_FLUID_TRACER) && psys_check_enabled(brushObj, brush->psys, for_render)) { /* Paint a particle system */ dynamicPaint_paintParticles(surface, brush->psys, brush, timescale); diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index ffab82b75af..8971021329a 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -62,7 +62,7 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_scene.h" -#include "BKE_smoke.h" +#include "BKE_fluid.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_physics.h" @@ -71,13 +71,6 @@ #include "RE_render_ext.h" #include "RE_shader_ext.h" -/* fluid sim particle import */ -#ifdef WITH_MOD_FLUID -# include "LBM_fluidsim.h" -# include <zlib.h> -# include <string.h> -#endif // WITH_MOD_FLUID - EffectorWeights *BKE_effector_add_weights(Collection *collection) { EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights"); @@ -1031,9 +1024,10 @@ static void do_physical_effector(EffectorCache *eff, break; case PFIELD_SMOKEFLOW: zero_v3(force); +#ifdef WITH_FLUID if (pd->f_source) { float density; - if ((density = BKE_smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) { + if ((density = BKE_fluid_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) { float influence = strength * efd->falloff; if (pd->flag & PFIELD_SMOKE_DENSITY) { influence *= density; @@ -1043,6 +1037,7 @@ static void do_physical_effector(EffectorCache *eff, madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence); } } +#endif break; } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c new file mode 100644 index 00000000000..81c7c700cc2 --- /dev/null +++ b/source/blender/blenkernel/intern/fluid.c @@ -0,0 +1,4806 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#ifdef WITH_FLUID + +# include "MEM_guardedalloc.h" + +# include <float.h> +# include <math.h> +# include <stdio.h> +# include <string.h> /* memset */ + +# include "BLI_blenlib.h" +# include "BLI_math.h" +# include "BLI_kdopbvh.h" +# include "BLI_threads.h" +# include "BLI_utildefines.h" + +# include "DNA_customdata_types.h" +# include "DNA_light_types.h" +# include "DNA_mesh_types.h" +# include "DNA_meshdata_types.h" +# include "DNA_modifier_types.h" +# include "DNA_object_types.h" +# include "DNA_particle_types.h" +# include "DNA_scene_types.h" +# include "DNA_fluid_types.h" + +# include "BKE_bvhutils.h" +# include "BKE_collision.h" +# include "BKE_colortools.h" +# include "BKE_customdata.h" +# include "BKE_deform.h" +# include "BKE_effect.h" +# include "BKE_library.h" +# include "BKE_mesh.h" +# include "BKE_mesh_runtime.h" +# include "BKE_modifier.h" +# include "BKE_object.h" +# include "BKE_particle.h" +# include "BKE_pointcache.h" +# include "BKE_scene.h" +# include "BKE_fluid.h" +# include "BKE_texture.h" + +# include "DEG_depsgraph.h" +# include "DEG_depsgraph_query.h" + +# include "RE_shader_ext.h" + +# include "manta_fluid_API.h" + +# include "BLI_task.h" +# include "BLI_kdtree.h" +# include "BLI_voxel.h" + +// #define DEBUG_PRINT + +static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER; + +struct FluidModifierData; +struct Mesh; +struct Object; +struct Scene; + +// timestep default value for nice appearance 0.1f +# define DT_DEFAULT 0.1f + +# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b)))) +# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b)))) +# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b))) + +void BKE_fluid_reallocate_fluid(FluidDomainSettings *mds, int res[3], int free_old) +{ + if (free_old && mds->fluid) { + manta_free(mds->fluid); + } + if (!min_iii(res[0], res[1], res[2])) { + mds->fluid = NULL; + return; + } + + mds->fluid = manta_init(res, mds->mmd); + + mds->res_noise[0] = res[0] * mds->noise_scale; + mds->res_noise[1] = res[1] * mds->noise_scale; + mds->res_noise[2] = res[2] * mds->noise_scale; +} + +void BKE_fluid_reallocate_copy_fluid(FluidDomainSettings *mds, + int o_res[3], + int n_res[3], + int o_min[3], + int n_min[3], + int o_max[3], + int o_shift[3], + int n_shift[3]) +{ + int x, y, z; + struct MANTA *fluid_old = mds->fluid; + const int block_size = mds->noise_scale; + int new_shift[3] = {0}; + sub_v3_v3v3_int(new_shift, n_shift, o_shift); + + /* allocate new fluid data */ + BKE_fluid_reallocate_fluid(mds, n_res, 0); + + int o_total_cells = o_res[0] * o_res[1] * o_res[2]; + int n_total_cells = n_res[0] * n_res[1] * n_res[2]; + + /* boundary cells will be skipped when copying data */ + int bwidth = mds->boundary_width; + + /* copy values from old fluid to new */ + if (o_total_cells > 1 && n_total_cells > 1) { + /* base smoke */ + float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_vx, *o_vy, *o_vz, *o_r, *o_g, *o_b; + float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_vx, *n_vy, *n_vz, *n_r, *n_g, *n_b; + float dummy, *dummy_s; + int *dummy_p; + /* noise smoke */ + int wt_res_old[3]; + float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw, + *o_wt_tcu2, *o_wt_tcv2, *o_wt_tcw2, *o_wt_r, *o_wt_g, *o_wt_b; + float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw, + *n_wt_tcu2, *n_wt_tcv2, *n_wt_tcw2, *n_wt_r, *n_wt_g, *n_wt_b; + + if (mds->flags & FLUID_DOMAIN_USE_NOISE) { + manta_smoke_turbulence_export(fluid_old, + &o_wt_dens, + &o_wt_react, + &o_wt_flame, + &o_wt_fuel, + &o_wt_r, + &o_wt_g, + &o_wt_b, + &o_wt_tcu, + &o_wt_tcv, + &o_wt_tcw, + &o_wt_tcu2, + &o_wt_tcv2, + &o_wt_tcw2); + manta_smoke_turbulence_get_res(fluid_old, wt_res_old); + manta_smoke_turbulence_export(mds->fluid, + &n_wt_dens, + &n_wt_react, + &n_wt_flame, + &n_wt_fuel, + &n_wt_r, + &n_wt_g, + &n_wt_b, + &n_wt_tcu, + &n_wt_tcv, + &n_wt_tcw, + &n_wt_tcu2, + &n_wt_tcv2, + &n_wt_tcw2); + } + + manta_smoke_export(fluid_old, + &dummy, + &dummy, + &o_dens, + &o_react, + &o_flame, + &o_fuel, + &o_heat, + &o_vx, + &o_vy, + &o_vz, + &o_r, + &o_g, + &o_b, + &dummy_p, + &dummy_s); + manta_smoke_export(mds->fluid, + &dummy, + &dummy, + &n_dens, + &n_react, + &n_flame, + &n_fuel, + &n_heat, + &n_vx, + &n_vy, + &n_vz, + &n_r, + &n_g, + &n_b, + &dummy_p, + &dummy_s); + + for (x = o_min[0]; x < o_max[0]; x++) { + for (y = o_min[1]; y < o_max[1]; y++) { + for (z = o_min[2]; z < o_max[2]; z++) { + /* old grid index */ + int xo = x - o_min[0]; + int yo = y - o_min[1]; + int zo = z - o_min[2]; + int index_old = manta_get_index(xo, o_res[0], yo, o_res[1], zo); + /* new grid index */ + int xn = x - n_min[0] - new_shift[0]; + int yn = y - n_min[1] - new_shift[1]; + int zn = z - n_min[2] - new_shift[2]; + int index_new = manta_get_index(xn, n_res[0], yn, n_res[1], zn); + + /* skip if outside new domain */ + if (xn < 0 || xn >= n_res[0] || yn < 0 || yn >= n_res[1] || zn < 0 || zn >= n_res[2]) { + continue; + } + /* skip if trying to copy from old boundary cell */ + if (xo < bwidth || yo < bwidth || zo < bwidth || xo >= o_res[0] - bwidth || + yo >= o_res[1] - bwidth || zo >= o_res[2] - bwidth) { + continue; + } + /* skip if trying to copy into new boundary cell */ + if (xn < bwidth || yn < bwidth || zn < bwidth || xn >= n_res[0] - bwidth || + yn >= n_res[1] - bwidth || zn >= n_res[2] - bwidth) { + continue; + } + + /* copy data */ + if (mds->flags & FLUID_DOMAIN_USE_NOISE) { + int i, j, k; + /* old grid index */ + int xx_o = xo * block_size; + int yy_o = yo * block_size; + int zz_o = zo * block_size; + /* new grid index */ + int xx_n = xn * block_size; + int yy_n = yn * block_size; + int zz_n = zn * block_size; + + /* insert old texture values into new texture grids */ + n_wt_tcu[index_new] = o_wt_tcu[index_old]; + n_wt_tcv[index_new] = o_wt_tcv[index_old]; + n_wt_tcw[index_new] = o_wt_tcw[index_old]; + + n_wt_tcu2[index_new] = o_wt_tcu2[index_old]; + n_wt_tcv2[index_new] = o_wt_tcv2[index_old]; + n_wt_tcw2[index_new] = o_wt_tcw2[index_old]; + + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + for (k = 0; k < block_size; k++) { + int big_index_old = manta_get_index( + xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k); + int big_index_new = manta_get_index( + xx_n + i, mds->res_noise[0], yy_n + j, mds->res_noise[1], zz_n + k); + /* copy data */ + n_wt_dens[big_index_new] = o_wt_dens[big_index_old]; + if (n_wt_flame && o_wt_flame) { + n_wt_flame[big_index_new] = o_wt_flame[big_index_old]; + n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old]; + n_wt_react[big_index_new] = o_wt_react[big_index_old]; + } + if (n_wt_r && o_wt_r) { + n_wt_r[big_index_new] = o_wt_r[big_index_old]; + n_wt_g[big_index_new] = o_wt_g[big_index_old]; + n_wt_b[big_index_new] = o_wt_b[big_index_old]; + } + } + } + } + } + + n_dens[index_new] = o_dens[index_old]; + /* heat */ + if (n_heat && o_heat) { + n_heat[index_new] = o_heat[index_old]; + } + /* fuel */ + if (n_fuel && o_fuel) { + n_flame[index_new] = o_flame[index_old]; + n_fuel[index_new] = o_fuel[index_old]; + n_react[index_new] = o_react[index_old]; + } + /* color */ + if (o_r && n_r) { + n_r[index_new] = o_r[index_old]; + n_g[index_new] = o_g[index_old]; + n_b[index_new] = o_b[index_old]; + } + n_vx[index_new] = o_vx[index_old]; + n_vy[index_new] = o_vy[index_old]; + n_vz[index_new] = o_vz[index_old]; + } + } + } + } + manta_free(fluid_old); +} + +void BKE_fluid_cache_free(FluidDomainSettings *mds, Object *ob, int cache_map) +{ + char temp_dir[FILE_MAX]; + int flags = mds->cache_flag; + + /* Ensure cache directory is not relative */ + const char *relbase = modifier_path_relbase_from_global(ob); + BLI_path_abs(mds->cache_directory, relbase); + + if (cache_map & FLUID_DOMAIN_OUTDATED_DATA) { + flags &= ~(FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA); + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL); + if (BLI_exists(temp_dir)) { + BLI_delete(temp_dir, true, true); + } + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL); + if (BLI_exists(temp_dir)) { + BLI_delete(temp_dir, true, true); + } + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL); + if (BLI_exists(temp_dir)) { + BLI_delete(temp_dir, true, true); + } + mds->cache_frame_pause_data = 0; + } + if (cache_map & FLUID_DOMAIN_OUTDATED_NOISE) { + flags &= ~(FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE); + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL); + if (BLI_exists(temp_dir)) { + BLI_delete(temp_dir, true, true); + } + mds->cache_frame_pause_noise = 0; + } + if (cache_map & FLUID_DOMAIN_OUTDATED_MESH) { + flags &= ~(FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH); + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL); + if (BLI_exists(temp_dir)) { + BLI_delete(temp_dir, true, true); + } + mds->cache_frame_pause_mesh = 0; + } + if (cache_map & FLUID_DOMAIN_OUTDATED_PARTICLES) { + flags &= ~(FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKED_PARTICLES | + FLUID_DOMAIN_OUTDATED_PARTICLES); + BLI_path_join( + temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL); + if (BLI_exists(temp_dir)) { + BLI_delete(temp_dir, true, true); + } + mds->cache_frame_pause_particles = 0; + } + + if (cache_map & FLUID_DOMAIN_OUTDATED_GUIDE) { + flags &= ~(FLUID_DOMAIN_BAKING_GUIDE | FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE); + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL); + if (BLI_exists(temp_dir)) { + BLI_delete(temp_dir, true, true); + } + mds->cache_frame_pause_guide = 0; + } + mds->cache_flag = flags; +} + +/* convert global position to domain cell space */ +static void manta_pos_to_cell(FluidDomainSettings *mds, float pos[3]) +{ + mul_m4_v3(mds->imat, pos); + sub_v3_v3(pos, mds->p0); + pos[0] *= 1.0f / mds->cell_size[0]; + pos[1] *= 1.0f / mds->cell_size[1]; + pos[2] *= 1.0f / mds->cell_size[2]; +} + +/* Set domain transformations and base resolution from object mesh. */ +static void manta_set_domain_from_mesh(FluidDomainSettings *mds, + Object *ob, + Mesh *me, + bool init_resolution) +{ + size_t i; + float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + float size[3]; + MVert *verts = me->mvert; + float scale = 0.0; + int res; + + res = mds->maxres; + + /* Set minimum and maximum coordinates of BB. */ + for (i = 0; i < me->totvert; i++) { + minmax_v3v3_v3(min, max, verts[i].co); + } + + /* Set domain bounds. */ + copy_v3_v3(mds->p0, min); + copy_v3_v3(mds->p1, max); + mds->dx = 1.0f / res; + + /* Calculate domain dimensions. */ + sub_v3_v3v3(size, max, min); + if (init_resolution) { + zero_v3_int(mds->base_res); + copy_v3_v3(mds->cell_size, size); + } + /* Apply object scale. */ + for (i = 0; i < 3; i++) { + size[i] = fabsf(size[i] * ob->scale[i]); + } + copy_v3_v3(mds->global_size, size); + copy_v3_v3(mds->dp0, min); + + invert_m4_m4(mds->imat, ob->obmat); + + /* Prevent crash when initializing a plane as domain. */ + if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || + (size[2] < FLT_EPSILON)) { + return; + } + + /* Define grid resolutions from longest domain side. */ + if (size[0] >= MAX2(size[1], size[2])) { + scale = res / size[0]; + mds->scale = size[0] / fabsf(ob->scale[0]); + mds->base_res[0] = res; + mds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4); + mds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4); + } + else if (size[1] >= MAX2(size[0], size[2])) { + scale = res / size[1]; + mds->scale = size[1] / fabsf(ob->scale[1]); + mds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4); + mds->base_res[1] = res; + mds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4); + } + else { + scale = res / size[2]; + mds->scale = size[2] / fabsf(ob->scale[2]); + mds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4); + mds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4); + mds->base_res[2] = res; + } + + /* Set cell size. */ + mds->cell_size[0] /= (float)mds->base_res[0]; + mds->cell_size[1] /= (float)mds->base_res[1]; + mds->cell_size[2] /= (float)mds->base_res[2]; +} + +static void manta_set_domain_gravity(Scene *scene, FluidDomainSettings *mds) +{ + float gravity[3] = {0.0f, 0.0f, -1.0f}; + float gravity_mag; + + /* Use global gravity if enabled. */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(gravity, scene->physics_settings.gravity); + /* Map default value to 1.0. */ + mul_v3_fl(gravity, 1.0f / 9.810f); + + /* Convert gravity to domain space. */ + gravity_mag = len_v3(gravity); + mul_mat3_m4_v3(mds->imat, gravity); + normalize_v3(gravity); + mul_v3_fl(gravity, gravity_mag); + + copy_v3_v3(mds->gravity, gravity); + } +} + +static bool BKE_fluid_modifier_init( + FluidModifierData *mmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me) +{ + int scene_framenr = (int)DEG_get_ctime(depsgraph); + + if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && !mmd->domain->fluid) { + FluidDomainSettings *mds = mmd->domain; + int res[3]; + /* Set domain dimensions from mesh. */ + manta_set_domain_from_mesh(mds, ob, me, true); + /* Set domain gravity. */ + manta_set_domain_gravity(scene, mds); + /* Reset domain values. */ + zero_v3_int(mds->shift); + zero_v3(mds->shift_f); + add_v3_fl(mds->shift_f, 0.5f); + zero_v3(mds->prev_loc); + mul_m4_v3(ob->obmat, mds->prev_loc); + copy_m4_m4(mds->obmat, ob->obmat); + + /* Set resolutions. */ + if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS && + mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { + res[0] = res[1] = res[2] = 1; /* Use minimum res for adaptive init. */ + } + else { + copy_v3_v3_int(res, mds->base_res); + } + copy_v3_v3_int(mds->res, res); + mds->total_cells = mds->res[0] * mds->res[1] * mds->res[2]; + mds->res_min[0] = mds->res_min[1] = mds->res_min[2] = 0; + copy_v3_v3_int(mds->res_max, res); + + /* Set time, frame length = 0.1 is at 25fps. */ + float fps = scene->r.frs_sec / scene->r.frs_sec_base; + mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale; + /* Initially dt is equal to frame length (dt can change with adaptive-time stepping though). */ + mds->dt = mds->frame_length; + mds->time_per_frame = 0; + mds->time_total = (scene_framenr - 1) * mds->frame_length; + + /* Allocate fluid. */ + BKE_fluid_reallocate_fluid(mds, mds->res, 0); + + mmd->time = scene_framenr; + + return true; + } + else if (mmd->type & MOD_FLUID_TYPE_FLOW) { + if (!mmd->flow) { + BKE_fluid_modifier_create_type_data(mmd); + } + mmd->time = scene_framenr; + return true; + } + else if (mmd->type & MOD_FLUID_TYPE_EFFEC) { + if (!mmd->effector) { + BKE_fluid_modifier_create_type_data(mmd); + } + mmd->time = scene_framenr; + return true; + } + return false; +} + +static void BKE_fluid_modifier_freeDomain(FluidModifierData *mmd) +{ + if (mmd->domain) { + if (mmd->domain->fluid) { + manta_free(mmd->domain->fluid); + } + + if (mmd->domain->fluid_mutex) { + BLI_rw_mutex_free(mmd->domain->fluid_mutex); + } + + if (mmd->domain->effector_weights) { + MEM_freeN(mmd->domain->effector_weights); + } + mmd->domain->effector_weights = NULL; + + if (!(mmd->modifier.flag & eModifierFlag_SharedCaches)) { + BKE_ptcache_free_list(&(mmd->domain->ptcaches[0])); + mmd->domain->point_cache[0] = NULL; + } + + if (mmd->domain->mesh_velocities) { + MEM_freeN(mmd->domain->mesh_velocities); + } + mmd->domain->mesh_velocities = NULL; + + if (mmd->domain->coba) { + MEM_freeN(mmd->domain->coba); + } + + MEM_freeN(mmd->domain); + mmd->domain = NULL; + } +} + +static void BKE_fluid_modifier_freeFlow(FluidModifierData *mmd) +{ + if (mmd->flow) { + if (mmd->flow->mesh) { + BKE_id_free(NULL, mmd->flow->mesh); + } + mmd->flow->mesh = NULL; + + if (mmd->flow->verts_old) { + MEM_freeN(mmd->flow->verts_old); + } + mmd->flow->verts_old = NULL; + mmd->flow->numverts = 0; + + MEM_freeN(mmd->flow); + mmd->flow = NULL; + } +} + +static void BKE_fluid_modifier_freeEffector(FluidModifierData *mmd) +{ + if (mmd->effector) { + if (mmd->effector->mesh) { + BKE_id_free(NULL, mmd->effector->mesh); + } + mmd->effector->mesh = NULL; + + if (mmd->effector->verts_old) { + MEM_freeN(mmd->effector->verts_old); + } + mmd->effector->verts_old = NULL; + mmd->effector->numverts = 0; + + MEM_freeN(mmd->effector); + mmd->effector = NULL; + } +} + +static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *mmd, bool need_lock) +{ + if (!mmd) { + return; + } + + if (mmd->domain) { + if (mmd->domain->fluid) { + if (need_lock) { + BLI_rw_mutex_lock(mmd->domain->fluid_mutex, THREAD_LOCK_WRITE); + } + + manta_free(mmd->domain->fluid); + mmd->domain->fluid = NULL; + + if (need_lock) { + BLI_rw_mutex_unlock(mmd->domain->fluid_mutex); + } + } + + mmd->time = -1; + mmd->domain->total_cells = 0; + mmd->domain->active_fields = 0; + } + else if (mmd->flow) { + if (mmd->flow->verts_old) { + MEM_freeN(mmd->flow->verts_old); + } + mmd->flow->verts_old = NULL; + mmd->flow->numverts = 0; + } + else if (mmd->effector) { + if (mmd->effector->verts_old) { + MEM_freeN(mmd->effector->verts_old); + } + mmd->effector->verts_old = NULL; + mmd->effector->numverts = 0; + } +} + +void BKE_fluid_modifier_reset(struct FluidModifierData *mmd) +{ + BKE_fluid_modifier_reset_ex(mmd, true); +} + +void BKE_fluid_modifier_free(FluidModifierData *mmd) +{ + if (!mmd) { + return; + } + + BKE_fluid_modifier_freeDomain(mmd); + BKE_fluid_modifier_freeFlow(mmd); + BKE_fluid_modifier_freeEffector(mmd); +} + +void BKE_fluid_modifier_create_type_data(struct FluidModifierData *mmd) +{ + if (!mmd) { + return; + } + + if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { + if (mmd->domain) { + BKE_fluid_modifier_freeDomain(mmd); + } + + /* domain object data */ + mmd->domain = MEM_callocN(sizeof(FluidDomainSettings), "FluidDomain"); + mmd->domain->mmd = mmd; + mmd->domain->effector_weights = BKE_effector_add_weights(NULL); + mmd->domain->fluid = NULL; + mmd->domain->fluid_mutex = BLI_rw_mutex_alloc(); + mmd->domain->force_group = NULL; + mmd->domain->fluid_group = NULL; + mmd->domain->effector_group = NULL; + + /* adaptive domain options */ + mmd->domain->adapt_margin = 4; + mmd->domain->adapt_res = 0; + mmd->domain->adapt_threshold = 0.02f; + + /* fluid domain options */ + mmd->domain->maxres = 64; + mmd->domain->solver_res = 3; + mmd->domain->border_collisions = 0; // open domain + mmd->domain->flags = FLUID_DOMAIN_USE_DISSOLVE_LOG | FLUID_DOMAIN_USE_ADAPTIVE_TIME; + mmd->domain->gravity[0] = 0.0f; + mmd->domain->gravity[1] = 0.0f; + mmd->domain->gravity[2] = -1.0f; + mmd->domain->active_fields = 0; + mmd->domain->type = FLUID_DOMAIN_TYPE_GAS; + mmd->domain->boundary_width = 1; + + /* smoke domain options */ + mmd->domain->alpha = 1.0f; + mmd->domain->beta = 1.0f; + mmd->domain->diss_speed = 5; + mmd->domain->vorticity = 0; + mmd->domain->active_color[0] = 0.0f; + mmd->domain->active_color[1] = 0.0f; + mmd->domain->active_color[2] = 0.0f; + mmd->domain->highres_sampling = SM_HRES_FULLSAMPLE; + + /* flame options */ + mmd->domain->burning_rate = 0.75f; + mmd->domain->flame_smoke = 1.0f; + mmd->domain->flame_vorticity = 0.5f; + mmd->domain->flame_ignition = 1.5f; + mmd->domain->flame_max_temp = 3.0f; + mmd->domain->flame_smoke_color[0] = 0.7f; + mmd->domain->flame_smoke_color[1] = 0.7f; + mmd->domain->flame_smoke_color[2] = 0.7f; + + /* noise options */ + mmd->domain->noise_strength = 1.0; + mmd->domain->noise_pos_scale = 2.0f; + mmd->domain->noise_time_anim = 0.1f; + mmd->domain->noise_scale = 2; + mmd->domain->noise_type = FLUID_NOISE_TYPE_WAVELET; + + /* liquid domain options */ + mmd->domain->simulation_method = FLUID_DOMAIN_METHOD_FLIP; + mmd->domain->flip_ratio = 0.97f; + mmd->domain->particle_randomness = 0.1f; + mmd->domain->particle_number = 2; + mmd->domain->particle_minimum = 8; + mmd->domain->particle_maximum = 16; + mmd->domain->particle_radius = 1.5f; + mmd->domain->particle_band_width = 3.0f; + mmd->domain->fractions_threshold = 0.05f; + + /* diffusion options*/ + mmd->domain->surface_tension = 0.0f; + mmd->domain->viscosity_base = 1.0f; + mmd->domain->viscosity_exponent = 6.0f; + mmd->domain->domain_size = 0.5f; + + /* mesh options */ + mmd->domain->mesh_velocities = NULL; + mmd->domain->mesh_concave_upper = 3.5f; + mmd->domain->mesh_concave_lower = 0.4f; + mmd->domain->mesh_particle_radius = 2.0; + mmd->domain->mesh_smoothen_pos = 1; + mmd->domain->mesh_smoothen_neg = 1; + mmd->domain->mesh_scale = 2; + mmd->domain->totvert = 0; + mmd->domain->mesh_generator = FLUID_DOMAIN_MESH_IMPROVED; + + /* secondary particle options */ + mmd->domain->sndparticle_tau_min_wc = 2.0; + mmd->domain->sndparticle_tau_max_wc = 8.0; + mmd->domain->sndparticle_tau_min_ta = 5.0; + mmd->domain->sndparticle_tau_max_ta = 20.0; + mmd->domain->sndparticle_tau_min_k = 1.0; + mmd->domain->sndparticle_tau_max_k = 5.0; + mmd->domain->sndparticle_k_wc = 200; + mmd->domain->sndparticle_k_ta = 40; + mmd->domain->sndparticle_k_b = 0.5; + mmd->domain->sndparticle_k_d = 0.6; + mmd->domain->sndparticle_l_min = 10.0; + mmd->domain->sndparticle_l_max = 25.0; + mmd->domain->sndparticle_boundary = SNDPARTICLE_BOUNDARY_DELETE; + mmd->domain->sndparticle_combined_export = SNDPARTICLE_COMBINED_EXPORT_OFF; + mmd->domain->sndparticle_potential_radius = 2; + mmd->domain->sndparticle_update_radius = 2; + mmd->domain->particle_type = 0; + mmd->domain->particle_scale = 1; + + /* fluid guide options */ + mmd->domain->guide_parent = NULL; + mmd->domain->guide_alpha = 2.0f; + mmd->domain->guide_beta = 5; + mmd->domain->guide_vel_factor = 2.0f; + mmd->domain->guide_source = FLUID_DOMAIN_GUIDE_SRC_DOMAIN; + + /* cache options */ + mmd->domain->cache_frame_start = 1; + mmd->domain->cache_frame_end = 50; + mmd->domain->cache_frame_pause_data = 0; + mmd->domain->cache_frame_pause_noise = 0; + mmd->domain->cache_frame_pause_mesh = 0; + mmd->domain->cache_frame_pause_particles = 0; + mmd->domain->cache_frame_pause_guide = 0; + mmd->domain->cache_flag = 0; + mmd->domain->cache_type = FLUID_DOMAIN_CACHE_MODULAR; + mmd->domain->cache_mesh_format = FLUID_DOMAIN_FILE_BIN_OBJECT; + mmd->domain->cache_data_format = FLUID_DOMAIN_FILE_UNI; + mmd->domain->cache_particle_format = FLUID_DOMAIN_FILE_UNI; + mmd->domain->cache_noise_format = FLUID_DOMAIN_FILE_UNI; + modifier_path_init(mmd->domain->cache_directory, + sizeof(mmd->domain->cache_directory), + FLUID_DOMAIN_DIR_DEFAULT); + + /* time options */ + mmd->domain->time_scale = 1.0; + mmd->domain->cfl_condition = 4.0; + mmd->domain->timesteps_minimum = 1; + mmd->domain->timesteps_maximum = 4; + + /* display options */ + mmd->domain->slice_method = FLUID_DOMAIN_SLICE_VIEW_ALIGNED; + mmd->domain->axis_slice_method = AXIS_SLICE_FULL; + mmd->domain->slice_axis = 0; + mmd->domain->interp_method = 0; + mmd->domain->draw_velocity = false; + mmd->domain->slice_per_voxel = 5.0f; + mmd->domain->slice_depth = 0.5f; + mmd->domain->display_thickness = 1.0f; + mmd->domain->coba = NULL; + mmd->domain->vector_scale = 1.0f; + mmd->domain->vector_draw_type = VECTOR_DRAW_NEEDLE; + mmd->domain->use_coba = false; + mmd->domain->coba_field = FLUID_DOMAIN_FIELD_DENSITY; + + /* -- Deprecated / unsed options (below)-- */ + + /* pointcache options */ + BLI_listbase_clear(&mmd->domain->ptcaches[1]); + mmd->domain->point_cache[0] = BKE_ptcache_add(&(mmd->domain->ptcaches[0])); + mmd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE; + mmd->domain->point_cache[0]->step = 1; + mmd->domain->point_cache[1] = NULL; /* Deprecated */ + mmd->domain->cache_comp = SM_CACHE_LIGHT; + mmd->domain->cache_high_comp = SM_CACHE_LIGHT; + + /* OpenVDB cache options */ +# ifdef WITH_OPENVDB_BLOSC + mmd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC; +# else + mmd->domain->openvdb_comp = VDB_COMPRESSION_ZIP; +# endif + mmd->domain->clipping = 1e-3f; + mmd->domain->data_depth = 0; + } + else if (mmd->type & MOD_FLUID_TYPE_FLOW) { + if (mmd->flow) { + BKE_fluid_modifier_freeFlow(mmd); + } + + /* flow object data */ + mmd->flow = MEM_callocN(sizeof(FluidFlowSettings), "MantaFlow"); + mmd->flow->mmd = mmd; + mmd->flow->mesh = NULL; + mmd->flow->psys = NULL; + mmd->flow->noise_texture = NULL; + + /* initial velocity */ + mmd->flow->verts_old = NULL; + mmd->flow->numverts = 0; + mmd->flow->vel_multi = 1.0f; + mmd->flow->vel_normal = 0.0f; + mmd->flow->vel_random = 0.0f; + mmd->flow->vel_coord[0] = 0.0f; + mmd->flow->vel_coord[1] = 0.0f; + mmd->flow->vel_coord[2] = 0.0f; + + /* emission */ + mmd->flow->density = 1.0f; + mmd->flow->color[0] = 0.7f; + mmd->flow->color[1] = 0.7f; + mmd->flow->color[2] = 0.7f; + mmd->flow->fuel_amount = 1.0f; + mmd->flow->temperature = 1.0f; + mmd->flow->volume_density = 0.0f; + mmd->flow->surface_distance = 1.5f; + mmd->flow->particle_size = 1.0f; + mmd->flow->subframes = 0; + + /* texture control */ + mmd->flow->source = FLUID_FLOW_SOURCE_MESH; + mmd->flow->texture_size = 1.0f; + + mmd->flow->type = FLUID_FLOW_TYPE_SMOKE; + mmd->flow->behavior = FLUID_FLOW_BEHAVIOR_GEOMETRY; + mmd->flow->type = FLUID_FLOW_TYPE_SMOKE; + mmd->flow->flags = FLUID_FLOW_ABSOLUTE | FLUID_FLOW_USE_PART_SIZE | FLUID_FLOW_USE_INFLOW; + } + else if (mmd->type & MOD_FLUID_TYPE_EFFEC) { + if (mmd->effector) { + BKE_fluid_modifier_freeEffector(mmd); + } + + /* effector object data */ + mmd->effector = MEM_callocN(sizeof(FluidEffectorSettings), "MantaEffector"); + mmd->effector->mmd = mmd; + mmd->effector->mesh = NULL; + mmd->effector->verts_old = NULL; + mmd->effector->numverts = 0; + mmd->effector->surface_distance = 0.0f; + mmd->effector->type = FLUID_EFFECTOR_TYPE_COLLISION; + mmd->effector->flags = 0; + + /* guide options */ + mmd->effector->guide_mode = FLUID_EFFECTOR_GUIDE_MAX; + mmd->effector->vel_multi = 1.0f; + } +} + +void BKE_fluid_modifier_copy(const struct FluidModifierData *mmd, + struct FluidModifierData *tmmd, + const int flag) +{ + tmmd->type = mmd->type; + tmmd->time = mmd->time; + + BKE_fluid_modifier_create_type_data(tmmd); + + if (tmmd->domain) { + FluidDomainSettings *tmds = tmmd->domain; + FluidDomainSettings *mds = mmd->domain; + + /* domain object data */ + tmds->fluid_group = mds->fluid_group; + tmds->force_group = mds->force_group; + tmds->effector_group = mds->effector_group; + if (tmds->effector_weights) { + MEM_freeN(tmds->effector_weights); + } + tmds->effector_weights = MEM_dupallocN(mds->effector_weights); + + /* adaptive domain options */ + tmds->adapt_margin = mds->adapt_margin; + tmds->adapt_res = mds->adapt_res; + tmds->adapt_threshold = mds->adapt_threshold; + + /* fluid domain options */ + tmds->maxres = mds->maxres; + tmds->solver_res = mds->solver_res; + tmds->border_collisions = mds->border_collisions; + tmds->flags = mds->flags; + tmds->gravity[0] = mds->gravity[0]; + tmds->gravity[1] = mds->gravity[1]; + tmds->gravity[2] = mds->gravity[2]; + tmds->active_fields = mds->active_fields; + tmds->type = mds->type; + tmds->boundary_width = mds->boundary_width; + + /* smoke domain options */ + tmds->alpha = mds->alpha; + tmds->beta = mds->beta; + tmds->diss_speed = mds->diss_speed; + tmds->vorticity = mds->vorticity; + tmds->highres_sampling = mds->highres_sampling; + + /* flame options */ + tmds->burning_rate = mds->burning_rate; + tmds->flame_smoke = mds->flame_smoke; + tmds->flame_vorticity = mds->flame_vorticity; + tmds->flame_ignition = mds->flame_ignition; + tmds->flame_max_temp = mds->flame_max_temp; + copy_v3_v3(tmds->flame_smoke_color, mds->flame_smoke_color); + + /* noise options */ + tmds->noise_strength = mds->noise_strength; + tmds->noise_pos_scale = mds->noise_pos_scale; + tmds->noise_time_anim = mds->noise_time_anim; + tmds->noise_scale = mds->noise_scale; + tmds->noise_type = mds->noise_type; + + /* liquid domain options */ + tmds->flip_ratio = mds->flip_ratio; + tmds->particle_randomness = mds->particle_randomness; + tmds->particle_number = mds->particle_number; + tmds->particle_minimum = mds->particle_minimum; + tmds->particle_maximum = mds->particle_maximum; + tmds->particle_radius = mds->particle_radius; + tmds->particle_band_width = mds->particle_band_width; + tmds->fractions_threshold = mds->fractions_threshold; + + /* diffusion options*/ + tmds->surface_tension = mds->surface_tension; + tmds->viscosity_base = mds->viscosity_base; + tmds->viscosity_exponent = mds->viscosity_exponent; + tmds->domain_size = mds->domain_size; + + /* mesh options */ + if (mds->mesh_velocities) { + tmds->mesh_velocities = MEM_dupallocN(mds->mesh_velocities); + } + tmds->mesh_concave_upper = mds->mesh_concave_upper; + tmds->mesh_concave_lower = mds->mesh_concave_lower; + tmds->mesh_particle_radius = mds->mesh_particle_radius; + tmds->mesh_smoothen_pos = mds->mesh_smoothen_pos; + tmds->mesh_smoothen_neg = mds->mesh_smoothen_neg; + tmds->mesh_scale = mds->mesh_scale; + tmds->totvert = mds->totvert; + tmds->mesh_generator = mds->mesh_generator; + + /* secondary particle options */ + tmds->sndparticle_k_b = mds->sndparticle_k_b; + tmds->sndparticle_k_d = mds->sndparticle_k_d; + tmds->sndparticle_k_ta = mds->sndparticle_k_ta; + tmds->sndparticle_k_wc = mds->sndparticle_k_wc; + tmds->sndparticle_l_max = mds->sndparticle_l_max; + tmds->sndparticle_l_min = mds->sndparticle_l_min; + tmds->sndparticle_tau_max_k = mds->sndparticle_tau_max_k; + tmds->sndparticle_tau_max_ta = mds->sndparticle_tau_max_ta; + tmds->sndparticle_tau_max_wc = mds->sndparticle_tau_max_wc; + tmds->sndparticle_tau_min_k = mds->sndparticle_tau_min_k; + tmds->sndparticle_tau_min_ta = mds->sndparticle_tau_min_ta; + tmds->sndparticle_tau_min_wc = mds->sndparticle_tau_min_wc; + tmds->sndparticle_boundary = mds->sndparticle_boundary; + tmds->sndparticle_combined_export = mds->sndparticle_combined_export; + tmds->sndparticle_potential_radius = mds->sndparticle_potential_radius; + tmds->sndparticle_update_radius = mds->sndparticle_update_radius; + tmds->particle_type = mds->particle_type; + tmds->particle_scale = mds->particle_scale; + + /* fluid guide options */ + tmds->guide_parent = mds->guide_parent; + tmds->guide_alpha = mds->guide_alpha; + tmds->guide_beta = mds->guide_beta; + tmds->guide_vel_factor = mds->guide_vel_factor; + copy_v3_v3_int(tmds->guide_res, mds->guide_res); + tmds->guide_source = mds->guide_source; + + /* cache options */ + tmds->cache_frame_start = mds->cache_frame_start; + tmds->cache_frame_end = mds->cache_frame_end; + tmds->cache_frame_pause_data = mds->cache_frame_pause_data; + tmds->cache_frame_pause_noise = mds->cache_frame_pause_noise; + tmds->cache_frame_pause_mesh = mds->cache_frame_pause_mesh; + tmds->cache_frame_pause_particles = mds->cache_frame_pause_particles; + tmds->cache_frame_pause_guide = mds->cache_frame_pause_guide; + tmds->cache_flag = mds->cache_flag; + tmds->cache_type = mds->cache_type; + tmds->cache_mesh_format = mds->cache_mesh_format; + tmds->cache_data_format = mds->cache_data_format; + tmds->cache_particle_format = mds->cache_particle_format; + tmds->cache_noise_format = mds->cache_noise_format; + BLI_strncpy(tmds->cache_directory, mds->cache_directory, sizeof(tmds->cache_directory)); + + /* time options */ + tmds->time_scale = mds->time_scale; + tmds->cfl_condition = mds->cfl_condition; + tmds->timesteps_minimum = mds->timesteps_minimum; + tmds->timesteps_maximum = mds->timesteps_maximum; + + /* display options */ + tmds->slice_method = mds->slice_method; + tmds->axis_slice_method = mds->axis_slice_method; + tmds->slice_axis = mds->slice_axis; + tmds->interp_method = mds->interp_method; + tmds->draw_velocity = mds->draw_velocity; + tmds->slice_per_voxel = mds->slice_per_voxel; + tmds->slice_depth = mds->slice_depth; + tmds->display_thickness = mds->display_thickness; + if (mds->coba) { + tmds->coba = MEM_dupallocN(mds->coba); + } + tmds->vector_scale = mds->vector_scale; + tmds->vector_draw_type = mds->vector_draw_type; + tmds->use_coba = mds->use_coba; + tmds->coba_field = mds->coba_field; + + /* -- Deprecated / unsed options (below)-- */ + + /* pointcache options */ + BKE_ptcache_free_list(&(tmds->ptcaches[0])); + if (flag & LIB_ID_CREATE_NO_MAIN) { + /* Share the cache with the original object's modifier. */ + tmmd->modifier.flag |= eModifierFlag_SharedCaches; + tmds->point_cache[0] = mds->point_cache[0]; + tmds->ptcaches[0] = mds->ptcaches[0]; + } + else { + tmds->point_cache[0] = BKE_ptcache_copy_list( + &(tmds->ptcaches[0]), &(mds->ptcaches[0]), flag); + } + + /* OpenVDB cache options */ + tmds->openvdb_comp = mds->openvdb_comp; + tmds->clipping = mds->clipping; + tmds->data_depth = mds->data_depth; + } + else if (tmmd->flow) { + FluidFlowSettings *tmfs = tmmd->flow; + FluidFlowSettings *mfs = mmd->flow; + + tmfs->psys = mfs->psys; + tmfs->noise_texture = mfs->noise_texture; + + /* initial velocity */ + tmfs->vel_multi = mfs->vel_multi; + tmfs->vel_normal = mfs->vel_normal; + tmfs->vel_random = mfs->vel_random; + tmfs->vel_coord[0] = mfs->vel_coord[0]; + tmfs->vel_coord[1] = mfs->vel_coord[1]; + tmfs->vel_coord[2] = mfs->vel_coord[2]; + + /* emission */ + tmfs->density = mfs->density; + copy_v3_v3(tmfs->color, mfs->color); + tmfs->fuel_amount = mfs->fuel_amount; + tmfs->temperature = mfs->temperature; + tmfs->volume_density = mfs->volume_density; + tmfs->surface_distance = mfs->surface_distance; + tmfs->particle_size = mfs->particle_size; + tmfs->subframes = mfs->subframes; + + /* texture control */ + tmfs->texture_size = mfs->texture_size; + tmfs->texture_offset = mfs->texture_offset; + BLI_strncpy(tmfs->uvlayer_name, mfs->uvlayer_name, sizeof(tmfs->uvlayer_name)); + tmfs->vgroup_density = mfs->vgroup_density; + + tmfs->type = mfs->type; + tmfs->behavior = mfs->behavior; + tmfs->source = mfs->source; + tmfs->texture_type = mfs->texture_type; + tmfs->flags = mfs->flags; + } + else if (tmmd->effector) { + FluidEffectorSettings *tmes = tmmd->effector; + FluidEffectorSettings *mes = mmd->effector; + + tmes->surface_distance = mes->surface_distance; + tmes->type = mes->type; + + /* guide options */ + tmes->guide_mode = mes->guide_mode; + tmes->vel_multi = mes->vel_multi; + } +} + +// forward declaration +static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *view_layer); +static float calc_voxel_transp( + float *result, float *input, int res[3], int *pixel, float *t_ray, float correct); +static void update_mesh_distances(int index, + float *mesh_distances, + BVHTreeFromMesh *tree_data, + const float ray_start[3], + float surface_thickness, + int use_plane_init); + +static int get_light(ViewLayer *view_layer, float *light) +{ + Base *base_tmp = NULL; + int found_light = 0; + + // try to find a lamp, preferably local + for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) { + if (base_tmp->object->type == OB_LAMP) { + Light *la = base_tmp->object->data; + + if (la->type == LA_LOCAL) { + copy_v3_v3(light, base_tmp->object->obmat[3]); + return 1; + } + else if (!found_light) { + copy_v3_v3(light, base_tmp->object->obmat[3]); + found_light = 1; + } + } + } + + return found_light; +} + +/********************************************************** + * Obstacles + **********************************************************/ + +typedef struct ObstaclesFromDMData { + FluidDomainSettings *mds; + FluidEffectorSettings *mes; + const MVert *mvert; + const MLoop *mloop; + const MLoopTri *looptri; + BVHTreeFromMesh *tree; + + bool has_velocity; + float *vert_vel; + float *velocity_x, *velocity_y, *velocity_z; + int *num_objects; + float *distances_map; +} ObstaclesFromDMData; + +static void obstacles_from_mesh_task_cb(void *__restrict userdata, + const int z, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + ObstaclesFromDMData *data = userdata; + FluidDomainSettings *mds = data->mds; + + /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */ + const float surface_distance = 2.0f; // 0.867f; + /* Note: Use larger surface distance to cover larger area with obvel. Manta will use these obvels + * and extrapolate them (inside and outside obstacle) */ + + for (int x = mds->res_min[0]; x < mds->res_max[0]; x++) { + for (int y = mds->res_min[1]; y < mds->res_max[1]; y++) { + const int index = manta_get_index( + x - mds->res_min[0], mds->res[0], y - mds->res_min[1], mds->res[1], z - mds->res_min[2]); + + float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f}; + BVHTreeNearest nearest = {0}; + nearest.index = -1; + nearest.dist_sq = surface_distance * + surface_distance; /* find_nearest uses squared distance */ + bool has_inc_obj = false; + + /* find the nearest point on the mesh */ + if (BLI_bvhtree_find_nearest( + data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != + -1) { + const MLoopTri *lt = &data->looptri[nearest.index]; + float weights[3]; + int v1, v2, v3; + + /* calculate barycentric weights for nearest point */ + v1 = data->mloop[lt->tri[0]].v; + v2 = data->mloop[lt->tri[1]].v; + v3 = data->mloop[lt->tri[2]].v; + interp_weights_tri_v3( + weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co); + + if (data->has_velocity) { + /* increase object count */ + data->num_objects[index]++; + has_inc_obj = true; + + /* apply object velocity */ + float hit_vel[3]; + interp_v3_v3v3v3(hit_vel, + &data->vert_vel[v1 * 3], + &data->vert_vel[v2 * 3], + &data->vert_vel[v3 * 3], + weights); + + /* Guiding has additional velocity multiplier */ + if (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) { + mul_v3_fl(hit_vel, data->mes->vel_multi); + + switch (data->mes->guide_mode) { + case FLUID_EFFECTOR_GUIDE_AVERAGED: + data->velocity_x[index] = (data->velocity_x[index] + hit_vel[0]) * 0.5f; + data->velocity_y[index] = (data->velocity_y[index] + hit_vel[1]) * 0.5f; + data->velocity_z[index] = (data->velocity_z[index] + hit_vel[2]) * 0.5f; + break; + case FLUID_EFFECTOR_GUIDE_OVERRIDE: + data->velocity_x[index] = hit_vel[0]; + data->velocity_y[index] = hit_vel[1]; + data->velocity_z[index] = hit_vel[2]; + break; + case FLUID_EFFECTOR_GUIDE_MIN: + data->velocity_x[index] = MIN2(fabsf(hit_vel[0]), fabsf(data->velocity_x[index])); + data->velocity_y[index] = MIN2(fabsf(hit_vel[1]), fabsf(data->velocity_y[index])); + data->velocity_z[index] = MIN2(fabsf(hit_vel[2]), fabsf(data->velocity_z[index])); + break; + case FLUID_EFFECTOR_GUIDE_MAX: + default: + data->velocity_x[index] = MAX2(fabsf(hit_vel[0]), fabsf(data->velocity_x[index])); + data->velocity_y[index] = MAX2(fabsf(hit_vel[1]), fabsf(data->velocity_y[index])); + data->velocity_z[index] = MAX2(fabsf(hit_vel[2]), fabsf(data->velocity_z[index])); + break; + } + } + else { + /* Apply (i.e. add) effector object velocity */ + data->velocity_x[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ? + hit_vel[0] * data->mes->vel_multi : + hit_vel[0]; + data->velocity_y[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ? + hit_vel[1] * data->mes->vel_multi : + hit_vel[1]; + data->velocity_z[index] += (data->mes->type == FLUID_EFFECTOR_TYPE_GUIDE) ? + hit_vel[2] * data->mes->vel_multi : + hit_vel[2]; +# ifdef DEBUG_PRINT + /* Debugging: Print object velocities. */ + printf("adding effector object vel: [%f, %f, %f], dx is: %f\n", + hit_vel[0], + hit_vel[1], + hit_vel[2], + mds->dx); +# endif + } + } + } + + /* Get distance to mesh surface from both within and outside grid (mantaflow phi grid). */ + if (data->distances_map) { + update_mesh_distances(index, + data->distances_map, + data->tree, + ray_start, + data->mes->surface_distance, + data->mes->flags & FLUID_FLOW_USE_PLANE_INIT); + + /* Ensure that num objects are also counted inside object. + * But don't count twice (see object inc for nearest point). */ + if (data->distances_map[index] < 0 && !has_inc_obj) { + data->num_objects[index]++; + } + } + } + } +} + +static void obstacles_from_mesh(Object *coll_ob, + FluidDomainSettings *mds, + FluidEffectorSettings *mes, + float *distances_map, + float *velocity_x, + float *velocity_y, + float *velocity_z, + int *num_objects, + float dt) +{ + if (!mes->mesh) { + return; + } + { + Mesh *me = NULL; + MVert *mvert = NULL; + const MLoopTri *looptri; + const MLoop *mloop; + BVHTreeFromMesh tree_data = {NULL}; + int numverts, i; + + float *vert_vel = NULL; + bool has_velocity = false; + + me = BKE_mesh_copy_for_eval(mes->mesh, true); + + /* Duplicate vertices to modify. */ + if (me->mvert) { + me->mvert = MEM_dupallocN(me->mvert); + CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); + } + + BKE_mesh_ensure_normals(me); + mvert = me->mvert; + mloop = me->mloop; + looptri = BKE_mesh_runtime_looptri_ensure(me); + numverts = me->totvert; + + /* TODO (sebbas): + * Make vert_vel init optional? + * code is in trouble if the object moves but is declared as "does not move" */ + { + vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "manta_obs_velocity"); + + if (mes->numverts != numverts || !mes->verts_old) { + if (mes->verts_old) { + MEM_freeN(mes->verts_old); + } + + mes->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "manta_obs_verts_old"); + mes->numverts = numverts; + } + else { + has_velocity = true; + } + } + + /* Transform collider vertices to + * domain grid space for fast lookups */ + for (i = 0; i < numverts; i++) { + float n[3]; + float co[3]; + + /* vert pos */ + mul_m4_v3(coll_ob->obmat, mvert[i].co); + manta_pos_to_cell(mds, mvert[i].co); + + /* vert normal */ + normal_short_to_float_v3(n, mvert[i].no); + mul_mat3_m4_v3(coll_ob->obmat, n); + mul_mat3_m4_v3(mds->imat, n); + normalize_v3(n); + normal_float_to_short_v3(mvert[i].no, n); + + /* vert velocity */ + add_v3fl_v3fl_v3i(co, mvert[i].co, mds->shift); + if (has_velocity) { + sub_v3_v3v3(&vert_vel[i * 3], co, &mes->verts_old[i * 3]); + mul_v3_fl(&vert_vel[i * 3], mds->dx / dt); + } + copy_v3_v3(&mes->verts_old[i * 3], co); + } + + if (BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) { + ObstaclesFromDMData data = {.mds = mds, + .mes = mes, + .mvert = mvert, + .mloop = mloop, + .looptri = looptri, + .tree = &tree_data, + .has_velocity = has_velocity, + .vert_vel = vert_vel, + .velocity_x = velocity_x, + .velocity_y = velocity_y, + .velocity_z = velocity_z, + .num_objects = num_objects, + .distances_map = distances_map}; + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 2; + BLI_task_parallel_range( + mds->res_min[2], mds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings); + } + /* free bvh tree */ + free_bvhtree_from_mesh(&tree_data); + + if (vert_vel) { + MEM_freeN(vert_vel); + } + if (me->mvert) { + MEM_freeN(me->mvert); + } + BKE_id_free(NULL, me); + } +} + +static void update_obstacleflags(FluidDomainSettings *mds, + Object **coll_ob_array, + int coll_ob_array_len) +{ + int active_fields = mds->active_fields; + uint coll_index; + + /* First, remove all flags that we want to update. */ + int prev_flags = (FLUID_DOMAIN_ACTIVE_OBSTACLE | FLUID_DOMAIN_ACTIVE_GUIDE); + active_fields &= ~prev_flags; + + /* Monitor active fields based on flow settings */ + for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) { + Object *coll_ob = coll_ob_array[coll_index]; + FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob, + eModifierType_Fluid); + + if ((mmd2->type & MOD_FLUID_TYPE_EFFEC) && mmd2->effector) { + FluidEffectorSettings *mes = mmd2->effector; + if (!mes) { + break; + } + if (mes->type == FLUID_EFFECTOR_TYPE_COLLISION) { + active_fields |= FLUID_DOMAIN_ACTIVE_OBSTACLE; + } + if (mes->type == FLUID_EFFECTOR_TYPE_GUIDE) { + active_fields |= FLUID_DOMAIN_ACTIVE_GUIDE; + } + } + } + /* Finally, initialize new data fields if any */ + if (active_fields & FLUID_DOMAIN_ACTIVE_OBSTACLE) { + manta_ensure_obstacle(mds->fluid, mds->mmd); + } + if (active_fields & FLUID_DOMAIN_ACTIVE_GUIDE) { + manta_ensure_guiding(mds->fluid, mds->mmd); + } + mds->active_fields = active_fields; +} + +static void update_obstacles(Depsgraph *depsgraph, + Scene *scene, + Object *ob, + FluidDomainSettings *mds, + float time_per_frame, + float frame_length, + int frame, + float dt) +{ + Object **coll_ob_array = NULL; + uint coll_ob_array_len = 0, coll_index = 0; + + coll_ob_array = BKE_collision_objects_create( + depsgraph, ob, mds->effector_group, &coll_ob_array_len, eModifierType_Fluid); + + /* Update all flow related flags and ensure that corresponding grids get initialized. */ + update_obstacleflags(mds, coll_ob_array, coll_ob_array_len); + + float *vel_x = manta_get_ob_velocity_x(mds->fluid); + float *vel_y = manta_get_ob_velocity_y(mds->fluid); + float *vel_z = manta_get_ob_velocity_z(mds->fluid); + float *vel_x_guide = manta_get_guide_velocity_x(mds->fluid); + float *vel_y_guide = manta_get_guide_velocity_y(mds->fluid); + float *vel_z_guide = manta_get_guide_velocity_z(mds->fluid); + float *vel_x_orig = manta_get_velocity_x(mds->fluid); + float *vel_y_orig = manta_get_velocity_y(mds->fluid); + float *vel_z_orig = manta_get_velocity_z(mds->fluid); + float *density = manta_smoke_get_density(mds->fluid); + float *fuel = manta_smoke_get_fuel(mds->fluid); + float *flame = manta_smoke_get_flame(mds->fluid); + float *r = manta_smoke_get_color_r(mds->fluid); + float *g = manta_smoke_get_color_g(mds->fluid); + float *b = manta_smoke_get_color_b(mds->fluid); + float *phi_obs_in = manta_get_phiobs_in(mds->fluid); + float *phi_guide_in = manta_get_phiguide_in(mds->fluid); + int *obstacles = manta_smoke_get_obstacle(mds->fluid); + int *num_obstacles = manta_get_num_obstacle(mds->fluid); + int *num_guides = manta_get_num_guide(mds->fluid); + uint z; + float tmp = 0; + + /* Grid reset before writing again. */ + for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) { + + /* Use big value that's not inf to initialize levelset grids. */ + if (phi_obs_in) { + phi_obs_in[z] = FLT_MAX; + } + if (phi_guide_in) { + phi_guide_in[z] = FLT_MAX; + } + if (num_obstacles) { + num_obstacles[z] = 0; + } + if (num_guides) { + num_guides[z] = 0; + } + if (vel_x && vel_y && vel_z) { + vel_x[z] = 0.0f; + vel_y[z] = 0.0f; + vel_z[z] = 0.0f; + } + if (vel_x_guide && vel_y_guide && vel_z_guide) { + vel_x_guide[z] = 0.0f; + vel_y_guide[z] = 0.0f; + vel_z_guide[z] = 0.0f; + } + } + + /* Prepare grids from effector objects. */ + for (coll_index = 0; coll_index < coll_ob_array_len; coll_index++) { + Object *coll_ob = coll_ob_array[coll_index]; + FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob, + eModifierType_Fluid); + + /* TODO (sebbas): check if modifier is active? */ + if ((mmd2->type & MOD_FLUID_TYPE_EFFEC) && mmd2->effector) { + FluidEffectorSettings *mes = mmd2->effector; + + /* Length of one frame. If using adaptive stepping, length is smaller than actual frame + * length. */ + float adaptframe_length = time_per_frame / frame_length; + + /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene subframe + * parameter. */ + if (time_per_frame < frame_length) { + scene->r.subframe = adaptframe_length; + scene->r.cfra = frame - 1; + } + /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe + * parameter to 0 and advance current scene frame. */ + else { + scene->r.subframe = 0.0f; + scene->r.cfra = frame; + } +# ifdef DEBUG_PRINT + /* Debugging: Print subframe information. */ + printf("effector: frame: %d // scene current frame: %d // scene current subframe: %f\n", + frame, + scene->r.cfra, + scene->r.subframe); +# endif + /* TODO (sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph) as + * subframes don't work with the latter yet. */ + BKE_object_modifier_update_subframe( + depsgraph, scene, coll_ob, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid); + + if (mes && (mes->type == FLUID_EFFECTOR_TYPE_COLLISION)) { + obstacles_from_mesh(coll_ob, mds, mes, phi_obs_in, vel_x, vel_y, vel_z, num_obstacles, dt); + } + if (mes && (mes->type == FLUID_EFFECTOR_TYPE_GUIDE)) { + obstacles_from_mesh(coll_ob, + mds, + mes, + phi_guide_in, + vel_x_guide, + vel_y_guide, + vel_z_guide, + num_guides, + dt); + } + } + } + + BKE_collision_objects_free(coll_ob_array); + + /* Obstacle cells should not contain any velocity from the smoke simulation. */ + for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) { + if (obstacles[z] & 2) /* Mantaflow convention: FlagObstacle. */ + { + if (vel_x_orig && vel_y_orig && vel_z_orig) { + vel_x_orig[z] = 0.0f; + vel_y_orig[z] = 0.0f; + vel_z_orig[z] = 0.0f; + } + if (density) { + density[z] = 0.0f; + } + if (fuel) { + fuel[z] = 0.0f; + flame[z] = 0.0f; + } + if (r) { + r[z] = 0.0f; + g[z] = 0.0f; + b[z] = 0.0f; + } + } + /* Average velocities from multiple obstacles in one cell. */ + if (num_obstacles && num_obstacles[z]) { + tmp = 1.0f / num_obstacles[z]; + vel_x[z] *= tmp; + vel_y[z] *= tmp; + vel_z[z] *= tmp; + } + /* Average velocities from multiple guides in one cell. */ + if (num_guides && num_guides[z]) { + tmp = 1.0f / num_guides[z]; + vel_x_guide[z] *= tmp; + vel_y_guide[z] *= tmp; + vel_z_guide[z] *= tmp; + } + } +} + +/********************************************************** + * Flow emission code + **********************************************************/ + +typedef struct EmissionMap { + float *influence; + float *influence_high; + float *velocity; + float *distances; + float *distances_high; + int min[3], max[3], res[3]; + int hmin[3], hmax[3], hres[3]; + int total_cells, valid; +} EmissionMap; + +static void em_boundInsert(EmissionMap *em, float point[3]) +{ + int i = 0; + if (!em->valid) { + for (; i < 3; i++) { + em->min[i] = (int)floor(point[i]); + em->max[i] = (int)ceil(point[i]); + } + em->valid = 1; + } + else { + for (; i < 3; i++) { + if (point[i] < em->min[i]) { + em->min[i] = (int)floor(point[i]); + } + if (point[i] > em->max[i]) { + em->max[i] = (int)ceil(point[i]); + } + } + } +} + +static void clamp_bounds_in_domain(FluidDomainSettings *mds, + int min[3], + int max[3], + float *min_vel, + float *max_vel, + int margin, + float dt) +{ + int i; + for (i = 0; i < 3; i++) { + int adapt = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) ? mds->adapt_res : 0; + /* add margin */ + min[i] -= margin; + max[i] += margin; + + /* adapt to velocity */ + if (min_vel && min_vel[i] < 0.0f) { + min[i] += (int)floor(min_vel[i] * dt); + } + if (max_vel && max_vel[i] > 0.0f) { + max[i] += (int)ceil(max_vel[i] * dt); + } + + /* clamp within domain max size */ + CLAMP(min[i], -adapt, mds->base_res[i] + adapt); + CLAMP(max[i], -adapt, mds->base_res[i] + adapt); + } +} + +static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul) +{ + int i, res[3]; + + for (i = 0; i < 3; i++) { + res[i] = em->max[i] - em->min[i]; + if (res[i] <= 0) { + return; + } + } + em->total_cells = res[0] * res[1] * res[2]; + copy_v3_v3_int(em->res, res); + + em->influence = MEM_calloc_arrayN(em->total_cells, sizeof(float), "manta_flow_influence"); + if (use_velocity) { + em->velocity = MEM_calloc_arrayN(em->total_cells * 3, sizeof(float), "manta_flow_velocity"); + } + + em->distances = MEM_malloc_arrayN(em->total_cells, sizeof(float), "fluid_flow_distances"); + /* Initialize to infinity. */ + memset(em->distances, 0x7f7f7f7f, sizeof(float) * em->total_cells); + + /* Allocate high resolution map if required. */ + if (hires_mul > 1) { + int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul); + + for (i = 0; i < 3; i++) { + em->hmin[i] = em->min[i] * hires_mul; + em->hmax[i] = em->max[i] * hires_mul; + em->hres[i] = em->res[i] * hires_mul; + } + + em->influence_high = MEM_calloc_arrayN( + total_cells_high, sizeof(float), "manta_flow_influence_high"); + em->distances_high = MEM_malloc_arrayN( + total_cells_high, sizeof(float), "manta_flow_distances_high"); + /* Initialize to infinity. */ + memset(em->distances_high, 0x7f7f7f7f, sizeof(float) * total_cells_high); + } + em->valid = true; +} + +static void em_freeData(EmissionMap *em) +{ + if (em->influence) { + MEM_freeN(em->influence); + } + if (em->influence_high) { + MEM_freeN(em->influence_high); + } + if (em->velocity) { + MEM_freeN(em->velocity); + } + if (em->distances) { + MEM_freeN(em->distances); + } + if (em->distances_high) { + MEM_freeN(em->distances_high); + } +} + +static void em_combineMaps( + EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size) +{ + int i, x, y, z; + + /* copyfill input 1 struct and clear output for new allocation */ + EmissionMap em1; + memcpy(&em1, output, sizeof(EmissionMap)); + memset(output, 0, sizeof(EmissionMap)); + + for (i = 0; i < 3; i++) { + if (em1.valid) { + output->min[i] = MIN2(em1.min[i], em2->min[i]); + output->max[i] = MAX2(em1.max[i], em2->max[i]); + } + else { + output->min[i] = em2->min[i]; + output->max[i] = em2->max[i]; + } + } + /* allocate output map */ + em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier); + + /* base resolution inputs */ + for (x = output->min[0]; x < output->max[0]; x++) { + for (y = output->min[1]; y < output->max[1]; y++) { + for (z = output->min[2]; z < output->max[2]; z++) { + int index_out = manta_get_index(x - output->min[0], + output->res[0], + y - output->min[1], + output->res[1], + z - output->min[2]); + + /* initialize with first input if in range */ + if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] && + z >= em1.min[2] && z < em1.max[2]) { + int index_in = manta_get_index( + x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]); + + /* values */ + output->influence[index_out] = em1.influence[index_in]; + output->distances[index_out] = em1.distances[index_in]; + if (output->velocity && em1.velocity) { + copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]); + } + } + + /* apply second input if in range */ + if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] && + z >= em2->min[2] && z < em2->max[2]) { + int index_in = manta_get_index( + x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]); + + /* values */ + if (additive) { + output->influence[index_out] += em2->influence[index_in] * sample_size; + } + else { + output->influence[index_out] = MAX2(em2->influence[index_in], + output->influence[index_out]); + } + output->distances[index_out] = MIN2(em2->distances[index_in], + output->distances[index_out]); + if (output->velocity && em2->velocity) { + /* last sample replaces the velocity */ + output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3], + em2->velocity[index_in * 3]); + output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], + em2->velocity[index_in * 3 + 1]); + output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], + em2->velocity[index_in * 3 + 2]); + } + } + } // low res loop + } + } + + /* initialize high resolution input if available */ + if (output->influence_high) { + for (x = output->hmin[0]; x < output->hmax[0]; x++) { + for (y = output->hmin[1]; y < output->hmax[1]; y++) { + for (z = output->hmin[2]; z < output->hmax[2]; z++) { + int index_out = manta_get_index(x - output->hmin[0], + output->hres[0], + y - output->hmin[1], + output->hres[1], + z - output->hmin[2]); + + /* initialize with first input if in range */ + if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] && + z >= em1.hmin[2] && z < em1.hmax[2]) { + int index_in = manta_get_index( + x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]); + /* values */ + output->influence_high[index_out] = em1.influence_high[index_in]; + } + + /* apply second input if in range */ + if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] && + z >= em2->hmin[2] && z < em2->hmax[2]) { + int index_in = manta_get_index( + x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]); + + /* values */ + if (additive) { + output->influence_high[index_out] += em2->distances_high[index_in] * sample_size; + } + else { + output->distances_high[index_out] = MAX2(em2->distances_high[index_in], + output->distances_high[index_out]); + } + output->distances_high[index_out] = MIN2(em2->distances_high[index_in], + output->distances_high[index_out]); + } + } // high res loop + } + } + } + + /* free original data */ + em_freeData(&em1); +} + +typedef struct EmitFromParticlesData { + FluidFlowSettings *mfs; + KDTree_3d *tree; + int hires_multiplier; + + EmissionMap *em; + float *particle_vel; + float hr; + + int *min, *max, *res; + + float solid; + float smooth; + float hr_smooth; +} EmitFromParticlesData; + +static void emit_from_particles_task_cb(void *__restrict userdata, + const int z, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + EmitFromParticlesData *data = userdata; + FluidFlowSettings *mfs = data->mfs; + EmissionMap *em = data->em; + const int hires_multiplier = data->hires_multiplier; + + for (int x = data->min[0]; x < data->max[0]; x++) { + for (int y = data->min[1]; y < data->max[1]; y++) { + /* Take low res samples where possible. */ + if (hires_multiplier <= 1 || + !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { + /* Get low res space coordinates. */ + float inv_multiplier = 1.0f / hires_multiplier; + const int lx = x * inv_multiplier; + const int ly = y * inv_multiplier; + const int lz = z * inv_multiplier; + + const int index = manta_get_index( + lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); + const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; + + /* Find particle distance from the kdtree. */ + KDTreeNearest_3d nearest; + const float range = data->solid + data->smooth; + BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); + + if (nearest.dist < range) { + em->influence[index] = (nearest.dist < data->solid) ? + 1.0f : + (1.0f - (nearest.dist - data->solid) / data->smooth); + /* Uses particle velocity as initial velocity for smoke. */ + if (mfs->flags & FLUID_FLOW_INITVELOCITY && + (mfs->psys->part->phystype != PART_PHYS_NO)) { + madd_v3_v3fl( + &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], mfs->vel_multi); + } + } + } + + /* Take high res samples if required. */ + if (hires_multiplier > 1) { + /* get low res space coordinates */ + const float lx = ((float)x) * data->hr; + const float ly = ((float)y) * data->hr; + const float lz = ((float)z) * data->hr; + + const int index = manta_get_index( + x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); + const float ray_start[3] = { + lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr}; + + /* Find particle distance from the kdtree. */ + KDTreeNearest_3d nearest; + const float range = data->solid + data->hr_smooth; + BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); + + if (nearest.dist < range) { + em->influence_high[index] = (nearest.dist < data->solid) ? + 1.0f : + (1.0f - (nearest.dist - data->solid) / data->smooth); + } + } + } + } +} + +static void emit_from_particles(Object *flow_ob, + FluidDomainSettings *mds, + FluidFlowSettings *mfs, + EmissionMap *em, + Depsgraph *depsgraph, + Scene *scene, + float dt) +{ + if (mfs && mfs->psys && mfs->psys->part && + ELEM(mfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected + { + ParticleSimulationData sim; + ParticleSystem *psys = mfs->psys; + float *particle_pos; + float *particle_vel; + int totpart = psys->totpart, totchild; + int p = 0; + int valid_particles = 0; + int bounds_margin = 1; + + /* radius based flow */ + const float solid = mfs->particle_size * 0.5f; + const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */ + int hires_multiplier = 1; + KDTree_3d *tree = NULL; + + sim.depsgraph = depsgraph; + sim.scene = scene; + sim.ob = flow_ob; + sim.psys = psys; + sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + /* prepare curvemapping tables */ + if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) { + BKE_curvemapping_changed_all(psys->part->clumpcurve); + } + if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) { + BKE_curvemapping_changed_all(psys->part->roughcurve); + } + if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) { + BKE_curvemapping_changed_all(psys->part->twistcurve); + } + + /* initialize particle cache */ + if (psys->part->type == PART_HAIR) { + // TODO: PART_HAIR not supported whatsoever + totchild = 0; + } + else { + totchild = psys->totchild * psys->part->disp / 100; + } + + particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, + "manta_flow_particles_pos"); + particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, + "manta_flow_particles_vel"); + + /* setup particle radius emission if enabled */ + if (mfs->flags & FLUID_FLOW_USE_PART_SIZE) { + tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild); + + /* check need for high resolution map */ + if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) { + hires_multiplier = mds->noise_scale; + } + + bounds_margin = (int)ceil(solid + smooth); + } + + /* calculate local position for each particle */ + for (p = 0; p < totpart + totchild; p++) { + ParticleKey state; + float *pos, *vel; + if (p < totpart) { + if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) { + continue; + } + } + else { + /* handle child particle */ + ChildParticle *cpa = &psys->child[p - totpart]; + if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) { + continue; + } + } + + state.time = BKE_scene_frame_get( + scene); /* DEG_get_ctime(depsgraph) does not give subframe time */ + if (psys_get_particle_state(&sim, p, &state, 0) == 0) { + continue; + } + + /* location */ + pos = &particle_pos[valid_particles * 3]; + copy_v3_v3(pos, state.co); + manta_pos_to_cell(mds, pos); + + /* velocity */ + vel = &particle_vel[valid_particles * 3]; + copy_v3_v3(vel, state.vel); + mul_mat3_m4_v3(mds->imat, &particle_vel[valid_particles * 3]); + + if (mfs->flags & FLUID_FLOW_USE_PART_SIZE) { + BLI_kdtree_3d_insert(tree, valid_particles, pos); + } + + /* calculate emission map bounds */ + em_boundInsert(em, pos); + valid_particles++; + } + + /* set emission map */ + clamp_bounds_in_domain(mds, em->min, em->max, NULL, NULL, bounds_margin, dt); + em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier); + + if (!(mfs->flags & FLUID_FLOW_USE_PART_SIZE)) { + for (p = 0; p < valid_particles; p++) { + int cell[3]; + size_t i = 0; + size_t index = 0; + int badcell = 0; + + /* 1. get corresponding cell */ + cell[0] = floor(particle_pos[p * 3]) - em->min[0]; + cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1]; + cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2]; + /* check if cell is valid (in the domain boundary) */ + for (i = 0; i < 3; i++) { + if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) { + badcell = 1; + break; + } + } + if (badcell) { + continue; + } + /* get cell index */ + index = manta_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]); + /* Add influence to emission map */ + em->influence[index] = 1.0f; + /* Uses particle velocity as initial velocity for smoke */ + if (mfs->flags & FLUID_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) { + madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], mfs->vel_multi); + } + } // particles loop + } + else if (valid_particles > 0) { // FLUID_FLOW_USE_PART_SIZE + int min[3], max[3], res[3]; + const float hr = 1.0f / ((float)hires_multiplier); + /* Slightly adjust high res anti-alias smoothness based on number of divisions + * to allow smaller details but yet not differing too much from the low res size. */ + const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f); + + /* setup loop bounds */ + for (int i = 0; i < 3; i++) { + min[i] = em->min[i] * hires_multiplier; + max[i] = em->max[i] * hires_multiplier; + res[i] = em->res[i] * hires_multiplier; + } + + BLI_kdtree_3d_balance(tree); + + EmitFromParticlesData data = { + .mfs = mfs, + .tree = tree, + .hires_multiplier = hires_multiplier, + .hr = hr, + .em = em, + .particle_vel = particle_vel, + .min = min, + .max = max, + .res = res, + .solid = solid, + .smooth = smooth, + .hr_smooth = hr_smooth, + }; + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 2; + BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings); + } + + if (mfs->flags & FLUID_FLOW_USE_PART_SIZE) { + BLI_kdtree_3d_free(tree); + } + + /* free data */ + if (particle_pos) { + MEM_freeN(particle_pos); + } + if (particle_vel) { + MEM_freeN(particle_vel); + } + } +} + +/* Calculate map of (minimum) distances to flow/obstacle surface. Distances outside mesh are + * positive, inside negative. */ +static void update_mesh_distances(int index, + float *mesh_distances, + BVHTreeFromMesh *tree_data, + const float ray_start[3], + float surface_thickness, + int use_plane_init) +{ + float min_dist = FLT_MAX; + + /* Ensure that planes get initialized correctly. */ + if (use_plane_init) { + BVHTreeNearest nearest = {0}; + nearest.index = -1; + nearest.dist_sq = surface_thickness; + + if (BLI_bvhtree_find_nearest( + tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) { + float ray[3] = {0}; + sub_v3_v3v3(ray, ray_start, nearest.co); + min_dist = len_v3(ray); + min_dist = (-1.0f) * fabsf(min_dist); + mesh_distances[index] = MIN2(mesh_distances[index], min_dist); + } + return; + } + + /* First pass: Ray-casts in 26 directions + * (6 main axis + 12 quadrant diagonals (2D) + 8 octant diagonals (3D)). */ + float ray_dirs[26][3] = { + {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, + {0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, {1.0f, -1.0f, 0.0f}, + {-1.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, {1.0f, 0.0f, -1.0f}, + {-1.0f, 0.0f, 1.0f}, {-1.0f, 0.0f, -1.0f}, {0.0f, 1.0f, 1.0f}, {0.0f, 1.0f, -1.0f}, + {0.0f, -1.0f, 1.0f}, {0.0f, -1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}}; + size_t ray_cnt = sizeof ray_dirs / sizeof ray_dirs[0]; + + /* Count for ray misses (no face hit) and cases where ray direction matches face normal + * direction. */ + int miss_cnt = 0, dir_cnt = 0; + min_dist = FLT_MAX; + + for (int i = 0; i < ray_cnt; i++) { + BVHTreeRayHit hit_tree = {0}; + hit_tree.index = -1; + hit_tree.dist = FLT_MAX; + + normalize_v3(ray_dirs[i]); + BLI_bvhtree_ray_cast(tree_data->tree, + ray_start, + ray_dirs[i], + 0.0f, + &hit_tree, + tree_data->raycast_callback, + tree_data); + + /* Ray did not hit mesh. Current point definitely not inside mesh. Inside mesh all rays have to + * hit. */ + if (hit_tree.index == -1) { + miss_cnt++; + continue; + } + + /* Ray and normal are in pointing opposite directions. */ + if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) { + dir_cnt++; + } + + if (hit_tree.dist < min_dist) { + min_dist = hit_tree.dist; + } + } + + /* Point lies inside mesh. Use negative sign for distance value. */ + if (!(miss_cnt > 0 || dir_cnt == ray_cnt)) { + min_dist = (-1.0f) * fabsf(min_dist); + } + + /* Update global distance array but ensure that older entries are not overridden. */ + mesh_distances[index] = MIN2(mesh_distances[index], min_dist); + + /* Second pass: Use nearest neighbor search on mesh surface. */ + BVHTreeNearest nearest = {0}; + nearest.index = -1; + nearest.dist_sq = 5; + + if (BLI_bvhtree_find_nearest( + tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) { + float ray[3] = {0}; + sub_v3_v3v3(ray, nearest.co, ray_start); + min_dist = len_v3(ray); + // CLAMP(min_dist, 0.5, min_dist); + + BVHTreeRayHit hit_tree = {0}; + hit_tree.index = -1; + hit_tree.dist = FLT_MAX; + + normalize_v3(ray); + BLI_bvhtree_ray_cast( + tree_data->tree, ray_start, ray, 0.0f, &hit_tree, tree_data->raycast_callback, tree_data); + + /* Only proceed if casted ray hit the mesh surface. */ + if (hit_tree.index != -1) { + + /* Ray and normal are in pointing same directions: Point must lie inside mesh. */ + if (dot_v3v3(ray, hit_tree.no) > 0) { + min_dist = (-1.0f) * fabsf(min_dist); + } + + /* Update distance value with more accurate one from this nearest neighbor search. + * Skip if new value would be outside and current value has inside value already. */ + if (!(min_dist > 0 && mesh_distances[index] <= 0)) { + mesh_distances[index] = min_dist; + } + } + } + + if (surface_thickness) { + mesh_distances[index] -= surface_thickness; + } +} + +static void sample_mesh(FluidFlowSettings *mfs, + const MVert *mvert, + const MLoop *mloop, + const MLoopTri *mlooptri, + const MLoopUV *mloopuv, + float *influence_map, + float *velocity_map, + int index, + const int base_res[3], + float flow_center[3], + BVHTreeFromMesh *tree_data, + const float ray_start[3], + const float *vert_vel, + bool has_velocity, + int defgrp_index, + MDeformVert *dvert, + float x, + float y, + float z) +{ + float ray_dir[3] = {1.0f, 0.0f, 0.0f}; + BVHTreeRayHit hit = {0}; + BVHTreeNearest nearest = {0}; + + float volume_factor = 0.0f; + float sample_str = 0.0f; + + hit.index = -1; + hit.dist = FLT_MAX; + nearest.index = -1; + nearest.dist_sq = mfs->surface_distance * + mfs->surface_distance; /* find_nearest uses squared distance */ + + /* Check volume collision */ + if (mfs->volume_density) { + if (BLI_bvhtree_ray_cast(tree_data->tree, + ray_start, + ray_dir, + 0.0f, + &hit, + tree_data->raycast_callback, + tree_data) != -1) { + float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2]; + /* If ray and hit face normal are facing same direction + * hit point is inside a closed mesh. */ + if (dot >= 0) { + /* Also cast a ray in opposite direction to make sure + * point is at least surrounded by two faces */ + negate_v3(ray_dir); + hit.index = -1; + hit.dist = FLT_MAX; + + BLI_bvhtree_ray_cast(tree_data->tree, + ray_start, + ray_dir, + 0.0f, + &hit, + tree_data->raycast_callback, + tree_data); + if (hit.index != -1) { + volume_factor = mfs->volume_density; + } + } + } + } + + /* find the nearest point on the mesh */ + if (BLI_bvhtree_find_nearest( + tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) { + float weights[3]; + int v1, v2, v3, f_index = nearest.index; + float n1[3], n2[3], n3[3], hit_normal[3]; + + /* emit from surface based on distance */ + if (mfs->surface_distance) { + sample_str = sqrtf(nearest.dist_sq) / mfs->surface_distance; + CLAMP(sample_str, 0.0f, 1.0f); + sample_str = pow(1.0f - sample_str, 0.5f); + } + else { + sample_str = 0.0f; + } + + /* calculate barycentric weights for nearest point */ + v1 = mloop[mlooptri[f_index].tri[0]].v; + v2 = mloop[mlooptri[f_index].tri[1]].v; + v3 = mloop[mlooptri[f_index].tri[2]].v; + interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co); + + if (mfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) { + /* apply normal directional velocity */ + if (mfs->vel_normal) { + /* interpolate vertex normal vectors to get nearest point normal */ + normal_short_to_float_v3(n1, mvert[v1].no); + normal_short_to_float_v3(n2, mvert[v2].no); + normal_short_to_float_v3(n3, mvert[v3].no); + interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights); + normalize_v3(hit_normal); + /* apply normal directional and random velocity + * - TODO: random disabled for now since it doesn't really work well + * as pressure calc smoothens it out. */ + velocity_map[index * 3] += hit_normal[0] * mfs->vel_normal * 0.25f; + velocity_map[index * 3 + 1] += hit_normal[1] * mfs->vel_normal * 0.25f; + velocity_map[index * 3 + 2] += hit_normal[2] * mfs->vel_normal * 0.25f; + /* TODO: for fire emitted from mesh surface we can use + * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */ + } + /* apply object velocity */ + if (has_velocity && mfs->vel_multi) { + float hit_vel[3]; + interp_v3_v3v3v3( + hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights); + velocity_map[index * 3] += hit_vel[0] * mfs->vel_multi; + velocity_map[index * 3 + 1] += hit_vel[1] * mfs->vel_multi; + velocity_map[index * 3 + 2] += hit_vel[2] * mfs->vel_multi; +# ifdef DEBUG_PRINT + /* Debugging: Print flow object velocities. */ + printf("adding flow object vel: [%f, %f, %f]\n", hit_vel[0], hit_vel[1], hit_vel[2]); +# endif + } + velocity_map[index * 3] += mfs->vel_coord[0]; + velocity_map[index * 3 + 1] += mfs->vel_coord[1]; + velocity_map[index * 3 + 2] += mfs->vel_coord[2]; + } + + /* apply vertex group influence if used */ + if (defgrp_index != -1 && dvert) { + float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] + + defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] + + defvert_find_weight(&dvert[v3], defgrp_index) * weights[2]; + sample_str *= weight_mask; + } + + /* apply emission texture */ + if ((mfs->flags & FLUID_FLOW_TEXTUREEMIT) && mfs->noise_texture) { + float tex_co[3] = {0}; + TexResult texres; + + if (mfs->texture_type == FLUID_FLOW_TEXTURE_MAP_AUTO) { + tex_co[0] = ((x - flow_center[0]) / base_res[0]) / mfs->texture_size; + tex_co[1] = ((y - flow_center[1]) / base_res[1]) / mfs->texture_size; + tex_co[2] = ((z - flow_center[2]) / base_res[2] - mfs->texture_offset) / mfs->texture_size; + } + else if (mloopuv) { + const float *uv[3]; + uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv; + uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv; + uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv; + + interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights); + + /* map between -1.0f and 1.0f */ + tex_co[0] = tex_co[0] * 2.0f - 1.0f; + tex_co[1] = tex_co[1] * 2.0f - 1.0f; + tex_co[2] = mfs->texture_offset; + } + texres.nor = NULL; + BKE_texture_get_value(NULL, mfs->noise_texture, tex_co, &texres, false); + sample_str *= texres.tin; + } + } + + /* multiply initial velocity by emitter influence */ + if (mfs->flags & FLUID_FLOW_INITVELOCITY && velocity_map) { + mul_v3_fl(&velocity_map[index * 3], sample_str); + } + + /* apply final influence based on volume factor */ + influence_map[index] = MAX2(volume_factor, sample_str); +} + +typedef struct EmitFromDMData { + FluidDomainSettings *mds; + FluidFlowSettings *mfs; + const MVert *mvert; + const MLoop *mloop; + const MLoopTri *mlooptri; + const MLoopUV *mloopuv; + MDeformVert *dvert; + int defgrp_index; + + BVHTreeFromMesh *tree; + int hires_multiplier; + float hr; + + EmissionMap *em; + bool has_velocity; + float *vert_vel; + + float *flow_center; + int *min, *max, *res; +} EmitFromDMData; + +static void emit_from_mesh_task_cb(void *__restrict userdata, + const int z, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + EmitFromDMData *data = userdata; + EmissionMap *em = data->em; + const int hires_multiplier = data->hires_multiplier; + + for (int x = data->min[0]; x < data->max[0]; x++) { + for (int y = data->min[1]; y < data->max[1]; y++) { + /* take low res samples where possible */ + if (hires_multiplier <= 1 || + !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { + /* get low res space coordinates */ + const int lx = x / hires_multiplier; + const int ly = y / hires_multiplier; + const int lz = z / hires_multiplier; + + const int index = manta_get_index( + lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); + const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; + + /* Emission for smoke and fire. Result in em->influence. Also, calculate invels */ + sample_mesh(data->mfs, + data->mvert, + data->mloop, + data->mlooptri, + data->mloopuv, + em->influence, + em->velocity, + index, + data->mds->base_res, + data->flow_center, + data->tree, + ray_start, + data->vert_vel, + data->has_velocity, + data->defgrp_index, + data->dvert, + (float)lx, + (float)ly, + (float)lz); + + /* Calculate levelset from meshes. Result in em->distances */ + update_mesh_distances(index, + em->distances, + data->tree, + ray_start, + data->mfs->surface_distance, + data->mfs->flags & FLUID_FLOW_USE_PLANE_INIT); + } + + /* take high res samples if required */ + if (hires_multiplier > 1) { + /* get low res space coordinates */ + const float lx = ((float)x) * data->hr; + const float ly = ((float)y) * data->hr; + const float lz = ((float)z) * data->hr; + + const int index = manta_get_index( + x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); + const float ray_start[3] = { + lx + 0.5f * data->hr, + ly + 0.5f * data->hr, + lz + 0.5f * data->hr, + }; + + /* Emission for smoke and fire high. Result in em->influence_high */ + if (data->mfs->type == FLUID_FLOW_TYPE_SMOKE || data->mfs->type == FLUID_FLOW_TYPE_FIRE || + data->mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE) { + sample_mesh(data->mfs, + data->mvert, + data->mloop, + data->mlooptri, + data->mloopuv, + em->influence_high, + NULL, + index, + data->mds->base_res, + data->flow_center, + data->tree, + ray_start, + data->vert_vel, + data->has_velocity, + data->defgrp_index, + data->dvert, + /* x,y,z needs to be always lowres */ + lx, + ly, + lz); + } + } + } + } +} + +static void emit_from_mesh( + Object *flow_ob, FluidDomainSettings *mds, FluidFlowSettings *mfs, EmissionMap *em, float dt) +{ + if (mfs->mesh) { + Mesh *me = NULL; + MVert *mvert = NULL; + const MLoopTri *mlooptri = NULL; + const MLoop *mloop = NULL; + const MLoopUV *mloopuv = NULL; + MDeformVert *dvert = NULL; + BVHTreeFromMesh tree_data = {NULL}; + int numverts, i; + + float *vert_vel = NULL; + bool has_velocity = false; + + int defgrp_index = mfs->vgroup_density - 1; + float flow_center[3] = {0}; + int min[3], max[3], res[3]; + int hires_multiplier = 1; + + /* copy mesh for thread safety because we modify it, + * main issue is its VertArray being modified, then replaced and freed + */ + me = BKE_mesh_copy_for_eval(mfs->mesh, true); + + /* Duplicate vertices to modify. */ + if (me->mvert) { + me->mvert = MEM_dupallocN(me->mvert); + CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); + } + + BKE_mesh_ensure_normals(me); + mvert = me->mvert; + mloop = me->mloop; + mlooptri = BKE_mesh_runtime_looptri_ensure(me); + numverts = me->totvert; + dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); + mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, mfs->uvlayer_name); + + if (mfs->flags & FLUID_FLOW_INITVELOCITY) { + vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "manta_flow_velocity"); + + if (mfs->numverts != numverts || !mfs->verts_old) { + if (mfs->verts_old) { + MEM_freeN(mfs->verts_old); + } + mfs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "manta_flow_verts_old"); + mfs->numverts = numverts; + } + else { + has_velocity = true; + } + } + + /* Transform mesh vertices to + * domain grid space for fast lookups */ + for (i = 0; i < numverts; i++) { + float n[3]; + + /* vert pos */ + mul_m4_v3(flow_ob->obmat, mvert[i].co); + manta_pos_to_cell(mds, mvert[i].co); + + /* vert normal */ + normal_short_to_float_v3(n, mvert[i].no); + mul_mat3_m4_v3(flow_ob->obmat, n); + mul_mat3_m4_v3(mds->imat, n); + normalize_v3(n); + normal_float_to_short_v3(mvert[i].no, n); + + /* vert velocity */ + if (mfs->flags & FLUID_FLOW_INITVELOCITY) { + float co[3]; + add_v3fl_v3fl_v3i(co, mvert[i].co, mds->shift); + if (has_velocity) { + sub_v3_v3v3(&vert_vel[i * 3], co, &mfs->verts_old[i * 3]); + mul_v3_fl(&vert_vel[i * 3], mds->dx / dt); + } + copy_v3_v3(&mfs->verts_old[i * 3], co); + } + + /* calculate emission map bounds */ + em_boundInsert(em, mvert[i].co); + } + mul_m4_v3(flow_ob->obmat, flow_center); + manta_pos_to_cell(mds, flow_center); + + /* check need for high resolution map */ + if ((mds->flags & FLUID_DOMAIN_USE_NOISE) && (mds->highres_sampling == SM_HRES_FULLSAMPLE)) { + hires_multiplier = mds->noise_scale; + } + + /* set emission map */ + clamp_bounds_in_domain( + mds, em->min, em->max, NULL, NULL, (int)ceil(mfs->surface_distance), dt); + em_allocateData(em, mfs->flags & FLUID_FLOW_INITVELOCITY, hires_multiplier); + + /* setup loop bounds */ + for (i = 0; i < 3; i++) { + min[i] = em->min[i] * hires_multiplier; + max[i] = em->max[i] * hires_multiplier; + res[i] = em->res[i] * hires_multiplier; + } + + if (BKE_bvhtree_from_mesh_get(&tree_data, me, BVHTREE_FROM_LOOPTRI, 4)) { + const float hr = 1.0f / ((float)hires_multiplier); + + EmitFromDMData data = { + .mds = mds, + .mfs = mfs, + .mvert = mvert, + .mloop = mloop, + .mlooptri = mlooptri, + .mloopuv = mloopuv, + .dvert = dvert, + .defgrp_index = defgrp_index, + .tree = &tree_data, + .hires_multiplier = hires_multiplier, + .hr = hr, + .em = em, + .has_velocity = has_velocity, + .vert_vel = vert_vel, + .flow_center = flow_center, + .min = min, + .max = max, + .res = res, + }; + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 2; + BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings); + } + /* free bvh tree */ + free_bvhtree_from_mesh(&tree_data); + + if (vert_vel) { + MEM_freeN(vert_vel); + } + if (me->mvert) { + MEM_freeN(me->mvert); + } + BKE_id_free(NULL, me); + } +} + +/********************************************************** + * Smoke step + **********************************************************/ + +static void adaptive_domain_adjust( + FluidDomainSettings *mds, Object *ob, EmissionMap *emaps, uint numflowobj, float dt) +{ + /* calculate domain shift for current frame */ + int new_shift[3] = {0}; + int total_shift[3]; + float frame_shift_f[3]; + float ob_loc[3] = {0}; + + mul_m4_v3(ob->obmat, ob_loc); + + sub_v3_v3v3(frame_shift_f, ob_loc, mds->prev_loc); + copy_v3_v3(mds->prev_loc, ob_loc); + /* convert global space shift to local "cell" space */ + mul_mat3_m4_v3(mds->imat, frame_shift_f); + frame_shift_f[0] = frame_shift_f[0] / mds->cell_size[0]; + frame_shift_f[1] = frame_shift_f[1] / mds->cell_size[1]; + frame_shift_f[2] = frame_shift_f[2] / mds->cell_size[2]; + /* add to total shift */ + add_v3_v3(mds->shift_f, frame_shift_f); + /* convert to integer */ + total_shift[0] = (int)(floorf(mds->shift_f[0])); + total_shift[1] = (int)(floorf(mds->shift_f[1])); + total_shift[2] = (int)(floorf(mds->shift_f[2])); + int temp_shift[3]; + copy_v3_v3_int(temp_shift, mds->shift); + sub_v3_v3v3_int(new_shift, total_shift, mds->shift); + copy_v3_v3_int(mds->shift, total_shift); + + /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */ + mds->p0[0] = mds->dp0[0] - mds->cell_size[0] * (mds->shift_f[0] - total_shift[0] - 0.5f); + mds->p0[1] = mds->dp0[1] - mds->cell_size[1] * (mds->shift_f[1] - total_shift[1] - 0.5f); + mds->p0[2] = mds->dp0[2] - mds->cell_size[2] * (mds->shift_f[2] - total_shift[2] - 0.5f); + mds->p1[0] = mds->p0[0] + mds->cell_size[0] * mds->base_res[0]; + mds->p1[1] = mds->p0[1] + mds->cell_size[1] * mds->base_res[1]; + mds->p1[2] = mds->p0[2] + mds->cell_size[2] * mds->base_res[2]; + + /* adjust domain resolution */ + const int block_size = mds->noise_scale; + int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3]; + int total_cells = 1, res_changed = 0, shift_changed = 0; + float min_vel[3], max_vel[3]; + int x, y, z; + float *density = manta_smoke_get_density(mds->fluid); + float *fuel = manta_smoke_get_fuel(mds->fluid); + float *bigdensity = manta_smoke_turbulence_get_density(mds->fluid); + float *bigfuel = manta_smoke_turbulence_get_fuel(mds->fluid); + float *vx = manta_get_velocity_x(mds->fluid); + float *vy = manta_get_velocity_y(mds->fluid); + float *vz = manta_get_velocity_z(mds->fluid); + int wt_res[3]; + + if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) { + manta_smoke_turbulence_get_res(mds->fluid, wt_res); + } + + INIT_MINMAX(min_vel, max_vel); + + /* Calculate bounds for current domain content */ + for (x = mds->res_min[0]; x < mds->res_max[0]; x++) { + for (y = mds->res_min[1]; y < mds->res_max[1]; y++) { + for (z = mds->res_min[2]; z < mds->res_max[2]; z++) { + int xn = x - new_shift[0]; + int yn = y - new_shift[1]; + int zn = z - new_shift[2]; + int index; + float max_den; + + /* skip if cell already belongs to new area */ + if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] && + zn <= max[2]) { + continue; + } + + index = manta_get_index(x - mds->res_min[0], + mds->res[0], + y - mds->res_min[1], + mds->res[1], + z - mds->res_min[2]); + max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index]; + + /* check high resolution bounds if max density isnt already high enough */ + if (max_den < mds->adapt_threshold && mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) { + int i, j, k; + /* high res grid index */ + int xx = (x - mds->res_min[0]) * block_size; + int yy = (y - mds->res_min[1]) * block_size; + int zz = (z - mds->res_min[2]) * block_size; + + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + for (k = 0; k < block_size; k++) { + int big_index = manta_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k); + float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) : + bigdensity[big_index]; + if (den > max_den) { + max_den = den; + } + } + } + } + } + + /* content bounds (use shifted coordinates) */ + if (max_den >= mds->adapt_threshold) { + if (min[0] > xn) { + min[0] = xn; + } + if (min[1] > yn) { + min[1] = yn; + } + if (min[2] > zn) { + min[2] = zn; + } + if (max[0] < xn) { + max[0] = xn; + } + if (max[1] < yn) { + max[1] = yn; + } + if (max[2] < zn) { + max[2] = zn; + } + } + + /* velocity bounds */ + if (min_vel[0] > vx[index]) { + min_vel[0] = vx[index]; + } + if (min_vel[1] > vy[index]) { + min_vel[1] = vy[index]; + } + if (min_vel[2] > vz[index]) { + min_vel[2] = vz[index]; + } + if (max_vel[0] < vx[index]) { + max_vel[0] = vx[index]; + } + if (max_vel[1] < vy[index]) { + max_vel[1] = vy[index]; + } + if (max_vel[2] < vz[index]) { + max_vel[2] = vz[index]; + } + } + } + } + + /* also apply emission maps */ + for (int i = 0; i < numflowobj; i++) { + EmissionMap *em = &emaps[i]; + + for (x = em->min[0]; x < em->max[0]; x++) { + for (y = em->min[1]; y < em->max[1]; y++) { + for (z = em->min[2]; z < em->max[2]; z++) { + int index = manta_get_index( + x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]); + float max_den = em->influence[index]; + + /* density bounds */ + if (max_den >= mds->adapt_threshold) { + if (min[0] > x) { + min[0] = x; + } + if (min[1] > y) { + min[1] = y; + } + if (min[2] > z) { + min[2] = z; + } + if (max[0] < x) { + max[0] = x; + } + if (max[1] < y) { + max[1] = y; + } + if (max[2] < z) { + max[2] = z; + } + } + } + } + } + } + + /* calculate new bounds based on these values */ + clamp_bounds_in_domain(mds, min, max, min_vel, max_vel, mds->adapt_margin + 1, dt); + + for (int i = 0; i < 3; i++) { + /* calculate new resolution */ + res[i] = max[i] - min[i]; + total_cells *= res[i]; + + if (new_shift[i]) { + shift_changed = 1; + } + + /* if no content set minimum dimensions */ + if (res[i] <= 0) { + int j; + for (j = 0; j < 3; j++) { + min[j] = 0; + max[j] = 1; + res[j] = 1; + } + res_changed = 1; + total_cells = 1; + break; + } + if (min[i] != mds->res_min[i] || max[i] != mds->res_max[i]) { + res_changed = 1; + } + } + + if (res_changed || shift_changed) { + BKE_fluid_reallocate_copy_fluid( + mds, mds->res, res, mds->res_min, min, mds->res_max, temp_shift, total_shift); + + /* set new domain dimensions */ + copy_v3_v3_int(mds->res_min, min); + copy_v3_v3_int(mds->res_max, max); + copy_v3_v3_int(mds->res, res); + mds->total_cells = total_cells; + + /* Redo adapt time step in manta to refresh solver state (ie time variables) */ + manta_adapt_timestep(mds->fluid); + } + + /* update global size field with new bbox size */ + /* volume bounds */ + float minf[3], maxf[3], size[3]; + madd_v3fl_v3fl_v3fl_v3i(minf, mds->p0, mds->cell_size, mds->res_min); + madd_v3fl_v3fl_v3fl_v3i(maxf, mds->p0, mds->cell_size, mds->res_max); + /* calculate domain dimensions */ + sub_v3_v3v3(size, maxf, minf); + /* apply object scale */ + for (int i = 0; i < 3; i++) { + size[i] = fabsf(size[i] * ob->scale[i]); + } + copy_v3_v3(mds->global_size, size); +} + +BLI_INLINE void apply_outflow_fields(int index, + float distance_value, + float *density, + float *heat, + float *fuel, + float *react, + float *color_r, + float *color_g, + float *color_b, + float *phiout) +{ + /* determine outflow cells - phiout used in smoke and liquids */ + if (phiout) { + phiout[index] = distance_value; + } + + /* set smoke outflow */ + if (density) { + density[index] = 0.0f; + } + if (heat) { + heat[index] = 0.0f; + } + if (fuel) { + fuel[index] = 0.0f; + react[index] = 0.0f; + } + if (color_r) { + color_r[index] = 0.0f; + color_g[index] = 0.0f; + color_b[index] = 0.0f; + } +} + +BLI_INLINE void apply_inflow_fields(FluidFlowSettings *mfs, + float emission_value, + float distance_value, + int index, + float *density_in, + const float *density, + float *heat_in, + const float *heat, + float *fuel_in, + const float *fuel, + float *react_in, + const float *react, + float *color_r_in, + const float *color_r, + float *color_g_in, + const float *color_g, + float *color_b_in, + const float *color_b, + float *phi_in, + float *emission_in) +{ + /* add inflow */ + if (phi_in) { + phi_in[index] = distance_value; + } + + /* save emission value for manta inflow */ + if (emission_in) { + emission_in[index] = emission_value; + } + + /* add smoke inflow */ + int absolute_flow = (mfs->flags & FLUID_FLOW_ABSOLUTE); + float dens_old = (density) ? density[index] : 0.0; + // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */ + float dens_flow = (mfs->type == FLUID_FLOW_TYPE_FIRE) ? 0.0f : emission_value * mfs->density; + float fuel_flow = (fuel) ? emission_value * mfs->fuel_amount : 0.0f; + /* add heat */ + if (heat && heat_in) { + if (emission_value > 0.0f) { + heat_in[index] = ADD_IF_LOWER(heat[index], mfs->temperature); + /* Scale inflow by dt/frame-length. + * This is to ensure that adaptive steps don't apply too much emission. */ + } + else { + heat_in[index] = heat[index]; + } + } + + /* set density and fuel - absolute mode */ + if (absolute_flow) { + if (density && density_in) { + density_in[index] = density[index]; + if (mfs->type != FLUID_FLOW_TYPE_FIRE && dens_flow > density[index]) { + density_in[index] = dens_flow; + } + } + if (fuel && fuel_in) { + fuel_in[index] = fuel[index]; + if (mfs->type != FLUID_FLOW_TYPE_SMOKE && fuel_flow && fuel_flow > fuel[index]) { + fuel_in[index] = fuel_flow; + } + } + } + /* set density and fuel - additive mode */ + else { + if (density && density_in) { + density_in[index] = density[index]; + if (mfs->type != FLUID_FLOW_TYPE_FIRE) { + density_in[index] += dens_flow; + CLAMP(density_in[index], 0.0f, 1.0f); + } + } + if (fuel && fuel_in) { + fuel_in[index] = fuel[index]; + if (mfs->type != FLUID_FLOW_TYPE_SMOKE && mfs->fuel_amount) { + fuel_in[index] += fuel_flow; + CLAMP(fuel_in[index], 0.0f, 10.0f); + } + } + } + + /* set color */ + if (color_r && color_r_in) { + color_r_in[index] = color_r[index]; + color_g_in[index] = color_g[index]; + color_b_in[index] = color_b[index]; + + if (dens_flow) { + float total_dens = density[index] / (dens_old + dens_flow); + color_r_in[index] = (color_r[index] + mfs->color[0] * dens_flow) * total_dens; + color_g_in[index] = (color_g[index] + mfs->color[1] * dens_flow) * total_dens; + color_b_in[index] = (color_b[index] + mfs->color[2] * dens_flow) * total_dens; + } + } + + /* set fire reaction coordinate */ + if (fuel && fuel_in) { + /* Instead of using 1.0 for all new fuel add slight falloff to reduce flow blocky-ness. */ + float value = 1.0f - pow2f(1.0f - emission_value); + + if (fuel[index] > FLT_EPSILON && value > react[index]) { + float f = fuel_flow / fuel[index]; + react_in[index] = value * f + (1.0f - f) * react[index]; + CLAMP(react_in[index], 0.0f, value); + } + else { + react_in[index] = react[index]; + } + } +} + +static void update_flowsflags(FluidDomainSettings *mds, Object **flowobjs, int numflowobj) +{ + int active_fields = mds->active_fields; + uint flow_index; + + /* Monitor active fields based on flow settings */ + for (flow_index = 0; flow_index < numflowobj; flow_index++) { + Object *coll_ob = flowobjs[flow_index]; + FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(coll_ob, + eModifierType_Fluid); + + // Sanity check + if (!mmd2) { + continue; + } + + /* First, remove all flags that we want to update. */ + int prev_flags = (FLUID_DOMAIN_ACTIVE_INVEL | FLUID_DOMAIN_ACTIVE_OUTFLOW | + FLUID_DOMAIN_ACTIVE_HEAT | FLUID_DOMAIN_ACTIVE_FIRE | + FLUID_DOMAIN_ACTIVE_COLOR_SET | FLUID_DOMAIN_ACTIVE_COLORS); + active_fields &= ~prev_flags; + + if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) { + FluidFlowSettings *mfs = mmd2->flow; + if (!mfs) { + break; + } + if (mfs->flags & FLUID_FLOW_INITVELOCITY) { + active_fields |= FLUID_DOMAIN_ACTIVE_INVEL; + } + if (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) { + active_fields |= FLUID_DOMAIN_ACTIVE_OUTFLOW; + } + /* liquids done from here */ + if (mds->type == FLUID_DOMAIN_TYPE_LIQUID) { + continue; + } + + /* activate heat field if flow produces any heat */ + if (mfs->temperature) { + active_fields |= FLUID_DOMAIN_ACTIVE_HEAT; + } + /* activate fuel field if flow adds any fuel */ + if (mfs->fuel_amount && + (mfs->type == FLUID_FLOW_TYPE_FIRE || mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE)) { + active_fields |= FLUID_DOMAIN_ACTIVE_FIRE; + } + /* activate color field if flows add smoke with varying colors */ + if (mfs->density && + (mfs->type == FLUID_FLOW_TYPE_SMOKE || mfs->type == FLUID_FLOW_TYPE_SMOKEFIRE)) { + if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) { + copy_v3_v3(mds->active_color, mfs->color); + active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET; + } + else if (!equals_v3v3(mds->active_color, mfs->color)) { + copy_v3_v3(mds->active_color, mfs->color); + active_fields |= FLUID_DOMAIN_ACTIVE_COLORS; + } + } + } + } + /* Monitor active fields based on domain settings */ + if (mds->type == FLUID_DOMAIN_TYPE_GAS && active_fields & FLUID_DOMAIN_ACTIVE_FIRE) { + /* heat is always needed for fire */ + active_fields |= FLUID_DOMAIN_ACTIVE_HEAT; + /* also activate colors if domain smoke color differs from active color */ + if (!(active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET)) { + copy_v3_v3(mds->active_color, mds->flame_smoke_color); + active_fields |= FLUID_DOMAIN_ACTIVE_COLOR_SET; + } + else if (!equals_v3v3(mds->active_color, mds->flame_smoke_color)) { + copy_v3_v3(mds->active_color, mds->flame_smoke_color); + active_fields |= FLUID_DOMAIN_ACTIVE_COLORS; + } + } + /* Finally, initialize new data fields if any */ + if (active_fields & FLUID_DOMAIN_ACTIVE_INVEL) { + manta_ensure_invelocity(mds->fluid, mds->mmd); + } + if (active_fields & FLUID_DOMAIN_ACTIVE_OUTFLOW) { + manta_ensure_outflow(mds->fluid, mds->mmd); + } + if (active_fields & FLUID_DOMAIN_ACTIVE_HEAT) { + manta_smoke_ensure_heat(mds->fluid, mds->mmd); + } + if (active_fields & FLUID_DOMAIN_ACTIVE_FIRE) { + manta_smoke_ensure_fire(mds->fluid, mds->mmd); + } + if (active_fields & FLUID_DOMAIN_ACTIVE_COLORS) { + /* initialize all smoke with "active_color" */ + manta_smoke_ensure_colors(mds->fluid, mds->mmd); + } + if (mds->type == FLUID_DOMAIN_TYPE_LIQUID && + (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY || + mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM || + mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER)) { + manta_liquid_ensure_sndparts(mds->fluid, mds->mmd); + } + mds->active_fields = active_fields; +} + +static void update_flowsfluids(struct Depsgraph *depsgraph, + Scene *scene, + Object *ob, + FluidDomainSettings *mds, + float time_per_frame, + float frame_length, + int frame, + float dt) +{ + EmissionMap *emaps = NULL; + Object **flowobjs = NULL; + uint numflowobj = 0, flow_index = 0; + bool is_first_frame = (frame == mds->cache_frame_start); + + flowobjs = BKE_collision_objects_create( + depsgraph, ob, mds->fluid_group, &numflowobj, eModifierType_Fluid); + + /* Update all flow related flags and ensure that corresponding grids get initialized */ + update_flowsflags(mds, flowobjs, numflowobj); + + /* init emission maps for each flow */ + emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "manta_flow_maps"); + + /* Prepare flow emission maps */ + for (flow_index = 0; flow_index < numflowobj; flow_index++) { + Object *flowobj = flowobjs[flow_index]; + FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj, + eModifierType_Fluid); + + /* Check for initialized smoke object */ + if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) { + FluidFlowSettings *mfs = mmd2->flow; + int subframes = mfs->subframes; + EmissionMap *em = &emaps[flow_index]; + + /* Length of one adaptive frame. If using adaptive stepping, length is smaller than actual + * frame length */ + float adaptframe_length = time_per_frame / frame_length; + /* Adaptive frame length as percentage */ + CLAMP(adaptframe_length, 0.0f, 1.0f); + + /* Further splitting because of emission subframe: If no subframes present, sample_size is 1 + */ + float sample_size = 1.0f / (float)(subframes + 1); + int hires_multiplier = 1; + + /* First frame cannot have any subframes because there is (obviously) no previous frame from + * where subframes could come from */ + if (is_first_frame) { + subframes = 0; + } + + int subframe; + float subframe_dt = dt * sample_size; + + /* Emission loop. When not using subframes this will loop only once. */ + for (subframe = subframes; subframe >= 0; subframe--) { + + /* Temporary emission map used when subframes are enabled, i.e. at least one subframe */ + EmissionMap em_temp = {NULL}; + + /* Set scene time */ + /* Handle emission subframe */ + if (subframe > 0 && !is_first_frame) { + scene->r.subframe = adaptframe_length - + sample_size * (float)(subframe) * (dt / frame_length); + scene->r.cfra = frame - 1; + } + /* Last frame in this loop (subframe == suframes). Can be real end frame or in between + * frames (adaptive frame) */ + else { + /* Handle adaptive subframe (ie has subframe fraction). Need to set according scene + * subframe parameter */ + if (time_per_frame < frame_length) { + scene->r.subframe = adaptframe_length; + scene->r.cfra = frame - 1; + } + /* Handle absolute endframe (ie no subframe fraction). Need to set the scene subframe + * parameter to 0 and advance current scene frame */ + else { + scene->r.subframe = 0.0f; + scene->r.cfra = frame; + } + } + /* Sanity check: subframe portion must be between 0 and 1 */ + CLAMP(scene->r.subframe, 0.0f, 1.0f); +# ifdef DEBUG_PRINT + /* Debugging: Print subframe information. */ + printf( + "flow: frame (is first: %d): %d // scene current frame: %d // scene current subframe: " + "%f\n", + is_first_frame, + frame, + scene->r.cfra, + scene->r.subframe); +# endif + /* Update frame time, this is considering current subframe fraction + * BLI_mutex_lock() called in manta_step(), so safe to update subframe here + * TODO (sebbas): Using BKE_scene_frame_get(scene) instead of new DEG_get_ctime(depsgraph) + * as subframes don't work with the latter yet */ + BKE_object_modifier_update_subframe( + depsgraph, scene, flowobj, true, 5, BKE_scene_frame_get(scene), eModifierType_Fluid); + + /* Emission from particles */ + if (mfs->source == FLUID_FLOW_SOURCE_PARTICLES) { + if (subframes) { + emit_from_particles(flowobj, mds, mfs, &em_temp, depsgraph, scene, subframe_dt); + } + else { + emit_from_particles(flowobj, mds, mfs, em, depsgraph, scene, subframe_dt); + } + + if (!(mfs->flags & FLUID_FLOW_USE_PART_SIZE)) { + hires_multiplier = 1; + } + } + /* Emission from mesh */ + else if (mfs->source == FLUID_FLOW_SOURCE_MESH) { + if (subframes) { + emit_from_mesh(flowobj, mds, mfs, &em_temp, subframe_dt); + } + else { + emit_from_mesh(flowobj, mds, mfs, em, subframe_dt); + } + } + else { + printf("Error: unknown flow emission source\n"); + } + + /* If this we emitted with temp emission map in this loop (subframe emission), we combine + * the temp map with the original emission map */ + if (subframes) { + /* Combine emission maps */ + em_combineMaps( + em, &em_temp, hires_multiplier, !(mfs->flags & FLUID_FLOW_ABSOLUTE), sample_size); + em_freeData(&em_temp); + } + } + } + } +# ifdef DEBUG_PRINT + /* Debugging: Print time information. */ + printf("flow: frame: %d // time per frame: %f // frame length: %f // dt: %f\n", + frame, + time_per_frame, + frame_length, + dt); +# endif + + /* Adjust domain size if needed. Only do this once for every frame */ + if (mds->type == FLUID_DOMAIN_TYPE_GAS && mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { + adaptive_domain_adjust(mds, ob, emaps, numflowobj, dt); + } + + float *phi_in = manta_get_phi_in(mds->fluid); + float *phiout_in = manta_get_phiout_in(mds->fluid); + float *density = manta_smoke_get_density(mds->fluid); + float *color_r = manta_smoke_get_color_r(mds->fluid); + float *color_g = manta_smoke_get_color_g(mds->fluid); + float *color_b = manta_smoke_get_color_b(mds->fluid); + float *fuel = manta_smoke_get_fuel(mds->fluid); + float *heat = manta_smoke_get_heat(mds->fluid); + float *react = manta_smoke_get_react(mds->fluid); + + float *density_in = manta_smoke_get_density_in(mds->fluid); + float *heat_in = manta_smoke_get_heat_in(mds->fluid); + float *color_r_in = manta_smoke_get_color_r_in(mds->fluid); + float *color_g_in = manta_smoke_get_color_g_in(mds->fluid); + float *color_b_in = manta_smoke_get_color_b_in(mds->fluid); + float *fuel_in = manta_smoke_get_fuel_in(mds->fluid); + float *react_in = manta_smoke_get_react_in(mds->fluid); + float *emission_in = manta_smoke_get_emission_in(mds->fluid); + + float *velx_initial = manta_get_in_velocity_x(mds->fluid); + float *vely_initial = manta_get_in_velocity_y(mds->fluid); + float *velz_initial = manta_get_in_velocity_z(mds->fluid); + uint z; + + /* Grid reset before writing again */ + for (z = 0; z < mds->res[0] * mds->res[1] * mds->res[2]; z++) { + if (phi_in) { + phi_in[z] = FLT_MAX; + } + if (phiout_in) { + phiout_in[z] = FLT_MAX; + } + if (density_in) { + density_in[z] = 0.0f; + } + if (heat_in) { + heat_in[z] = 0.0f; + } + if (color_r_in) { + color_r_in[z] = 0.0f; + color_g_in[z] = 0.0f; + color_b_in[z] = 0.0f; + } + if (fuel_in) { + fuel_in[z] = 0.0f; + react_in[z] = 0.0f; + } + if (emission_in) { + emission_in[z] = 0.0f; + } + if (velx_initial) { + velx_initial[z] = 0.0f; + vely_initial[z] = 0.0f; + velz_initial[z] = 0.0f; + } + } + + /* Apply emission data */ + for (flow_index = 0; flow_index < numflowobj; flow_index++) { + Object *flowobj = flowobjs[flow_index]; + FluidModifierData *mmd2 = (FluidModifierData *)modifiers_findByType(flowobj, + eModifierType_Fluid); + + // check for initialized flow object + if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) { + FluidFlowSettings *mfs = mmd2->flow; + EmissionMap *em = &emaps[flow_index]; + float *velocity_map = em->velocity; + float *emission_map = em->influence; + float *distance_map = em->distances; + + int gx, gy, gz, ex, ey, ez, dx, dy, dz; + size_t e_index, d_index; + + // loop through every emission map cell + for (gx = em->min[0]; gx < em->max[0]; gx++) { + for (gy = em->min[1]; gy < em->max[1]; gy++) { + for (gz = em->min[2]; gz < em->max[2]; gz++) { + /* get emission map index */ + ex = gx - em->min[0]; + ey = gy - em->min[1]; + ez = gz - em->min[2]; + e_index = manta_get_index(ex, em->res[0], ey, em->res[1], ez); + + /* get domain index */ + dx = gx - mds->res_min[0]; + dy = gy - mds->res_min[1]; + dz = gz - mds->res_min[2]; + d_index = manta_get_index(dx, mds->res[0], dy, mds->res[1], dz); + /* make sure emission cell is inside the new domain boundary */ + if (dx < 0 || dy < 0 || dz < 0 || dx >= mds->res[0] || dy >= mds->res[1] || + dz >= mds->res[2]) { + continue; + } + + if (mfs->behavior == FLUID_FLOW_BEHAVIOR_OUTFLOW) { // outflow + apply_outflow_fields(d_index, + distance_map[e_index], + density_in, + heat_in, + fuel_in, + react_in, + color_r_in, + color_g_in, + color_b_in, + phiout_in); + } + else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY && mmd2->time > 2) { + apply_inflow_fields(mfs, + 0.0f, + FLT_MAX, + d_index, + density_in, + density, + heat_in, + heat, + fuel_in, + fuel, + react_in, + react, + color_r_in, + color_r, + color_g_in, + color_g, + color_b_in, + color_b, + phi_in, + emission_in); + } + else if (mfs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW || + mfs->behavior == FLUID_FLOW_BEHAVIOR_GEOMETRY) { // inflow + /* only apply inflow if enabled */ + if (mfs->flags & FLUID_FLOW_USE_INFLOW) { + apply_inflow_fields(mfs, + emission_map[e_index], + distance_map[e_index], + d_index, + density_in, + density, + heat_in, + heat, + fuel_in, + fuel, + react_in, + react, + color_r_in, + color_r, + color_g_in, + color_g, + color_b_in, + color_b, + phi_in, + emission_in); + /* initial velocity */ + if (mfs->flags & FLUID_FLOW_INITVELOCITY) { + velx_initial[d_index] = velocity_map[e_index * 3]; + vely_initial[d_index] = velocity_map[e_index * 3 + 1]; + velz_initial[d_index] = velocity_map[e_index * 3 + 2]; + } + } + } + } // low res loop + } + } + + // free emission maps + em_freeData(em); + + } // end emission + } + + BKE_collision_objects_free(flowobjs); + if (emaps) { + MEM_freeN(emaps); + } +} + +typedef struct UpdateEffectorsData { + Scene *scene; + FluidDomainSettings *mds; + ListBase *effectors; + + float *density; + float *fuel; + float *force_x; + float *force_y; + float *force_z; + float *velocity_x; + float *velocity_y; + float *velocity_z; + int *flags; + float *phi_obs_in; +} UpdateEffectorsData; + +static void update_effectors_task_cb(void *__restrict userdata, + const int x, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + UpdateEffectorsData *data = userdata; + FluidDomainSettings *mds = data->mds; + + for (int y = 0; y < mds->res[1]; y++) { + for (int z = 0; z < mds->res[2]; z++) { + EffectedPoint epoint; + float mag; + float voxel_center[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0}; + const uint index = manta_get_index(x, mds->res[0], y, mds->res[1], z); + + if ((data->fuel && MAX2(data->density[index], data->fuel[index]) < FLT_EPSILON) || + (data->density && data->density[index] < FLT_EPSILON) || + (data->phi_obs_in && data->phi_obs_in[index] < 0.0f) || + data->flags[index] & 2) // mantaflow convention: 2 == FlagObstacle + { + continue; + } + + /* get velocities from manta grid space and convert to blender units */ + vel[0] = data->velocity_x[index]; + vel[1] = data->velocity_y[index]; + vel[2] = data->velocity_z[index]; + mul_v3_fl(vel, mds->dx); + + /* convert vel to global space */ + mag = len_v3(vel); + mul_mat3_m4_v3(mds->obmat, vel); + normalize_v3(vel); + mul_v3_fl(vel, mag); + + voxel_center[0] = mds->p0[0] + mds->cell_size[0] * ((float)(x + mds->res_min[0]) + 0.5f); + voxel_center[1] = mds->p0[1] + mds->cell_size[1] * ((float)(y + mds->res_min[1]) + 0.5f); + voxel_center[2] = mds->p0[2] + mds->cell_size[2] * ((float)(z + mds->res_min[2]) + 0.5f); + mul_m4_v3(mds->obmat, voxel_center); + + /* do effectors */ + pd_point_from_loc(data->scene, voxel_center, vel, index, &epoint); + BKE_effectors_apply(data->effectors, NULL, mds->effector_weights, &epoint, retvel, NULL); + + /* convert retvel to local space */ + mag = len_v3(retvel); + mul_mat3_m4_v3(mds->imat, retvel); + normalize_v3(retvel); + mul_v3_fl(retvel, mag); + + /* constrain forces to interval -1 to 1 */ + data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f); + data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f); + data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f); + } + } +} + +static void update_effectors( + Depsgraph *depsgraph, Scene *scene, Object *ob, FluidDomainSettings *mds, float UNUSED(dt)) +{ + ListBase *effectors; + /* make sure smoke flow influence is 0.0f */ + mds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f; + effectors = BKE_effectors_create(depsgraph, ob, NULL, mds->effector_weights); + + if (effectors) { + // precalculate wind forces + UpdateEffectorsData data; + data.scene = scene; + data.mds = mds; + data.effectors = effectors; + data.density = manta_smoke_get_density(mds->fluid); + data.fuel = manta_smoke_get_fuel(mds->fluid); + data.force_x = manta_get_force_x(mds->fluid); + data.force_y = manta_get_force_y(mds->fluid); + data.force_z = manta_get_force_z(mds->fluid); + data.velocity_x = manta_get_velocity_x(mds->fluid); + data.velocity_y = manta_get_velocity_y(mds->fluid); + data.velocity_z = manta_get_velocity_z(mds->fluid); + data.flags = manta_smoke_get_obstacle(mds->fluid); + data.phi_obs_in = manta_get_phiobs_in(mds->fluid); + + TaskParallelSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = 2; + BLI_task_parallel_range(0, mds->res[0], &data, update_effectors_task_cb, &settings); + } + + BKE_effectors_free(effectors); +} + +static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Object *ob) +{ + Mesh *me; + MVert *mverts; + MPoly *mpolys; + MLoop *mloops; + short *normals, *no_s; + float no[3]; + float min[3]; + float max[3]; + float size[3]; + float cell_size_scaled[3]; + + /* assign material + flags to new dm + * if there's no faces in original dm, keep materials and flags unchanged */ + MPoly *mpoly; + MPoly mp_example = {0}; + mpoly = orgmesh->mpoly; + if (mpoly) { + mp_example = *mpoly; + } + /* else leave NULL'd */ + + const short mp_mat_nr = mp_example.mat_nr; + const char mp_flag = mp_example.flag; + + int i; + int num_verts, num_normals, num_faces; + + if (!mds->fluid) { + return NULL; + } + + num_verts = manta_liquid_get_num_verts(mds->fluid); + num_normals = manta_liquid_get_num_normals(mds->fluid); + num_faces = manta_liquid_get_num_triangles(mds->fluid); + +# ifdef DEBUG_PRINT + /* Debugging: Print number of vertices, normals, and faces. */ + printf("num_verts: %d, num_normals: %d, num_faces: %d\n", num_verts, num_normals, num_faces); +# endif + + if (!num_verts || !num_faces) { + return NULL; + } + + me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces); + mverts = me->mvert; + mpolys = me->mpoly; + mloops = me->mloop; + if (!me) { + return NULL; + } + + // Get size (dimension) but considering scaling scaling + copy_v3_v3(cell_size_scaled, mds->cell_size); + mul_v3_v3(cell_size_scaled, ob->scale); + madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, cell_size_scaled, mds->res_min); + madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, cell_size_scaled, mds->res_max); + sub_v3_v3v3(size, max, min); + + // Biggest dimension will be used for upscaling + float max_size = MAX3(size[0], size[1], size[2]); + + // Vertices + for (i = 0; i < num_verts; i++, mverts++) { + // read raw data. is normalized cube around domain origin + mverts->co[0] = manta_liquid_get_vertex_x_at(mds->fluid, i); + mverts->co[1] = manta_liquid_get_vertex_y_at(mds->fluid, i); + mverts->co[2] = manta_liquid_get_vertex_z_at(mds->fluid, i); + + // if reading raw data directly from manta, normalize now, otherwise omit this, ie when reading + // from files + { + // normalize to unit cube around 0 + mverts->co[0] -= ((float)mds->res[0] * mds->mesh_scale) * 0.5f; + mverts->co[1] -= ((float)mds->res[1] * mds->mesh_scale) * 0.5f; + mverts->co[2] -= ((float)mds->res[2] * mds->mesh_scale) * 0.5f; + mverts->co[0] *= mds->dx / mds->mesh_scale; + mverts->co[1] *= mds->dx / mds->mesh_scale; + mverts->co[2] *= mds->dx / mds->mesh_scale; + } + + mverts->co[0] *= max_size / fabsf(ob->scale[0]); + mverts->co[1] *= max_size / fabsf(ob->scale[1]); + mverts->co[2] *= max_size / fabsf(ob->scale[2]); +# ifdef DEBUG_PRINT + /* Debugging: Print coordinates of vertices. */ + printf("mverts->co[0]: %f, mverts->co[1]: %f, mverts->co[2]: %f\n", + mverts->co[0], + mverts->co[1], + mverts->co[2]); +# endif + } + + // Normals + normals = MEM_callocN(sizeof(short) * num_normals * 3, "Fluidmesh_tmp_normals"); + + for (i = 0, no_s = normals; i < num_normals; no_s += 3, i++) { + no[0] = manta_liquid_get_normal_x_at(mds->fluid, i); + no[1] = manta_liquid_get_normal_y_at(mds->fluid, i); + no[2] = manta_liquid_get_normal_z_at(mds->fluid, i); + + normal_float_to_short_v3(no_s, no); +# ifdef DEBUG_PRINT + /* Debugging: Print coordinates of normals. */ + printf("no_s[0]: %d, no_s[1]: %d, no_s[2]: %d\n", no_s[0], no_s[1], no_s[2]); +# endif + } + + // Triangles + for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) { + /* initialize from existing face */ + mpolys->mat_nr = mp_mat_nr; + mpolys->flag = mp_flag; + + mpolys->loopstart = i * 3; + mpolys->totloop = 3; + + mloops[0].v = manta_liquid_get_triangle_x_at(mds->fluid, i); + mloops[1].v = manta_liquid_get_triangle_y_at(mds->fluid, i); + mloops[2].v = manta_liquid_get_triangle_z_at(mds->fluid, i); +# ifdef DEBUG_PRINT + /* Debugging: Print mesh faces. */ + printf("mloops[0].v: %d, mloops[1].v: %d, mloops[2].v: %d\n", + mloops[0].v, + mloops[1].v, + mloops[2].v); +# endif + } + + BKE_mesh_ensure_normals(me); + BKE_mesh_calc_edges(me, false, false); + BKE_mesh_vert_normals_apply(me, (short(*)[3])normals); + + MEM_freeN(normals); + + /* return early if no mesh vert velocities required */ + if ((mds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS) == 0) { + return me; + } + + if (mds->mesh_velocities) { + MEM_freeN(mds->mesh_velocities); + } + + mds->mesh_velocities = MEM_calloc_arrayN( + num_verts, sizeof(FluidDomainVertexVelocity), "Fluidmesh_vertvelocities"); + mds->totvert = num_verts; + + FluidDomainVertexVelocity *velarray = NULL; + velarray = mds->mesh_velocities; + + float time_mult = 25.f * DT_DEFAULT; + + for (i = 0; i < num_verts; i++, mverts++) { + velarray[i].vel[0] = manta_liquid_get_vertvel_x_at(mds->fluid, i) * (mds->dx / time_mult); + velarray[i].vel[1] = manta_liquid_get_vertvel_y_at(mds->fluid, i) * (mds->dx / time_mult); + velarray[i].vel[2] = manta_liquid_get_vertvel_z_at(mds->fluid, i) * (mds->dx / time_mult); +# ifdef DEBUG_PRINT + /* Debugging: Print velocities of vertices. */ + printf("velarray[%d].vel[0]: %f, velarray[%d].vel[1]: %f, velarray[%d].vel[2]: %f\n", + i, + velarray[i].vel[0], + i, + velarray[i].vel[1], + i, + velarray[i].vel[2]); +# endif + } + + return me; +} + +static Mesh *create_smoke_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Object *ob) +{ + Mesh *result; + MVert *mverts; + MPoly *mpolys; + MLoop *mloops; + float min[3]; + float max[3]; + float *co; + MPoly *mp; + MLoop *ml; + + int num_verts = 8; + int num_faces = 6; + int i; + float ob_loc[3] = {0}; + float ob_cache_loc[3] = {0}; + + /* Just copy existing mesh if there is no content or if the adaptive domain is not being used. */ + if (mds->total_cells <= 1 || (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) == 0) { + return BKE_mesh_copy_for_eval(orgmesh, false); + } + + result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces); + mverts = result->mvert; + mpolys = result->mpoly; + mloops = result->mloop; + + if (num_verts) { + /* Volume bounds. */ + madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min); + madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, mds->cell_size, mds->res_max); + + /* Set vertices of smoke BB. Especially important, when BB changes (adaptive domain). */ + /* Top slab */ + co = mverts[0].co; + co[0] = min[0]; + co[1] = min[1]; + co[2] = max[2]; + co = mverts[1].co; + co[0] = max[0]; + co[1] = min[1]; + co[2] = max[2]; + co = mverts[2].co; + co[0] = max[0]; + co[1] = max[1]; + co[2] = max[2]; + co = mverts[3].co; + co[0] = min[0]; + co[1] = max[1]; + co[2] = max[2]; + /* Bottom slab. */ + co = mverts[4].co; + co[0] = min[0]; + co[1] = min[1]; + co[2] = min[2]; + co = mverts[5].co; + co[0] = max[0]; + co[1] = min[1]; + co[2] = min[2]; + co = mverts[6].co; + co[0] = max[0]; + co[1] = max[1]; + co[2] = min[2]; + co = mverts[7].co; + co[0] = min[0]; + co[1] = max[1]; + co[2] = min[2]; + + /* Create faces. */ + /* Top side. */ + mp = &mpolys[0]; + ml = &mloops[0 * 4]; + mp->loopstart = 0 * 4; + mp->totloop = 4; + ml[0].v = 0; + ml[1].v = 1; + ml[2].v = 2; + ml[3].v = 3; + /* Right side. */ + mp = &mpolys[1]; + ml = &mloops[1 * 4]; + mp->loopstart = 1 * 4; + mp->totloop = 4; + ml[0].v = 2; + ml[1].v = 1; + ml[2].v = 5; + ml[3].v = 6; + /* Bottom side. */ + mp = &mpolys[2]; + ml = &mloops[2 * 4]; + mp->loopstart = 2 * 4; + mp->totloop = 4; + ml[0].v = 7; + ml[1].v = 6; + ml[2].v = 5; + ml[3].v = 4; + /* Left side. */ + mp = &mpolys[3]; + ml = &mloops[3 * 4]; + mp->loopstart = 3 * 4; + mp->totloop = 4; + ml[0].v = 0; + ml[1].v = 3; + ml[2].v = 7; + ml[3].v = 4; + /* Front side. */ + mp = &mpolys[4]; + ml = &mloops[4 * 4]; + mp->loopstart = 4 * 4; + mp->totloop = 4; + ml[0].v = 3; + ml[1].v = 2; + ml[2].v = 6; + ml[3].v = 7; + /* Back side. */ + mp = &mpolys[5]; + ml = &mloops[5 * 4]; + mp->loopstart = 5 * 4; + mp->totloop = 4; + ml[0].v = 1; + ml[1].v = 0; + ml[2].v = 4; + ml[3].v = 5; + + /* Calculate required shift to match domain's global position + * it was originally simulated at (if object moves without manta step). */ + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_v3(ob->obmat, ob_loc); + mul_m4_v3(mds->obmat, ob_cache_loc); + sub_v3_v3v3(mds->obj_shift_f, ob_cache_loc, ob_loc); + /* Convert shift to local space and apply to vertices. */ + mul_mat3_m4_v3(ob->imat, mds->obj_shift_f); + /* Apply shift to vertices. */ + for (i = 0; i < num_verts; i++) { + add_v3_v3(mverts[i].co, mds->obj_shift_f); + } + } + + BKE_mesh_calc_edges(result, false, false); + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + return result; +} + +static void manta_step( + Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me, FluidModifierData *mmd, int frame) +{ + FluidDomainSettings *mds = mmd->domain; + float dt, frame_length, time_total; + float time_per_frame; + bool init_resolution = true; + + /* update object state */ + invert_m4_m4(mds->imat, ob->obmat); + copy_m4_m4(mds->obmat, ob->obmat); + + /* gas domain might use adaptive domain */ + if (mds->type == FLUID_DOMAIN_TYPE_GAS) { + init_resolution = (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) != 0; + } + manta_set_domain_from_mesh(mds, ob, me, init_resolution); + + /* use local variables for adaptive loop, dt can change */ + frame_length = mds->frame_length; + dt = mds->dt; + time_per_frame = 0; + time_total = mds->time_total; + + BLI_mutex_lock(&object_update_lock); + + /* loop as long as time_per_frame (sum of sub dt's) does not exceed actual framelength */ + while (time_per_frame < frame_length) { + manta_adapt_timestep(mds->fluid); + dt = manta_get_timestep(mds->fluid); + + /* save adapted dt so that MANTA object can access it (important when adaptive domain creates + * new MANTA object) */ + mds->dt = dt; + + /* count for how long this while loop is running */ + time_per_frame += dt; + time_total += dt; + + /* Calculate inflow geometry */ + update_flowsfluids(depsgraph, scene, ob, mds, time_per_frame, frame_length, frame, dt); + + manta_update_variables(mds->fluid, mmd); + + /* Calculate obstacle geometry */ + update_obstacles(depsgraph, scene, ob, mds, time_per_frame, frame_length, frame, dt); + + if (mds->total_cells > 1) { + update_effectors(depsgraph, scene, ob, mds, dt); + manta_bake_data(mds->fluid, mmd, frame); + + mds->time_per_frame = time_per_frame; + mds->time_total = time_total; + } + } + + if (mds->type == FLUID_DOMAIN_TYPE_GAS) { + manta_smoke_calc_transparency(mds, DEG_get_evaluated_view_layer(depsgraph)); + } + BLI_mutex_unlock(&object_update_lock); +} + +static void manta_guiding( + Depsgraph *depsgraph, Scene *scene, Object *ob, FluidModifierData *mmd, int frame) +{ + FluidDomainSettings *mds = mmd->domain; + float fps = scene->r.frs_sec / scene->r.frs_sec_base; + float dt = DT_DEFAULT * (25.0f / fps) * mds->time_scale; + ; + + BLI_mutex_lock(&object_update_lock); + + update_obstacles(depsgraph, scene, ob, mds, dt, dt, frame, dt); + manta_bake_guiding(mds->fluid, mmd, frame); + + BLI_mutex_unlock(&object_update_lock); +} + +static void BKE_fluid_modifier_processFlow(FluidModifierData *mmd, + Depsgraph *depsgraph, + Scene *scene, + Object *ob, + Mesh *me, + const int scene_framenr) +{ + if (scene_framenr >= mmd->time) { + BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me); + } + + if (mmd->flow) { + if (mmd->flow->mesh) { + BKE_id_free(NULL, mmd->flow->mesh); + } + mmd->flow->mesh = BKE_mesh_copy_for_eval(me, false); + } + + if (scene_framenr > mmd->time) { + mmd->time = scene_framenr; + } + else if (scene_framenr < mmd->time) { + mmd->time = scene_framenr; + BKE_fluid_modifier_reset_ex(mmd, false); + } +} + +static void BKE_fluid_modifier_processEffector(FluidModifierData *mmd, + Depsgraph *depsgraph, + Scene *scene, + Object *ob, + Mesh *me, + const int scene_framenr) +{ + if (scene_framenr >= mmd->time) { + BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me); + } + + if (mmd->effector) { + if (mmd->effector->mesh) { + BKE_id_free(NULL, mmd->effector->mesh); + } + mmd->effector->mesh = BKE_mesh_copy_for_eval(me, false); + } + + if (scene_framenr > mmd->time) { + mmd->time = scene_framenr; + } + else if (scene_framenr < mmd->time) { + mmd->time = scene_framenr; + BKE_fluid_modifier_reset_ex(mmd, false); + } +} + +static void BKE_fluid_modifier_processDomain(FluidModifierData *mmd, + Depsgraph *depsgraph, + Scene *scene, + Object *ob, + Mesh *me, + const int scene_framenr) +{ + FluidDomainSettings *mds = mmd->domain; + Object *guide_parent = NULL; + Object **objs = NULL; + uint numobj = 0; + FluidModifierData *mmd_parent = NULL; + + bool is_startframe; + is_startframe = (scene_framenr == mds->cache_frame_start); + + /* Reset fluid if no fluid present (obviously) + * or if timeline gets reset to startframe */ + if (!mds->fluid || is_startframe) { + BKE_fluid_modifier_reset_ex(mmd, false); + } + + BKE_fluid_modifier_init(mmd, depsgraph, ob, scene, me); + + /* ensure that time parameters are initialized correctly before every step */ + float fps = scene->r.frs_sec / scene->r.frs_sec_base; + mds->frame_length = DT_DEFAULT * (25.0f / fps) * mds->time_scale; + mds->dt = mds->frame_length; + mds->time_per_frame = 0; + mds->time_total = (scene_framenr - 1) * mds->frame_length; + + /* Guiding parent res pointer needs initialization */ + guide_parent = mds->guide_parent; + if (guide_parent) { + mmd_parent = (FluidModifierData *)modifiers_findByType(guide_parent, eModifierType_Fluid); + if (mmd_parent->domain) { + copy_v3_v3_int(mds->guide_res, mmd_parent->domain->res); + } + } + + objs = BKE_collision_objects_create( + depsgraph, ob, mds->fluid_group, &numobj, eModifierType_Fluid); + update_flowsflags(mds, objs, numobj); + if (objs) { + MEM_freeN(objs); + } + + objs = BKE_collision_objects_create( + depsgraph, ob, mds->effector_group, &numobj, eModifierType_Fluid); + update_obstacleflags(mds, objs, numobj); + if (objs) { + MEM_freeN(objs); + } + + /* Ensure cache directory is not relative */ + const char *relbase = modifier_path_relbase_from_global(ob); + BLI_path_abs(mds->cache_directory, relbase); + + int data_frame = scene_framenr, noise_frame = scene_framenr; + int mesh_frame = scene_framenr, particles_frame = scene_framenr, guide_frame = scene_framenr; + + bool with_smoke, with_liquid; + with_smoke = mds->type == FLUID_DOMAIN_TYPE_GAS; + with_liquid = mds->type == FLUID_DOMAIN_TYPE_LIQUID; + + bool drops, bubble, floater; + drops = mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY; + bubble = mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE; + floater = mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM; + + bool with_script, with_adaptive, with_noise, with_mesh, with_particles, with_guide; + with_script = mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT; + with_adaptive = mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN; + with_noise = mds->flags & FLUID_DOMAIN_USE_NOISE; + with_mesh = mds->flags & FLUID_DOMAIN_USE_MESH; + with_guide = mds->flags & FLUID_DOMAIN_USE_GUIDE; + with_particles = drops || bubble || floater; + + bool has_data, has_noise, has_mesh, has_particles, has_guide; + has_data = has_noise = has_mesh = has_particles = has_guide = false; + + bool baking_data, baking_noise, baking_mesh, baking_particles, baking_guide, bake_outdated; + baking_data = mds->cache_flag & FLUID_DOMAIN_BAKING_DATA; + baking_noise = mds->cache_flag & FLUID_DOMAIN_BAKING_NOISE; + baking_mesh = mds->cache_flag & FLUID_DOMAIN_BAKING_MESH; + baking_particles = mds->cache_flag & FLUID_DOMAIN_BAKING_PARTICLES; + baking_guide = mds->cache_flag & FLUID_DOMAIN_BAKING_GUIDE; + bake_outdated = mds->cache_flag & + (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE | + FLUID_DOMAIN_OUTDATED_NOISE | FLUID_DOMAIN_OUTDATED_MESH | + FLUID_DOMAIN_OUTDATED_PARTICLES | FLUID_DOMAIN_OUTDATED_GUIDE); + + bool resume_data, resume_noise, resume_mesh, resume_particles, resume_guide; + resume_data = (!is_startframe) && (mds->cache_frame_pause_data == scene_framenr); + resume_noise = (!is_startframe) && (mds->cache_frame_pause_noise == scene_framenr); + resume_mesh = (!is_startframe) && (mds->cache_frame_pause_mesh == scene_framenr); + resume_particles = (!is_startframe) && (mds->cache_frame_pause_particles == scene_framenr); + resume_guide = (!is_startframe) && (mds->cache_frame_pause_guide == scene_framenr); + + bool read_cache, bake_cache; + read_cache = false, bake_cache = baking_data || baking_noise || baking_mesh || baking_particles; + + bool with_gdomain; + with_gdomain = (mds->guide_source == FLUID_DOMAIN_GUIDE_SRC_DOMAIN); + + int o_res[3], o_min[3], o_max[3], o_shift[3]; + int mode = mds->cache_type; + int prev_frame = scene_framenr - 1; + + /* Ensure positivity of previous frame. */ + CLAMP(prev_frame, 1, prev_frame); + + /* Cache mode specific settings */ + switch (mode) { + case FLUID_DOMAIN_CACHE_FINAL: + /* Just load the data that has already been baked */ + if (!baking_data && !baking_noise && !baking_mesh && !baking_particles) { + read_cache = true; + bake_cache = false; + } + break; + case FLUID_DOMAIN_CACHE_MODULAR: + /* Just load the data that has already been baked */ + if (!baking_data && !baking_noise && !baking_mesh && !baking_particles) { + read_cache = true; + bake_cache = false; + break; + } + + /* Set to previous frame if the bake was resumed + * ie don't read all of the already baked frames, just the one before bake resumes */ + if (baking_data && resume_data) { + data_frame = prev_frame; + } + if (baking_noise && resume_noise) { + noise_frame = prev_frame; + } + if (baking_mesh && resume_mesh) { + mesh_frame = prev_frame; + } + if (baking_particles && resume_particles) { + particles_frame = prev_frame; + } + if (baking_guide && resume_guide) { + guide_frame = prev_frame; + } + + /* Noise, mesh and particles can never be baked more than data. */ + CLAMP(noise_frame, noise_frame, data_frame); + CLAMP(mesh_frame, mesh_frame, data_frame); + CLAMP(particles_frame, particles_frame, data_frame); + CLAMP(guide_frame, guide_frame, mds->cache_frame_end); + + /* Force to read cache as we're resuming the bake */ + read_cache = true; + break; + case FLUID_DOMAIN_CACHE_REPLAY: + default: + /* Always trying to read the cache in replay mode. */ + read_cache = true; + break; + } + + /* Cache outdated? If so reset, don't read, and then just rebake. + * Note: Only do this in replay mode! */ + bool mode_replay = (mode == FLUID_DOMAIN_CACHE_REPLAY); + if (bake_outdated && mode_replay) { + read_cache = false; + bake_cache = true; + BKE_fluid_cache_free(mds, ob, mds->cache_flag); + } + + /* Try to read from cache and keep track of read success. */ + if (read_cache) { + + /* Read mesh cache. */ + if (with_liquid && with_mesh) { + has_mesh = manta_read_mesh(mds->fluid, mmd, mesh_frame); + } + + /* Read particles cache. */ + if (with_liquid && with_particles) { + has_particles = manta_read_particles(mds->fluid, mmd, particles_frame); + } + + /* Read guide cache. */ + if (with_guide) { + FluidModifierData *mmd2 = (with_gdomain) ? mmd_parent : mmd; + has_guide = manta_read_guiding(mds->fluid, mmd2, scene_framenr, with_gdomain); + } + + /* Read noise and data cache */ + if (with_smoke && with_noise) { + + /* Only reallocate when just reading cache or when resuming during bake. */ + if ((!baking_noise || (baking_noise && resume_noise)) && + manta_read_config(mds->fluid, mmd, noise_frame) && + manta_needs_realloc(mds->fluid, mmd)) { + BKE_fluid_reallocate_fluid(mds, mds->res, 1); + } + has_noise = manta_read_noise(mds->fluid, mmd, noise_frame); + + /* In case of using the adaptive domain, copy all data that was read to a new fluid object. + */ + if (with_adaptive && baking_noise) { + /* Adaptive domain needs to know about current state, so save it, then copy. */ + copy_v3_v3_int(o_res, mds->res); + copy_v3_v3_int(o_min, mds->res_min); + copy_v3_v3_int(o_max, mds->res_max); + copy_v3_v3_int(o_shift, mds->shift); + if (manta_read_config(mds->fluid, mmd, data_frame) && + manta_needs_realloc(mds->fluid, mmd)) { + BKE_fluid_reallocate_copy_fluid( + mds, o_res, mds->res, o_min, mds->res_min, o_max, o_shift, mds->shift); + } + } + has_data = manta_read_data(mds->fluid, mmd, data_frame); + } + /* Read data cache only */ + else { + /* Read config and realloc fluid object if needed. */ + if (manta_read_config(mds->fluid, mmd, data_frame) && manta_needs_realloc(mds->fluid, mmd)) { + BKE_fluid_reallocate_fluid(mds, mds->res, 1); + } + /* Read data cache */ + has_data = manta_read_data(mds->fluid, mmd, data_frame); + } + } + + /* Cache mode specific settings */ + switch (mode) { + case FLUID_DOMAIN_CACHE_FINAL: + case FLUID_DOMAIN_CACHE_MODULAR: + break; + case FLUID_DOMAIN_CACHE_REPLAY: + default: + baking_data = !has_data; + if (with_smoke && with_noise) { + baking_noise = !has_noise; + } + if (with_liquid && with_mesh) { + baking_mesh = !has_mesh; + } + if (with_liquid && with_particles) { + baking_particles = !has_particles; + } + + bake_cache = baking_data || baking_noise || baking_mesh || baking_particles; + break; + } + + /* Trigger bake calls individually */ + if (bake_cache) { + /* Ensure fresh variables at every animation step */ + manta_update_variables(mds->fluid, mmd); + + /* Export mantaflow python script on first frame (once only) and for any bake type */ + if (with_script && is_startframe) { + if (with_smoke) { + manta_smoke_export_script(mmd->domain->fluid, mmd); + } + if (with_liquid) { + manta_liquid_export_script(mmd->domain->fluid, mmd); + } + } + + if (baking_guide && with_guide) { + manta_guiding(depsgraph, scene, ob, mmd, scene_framenr); + } + if (baking_data) { + manta_step(depsgraph, scene, ob, me, mmd, scene_framenr); + manta_write_config(mds->fluid, mmd, scene_framenr); + manta_write_data(mds->fluid, mmd, scene_framenr); + } + if (has_data || baking_data) { + if (baking_noise && with_smoke && with_noise) { + manta_bake_noise(mds->fluid, mmd, scene_framenr); + } + if (baking_mesh && with_liquid && with_mesh) { + manta_bake_mesh(mds->fluid, mmd, scene_framenr); + } + if (baking_particles && with_liquid && with_particles) { + manta_bake_particles(mds->fluid, mmd, scene_framenr); + } + } + } + mmd->time = scene_framenr; +} + +static void BKE_fluid_modifier_process( + FluidModifierData *mmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) +{ + const int scene_framenr = (int)DEG_get_ctime(depsgraph); + + if ((mmd->type & MOD_FLUID_TYPE_FLOW)) { + BKE_fluid_modifier_processFlow(mmd, depsgraph, scene, ob, me, scene_framenr); + } + else if (mmd->type & MOD_FLUID_TYPE_EFFEC) { + BKE_fluid_modifier_processEffector(mmd, depsgraph, scene, ob, me, scene_framenr); + } + else if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { + BKE_fluid_modifier_processDomain(mmd, depsgraph, scene, ob, me, scene_framenr); + } +} + +struct Mesh *BKE_fluid_modifier_do( + FluidModifierData *mmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) +{ + /* Lock so preview render does not read smoke data while it gets modified. */ + if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { + BLI_rw_mutex_lock(mmd->domain->fluid_mutex, THREAD_LOCK_WRITE); + } + + BKE_fluid_modifier_process(mmd, depsgraph, scene, ob, me); + + if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { + BLI_rw_mutex_unlock(mmd->domain->fluid_mutex); + } + + Mesh *result = NULL; + if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) { + /* Return generated geometry depending on domain type. */ + if (mmd->domain->type == FLUID_DOMAIN_TYPE_LIQUID) { + result = create_liquid_geometry(mmd->domain, me, ob); + } + if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS) { + result = create_smoke_geometry(mmd->domain, me, ob); + } + /* Clear flag outside of locked block (above). */ + mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA; + mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE; + mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_MESH; + mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES; + mmd->domain->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE; + } + if (!result) { + result = BKE_mesh_copy_for_eval(me, false); + } + else { + BKE_mesh_copy_settings(result, me); + } + + /* Liquid simulation has a texture space that based on the bounds of the fluid mesh. + * This does not seem particularly useful, but it's backwards compatible. + * + * Smoke simulation needs a texture space relative to the adaptive domain bounds, not the + * original mesh. So recompute it at this point in the modifier stack. See T58492. */ + BKE_mesh_texspace_calc(result); + + return result; +} + +static float calc_voxel_transp( + float *result, float *input, int res[3], int *pixel, float *t_ray, float correct) +{ + const size_t index = manta_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]); + + // T_ray *= T_vox + *t_ray *= expf(input[index] * correct); + + if (result[index] < 0.0f) { + result[index] = *t_ray; + } + + return *t_ray; +} + +static void bresenham_linie_3D(int x1, + int y1, + int z1, + int x2, + int y2, + int z2, + float *t_ray, + BKE_Fluid_BresenhamFn cb, + float *result, + float *input, + int res[3], + float correct) +{ + int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2; + int pixel[3]; + + pixel[0] = x1; + pixel[1] = y1; + pixel[2] = z1; + + dx = x2 - x1; + dy = y2 - y1; + dz = z2 - z1; + + x_inc = (dx < 0) ? -1 : 1; + l = abs(dx); + y_inc = (dy < 0) ? -1 : 1; + m = abs(dy); + z_inc = (dz < 0) ? -1 : 1; + n = abs(dz); + dx2 = l << 1; + dy2 = m << 1; + dz2 = n << 1; + + if ((l >= m) && (l >= n)) { + err_1 = dy2 - l; + err_2 = dz2 - l; + for (i = 0; i < l; i++) { + if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) { + break; + } + if (err_1 > 0) { + pixel[1] += y_inc; + err_1 -= dx2; + } + if (err_2 > 0) { + pixel[2] += z_inc; + err_2 -= dx2; + } + err_1 += dy2; + err_2 += dz2; + pixel[0] += x_inc; + } + } + else if ((m >= l) && (m >= n)) { + err_1 = dx2 - m; + err_2 = dz2 - m; + for (i = 0; i < m; i++) { + if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) { + break; + } + if (err_1 > 0) { + pixel[0] += x_inc; + err_1 -= dy2; + } + if (err_2 > 0) { + pixel[2] += z_inc; + err_2 -= dy2; + } + err_1 += dx2; + err_2 += dz2; + pixel[1] += y_inc; + } + } + else { + err_1 = dy2 - n; + err_2 = dx2 - n; + for (i = 0; i < n; i++) { + if (cb(result, input, res, pixel, t_ray, correct) <= FLT_EPSILON) { + break; + } + if (err_1 > 0) { + pixel[1] += y_inc; + err_1 -= dz2; + } + if (err_2 > 0) { + pixel[0] += x_inc; + err_2 -= dz2; + } + err_1 += dy2; + err_2 += dx2; + pixel[2] += z_inc; + } + } + cb(result, input, res, pixel, t_ray, correct); +} + +static void manta_smoke_calc_transparency(FluidDomainSettings *mds, ViewLayer *view_layer) +{ + float bv[6] = {0}; + float light[3]; + int a, z, slabsize = mds->res[0] * mds->res[1], size = mds->res[0] * mds->res[1] * mds->res[2]; + float *density = manta_smoke_get_density(mds->fluid); + float *shadow = manta_smoke_get_shadow(mds->fluid); + float correct = -7.0f * mds->dx; + + if (!get_light(view_layer, light)) { + return; + } + + /* convert light pos to sim cell space */ + mul_m4_v3(mds->imat, light); + light[0] = (light[0] - mds->p0[0]) / mds->cell_size[0] - 0.5f - (float)mds->res_min[0]; + light[1] = (light[1] - mds->p0[1]) / mds->cell_size[1] - 0.5f - (float)mds->res_min[1]; + light[2] = (light[2] - mds->p0[2]) / mds->cell_size[2] - 0.5f - (float)mds->res_min[2]; + + for (a = 0; a < size; a++) { + shadow[a] = -1.0f; + } + + /* calculate domain bounds in sim cell space */ + // 0,2,4 = 0.0f + bv[1] = (float)mds->res[0]; // x + bv[3] = (float)mds->res[1]; // y + bv[5] = (float)mds->res[2]; // z + + for (z = 0; z < mds->res[2]; z++) { + size_t index = z * slabsize; + int x, y; + + for (y = 0; y < mds->res[1]; y++) { + for (x = 0; x < mds->res[0]; x++, index++) { + float voxel_center[3]; + float pos[3]; + int cell[3]; + float t_ray = 1.0; + + if (shadow[index] >= 0.0f) { + continue; + } + voxel_center[0] = (float)x; + voxel_center[1] = (float)y; + voxel_center[2] = (float)z; + + // get starting cell (light pos) + if (BLI_bvhtree_bb_raycast(bv, light, voxel_center, pos) > FLT_EPSILON) { + // we're ouside -> use point on side of domain + cell[0] = (int)floor(pos[0]); + cell[1] = (int)floor(pos[1]); + cell[2] = (int)floor(pos[2]); + } + else { + // we're inside -> use light itself + cell[0] = (int)floor(light[0]); + cell[1] = (int)floor(light[1]); + cell[2] = (int)floor(light[2]); + } + /* clamp within grid bounds */ + CLAMP(cell[0], 0, mds->res[0] - 1); + CLAMP(cell[1], 0, mds->res[1] - 1); + CLAMP(cell[2], 0, mds->res[2] - 1); + + bresenham_linie_3D(cell[0], + cell[1], + cell[2], + x, + y, + z, + &t_ray, + calc_voxel_transp, + shadow, + density, + mds->res, + correct); + + // convention -> from a RGBA float array, use G value for t_ray + shadow[index] = t_ray; + } + } + } +} + +/* get smoke velocity and density at given coordinates + * returns fluid density or -1.0f if outside domain. */ +float BKE_fluid_get_velocity_at(struct Object *ob, float position[3], float velocity[3]) +{ + FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + zero_v3(velocity); + + if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain && mmd->domain->fluid) { + FluidDomainSettings *mds = mmd->domain; + float time_mult = 25.f * DT_DEFAULT; + float vel_mag; + float *velX = manta_get_velocity_x(mds->fluid); + float *velY = manta_get_velocity_y(mds->fluid); + float *velZ = manta_get_velocity_z(mds->fluid); + float density = 0.0f, fuel = 0.0f; + float pos[3]; + copy_v3_v3(pos, position); + manta_pos_to_cell(mds, pos); + + /* check if point is outside domain max bounds */ + if (pos[0] < mds->res_min[0] || pos[1] < mds->res_min[1] || pos[2] < mds->res_min[2]) { + return -1.0f; + } + if (pos[0] > mds->res_max[0] || pos[1] > mds->res_max[1] || pos[2] > mds->res_max[2]) { + return -1.0f; + } + + /* map pos between 0.0 - 1.0 */ + pos[0] = (pos[0] - mds->res_min[0]) / ((float)mds->res[0]); + pos[1] = (pos[1] - mds->res_min[1]) / ((float)mds->res[1]); + pos[2] = (pos[2] - mds->res_min[2]) / ((float)mds->res[2]); + + /* check if point is outside active area */ + if (mmd->domain->type == FLUID_DOMAIN_TYPE_GAS && + mmd->domain->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { + if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) { + return 0.0f; + } + if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) { + return 0.0f; + } + } + + /* get interpolated velocity */ + velocity[0] = BLI_voxel_sample_trilinear(velX, mds->res, pos) * mds->global_size[0] * + time_mult; + velocity[1] = BLI_voxel_sample_trilinear(velY, mds->res, pos) * mds->global_size[1] * + time_mult; + velocity[2] = BLI_voxel_sample_trilinear(velZ, mds->res, pos) * mds->global_size[2] * + time_mult; + + /* convert velocity direction to global space */ + vel_mag = len_v3(velocity); + mul_mat3_m4_v3(mds->obmat, velocity); + normalize_v3(velocity); + mul_v3_fl(velocity, vel_mag); + + /* use max value of fuel or smoke density */ + density = BLI_voxel_sample_trilinear(manta_smoke_get_density(mds->fluid), mds->res, pos); + if (manta_smoke_has_fuel(mds->fluid)) { + fuel = BLI_voxel_sample_trilinear(manta_smoke_get_fuel(mds->fluid), mds->res, pos); + } + return MAX2(density, fuel); + } + return -1.0f; +} + +int BKE_fluid_get_data_flags(FluidDomainSettings *mds) +{ + int flags = 0; + + if (mds->fluid) { + if (manta_smoke_has_heat(mds->fluid)) { + flags |= FLUID_DOMAIN_ACTIVE_HEAT; + } + if (manta_smoke_has_fuel(mds->fluid)) { + flags |= FLUID_DOMAIN_ACTIVE_FIRE; + } + if (manta_smoke_has_colors(mds->fluid)) { + flags |= FLUID_DOMAIN_ACTIVE_COLORS; + } + } + + return flags; +} + +void BKE_fluid_particle_system_create(struct Main *bmain, + struct Object *ob, + const char *pset_name, + const char *parts_name, + const char *psys_name, + const int psys_type) +{ + ParticleSystem *psys; + ParticleSettings *part; + ParticleSystemModifierData *pmmd; + + /* add particle system */ + part = BKE_particlesettings_add(bmain, pset_name); + psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); + + part->type = psys_type; + part->totpart = 0; + part->draw_size = 0.01f; // make fluid particles more subtle in viewport + part->draw_col = PART_DRAW_COL_VEL; + psys->part = part; + psys->pointcache = BKE_ptcache_add(&psys->ptcaches); + BLI_strncpy(psys->name, parts_name, sizeof(psys->name)); + BLI_addtail(&ob->particlesystem, psys); + + /* add modifier */ + pmmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem); + BLI_strncpy(pmmd->modifier.name, psys_name, sizeof(pmmd->modifier.name)); + pmmd->psys = psys; + BLI_addtail(&ob->modifiers, pmmd); + modifier_unique_name(&ob->modifiers, (ModifierData *)pmmd); +} + +void BKE_fluid_particle_system_destroy(struct Object *ob, const int particle_type) +{ + ParticleSystemModifierData *pmmd; + ParticleSystem *psys, *next_psys; + + for (psys = ob->particlesystem.first; psys; psys = next_psys) { + next_psys = psys->next; + if (psys->part->type & particle_type) { + /* clear modifier */ + pmmd = psys_get_modifier(ob, psys); + BLI_remlink(&ob->modifiers, pmmd); + modifier_free((ModifierData *)pmmd); + + /* clear particle system */ + BLI_remlink(&ob->particlesystem, psys); + psys_free(ob, psys); + } + } +} + +#endif /* WITH_FLUID */ diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c deleted file mode 100644 index 994e00f227a..00000000000 --- a/source/blender/blenkernel/intern/fluidsim.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation - * All rights reserved. - */ - -/** \file - * \ingroup bke - */ - -#include "MEM_guardedalloc.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" - -#include "BLI_math.h" - -#include "BKE_customdata.h" -#include "BKE_fluidsim.h" -#include "BKE_library.h" -#include "BKE_mesh_runtime.h" - -/* ************************* fluidsim bobj file handling **************************** */ - -//------------------------------------------------------------------------------- -// file handling -//------------------------------------------------------------------------------- - -void initElbeemMesh(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - int *numVertices, - float **vertices, - int *numTriangles, - int **triangles, - int useGlobalCoords, - int modifierIndex) -{ - Mesh *mesh; - const MVert *mvert; - const MLoop *mloop; - const MLoopTri *looptri, *lt; - int i, mvert_num, looptri_num; - float *verts; - int *tris; - - mesh = mesh_create_eval_final_index_render( - depsgraph, scene, ob, &CD_MASK_BAREMESH, modifierIndex); - - mvert = mesh->mvert; - mloop = mesh->mloop; - looptri = BKE_mesh_runtime_looptri_ensure(mesh); - mvert_num = mesh->totvert; - looptri_num = mesh->runtime.looptris.len; - - *numVertices = mvert_num; - verts = MEM_mallocN(mvert_num * sizeof(float[3]), "elbeemmesh_vertices"); - for (i = 0; i < mvert_num; i++) { - copy_v3_v3(&verts[i * 3], mvert[i].co); - if (useGlobalCoords) { - mul_m4_v3(ob->obmat, &verts[i * 3]); - } - } - *vertices = verts; - - *numTriangles = looptri_num; - tris = MEM_mallocN(looptri_num * sizeof(int[3]), "elbeemmesh_triangles"); - for (i = 0, lt = looptri; i < looptri_num; i++, lt++) { - tris[(i * 3) + 0] = mloop[lt->tri[0]].v; - tris[(i * 3) + 1] = mloop[lt->tri[1]].v; - tris[(i * 3) + 2] = mloop[lt->tri[2]].v; - } - *triangles = tris; - - BKE_id_free(NULL, mesh); -} diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c index 4768957e2c8..eba6a1c9174 100644 --- a/source/blender/blenkernel/intern/image_save.c +++ b/source/blender/blenkernel/intern/image_save.c @@ -1,6 +1,4 @@ /* - * ***** BEGIN GPL LICENSE BLOCK ***** - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -17,13 +15,9 @@ * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. - * - * Contributor(s): Blender Foundation, 2019 - * - * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/blenkernel/intern/image_save.c +/** \file * \ingroup bke */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index fd7d2fd4a03..a784be9c645 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -108,7 +108,7 @@ void BKE_modifier_init(void) const ModifierTypeInfo *modifierType_getInfo(ModifierType type) { /* type unsigned, no need to check < 0 */ - if (type < NUM_MODIFIER_TYPES && modifier_types[type]->name[0] != '\0') { + if (type < NUM_MODIFIER_TYPES && modifier_types[type] && modifier_types[type]->name[0] != '\0') { return modifier_types[type]; } else { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 08890965ece..10553e73d8d 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -39,6 +39,7 @@ #include "DNA_key_types.h" #include "DNA_light_types.h" #include "DNA_lattice_types.h" +#include "DNA_fluid_types.h" #include "DNA_material_types.h" #include "DNA_meta_types.h" #include "DNA_mesh_types.h" @@ -48,7 +49,6 @@ #include "DNA_screen_types.h" #include "DNA_sequence_types.h" #include "DNA_shader_fx_types.h" -#include "DNA_smoke_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_world_types.h" @@ -123,10 +123,6 @@ #include "DRW_engine.h" -#ifdef WITH_MOD_FLUID -# include "LBM_fluidsim.h" -#endif - #ifdef WITH_PYTHON # include "BPY_extern.h" #endif @@ -1130,13 +1126,13 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const } } } - else if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; + else if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; - if (smd->type == MOD_SMOKE_TYPE_FLOW) { - if (smd->flow) { - if (smd->flow->psys == psys) { - smd->flow->psys = npsys; + if (mmd->type == MOD_FLUID_TYPE_FLOW) { + if (mmd->flow) { + if (mmd->flow->psys == psys) { + mmd->flow->psys = npsys; } } } @@ -4380,10 +4376,10 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph, return true; } } - else if (type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; + else if (type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; - if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) != 0) { + if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) != 0) { return true; } } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 096142b9889..ded38cf562f 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -34,7 +34,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_particle_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_scene_types.h" #include "DNA_dynamicpaint_types.h" @@ -360,6 +360,11 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_ } psmd = psys_get_modifier(ob, psys); + + if (!psmd) { + return 0; + } + if (use_render_params) { if (!(psmd->modifier.mode & eModifierMode_Render)) { return 0; @@ -3577,12 +3582,12 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob return; } - /* clear all other appearances of this pointer (like on smoke flow modifier) */ - if ((md = modifiers_findByType(ob, eModifierType_Smoke))) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if ((smd->type == MOD_SMOKE_TYPE_FLOW) && smd->flow && smd->flow->psys) { - if (smd->flow->psys == psys) { - smd->flow->psys = NULL; + /* clear all other appearances of this pointer (like on manta flow modifier) */ + if ((md = modifiers_findByType(ob, eModifierType_Fluid))) { + FluidModifierData *mmd = (FluidModifierData *)md; + if ((mmd->type == MOD_FLUID_TYPE_FLOW) && mmd->flow && mmd->flow->psys) { + if (mmd->flow->psys == psys) { + mmd->flow->psys = NULL; } } } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 5985d498606..41ca44fbcd9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -85,14 +85,11 @@ #include "RE_shader_ext.h" -/* fluid sim particle import */ -#ifdef WITH_MOD_FLUID -# include "DNA_object_fluidsim_types.h" -# include "LBM_fluidsim.h" -# include <zlib.h> -# include <string.h> - -#endif // WITH_MOD_FLUID +/* FLUID sim particle import */ +#ifdef WITH_FLUID +# include "DNA_fluid_types.h" +# include "manta_fluid_API.h" +#endif // WITH_FLUID static ThreadRWMutex psys_bvhtree_rwlock = BLI_RWLOCK_INITIALIZER; @@ -594,8 +591,6 @@ static void initialize_particle_texture(ParticleSimulationData *sim, ParticleDat } pa->time = 0.f; break; - case PART_FLUID: - break; } } @@ -4143,7 +4138,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_ } static void particles_fluid_step(ParticleSimulationData *sim, - int UNUSED(cfra), + int cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; @@ -4153,80 +4148,235 @@ static void particles_fluid_step(ParticleSimulationData *sim, psys->totpart = 0; } - /* fluid sim particle import handling, actual loading of particles from file */ -#ifdef WITH_MOD_FLUID +#ifdef WITH_FLUID { - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType( - sim->ob, eModifierType_Fluidsim); + Object *ob = sim->ob; + FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + + if (mmd && mmd->domain && mmd->domain->fluid) { + FluidDomainSettings *mds = mmd->domain; - if (fluidmd && fluidmd->fss) { - FluidsimSettings *fss = fluidmd->fss; ParticleSettings *part = psys->part; ParticleData *pa = NULL; - char filename[256]; - char debugStrBuffer[256]; - int curFrame = sim->scene->r.cfra - 1; // warning - sync with derived mesh fsmesh loading - int p, j, totpart; - int readMask, activeParts = 0, fileParts = 0; - gzFile gzf; - - // XXX if (ob==G.obedit) // off... - // return; - - // ok, start loading - BLI_join_dirfile( - filename, sizeof(filename), fss->surfdataPath, OB_FLUIDSIM_SURF_PARTICLES_FNAME); - - BLI_path_abs(filename, modifier_path_relbase_from_global(sim->ob)); - BLI_path_frame(filename, curFrame, 0); // fixed #frame-no - - gzf = BLI_gzopen(filename, "rb"); - if (!gzf) { + int p, totpart, tottypepart = 0; + int flagActivePart, activeParts = 0; + float posX, posY, posZ, velX, velY, velZ; + float resX, resY, resZ; + int upres = 1; + char debugStrBuffer[256]; + float tmp[3] = {0}, tmp2[3] = {0}; + + /* Helper variables for scaling. */ + float min[3], max[3], size[3], cell_size_scaled[3], max_size; + + /* Sanity check: parts also enabled in fluid domain? */ + if ((part->type & PART_FLUID_FLIP && + (mds->particle_type & FLUID_DOMAIN_PARTICLE_FLIP) == 0) || + (part->type & PART_FLUID_SPRAY && + (mds->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) == 0) || + (part->type & PART_FLUID_BUBBLE && + (mds->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) == 0) || + (part->type & PART_FLUID_FOAM && + (mds->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) == 0) || + (part->type & PART_FLUID_TRACER && + (mds->particle_type & FLUID_DOMAIN_PARTICLE_TRACER) == 0)) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), - "readFsPartData::error - Unable to open file for reading '%s'\n", - filename); - // XXX bad level call elbeemDebugOut(debugStrBuffer); + "particles_fluid_step::error - found particle system that is not enabled in " + "fluid domain\n"); + return; + } + + /* Count particle amount. tottypepart is only important for snd particles. */ + if (part->type & PART_FLUID_FLIP) { + tottypepart = totpart = manta_liquid_get_num_flip_particles(mds->fluid); + } + if (part->type & + (PART_FLUID_SPRAY | PART_FLUID_BUBBLE | PART_FLUID_FOAM | PART_FLUID_TRACER)) { + totpart = manta_liquid_get_num_snd_particles(mds->fluid); + + /* tottypepart is the amount of particles of a snd particle type. */ + for (p = 0; p < totpart; p++) { + flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p); + if ((part->type & PART_FLUID_SPRAY) && (flagActivePart & PARTICLE_TYPE_SPRAY)) { + tottypepart++; + } + if ((part->type & PART_FLUID_BUBBLE) && (flagActivePart & PARTICLE_TYPE_BUBBLE)) { + tottypepart++; + } + if ((part->type & PART_FLUID_FOAM) && (flagActivePart & PARTICLE_TYPE_FOAM)) { + tottypepart++; + } + if ((part->type & PART_FLUID_TRACER) && (flagActivePart & PARTICLE_TYPE_TRACER)) { + tottypepart++; + } + } + } + /* Sanity check: no particles present. */ + if (!totpart || !tottypepart) { return; } - gzread(gzf, &totpart, sizeof(totpart)); - totpart = (use_render_params) ? totpart : (part->disp * totpart) / 100; + /* How many particles to display? */ + tottypepart = (use_render_params) ? tottypepart : (part->disp * tottypepart) / 100; - part->totpart = totpart; + part->totpart = tottypepart; part->sta = part->end = 1.0f; part->lifetime = sim->scene->r.efra + 1; - /* allocate particles */ + /* Allocate particles. */ realloc_particles(sim, part->totpart); - // set up reading mask - readMask = fss->typeFlags; + /* Set some randomness when choosing which particles to display. */ + sim->rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed); + double r, dispProb = (double)part->disp / 100.0; - for (p = 0, pa = psys->particles; p < totpart; p++, pa++) { - int ptype = 0; + /* Loop over *all* particles. Will break out of loop before tottypepart amount exceeded. */ + for (p = 0, pa = psys->particles; p < totpart; p++) { - gzread(gzf, &ptype, sizeof(ptype)); - if (ptype & readMask) { - activeParts++; + /* Apply some randomness and determine which particles to skip. */ + r = BLI_rng_get_double(sim->rng); + if (r > dispProb) { + continue; + } - gzread(gzf, &(pa->size), sizeof(float)); + /* flag, res, upres, pos, vel for FLIP and snd particles have different getters. */ + if (part->type & PART_FLUID_FLIP) { + flagActivePart = manta_liquid_get_flip_particle_flag_at(mds->fluid, p); - pa->size /= 10.0f; + resX = (float)manta_get_res_x(mds->fluid); + resY = (float)manta_get_res_y(mds->fluid); + resZ = (float)manta_get_res_z(mds->fluid); - for (j = 0; j < 3; j++) { - float wrf; - gzread(gzf, &wrf, sizeof(wrf)); - pa->state.co[j] = wrf; - // fprintf(stderr,"Rj%d ",j); - } - for (j = 0; j < 3; j++) { - float wrf; - gzread(gzf, &wrf, sizeof(wrf)); - pa->state.vel[j] = wrf; + upres = 1; + + posX = manta_liquid_get_flip_particle_position_x_at(mds->fluid, p); + posY = manta_liquid_get_flip_particle_position_y_at(mds->fluid, p); + posZ = manta_liquid_get_flip_particle_position_z_at(mds->fluid, p); + + velX = manta_liquid_get_flip_particle_velocity_x_at(mds->fluid, p); + velY = manta_liquid_get_flip_particle_velocity_y_at(mds->fluid, p); + velZ = manta_liquid_get_flip_particle_velocity_z_at(mds->fluid, p); + } + else if (part->type & + (PART_FLUID_SPRAY | PART_FLUID_BUBBLE | PART_FLUID_FOAM | PART_FLUID_TRACER)) { + flagActivePart = manta_liquid_get_snd_particle_flag_at(mds->fluid, p); + + resX = (float)manta_liquid_get_particle_res_x(mds->fluid); + resY = (float)manta_liquid_get_particle_res_y(mds->fluid); + resZ = (float)manta_liquid_get_particle_res_z(mds->fluid); + + upres = manta_liquid_get_particle_upres(mds->fluid); + + posX = manta_liquid_get_snd_particle_position_x_at(mds->fluid, p); + posY = manta_liquid_get_snd_particle_position_y_at(mds->fluid, p); + posZ = manta_liquid_get_snd_particle_position_z_at(mds->fluid, p); + + velX = manta_liquid_get_snd_particle_velocity_x_at(mds->fluid, p); + velY = manta_liquid_get_snd_particle_velocity_y_at(mds->fluid, p); + velZ = manta_liquid_get_snd_particle_velocity_z_at(mds->fluid, p); + } + else { + BLI_snprintf(debugStrBuffer, + sizeof(debugStrBuffer), + "particles_fluid_step::error - unknown particle system type\n"); + return; + } +# if 0 + /* Debugging: Print type of particle system and current particles. */ + printf("system type is %d and particle type is %d\n", part->type, flagActivePart); +# endif + + /* Type of particle must match current particle system type + * (only important for snd particles). */ + if ((flagActivePart & PARTICLE_TYPE_SPRAY) && (part->type & PART_FLUID_SPRAY) == 0) { + continue; + } + if ((flagActivePart & PARTICLE_TYPE_BUBBLE) && (part->type & PART_FLUID_BUBBLE) == 0) { + continue; + } + if ((flagActivePart & PARTICLE_TYPE_FOAM) && (part->type & PART_FLUID_FOAM) == 0) { + continue; + } + if ((flagActivePart & PARTICLE_TYPE_TRACER) && (part->type & PART_FLUID_TRACER) == 0) { + continue; + } +# if 0 + /* Debugging: Print type of particle system and current particles. */ + printf("system type is %d and particle type is %d\n", part->type, flagActivePart); +# endif + /* Particle system has allocated 'tottypepart' particles - so break early before exceeded. + */ + if (activeParts >= tottypepart) { + break; + } + + /* Only show active particles, i.e. filter out dead particles that just Mantaflow needs. + * Mantaflow convention: PARTICLE_TYPE_DELETE == inactive particle. */ + if ((flagActivePart & PARTICLE_TYPE_DELETE) == 0) { + activeParts++; + + /* Use particle system settings for particle size. */ + pa->size = part->size; + if (part->randsize > 0.0f) { + pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1); } + /* Get size (dimension) but considering scaling */ + copy_v3_v3(cell_size_scaled, mds->cell_size); + mul_v3_v3(cell_size_scaled, ob->scale); + madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, cell_size_scaled, mds->res_min); + madd_v3fl_v3fl_v3fl_v3i(max, mds->p0, cell_size_scaled, mds->res_max); + sub_v3_v3v3(size, max, min); + + /* Biggest dimension will be used for up-scaling. */ + max_size = MAX3(size[0] / (float)upres, size[1] / (float)upres, size[2] / (float)upres); + + /* Set particle position. */ + float posParticle[3] = {posX, posY, posZ}; + copy_v3_v3(pa->state.co, posParticle); + + /* Normalize to unit cube around 0. */ + float resDomain[3] = {resX, resY, resZ}; + mul_v3_fl(resDomain, 0.5f); + sub_v3_v3(pa->state.co, resDomain); + mul_v3_fl(pa->state.co, mds->dx); + + /* Match domain dimension / size. */ + float scaleAbs[3] = { + 1. / fabsf(ob->scale[0]), 1. / fabsf(ob->scale[1]), 1. / fabsf(ob->scale[2])}; + mul_v3_fl(scaleAbs, max_size); + mul_v3_v3(pa->state.co, scaleAbs); + ; + + /* Match domain scale. */ + mul_m4_v3(ob->obmat, pa->state.co); + + /* Add origin offset to particle position. */ + zero_v3(tmp); + zero_v3(tmp2); + sub_v3_v3v3(tmp2, mds->p1, mds->p0); + mul_v3_fl(tmp2, 0.5f); + add_v3_v3v3(tmp, tmp, mds->p1); + sub_v3_v3(tmp, tmp2); + mul_v3_v3(tmp, ob->scale); + add_v3_v3(pa->state.co, tmp); +# if 0 + /* Debugging: Print particle coordinates. */ + printf("pa->state.co[0]: %f, pa->state.co[1]: %f, pa->state.co[2]: %f\n", + pa->state.co[0], pa->state.co[1], pa->state.co[2]); +# endif + /* Set particle velocity. */ + float velParticle[3] = {velX, velY, velZ}; + copy_v3_v3(pa->state.vel, velParticle); + mul_v3_fl(pa->state.vel, mds->dx); +# if 0 + /* Debugging: Print particle velocity. */ + printf("pa->state.vel[0]: %f, pa->state.vel[1]: %f, pa->state.vel[2]: %f\n", + pa->state.vel[0], pa->state.vel[1], pa->state.vel[2]); +# endif + /* Set default angular velocity and particle rotation. */ zero_v3(pa->state.ave); unit_qt(pa->state.rot); @@ -4234,46 +4384,25 @@ static void particles_fluid_step(ParticleSimulationData *sim, pa->dietime = sim->scene->r.efra + 1; pa->lifetime = sim->scene->r.efra; pa->alive = PARS_ALIVE; -# if 0 - if (a < 25) { - fprintf(stderr, - "FSPARTICLE debug set %s, a%d = %f,%f,%f, life=%f\n", - filename, - a, - pa->co[0], - pa->co[1], - pa->co[2], - pa->lifetime); - } -# endif - } - else { - // skip... - for (j = 0; j < 2 * 3 + 1; j++) { - float wrf; - gzread(gzf, &wrf, sizeof(wrf)); - } + + /* Increasing particle settings pointer only for active particles. */ + pa++; } - fileParts++; } - gzclose(gzf); +# if 0 + /* Debugging: Print number of active particles. */ + printf("active parts: %d\n", activeParts); +# endif + totpart = psys->totpart = part->totpart = activeParts; - totpart = psys->totpart = activeParts; - BLI_snprintf(debugStrBuffer, - sizeof(debugStrBuffer), - "readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d\n", - psys->totpart, - activeParts, - fileParts, - readMask); - // bad level call - // XXX elbeemDebugOut(debugStrBuffer); + BLI_rng_free(sim->rng); + sim->rng = NULL; - } // fluid sim particles done + } /* Fluid sim particles done. */ } #else UNUSED_VARS(use_render_params); -#endif // WITH_MOD_FLUID +#endif // WITH_FLUID } static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNUSED(cfra)) @@ -4289,12 +4418,16 @@ static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNU return totpart - oldtotpart; } -/* Calculates the next state for all particles of the system - * In particles code most fra-ending are frames, time-ending are fra*timestep (seconds) +/** + * Calculates the next state for all particles of the system. + * In particles code most 'cfra - ending' are frames, + * 'time - ending' are 'cfra * timestep' (seconds). + * * 1. Emit particles * 2. Check cache (if used) and return if frame is cached * 3. Do dynamics - * 4. Save to cache */ + * 4. Save to cache + */ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; @@ -4654,128 +4787,124 @@ void particle_system_update(struct Depsgraph *depsgraph, /* setup necessary physics type dependent additional data if it doesn't yet exist */ psys_prepare_physics(&sim); - switch (part->type) { - case PART_HAIR: { - /* nothing to do so bail out early */ - if (psys->totpart == 0 && part->totpart == 0) { - psys_free_path_cache(psys, NULL); - free_hair(ob, psys, 0); - psys->flag |= PSYS_HAIR_DONE; - } - /* (re-)create hair */ - else if (hair_needs_recalc(psys)) { - float hcfra = 0.0f; - int i, recalc = psys->recalc; - - free_hair(ob, psys, 0); + if (part->type & PART_HAIR) { + /* nothing to do so bail out early */ + if (psys->totpart == 0 && part->totpart == 0) { + psys_free_path_cache(psys, NULL); + free_hair(ob, psys, 0); + psys->flag |= PSYS_HAIR_DONE; + } + /* (re-)create hair */ + else if (hair_needs_recalc(psys)) { + float hcfra = 0.0f; + int i, recalc = psys->recalc; - if (psys_orig->edit && psys_orig->free_edit) { - psys_orig->free_edit(psys_orig->edit); - psys_orig->edit = NULL; - psys_orig->free_edit = NULL; - } + free_hair(ob, psys, 0); - /* first step is negative so particles get killed and reset */ - psys->cfra = 1.0f; + if (psys_orig->edit && psys_orig->free_edit) { + psys_orig->free_edit(psys_orig->edit); + psys_orig->edit = NULL; + psys_orig->free_edit = NULL; + } - ParticleSettings *part_local = part; - if ((part->flag & PART_HAIR_REGROW) == 0) { - part_local = particle_settings_localize(part); - psys->part = part_local; - } + /* first step is negative so particles get killed and reset */ + psys->cfra = 1.0f; - for (i = 0; i <= part->hair_step; i++) { - hcfra = 100.0f * (float)i / (float)psys->part->hair_step; - if ((part->flag & PART_HAIR_REGROW) == 0) { - BKE_animsys_evaluate_animdata( - scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false); - } - system_step(&sim, hcfra, use_render_params); - psys->cfra = hcfra; - psys->recalc = 0; - save_hair(&sim, hcfra); - } + ParticleSettings *part_local = part; + if ((part->flag & PART_HAIR_REGROW) == 0) { + part_local = particle_settings_localize(part); + psys->part = part_local; + } - if (part_local != part) { - particle_settings_free_local(part_local); - psys->part = part; + for (i = 0; i <= part->hair_step; i++) { + hcfra = 100.0f * (float)i / (float)psys->part->hair_step; + if ((part->flag & PART_HAIR_REGROW) == 0) { + BKE_animsys_evaluate_animdata( + scene, &part_local->id, part_local->adt, hcfra, ADT_RECALC_ANIM, false); } - - psys->flag |= PSYS_HAIR_DONE; - psys->recalc = recalc; - } - else if (psys->flag & PSYS_EDITED) { - psys->flag |= PSYS_HAIR_DONE; + system_step(&sim, hcfra, use_render_params); + psys->cfra = hcfra; + psys->recalc = 0; + save_hair(&sim, hcfra); } - if (psys->flag & PSYS_HAIR_DONE) { - hair_step(&sim, cfra, use_render_params); + if (part_local != part) { + particle_settings_free_local(part_local); + psys->part = part; } - break; + + psys->flag |= PSYS_HAIR_DONE; + psys->recalc = recalc; } - case PART_FLUID: { - particles_fluid_step(&sim, (int)cfra, use_render_params); - break; + else if (psys->flag & PSYS_EDITED) { + psys->flag |= PSYS_HAIR_DONE; } - default: { - switch (part->phystype) { - case PART_PHYS_NO: - case PART_PHYS_KEYED: { - PARTICLE_P; - float disp = psys_get_current_display_percentage(psys, use_render_params); - bool free_unexisting = false; - - /* Particles without dynamics haven't been reset yet because they don't use pointcache */ - if (psys->recalc & ID_RECALC_PSYS_RESET) { - psys_reset(psys, PSYS_RESET_ALL); - } - if (emit_particles(&sim, NULL, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) { - free_keyed_keys(psys); - distribute_particles(&sim, part->from); - initialize_all_particles(&sim); - free_unexisting = true; + if (psys->flag & PSYS_HAIR_DONE) { + hair_step(&sim, cfra, use_render_params); + } + } + else if (part->type & (PART_FLUID_FLIP | PART_FLUID_BUBBLE | PART_FLUID_BUBBLE | + PART_FLUID_FOAM | PART_FLUID_TRACER)) { + particles_fluid_step(&sim, (int)cfra, use_render_params); + } + else { + switch (part->phystype) { + case PART_PHYS_NO: + case PART_PHYS_KEYED: { + PARTICLE_P; + float disp = psys_get_current_display_percentage(psys, use_render_params); + bool free_unexisting = false; + + /* Particles without dynamics haven't been reset yet because they don't use pointcache */ + if (psys->recalc & ID_RECALC_PSYS_RESET) { + psys_reset(psys, PSYS_RESET_ALL); + } - /* flag for possible explode modifiers after this system */ - sim.psmd->flag |= eParticleSystemFlag_Pars; - } + if (emit_particles(&sim, NULL, cfra) || (psys->recalc & ID_RECALC_PSYS_RESET)) { + free_keyed_keys(psys); + distribute_particles(&sim, part->from); + initialize_all_particles(&sim); + free_unexisting = true; - LOOP_EXISTING_PARTICLES - { - pa->size = part->size; - if (part->randsize > 0.0f) { - pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1); - } - - reset_particle(&sim, pa, 0.0, cfra); - - if (psys_frand(psys, p) > disp) { - pa->flag |= PARS_NO_DISP; - } - else { - pa->flag &= ~PARS_NO_DISP; - } - } + /* flag for possible explode modifiers after this system */ + sim.psmd->flag |= eParticleSystemFlag_Pars; + } - /* free unexisting after resetting particles */ - if (free_unexisting) { - free_unexisting_particles(&sim); + LOOP_EXISTING_PARTICLES + { + pa->size = part->size; + if (part->randsize > 0.0f) { + pa->size *= 1.0f - part->randsize * psys_frand(psys, p + 1); } - if (part->phystype == PART_PHYS_KEYED) { - psys_count_keyed_targets(&sim); - set_keyed_keys(&sim); - psys_update_path_cache(&sim, (int)cfra, use_render_params); + reset_particle(&sim, pa, 0.0, cfra); + + if (psys_frand(psys, p) > disp) { + pa->flag |= PARS_NO_DISP; + } + else { + pa->flag &= ~PARS_NO_DISP; } - break; } - default: { - /* the main dynamic particle system step */ - system_step(&sim, cfra, use_render_params); - break; + + /* free unexisting after resetting particles */ + if (free_unexisting) { + free_unexisting_particles(&sim); } + + if (part->phystype == PART_PHYS_KEYED) { + psys_count_keyed_targets(&sim); + set_keyed_keys(&sim); + psys_update_path_cache(&sim, (int)cfra, use_render_params); + } + break; + } + default: { + /* the main dynamic particle system step */ + system_step(&sim, cfra, use_render_params); + break; } - break; } } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 7ae5f91c615..5e1611cb3f9 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -40,7 +40,7 @@ #include "DNA_particle_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "BLI_blenlib.h" #include "BLI_math.h" @@ -64,7 +64,7 @@ #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_scene.h" -#include "BKE_smoke.h" +#include "BKE_fluid.h" #include "BKE_softbody.h" #include "BIK_api.h" @@ -591,11 +591,11 @@ static void ptcache_cloth_error(void *cloth_v, const char *message) /* Smoke functions */ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra)) { - SmokeModifierData *smd = (SmokeModifierData *)smoke_v; - SmokeDomainSettings *sds = smd->domain; + FluidModifierData *mmd = (FluidModifierData *)smoke_v; + FluidDomainSettings *mds = mmd->domain; - if (sds->fluid) { - return sds->base_res[0] * sds->base_res[1] * sds->base_res[2]; + if (mds->fluid) { + return mds->base_res[0] * mds->base_res[1] * mds->base_res[2]; } else { return 0; @@ -604,28 +604,28 @@ static int ptcache_smoke_totpoint(void *smoke_v, int UNUSED(cfra)) static void ptcache_smoke_error(void *smoke_v, const char *message) { - SmokeModifierData *smd = (SmokeModifierData *)smoke_v; - modifier_setError(&smd->modifier, "%s", message); + FluidModifierData *mmd = (FluidModifierData *)smoke_v; + modifier_setError(&mmd->modifier, "%s", message); } # define SMOKE_CACHE_VERSION "1.04" static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v) { - SmokeModifierData *smd = (SmokeModifierData *)smoke_v; - SmokeDomainSettings *sds = smd->domain; + FluidModifierData *mmd = (FluidModifierData *)smoke_v; + FluidDomainSettings *mds = mmd->domain; int ret = 0; - int fluid_fields = BKE_smoke_get_data_flags(sds); + int fluid_fields = BKE_fluid_get_data_flags(mds); /* version header */ ptcache_file_write(pf, SMOKE_CACHE_VERSION, 4, sizeof(char)); ptcache_file_write(pf, &fluid_fields, 1, sizeof(int)); - ptcache_file_write(pf, &sds->active_fields, 1, sizeof(int)); - ptcache_file_write(pf, &sds->res, 3, sizeof(int)); - ptcache_file_write(pf, &sds->dx, 1, sizeof(float)); + ptcache_file_write(pf, &mds->active_fields, 1, sizeof(int)); + ptcache_file_write(pf, &mds->res, 3, sizeof(int)); + ptcache_file_write(pf, &mds->dx, 1, sizeof(float)); - if (sds->fluid) { - size_t res = sds->res[0] * sds->res[1] * sds->res[2]; + if (mds->fluid) { + size_t res = mds->res[0] * mds->res[1] * mds->res[2]; float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b; unsigned char *obstacles; unsigned int in_len = sizeof(float) * (unsigned int)res; @@ -633,11 +633,11 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v) "pointcache_lzo_buffer"); // int mode = res >= 1000000 ? 2 : 1; int mode = 1; // light - if (sds->cache_comp == SM_CACHE_HEAVY) { + if (mds->cache_comp == SM_CACHE_HEAVY) { mode = 2; // heavy } - smoke_export(sds->fluid, + smoke_export(mds->fluid, &dt, &dx, &dens, @@ -652,20 +652,21 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v) &r, &g, &b, - &obstacles); + &obstacles, + NULL); - ptcache_file_compressed_write(pf, (unsigned char *)sds->shadow, in_len, out, mode); + ptcache_file_compressed_write(pf, (unsigned char *)mds->shadow, in_len, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len, out, mode); - if (fluid_fields & SM_ACTIVE_HEAT) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) { ptcache_file_compressed_write(pf, (unsigned char *)heat, in_len, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)heatold, in_len, out, mode); } - if (fluid_fields & SM_ACTIVE_FIRE) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) { ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)react, in_len, out, mode); } - if (fluid_fields & SM_ACTIVE_COLORS) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) { ptcache_file_compressed_write(pf, (unsigned char *)r, in_len, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)g, in_len, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)b, in_len, out, mode); @@ -676,52 +677,52 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v) ptcache_file_compressed_write(pf, (unsigned char *)obstacles, (unsigned int)res, out, mode); ptcache_file_write(pf, &dt, 1, sizeof(float)); ptcache_file_write(pf, &dx, 1, sizeof(float)); - ptcache_file_write(pf, &sds->p0, 3, sizeof(float)); - ptcache_file_write(pf, &sds->p1, 3, sizeof(float)); - ptcache_file_write(pf, &sds->dp0, 3, sizeof(float)); - ptcache_file_write(pf, &sds->shift, 3, sizeof(int)); - ptcache_file_write(pf, &sds->obj_shift_f, 3, sizeof(float)); - ptcache_file_write(pf, &sds->obmat, 16, sizeof(float)); - ptcache_file_write(pf, &sds->base_res, 3, sizeof(int)); - ptcache_file_write(pf, &sds->res_min, 3, sizeof(int)); - ptcache_file_write(pf, &sds->res_max, 3, sizeof(int)); - ptcache_file_write(pf, &sds->active_color, 3, sizeof(float)); + ptcache_file_write(pf, &mds->p0, 3, sizeof(float)); + ptcache_file_write(pf, &mds->p1, 3, sizeof(float)); + ptcache_file_write(pf, &mds->dp0, 3, sizeof(float)); + ptcache_file_write(pf, &mds->shift, 3, sizeof(int)); + ptcache_file_write(pf, &mds->obj_shift_f, 3, sizeof(float)); + ptcache_file_write(pf, &mds->obmat, 16, sizeof(float)); + ptcache_file_write(pf, &mds->base_res, 3, sizeof(int)); + ptcache_file_write(pf, &mds->res_min, 3, sizeof(int)); + ptcache_file_write(pf, &mds->res_max, 3, sizeof(int)); + ptcache_file_write(pf, &mds->active_color, 3, sizeof(float)); MEM_freeN(out); ret = 1; } - if (sds->wt) { + if (mds->wt) { int res_big_array[3]; int res_big; - int res = sds->res[0] * sds->res[1] * sds->res[2]; + int res = mds->res[0] * mds->res[1] * mds->res[2]; float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b; unsigned int in_len = sizeof(float) * (unsigned int)res; unsigned int in_len_big; unsigned char *out; int mode; - smoke_turbulence_get_res(sds->wt, res_big_array); + smoke_turbulence_get_res(mds->wt, res_big_array); res_big = res_big_array[0] * res_big_array[1] * res_big_array[2]; // mode = res_big >= 1000000 ? 2 : 1; mode = 1; // light - if (sds->cache_high_comp == SM_CACHE_HEAVY) { + if (mds->cache_high_comp == SM_CACHE_HEAVY) { mode = 2; // heavy } in_len_big = sizeof(float) * (unsigned int)res_big; - smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); + smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); out = (unsigned char *)MEM_callocN(LZO_OUT_LEN(in_len_big), "pointcache_lzo_buffer"); ptcache_file_compressed_write(pf, (unsigned char *)dens, in_len_big, out, mode); - if (fluid_fields & SM_ACTIVE_FIRE) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) { ptcache_file_compressed_write(pf, (unsigned char *)flame, in_len_big, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)fuel, in_len_big, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)react, in_len_big, out, mode); } - if (fluid_fields & SM_ACTIVE_COLORS) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) { ptcache_file_compressed_write(pf, (unsigned char *)r, in_len_big, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)g, in_len_big, out, mode); ptcache_file_compressed_write(pf, (unsigned char *)b, in_len_big, out, mode); @@ -743,24 +744,24 @@ static int ptcache_smoke_write(PTCacheFile *pf, void *smoke_v) /* read old smoke cache from 2.64 */ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v) { - SmokeModifierData *smd = (SmokeModifierData *)smoke_v; - SmokeDomainSettings *sds = smd->domain; + FluidModifierData *mmd = (FluidModifierData *)smoke_v; + FluidDomainSettings *mds = mmd->domain; - if (sds->fluid) { - const size_t res = sds->res[0] * sds->res[1] * sds->res[2]; + if (mds->fluid) { + const size_t res = mds->res[0] * mds->res[1] * mds->res[2]; const unsigned int out_len = (unsigned int)res * sizeof(float); float dt, dx, *dens, *heat, *heatold, *vx, *vy, *vz; unsigned char *obstacles; float *tmp_array = MEM_callocN(out_len, "Smoke old cache tmp"); - int fluid_fields = BKE_smoke_get_data_flags(sds); + int fluid_fields = BKE_fluid_get_data_flags(mds); /* Part part of the new cache header */ - sds->active_color[0] = 0.7f; - sds->active_color[1] = 0.7f; - sds->active_color[2] = 0.7f; + mds->active_color[0] = 0.7f; + mds->active_color[1] = 0.7f; + mds->active_color[2] = 0.7f; - smoke_export(sds->fluid, + smoke_export(mds->fluid, &dt, &dx, &dens, @@ -775,13 +776,14 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v) NULL, NULL, NULL, - &obstacles); + &obstacles, + NULL); - ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len); + ptcache_file_compressed_read(pf, (unsigned char *)mds->shadow, out_len); ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len); ptcache_file_compressed_read(pf, (unsigned char *)tmp_array, out_len); - if (fluid_fields & SM_ACTIVE_HEAT) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) { ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len); ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len); } @@ -801,19 +803,19 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v) MEM_freeN(tmp_array); - if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && sds->wt) { + if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && mds->wt) { int res_big, res_big_array[3]; float *tcu, *tcv, *tcw; unsigned int out_len_big; unsigned char *tmp_array_big; - smoke_turbulence_get_res(sds->wt, res_big_array); + smoke_turbulence_get_res(mds->wt, res_big_array); res_big = res_big_array[0] * res_big_array[1] * res_big_array[2]; out_len_big = sizeof(float) * (unsigned int)res_big; tmp_array_big = MEM_callocN(out_len_big, "Smoke old cache tmp"); smoke_turbulence_export( - sds->wt, &dens, NULL, NULL, NULL, NULL, NULL, NULL, &tcu, &tcv, &tcw); + mds->wt, &dens, NULL, NULL, NULL, NULL, NULL, NULL, &tcu, &tcv, &tcw); ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big); ptcache_file_compressed_read(pf, (unsigned char *)tmp_array_big, out_len_big); @@ -831,12 +833,12 @@ static int ptcache_smoke_read_old(PTCacheFile *pf, void *smoke_v) static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) { - SmokeModifierData *smd = (SmokeModifierData *)smoke_v; - SmokeDomainSettings *sds = smd->domain; + FluidModifierData *mmd = (FluidModifierData *)smoke_v; + FluidDomainSettings *mds = mmd->domain; char version[4]; int ch_res[3]; float ch_dx; - int fluid_fields = BKE_smoke_get_data_flags(sds); + int fluid_fields = BKE_fluid_get_data_flags(mds); int cache_fields = 0; int active_fields = 0; int reallocate = 0; @@ -856,8 +858,8 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) ptcache_file_read(pf, &ch_dx, 1, sizeof(float)); /* check if resolution has changed */ - if (sds->res[0] != ch_res[0] || sds->res[1] != ch_res[1] || sds->res[2] != ch_res[2]) { - if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + if (mds->res[0] != ch_res[0] || mds->res[1] != ch_res[1] || mds->res[2] != ch_res[2]) { + if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { reallocate = 1; } else { @@ -865,29 +867,26 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) } } /* check if active fields have changed */ - if (fluid_fields != cache_fields || active_fields != sds->active_fields) { + if (fluid_fields != cache_fields || active_fields != mds->active_fields) { reallocate = 1; } /* reallocate fluid if needed*/ if (reallocate) { - sds->active_fields = active_fields | cache_fields; - BKE_smoke_reallocate_fluid(sds, ch_dx, ch_res, 1); - sds->dx = ch_dx; - copy_v3_v3_int(sds->res, ch_res); - sds->total_cells = ch_res[0] * ch_res[1] * ch_res[2]; - if (sds->flags & MOD_SMOKE_HIGHRES) { - BKE_smoke_reallocate_highres_fluid(sds, ch_dx, ch_res, 1); - } + mds->active_fields = active_fields | cache_fields; + BKE_fluid_reallocate_fluid(mds, ch_res, 1); + mds->dx = ch_dx; + copy_v3_v3_int(mds->res, ch_res); + mds->total_cells = ch_res[0] * ch_res[1] * ch_res[2]; } - if (sds->fluid) { - size_t res = sds->res[0] * sds->res[1] * sds->res[2]; + if (mds->fluid) { + size_t res = mds->res[0] * mds->res[1] * mds->res[2]; float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b; unsigned char *obstacles; unsigned int out_len = (unsigned int)res * sizeof(float); - smoke_export(sds->fluid, + smoke_export(mds->fluid, &dt, &dx, &dens, @@ -902,20 +901,21 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) &r, &g, &b, - &obstacles); + &obstacles, + NULL); - ptcache_file_compressed_read(pf, (unsigned char *)sds->shadow, out_len); + ptcache_file_compressed_read(pf, (unsigned char *)mds->shadow, out_len); ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len); - if (cache_fields & SM_ACTIVE_HEAT) { + if (cache_fields & FLUID_DOMAIN_ACTIVE_HEAT) { ptcache_file_compressed_read(pf, (unsigned char *)heat, out_len); ptcache_file_compressed_read(pf, (unsigned char *)heatold, out_len); } - if (cache_fields & SM_ACTIVE_FIRE) { + if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) { ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len); ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len); ptcache_file_compressed_read(pf, (unsigned char *)react, out_len); } - if (cache_fields & SM_ACTIVE_COLORS) { + if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) { ptcache_file_compressed_read(pf, (unsigned char *)r, out_len); ptcache_file_compressed_read(pf, (unsigned char *)g, out_len); ptcache_file_compressed_read(pf, (unsigned char *)b, out_len); @@ -926,38 +926,38 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) ptcache_file_compressed_read(pf, (unsigned char *)obstacles, (unsigned int)res); ptcache_file_read(pf, &dt, 1, sizeof(float)); ptcache_file_read(pf, &dx, 1, sizeof(float)); - ptcache_file_read(pf, &sds->p0, 3, sizeof(float)); - ptcache_file_read(pf, &sds->p1, 3, sizeof(float)); - ptcache_file_read(pf, &sds->dp0, 3, sizeof(float)); - ptcache_file_read(pf, &sds->shift, 3, sizeof(int)); - ptcache_file_read(pf, &sds->obj_shift_f, 3, sizeof(float)); - ptcache_file_read(pf, &sds->obmat, 16, sizeof(float)); - ptcache_file_read(pf, &sds->base_res, 3, sizeof(int)); - ptcache_file_read(pf, &sds->res_min, 3, sizeof(int)); - ptcache_file_read(pf, &sds->res_max, 3, sizeof(int)); - ptcache_file_read(pf, &sds->active_color, 3, sizeof(float)); - } - - if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && sds->wt) { - int res = sds->res[0] * sds->res[1] * sds->res[2]; + ptcache_file_read(pf, &mds->p0, 3, sizeof(float)); + ptcache_file_read(pf, &mds->p1, 3, sizeof(float)); + ptcache_file_read(pf, &mds->dp0, 3, sizeof(float)); + ptcache_file_read(pf, &mds->shift, 3, sizeof(int)); + ptcache_file_read(pf, &mds->obj_shift_f, 3, sizeof(float)); + ptcache_file_read(pf, &mds->obmat, 16, sizeof(float)); + ptcache_file_read(pf, &mds->base_res, 3, sizeof(int)); + ptcache_file_read(pf, &mds->res_min, 3, sizeof(int)); + ptcache_file_read(pf, &mds->res_max, 3, sizeof(int)); + ptcache_file_read(pf, &mds->active_color, 3, sizeof(float)); + } + + if (pf->data_types & (1 << BPHYS_DATA_SMOKE_HIGH) && mds->wt) { + int res = mds->res[0] * mds->res[1] * mds->res[2]; int res_big, res_big_array[3]; float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b; unsigned int out_len = sizeof(float) * (unsigned int)res; unsigned int out_len_big; - smoke_turbulence_get_res(sds->wt, res_big_array); + smoke_turbulence_get_res(mds->wt, res_big_array); res_big = res_big_array[0] * res_big_array[1] * res_big_array[2]; out_len_big = sizeof(float) * (unsigned int)res_big; - smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); + smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); ptcache_file_compressed_read(pf, (unsigned char *)dens, out_len_big); - if (cache_fields & SM_ACTIVE_FIRE) { + if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) { ptcache_file_compressed_read(pf, (unsigned char *)flame, out_len_big); ptcache_file_compressed_read(pf, (unsigned char *)fuel, out_len_big); ptcache_file_compressed_read(pf, (unsigned char *)react, out_len_big); } - if (cache_fields & SM_ACTIVE_COLORS) { + if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) { ptcache_file_compressed_read(pf, (unsigned char *)r, out_len_big); ptcache_file_compressed_read(pf, (unsigned char *)g, out_len_big); ptcache_file_compressed_read(pf, (unsigned char *)b, out_len_big); @@ -984,101 +984,101 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v) * with `vs` = voxel size, and `px, py, pz`, * the min position of the domain's bounding box. */ -static void compute_fluid_matrices(SmokeDomainSettings *sds) +static void compute_fluid_matrices(FluidDomainSettings *mds) { float bbox_min[3]; - copy_v3_v3(bbox_min, sds->p0); + copy_v3_v3(bbox_min, mds->p0); - if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - bbox_min[0] += (sds->cell_size[0] * (float)sds->res_min[0]); - bbox_min[1] += (sds->cell_size[1] * (float)sds->res_min[1]); - bbox_min[2] += (sds->cell_size[2] * (float)sds->res_min[2]); - add_v3_v3(bbox_min, sds->obj_shift_f); + if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { + bbox_min[0] += (mds->cell_size[0] * (float)mds->res_min[0]); + bbox_min[1] += (mds->cell_size[1] * (float)mds->res_min[1]); + bbox_min[2] += (mds->cell_size[2] * (float)mds->res_min[2]); + add_v3_v3(bbox_min, mds->obj_shift_f); } /* construct low res matrix */ - size_to_mat4(sds->fluidmat, sds->cell_size); - copy_v3_v3(sds->fluidmat[3], bbox_min); + size_to_mat4(mds->fluidmat, mds->cell_size); + copy_v3_v3(mds->fluidmat[3], bbox_min); /* The smoke simulator stores voxels cell-centered, whilst VDB is node * centered, so we offset the matrix by half a voxel to compensate. */ - madd_v3_v3fl(sds->fluidmat[3], sds->cell_size, 0.5f); + madd_v3_v3fl(mds->fluidmat[3], mds->cell_size, 0.5f); - mul_m4_m4m4(sds->fluidmat, sds->obmat, sds->fluidmat); + mul_m4_m4m4(mds->fluidmat, mds->obmat, mds->fluidmat); - if (sds->wt) { + if (mds->wt) { float voxel_size_high[3]; /* construct high res matrix */ - mul_v3_v3fl(voxel_size_high, sds->cell_size, 1.0f / (float)(sds->amplify + 1)); - size_to_mat4(sds->fluidmat_wt, voxel_size_high); - copy_v3_v3(sds->fluidmat_wt[3], bbox_min); + mul_v3_v3fl(voxel_size_high, mds->cell_size, 1.0f / (float)(mds->amplify + 1)); + size_to_mat4(mds->fluidmat_wt, voxel_size_high); + copy_v3_v3(mds->fluidmat_wt[3], bbox_min); /* Same here, add half a voxel to adjust the position of the fluid. */ - madd_v3_v3fl(sds->fluidmat_wt[3], voxel_size_high, 0.5f); + madd_v3_v3fl(mds->fluidmat_wt[3], voxel_size_high, 0.5f); - mul_m4_m4m4(sds->fluidmat_wt, sds->obmat, sds->fluidmat_wt); + mul_m4_m4m4(mds->fluidmat_wt, mds->obmat, mds->fluidmat_wt); } } static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke_v) { - SmokeModifierData *smd = (SmokeModifierData *)smoke_v; - SmokeDomainSettings *sds = smd->domain; - - OpenVDBWriter_set_flags(writer, sds->openvdb_comp, (sds->data_depth == 16)); - - OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", sds->active_fields); - OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", sds->res); - OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", sds->res_min); - OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", sds->res_max); - OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", sds->base_res); - OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", sds->p0); - OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", sds->p1); - OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", sds->dp0); - OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", sds->shift); - OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", sds->obj_shift_f); - OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", sds->active_color); - OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", sds->obmat); - - int fluid_fields = BKE_smoke_get_data_flags(sds); + FluidModifierData *mmd = (FluidModifierData *)smoke_v; + FluidDomainSettings *mds = mmd->domain; + + OpenVDBWriter_set_flags(writer, mds->openvdb_comp, (mds->data_depth == 16)); + + OpenVDBWriter_add_meta_int(writer, "blender/smoke/active_fields", mds->active_fields); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/resolution", mds->res); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/min_resolution", mds->res_min); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/max_resolution", mds->res_max); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/base_resolution", mds->base_res); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/min_bbox", mds->p0); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/max_bbox", mds->p1); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/dp0", mds->dp0); + OpenVDBWriter_add_meta_v3_int(writer, "blender/smoke/shift", mds->shift); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/obj_shift_f", mds->obj_shift_f); + OpenVDBWriter_add_meta_v3(writer, "blender/smoke/active_color", mds->active_color); + OpenVDBWriter_add_meta_mat4(writer, "blender/smoke/obmat", mds->obmat); + + int fluid_fields = BKE_fluid_get_data_flags(mds); struct OpenVDBFloatGrid *clip_grid = NULL; - compute_fluid_matrices(sds); + compute_fluid_matrices(mds); OpenVDBWriter_add_meta_int(writer, "blender/smoke/fluid_fields", fluid_fields); - if (sds->wt) { + if (mds->wt) { struct OpenVDBFloatGrid *wt_density_grid; float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b; - smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); + smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); wt_density_grid = OpenVDB_export_grid_fl( - writer, "density", dens, sds->res_wt, sds->fluidmat_wt, sds->clipping, NULL); + writer, "density", dens, mds->res_wt, mds->fluidmat_wt, mds->clipping, NULL); clip_grid = wt_density_grid; - if (fluid_fields & SM_ACTIVE_FIRE) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) { OpenVDB_export_grid_fl( - writer, "flame", flame, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid); + writer, "flame", flame, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid); OpenVDB_export_grid_fl( - writer, "fuel", fuel, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid); + writer, "fuel", fuel, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid); OpenVDB_export_grid_fl( - writer, "react", react, sds->res_wt, sds->fluidmat_wt, sds->clipping, wt_density_grid); + writer, "react", react, mds->res_wt, mds->fluidmat_wt, mds->clipping, wt_density_grid); } - if (fluid_fields & SM_ACTIVE_COLORS) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) { OpenVDB_export_grid_vec(writer, "color", r, g, b, - sds->res_wt, - sds->fluidmat_wt, + mds->res_wt, + mds->fluidmat_wt, VEC_INVARIANT, true, - sds->clipping, + mds->clipping, wt_density_grid); } @@ -1087,20 +1087,20 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke tcu, tcv, tcw, - sds->res, - sds->fluidmat, + mds->res, + mds->fluidmat, VEC_INVARIANT, false, - sds->clipping, + mds->clipping, wt_density_grid); } - if (sds->fluid) { + if (mds->fluid) { struct OpenVDBFloatGrid *density_grid; float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b; unsigned char *obstacles; - smoke_export(sds->fluid, + smoke_export(mds->fluid, &dt, &dx, &dens, @@ -1115,50 +1115,51 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke &r, &g, &b, - &obstacles); + &obstacles, + NULL); OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dx", dx); OpenVDBWriter_add_meta_fl(writer, "blender/smoke/dt", dt); - const char *name = (!sds->wt) ? "density" : "density_low"; + const char *name = (!mds->wt) ? "density" : "density_low"; density_grid = OpenVDB_export_grid_fl( - writer, name, dens, sds->res, sds->fluidmat, sds->clipping, NULL); - clip_grid = sds->wt ? clip_grid : density_grid; + writer, name, dens, mds->res, mds->fluidmat, mds->clipping, NULL); + clip_grid = mds->wt ? clip_grid : density_grid; OpenVDB_export_grid_fl( - writer, "shadow", sds->shadow, sds->res, sds->fluidmat, sds->clipping, NULL); + writer, "shadow", mds->shadow, mds->res, mds->fluidmat, mds->clipping, NULL); - if (fluid_fields & SM_ACTIVE_HEAT) { + if (fluid_fields & FLUID_DOMAIN_ACTIVE_HEAT) { OpenVDB_export_grid_fl( - writer, "heat", heat, sds->res, sds->fluidmat, sds->clipping, clip_grid); + writer, "heat", heat, mds->res, mds->fluidmat, mds->clipping, clip_grid); OpenVDB_export_grid_fl( - writer, "heat_old", heatold, sds->res, sds->fluidmat, sds->clipping, clip_grid); + writer, "heat_old", heatold, mds->res, mds->fluidmat, mds->clipping, clip_grid); } - if (fluid_fields & SM_ACTIVE_FIRE) { - name = (!sds->wt) ? "flame" : "flame_low"; + if (fluid_fields & FLUID_DOMAIN_ACTIVE_FIRE) { + name = (!mds->wt) ? "flame" : "flame_low"; OpenVDB_export_grid_fl( - writer, name, flame, sds->res, sds->fluidmat, sds->clipping, density_grid); - name = (!sds->wt) ? "fuel" : "fuel_low"; + writer, name, flame, mds->res, mds->fluidmat, mds->clipping, density_grid); + name = (!mds->wt) ? "fuel" : "fuel_low"; OpenVDB_export_grid_fl( - writer, name, fuel, sds->res, sds->fluidmat, sds->clipping, density_grid); - name = (!sds->wt) ? "react" : "react_low"; + writer, name, fuel, mds->res, mds->fluidmat, mds->clipping, density_grid); + name = (!mds->wt) ? "react" : "react_low"; OpenVDB_export_grid_fl( - writer, name, react, sds->res, sds->fluidmat, sds->clipping, density_grid); + writer, name, react, mds->res, mds->fluidmat, mds->clipping, density_grid); } - if (fluid_fields & SM_ACTIVE_COLORS) { - name = (!sds->wt) ? "color" : "color_low"; + if (fluid_fields & FLUID_DOMAIN_ACTIVE_COLORS) { + name = (!mds->wt) ? "color" : "color_low"; OpenVDB_export_grid_vec(writer, name, r, g, b, - sds->res, - sds->fluidmat, + mds->res, + mds->fluidmat, VEC_INVARIANT, true, - sds->clipping, + mds->clipping, density_grid); } @@ -1167,14 +1168,14 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke vx, vy, vz, - sds->res, - sds->fluidmat, + mds->res, + mds->fluidmat, VEC_CONTRAVARIANT_RELATIVE, false, - sds->clipping, + mds->clipping, clip_grid); OpenVDB_export_grid_ch( - writer, "obstacles", obstacles, sds->res, sds->fluidmat, sds->clipping, NULL); + writer, "obstacles", obstacles, mds->res, mds->fluidmat, mds->clipping, NULL); } return 1; @@ -1182,38 +1183,38 @@ static int ptcache_smoke_openvdb_write(struct OpenVDBWriter *writer, void *smoke static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_v) { - SmokeModifierData *smd = (SmokeModifierData *)smoke_v; + FluidModifierData *mmd = (FluidModifierData *)smoke_v; - if (!smd) { + if (!mmd) { return 0; } - SmokeDomainSettings *sds = smd->domain; + FluidDomainSettings *mds = mmd->domain; - int fluid_fields = BKE_smoke_get_data_flags(sds); + int fluid_fields = BKE_fluid_get_data_flags(mds); int active_fields, cache_fields = 0; int cache_res[3]; float cache_dx; bool reallocate = false; - OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", sds->res_min); - OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", sds->res_max); - OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", sds->base_res); - OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", sds->p0); - OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", sds->p1); - OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", sds->dp0); - OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", sds->shift); - OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", sds->obj_shift_f); - OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", sds->active_color); - OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", sds->obmat); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/min_resolution", mds->res_min); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/max_resolution", mds->res_max); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/base_resolution", mds->base_res); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/min_bbox", mds->p0); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/max_bbox", mds->p1); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/dp0", mds->dp0); + OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/shift", mds->shift); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/obj_shift_f", mds->obj_shift_f); + OpenVDBReader_get_meta_v3(reader, "blender/smoke/active_color", mds->active_color); + OpenVDBReader_get_meta_mat4(reader, "blender/smoke/obmat", mds->obmat); OpenVDBReader_get_meta_int(reader, "blender/smoke/fluid_fields", &cache_fields); OpenVDBReader_get_meta_int(reader, "blender/smoke/active_fields", &active_fields); OpenVDBReader_get_meta_fl(reader, "blender/smoke/dx", &cache_dx); OpenVDBReader_get_meta_v3_int(reader, "blender/smoke/resolution", cache_res); /* check if resolution has changed */ - if (sds->res[0] != cache_res[0] || sds->res[1] != cache_res[1] || sds->res[2] != cache_res[2]) { - if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { + if (mds->res[0] != cache_res[0] || mds->res[1] != cache_res[1] || mds->res[2] != cache_res[2]) { + if (mds->flags & FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN) { reallocate = true; } else { @@ -1222,28 +1223,24 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_ } /* check if active fields have changed */ - if ((fluid_fields != cache_fields) || (active_fields != sds->active_fields)) { + if ((fluid_fields != cache_fields) || (active_fields != mds->active_fields)) { reallocate = true; } /* reallocate fluid if needed*/ if (reallocate) { - sds->active_fields = active_fields | cache_fields; - BKE_smoke_reallocate_fluid(sds, cache_dx, cache_res, 1); - sds->dx = cache_dx; - copy_v3_v3_int(sds->res, cache_res); - sds->total_cells = cache_res[0] * cache_res[1] * cache_res[2]; - - if (sds->flags & MOD_SMOKE_HIGHRES) { - BKE_smoke_reallocate_highres_fluid(sds, cache_dx, cache_res, 1); - } + mds->active_fields = active_fields | cache_fields; + BKE_fluid_reallocate_fluid(mds, cache_dx, cache_res, 1); + mds->dx = cache_dx; + copy_v3_v3_int(mds->res, cache_res); + mds->total_cells = cache_res[0] * cache_res[1] * cache_res[2]; } - if (sds->fluid) { + if (mds->fluid) { float dt, dx, *dens, *react, *fuel, *flame, *heat, *heatold, *vx, *vy, *vz, *r, *g, *b; unsigned char *obstacles; - smoke_export(sds->fluid, + smoke_export(mds->fluid, &dt, &dx, &dens, @@ -1258,56 +1255,57 @@ static int ptcache_smoke_openvdb_read(struct OpenVDBReader *reader, void *smoke_ &r, &g, &b, - &obstacles); + &obstacles, + NULL); OpenVDBReader_get_meta_fl(reader, "blender/smoke/dt", &dt); - OpenVDB_import_grid_fl(reader, "shadow", &sds->shadow, sds->res); + OpenVDB_import_grid_fl(reader, "shadow", &mds->shadow, mds->res); - const char *name = (!sds->wt) ? "density" : "density_low"; - OpenVDB_import_grid_fl(reader, name, &dens, sds->res); + const char *name = (!mds->wt) ? "density" : "density_low"; + OpenVDB_import_grid_fl(reader, name, &dens, mds->res); - if (cache_fields & SM_ACTIVE_HEAT) { - OpenVDB_import_grid_fl(reader, "heat", &heat, sds->res); - OpenVDB_import_grid_fl(reader, "heat_old", &heatold, sds->res); + if (cache_fields & FLUID_DOMAIN_ACTIVE_HEAT) { + OpenVDB_import_grid_fl(reader, "heat", &heat, mds->res); + OpenVDB_import_grid_fl(reader, "heat_old", &heatold, mds->res); } - if (cache_fields & SM_ACTIVE_FIRE) { - name = (!sds->wt) ? "flame" : "flame_low"; - OpenVDB_import_grid_fl(reader, name, &flame, sds->res); - name = (!sds->wt) ? "fuel" : "fuel_low"; - OpenVDB_import_grid_fl(reader, name, &fuel, sds->res); - name = (!sds->wt) ? "react" : "react_low"; - OpenVDB_import_grid_fl(reader, name, &react, sds->res); + if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) { + name = (!mds->wt) ? "flame" : "flame_low"; + OpenVDB_import_grid_fl(reader, name, &flame, mds->res); + name = (!mds->wt) ? "fuel" : "fuel_low"; + OpenVDB_import_grid_fl(reader, name, &fuel, mds->res); + name = (!mds->wt) ? "react" : "react_low"; + OpenVDB_import_grid_fl(reader, name, &react, mds->res); } - if (cache_fields & SM_ACTIVE_COLORS) { - name = (!sds->wt) ? "color" : "color_low"; - OpenVDB_import_grid_vec(reader, name, &r, &g, &b, sds->res); + if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) { + name = (!mds->wt) ? "color" : "color_low"; + OpenVDB_import_grid_vec(reader, name, &r, &g, &b, mds->res); } - OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, sds->res); - OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, sds->res); + OpenVDB_import_grid_vec(reader, "velocity", &vx, &vy, &vz, mds->res); + OpenVDB_import_grid_ch(reader, "obstacles", &obstacles, mds->res); } - if (sds->wt) { + if (mds->wt) { float *dens, *react, *fuel, *flame, *tcu, *tcv, *tcw, *r, *g, *b; - smoke_turbulence_export(sds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); + smoke_turbulence_export(mds->wt, &dens, &react, &flame, &fuel, &r, &g, &b, &tcu, &tcv, &tcw); - OpenVDB_import_grid_fl(reader, "density", &dens, sds->res_wt); + OpenVDB_import_grid_fl(reader, "density", &dens, mds->res_wt); - if (cache_fields & SM_ACTIVE_FIRE) { - OpenVDB_import_grid_fl(reader, "flame", &flame, sds->res_wt); - OpenVDB_import_grid_fl(reader, "fuel", &fuel, sds->res_wt); - OpenVDB_import_grid_fl(reader, "react", &react, sds->res_wt); + if (cache_fields & FLUID_DOMAIN_ACTIVE_FIRE) { + OpenVDB_import_grid_fl(reader, "flame", &flame, mds->res_wt); + OpenVDB_import_grid_fl(reader, "fuel", &fuel, mds->res_wt); + OpenVDB_import_grid_fl(reader, "react", &react, mds->res_wt); } - if (cache_fields & SM_ACTIVE_COLORS) { - OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, sds->res_wt); + if (cache_fields & FLUID_DOMAIN_ACTIVE_COLORS) { + OpenVDB_import_grid_vec(reader, "color", &r, &g, &b, mds->res_wt); } - OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, sds->res); + OpenVDB_import_grid_vec(reader, "texture coordinates", &tcu, &tcv, &tcw, mds->res); } OpenVDBReader_free(reader); @@ -1698,21 +1696,21 @@ void BKE_ptcache_id_from_cloth(PTCacheID *pid, Object *ob, ClothModifierData *cl pid->max_step = 1; pid->file_type = PTCACHE_FILE_PTCACHE; } -void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeModifierData *smd) +void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct FluidModifierData *mmd) { - SmokeDomainSettings *sds = smd->domain; + FluidDomainSettings *mds = mmd->domain; memset(pid, 0, sizeof(PTCacheID)); pid->ob = ob; - pid->calldata = smd; + pid->calldata = mmd; pid->type = PTCACHE_TYPE_SMOKE_DOMAIN; - pid->stack_index = sds->point_cache[0]->index; + pid->stack_index = mds->point_cache[0]->index; - pid->cache = sds->point_cache[0]; - pid->cache_ptr = &(sds->point_cache[0]); - pid->ptcaches = &(sds->ptcaches[0]); + pid->cache = mds->point_cache[0]; + pid->cache_ptr = &(mds->point_cache[0]); + pid->ptcaches = &(mds->ptcaches[0]); pid->totpoint = pid->totwrite = ptcache_smoke_totpoint; pid->error = ptcache_smoke_error; @@ -1737,16 +1735,16 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo pid->data_types = 0; pid->info_types = 0; - if (sds->fluid) { + if (mds->fluid) { pid->data_types |= (1 << BPHYS_DATA_SMOKE_LOW); - } - if (sds->wt) { - pid->data_types |= (1 << BPHYS_DATA_SMOKE_HIGH); + if (mds->flags & FLUID_DOMAIN_USE_NOISE) { + pid->data_types |= (1 << BPHYS_DATA_SMOKE_HIGH); + } } pid->default_step = 1; pid->max_step = 1; - pid->file_type = smd->domain->cache_file_format; + pid->file_type = mmd->domain->cache_file_format; } void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, Object *ob, DynamicPaintSurface *surface) @@ -1908,10 +1906,10 @@ static bool foreach_object_modifier_ptcache(Object *object, return false; } } - else if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - BKE_ptcache_id_from_smoke(&pid, object, (SmokeModifierData *)md); + else if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { + BKE_ptcache_id_from_smoke(&pid, object, (FluidModifierData *)md); if (!callback(&pid, callback_user_data)) { return false; } @@ -3741,10 +3739,10 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode) BKE_ptcache_id_from_cloth(&pid, ob, (ClothModifierData *)md); reset |= BKE_ptcache_id_reset(scene, &pid, mode); } - if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - BKE_ptcache_id_from_smoke(&pid, ob, (SmokeModifierData *)md); + if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { + BKE_ptcache_id_from_smoke(&pid, ob, (FluidModifierData *)md); reset |= BKE_ptcache_id_reset(scene, &pid, mode); } } diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c deleted file mode 100644 index 4c3b7a619da..00000000000 --- a/source/blender/blenkernel/intern/smoke.c +++ /dev/null @@ -1,3654 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup bke - */ - -/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */ - -#include "MEM_guardedalloc.h" - -#include <float.h> -#include <math.h> -#include <stdio.h> -#include <string.h> /* memset */ - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_kdopbvh.h" -#include "BLI_threads.h" -#include "BLI_utildefines.h" - -#include "DNA_anim_types.h" -#include "DNA_armature_types.h" -#include "DNA_constraint_types.h" -#include "DNA_customdata_types.h" -#include "DNA_light_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_particle_types.h" -#include "DNA_scene_types.h" -#include "DNA_smoke_types.h" - -#include "BKE_appdir.h" -#include "BKE_animsys.h" -#include "BKE_armature.h" -#include "BKE_bvhutils.h" -#include "BKE_collision.h" -#include "BKE_colortools.h" -#include "BKE_constraint.h" -#include "BKE_customdata.h" -#include "BKE_deform.h" -#include "BKE_effect.h" -#include "BKE_library.h" -#include "BKE_mesh.h" -#include "BKE_mesh_runtime.h" -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_particle.h" -#include "BKE_pointcache.h" -#include "BKE_scene.h" -#include "BKE_smoke.h" -#include "BKE_texture.h" - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" - -#include "RE_shader_ext.h" - -#include "GPU_glew.h" - -/* UNUSED so far, may be enabled later */ -/* #define USE_SMOKE_COLLISION_DM */ - -//#define DEBUG_TIME - -#include "smoke_API.h" - -#ifdef DEBUG_TIME -# include "PIL_time.h" -#endif - -#ifdef WITH_SMOKE -# include "BLI_task.h" -# include "BLI_kdtree.h" -# include "BLI_voxel.h" - -static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER; - -struct Mesh; -struct Object; -struct Scene; -struct SmokeModifierData; - -// timestep default value for nice appearance 0.1f -# define DT_DEFAULT 0.1f - -# define ADD_IF_LOWER_POS(a, b) (min_ff((a) + (b), max_ff((a), (b)))) -# define ADD_IF_LOWER_NEG(a, b) (max_ff((a) + (b), min_ff((a), (b)))) -# define ADD_IF_LOWER(a, b) (((b) > 0) ? ADD_IF_LOWER_POS((a), (b)) : ADD_IF_LOWER_NEG((a), (b))) - -#else /* WITH_SMOKE */ - -/* Stubs to use when smoke is disabled */ -struct WTURBULENCE *smoke_turbulence_init(int *UNUSED(res), - int UNUSED(amplify), - int UNUSED(noisetype), - const char *UNUSED(noisefile_path), - int UNUSED(use_fire), - int UNUSED(use_colors)) -{ - return NULL; -} - -void smoke_free(struct FLUID_3D *UNUSED(fluid)) -{ -} -float *smoke_get_density(struct FLUID_3D *UNUSED(fluid)) -{ - return NULL; -} -void smoke_turbulence_free(struct WTURBULENCE *UNUSED(wt)) -{ -} -void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(strength)) -{ -} -void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), - float *UNUSED(alpha), - float *UNUSED(beta), - float *UNUSED(dt_factor), - float *UNUSED(vorticity), - int *UNUSED(border_colli), - float *UNUSED(burning_rate), - float *UNUSED(flame_smoke), - float *UNUSED(flame_smoke_color), - float *UNUSED(flame_vorticity), - float *UNUSED(flame_ignition_temp), - float *UNUSED(flame_max_temp)) -{ -} -struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), - Depsgraph *UNUSED(depsgraph), - Scene *UNUSED(scene), - Object *UNUSED(ob), - Mesh *UNUSED(me)) -{ - return NULL; -} -float BKE_smoke_get_velocity_at(struct Object *UNUSED(ob), - float UNUSED(position[3]), - float UNUSED(velocity[3])) -{ - return 0.0f; -} - -#endif /* WITH_SMOKE */ - -#ifdef WITH_SMOKE - -void BKE_smoke_reallocate_fluid(SmokeDomainSettings *sds, float dx, int res[3], int free_old) -{ - int use_heat = (sds->active_fields & SM_ACTIVE_HEAT); - int use_fire = (sds->active_fields & SM_ACTIVE_FIRE); - int use_colors = (sds->active_fields & SM_ACTIVE_COLORS); - - if (free_old && sds->fluid) { - smoke_free(sds->fluid); - } - if (!min_iii(res[0], res[1], res[2])) { - sds->fluid = NULL; - return; - } - sds->fluid = smoke_init(res, dx, DT_DEFAULT, use_heat, use_fire, use_colors); - smoke_initBlenderRNA(sds->fluid, - &(sds->alpha), - &(sds->beta), - &(sds->time_scale), - &(sds->vorticity), - &(sds->border_collisions), - &(sds->burning_rate), - &(sds->flame_smoke), - sds->flame_smoke_color, - &(sds->flame_vorticity), - &(sds->flame_ignition), - &(sds->flame_max_temp)); - - /* reallocate shadow buffer */ - if (sds->shadow) { - MEM_freeN(sds->shadow); - } - sds->shadow = MEM_callocN(sizeof(float) * res[0] * res[1] * res[2], "SmokeDomainShadow"); -} - -void BKE_smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, - float dx, - int res[3], - int free_old) -{ - int use_fire = (sds->active_fields & (SM_ACTIVE_HEAT | SM_ACTIVE_FIRE)); - int use_colors = (sds->active_fields & SM_ACTIVE_COLORS); - - if (free_old && sds->wt) { - smoke_turbulence_free(sds->wt); - } - if (!min_iii(res[0], res[1], res[2])) { - sds->wt = NULL; - return; - } - - /* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */ - BLI_thread_lock(LOCK_FFTW); - - sds->wt = smoke_turbulence_init( - res, sds->amplify + 1, sds->noise, BKE_tempdir_session(), use_fire, use_colors); - - BLI_thread_unlock(LOCK_FFTW); - - sds->res_wt[0] = res[0] * (sds->amplify + 1); - sds->res_wt[1] = res[1] * (sds->amplify + 1); - sds->res_wt[2] = res[2] * (sds->amplify + 1); - sds->dx_wt = dx / (sds->amplify + 1); - smoke_initWaveletBlenderRNA(sds->wt, &(sds->strength)); -} - -/* convert global position to domain cell space */ -static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3]) -{ - mul_m4_v3(sds->imat, pos); - sub_v3_v3(pos, sds->p0); - pos[0] *= 1.0f / sds->cell_size[0]; - pos[1] *= 1.0f / sds->cell_size[1]; - pos[2] *= 1.0f / sds->cell_size[2]; -} - -/* set domain transformations and base resolution from object mesh */ -static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds, - Object *ob, - Mesh *me, - bool init_resolution) -{ - size_t i; - float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; - float size[3]; - MVert *verts = me->mvert; - float scale = 0.0; - int res; - - res = sds->maxres; - - // get BB of domain - for (i = 0; i < me->totvert; i++) { - // min BB - min[0] = MIN2(min[0], verts[i].co[0]); - min[1] = MIN2(min[1], verts[i].co[1]); - min[2] = MIN2(min[2], verts[i].co[2]); - - // max BB - max[0] = MAX2(max[0], verts[i].co[0]); - max[1] = MAX2(max[1], verts[i].co[1]); - max[2] = MAX2(max[2], verts[i].co[2]); - } - - /* set domain bounds */ - copy_v3_v3(sds->p0, min); - copy_v3_v3(sds->p1, max); - sds->dx = 1.0f / res; - - /* calculate domain dimensions */ - sub_v3_v3v3(size, max, min); - if (init_resolution) { - zero_v3_int(sds->base_res); - copy_v3_v3(sds->cell_size, size); - } - /* apply object scale */ - for (i = 0; i < 3; i++) { - size[i] = fabsf(size[i] * ob->scale[i]); - } - copy_v3_v3(sds->global_size, size); - copy_v3_v3(sds->dp0, min); - - invert_m4_m4(sds->imat, ob->obmat); - - // prevent crash when initializing a plane as domain - if (!init_resolution || (size[0] < FLT_EPSILON) || (size[1] < FLT_EPSILON) || - (size[2] < FLT_EPSILON)) { - return; - } - - /* define grid resolutions from longest domain side */ - if (size[0] >= MAX2(size[1], size[2])) { - scale = res / size[0]; - sds->scale = size[0] / fabsf(ob->scale[0]); - sds->base_res[0] = res; - sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4); - sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4); - } - else if (size[1] >= MAX2(size[0], size[2])) { - scale = res / size[1]; - sds->scale = size[1] / fabsf(ob->scale[1]); - sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4); - sds->base_res[1] = res; - sds->base_res[2] = max_ii((int)(size[2] * scale + 0.5f), 4); - } - else { - scale = res / size[2]; - sds->scale = size[2] / fabsf(ob->scale[2]); - sds->base_res[0] = max_ii((int)(size[0] * scale + 0.5f), 4); - sds->base_res[1] = max_ii((int)(size[1] * scale + 0.5f), 4); - sds->base_res[2] = res; - } - - /* set cell size */ - sds->cell_size[0] /= (float)sds->base_res[0]; - sds->cell_size[1] /= (float)sds->base_res[1]; - sds->cell_size[2] /= (float)sds->base_res[2]; -} - -static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me) -{ - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid) { - SmokeDomainSettings *sds = smd->domain; - int res[3]; - /* set domain dimensions from mesh */ - smoke_set_domain_from_mesh(sds, ob, me, true); - /* reset domain values */ - zero_v3_int(sds->shift); - zero_v3(sds->shift_f); - add_v3_fl(sds->shift_f, 0.5f); - zero_v3(sds->prev_loc); - mul_m4_v3(ob->obmat, sds->prev_loc); - copy_m4_m4(sds->obmat, ob->obmat); - - /* set resolutions */ - if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - res[0] = res[1] = res[2] = 1; /* use minimum res for adaptive init */ - } - else { - copy_v3_v3_int(res, sds->base_res); - } - copy_v3_v3_int(sds->res, res); - sds->total_cells = sds->res[0] * sds->res[1] * sds->res[2]; - sds->res_min[0] = sds->res_min[1] = sds->res_min[2] = 0; - copy_v3_v3_int(sds->res_max, res); - - /* allocate fluid */ - BKE_smoke_reallocate_fluid(sds, sds->dx, sds->res, 0); - - smd->time = scene_framenr; - - /* allocate highres fluid */ - if (sds->flags & MOD_SMOKE_HIGHRES) { - BKE_smoke_reallocate_highres_fluid(sds, sds->dx, sds->res, 0); - } - /* allocate shadow buffer */ - if (!sds->shadow) { - sds->shadow = MEM_callocN(sizeof(float) * sds->res[0] * sds->res[1] * sds->res[2], - "SmokeDomainShadow"); - } - return 1; - } - else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { - smd->time = scene_framenr; - - return 1; - } - else if ((smd->type & MOD_SMOKE_TYPE_COLL)) { - if (!smd->coll) { - smokeModifier_createType(smd); - } - - smd->time = scene_framenr; - - return 1; - } - - return 2; -} - -#endif /* WITH_SMOKE */ - -static void smokeModifier_freeDomain(SmokeModifierData *smd) -{ - if (smd->domain) { - if (smd->domain->shadow) { - MEM_freeN(smd->domain->shadow); - } - smd->domain->shadow = NULL; - - if (smd->domain->fluid) { - smoke_free(smd->domain->fluid); - } - - if (smd->domain->fluid_mutex) { - BLI_rw_mutex_free(smd->domain->fluid_mutex); - } - - if (smd->domain->wt) { - smoke_turbulence_free(smd->domain->wt); - } - - if (smd->domain->effector_weights) { - MEM_freeN(smd->domain->effector_weights); - } - smd->domain->effector_weights = NULL; - - if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) { - BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); - smd->domain->point_cache[0] = NULL; - } - - if (smd->domain->coba) { - MEM_freeN(smd->domain->coba); - } - - MEM_freeN(smd->domain); - smd->domain = NULL; - } -} - -static void smokeModifier_freeFlow(SmokeModifierData *smd) -{ - if (smd->flow) { - if (smd->flow->mesh) { - BKE_id_free(NULL, smd->flow->mesh); - } - if (smd->flow->verts_old) { - MEM_freeN(smd->flow->verts_old); - } - MEM_freeN(smd->flow); - smd->flow = NULL; - } -} - -static void smokeModifier_freeCollision(SmokeModifierData *smd) -{ - if (smd->coll) { - SmokeCollSettings *scs = smd->coll; - - if (scs->numverts) { - if (scs->verts_old) { - MEM_freeN(scs->verts_old); - scs->verts_old = NULL; - } - } - - if (smd->coll->mesh) { - BKE_id_free(NULL, smd->coll->mesh); - } - smd->coll->mesh = NULL; - - MEM_freeN(smd->coll); - smd->coll = NULL; - } -} - -void smokeModifier_reset_turbulence(struct SmokeModifierData *smd) -{ - if (smd && smd->domain && smd->domain->wt) { - smoke_turbulence_free(smd->domain->wt); - smd->domain->wt = NULL; - } -} - -static void smokeModifier_reset_ex(struct SmokeModifierData *smd, bool need_lock) -{ - if (smd) { - if (smd->domain) { - if (smd->domain->shadow) { - MEM_freeN(smd->domain->shadow); - } - smd->domain->shadow = NULL; - - if (smd->domain->fluid) { - if (need_lock) { - BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); - } - - smoke_free(smd->domain->fluid); - smd->domain->fluid = NULL; - - if (need_lock) { - BLI_rw_mutex_unlock(smd->domain->fluid_mutex); - } - } - - smokeModifier_reset_turbulence(smd); - - smd->time = -1; - smd->domain->total_cells = 0; - smd->domain->active_fields = 0; - } - else if (smd->flow) { - if (smd->flow->verts_old) { - MEM_freeN(smd->flow->verts_old); - } - smd->flow->verts_old = NULL; - smd->flow->numverts = 0; - } - else if (smd->coll) { - SmokeCollSettings *scs = smd->coll; - - if (scs->numverts && scs->verts_old) { - MEM_freeN(scs->verts_old); - scs->verts_old = NULL; - } - } - } -} - -void smokeModifier_reset(struct SmokeModifierData *smd) -{ - smokeModifier_reset_ex(smd, true); -} - -void smokeModifier_free(SmokeModifierData *smd) -{ - if (smd) { - smokeModifier_freeDomain(smd); - smokeModifier_freeFlow(smd); - smokeModifier_freeCollision(smd); - } -} - -void smokeModifier_createType(struct SmokeModifierData *smd) -{ - if (smd) { - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - if (smd->domain) { - smokeModifier_freeDomain(smd); - } - - smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain"); - - smd->domain->smd = smd; - - smd->domain->point_cache[0] = BKE_ptcache_add(&(smd->domain->ptcaches[0])); - smd->domain->point_cache[0]->flag |= PTCACHE_DISK_CACHE; - smd->domain->point_cache[0]->step = 1; - - /* Deprecated */ - smd->domain->point_cache[1] = NULL; - BLI_listbase_clear(&smd->domain->ptcaches[1]); - /* set some standard values */ - smd->domain->fluid = NULL; - smd->domain->fluid_mutex = BLI_rw_mutex_alloc(); - smd->domain->wt = NULL; - smd->domain->eff_group = NULL; - smd->domain->fluid_group = NULL; - smd->domain->coll_group = NULL; - smd->domain->maxres = 32; - smd->domain->amplify = 1; - smd->domain->alpha = -0.001; - smd->domain->beta = 0.1; - smd->domain->time_scale = 1.0; - smd->domain->vorticity = 2.0; - smd->domain->border_collisions = SM_BORDER_OPEN; // open domain - smd->domain->flags = MOD_SMOKE_DISSOLVE_LOG; - smd->domain->highres_sampling = SM_HRES_FULLSAMPLE; - smd->domain->strength = 2.0; - smd->domain->noise = MOD_SMOKE_NOISEWAVE; - smd->domain->diss_speed = 5; - smd->domain->active_fields = 0; - - smd->domain->adapt_margin = 4; - smd->domain->adapt_res = 0; - smd->domain->adapt_threshold = 0.02f; - - smd->domain->burning_rate = 0.75f; - smd->domain->flame_smoke = 1.0f; - smd->domain->flame_vorticity = 0.5f; - smd->domain->flame_ignition = 1.5f; - smd->domain->flame_max_temp = 3.0f; - /* color */ - smd->domain->flame_smoke_color[0] = 0.7f; - smd->domain->flame_smoke_color[1] = 0.7f; - smd->domain->flame_smoke_color[2] = 0.7f; - - smd->domain->viewsettings = MOD_SMOKE_VIEW_SHOW_HIGHRES; - smd->domain->effector_weights = BKE_effector_add_weights(NULL); - -#ifdef WITH_OPENVDB_BLOSC - smd->domain->openvdb_comp = VDB_COMPRESSION_BLOSC; -#else - smd->domain->openvdb_comp = VDB_COMPRESSION_ZIP; -#endif - smd->domain->data_depth = 0; - smd->domain->cache_file_format = PTCACHE_FILE_PTCACHE; - - smd->domain->display_thickness = 1.0f; - smd->domain->slice_method = MOD_SMOKE_SLICE_VIEW_ALIGNED; - smd->domain->axis_slice_method = AXIS_SLICE_FULL; - smd->domain->slice_per_voxel = 5.0f; - smd->domain->slice_depth = 0.5f; - smd->domain->slice_axis = 0; - smd->domain->vector_scale = 1.0f; - - smd->domain->coba = NULL; - smd->domain->coba_field = FLUID_FIELD_DENSITY; - - smd->domain->clipping = 1e-3f; - } - else if (smd->type & MOD_SMOKE_TYPE_FLOW) { - if (smd->flow) { - smokeModifier_freeFlow(smd); - } - - smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow"); - - smd->flow->smd = smd; - - /* set some standard values */ - smd->flow->density = 1.0f; - smd->flow->fuel_amount = 1.0f; - smd->flow->temp = 1.0f; - smd->flow->flags = MOD_SMOKE_FLOW_ABSOLUTE | MOD_SMOKE_FLOW_USE_PART_SIZE; - smd->flow->vel_multi = 1.0f; - smd->flow->volume_density = 0.0f; - smd->flow->surface_distance = 1.5f; - smd->flow->source = MOD_SMOKE_FLOW_SOURCE_MESH; - smd->flow->texture_size = 1.0f; - smd->flow->particle_size = 1.0f; - smd->flow->subframes = 0; - - smd->flow->color[0] = 0.7f; - smd->flow->color[1] = 0.7f; - smd->flow->color[2] = 0.7f; - - smd->flow->mesh = NULL; - smd->flow->psys = NULL; - } - else if (smd->type & MOD_SMOKE_TYPE_COLL) { - if (smd->coll) { - smokeModifier_freeCollision(smd); - } - - smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl"); - - smd->coll->smd = smd; - smd->coll->verts_old = NULL; - smd->coll->numverts = 0; - smd->coll->type = 0; // static obstacle - smd->coll->mesh = NULL; - } - } -} - -void smokeModifier_copy(const struct SmokeModifierData *smd, - struct SmokeModifierData *tsmd, - const int flag) -{ - tsmd->type = smd->type; - tsmd->time = smd->time; - - smokeModifier_createType(tsmd); - - if (tsmd->domain) { - SmokeDomainSettings *tsds = tsmd->domain; - SmokeDomainSettings *sds = smd->domain; - - BKE_ptcache_free_list(&(tsds->ptcaches[0])); - - if (flag & LIB_ID_CREATE_NO_MAIN) { - /* Share the cache with the original object's modifier. */ - tsmd->modifier.flag |= eModifierFlag_SharedCaches; - tsds->point_cache[0] = sds->point_cache[0]; - tsds->ptcaches[0] = sds->ptcaches[0]; - } - else { - tsds->point_cache[0] = BKE_ptcache_copy_list( - &(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag); - } - - tsds->fluid_group = sds->fluid_group; - tsds->coll_group = sds->coll_group; - - tsds->adapt_margin = sds->adapt_margin; - tsds->adapt_res = sds->adapt_res; - tsds->adapt_threshold = sds->adapt_threshold; - - tsds->alpha = sds->alpha; - tsds->beta = sds->beta; - tsds->amplify = sds->amplify; - tsds->maxres = sds->maxres; - tsds->flags = sds->flags; - tsds->highres_sampling = sds->highres_sampling; - tsds->viewsettings = sds->viewsettings; - tsds->noise = sds->noise; - tsds->diss_speed = sds->diss_speed; - tsds->strength = sds->strength; - - tsds->border_collisions = sds->border_collisions; - tsds->vorticity = sds->vorticity; - tsds->time_scale = sds->time_scale; - - tsds->burning_rate = sds->burning_rate; - tsds->flame_smoke = sds->flame_smoke; - tsds->flame_vorticity = sds->flame_vorticity; - tsds->flame_ignition = sds->flame_ignition; - tsds->flame_max_temp = sds->flame_max_temp; - copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color); - - MEM_freeN(tsds->effector_weights); - tsds->effector_weights = MEM_dupallocN(sds->effector_weights); - tsds->openvdb_comp = sds->openvdb_comp; - tsds->data_depth = sds->data_depth; - tsds->cache_file_format = sds->cache_file_format; - - tsds->display_thickness = sds->display_thickness; - tsds->slice_method = sds->slice_method; - tsds->axis_slice_method = sds->axis_slice_method; - tsds->slice_per_voxel = sds->slice_per_voxel; - tsds->slice_depth = sds->slice_depth; - tsds->slice_axis = sds->slice_axis; - tsds->interp_method = sds->interp_method; - tsds->draw_velocity = sds->draw_velocity; - tsds->vector_draw_type = sds->vector_draw_type; - tsds->vector_scale = sds->vector_scale; - - tsds->use_coba = sds->use_coba; - tsds->coba_field = sds->coba_field; - if (sds->coba) { - tsds->coba = MEM_dupallocN(sds->coba); - } - - tsds->clipping = sds->clipping; - } - else if (tsmd->flow) { - SmokeFlowSettings *tsfs = tsmd->flow; - SmokeFlowSettings *sfs = smd->flow; - - tsfs->psys = sfs->psys; - tsfs->noise_texture = sfs->noise_texture; - - tsfs->vel_multi = sfs->vel_multi; - tsfs->vel_normal = sfs->vel_normal; - tsfs->vel_random = sfs->vel_random; - - tsfs->density = sfs->density; - copy_v3_v3(tsfs->color, sfs->color); - tsfs->fuel_amount = sfs->fuel_amount; - tsfs->temp = sfs->temp; - tsfs->volume_density = sfs->volume_density; - tsfs->surface_distance = sfs->surface_distance; - tsfs->particle_size = sfs->particle_size; - tsfs->subframes = sfs->subframes; - - tsfs->texture_size = sfs->texture_size; - tsfs->texture_offset = sfs->texture_offset; - BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name)); - tsfs->vgroup_density = sfs->vgroup_density; - - tsfs->type = sfs->type; - tsfs->source = sfs->source; - tsfs->texture_type = sfs->texture_type; - tsfs->flags = sfs->flags; - } - else if (tsmd->coll) { - /* leave it as initialized, collision settings is mostly caches */ - } -} - -#ifdef WITH_SMOKE - -// forward declaration -static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer); -static float calc_voxel_transp( - float *result, float *input, int res[3], int *pixel, float *tRay, float correct); - -static int get_light(ViewLayer *view_layer, float *light) -{ - Base *base_tmp = NULL; - int found_light = 0; - - // try to find a lamp, preferably local - for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) { - if (base_tmp->object->type == OB_LAMP) { - Light *la = base_tmp->object->data; - - if (la->type == LA_LOCAL) { - copy_v3_v3(light, base_tmp->object->obmat[3]); - return 1; - } - else if (!found_light) { - copy_v3_v3(light, base_tmp->object->obmat[3]); - found_light = 1; - } - } - } - - return found_light; -} - -/********************************************************** - * Obstacles - **********************************************************/ - -typedef struct ObstaclesFromDMData { - SmokeDomainSettings *sds; - const MVert *mvert; - const MLoop *mloop; - const MLoopTri *looptri; - BVHTreeFromMesh *tree; - unsigned char *obstacle_map; - - bool has_velocity; - float *vert_vel; - float *velocityX, *velocityY, *velocityZ; - int *num_obstacles; -} ObstaclesFromDMData; - -static void obstacles_from_mesh_task_cb(void *__restrict userdata, - const int z, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - ObstaclesFromDMData *data = userdata; - SmokeDomainSettings *sds = data->sds; - - /* slightly rounded-up sqrt(3 * (0.5)^2) == max. distance of cell boundary along the diagonal */ - const float surface_distance = 0.867f; - - for (int x = sds->res_min[0]; x < sds->res_max[0]; x++) { - for (int y = sds->res_min[1]; y < sds->res_max[1]; y++) { - const int index = smoke_get_index( - x - sds->res_min[0], sds->res[0], y - sds->res_min[1], sds->res[1], z - sds->res_min[2]); - - float ray_start[3] = {(float)x + 0.5f, (float)y + 0.5f, (float)z + 0.5f}; - BVHTreeNearest nearest = {0}; - nearest.index = -1; - nearest.dist_sq = surface_distance * - surface_distance; /* find_nearest uses squared distance */ - - /* find the nearest point on the mesh */ - if (BLI_bvhtree_find_nearest( - data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != - -1) { - const MLoopTri *lt = &data->looptri[nearest.index]; - float weights[3]; - int v1, v2, v3; - - /* calculate barycentric weights for nearest point */ - v1 = data->mloop[lt->tri[0]].v; - v2 = data->mloop[lt->tri[1]].v; - v3 = data->mloop[lt->tri[2]].v; - interp_weights_tri_v3( - weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co); - - // DG TODO - if (data->has_velocity) { - /* apply object velocity */ - { - float hit_vel[3]; - interp_v3_v3v3v3(hit_vel, - &data->vert_vel[v1 * 3], - &data->vert_vel[v2 * 3], - &data->vert_vel[v3 * 3], - weights); - data->velocityX[index] += hit_vel[0]; - data->velocityY[index] += hit_vel[1]; - data->velocityZ[index] += hit_vel[2]; - } - } - - /* tag obstacle cells */ - data->obstacle_map[index] = 1; - - if (data->has_velocity) { - data->obstacle_map[index] |= 8; - data->num_obstacles[index]++; - } - } - } - } -} - -static void obstacles_from_mesh(Object *coll_ob, - SmokeDomainSettings *sds, - SmokeCollSettings *scs, - unsigned char *obstacle_map, - float *velocityX, - float *velocityY, - float *velocityZ, - int *num_obstacles, - float dt) -{ - if (!scs->mesh) { - return; - } - { - Mesh *me = NULL; - MVert *mvert = NULL; - const MLoopTri *looptri; - const MLoop *mloop; - BVHTreeFromMesh treeData = {NULL}; - int numverts, i; - - float *vert_vel = NULL; - bool has_velocity = false; - - me = BKE_mesh_copy_for_eval(scs->mesh, true); - BKE_mesh_ensure_normals(me); - mvert = me->mvert; - mloop = me->mloop; - looptri = BKE_mesh_runtime_looptri_ensure(me); - numverts = me->totvert; - - // DG TODO - // if (scs->type > SM_COLL_STATIC) - // if line above is used, the code is in trouble if the object moves - // but is declared as "does not move". - - { - vert_vel = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_velocity"); - - if (scs->numverts != numverts || !scs->verts_old) { - if (scs->verts_old) { - MEM_freeN(scs->verts_old); - } - - scs->verts_old = MEM_callocN(sizeof(float) * numverts * 3, "smoke_obs_verts_old"); - scs->numverts = numverts; - } - else { - has_velocity = true; - } - } - - /* Transform collider vertices to - * domain grid space for fast lookups */ - for (i = 0; i < numverts; i++) { - float n[3]; - float co[3]; - - /* vert pos */ - mul_m4_v3(coll_ob->obmat, mvert[i].co); - smoke_pos_to_cell(sds, mvert[i].co); - - /* vert normal */ - normal_short_to_float_v3(n, mvert[i].no); - mul_mat3_m4_v3(coll_ob->obmat, n); - mul_mat3_m4_v3(sds->imat, n); - normalize_v3(n); - normal_float_to_short_v3(mvert[i].no, n); - - /* vert velocity */ - add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift); - if (has_velocity) { - sub_v3_v3v3(&vert_vel[i * 3], co, &scs->verts_old[i * 3]); - mul_v3_fl(&vert_vel[i * 3], sds->dx / dt); - } - copy_v3_v3(&scs->verts_old[i * 3], co); - } - - if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) { - ObstaclesFromDMData data = { - .sds = sds, - .mvert = mvert, - .mloop = mloop, - .looptri = looptri, - .tree = &treeData, - .obstacle_map = obstacle_map, - .has_velocity = has_velocity, - .vert_vel = vert_vel, - .velocityX = velocityX, - .velocityY = velocityY, - .velocityZ = velocityZ, - .num_obstacles = num_obstacles, - }; - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; - BLI_task_parallel_range( - sds->res_min[2], sds->res_max[2], &data, obstacles_from_mesh_task_cb, &settings); - } - /* free bvh tree */ - free_bvhtree_from_mesh(&treeData); - BKE_id_free(NULL, me); - - if (vert_vel) { - MEM_freeN(vert_vel); - } - } -} - -/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */ -static void update_obstacles(Depsgraph *depsgraph, - Object *ob, - SmokeDomainSettings *sds, - float dt, - int UNUSED(substep), - int UNUSED(totalsteps)) -{ - Object **collobjs = NULL; - unsigned int numcollobj = 0; - - unsigned int collIndex; - unsigned char *obstacles = smoke_get_obstacle(sds->fluid); - float *velx = NULL; - float *vely = NULL; - float *velz = NULL; - float *velxOrig = smoke_get_velocity_x(sds->fluid); - float *velyOrig = smoke_get_velocity_y(sds->fluid); - float *velzOrig = smoke_get_velocity_z(sds->fluid); - float *density = smoke_get_density(sds->fluid); - float *fuel = smoke_get_fuel(sds->fluid); - float *flame = smoke_get_flame(sds->fluid); - float *r = smoke_get_color_r(sds->fluid); - float *g = smoke_get_color_g(sds->fluid); - float *b = smoke_get_color_b(sds->fluid); - unsigned int z; - - int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], - "smoke_num_obstacles"); - - smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz); - - // TODO: delete old obstacle flags - for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) { - if (obstacles[z] & 8) // Do not delete static obstacles - { - obstacles[z] = 0; - } - - velx[z] = 0; - vely[z] = 0; - velz[z] = 0; - } - - collobjs = BKE_collision_objects_create( - depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke); - - // update obstacle tags in cells - for (collIndex = 0; collIndex < numcollobj; collIndex++) { - Object *collob = collobjs[collIndex]; - SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, - eModifierType_Smoke); - - // DG TODO: check if modifier is active? - - if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) { - SmokeCollSettings *scs = smd2->coll; - obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt); - } - } - - BKE_collision_objects_free(collobjs); - - /* obstacle cells should not contain any velocity from the smoke simulation */ - for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++) { - if (obstacles[z]) { - velxOrig[z] = 0; - velyOrig[z] = 0; - velzOrig[z] = 0; - density[z] = 0; - if (fuel) { - fuel[z] = 0; - flame[z] = 0; - } - if (r) { - r[z] = 0; - g[z] = 0; - b[z] = 0; - } - } - /* average velocities from multiple obstacles in one cell */ - if (num_obstacles[z]) { - velx[z] /= num_obstacles[z]; - vely[z] /= num_obstacles[z]; - velz[z] /= num_obstacles[z]; - } - } - - MEM_freeN(num_obstacles); -} - -/********************************************************** - * Flow emission code - **********************************************************/ - -typedef struct EmissionMap { - float *influence; - float *influence_high; - float *velocity; - int min[3], max[3], res[3]; - int hmin[3], hmax[3], hres[3]; - int total_cells, valid; -} EmissionMap; - -static void em_boundInsert(EmissionMap *em, float point[3]) -{ - int i = 0; - if (!em->valid) { - for (; i < 3; i++) { - em->min[i] = (int)floor(point[i]); - em->max[i] = (int)ceil(point[i]); - } - em->valid = 1; - } - else { - for (; i < 3; i++) { - if (point[i] < em->min[i]) { - em->min[i] = (int)floor(point[i]); - } - if (point[i] > em->max[i]) { - em->max[i] = (int)ceil(point[i]); - } - } - } -} - -static void clampBoundsInDomain(SmokeDomainSettings *sds, - int min[3], - int max[3], - float *min_vel, - float *max_vel, - int margin, - float dt) -{ - int i; - for (i = 0; i < 3; i++) { - int adapt = (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) ? sds->adapt_res : 0; - /* add margin */ - min[i] -= margin; - max[i] += margin; - - /* adapt to velocity */ - if (min_vel && min_vel[i] < 0.0f) { - min[i] += (int)floor(min_vel[i] * dt); - } - if (max_vel && max_vel[i] > 0.0f) { - max[i] += (int)ceil(max_vel[i] * dt); - } - - /* clamp within domain max size */ - CLAMP(min[i], -adapt, sds->base_res[i] + adapt); - CLAMP(max[i], -adapt, sds->base_res[i] + adapt); - } -} - -static void em_allocateData(EmissionMap *em, bool use_velocity, int hires_mul) -{ - int i, res[3]; - - for (i = 0; i < 3; i++) { - res[i] = em->max[i] - em->min[i]; - if (res[i] <= 0) { - return; - } - } - em->total_cells = res[0] * res[1] * res[2]; - copy_v3_v3_int(em->res, res); - - em->influence = MEM_callocN(sizeof(float) * em->total_cells, "smoke_flow_influence"); - if (use_velocity) { - em->velocity = MEM_callocN(sizeof(float) * em->total_cells * 3, "smoke_flow_velocity"); - } - - /* allocate high resolution map if required */ - if (hires_mul > 1) { - int total_cells_high = em->total_cells * (hires_mul * hires_mul * hires_mul); - - for (i = 0; i < 3; i++) { - em->hmin[i] = em->min[i] * hires_mul; - em->hmax[i] = em->max[i] * hires_mul; - em->hres[i] = em->res[i] * hires_mul; - } - - em->influence_high = MEM_callocN(sizeof(float) * total_cells_high, - "smoke_flow_influence_high"); - } - em->valid = 1; -} - -static void em_freeData(EmissionMap *em) -{ - if (em->influence) { - MEM_freeN(em->influence); - } - if (em->influence_high) { - MEM_freeN(em->influence_high); - } - if (em->velocity) { - MEM_freeN(em->velocity); - } -} - -static void em_combineMaps( - EmissionMap *output, EmissionMap *em2, int hires_multiplier, int additive, float sample_size) -{ - int i, x, y, z; - - /* copyfill input 1 struct and clear output for new allocation */ - EmissionMap em1; - memcpy(&em1, output, sizeof(EmissionMap)); - memset(output, 0, sizeof(EmissionMap)); - - for (i = 0; i < 3; i++) { - if (em1.valid) { - output->min[i] = MIN2(em1.min[i], em2->min[i]); - output->max[i] = MAX2(em1.max[i], em2->max[i]); - } - else { - output->min[i] = em2->min[i]; - output->max[i] = em2->max[i]; - } - } - /* allocate output map */ - em_allocateData(output, (em1.velocity || em2->velocity), hires_multiplier); - - /* base resolution inputs */ - for (x = output->min[0]; x < output->max[0]; x++) { - for (y = output->min[1]; y < output->max[1]; y++) { - for (z = output->min[2]; z < output->max[2]; z++) { - int index_out = smoke_get_index(x - output->min[0], - output->res[0], - y - output->min[1], - output->res[1], - z - output->min[2]); - - /* initialize with first input if in range */ - if (x >= em1.min[0] && x < em1.max[0] && y >= em1.min[1] && y < em1.max[1] && - z >= em1.min[2] && z < em1.max[2]) { - int index_in = smoke_get_index( - x - em1.min[0], em1.res[0], y - em1.min[1], em1.res[1], z - em1.min[2]); - - /* values */ - output->influence[index_out] = em1.influence[index_in]; - if (output->velocity && em1.velocity) { - copy_v3_v3(&output->velocity[index_out * 3], &em1.velocity[index_in * 3]); - } - } - - /* apply second input if in range */ - if (x >= em2->min[0] && x < em2->max[0] && y >= em2->min[1] && y < em2->max[1] && - z >= em2->min[2] && z < em2->max[2]) { - int index_in = smoke_get_index( - x - em2->min[0], em2->res[0], y - em2->min[1], em2->res[1], z - em2->min[2]); - - /* values */ - if (additive) { - output->influence[index_out] += em2->influence[index_in] * sample_size; - } - else { - output->influence[index_out] = MAX2(em2->influence[index_in], - output->influence[index_out]); - } - if (output->velocity && em2->velocity) { - /* last sample replaces the velocity */ - output->velocity[index_out * 3] = ADD_IF_LOWER(output->velocity[index_out * 3], - em2->velocity[index_in * 3]); - output->velocity[index_out * 3 + 1] = ADD_IF_LOWER(output->velocity[index_out * 3 + 1], - em2->velocity[index_in * 3 + 1]); - output->velocity[index_out * 3 + 2] = ADD_IF_LOWER(output->velocity[index_out * 3 + 2], - em2->velocity[index_in * 3 + 2]); - } - } - } // low res loop - } - } - - /* initialize high resolution input if available */ - if (output->influence_high) { - for (x = output->hmin[0]; x < output->hmax[0]; x++) { - for (y = output->hmin[1]; y < output->hmax[1]; y++) { - for (z = output->hmin[2]; z < output->hmax[2]; z++) { - int index_out = smoke_get_index(x - output->hmin[0], - output->hres[0], - y - output->hmin[1], - output->hres[1], - z - output->hmin[2]); - - /* initialize with first input if in range */ - if (x >= em1.hmin[0] && x < em1.hmax[0] && y >= em1.hmin[1] && y < em1.hmax[1] && - z >= em1.hmin[2] && z < em1.hmax[2]) { - int index_in = smoke_get_index( - x - em1.hmin[0], em1.hres[0], y - em1.hmin[1], em1.hres[1], z - em1.hmin[2]); - /* values */ - output->influence_high[index_out] = em1.influence_high[index_in]; - } - - /* apply second input if in range */ - if (x >= em2->hmin[0] && x < em2->hmax[0] && y >= em2->hmin[1] && y < em2->hmax[1] && - z >= em2->hmin[2] && z < em2->hmax[2]) { - int index_in = smoke_get_index( - x - em2->hmin[0], em2->hres[0], y - em2->hmin[1], em2->hres[1], z - em2->hmin[2]); - - /* values */ - if (additive) { - output->influence_high[index_out] += em2->influence_high[index_in] * sample_size; - } - else { - output->influence_high[index_out] = MAX2(em2->influence_high[index_in], - output->influence_high[index_out]); - } - } - } // high res loop - } - } - } - - /* free original data */ - em_freeData(&em1); -} - -typedef struct EmitFromParticlesData { - SmokeFlowSettings *sfs; - KDTree_3d *tree; - int hires_multiplier; - - EmissionMap *em; - float *particle_vel; - float hr; - - int *min, *max, *res; - - float solid; - float smooth; - float hr_smooth; -} EmitFromParticlesData; - -static void emit_from_particles_task_cb(void *__restrict userdata, - const int z, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - EmitFromParticlesData *data = userdata; - SmokeFlowSettings *sfs = data->sfs; - EmissionMap *em = data->em; - const int hires_multiplier = data->hires_multiplier; - - for (int x = data->min[0]; x < data->max[0]; x++) { - for (int y = data->min[1]; y < data->max[1]; y++) { - /* take low res samples where possible */ - if (hires_multiplier <= 1 || - !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { - /* get low res space coordinates */ - const int lx = x / hires_multiplier; - const int ly = y / hires_multiplier; - const int lz = z / hires_multiplier; - - const int index = smoke_get_index( - lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); - const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; - - /* find particle distance from the kdtree */ - KDTreeNearest_3d nearest; - const float range = data->solid + data->smooth; - BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); - - if (nearest.dist < range) { - em->influence[index] = (nearest.dist < data->solid) ? - 1.0f : - (1.0f - (nearest.dist - data->solid) / data->smooth); - /* Uses particle velocity as initial velocity for smoke */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && - (sfs->psys->part->phystype != PART_PHYS_NO)) { - madd_v3_v3fl( - &em->velocity[index * 3], &data->particle_vel[nearest.index * 3], sfs->vel_multi); - } - } - } - - /* take high res samples if required */ - if (hires_multiplier > 1) { - /* get low res space coordinates */ - const float lx = ((float)x) * data->hr; - const float ly = ((float)y) * data->hr; - const float lz = ((float)z) * data->hr; - - const int index = smoke_get_index( - x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); - const float ray_start[3] = { - lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr}; - - /* find particle distance from the kdtree */ - KDTreeNearest_3d nearest; - const float range = data->solid + data->hr_smooth; - BLI_kdtree_3d_find_nearest(data->tree, ray_start, &nearest); - - if (nearest.dist < range) { - em->influence_high[index] = (nearest.dist < data->solid) ? - 1.0f : - (1.0f - (nearest.dist - data->solid) / data->smooth); - } - } - } - } -} - -static void emit_from_particles(Object *flow_ob, - SmokeDomainSettings *sds, - SmokeFlowSettings *sfs, - EmissionMap *em, - Depsgraph *depsgraph, - Scene *scene, - float dt) -{ - /* Is particle system selected. */ - if (sfs && sfs->psys && sfs->psys->part && - ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) { - ParticleSimulationData sim; - ParticleSystem *psys = sfs->psys; - float *particle_pos; - float *particle_vel; - int totpart = psys->totpart, totchild; - int p = 0; - int valid_particles = 0; - int bounds_margin = 1; - - /* radius based flow */ - const float solid = sfs->particle_size * 0.5f; - const float smooth = 0.5f; /* add 0.5 cells of linear falloff to reduce aliasing */ - int hires_multiplier = 1; - KDTree_3d *tree = NULL; - - sim.depsgraph = depsgraph; - sim.scene = scene; - sim.ob = flow_ob; - sim.psys = psys; - sim.psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); - - /* prepare curvemapping tables */ - if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) { - BKE_curvemapping_changed_all(psys->part->clumpcurve); - } - if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) { - BKE_curvemapping_changed_all(psys->part->roughcurve); - } - if ((psys->part->child_flag & PART_CHILD_USE_TWIST_CURVE) && psys->part->twistcurve) { - BKE_curvemapping_changed_all(psys->part->twistcurve); - } - - /* initialize particle cache */ - if (psys->part->type == PART_HAIR) { - // TODO: PART_HAIR not supported whatsoever - totchild = 0; - } - else { - totchild = psys->totchild * psys->part->disp / 100; - } - - particle_pos = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles"); - particle_vel = MEM_callocN(sizeof(float) * (totpart + totchild) * 3, "smoke_flow_particles"); - - /* setup particle radius emission if enabled */ - if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { - tree = BLI_kdtree_3d_new(psys->totpart + psys->totchild); - - /* check need for high resolution map */ - if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { - hires_multiplier = sds->amplify + 1; - } - - bounds_margin = (int)ceil(solid + smooth); - } - - /* calculate local position for each particle */ - for (p = 0; p < totpart + totchild; p++) { - ParticleKey state; - float *pos; - if (p < totpart) { - if (psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) { - continue; - } - } - else { - /* handle child particle */ - ChildParticle *cpa = &psys->child[p - totpart]; - if (psys->particles[cpa->parent].flag & (PARS_NO_DISP | PARS_UNEXIST)) { - continue; - } - } - - /* DEG_get_ctime(depsgraph) does not give subframe time */ - state.time = BKE_scene_frame_get(scene); - if (psys_get_particle_state(&sim, p, &state, 0) == 0) { - continue; - } - - /* location */ - pos = &particle_pos[valid_particles * 3]; - copy_v3_v3(pos, state.co); - smoke_pos_to_cell(sds, pos); - - /* velocity */ - copy_v3_v3(&particle_vel[valid_particles * 3], state.vel); - mul_mat3_m4_v3(sds->imat, &particle_vel[valid_particles * 3]); - - if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { - BLI_kdtree_3d_insert(tree, valid_particles, pos); - } - - /* calculate emission map bounds */ - em_boundInsert(em, pos); - valid_particles++; - } - - /* set emission map */ - clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, bounds_margin, dt); - em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier); - - if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) { - for (p = 0; p < valid_particles; p++) { - int cell[3]; - size_t i = 0; - size_t index = 0; - int badcell = 0; - - /* 1. get corresponding cell */ - cell[0] = floor(particle_pos[p * 3]) - em->min[0]; - cell[1] = floor(particle_pos[p * 3 + 1]) - em->min[1]; - cell[2] = floor(particle_pos[p * 3 + 2]) - em->min[2]; - /* check if cell is valid (in the domain boundary) */ - for (i = 0; i < 3; i++) { - if ((cell[i] > em->res[i] - 1) || (cell[i] < 0)) { - badcell = 1; - break; - } - } - if (badcell) { - continue; - } - /* get cell index */ - index = smoke_get_index(cell[0], em->res[0], cell[1], em->res[1], cell[2]); - /* Add influence to emission map */ - em->influence[index] = 1.0f; - /* Uses particle velocity as initial velocity for smoke */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && (psys->part->phystype != PART_PHYS_NO)) { - madd_v3_v3fl(&em->velocity[index * 3], &particle_vel[p * 3], sfs->vel_multi); - } - } // particles loop - } - else if (valid_particles > 0) { // MOD_SMOKE_FLOW_USE_PART_SIZE - int min[3], max[3], res[3]; - const float hr = 1.0f / ((float)hires_multiplier); - /* slightly adjust high res antialias smoothness based on number of divisions - * to allow smaller details but yet not differing too much from the low res size */ - const float hr_smooth = smooth * powf(hr, 1.0f / 3.0f); - - /* setup loop bounds */ - for (int i = 0; i < 3; i++) { - min[i] = em->min[i] * hires_multiplier; - max[i] = em->max[i] * hires_multiplier; - res[i] = em->res[i] * hires_multiplier; - } - - BLI_kdtree_3d_balance(tree); - - EmitFromParticlesData data = { - .sfs = sfs, - .tree = tree, - .hires_multiplier = hires_multiplier, - .hr = hr, - .em = em, - .particle_vel = particle_vel, - .min = min, - .max = max, - .res = res, - .solid = solid, - .smooth = smooth, - .hr_smooth = hr_smooth, - }; - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; - BLI_task_parallel_range(min[2], max[2], &data, emit_from_particles_task_cb, &settings); - } - - if (sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE) { - BLI_kdtree_3d_free(tree); - } - - /* free data */ - if (particle_pos) { - MEM_freeN(particle_pos); - } - if (particle_vel) { - MEM_freeN(particle_vel); - } - } -} - -static void sample_mesh(SmokeFlowSettings *sfs, - const MVert *mvert, - const MLoop *mloop, - const MLoopTri *mlooptri, - const MLoopUV *mloopuv, - float *influence_map, - float *velocity_map, - int index, - const int base_res[3], - float flow_center[3], - BVHTreeFromMesh *treeData, - const float ray_start[3], - const float *vert_vel, - bool has_velocity, - int defgrp_index, - MDeformVert *dvert, - float x, - float y, - float z) -{ - float ray_dir[3] = {1.0f, 0.0f, 0.0f}; - BVHTreeRayHit hit = {0}; - BVHTreeNearest nearest = {0}; - - float volume_factor = 0.0f; - float sample_str = 0.0f; - - hit.index = -1; - hit.dist = 9999; - nearest.index = -1; - nearest.dist_sq = sfs->surface_distance * - sfs->surface_distance; /* find_nearest uses squared distance */ - - /* Check volume collision */ - if (sfs->volume_density) { - if (BLI_bvhtree_ray_cast(treeData->tree, - ray_start, - ray_dir, - 0.0f, - &hit, - treeData->raycast_callback, - treeData) != -1) { - float dot = ray_dir[0] * hit.no[0] + ray_dir[1] * hit.no[1] + ray_dir[2] * hit.no[2]; - /* If ray and hit face normal are facing same direction - * hit point is inside a closed mesh. */ - if (dot >= 0) { - /* Also cast a ray in opposite direction to make sure - * point is at least surrounded by two faces */ - negate_v3(ray_dir); - hit.index = -1; - hit.dist = 9999; - - BLI_bvhtree_ray_cast( - treeData->tree, ray_start, ray_dir, 0.0f, &hit, treeData->raycast_callback, treeData); - if (hit.index != -1) { - volume_factor = sfs->volume_density; - } - } - } - } - - /* find the nearest point on the mesh */ - if (BLI_bvhtree_find_nearest( - treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) { - float weights[3]; - int v1, v2, v3, f_index = nearest.index; - float n1[3], n2[3], n3[3], hit_normal[3]; - - /* emit from surface based on distance */ - if (sfs->surface_distance) { - sample_str = sqrtf(nearest.dist_sq) / sfs->surface_distance; - CLAMP(sample_str, 0.0f, 1.0f); - sample_str = pow(1.0f - sample_str, 0.5f); - } - else { - sample_str = 0.0f; - } - - /* calculate barycentric weights for nearest point */ - v1 = mloop[mlooptri[f_index].tri[0]].v; - v2 = mloop[mlooptri[f_index].tri[1]].v; - v3 = mloop[mlooptri[f_index].tri[2]].v; - interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co); - - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) { - /* apply normal directional velocity */ - if (sfs->vel_normal) { - /* interpolate vertex normal vectors to get nearest point normal */ - normal_short_to_float_v3(n1, mvert[v1].no); - normal_short_to_float_v3(n2, mvert[v2].no); - normal_short_to_float_v3(n3, mvert[v3].no); - interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights); - normalize_v3(hit_normal); - /* apply normal directional and random velocity - * - TODO: random disabled for now since it doesn't really work well - * as pressure calc smoothens it out. */ - velocity_map[index * 3] += hit_normal[0] * sfs->vel_normal * 0.25f; - velocity_map[index * 3 + 1] += hit_normal[1] * sfs->vel_normal * 0.25f; - velocity_map[index * 3 + 2] += hit_normal[2] * sfs->vel_normal * 0.25f; - /* TODO: for fire emitted from mesh surface we can use - * Vf = Vs + (Ps/Pf - 1)*S to model gaseous expansion from solid to fuel */ - } - /* apply object velocity */ - if (has_velocity && sfs->vel_multi) { - float hit_vel[3]; - interp_v3_v3v3v3( - hit_vel, &vert_vel[v1 * 3], &vert_vel[v2 * 3], &vert_vel[v3 * 3], weights); - velocity_map[index * 3] += hit_vel[0] * sfs->vel_multi; - velocity_map[index * 3 + 1] += hit_vel[1] * sfs->vel_multi; - velocity_map[index * 3 + 2] += hit_vel[2] * sfs->vel_multi; - } - } - - /* apply vertex group influence if used */ - if (defgrp_index != -1 && dvert) { - float weight_mask = defvert_find_weight(&dvert[v1], defgrp_index) * weights[0] + - defvert_find_weight(&dvert[v2], defgrp_index) * weights[1] + - defvert_find_weight(&dvert[v3], defgrp_index) * weights[2]; - sample_str *= weight_mask; - } - - /* apply emission texture */ - if ((sfs->flags & MOD_SMOKE_FLOW_TEXTUREEMIT) && sfs->noise_texture) { - float tex_co[3] = {0}; - TexResult texres; - - if (sfs->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO) { - tex_co[0] = ((x - flow_center[0]) / base_res[0]) / sfs->texture_size; - tex_co[1] = ((y - flow_center[1]) / base_res[1]) / sfs->texture_size; - tex_co[2] = ((z - flow_center[2]) / base_res[2] - sfs->texture_offset) / sfs->texture_size; - } - else if (mloopuv) { - const float *uv[3]; - uv[0] = mloopuv[mlooptri[f_index].tri[0]].uv; - uv[1] = mloopuv[mlooptri[f_index].tri[1]].uv; - uv[2] = mloopuv[mlooptri[f_index].tri[2]].uv; - - interp_v2_v2v2v2(tex_co, UNPACK3(uv), weights); - - /* map between -1.0f and 1.0f */ - tex_co[0] = tex_co[0] * 2.0f - 1.0f; - tex_co[1] = tex_co[1] * 2.0f - 1.0f; - tex_co[2] = sfs->texture_offset; - } - texres.nor = NULL; - BKE_texture_get_value(NULL, sfs->noise_texture, tex_co, &texres, false); - sample_str *= texres.tin; - } - } - - /* multiply initial velocity by emitter influence */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) { - mul_v3_fl(&velocity_map[index * 3], sample_str); - } - - /* apply final influence based on volume factor */ - influence_map[index] = MAX2(volume_factor, sample_str); -} - -typedef struct EmitFromDMData { - SmokeDomainSettings *sds; - SmokeFlowSettings *sfs; - const MVert *mvert; - const MLoop *mloop; - const MLoopTri *mlooptri; - const MLoopUV *mloopuv; - MDeformVert *dvert; - int defgrp_index; - - BVHTreeFromMesh *tree; - int hires_multiplier; - float hr; - - EmissionMap *em; - bool has_velocity; - float *vert_vel; - - float *flow_center; - int *min, *max, *res; -} EmitFromDMData; - -static void emit_from_mesh_task_cb(void *__restrict userdata, - const int z, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - EmitFromDMData *data = userdata; - EmissionMap *em = data->em; - const int hires_multiplier = data->hires_multiplier; - - for (int x = data->min[0]; x < data->max[0]; x++) { - for (int y = data->min[1]; y < data->max[1]; y++) { - /* take low res samples where possible */ - if (hires_multiplier <= 1 || - !(x % hires_multiplier || y % hires_multiplier || z % hires_multiplier)) { - /* get low res space coordinates */ - const int lx = x / hires_multiplier; - const int ly = y / hires_multiplier; - const int lz = z / hires_multiplier; - - const int index = smoke_get_index( - lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]); - const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f}; - - sample_mesh(data->sfs, - data->mvert, - data->mloop, - data->mlooptri, - data->mloopuv, - em->influence, - em->velocity, - index, - data->sds->base_res, - data->flow_center, - data->tree, - ray_start, - data->vert_vel, - data->has_velocity, - data->defgrp_index, - data->dvert, - (float)lx, - (float)ly, - (float)lz); - } - - /* take high res samples if required */ - if (hires_multiplier > 1) { - /* get low res space coordinates */ - const float lx = ((float)x) * data->hr; - const float ly = ((float)y) * data->hr; - const float lz = ((float)z) * data->hr; - - const int index = smoke_get_index( - x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]); - const float ray_start[3] = { - lx + 0.5f * data->hr, - ly + 0.5f * data->hr, - lz + 0.5f * data->hr, - }; - - sample_mesh(data->sfs, - data->mvert, - data->mloop, - data->mlooptri, - data->mloopuv, - em->influence_high, - NULL, - index, - data->sds->base_res, - data->flow_center, - data->tree, - ray_start, - data->vert_vel, - data->has_velocity, - data->defgrp_index, - data->dvert, - /* x,y,z needs to be always lowres */ - lx, - ly, - lz); - } - } - } -} - -static void emit_from_mesh( - Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt) -{ - if (sfs->mesh) { - Mesh *me; - int defgrp_index = sfs->vgroup_density - 1; - MDeformVert *dvert = NULL; - MVert *mvert = NULL; - const MLoopTri *mlooptri = NULL; - const MLoopUV *mloopuv = NULL; - const MLoop *mloop = NULL; - BVHTreeFromMesh treeData = {NULL}; - int numOfVerts, i; - float flow_center[3] = {0}; - - float *vert_vel = NULL; - int has_velocity = 0; - int min[3], max[3], res[3]; - int hires_multiplier = 1; - - /* copy mesh for thread safety because we modify it, - * main issue is its VertArray being modified, then replaced and freed - */ - me = BKE_mesh_copy_for_eval(sfs->mesh, true); - - /* Duplicate vertices to modify. */ - if (me->mvert) { - me->mvert = MEM_dupallocN(me->mvert); - CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert); - } - - BKE_mesh_ensure_normals(me); - mvert = me->mvert; - numOfVerts = me->totvert; - dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); - mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name); - mloop = me->mloop; - mlooptri = BKE_mesh_runtime_looptri_ensure(me); - - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { - vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity"); - - if (sfs->numverts != numOfVerts || !sfs->verts_old) { - if (sfs->verts_old) { - MEM_freeN(sfs->verts_old); - } - sfs->verts_old = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_verts_old"); - sfs->numverts = numOfVerts; - } - else { - has_velocity = 1; - } - } - - /* Transform mesh vertices to - * domain grid space for fast lookups */ - for (i = 0; i < numOfVerts; i++) { - float n[3]; - /* vert pos */ - mul_m4_v3(flow_ob->obmat, mvert[i].co); - smoke_pos_to_cell(sds, mvert[i].co); - /* vert normal */ - normal_short_to_float_v3(n, mvert[i].no); - mul_mat3_m4_v3(flow_ob->obmat, n); - mul_mat3_m4_v3(sds->imat, n); - normalize_v3(n); - normal_float_to_short_v3(mvert[i].no, n); - /* vert velocity */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { - float co[3]; - add_v3fl_v3fl_v3i(co, mvert[i].co, sds->shift); - if (has_velocity) { - sub_v3_v3v3(&vert_vel[i * 3], co, &sfs->verts_old[i * 3]); - mul_v3_fl(&vert_vel[i * 3], sds->dx / dt); - } - copy_v3_v3(&sfs->verts_old[i * 3], co); - } - - /* calculate emission map bounds */ - em_boundInsert(em, mvert[i].co); - } - mul_m4_v3(flow_ob->obmat, flow_center); - smoke_pos_to_cell(sds, flow_center); - - /* check need for high resolution map */ - if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { - hires_multiplier = sds->amplify + 1; - } - - /* set emission map */ - clampBoundsInDomain(sds, em->min, em->max, NULL, NULL, (int)ceil(sfs->surface_distance), dt); - em_allocateData(em, sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY, hires_multiplier); - - /* setup loop bounds */ - for (i = 0; i < 3; i++) { - min[i] = em->min[i] * hires_multiplier; - max[i] = em->max[i] * hires_multiplier; - res[i] = em->res[i] * hires_multiplier; - } - - if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) { - const float hr = 1.0f / ((float)hires_multiplier); - - EmitFromDMData data = { - .sds = sds, - .sfs = sfs, - .mvert = mvert, - .mloop = mloop, - .mlooptri = mlooptri, - .mloopuv = mloopuv, - .dvert = dvert, - .defgrp_index = defgrp_index, - .tree = &treeData, - .hires_multiplier = hires_multiplier, - .hr = hr, - .em = em, - .has_velocity = has_velocity, - .vert_vel = vert_vel, - .flow_center = flow_center, - .min = min, - .max = max, - .res = res, - }; - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; - BLI_task_parallel_range(min[2], max[2], &data, emit_from_mesh_task_cb, &settings); - } - /* free bvh tree */ - free_bvhtree_from_mesh(&treeData); - - if (vert_vel) { - MEM_freeN(vert_vel); - } - - if (me->mvert) { - MEM_freeN(me->mvert); - } - BKE_id_free(NULL, me); - } -} - -/********************************************************** - * Smoke step - **********************************************************/ - -static void adjustDomainResolution(SmokeDomainSettings *sds, - int new_shift[3], - EmissionMap *emaps, - unsigned int numflowobj, - float dt) -{ - const int block_size = sds->amplify + 1; - int min[3] = {32767, 32767, 32767}, max[3] = {-32767, -32767, -32767}, res[3]; - int total_cells = 1, res_changed = 0, shift_changed = 0; - float min_vel[3], max_vel[3]; - int x, y, z; - float *density = smoke_get_density(sds->fluid); - float *fuel = smoke_get_fuel(sds->fluid); - float *bigdensity = smoke_turbulence_get_density(sds->wt); - float *bigfuel = smoke_turbulence_get_fuel(sds->wt); - float *vx = smoke_get_velocity_x(sds->fluid); - float *vy = smoke_get_velocity_y(sds->fluid); - float *vz = smoke_get_velocity_z(sds->fluid); - int wt_res[3]; - - if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { - smoke_turbulence_get_res(sds->wt, wt_res); - } - - INIT_MINMAX(min_vel, max_vel); - - /* Calculate bounds for current domain content */ - for (x = sds->res_min[0]; x < sds->res_max[0]; x++) { - for (y = sds->res_min[1]; y < sds->res_max[1]; y++) { - for (z = sds->res_min[2]; z < sds->res_max[2]; z++) { - int xn = x - new_shift[0]; - int yn = y - new_shift[1]; - int zn = z - new_shift[2]; - int index; - float max_den; - - /* skip if cell already belongs to new area */ - if (xn >= min[0] && xn <= max[0] && yn >= min[1] && yn <= max[1] && zn >= min[2] && - zn <= max[2]) { - continue; - } - - index = smoke_get_index(x - sds->res_min[0], - sds->res[0], - y - sds->res_min[1], - sds->res[1], - z - sds->res_min[2]); - max_den = (fuel) ? MAX2(density[index], fuel[index]) : density[index]; - - /* check high resolution bounds if max density isnt already high enough */ - if (max_den < sds->adapt_threshold && sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { - int i, j, k; - /* high res grid index */ - int xx = (x - sds->res_min[0]) * block_size; - int yy = (y - sds->res_min[1]) * block_size; - int zz = (z - sds->res_min[2]) * block_size; - - for (i = 0; i < block_size; i++) { - for (j = 0; j < block_size; j++) { - for (k = 0; k < block_size; k++) { - int big_index = smoke_get_index(xx + i, wt_res[0], yy + j, wt_res[1], zz + k); - float den = (bigfuel) ? MAX2(bigdensity[big_index], bigfuel[big_index]) : - bigdensity[big_index]; - if (den > max_den) { - max_den = den; - } - } - } - } - } - - /* content bounds (use shifted coordinates) */ - if (max_den >= sds->adapt_threshold) { - if (min[0] > xn) { - min[0] = xn; - } - if (min[1] > yn) { - min[1] = yn; - } - if (min[2] > zn) { - min[2] = zn; - } - if (max[0] < xn) { - max[0] = xn; - } - if (max[1] < yn) { - max[1] = yn; - } - if (max[2] < zn) { - max[2] = zn; - } - } - - /* velocity bounds */ - if (min_vel[0] > vx[index]) { - min_vel[0] = vx[index]; - } - if (min_vel[1] > vy[index]) { - min_vel[1] = vy[index]; - } - if (min_vel[2] > vz[index]) { - min_vel[2] = vz[index]; - } - if (max_vel[0] < vx[index]) { - max_vel[0] = vx[index]; - } - if (max_vel[1] < vy[index]) { - max_vel[1] = vy[index]; - } - if (max_vel[2] < vz[index]) { - max_vel[2] = vz[index]; - } - } - } - } - - /* also apply emission maps */ - for (int i = 0; i < numflowobj; i++) { - EmissionMap *em = &emaps[i]; - - for (x = em->min[0]; x < em->max[0]; x++) { - for (y = em->min[1]; y < em->max[1]; y++) { - for (z = em->min[2]; z < em->max[2]; z++) { - int index = smoke_get_index( - x - em->min[0], em->res[0], y - em->min[1], em->res[1], z - em->min[2]); - float max_den = em->influence[index]; - - /* density bounds */ - if (max_den >= sds->adapt_threshold) { - if (min[0] > x) { - min[0] = x; - } - if (min[1] > y) { - min[1] = y; - } - if (min[2] > z) { - min[2] = z; - } - if (max[0] < x) { - max[0] = x; - } - if (max[1] < y) { - max[1] = y; - } - if (max[2] < z) { - max[2] = z; - } - } - } - } - } - } - - /* calculate new bounds based on these values */ - mul_v3_fl(min_vel, 1.0f / sds->dx); - mul_v3_fl(max_vel, 1.0f / sds->dx); - clampBoundsInDomain(sds, min, max, min_vel, max_vel, sds->adapt_margin + 1, dt); - - for (int i = 0; i < 3; i++) { - /* calculate new resolution */ - res[i] = max[i] - min[i]; - total_cells *= res[i]; - - if (new_shift[i]) { - shift_changed = 1; - } - - /* if no content set minimum dimensions */ - if (res[i] <= 0) { - int j; - for (j = 0; j < 3; j++) { - min[j] = 0; - max[j] = 1; - res[j] = 1; - } - res_changed = 1; - total_cells = 1; - break; - } - if (min[i] != sds->res_min[i] || max[i] != sds->res_max[i]) { - res_changed = 1; - } - } - - if (res_changed || shift_changed) { - struct FLUID_3D *fluid_old = sds->fluid; - struct WTURBULENCE *turb_old = sds->wt; - /* allocate new fluid data */ - BKE_smoke_reallocate_fluid(sds, sds->dx, res, 0); - if (sds->flags & MOD_SMOKE_HIGHRES) { - BKE_smoke_reallocate_highres_fluid(sds, sds->dx, res, 0); - } - - /* copy values from old fluid to new */ - if (sds->total_cells > 1 && total_cells > 1) { - /* low res smoke */ - float *o_dens, *o_react, *o_flame, *o_fuel, *o_heat, *o_heatold, *o_vx, *o_vy, *o_vz, *o_r, - *o_g, *o_b; - float *n_dens, *n_react, *n_flame, *n_fuel, *n_heat, *n_heatold, *n_vx, *n_vy, *n_vz, *n_r, - *n_g, *n_b; - float dummy; - unsigned char *dummy_p; - /* high res smoke */ - int wt_res_old[3]; - float *o_wt_dens, *o_wt_react, *o_wt_flame, *o_wt_fuel, *o_wt_tcu, *o_wt_tcv, *o_wt_tcw, - *o_wt_r, *o_wt_g, *o_wt_b; - float *n_wt_dens, *n_wt_react, *n_wt_flame, *n_wt_fuel, *n_wt_tcu, *n_wt_tcv, *n_wt_tcw, - *n_wt_r, *n_wt_g, *n_wt_b; - - smoke_export(fluid_old, - &dummy, - &dummy, - &o_dens, - &o_react, - &o_flame, - &o_fuel, - &o_heat, - &o_heatold, - &o_vx, - &o_vy, - &o_vz, - &o_r, - &o_g, - &o_b, - &dummy_p); - smoke_export(sds->fluid, - &dummy, - &dummy, - &n_dens, - &n_react, - &n_flame, - &n_fuel, - &n_heat, - &n_heatold, - &n_vx, - &n_vy, - &n_vz, - &n_r, - &n_g, - &n_b, - &dummy_p); - - if (sds->flags & MOD_SMOKE_HIGHRES) { - smoke_turbulence_export(turb_old, - &o_wt_dens, - &o_wt_react, - &o_wt_flame, - &o_wt_fuel, - &o_wt_r, - &o_wt_g, - &o_wt_b, - &o_wt_tcu, - &o_wt_tcv, - &o_wt_tcw); - smoke_turbulence_get_res(turb_old, wt_res_old); - smoke_turbulence_export(sds->wt, - &n_wt_dens, - &n_wt_react, - &n_wt_flame, - &n_wt_fuel, - &n_wt_r, - &n_wt_g, - &n_wt_b, - &n_wt_tcu, - &n_wt_tcv, - &n_wt_tcw); - } - - for (x = sds->res_min[0]; x < sds->res_max[0]; x++) { - for (y = sds->res_min[1]; y < sds->res_max[1]; y++) { - for (z = sds->res_min[2]; z < sds->res_max[2]; z++) { - /* old grid index */ - int xo = x - sds->res_min[0]; - int yo = y - sds->res_min[1]; - int zo = z - sds->res_min[2]; - int index_old = smoke_get_index(xo, sds->res[0], yo, sds->res[1], zo); - /* new grid index */ - int xn = x - min[0] - new_shift[0]; - int yn = y - min[1] - new_shift[1]; - int zn = z - min[2] - new_shift[2]; - int index_new = smoke_get_index(xn, res[0], yn, res[1], zn); - - /* skip if outside new domain */ - if (xn < 0 || xn >= res[0] || yn < 0 || yn >= res[1] || zn < 0 || zn >= res[2]) { - continue; - } - - /* copy data */ - n_dens[index_new] = o_dens[index_old]; - /* heat */ - if (n_heat && o_heat) { - n_heat[index_new] = o_heat[index_old]; - n_heatold[index_new] = o_heatold[index_old]; - } - /* fuel */ - if (n_fuel && o_fuel) { - n_flame[index_new] = o_flame[index_old]; - n_fuel[index_new] = o_fuel[index_old]; - n_react[index_new] = o_react[index_old]; - } - /* color */ - if (o_r && n_r) { - n_r[index_new] = o_r[index_old]; - n_g[index_new] = o_g[index_old]; - n_b[index_new] = o_b[index_old]; - } - n_vx[index_new] = o_vx[index_old]; - n_vy[index_new] = o_vy[index_old]; - n_vz[index_new] = o_vz[index_old]; - - if (sds->flags & MOD_SMOKE_HIGHRES && turb_old) { - int i, j, k; - /* old grid index */ - int xx_o = xo * block_size; - int yy_o = yo * block_size; - int zz_o = zo * block_size; - /* new grid index */ - int xx_n = xn * block_size; - int yy_n = yn * block_size; - int zz_n = zn * block_size; - - n_wt_tcu[index_new] = o_wt_tcu[index_old]; - n_wt_tcv[index_new] = o_wt_tcv[index_old]; - n_wt_tcw[index_new] = o_wt_tcw[index_old]; - - for (i = 0; i < block_size; i++) { - for (j = 0; j < block_size; j++) { - for (k = 0; k < block_size; k++) { - int big_index_old = smoke_get_index( - xx_o + i, wt_res_old[0], yy_o + j, wt_res_old[1], zz_o + k); - int big_index_new = smoke_get_index( - xx_n + i, sds->res_wt[0], yy_n + j, sds->res_wt[1], zz_n + k); - /* copy data */ - n_wt_dens[big_index_new] = o_wt_dens[big_index_old]; - if (n_wt_flame && o_wt_flame) { - n_wt_flame[big_index_new] = o_wt_flame[big_index_old]; - n_wt_fuel[big_index_new] = o_wt_fuel[big_index_old]; - n_wt_react[big_index_new] = o_wt_react[big_index_old]; - } - if (n_wt_r && o_wt_r) { - n_wt_r[big_index_new] = o_wt_r[big_index_old]; - n_wt_g[big_index_new] = o_wt_g[big_index_old]; - n_wt_b[big_index_new] = o_wt_b[big_index_old]; - } - } - } - } - } - } - } - } - } - smoke_free(fluid_old); - if (turb_old) { - smoke_turbulence_free(turb_old); - } - - /* set new domain dimensions */ - copy_v3_v3_int(sds->res_min, min); - copy_v3_v3_int(sds->res_max, max); - copy_v3_v3_int(sds->res, res); - sds->total_cells = total_cells; - } -} - -BLI_INLINE void apply_outflow_fields(int index, - float *density, - float *heat, - float *fuel, - float *react, - float *color_r, - float *color_g, - float *color_b) -{ - density[index] = 0.f; - if (heat) { - heat[index] = 0.f; - } - if (fuel) { - fuel[index] = 0.f; - react[index] = 0.f; - } - if (color_r) { - color_r[index] = 0.f; - color_g[index] = 0.f; - color_b[index] = 0.f; - } -} - -BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, - float emission_value, - int index, - float *density, - float *heat, - float *fuel, - float *react, - float *color_r, - float *color_g, - float *color_b) -{ - int absolute_flow = (sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE); - float dens_old = density[index]; - // float fuel_old = (fuel) ? fuel[index] : 0.0f; /* UNUSED */ - float dens_flow = (sfs->type == MOD_SMOKE_FLOW_TYPE_FIRE) ? 0.0f : emission_value * sfs->density; - float fuel_flow = emission_value * sfs->fuel_amount; - /* add heat */ - if (heat && emission_value > 0.0f) { - heat[index] = ADD_IF_LOWER(heat[index], sfs->temp); - } - /* absolute */ - if (absolute_flow) { - if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) { - if (dens_flow > density[index]) { - density[index] = dens_flow; - } - } - if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && fuel_flow) { - if (fuel_flow > fuel[index]) { - fuel[index] = fuel_flow; - } - } - } - /* additive */ - else { - if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE) { - density[index] += dens_flow; - CLAMP(density[index], 0.0f, 1.0f); - } - if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && fuel && sfs->fuel_amount) { - fuel[index] += fuel_flow; - CLAMP(fuel[index], 0.0f, 10.0f); - } - } - - /* set color */ - if (color_r && dens_flow) { - float total_dens = density[index] / (dens_old + dens_flow); - color_r[index] = (color_r[index] + sfs->color[0] * dens_flow) * total_dens; - color_g[index] = (color_g[index] + sfs->color[1] * dens_flow) * total_dens; - color_b[index] = (color_b[index] + sfs->color[2] * dens_flow) * total_dens; - } - - /* set fire reaction coordinate */ - if (fuel && fuel[index] > FLT_EPSILON) { - /* instead of using 1.0 for all new fuel add slight falloff - * to reduce flow blockiness */ - float value = 1.0f - pow2f(1.0f - emission_value); - - if (value > react[index]) { - float f = fuel_flow / fuel[index]; - react[index] = value * f + (1.0f - f) * react[index]; - CLAMP(react[index], 0.0f, value); - } - } -} - -static void update_flowsfluids( - Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt) -{ - Object **flowobjs = NULL; - EmissionMap *emaps = NULL; - unsigned int numflowobj = 0; - unsigned int flowIndex; - int new_shift[3] = {0}; - int active_fields = sds->active_fields; - - /* calculate domain shift for current frame if using adaptive domain */ - if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - int total_shift[3]; - float frame_shift_f[3]; - float ob_loc[3] = {0}; - - mul_m4_v3(ob->obmat, ob_loc); - - sub_v3_v3v3(frame_shift_f, ob_loc, sds->prev_loc); - copy_v3_v3(sds->prev_loc, ob_loc); - /* convert global space shift to local "cell" space */ - mul_mat3_m4_v3(sds->imat, frame_shift_f); - frame_shift_f[0] = frame_shift_f[0] / sds->cell_size[0]; - frame_shift_f[1] = frame_shift_f[1] / sds->cell_size[1]; - frame_shift_f[2] = frame_shift_f[2] / sds->cell_size[2]; - /* add to total shift */ - add_v3_v3(sds->shift_f, frame_shift_f); - /* convert to integer */ - total_shift[0] = (int)(floorf(sds->shift_f[0])); - total_shift[1] = (int)(floorf(sds->shift_f[1])); - total_shift[2] = (int)(floorf(sds->shift_f[2])); - sub_v3_v3v3_int(new_shift, total_shift, sds->shift); - copy_v3_v3_int(sds->shift, total_shift); - - /* calculate new domain boundary points so that smoke doesn't slide on sub-cell movement */ - sds->p0[0] = sds->dp0[0] - sds->cell_size[0] * (sds->shift_f[0] - total_shift[0] - 0.5f); - sds->p0[1] = sds->dp0[1] - sds->cell_size[1] * (sds->shift_f[1] - total_shift[1] - 0.5f); - sds->p0[2] = sds->dp0[2] - sds->cell_size[2] * (sds->shift_f[2] - total_shift[2] - 0.5f); - sds->p1[0] = sds->p0[0] + sds->cell_size[0] * sds->base_res[0]; - sds->p1[1] = sds->p0[1] + sds->cell_size[1] * sds->base_res[1]; - sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2]; - } - - flowobjs = BKE_collision_objects_create( - depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke); - - /* init emission maps for each flow */ - emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps"); - - /* Prepare flow emission maps */ - for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) { - Object *collob = flowobjs[flowIndex]; - SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, - eModifierType_Smoke); - - // check for initialized smoke object - if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) { - // we got nice flow object - SmokeFlowSettings *sfs = smd2->flow; - int subframes = sfs->subframes; - EmissionMap *em = &emaps[flowIndex]; - - /* just sample flow directly to emission map if no subframes */ - if (!subframes) { - if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { - emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt); - } - else { - emit_from_mesh(collob, sds, sfs, em, dt); - } - } - /* sample subframes */ - else { - int scene_frame = (int)DEG_get_ctime(depsgraph); - // float scene_subframe = scene->r.subframe; // UNUSED - int subframe; - for (subframe = 0; subframe <= subframes; subframe++) { - EmissionMap em_temp = {NULL}; - float sample_size = 1.0f / (float)(subframes + 1); - float prev_frame_pos = sample_size * (float)(subframe + 1); - float sdt = dt * sample_size; - int hires_multiplier = 1; - - if ((sds->flags & MOD_SMOKE_HIGHRES) && (sds->highres_sampling == SM_HRES_FULLSAMPLE)) { - hires_multiplier = sds->amplify + 1; - } - - /* set scene frame to match previous frame + subframe - * or use current frame for last sample */ - if (subframe < subframes) { - scene->r.cfra = scene_frame - 1; - scene->r.subframe = prev_frame_pos; - } - else { - scene->r.cfra = scene_frame; - scene->r.subframe = 0.0f; - } - - /* update flow object frame */ - BLI_mutex_lock(&object_update_lock); - BKE_object_modifier_update_subframe( - depsgraph, scene, collob, true, 5, BKE_scene_frame_get(scene), eModifierType_Smoke); - BLI_mutex_unlock(&object_update_lock); - - if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) { - /* emit_from_particles() updates timestep internally */ - emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt); - if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) { - hires_multiplier = 1; - } - } - else { /* MOD_SMOKE_FLOW_SOURCE_MESH */ - /* apply flow */ - emit_from_mesh(collob, sds, sfs, &em_temp, sdt); - } - - /* combine emission maps */ - em_combineMaps(em, - &em_temp, - hires_multiplier, - !(sfs->flags & MOD_SMOKE_FLOW_ABSOLUTE), - sample_size); - em_freeData(&em_temp); - } - } - - /* update required data fields */ - if (em->total_cells && sfs->type != MOD_SMOKE_FLOW_TYPE_OUTFLOW) { - /* activate heat field if flow produces any heat */ - if (sfs->temp) { - active_fields |= SM_ACTIVE_HEAT; - } - /* activate fuel field if flow adds any fuel */ - if (sfs->type != MOD_SMOKE_FLOW_TYPE_SMOKE && sfs->fuel_amount) { - active_fields |= SM_ACTIVE_FIRE; - } - /* activate color field if flows add smoke with varying colors */ - if (sfs->type != MOD_SMOKE_FLOW_TYPE_FIRE && sfs->density) { - if (!(active_fields & SM_ACTIVE_COLOR_SET)) { - copy_v3_v3(sds->active_color, sfs->color); - active_fields |= SM_ACTIVE_COLOR_SET; - } - else if (!equals_v3v3(sds->active_color, sfs->color)) { - copy_v3_v3(sds->active_color, sfs->color); - active_fields |= SM_ACTIVE_COLORS; - } - } - } - } - } - - /* monitor active fields based on domain settings */ - /* if domain has fire, activate new fields if required */ - if (active_fields & SM_ACTIVE_FIRE) { - /* heat is always needed for fire */ - active_fields |= SM_ACTIVE_HEAT; - /* also activate colors if domain smoke color differs from active color */ - if (!(active_fields & SM_ACTIVE_COLOR_SET)) { - copy_v3_v3(sds->active_color, sds->flame_smoke_color); - active_fields |= SM_ACTIVE_COLOR_SET; - } - else if (!equals_v3v3(sds->active_color, sds->flame_smoke_color)) { - copy_v3_v3(sds->active_color, sds->flame_smoke_color); - active_fields |= SM_ACTIVE_COLORS; - } - } - - /* Adjust domain size if needed */ - if (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - adjustDomainResolution(sds, new_shift, emaps, numflowobj, dt); - } - - /* Initialize new data fields if any */ - if (active_fields & SM_ACTIVE_HEAT) { - smoke_ensure_heat(sds->fluid); - } - if (active_fields & SM_ACTIVE_FIRE) { - smoke_ensure_fire(sds->fluid, sds->wt); - } - if (active_fields & SM_ACTIVE_COLORS) { - /* initialize all smoke with "active_color" */ - smoke_ensure_colors( - sds->fluid, sds->wt, sds->active_color[0], sds->active_color[1], sds->active_color[2]); - } - sds->active_fields = active_fields; - - /* Apply emission data */ - if (sds->fluid) { - for (flowIndex = 0; flowIndex < numflowobj; flowIndex++) { - Object *collob = flowobjs[flowIndex]; - SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(collob, - eModifierType_Smoke); - - // check for initialized smoke object - if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) { - // we got nice flow object - SmokeFlowSettings *sfs = smd2->flow; - EmissionMap *em = &emaps[flowIndex]; - - float *density = smoke_get_density(sds->fluid); - float *color_r = smoke_get_color_r(sds->fluid); - float *color_g = smoke_get_color_g(sds->fluid); - float *color_b = smoke_get_color_b(sds->fluid); - float *fuel = smoke_get_fuel(sds->fluid); - float *react = smoke_get_react(sds->fluid); - float *bigdensity = smoke_turbulence_get_density(sds->wt); - float *bigfuel = smoke_turbulence_get_fuel(sds->wt); - float *bigreact = smoke_turbulence_get_react(sds->wt); - float *bigcolor_r = smoke_turbulence_get_color_r(sds->wt); - float *bigcolor_g = smoke_turbulence_get_color_g(sds->wt); - float *bigcolor_b = smoke_turbulence_get_color_b(sds->wt); - float *heat = smoke_get_heat(sds->fluid); - float *velocity_x = smoke_get_velocity_x(sds->fluid); - float *velocity_y = smoke_get_velocity_y(sds->fluid); - float *velocity_z = smoke_get_velocity_z(sds->fluid); - // unsigned char *obstacle = smoke_get_obstacle(sds->fluid); - // DG TODO UNUSED unsigned char *obstacleAnim = smoke_get_obstacle_anim(sds->fluid); - int bigres[3]; - float *velocity_map = em->velocity; - float *emission_map = em->influence; - float *emission_map_high = em->influence_high; - - int ii, jj, kk, gx, gy, gz, ex, ey, ez, dx, dy, dz, block_size; - size_t e_index, d_index, index_big; - - // loop through every emission map cell - for (gx = em->min[0]; gx < em->max[0]; gx++) { - for (gy = em->min[1]; gy < em->max[1]; gy++) { - for (gz = em->min[2]; gz < em->max[2]; gz++) { - /* get emission map index */ - ex = gx - em->min[0]; - ey = gy - em->min[1]; - ez = gz - em->min[2]; - e_index = smoke_get_index(ex, em->res[0], ey, em->res[1], ez); - - /* get domain index */ - dx = gx - sds->res_min[0]; - dy = gy - sds->res_min[1]; - dz = gz - sds->res_min[2]; - d_index = smoke_get_index(dx, sds->res[0], dy, sds->res[1], dz); - /* make sure emission cell is inside the new domain boundary */ - if (dx < 0 || dy < 0 || dz < 0 || dx >= sds->res[0] || dy >= sds->res[1] || - dz >= sds->res[2]) { - continue; - } - - if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow - apply_outflow_fields( - d_index, density, heat, fuel, react, color_r, color_g, color_b); - } - else { // inflow - apply_inflow_fields(sfs, - emission_map[e_index], - d_index, - density, - heat, - fuel, - react, - color_r, - color_g, - color_b); - - /* initial velocity */ - if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) { - velocity_x[d_index] = ADD_IF_LOWER(velocity_x[d_index], - velocity_map[e_index * 3]); - velocity_y[d_index] = ADD_IF_LOWER(velocity_y[d_index], - velocity_map[e_index * 3 + 1]); - velocity_z[d_index] = ADD_IF_LOWER(velocity_z[d_index], - velocity_map[e_index * 3 + 2]); - } - } - - /* loop through high res blocks if high res enabled */ - if (bigdensity) { - /* Neighbor cell emission densities - * (for high resolution smoke smooth interpolation). */ - float c000, c001, c010, c011, c100, c101, c110, c111; - - smoke_turbulence_get_res(sds->wt, bigres); - block_size = sds->amplify + 1; // high res block size - - c000 = (ex > 0 && ey > 0 && ez > 0) ? - emission_map[smoke_get_index( - ex - 1, em->res[0], ey - 1, em->res[1], ez - 1)] : - 0; - c001 = - (ex > 0 && ey > 0) ? - emission_map[smoke_get_index(ex - 1, em->res[0], ey - 1, em->res[1], ez)] : - 0; - c010 = - (ex > 0 && ez > 0) ? - emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez - 1)] : - 0; - c011 = (ex > 0) ? - emission_map[smoke_get_index(ex - 1, em->res[0], ey, em->res[1], ez)] : - 0; - - c100 = - (ey > 0 && ez > 0) ? - emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez - 1)] : - 0; - c101 = (ey > 0) ? - emission_map[smoke_get_index(ex, em->res[0], ey - 1, em->res[1], ez)] : - 0; - c110 = (ez > 0) ? - emission_map[smoke_get_index(ex, em->res[0], ey, em->res[1], ez - 1)] : - 0; - c111 = emission_map[smoke_get_index( - ex, em->res[0], ey, em->res[1], ez)]; // this cell - - for (ii = 0; ii < block_size; ii++) { - for (jj = 0; jj < block_size; jj++) { - for (kk = 0; kk < block_size; kk++) { - - float fx, fy, fz, interpolated_value; - int shift_x = 0, shift_y = 0, shift_z = 0; - - /* Use full sample emission map if enabled and available */ - if ((sds->highres_sampling == SM_HRES_FULLSAMPLE) && emission_map_high) { - interpolated_value = - emission_map_high[smoke_get_index(ex * block_size + ii, - em->res[0] * block_size, - ey * block_size + jj, - em->res[1] * block_size, - ez * block_size + kk)]; // this cell - } - else if (sds->highres_sampling == SM_HRES_NEAREST) { - /* without interpolation use same low resolution - * block value for all hi-res blocks */ - interpolated_value = c111; - } - /* Fall back to interpolated */ - else { - /* get relative block position - * for interpolation smoothing */ - fx = (float)ii / block_size + 0.5f / block_size; - fy = (float)jj / block_size + 0.5f / block_size; - fz = (float)kk / block_size + 0.5f / block_size; - - /* calculate trilinear interpolation */ - interpolated_value = c000 * (1 - fx) * (1 - fy) * (1 - fz) + - c100 * fx * (1 - fy) * (1 - fz) + - c010 * (1 - fx) * fy * (1 - fz) + - c001 * (1 - fx) * (1 - fy) * fz + - c101 * fx * (1 - fy) * fz + - c011 * (1 - fx) * fy * fz + - c110 * fx * fy * (1 - fz) + c111 * fx * fy * fz; - - /* add some contrast / sharpness - * depending on hi-res block size */ - interpolated_value = (interpolated_value - 0.4f) * (block_size / 2) + 0.4f; - CLAMP(interpolated_value, 0.0f, 1.0f); - - /* shift smoke block index - * (because pixel center is actually - * in halfway of the low res block) */ - shift_x = (dx < 1) ? 0 : block_size / 2; - shift_y = (dy < 1) ? 0 : block_size / 2; - shift_z = (dz < 1) ? 0 : block_size / 2; - } - - /* get shifted index for current high resolution block */ - index_big = smoke_get_index(block_size * dx + ii - shift_x, - bigres[0], - block_size * dy + jj - shift_y, - bigres[1], - block_size * dz + kk - shift_z); - - if (sfs->type == MOD_SMOKE_FLOW_TYPE_OUTFLOW) { // outflow - if (interpolated_value) { - apply_outflow_fields(index_big, - bigdensity, - NULL, - bigfuel, - bigreact, - bigcolor_r, - bigcolor_g, - bigcolor_b); - } - } - else { // inflow - apply_inflow_fields(sfs, - interpolated_value, - index_big, - bigdensity, - NULL, - bigfuel, - bigreact, - bigcolor_r, - bigcolor_g, - bigcolor_b); - } - } // hires loop - } - } - } // bigdensity - } // low res loop - } - } - - // free emission maps - em_freeData(em); - - } // end emission - } - } - - BKE_collision_objects_free(flowobjs); - if (emaps) { - MEM_freeN(emaps); - } -} - -typedef struct UpdateEffectorsData { - Scene *scene; - SmokeDomainSettings *sds; - ListBase *effectors; - - float *density; - float *fuel; - float *force_x; - float *force_y; - float *force_z; - float *velocity_x; - float *velocity_y; - float *velocity_z; - unsigned char *obstacle; -} UpdateEffectorsData; - -static void update_effectors_task_cb(void *__restrict userdata, - const int x, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - UpdateEffectorsData *data = userdata; - SmokeDomainSettings *sds = data->sds; - - for (int y = 0; y < sds->res[1]; y++) { - for (int z = 0; z < sds->res[2]; z++) { - EffectedPoint epoint; - float mag; - float voxelCenter[3] = {0, 0, 0}, vel[3] = {0, 0, 0}, retvel[3] = {0, 0, 0}; - const unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); - - if (((data->fuel ? MAX2(data->density[index], data->fuel[index]) : data->density[index]) < - FLT_EPSILON) || - data->obstacle[index]) { - continue; - } - - vel[0] = data->velocity_x[index]; - vel[1] = data->velocity_y[index]; - vel[2] = data->velocity_z[index]; - - /* convert vel to global space */ - mag = len_v3(vel); - mul_mat3_m4_v3(sds->obmat, vel); - normalize_v3(vel); - mul_v3_fl(vel, mag); - - voxelCenter[0] = sds->p0[0] + sds->cell_size[0] * ((float)(x + sds->res_min[0]) + 0.5f); - voxelCenter[1] = sds->p0[1] + sds->cell_size[1] * ((float)(y + sds->res_min[1]) + 0.5f); - voxelCenter[2] = sds->p0[2] + sds->cell_size[2] * ((float)(z + sds->res_min[2]) + 0.5f); - mul_m4_v3(sds->obmat, voxelCenter); - - pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint); - BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); - - /* convert retvel to local space */ - mag = len_v3(retvel); - mul_mat3_m4_v3(sds->imat, retvel); - normalize_v3(retvel); - mul_v3_fl(retvel, mag); - - // TODO dg - do in force! - data->force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f); - data->force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f); - data->force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f); - } - } -} - -static void update_effectors( - Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt)) -{ - ListBase *effectors; - /* make sure smoke flow influence is 0.0f */ - sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f; - effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights); - - if (effectors) { - // precalculate wind forces - UpdateEffectorsData data; - data.scene = scene; - data.sds = sds; - data.effectors = effectors; - data.density = smoke_get_density(sds->fluid); - data.fuel = smoke_get_fuel(sds->fluid); - data.force_x = smoke_get_force_x(sds->fluid); - data.force_y = smoke_get_force_y(sds->fluid); - data.force_z = smoke_get_force_z(sds->fluid); - data.velocity_x = smoke_get_velocity_x(sds->fluid); - data.velocity_y = smoke_get_velocity_y(sds->fluid); - data.velocity_z = smoke_get_velocity_z(sds->fluid); - data.obstacle = smoke_get_obstacle(sds->fluid); - - TaskParallelSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; - BLI_task_parallel_range(0, sds->res[0], &data, update_effectors_task_cb, &settings); - } - - BKE_effectors_free(effectors); -} - -static void step(Depsgraph *depsgraph, - Scene *scene, - Object *ob, - SmokeModifierData *smd, - Mesh *domain_me, - float fps) -{ - SmokeDomainSettings *sds = smd->domain; - /* stability values copied from wturbulence.cpp */ - const int maxSubSteps = 25; - float maxVel; - // maxVel should be 1.5 (1.5 cell max movement) * dx (cell size) - - float dt; - float maxVelMag = 0.0f; - int totalSubsteps; - int substep = 0; - float dtSubdiv; - float gravity[3] = {0.0f, 0.0f, -1.0f}; - float gravity_mag; - - /* update object state */ - invert_m4_m4(sds->imat, ob->obmat); - copy_m4_m4(sds->obmat, ob->obmat); - smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0); - - /* use global gravity if enabled */ - if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { - copy_v3_v3(gravity, scene->physics_settings.gravity); - /* map default value to 1.0 */ - mul_v3_fl(gravity, 1.0f / 9.810f); - } - /* convert gravity to domain space */ - gravity_mag = len_v3(gravity); - mul_mat3_m4_v3(sds->imat, gravity); - normalize_v3(gravity); - mul_v3_fl(gravity, gravity_mag); - - /* adapt timestep for different framerates, dt = 0.1 is at 25fps */ - dt = DT_DEFAULT * (25.0f / fps); - // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel - maxVel = (sds->dx * 5.0f); - - maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale; - totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */ - totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; - totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; - - /* Disable substeps for now, since it results in numerical instability */ - totalSubsteps = 1.0f; - - dtSubdiv = (float)dt / (float)totalSubsteps; - - // printf("totalSubsteps: %d, maxVelMag: %f, dt: %f\n", totalSubsteps, maxVelMag, dt); - - for (substep = 0; substep < totalSubsteps; substep++) { - // calc animated obstacle velocities - update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv); - update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps); - - if (sds->total_cells > 1) { - // DG TODO? problem --> uses forces instead of velocity, - // need to check how they need to be changed with variable dt. - update_effectors(depsgraph, scene, ob, sds, dtSubdiv); - smoke_step(sds->fluid, gravity, dtSubdiv); - } - } -} - -static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob) -{ - Mesh *result; - MVert *mverts; - MPoly *mpolys; - MLoop *mloops; - float min[3]; - float max[3]; - float *co; - MPoly *mp; - MLoop *ml; - - int num_verts = 8; - int num_faces = 6; - int i; - float ob_loc[3] = {0}; - float ob_cache_loc[3] = {0}; - - /* dont generate any mesh if there isnt any content */ - if (sds->total_cells <= 1) { - num_verts = 0; - num_faces = 0; - } - - result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces); - mverts = result->mvert; - mpolys = result->mpoly; - mloops = result->mloop; - - if (num_verts) { - /* volume bounds */ - madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min); - madd_v3fl_v3fl_v3fl_v3i(max, sds->p0, sds->cell_size, sds->res_max); - - /* set vertices */ - /* top slab */ - co = mverts[0].co; - co[0] = min[0]; - co[1] = min[1]; - co[2] = max[2]; - co = mverts[1].co; - co[0] = max[0]; - co[1] = min[1]; - co[2] = max[2]; - co = mverts[2].co; - co[0] = max[0]; - co[1] = max[1]; - co[2] = max[2]; - co = mverts[3].co; - co[0] = min[0]; - co[1] = max[1]; - co[2] = max[2]; - /* bottom slab */ - co = mverts[4].co; - co[0] = min[0]; - co[1] = min[1]; - co[2] = min[2]; - co = mverts[5].co; - co[0] = max[0]; - co[1] = min[1]; - co[2] = min[2]; - co = mverts[6].co; - co[0] = max[0]; - co[1] = max[1]; - co[2] = min[2]; - co = mverts[7].co; - co[0] = min[0]; - co[1] = max[1]; - co[2] = min[2]; - - /* create faces */ - /* top */ - mp = &mpolys[0]; - ml = &mloops[0 * 4]; - mp->loopstart = 0 * 4; - mp->totloop = 4; - ml[0].v = 0; - ml[1].v = 1; - ml[2].v = 2; - ml[3].v = 3; - /* right */ - mp = &mpolys[1]; - ml = &mloops[1 * 4]; - mp->loopstart = 1 * 4; - mp->totloop = 4; - ml[0].v = 2; - ml[1].v = 1; - ml[2].v = 5; - ml[3].v = 6; - /* bottom */ - mp = &mpolys[2]; - ml = &mloops[2 * 4]; - mp->loopstart = 2 * 4; - mp->totloop = 4; - ml[0].v = 7; - ml[1].v = 6; - ml[2].v = 5; - ml[3].v = 4; - /* left */ - mp = &mpolys[3]; - ml = &mloops[3 * 4]; - mp->loopstart = 3 * 4; - mp->totloop = 4; - ml[0].v = 0; - ml[1].v = 3; - ml[2].v = 7; - ml[3].v = 4; - /* front */ - mp = &mpolys[4]; - ml = &mloops[4 * 4]; - mp->loopstart = 4 * 4; - mp->totloop = 4; - ml[0].v = 3; - ml[1].v = 2; - ml[2].v = 6; - ml[3].v = 7; - /* back */ - mp = &mpolys[5]; - ml = &mloops[5 * 4]; - mp->loopstart = 5 * 4; - mp->totloop = 4; - ml[0].v = 1; - ml[1].v = 0; - ml[2].v = 4; - ml[3].v = 5; - - /* calculate required shift to match domain's global position - * it was originally simulated at (if object moves without smoke step) */ - invert_m4_m4(ob->imat, ob->obmat); - mul_m4_v3(ob->obmat, ob_loc); - mul_m4_v3(sds->obmat, ob_cache_loc); - sub_v3_v3v3(sds->obj_shift_f, ob_cache_loc, ob_loc); - /* convert shift to local space and apply to vertices */ - mul_mat3_m4_v3(ob->imat, sds->obj_shift_f); - /* apply */ - for (i = 0; i < num_verts; i++) { - add_v3_v3(mverts[i].co, sds->obj_shift_f); - } - } - - BKE_mesh_calc_edges(result, false, false); - result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; - return result; -} - -static void smokeModifier_process( - SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) -{ - const int scene_framenr = (int)DEG_get_ctime(depsgraph); - - if ((smd->type & MOD_SMOKE_TYPE_FLOW)) { - if (scene_framenr >= smd->time) { - smokeModifier_init(smd, ob, scene_framenr, me); - } - - if (smd->flow->mesh) { - BKE_id_free(NULL, smd->flow->mesh); - } - smd->flow->mesh = BKE_mesh_copy_for_eval(me, false); - - if (scene_framenr > smd->time) { - smd->time = scene_framenr; - } - else if (scene_framenr < smd->time) { - smd->time = scene_framenr; - smokeModifier_reset_ex(smd, false); - } - } - else if (smd->type & MOD_SMOKE_TYPE_COLL) { - if (scene_framenr >= smd->time) { - smokeModifier_init(smd, ob, scene_framenr, me); - } - - if (smd->coll) { - if (smd->coll->mesh) { - BKE_id_free(NULL, smd->coll->mesh); - } - - smd->coll->mesh = BKE_mesh_copy_for_eval(me, false); - } - - smd->time = scene_framenr; - if (scene_framenr < smd->time) { - smokeModifier_reset_ex(smd, false); - } - } - else if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - SmokeDomainSettings *sds = smd->domain; - PointCache *cache = NULL; - PTCacheID pid; - int startframe, endframe, framenr; - float timescale; - - framenr = scene_framenr; - - cache = sds->point_cache[0]; - BKE_ptcache_id_from_smoke(&pid, ob, smd); - BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); - - if (!smd->domain->fluid || framenr == startframe) { - BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); - smokeModifier_reset_ex(smd, false); - BKE_ptcache_validate(cache, framenr); - cache->flag &= ~PTCACHE_REDO_NEEDED; - } - - if (!smd->domain->fluid && (framenr != startframe) && - (smd->domain->flags & MOD_SMOKE_FILE_LOAD) == 0 && (cache->flag & PTCACHE_BAKED) == 0) { - return; - } - - smd->domain->flags &= ~MOD_SMOKE_FILE_LOAD; - CLAMP(framenr, startframe, endframe); - - /* If already viewing a pre/after frame, no need to reload */ - if ((smd->time == framenr) && (framenr != scene_framenr)) { - return; - } - - if (smokeModifier_init(smd, ob, scene_framenr, me) == 0) { - printf("bad smokeModifier_init\n"); - return; - } - - /* only calculate something when we advanced a single frame */ - /* don't simulate if viewing start frame, but scene frame is not real start frame */ - bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr); - - /* try to read from cache */ - if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) { - BKE_ptcache_validate(cache, framenr); - smd->time = framenr; - return; - } - - if (!can_simulate) { - return; - } - -# ifdef DEBUG_TIME - double start = PIL_check_seconds_timer(); -# endif - - /* if on second frame, write cache for first frame */ - if ((int)smd->time == startframe && - (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { - BKE_ptcache_write(&pid, startframe); - } - - // set new time - smd->time = scene_framenr; - - /* do simulation */ - - // simulate the actual smoke (c++ code in intern/smoke) - // DG: interesting commenting this line + deactivating loading of noise files - if (framenr != startframe) { - if (sds->flags & MOD_SMOKE_DISSOLVE) { - /* low res dissolve */ - smoke_dissolve(sds->fluid, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); - /* high res dissolve */ - if (sds->wt) { - smoke_dissolve_wavelet(sds->wt, sds->diss_speed, sds->flags & MOD_SMOKE_DISSOLVE_LOG); - } - } - - step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base); - } - - // create shadows before writing cache so they get stored - smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph)); - - if (sds->wt && sds->total_cells > 1) { - smoke_turbulence_step(sds->wt, sds->fluid); - } - - BKE_ptcache_validate(cache, framenr); - if (framenr != startframe) { - BKE_ptcache_write(&pid, framenr); - } - -# ifdef DEBUG_TIME - double end = PIL_check_seconds_timer(); - printf("Frame: %d, Time: %f\n\n", (int)smd->time, (float)(end - start)); -# endif - } -} - -struct Mesh *smokeModifier_do( - SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me) -{ - /* lock so preview render does not read smoke data while it gets modified */ - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { - BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE); - } - - smokeModifier_process(smd, depsgraph, scene, ob, me); - - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { - BLI_rw_mutex_unlock(smd->domain->fluid_mutex); - } - - /* return generated geometry for adaptive domain */ - Mesh *result; - if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain && - smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) { - result = createDomainGeometry(smd->domain, ob); - BKE_mesh_copy_settings(result, me); - } - else { - result = BKE_mesh_copy_for_eval(me, false); - } - - /* Smoke simulation needs a texture space relative to the adaptive domain bounds, not the - * original mesh. So recompute it at this point in the modifier stack. See T58492. */ - BKE_mesh_texspace_calc(result); - - return result; -} - -static float calc_voxel_transp( - float *result, float *input, int res[3], int *pixel, float *tRay, float correct) -{ - const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]); - - // T_ray *= T_vox - *tRay *= expf(input[index] * correct); - - if (result[index] < 0.0f) { - result[index] = *tRay; - } - - return *tRay; -} - -static void bresenham_linie_3D(int x1, - int y1, - int z1, - int x2, - int y2, - int z2, - float *tRay, - bresenham_callback cb, - float *result, - float *input, - int res[3], - float correct) -{ - int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2; - int pixel[3]; - - pixel[0] = x1; - pixel[1] = y1; - pixel[2] = z1; - - dx = x2 - x1; - dy = y2 - y1; - dz = z2 - z1; - - x_inc = (dx < 0) ? -1 : 1; - l = abs(dx); - y_inc = (dy < 0) ? -1 : 1; - m = abs(dy); - z_inc = (dz < 0) ? -1 : 1; - n = abs(dz); - dx2 = l << 1; - dy2 = m << 1; - dz2 = n << 1; - - if ((l >= m) && (l >= n)) { - err_1 = dy2 - l; - err_2 = dz2 - l; - for (i = 0; i < l; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) { - break; - } - if (err_1 > 0) { - pixel[1] += y_inc; - err_1 -= dx2; - } - if (err_2 > 0) { - pixel[2] += z_inc; - err_2 -= dx2; - } - err_1 += dy2; - err_2 += dz2; - pixel[0] += x_inc; - } - } - else if ((m >= l) && (m >= n)) { - err_1 = dx2 - m; - err_2 = dz2 - m; - for (i = 0; i < m; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) { - break; - } - if (err_1 > 0) { - pixel[0] += x_inc; - err_1 -= dy2; - } - if (err_2 > 0) { - pixel[2] += z_inc; - err_2 -= dy2; - } - err_1 += dx2; - err_2 += dz2; - pixel[1] += y_inc; - } - } - else { - err_1 = dy2 - n; - err_2 = dx2 - n; - for (i = 0; i < n; i++) { - if (cb(result, input, res, pixel, tRay, correct) <= FLT_EPSILON) { - break; - } - if (err_1 > 0) { - pixel[1] += y_inc; - err_1 -= dz2; - } - if (err_2 > 0) { - pixel[0] += x_inc; - err_2 -= dz2; - } - err_1 += dy2; - err_2 += dx2; - pixel[2] += z_inc; - } - } - cb(result, input, res, pixel, tRay, correct); -} - -static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer) -{ - float bv[6] = {0}; - float light[3]; - int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2]; - float *density = smoke_get_density(sds->fluid); - float correct = -7.0f * sds->dx; - - if (!get_light(view_layer, light)) { - return; - } - - /* convert light pos to sim cell space */ - mul_m4_v3(sds->imat, light); - light[0] = (light[0] - sds->p0[0]) / sds->cell_size[0] - 0.5f - (float)sds->res_min[0]; - light[1] = (light[1] - sds->p0[1]) / sds->cell_size[1] - 0.5f - (float)sds->res_min[1]; - light[2] = (light[2] - sds->p0[2]) / sds->cell_size[2] - 0.5f - (float)sds->res_min[2]; - - for (a = 0; a < size; a++) { - sds->shadow[a] = -1.0f; - } - - /* calculate domain bounds in sim cell space */ - // 0,2,4 = 0.0f - bv[1] = (float)sds->res[0]; // x - bv[3] = (float)sds->res[1]; // y - bv[5] = (float)sds->res[2]; // z - - for (z = 0; z < sds->res[2]; z++) { - size_t index = z * slabsize; - int x, y; - - for (y = 0; y < sds->res[1]; y++) { - for (x = 0; x < sds->res[0]; x++, index++) { - float voxelCenter[3]; - float pos[3]; - int cell[3]; - float tRay = 1.0; - - if (sds->shadow[index] >= 0.0f) { - continue; - } - voxelCenter[0] = (float)x; - voxelCenter[1] = (float)y; - voxelCenter[2] = (float)z; - - // get starting cell (light pos) - if (BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON) { - // we're outside -> use point on side of domain - cell[0] = (int)floor(pos[0]); - cell[1] = (int)floor(pos[1]); - cell[2] = (int)floor(pos[2]); - } - else { - // we're inside -> use light itself - cell[0] = (int)floor(light[0]); - cell[1] = (int)floor(light[1]); - cell[2] = (int)floor(light[2]); - } - /* clamp within grid bounds */ - CLAMP(cell[0], 0, sds->res[0] - 1); - CLAMP(cell[1], 0, sds->res[1] - 1); - CLAMP(cell[2], 0, sds->res[2] - 1); - - bresenham_linie_3D(cell[0], - cell[1], - cell[2], - x, - y, - z, - &tRay, - calc_voxel_transp, - sds->shadow, - density, - sds->res, - correct); - - // convention -> from a RGBA float array, use G value for tRay - sds->shadow[index] = tRay; - } - } - } -} - -/* get smoke velocity and density at given coordinates - * returns fluid density or -1.0f if outside domain. */ -float BKE_smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]) -{ - SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, eModifierType_Smoke); - zero_v3(velocity); - - if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && smd->domain->fluid) { - SmokeDomainSettings *sds = smd->domain; - float time_mult = 25.f * DT_DEFAULT; - float vel_mag; - float *velX = smoke_get_velocity_x(sds->fluid); - float *velY = smoke_get_velocity_y(sds->fluid); - float *velZ = smoke_get_velocity_z(sds->fluid); - float density = 0.0f, fuel = 0.0f; - float pos[3]; - copy_v3_v3(pos, position); - smoke_pos_to_cell(sds, pos); - - /* check if point is outside domain max bounds */ - if (pos[0] < sds->res_min[0] || pos[1] < sds->res_min[1] || pos[2] < sds->res_min[2]) { - return -1.0f; - } - if (pos[0] > sds->res_max[0] || pos[1] > sds->res_max[1] || pos[2] > sds->res_max[2]) { - return -1.0f; - } - - /* map pos between 0.0 - 1.0 */ - pos[0] = (pos[0] - sds->res_min[0]) / ((float)sds->res[0]); - pos[1] = (pos[1] - sds->res_min[1]) / ((float)sds->res[1]); - pos[2] = (pos[2] - sds->res_min[2]) / ((float)sds->res[2]); - - /* check if point is outside active area */ - if (smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) { - if (pos[0] < 0.0f || pos[1] < 0.0f || pos[2] < 0.0f) { - return 0.0f; - } - if (pos[0] > 1.0f || pos[1] > 1.0f || pos[2] > 1.0f) { - return 0.0f; - } - } - - /* get interpolated velocity */ - velocity[0] = BLI_voxel_sample_trilinear(velX, sds->res, pos) * sds->global_size[0] * - time_mult; - velocity[1] = BLI_voxel_sample_trilinear(velY, sds->res, pos) * sds->global_size[1] * - time_mult; - velocity[2] = BLI_voxel_sample_trilinear(velZ, sds->res, pos) * sds->global_size[2] * - time_mult; - - /* convert velocity direction to global space */ - vel_mag = len_v3(velocity); - mul_mat3_m4_v3(sds->obmat, velocity); - normalize_v3(velocity); - mul_v3_fl(velocity, vel_mag); - - /* use max value of fuel or smoke density */ - density = BLI_voxel_sample_trilinear(smoke_get_density(sds->fluid), sds->res, pos); - if (smoke_has_fuel(sds->fluid)) { - fuel = BLI_voxel_sample_trilinear(smoke_get_fuel(sds->fluid), sds->res, pos); - } - return MAX2(density, fuel); - } - return -1.0f; -} - -int BKE_smoke_get_data_flags(SmokeDomainSettings *sds) -{ - int flags = 0; - - if (sds->fluid) { - if (smoke_has_heat(sds->fluid)) { - flags |= SM_ACTIVE_HEAT; - } - if (smoke_has_fuel(sds->fluid)) { - flags |= SM_ACTIVE_FIRE; - } - if (smoke_has_colors(sds->fluid)) { - flags |= SM_ACTIVE_COLORS; - } - } - - return flags; -} - -#endif /* WITH_SMOKE */ - -bool BKE_smoke_show_highres(Scene *scene, SmokeDomainSettings *sds) -{ - if ((sds->viewsettings & MOD_SMOKE_VIEW_SHOW_HIGHRES) == 0) { - return false; - } - if (scene->r.mode & R_SIMPLIFY) { - return !scene->r.simplify_smoke_ignore_highres; - } - return true; -} diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index f2c0bf1e6f1..eb926c51ba9 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -406,6 +406,9 @@ GSet *BLI_gset_str_new(const char *info); GSet *BLI_gset_pair_new_ex(const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; GSet *BLI_gset_pair_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GSet *BLI_gset_int_new_ex(const char *info, + const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; +GSet *BLI_gset_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; /** \} */ diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index 05c3d43a0de..24346454a3f 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -19,7 +19,6 @@ #include <string.h> /* for memset() */ -struct Link; struct ListBase; /** \file diff --git a/source/blender/blenlib/intern/BLI_ghash_utils.c b/source/blender/blenlib/intern/BLI_ghash_utils.c index 1c6484acbdf..63559da5bd7 100644 --- a/source/blender/blenlib/intern/BLI_ghash_utils.c +++ b/source/blender/blenlib/intern/BLI_ghash_utils.c @@ -278,4 +278,13 @@ GSet *BLI_gset_pair_new(const char *info) return BLI_gset_pair_new_ex(info, 0); } +GSet *BLI_gset_int_new_ex(const char *info, const uint nentries_reserve) +{ + return BLI_gset_new_ex(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, info, nentries_reserve); +} +GSet *BLI_gset_int_new(const char *info) +{ + return BLI_gset_int_new_ex(info, 0); +} + /** \} */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9ec178f7a21..d433d38b557 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -83,7 +83,7 @@ #include "DNA_sdna_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_speaker_types.h" #include "DNA_sound_types.h" #include "DNA_space_types.h" @@ -239,7 +239,7 @@ /* local prototypes */ static void read_libraries(FileData *basefd, ListBase *mainlist); static void *read_struct(FileData *fd, BHead *bh, const char *blockname); -static void direct_link_modifiers(FileData *fd, ListBase *lb); +static void direct_link_modifiers(FileData *fd, ListBase *lb, const Object *ob); static BHead *find_bhead_from_code_name(FileData *fd, const short idcode, const char *name); static BHead *find_bhead_from_idname(FileData *fd, const char *idname); @@ -4636,7 +4636,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main) part->instance_object = newlibadr(fd, part->id.lib, part->instance_object); part->instance_collection = newlibadr_us(fd, part->id.lib, part->instance_collection); - part->eff_group = newlibadr(fd, part->id.lib, part->eff_group); + part->force_group = newlibadr(fd, part->id.lib, part->force_group); part->bb_ob = newlibadr(fd, part->id.lib, part->bb_ob); part->collision_group = newlibadr(fd, part->id.lib, part->collision_group); @@ -4647,7 +4647,7 @@ static void lib_link_particlesettings(FileData *fd, Main *main) part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group); } else { - part->effector_weights = BKE_effector_add_weights(part->eff_group); + part->effector_weights = BKE_effector_add_weights(part->force_group); } if (part->instance_weights.first && part->instance_collection) { @@ -4729,7 +4729,7 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part) part->effector_weights = newdataadr(fd, part->effector_weights); if (!part->effector_weights) { - part->effector_weights = BKE_effector_add_weights(part->eff_group); + part->effector_weights = BKE_effector_add_weights(part->force_group); } link_list(fd, &part->instance_weights); @@ -5372,12 +5372,12 @@ static void lib_link_object(FileData *fd, Main *main) } { - SmokeModifierData *smd = (SmokeModifierData *)modifiers_findByType(ob, - eModifierType_Smoke); + FluidModifierData *mmd = (FluidModifierData *)modifiers_findByType(ob, + eModifierType_Fluid); - if (smd && (smd->type == MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { - /* Flag for refreshing the simulation after loading. */ - smd->domain->flags |= MOD_SMOKE_FILE_LOAD; + if (mmd && (mmd->type == MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { + /* Flag for refreshing the simulation after loading */ + mmd->domain->flags |= FLUID_DOMAIN_FILE_LOAD; } } @@ -5485,7 +5485,7 @@ static void direct_link_pose(FileData *fd, bPose *pose) } } -static void direct_link_modifiers(FileData *fd, ListBase *lb) +static void direct_link_modifiers(FileData *fd, ListBase *lb, const Object *ob) { ModifierData *md; @@ -5495,6 +5495,24 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) md->error = NULL; md->runtime = NULL; + if (md->type == eModifierType_Fluidsim) { + blo_reportf_wrap( + fd->reports, + RPT_WARNING, + TIP_( + "Possible data loss when saving this file! %s modifier is deprecated (Object: %s)."), + md->name, + ob->id.name + 2); + } + else if (md->type == eModifierType_Smoke) { + blo_reportf_wrap( + fd->reports, + RPT_WARNING, + TIP_( + "Possible data loss when saving this file! %s modifier is deprecated (Object: %s)."), + md->name, + ob->id.name + 2); + } /* if modifiers disappear, or for upward compatibility */ if (NULL == modifierType_getInfo(md->type)) { md->type = eModifierType_None; @@ -5537,91 +5555,82 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) clmd->solver_result = NULL; } - else if (md->type == eModifierType_Fluidsim) { - FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; + else if (md->type == eModifierType_Fluid) { - fluidmd->fss = newdataadr(fd, fluidmd->fss); - if (fluidmd->fss) { - fluidmd->fss->fmd = fluidmd; - fluidmd->fss->meshVelocities = NULL; - } - } - else if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - - if (smd->type == MOD_SMOKE_TYPE_DOMAIN) { - smd->flow = NULL; - smd->coll = NULL; - smd->domain = newdataadr(fd, smd->domain); - smd->domain->smd = smd; - - smd->domain->fluid = NULL; - smd->domain->fluid_mutex = BLI_rw_mutex_alloc(); - smd->domain->wt = NULL; - smd->domain->shadow = NULL; - smd->domain->tex = NULL; - smd->domain->tex_shadow = NULL; - smd->domain->tex_flame = NULL; - smd->domain->tex_flame_coba = NULL; - smd->domain->tex_coba = NULL; - smd->domain->tex_field = NULL; - smd->domain->tex_velocity_x = NULL; - smd->domain->tex_velocity_y = NULL; - smd->domain->tex_velocity_z = NULL; - smd->domain->tex_wt = NULL; - smd->domain->coba = newdataadr(fd, smd->domain->coba); - - smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights); - if (!smd->domain->effector_weights) { - smd->domain->effector_weights = BKE_effector_add_weights(NULL); + FluidModifierData *mmd = (FluidModifierData *)md; + + if (mmd->type == MOD_FLUID_TYPE_DOMAIN) { + mmd->flow = NULL; + mmd->effector = NULL; + mmd->domain = newdataadr(fd, mmd->domain); + mmd->domain->mmd = mmd; + + mmd->domain->fluid = NULL; + mmd->domain->fluid_mutex = BLI_rw_mutex_alloc(); + mmd->domain->tex = NULL; + mmd->domain->tex_shadow = NULL; + mmd->domain->tex_flame = NULL; + mmd->domain->tex_flame_coba = NULL; + mmd->domain->tex_coba = NULL; + mmd->domain->tex_field = NULL; + mmd->domain->tex_velocity_x = NULL; + mmd->domain->tex_velocity_y = NULL; + mmd->domain->tex_velocity_z = NULL; + mmd->domain->tex_wt = NULL; + mmd->domain->mesh_velocities = NULL; + mmd->domain->coba = newdataadr(fd, mmd->domain->coba); + + mmd->domain->effector_weights = newdataadr(fd, mmd->domain->effector_weights); + if (!mmd->domain->effector_weights) { + mmd->domain->effector_weights = BKE_effector_add_weights(NULL); } direct_link_pointcache_list( - fd, &(smd->domain->ptcaches[0]), &(smd->domain->point_cache[0]), 1); + fd, &(mmd->domain->ptcaches[0]), &(mmd->domain->point_cache[0]), 1); - /* Smoke uses only one cache from now on, so store pointer convert */ - if (smd->domain->ptcaches[1].first || smd->domain->point_cache[1]) { - if (smd->domain->point_cache[1]) { - PointCache *cache = newdataadr(fd, smd->domain->point_cache[1]); + /* Manta sim uses only one cache from now on, so store pointer convert */ + if (mmd->domain->ptcaches[1].first || mmd->domain->point_cache[1]) { + if (mmd->domain->point_cache[1]) { + PointCache *cache = newdataadr(fd, mmd->domain->point_cache[1]); if (cache->flag & PTCACHE_FAKE_SMOKE) { - /* Smoke was already saved in "new format" and this cache is a fake one. */ + /* Manta-sim/smoke was already saved in "new format" and this cache is a fake one. */ } else { printf( - "High resolution smoke cache not available due to pointcache update. Please " + "High resolution manta cache not available due to pointcache update. Please " "reset the simulation.\n"); } BKE_ptcache_free(cache); } - BLI_listbase_clear(&smd->domain->ptcaches[1]); - smd->domain->point_cache[1] = NULL; - } - } - else if (smd->type == MOD_SMOKE_TYPE_FLOW) { - smd->domain = NULL; - smd->coll = NULL; - smd->flow = newdataadr(fd, smd->flow); - smd->flow->smd = smd; - smd->flow->mesh = NULL; - smd->flow->verts_old = NULL; - smd->flow->numverts = 0; - smd->flow->psys = newdataadr(fd, smd->flow->psys); - } - else if (smd->type == MOD_SMOKE_TYPE_COLL) { - smd->flow = NULL; - smd->domain = NULL; - smd->coll = newdataadr(fd, smd->coll); - if (smd->coll) { - smd->coll->smd = smd; - smd->coll->verts_old = NULL; - smd->coll->numverts = 0; - smd->coll->mesh = NULL; + BLI_listbase_clear(&mmd->domain->ptcaches[1]); + mmd->domain->point_cache[1] = NULL; + } + } + else if (mmd->type == MOD_FLUID_TYPE_FLOW) { + mmd->domain = NULL; + mmd->effector = NULL; + mmd->flow = newdataadr(fd, mmd->flow); + mmd->flow->mmd = mmd; + mmd->flow->mesh = NULL; + mmd->flow->verts_old = NULL; + mmd->flow->numverts = 0; + mmd->flow->psys = newdataadr(fd, mmd->flow->psys); + } + else if (mmd->type == MOD_FLUID_TYPE_EFFEC) { + mmd->flow = NULL; + mmd->domain = NULL; + mmd->effector = newdataadr(fd, mmd->effector); + if (mmd->effector) { + mmd->effector->mmd = mmd; + mmd->effector->verts_old = NULL; + mmd->effector->numverts = 0; + mmd->effector->mesh = NULL; } else { - smd->type = 0; - smd->flow = NULL; - smd->domain = NULL; - smd->coll = NULL; + mmd->type = 0; + mmd->flow = NULL; + mmd->domain = NULL; + mmd->effector = NULL; } } } @@ -5968,7 +5977,7 @@ static void direct_link_object(FileData *fd, Object *ob) ob->matbits = newdataadr(fd, ob->matbits); /* do it here, below old data gets converted */ - direct_link_modifiers(fd, &ob->modifiers); + direct_link_modifiers(fd, &ob->modifiers, ob); direct_link_gpencil_modifiers(fd, &ob->greasepencil_modifiers); direct_link_shaderfxs(fd, &ob->shader_fx); @@ -10407,7 +10416,7 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting expand_doit(fd, mainvar, part->instance_object); expand_doit(fd, mainvar, part->instance_collection); - expand_doit(fd, mainvar, part->eff_group); + expand_doit(fd, mainvar, part->force_group); expand_doit(fd, mainvar, part->bb_ob); expand_doit(fd, mainvar, part->collision_group); diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 3e7b1582603..a5ab0c0acb7 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -50,7 +50,7 @@ #include "DNA_screen_types.h" #include "DNA_sdna_types.h" #include "DNA_sequence_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_sound_types.h" #include "DNA_space_types.h" #include "DNA_world_types.h" @@ -1789,19 +1789,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; + if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { - smd->domain->vorticity = 2.0f; - smd->domain->time_scale = 1.0f; + if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { + mmd->domain->vorticity = 2.0f; + mmd->domain->time_scale = 1.0f; - if (!(smd->domain->flags & (1 << 4))) { + if (!(mmd->domain->flags & (1 << 4))) { continue; } /* delete old MOD_SMOKE_INITVELOCITY flag */ - smd->domain->flags &= ~(1 << 4); + mmd->domain->flags &= ~(1 << 4); /* for now just add it to all flow objects in the scene */ { @@ -1809,19 +1809,19 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) for (ob2 = bmain->objects.first; ob2; ob2 = ob2->id.next) { ModifierData *md2; for (md2 = ob2->modifiers.first; md2; md2 = md2->next) { - if (md2->type == eModifierType_Smoke) { - SmokeModifierData *smd2 = (SmokeModifierData *)md2; + if (md2->type == eModifierType_Fluid) { + FluidModifierData *mmd2 = (FluidModifierData *)md2; - if ((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) { - smd2->flow->flags |= MOD_SMOKE_FLOW_INITVELOCITY; + if ((mmd2->type & MOD_FLUID_TYPE_FLOW) && mmd2->flow) { + mmd2->flow->flags |= FLUID_FLOW_INITVELOCITY; } } } } } } - else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { - smd->flow->vel_multi = 1.0f; + else if ((mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow) { + mmd->flow->vel_multi = 1.0f; } } } diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 40219a36323..f23e4b5e2a4 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -39,7 +39,7 @@ #include "DNA_view3d_types.h" #include "DNA_screen_types.h" #include "DNA_sdna_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_space_types.h" #include "DNA_world_types.h" #include "DNA_light_types.h" @@ -1292,12 +1292,12 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) for (ob = bmain->objects.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { - int maxres = max_iii(smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]); - smd->domain->scale = smd->domain->dx * maxres; - smd->domain->dx = 1.0f / smd->domain->scale; + if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { + int maxres = max_iii(mmd->domain->res[0], mmd->domain->res[1], mmd->domain->res[2]); + mmd->domain->scale = mmd->domain->dx * maxres; + mmd->domain->dx = 1.0f / mmd->domain->scale; } } } @@ -1610,31 +1610,31 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) for (ob = bmain->objects.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { + if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { /* keep branch saves if possible */ - if (!smd->domain->flame_max_temp) { - smd->domain->burning_rate = 0.75f; - smd->domain->flame_smoke = 1.0f; - smd->domain->flame_vorticity = 0.5f; - smd->domain->flame_ignition = 1.25f; - smd->domain->flame_max_temp = 1.75f; - smd->domain->adapt_threshold = 0.02f; - smd->domain->adapt_margin = 4; - smd->domain->flame_smoke_color[0] = 0.7f; - smd->domain->flame_smoke_color[1] = 0.7f; - smd->domain->flame_smoke_color[2] = 0.7f; + if (!mmd->domain->flame_max_temp) { + mmd->domain->burning_rate = 0.75f; + mmd->domain->flame_smoke = 1.0f; + mmd->domain->flame_vorticity = 0.5f; + mmd->domain->flame_ignition = 1.25f; + mmd->domain->flame_max_temp = 1.75f; + mmd->domain->adapt_threshold = 0.02f; + mmd->domain->adapt_margin = 4; + mmd->domain->flame_smoke_color[0] = 0.7f; + mmd->domain->flame_smoke_color[1] = 0.7f; + mmd->domain->flame_smoke_color[2] = 0.7f; } } - else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { - if (!smd->flow->texture_size) { - smd->flow->fuel_amount = 1.0; - smd->flow->surface_distance = 1.5; - smd->flow->color[0] = 0.7f; - smd->flow->color[1] = 0.7f; - smd->flow->color[2] = 0.7f; - smd->flow->texture_size = 1.0f; + else if ((mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow) { + if (!mmd->flow->texture_size) { + mmd->flow->fuel_amount = 1.0; + mmd->flow->surface_distance = 1.5; + mmd->flow->color[0] = 0.7f; + mmd->flow->color[1] = 0.7f; + mmd->flow->color[2] = 0.7f; + mmd->flow->texture_size = 1.0f; } } } @@ -2140,14 +2140,14 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) for (ob = bmain->objects.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { - if (smd->domain->flags & MOD_SMOKE_HIGH_SMOOTH) { - smd->domain->highres_sampling = SM_HRES_LINEAR; + if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { + if (mmd->domain->flags & FLUID_DOMAIN_USE_HIGH_SMOOTH) { + mmd->domain->highres_sampling = SM_HRES_LINEAR; } else { - smd->domain->highres_sampling = SM_HRES_NEAREST; + mmd->domain->highres_sampling = SM_HRES_NEAREST; } } } @@ -2207,11 +2207,11 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) for (ob = bmain->objects.first; ob; ob = ob->id.next) { ModifierData *md; for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { - if (!smd->flow->particle_size) { - smd->flow->particle_size = 1.0f; + if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if ((mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow) { + if (!mmd->flow->particle_size) { + mmd->flow->particle_size = 1.0f; } } } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index fb570b956b6..f421f31814c 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -46,7 +46,7 @@ #include "DNA_particle_types.h" #include "DNA_linestyle_types.h" #include "DNA_view3d_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_rigidbody_types.h" #include "DNA_light_types.h" @@ -1549,18 +1549,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - if (!DNA_struct_elem_find(fd->filesdna, "SmokeModifierData", "float", "slice_per_voxel")) { + if (!DNA_struct_elem_find(fd->filesdna, "FluidModifierData", "float", "slice_per_voxel")) { Object *ob; ModifierData *md; for (ob = bmain->objects.first; ob; ob = ob->id.next) { for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if (smd->domain) { - smd->domain->slice_per_voxel = 5.0f; - smd->domain->slice_depth = 0.5f; - smd->domain->display_thickness = 1.0f; + if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if (mmd->domain) { + mmd->domain->slice_per_voxel = 5.0f; + mmd->domain->slice_depth = 0.5f; + mmd->domain->display_thickness = 1.0f; } } } @@ -1719,16 +1719,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) } if (!MAIN_VERSION_ATLEAST(bmain, 279, 3)) { - if (!DNA_struct_elem_find(fd->filesdna, "SmokeDomainSettings", "float", "clipping")) { + if (!DNA_struct_elem_find(fd->filesdna, "FluidDomainSettings", "float", "clipping")) { Object *ob; ModifierData *md; for (ob = bmain->objects.first; ob; ob = ob->id.next) { for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if (smd->domain) { - smd->domain->clipping = 1e-3f; + if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; + if (mmd->domain) { + mmd->domain->clipping = 1e-3f; } } } diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 5d46f0735eb..73cdd40c02c 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -2292,7 +2292,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) part->omat = paf->mat[0]; part->hair_step = paf->totkey; - part->eff_group = paf->group; + part->force_group = paf->group; /* old system didn't interpolate between keypoints at render time */ part->draw_step = part->ren_step = 0; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 2b68ba2a8f6..89c097044f4 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -126,7 +126,7 @@ #include "DNA_scene_types.h" #include "DNA_sdna_types.h" #include "DNA_sequence_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_space_types.h" #include "DNA_screen_types.h" #include "DNA_speaker_types.h" @@ -1628,38 +1628,38 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights); write_pointcaches(wd, &clmd->ptcaches); } - else if (md->type == eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData *)md; + else if (md->type == eModifierType_Fluid) { + FluidModifierData *mmd = (FluidModifierData *)md; - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); + if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { + writestruct(wd, DATA, FluidDomainSettings, 1, mmd->domain); - if (smd->domain) { - write_pointcaches(wd, &(smd->domain->ptcaches[0])); + if (mmd->domain) { + write_pointcaches(wd, &(mmd->domain->ptcaches[0])); /* create fake pointcache so that old blender versions can read it */ - smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]); - smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE; - smd->domain->point_cache[1]->step = 1; + mmd->domain->point_cache[1] = BKE_ptcache_add(&mmd->domain->ptcaches[1]); + mmd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE; + mmd->domain->point_cache[1]->step = 1; - write_pointcaches(wd, &(smd->domain->ptcaches[1])); + write_pointcaches(wd, &(mmd->domain->ptcaches[1])); - if (smd->domain->coba) { - writestruct(wd, DATA, ColorBand, 1, smd->domain->coba); + if (mmd->domain->coba) { + writestruct(wd, DATA, ColorBand, 1, mmd->domain->coba); } /* cleanup the fake pointcache */ - BKE_ptcache_free_list(&smd->domain->ptcaches[1]); - smd->domain->point_cache[1] = NULL; + BKE_ptcache_free_list(&mmd->domain->ptcaches[1]); + mmd->domain->point_cache[1] = NULL; - writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights); + writestruct(wd, DATA, EffectorWeights, 1, mmd->domain->effector_weights); } } - else if (smd->type & MOD_SMOKE_TYPE_FLOW) { - writestruct(wd, DATA, SmokeFlowSettings, 1, smd->flow); + else if (mmd->type & MOD_FLUID_TYPE_FLOW) { + writestruct(wd, DATA, FluidFlowSettings, 1, mmd->flow); } - else if (smd->type & MOD_SMOKE_TYPE_COLL) { - writestruct(wd, DATA, SmokeCollSettings, 1, smd->coll); + else if (mmd->type & MOD_FLUID_TYPE_EFFEC) { + writestruct(wd, DATA, FluidEffectorSettings, 1, mmd->effector); } } else if (md->type == eModifierType_Fluidsim) { diff --git a/source/blender/collada/ExtraTags.h b/source/blender/collada/ExtraTags.h index 2d827159af8..9191182c757 100644 --- a/source/blender/collada/ExtraTags.h +++ b/source/blender/collada/ExtraTags.h @@ -18,6 +18,9 @@ * \ingroup collada */ +#ifndef __EXTRATAGS_H__ +#define __EXTRATAGS_H__ + #include <string> #include <map> #include <vector> @@ -70,3 +73,5 @@ class ExtraTags { /** Get text data for tag as a string. */ std::string asString(std::string tag, bool *ok); }; + +#endif /* __EXTRATAGS_H__ */ diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cpp b/source/blender/compositor/nodes/COM_DenoiseNode.cpp index 7de120d1204..a18fc82908a 100644 --- a/source/blender/compositor/nodes/COM_DenoiseNode.cpp +++ b/source/blender/compositor/nodes/COM_DenoiseNode.cpp @@ -1,6 +1,4 @@ /* - * Copyright 2019, Blender Foundation. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -15,10 +13,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Stefan Werner + * Copyright 2019, Blender Foundation. */ - #include "COM_DenoiseNode.h" #include "DNA_node_types.h" #include "COM_SetValueOperation.h" diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.h b/source/blender/compositor/nodes/COM_DenoiseNode.h index 0924da8931c..6cbe598f7d2 100644 --- a/source/blender/compositor/nodes/COM_DenoiseNode.h +++ b/source/blender/compositor/nodes/COM_DenoiseNode.h @@ -1,6 +1,4 @@ /* - * Copyright 2019, Blender Foundation. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -15,8 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Stefan Werner + * Copyright 2019, Blender Foundation. */ #ifndef __COM_DENOISENODE_H__ diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cpp index 8235c296c5a..d9a59002caf 100644 --- a/source/blender/compositor/operations/COM_DenoiseOperation.cpp +++ b/source/blender/compositor/operations/COM_DenoiseOperation.cpp @@ -1,6 +1,4 @@ /* - * Copyright 2019, Blender Foundation. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -15,8 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Stefan Werner + * Copyright 2019, Blender Foundation. */ #include "COM_DenoiseOperation.h" diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.h b/source/blender/compositor/operations/COM_DenoiseOperation.h index fc06bb81a97..6a53eead65c 100644 --- a/source/blender/compositor/operations/COM_DenoiseOperation.h +++ b/source/blender/compositor/operations/COM_DenoiseOperation.h @@ -1,6 +1,4 @@ /* - * Copyright 2019, Blender Foundation. - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -15,8 +13,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Stefan Werner + * Copyright 2019, Blender Foundation. */ #ifndef __COM_DENOISEOPERATION_H__ diff --git a/source/blender/depsgraph/intern/depsgraph_physics.cc b/source/blender/depsgraph/intern/depsgraph_physics.cc index 3f81e49b170..f47081cd54e 100644 --- a/source/blender/depsgraph/intern/depsgraph_physics.cc +++ b/source/blender/depsgraph/intern/depsgraph_physics.cc @@ -54,7 +54,7 @@ static ePhysicsRelationType modifier_to_relation_type(unsigned int modifier_type switch (modifier_type) { case eModifierType_Collision: return DEG_PHYSICS_COLLISION; - case eModifierType_Smoke: + case eModifierType_Fluid: return DEG_PHYSICS_SMOKE_COLLISION; case eModifierType_DynamicPaint: return DEG_PHYSICS_DYNAMIC_BRUSH; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h index a9d528a254c..427e9c7b483 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h @@ -23,9 +23,9 @@ #pragma once -struct anim; struct MovieClip; struct MovieClipCache; +struct anim; namespace DEG { diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 723965172ae..6c55fa7ce30 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -121,10 +121,10 @@ set(SRC engines/select/select_engine.c engines/overlay/overlay_antialiasing.c engines/overlay/overlay_armature.c - engines/overlay/overlay_engine.c engines/overlay/overlay_edit_curve.c - engines/overlay/overlay_edit_text.c engines/overlay/overlay_edit_mesh.c + engines/overlay/overlay_edit_text.c + engines/overlay/overlay_engine.c engines/overlay/overlay_extra.c engines/overlay/overlay_facing.c engines/overlay/overlay_grid.c @@ -135,8 +135,8 @@ set(SRC engines/overlay/overlay_outline.c engines/overlay/overlay_paint.c engines/overlay/overlay_particle.c - engines/overlay/overlay_shader.c engines/overlay/overlay_sculpt.c + engines/overlay/overlay_shader.c engines/overlay/overlay_wireframe.c DRW_engine.h diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 67fd441a0b1..d32f93432b8 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -28,12 +28,12 @@ #include "BLI_string_utils.h" #include "DNA_object_force_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_world_types.h" #include "BKE_modifier.h" #include "BKE_mesh.h" -#include "BKE_smoke.h" +#include "BKE_fluid.h" #include "ED_screen.h" @@ -63,7 +63,7 @@ static struct { GPUTexture *dummy_scatter; GPUTexture *dummy_transmit; - /* List of all smoke domains rendered within this frame. */ + /* List of all fluid simulation / smoke domains rendered within this frame. */ ListBase smoke_domains; } e_data = {NULL}; /* Engine data */ @@ -390,8 +390,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, Scene *scene, Object *ob) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - static float white[3] = {1.0f, 1.0f, 1.0f}; + static const float white[3] = {1.0f, 1.0f, 1.0f}; float *texcoloc = NULL; float *texcosize = NULL; @@ -430,41 +429,49 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, /* Smoke Simulation */ if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Smoke)) && + (md = modifiers_findByType(ob, eModifierType_Fluid)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && - ((SmokeModifierData *)md)->domain != NULL) { - SmokeModifierData *smd = (SmokeModifierData *)md; - SmokeDomainSettings *sds = smd->domain; + ((FluidModifierData *)md)->domain != NULL) { + FluidModifierData *mmd = (FluidModifierData *)md; + FluidDomainSettings *mds = mmd->domain; + + /* Don't try to show liquid domains here. */ + if (!mds->fluid || !(mds->type == FLUID_DOMAIN_TYPE_GAS)) { + return; + } /* Don't show smoke before simulation starts, this could be made an option in the future. */ + /* (sebbas): Always show smoke for manta */ +#if 0 + const DRWContextState *draw_ctx = DRW_context_state_get(); const bool show_smoke = ((int)DEG_get_ctime(draw_ctx->depsgraph) >= - sds->point_cache[0]->startframe); + *mds->point_cache[0]->startframe); +#endif - if (sds->fluid && show_smoke) { - const bool show_highres = BKE_smoke_show_highres(scene, sds); - if (!sds->wt || !show_highres) { - GPU_create_smoke(smd, 0); + if (mds->fluid && (mds->type == FLUID_DOMAIN_TYPE_GAS) /* && show_smoke */) { + if (!(mds->flags & FLUID_DOMAIN_USE_NOISE)) { + GPU_create_smoke(mmd, 0); } - else if (sds->wt && show_highres) { - GPU_create_smoke(smd, 1); + else if (mds->flags & FLUID_DOMAIN_USE_NOISE) { + GPU_create_smoke(mmd, 1); } - BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(smd)); + BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(mmd)); } DRW_shgroup_uniform_texture_ref( - grp, "sampdensity", sds->tex ? &sds->tex : &e_data.dummy_density); + grp, "sampdensity", mds->tex ? &mds->tex : &e_data.dummy_density); DRW_shgroup_uniform_texture_ref( - grp, "sampflame", sds->tex_flame ? &sds->tex_flame : &e_data.dummy_flame); + grp, "sampflame", mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame); /* Constant Volume color. */ - bool use_constant_color = ((sds->active_fields & SM_ACTIVE_COLORS) == 0 && - (sds->active_fields & SM_ACTIVE_COLOR_SET) != 0); + bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && + (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); DRW_shgroup_uniform_vec3( - grp, "volumeColor", (use_constant_color) ? sds->active_color : white, 1); + grp, "volumeColor", (use_constant_color) ? mds->active_color : white, 1); /* Output is such that 0..1 maps to 0..1000K */ - DRW_shgroup_uniform_vec2(grp, "unftemperature", &sds->flame_ignition, 1); + DRW_shgroup_uniform_vec2(grp, "unftemperature", &mds->flame_ignition, 1); } else { DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density); @@ -692,8 +699,8 @@ void EEVEE_volumes_free_smoke_textures(void) { /* Free Smoke Textures after rendering */ for (LinkData *link = e_data.smoke_domains.first; link; link = link->next) { - SmokeModifierData *smd = (SmokeModifierData *)link->data; - GPU_free_smoke(smd); + FluidModifierData *mmd = (FluidModifierData *)link->data; + GPU_free_smoke(mmd); } BLI_freelistN(&e_data.smoke_domains); } diff --git a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl index 5a738d0f130..35bfb411cb9 100644 --- a/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/renderpass_postprocess_frag.glsl @@ -61,4 +61,4 @@ void main() else { fragColor = vec4(1.0, 0.0, 1.0, 1.0); } -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index 7e75edfddf3..4c6ce896ebc 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -1948,9 +1948,12 @@ void gpencil_populate_datablock(GPENCIL_e_data *e_data, bGPdata *gpd = (bGPdata *)ob->data; - const bool main_onion = stl->storage->is_main_onion; + /* If render mode, instead to use view switches, test if the datablock has + * the onion activated for render. */ + const bool render_onion = (gpd && gpd->onion_flag & GP_ONION_GHOST_ALWAYS); + const bool main_onion = (stl->storage->is_render) ? render_onion : stl->storage->is_main_onion; + const bool overlay = (stl->storage->is_render) ? render_onion : stl->storage->is_main_overlay; const bool playing = stl->storage->is_playing; - const bool overlay = stl->storage->is_main_overlay; const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay && main_onion && !playing && gpencil_onion_active(gpd); diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index b0fb95380f4..0b77fcad265 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -2354,4 +2354,4 @@ void OVERLAY_pose_draw(OVERLAY_Data *vedata) DRW_draw_pass(psl->armature_ps[1]); } -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/overlay_edit_curve.c b/source/blender/draw/engines/overlay/overlay_edit_curve.c index b39dc39fd47..d9b9fac6b4b 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_curve.c +++ b/source/blender/draw/engines/overlay/overlay_edit_curve.c @@ -129,4 +129,4 @@ void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata) DRW_draw_pass(psl->edit_curve_wire_ps[1]); DRW_draw_pass(psl->edit_curve_handle_ps); -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/overlay_edit_text.c b/source/blender/draw/engines/overlay/overlay_edit_text.c index 0975608a300..72b5ae74255 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_text.c +++ b/source/blender/draw/engines/overlay/overlay_edit_text.c @@ -202,4 +202,4 @@ void OVERLAY_edit_text_draw(OVERLAY_Data *vedata) DRW_draw_pass(psl->edit_text_wire_ps[1]); DRW_draw_pass(psl->edit_text_overlay_ps); -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index f6e3ed4d4de..90ddb9f7476 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -45,7 +45,7 @@ #include "DNA_modifier_types.h" #include "DNA_object_force_types.h" #include "DNA_rigidbody_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DEG_depsgraph_query.h" @@ -1410,22 +1410,22 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, Scene *scene, float *color) { - SmokeModifierData *smd = (SmokeModifierData *)md; - SmokeDomainSettings *sds = smd->domain; + FluidModifierData *mmd = (FluidModifierData *)md; + FluidDomainSettings *mds = mmd->domain; /* Don't show smoke before simulation starts, this could be made an option in the future. */ - const bool draw_velocity = (sds->draw_velocity && sds->fluid && - CFRA >= sds->point_cache[0]->startframe); + const bool draw_velocity = (mds->draw_velocity && mds->fluid && + CFRA >= mds->point_cache[0]->startframe); /* Small cube showing voxel size. */ { float min[3]; - madd_v3fl_v3fl_v3fl_v3i(min, sds->p0, sds->cell_size, sds->res_min); + madd_v3fl_v3fl_v3fl_v3i(min, mds->p0, mds->cell_size, mds->res_min); float voxel_cubemat[4][4] = {{0.0f}}; /* scale small cube to voxel size */ - voxel_cubemat[0][0] = 1.0f / (float)sds->base_res[0]; - voxel_cubemat[1][1] = 1.0f / (float)sds->base_res[1]; - voxel_cubemat[2][2] = 1.0f / (float)sds->base_res[2]; + voxel_cubemat[0][0] = 1.0f / (float)mds->base_res[0]; + voxel_cubemat[1][1] = 1.0f / (float)mds->base_res[1]; + voxel_cubemat[2][2] = 1.0f / (float)mds->base_res[2]; voxel_cubemat[3][3] = 1.0f; /* translate small cube to corner */ copy_v3_v3(voxel_cubemat[3], min); @@ -1437,38 +1437,38 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb, } if (draw_velocity) { - const bool use_needle = (sds->vector_draw_type == VECTOR_DRAW_NEEDLE); + const bool use_needle = (mds->vector_draw_type == VECTOR_DRAW_NEEDLE); int line_count = (use_needle) ? 6 : 1; int slice_axis = -1; - line_count *= sds->res[0] * sds->res[1] * sds->res[2]; + line_count *= mds->res[0] * mds->res[1] * mds->res[2]; - if (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED && - sds->axis_slice_method == AXIS_SLICE_SINGLE) { + if (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED && + mds->axis_slice_method == AXIS_SLICE_SINGLE) { float viewinv[4][4]; DRW_view_viewmat_get(NULL, viewinv, true); - const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) : - sds->slice_axis - 1; + const int axis = (mds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(viewinv[2]) : + mds->slice_axis - 1; slice_axis = axis; - line_count /= sds->res[axis]; + line_count /= mds->res[axis]; } - GPU_create_smoke_velocity(smd); + GPU_create_smoke_velocity(mmd); GPUShader *sh = OVERLAY_shader_volume_velocity(use_needle); DRWShadingGroup *grp = DRW_shgroup_create(sh, data->psl->extra_ps[0]); - DRW_shgroup_uniform_texture(grp, "velocityX", sds->tex_velocity_x); - DRW_shgroup_uniform_texture(grp, "velocityY", sds->tex_velocity_y); - DRW_shgroup_uniform_texture(grp, "velocityZ", sds->tex_velocity_z); - DRW_shgroup_uniform_float_copy(grp, "displaySize", sds->vector_scale); - DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth); - DRW_shgroup_uniform_vec3_copy(grp, "cellSize", sds->cell_size); - DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", sds->p0); - DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", sds->res_min); + DRW_shgroup_uniform_texture(grp, "velocityX", mds->tex_velocity_x); + DRW_shgroup_uniform_texture(grp, "velocityY", mds->tex_velocity_y); + DRW_shgroup_uniform_texture(grp, "velocityZ", mds->tex_velocity_z); + DRW_shgroup_uniform_float_copy(grp, "displaySize", mds->vector_scale); + DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth); + DRW_shgroup_uniform_vec3_copy(grp, "cellSize", mds->cell_size); + DRW_shgroup_uniform_vec3_copy(grp, "domainOriginOffset", mds->p0); + DRW_shgroup_uniform_ivec3_copy(grp, "adaptiveCellOffset", mds->res_min); DRW_shgroup_uniform_int_copy(grp, "sliceAxis", slice_axis); DRW_shgroup_call_procedural_lines(grp, ob, line_count); - BLI_addtail(&data->stl->pd->smoke_domains, BLI_genericNodeN(smd)); + BLI_addtail(&data->stl->pd->smoke_domains, BLI_genericNodeN(mmd)); } } @@ -1482,8 +1482,8 @@ static void OVERLAY_volume_free_smoke_textures(OVERLAY_Data *data) * all viewport in a redraw at least. */ LinkData *link; while ((link = BLI_pophead(&data->stl->pd->smoke_domains))) { - SmokeModifierData *smd = (SmokeModifierData *)link->data; - GPU_free_smoke_velocity(smd); + FluidModifierData *mmd = (FluidModifierData *)link->data; + GPU_free_smoke_velocity(mmd); MEM_freeN(link); } } @@ -1555,9 +1555,9 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob) const bool draw_xform = draw_ctx->object_mode == OB_MODE_OBJECT && (scene->toolsettings->transform_flag & SCE_XFORM_DATA_ORIGIN) && (ob->base_flag & BASE_SELECTED) && !is_select_mode; - const bool draw_volume = !from_dupli && (md = modifiers_findByType(ob, eModifierType_Smoke)) && + const bool draw_volume = !from_dupli && (md = modifiers_findByType(ob, eModifierType_Fluid)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && - (((SmokeModifierData *)md)->domain != NULL); + (((FluidModifierData *)md)->domain != NULL); float *color; int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color); diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 9be92e0ab14..996ee845799 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -571,4 +571,4 @@ OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void); void OVERLAY_shader_free(void); -#endif /* __OVERLAY_PRIVATE_H__ */
\ No newline at end of file +#endif /* __OVERLAY_PRIVATE_H__ */ diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl index 386e6d9e141..4784d420e1d 100644 --- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl @@ -147,4 +147,4 @@ void main() fragColor = mix(fragColor, fragColor / fragColor.a, blend); } #endif -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl index 4f3c36c7bd7..8cf8ba121ed 100644 --- a/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/antialiasing_vert.glsl @@ -8,4 +8,4 @@ void main() float y = float((v & 2) << 1); gl_Position = vec4(x - 1.0, y - 1.0, 1.0, 1.0); uvs = vec2(x, y) * 0.5; -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl index 8a8ae8a9611..a2572f44e70 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_frag.glsl @@ -10,4 +10,4 @@ void main() { fragColor = finalColor; lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos); -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl index 4b08ea587d4..738f0025f07 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl @@ -27,4 +27,4 @@ void main() #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl index 8784b6cd73a..c27061f8f97 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl @@ -15,4 +15,4 @@ void main() * the depth and creating mini-spheres. * Disabled as it has performance impact. */ // gl_FragDepth = gl_FragCoord.z + 1e-6 * fac; -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl index 76a2678a50e..7e31bf966bc 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl @@ -17,4 +17,4 @@ void main() #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl index 14c03248981..537c55cf3f5 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl @@ -27,4 +27,4 @@ void main() #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl index a72c5adb691..92db27ea6dd 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_vert.glsl @@ -224,4 +224,4 @@ void main() #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl index 7e469aee18d..a2bc13ba443 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl @@ -28,4 +28,4 @@ void main() if (fract(dist / dash_width) > dash_factor) { discard; } -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl index 933b9d65a5f..97183638a71 100644 --- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl @@ -37,4 +37,4 @@ void main() #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance(world_pos); #endif -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl index 64f88bd74fa..752694301f7 100644 --- a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl @@ -6,11 +6,11 @@ uniform float displaySize = 1.0; uniform float slicePosition; uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ -/* SmokeDomainSettings.cell_size */ +/* FluidDomainSettings.cell_size */ uniform vec3 cellSize; -/* SmokeDomainSettings.p0 */ +/* FluidDomainSettings.p0 */ uniform vec3 domainOriginOffset; -/* SmokeDomainSettings.res_min */ +/* FluidDomainSettings.res_min */ uniform ivec3 adaptiveCellOffset; flat out vec4 finalColor; diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 8e61750da38..a536132a1cf 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -34,6 +34,7 @@ #include "BKE_particle.h" #include "DNA_image_types.h" +#include "DNA_fluid_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_node_types.h" @@ -981,9 +982,10 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) ModifierData *md; if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Smoke)) && + (md = modifiers_findByType(ob, eModifierType_Fluid)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && - (((SmokeModifierData *)md)->domain != NULL)) { + (((FluidModifierData *)md)->domain != NULL) && + (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) { workbench_volume_cache_populate(vedata, scene, ob, md); return; /* Do not draw solid in this case. */ } diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index dbd7ebfe0d1..90f5d24fabd 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -33,6 +33,7 @@ #include "BKE_particle.h" #include "DNA_image_types.h" +#include "DNA_fluid_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_node_types.h" @@ -618,9 +619,10 @@ void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) ModifierData *md; if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Smoke)) && + (md = modifiers_findByType(ob, eModifierType_Fluid)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && - (((SmokeModifierData *)md)->domain != NULL)) { + (((FluidModifierData *)md)->domain != NULL) && + (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) { workbench_volume_cache_populate(vedata, scene, ob, md); return; /* Do not draw solid in this case. */ } diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index 23f0898c138..2f7296fb40f 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -23,7 +23,7 @@ #include "workbench_private.h" #include "BKE_object.h" -#include "BKE_smoke.h" +#include "BKE_fluid.h" #include "BLI_rand.h" #include "BLI_dynstr.h" @@ -31,7 +31,7 @@ #include "DNA_modifier_types.h" #include "DNA_object_force_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "GPU_draw.h" @@ -119,57 +119,56 @@ void workbench_volume_cache_init(WORKBENCH_Data *vedata) } void workbench_volume_cache_populate(WORKBENCH_Data *vedata, - Scene *scene, + Scene *UNUSED(scene), Object *ob, ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *)md; - SmokeDomainSettings *sds = smd->domain; + FluidModifierData *mmd = (FluidModifierData *)md; + FluidDomainSettings *mds = mmd->domain; WORKBENCH_PrivateData *wpd = vedata->stl->g_data; WORKBENCH_EffectInfo *effect_info = vedata->stl->effects; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DRWShadingGroup *grp = NULL; - /* Don't show smoke before simulation starts, this could be made an option in the future. */ - if (!sds->fluid || CFRA < sds->point_cache[0]->startframe) { + /* Don't try to show liquid domains here */ + if (!mds->fluid || !(mds->type == FLUID_DOMAIN_TYPE_GAS)) { return; } wpd->volumes_do = true; - const bool show_highres = BKE_smoke_show_highres(scene, sds); - if (sds->use_coba) { - GPU_create_smoke_coba_field(smd); + if (mds->use_coba) { + GPU_create_smoke_coba_field(mmd); } - else if (!sds->wt || !show_highres) { - GPU_create_smoke(smd, 0); + else if (!(mds->flags & FLUID_DOMAIN_USE_NOISE)) { + GPU_create_smoke(mmd, 0); } - else if (sds->wt && show_highres) { - GPU_create_smoke(smd, 1); + else if (mds->flags & FLUID_DOMAIN_USE_NOISE) { + GPU_create_smoke(mmd, 1); } - if ((!sds->use_coba && sds->tex == NULL) || (sds->use_coba && sds->tex_field == NULL)) { + if ((!mds->use_coba && mds->tex == NULL) || (mds->use_coba && mds->tex_field == NULL)) { return; } - const bool use_slice = (sds->slice_method == MOD_SMOKE_SLICE_AXIS_ALIGNED && - sds->axis_slice_method == AXIS_SLICE_SINGLE); - const bool cubic_interp = (sds->interp_method == VOLUME_INTERP_CUBIC); - GPUShader *sh = volume_shader_get(use_slice, sds->use_coba, cubic_interp); + const bool use_slice = (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED && + mds->axis_slice_method == AXIS_SLICE_SINGLE); + const bool cubic_interp = (mds->interp_method == VOLUME_INTERP_CUBIC); + GPUShader *sh = volume_shader_get(use_slice, mds->use_coba, cubic_interp); if (use_slice) { float invviewmat[4][4]; DRW_view_viewmat_get(NULL, invviewmat, true); - const int axis = (sds->slice_axis == SLICE_AXIS_AUTO) ? + const int axis = (mds->slice_axis == SLICE_AXIS_AUTO) ? axis_dominant_v3_single(invviewmat[2]) : - sds->slice_axis - 1; + mds->slice_axis - 1; float dim[3]; BKE_object_dimensions_get(ob, dim); /* 0.05f to achieve somewhat the same opacity as the full view. */ float step_length = max_ff(1e-16f, dim[axis] * 0.05f); grp = DRW_shgroup_create(sh, vedata->psl->volume_pass); - DRW_shgroup_uniform_float_copy(grp, "slicePosition", sds->slice_depth); + DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth); DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis); DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); DRW_shgroup_state_disable(grp, DRW_STATE_CULL_FRONT); @@ -178,8 +177,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, double noise_ofs; BLI_halton_1d(3, 0.0, effect_info->jitter_index, &noise_ofs); float dim[3], step_length, max_slice; - float slice_ct[3] = {sds->res[0], sds->res[1], sds->res[2]}; - mul_v3_fl(slice_ct, max_ff(0.001f, sds->slice_per_voxel)); + float slice_ct[3] = {mds->res[0], mds->res[1], mds->res[2]}; + mul_v3_fl(slice_ct, max_ff(0.001f, mds->slice_per_voxel)); max_slice = max_fff(slice_ct[0], slice_ct[1], slice_ct[2]); BKE_object_dimensions_get(ob, dim); invert_v3(slice_ct); @@ -194,25 +193,25 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, DRW_shgroup_state_enable(grp, DRW_STATE_CULL_FRONT); } - if (sds->use_coba) { - DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex_field); - DRW_shgroup_uniform_texture(grp, "transferTexture", sds->tex_coba); + if (mds->use_coba) { + DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex_field); + DRW_shgroup_uniform_texture(grp, "transferTexture", mds->tex_coba); } else { static float white[3] = {1.0f, 1.0f, 1.0f}; - bool use_constant_color = ((sds->active_fields & SM_ACTIVE_COLORS) == 0 && - (sds->active_fields & SM_ACTIVE_COLOR_SET) != 0); - DRW_shgroup_uniform_texture(grp, "densityTexture", sds->tex); - DRW_shgroup_uniform_texture(grp, "shadowTexture", sds->tex_shadow); + bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && + (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); + DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex); + DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow); DRW_shgroup_uniform_texture( - grp, "flameTexture", (sds->tex_flame) ? sds->tex_flame : e_data.dummy_tex); + grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex); DRW_shgroup_uniform_texture( - grp, "flameColorTexture", (sds->tex_flame) ? sds->tex_flame_coba : e_data.dummy_coba_tex); + grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : e_data.dummy_coba_tex); DRW_shgroup_uniform_vec3( - grp, "activeColor", (use_constant_color) ? sds->active_color : white, 1); + grp, "activeColor", (use_constant_color) ? mds->active_color : white, 1); } DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * sds->display_thickness); + DRW_shgroup_uniform_float_copy(grp, "densityScale", 10.0f * mds->display_thickness); if (use_slice) { DRW_shgroup_call(grp, DRW_cache_quad_get(), ob); @@ -221,7 +220,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, DRW_shgroup_call(grp, DRW_cache_cube_get(), ob); } - BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(smd)); + BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(mmd)); } void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd) @@ -233,8 +232,8 @@ void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd) * modifier is not used for display. We should share them for * all viewport in a redraw at least. */ for (LinkData *link = wpd->smoke_domains.first; link; link = link->next) { - SmokeModifierData *smd = (SmokeModifierData *)link->data; - GPU_free_smoke(smd); + FluidModifierData *mmd = (FluidModifierData *)link->data; + GPU_free_smoke(mmd); } BLI_freelistN(&wpd->smoke_domains); } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index a486eb6ba77..97afb5e6aa4 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -23,10 +23,8 @@ #ifndef __DRAW_COMMON_H__ #define __DRAW_COMMON_H__ -struct DRWCallBuffer; struct DRWPass; struct DRWShadingGroup; -struct GPUBatch; struct GPUMaterial; struct ModifierData; struct Object; diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c index 9462a0d8072..38e8544de07 100644 --- a/source/blender/draw/intern/draw_manager_text.c +++ b/source/blender/draw/intern/draw_manager_text.c @@ -526,4 +526,4 @@ void DRW_text_edit_mesh_measure_stats(ARegion *ar, } } } -}
\ No newline at end of file +} diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h index a8eb45ee8f5..393645e614a 100644 --- a/source/blender/draw/intern/draw_manager_text.h +++ b/source/blender/draw/intern/draw_manager_text.h @@ -23,11 +23,11 @@ #ifndef __DRAW_MANAGER_TEXT_H__ #define __DRAW_MANAGER_TEXT_H__ -struct DRWTextStore; struct ARegion; -struct View3D; +struct DRWTextStore; struct Object; struct UnitSettings; +struct View3D; struct DRWTextStore *DRW_text_cache_create(void); void DRW_text_cache_destroy(struct DRWTextStore *dt); diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index fd8fe103a2d..4cc0c865093 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -385,9 +385,8 @@ set(ICON_NAMES mod_mask mod_cloth mod_explode - mod_fluidsim mod_multires - mod_smoke + mod_fluid mod_solidify mod_screw mod_vertex_weight diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index 5afb645d9e7..8ffae0f2b66 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -25,7 +25,6 @@ #define __ED_MBALL_H__ struct Base; -struct MetaBall; struct Object; struct UndoType; struct bContext; diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 5f7730a94e3..29bac9df93a 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -27,8 +27,6 @@ /* ******************* Registration Function ********************** */ struct Object; -struct SnapObjectContext; -struct SnapObjectParams; struct bContext; struct wmKeyConfig; struct wmOperatorType; @@ -107,7 +105,6 @@ bool calculateTransformCenter(struct bContext *C, struct Object; struct Scene; -struct TransInfo; struct wmGizmoGroup; struct wmGizmoGroupType; diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 2bf50d3b4b8..44c734e264a 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -560,7 +560,7 @@ DEF_ICON_MODIFIER(MOD_CLOTH) DEF_ICON_MODIFIER(MOD_EXPLODE) DEF_ICON_MODIFIER(MOD_FLUIDSIM) DEF_ICON_MODIFIER(MOD_MULTIRES) -DEF_ICON_MODIFIER(MOD_SMOKE) +DEF_ICON_MODIFIER(MOD_FLUID) DEF_ICON_MODIFIER(MOD_SOLIDIFY) DEF_ICON_MODIFIER(MOD_SCREW) DEF_ICON_MODIFIER(MOD_VERTEX_WEIGHT) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 17247736d3b..2c93f35e02a 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1819,11 +1819,13 @@ static int modifier_can_delete(ModifierData *md) { /* fluid particle modifier can't be deleted here */ if (md->type == eModifierType_ParticleSystem) { - if (((ParticleSystemModifierData *)md)->psys->part->type == PART_FLUID) { + short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type; + if (particle_type == PART_FLUID || particle_type == PART_FLUID_FLIP || + particle_type == PART_FLUID_FOAM || particle_type == PART_FLUID_SPRAY || + particle_type == PART_FLUID_BUBBLE || particle_type == PART_FLUID_BUBBLE) { return 0; } } - return 1; } @@ -1836,7 +1838,7 @@ static int modifier_is_simulation(ModifierData *md) eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, - eModifierType_Smoke, + eModifierType_Fluid, eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint)) { @@ -2069,7 +2071,7 @@ static uiLayout *draw_modifier(uiLayout *layout, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, - eModifierType_Smoke)) { + eModifierType_Fluid)) { uiItemO(row, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE, diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt index 021c17a94c2..0998280c381 100644 --- a/source/blender/editors/physics/CMakeLists.txt +++ b/source/blender/editors/physics/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc + ../../../../intern/mantaflow/extern ) set(INC_SYS @@ -56,19 +57,10 @@ set(LIB ) if(WITH_MOD_FLUID) - list(APPEND INC - ../../../../intern/elbeem/extern - ) - list(APPEND LIB - bf_intern_elbeem - ) - add_definitions(-DWITH_MOD_FLUID) -endif() - -if(WITH_MOD_SMOKE) list(APPEND LIB - bf_intern_smoke + bf_intern_mantaflow ) + add_definitions(-DWITH_FLUID) endif() if(WITH_INTERNATIONAL) diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index cfb3a400f47..4df74434c6a 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1065,7 +1065,7 @@ static void remove_particle_systems_from_object(Object *ob_to) if (ELEM(md->type, eModifierType_ParticleSystem, eModifierType_DynamicPaint, - eModifierType_Smoke)) { + eModifierType_Fluid)) { BLI_remlink(&ob_to->modifiers, md); modifier_free(md); } diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 44858e36fab..5414c2a44a2 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -18,7 +18,7 @@ */ /** \file - * \ingroup edphys + * \ingroup edphys */ #include <math.h> @@ -31,1219 +31,808 @@ /* types */ #include "DNA_action_types.h" #include "DNA_object_types.h" -#include "DNA_object_fluidsim_types.h" +#include "BLI_blenlib.h" +#include "BLI_path_util.h" +#include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "BKE_context.h" #include "BKE_customdata.h" -#include "BKE_fluidsim.h" +#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_fluid.h" +#include "BKE_global.h" #include "DEG_depsgraph.h" #include "ED_screen.h" -#include "ED_object.h" +#include "PIL_time.h" #include "WM_types.h" #include "WM_api.h" #include "physics_intern.h" // own include +#include "manta_fluid_API.h" + +#include "DNA_scene_types.h" +#include "DNA_fluid_types.h" +#include "DNA_mesh_types.h" + +#define FLUID_JOB_BAKE_ALL "FLUID_OT_bake_all" +#define FLUID_JOB_BAKE_DATA "FLUID_OT_bake_data" +#define FLUID_JOB_BAKE_NOISE "FLUID_OT_bake_noise" +#define FLUID_JOB_BAKE_MESH "FLUID_OT_bake_mesh" +#define FLUID_JOB_BAKE_PARTICLES "FLUID_OT_bake_particles" +#define FLUID_JOB_BAKE_GUIDES "FLUID_OT_bake_guides" +#define FLUID_JOB_FREE_ALL "FLUID_OT_free_all" +#define FLUID_JOB_FREE_DATA "FLUID_OT_free_data" +#define FLUID_JOB_FREE_NOISE "FLUID_OT_free_noise" +#define FLUID_JOB_FREE_MESH "FLUID_OT_free_mesh" +#define FLUID_JOB_FREE_PARTICLES "FLUID_OT_free_particles" +#define FLUID_JOB_FREE_GUIDES "FLUID_OT_free_guides" +#define FLUID_JOB_BAKE_PAUSE "FLUID_OT_pause_bake" + +typedef struct FluidJob { + /* from wmJob */ + void *owner; + short *stop, *do_update; + float *progress; + const char *type; + const char *name; -/* enable/disable overall compilation */ -#ifdef WITH_MOD_FLUID - -# include "LBM_fluidsim.h" - -# include "BLI_blenlib.h" -# include "BLI_path_util.h" -# include "BLI_math.h" + struct Main *bmain; + Scene *scene; + Depsgraph *depsgraph; + Object *ob; -# include "BKE_global.h" -# include "BKE_main.h" + FluidModifierData *mmd; -# include "WM_api.h" + int success; + double start; -# include "DNA_scene_types.h" -# include "DNA_mesh_types.h" + int *pause_frame; +} FluidJob; -static float get_fluid_viscosity(FluidsimSettings *settings) +static inline bool fluid_is_bake_all(FluidJob *job) { - return (1.0f / powf(10.0f, settings->viscosityExponent)) * settings->viscosityValue; + return (STREQ(job->type, FLUID_JOB_BAKE_ALL)); } - -static float get_fluid_rate(FluidsimSettings *settings) +static inline bool fluid_is_bake_data(FluidJob *job) { - float rate = 1.0f; /* default rate if not animated... */ - - rate = settings->animRate; - - if (rate < 0.0f) { - rate = 0.0f; - } - - return rate; + return (STREQ(job->type, FLUID_JOB_BAKE_DATA)); } - -static void get_fluid_gravity(float *gravity, Scene *scene, FluidsimSettings *fss) +static inline bool fluid_is_bake_noise(FluidJob *job) { - if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { - copy_v3_v3(gravity, scene->physics_settings.gravity); - } - else { - copy_v3_v3(gravity, fss->grav); - } + return (STREQ(job->type, FLUID_JOB_BAKE_NOISE)); } - -static float get_fluid_size_m(Scene *scene, Object *domainob, FluidsimSettings *fss) +static inline bool fluid_is_bake_mesh(FluidJob *job) { - if (!scene->unit.system) { - return fss->realsize; - } - else { - float dim[3]; - float longest_axis; - - BKE_object_dimensions_get(domainob, dim); - longest_axis = max_fff(dim[0], dim[1], dim[2]); - - return longest_axis * scene->unit.scale_length; - } + return (STREQ(job->type, FLUID_JOB_BAKE_MESH)); } - -static bool fluid_is_animated_mesh(FluidsimSettings *fss) +static inline bool fluid_is_bake_particle(FluidJob *job) { - return ((fss->type == OB_FLUIDSIM_CONTROL) || fss->domainNovecgen); + return (STREQ(job->type, FLUID_JOB_BAKE_PARTICLES)); } - -/* ********************** fluid sim settings struct functions ********************** */ - -# if 0 -/* helper function */ -void fluidsimGetGeometryObjFilename(Object *ob, char *dst) //, char *srcname) +static inline bool fluid_is_bake_guiding(FluidJob *job) { - //BLI_snprintf(dst, FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name); - BLI_snprintf(dst, FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name); + return (STREQ(job->type, FLUID_JOB_BAKE_GUIDES)); } -# endif - -/* ********************** fluid sim channel helper functions ********************** */ - -typedef struct FluidAnimChannels { - int length; - - double aniFrameTime; - - float *timeAtFrame; - float *DomainTime; - float *DomainGravity; - float *DomainViscosity; -} FluidAnimChannels; - -typedef struct FluidObject { - struct FluidObject *next, *prev; - - struct Object *object; - - float *Translation; - float *Rotation; - float *Scale; - float *Active; - - float *InitialVelocity; - - float *AttractforceStrength; - float *AttractforceRadius; - float *VelocityforceStrength; - float *VelocityforceRadius; - - float *VertexCache; - int numVerts, numTris; -} FluidObject; - -// no. of entries for the two channel sizes -# define CHANNEL_FLOAT 1 -# define CHANNEL_VEC 3 - -// simplify channels before printing -// for API this is done anyway upon init -# if 0 -static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries) +static inline bool fluid_is_free_all(FluidJob *job) { - int i, j; - int channelSize = paramsize; - - if (entries == 3) { - elbeemSimplifyChannelVec3(channel, &channelSize); - } - else if (entries == 1) { - elbeemSimplifyChannelFloat(channel, &channelSize); - } - else { - /* invalid, cant happen? */ - } - - fprintf(file, " CHANNEL %s =\n", str); - for (i = 0; i < channelSize; i++) { - fprintf(file, " "); - for (j = 0; j <= entries; j++) { // also print time value - fprintf(file, " %f ", channel[i * (entries + 1) + j]); - if (j == entries - 1) { - fprintf(file, " "); - } - } - fprintf(file, "\n"); - } - - fprintf(file, " ;\n"); + return (STREQ(job->type, FLUID_JOB_FREE_ALL)); } -# endif - -/* Note: fluid anim channel data layout - * ------------------------------------ - * CHANNEL_FLOAT: - * frame 1 |frame 2 - * [dataF][time][dataF][time] - * - * CHANNEL_VEC: - * frame 1 |frame 2 - * [dataX][dataY][dataZ][time][dataX][dataY][dataZ][time] - */ - -static void init_time(FluidsimSettings *domainSettings, FluidAnimChannels *channels) +static inline bool fluid_is_free_data(FluidJob *job) { - int i; - - channels->timeAtFrame = MEM_callocN((channels->length + 1) * sizeof(float), - "timeAtFrame channel"); - - channels->timeAtFrame[0] = channels->timeAtFrame[1] = - domainSettings->animStart; // start at index 1 - - for (i = 2; i <= channels->length; i++) { - channels->timeAtFrame[i] = channels->timeAtFrame[i - 1] + (float)channels->aniFrameTime; - } + return (STREQ(job->type, FLUID_JOB_FREE_DATA)); } - -/* if this is slow, can replace with faster, less readable code */ -static void set_channel(float *channel, float time, float *value, int i, int size) +static inline bool fluid_is_free_noise(FluidJob *job) { - if (size == CHANNEL_FLOAT) { - channel[(i * 2) + 0] = value[0]; - channel[(i * 2) + 1] = time; - } - else if (size == CHANNEL_VEC) { - channel[(i * 4) + 0] = value[0]; - channel[(i * 4) + 1] = value[1]; - channel[(i * 4) + 2] = value[2]; - channel[(i * 4) + 3] = time; - } + return (STREQ(job->type, FLUID_JOB_FREE_NOISE)); } - -static void set_vertex_channel(Depsgraph *depsgraph, - float *channel, - float time, - struct Scene *scene, - struct FluidObject *fobj, - int i) +static inline bool fluid_is_free_mesh(FluidJob *job) { - Object *ob = fobj->object; - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType( - ob, eModifierType_Fluidsim); - float *verts; - int *tris = NULL, numVerts = 0, numTris = 0; - int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd); - int framesize = (3 * fobj->numVerts) + 1; - int j; - - if (channel == NULL) { - return; - } + return (STREQ(job->type, FLUID_JOB_FREE_MESH)); +} +static inline bool fluid_is_free_particles(FluidJob *job) +{ + return (STREQ(job->type, FLUID_JOB_FREE_PARTICLES)); +} +static inline bool fluid_is_free_guiding(FluidJob *job) +{ + return (STREQ(job->type, FLUID_JOB_FREE_GUIDES)); +} - initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 1, modifierIndex); +static bool fluid_initjob( + bContext *C, FluidJob *job, wmOperator *op, char *error_msg, int error_size) +{ + FluidModifierData *mmd = NULL; + FluidDomainSettings *mds; + Object *ob = CTX_data_active_object(C); - /* don't allow mesh to change number of verts in anim sequence */ - if (numVerts != fobj->numVerts) { - MEM_freeN(channel); - channel = NULL; - return; + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + if (!mmd) { + BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size); + return false; } - - /* fill frame of channel with vertex locations */ - for (j = 0; j < (3 * numVerts); j++) { - channel[i * framesize + j] = verts[j]; + mds = mmd->domain; + if (!mds) { + BLI_strncpy(error_msg, N_("Bake failed: invalid domain"), error_size); + return false; } - channel[i * framesize + framesize - 1] = time; - MEM_freeN(verts); - MEM_freeN(tris); -} + job->bmain = CTX_data_main(C); + job->scene = CTX_data_scene(C); + job->depsgraph = CTX_data_depsgraph_pointer(C); + job->ob = CTX_data_active_object(C); + job->mmd = mmd; + job->type = op->type->idname; + job->name = op->type->name; -static void free_domain_channels(FluidAnimChannels *channels) -{ - if (!channels->timeAtFrame) { - return; - } - MEM_freeN(channels->timeAtFrame); - channels->timeAtFrame = NULL; - MEM_freeN(channels->DomainGravity); - channels->DomainGravity = NULL; - MEM_freeN(channels->DomainViscosity); - channels->DomainViscosity = NULL; - MEM_freeN(channels->DomainTime); - channels->DomainTime = NULL; + return true; } -static void free_all_fluidobject_channels(ListBase *fobjects) +static bool fluid_initpaths(FluidJob *job, ReportList *reports) { - FluidObject *fobj; - - for (fobj = fobjects->first; fobj; fobj = fobj->next) { - if (fobj->Translation) { - MEM_freeN(fobj->Translation); - fobj->Translation = NULL; - MEM_freeN(fobj->Rotation); - fobj->Rotation = NULL; - MEM_freeN(fobj->Scale); - fobj->Scale = NULL; - MEM_freeN(fobj->Active); - fobj->Active = NULL; - MEM_freeN(fobj->InitialVelocity); - fobj->InitialVelocity = NULL; - } - - if (fobj->AttractforceStrength) { - MEM_freeN(fobj->AttractforceStrength); - fobj->AttractforceStrength = NULL; - MEM_freeN(fobj->AttractforceRadius); - fobj->AttractforceRadius = NULL; - MEM_freeN(fobj->VelocityforceStrength); - fobj->VelocityforceStrength = NULL; - MEM_freeN(fobj->VelocityforceRadius); - fobj->VelocityforceRadius = NULL; - } + FluidDomainSettings *mds = job->mmd->domain; + char temp_dir[FILE_MAX]; + temp_dir[0] = '\0'; - if (fobj->VertexCache) { - MEM_freeN(fobj->VertexCache); - fobj->VertexCache = NULL; - } - } -} + const char *relbase = modifier_path_relbase(job->bmain, job->ob); -static void fluid_init_all_channels(bContext *C, - Depsgraph *depsgraph, - Object *UNUSED(fsDomain), - FluidsimSettings *domainSettings, - FluidAnimChannels *channels, - ListBase *fobjects) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base; - int i; - int length = channels->length; - float eval_time; - - /* init time values (assuming that time moves at a constant speed; may be overridden later) */ - init_time(domainSettings, channels); - - /* allocate domain animation channels */ - channels->DomainGravity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), - "channel DomainGravity"); - channels->DomainViscosity = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float), - "channel DomainViscosity"); - channels->DomainTime = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float), - "channel DomainTime"); - - /* allocate fluid objects */ - for (base = FIRSTBASE(view_layer); base; base = base->next) { - Object *ob = base->object; - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType( - ob, eModifierType_Fluidsim); - - if (fluidmd) { - FluidObject *fobj = MEM_callocN(sizeof(FluidObject), "Fluid Object"); - fobj->object = ob; - - if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) { - BLI_addtail(fobjects, fobj); - continue; - } - - fobj->Translation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), - "fluidobject Translation"); - fobj->Rotation = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), - "fluidobject Rotation"); - fobj->Scale = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), "fluidobject Scale"); - fobj->Active = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float), - "fluidobject Active"); - fobj->InitialVelocity = MEM_callocN(length * (CHANNEL_VEC + 1) * sizeof(float), - "fluidobject InitialVelocity"); - - if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { - fobj->AttractforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float), - "fluidobject AttractforceStrength"); - fobj->AttractforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float), - "fluidobject AttractforceRadius"); - fobj->VelocityforceStrength = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float), - "fluidobject VelocityforceStrength"); - fobj->VelocityforceRadius = MEM_callocN(length * (CHANNEL_FLOAT + 1) * sizeof(float), - "fluidobject VelocityforceRadius"); - } - - if (fluid_is_animated_mesh(fluidmd->fss)) { - float *verts = NULL; - int *tris = NULL, modifierIndex = BLI_findindex(&ob->modifiers, (ModifierData *)fluidmd); - - initElbeemMesh(depsgraph, - scene, - ob, - &fobj->numVerts, - &verts, - &fobj->numTris, - &tris, - 0, - modifierIndex); - fobj->VertexCache = MEM_callocN(length * ((fobj->numVerts * CHANNEL_VEC) + 1) * - sizeof(float), - "fluidobject VertexCache"); - - MEM_freeN(verts); - MEM_freeN(tris); - } - - BLI_addtail(fobjects, fobj); - } + /* We do not accept empty paths, they can end in random places silently, see T51176. */ + if (mds->cache_directory[0] == '\0') { + modifier_path_init( + mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT); + BKE_reportf(reports, + RPT_WARNING, + "Fluid: Empty cache path, reset to default '%s'", + mds->cache_directory); } - /* now we loop over the frames and fill the allocated channels with data */ - for (i = 0; i < channels->length; i++) { - FluidObject *fobj; - float viscosity, gravity[3]; - float timeAtFrame, time; + BLI_strncpy(temp_dir, mds->cache_directory, FILE_MAXDIR); + BLI_path_abs(temp_dir, relbase); - eval_time = domainSettings->bakeStart + i; + /* Ensure whole path exists */ + const bool dir_exists = BLI_dir_create_recursive(temp_dir); - /* Modifying the global scene isn't nice, but we can do it in - * this part of the process before a threaded job is created */ - scene->r.cfra = (int)eval_time; - ED_update_for_newframe(CTX_data_main(C), depsgraph); + /* We change path to some presumably valid default value, but do not allow bake process to + * continue, this gives user chance to set manually another path. */ + if (!dir_exists) { + modifier_path_init( + mds->cache_directory, sizeof(mds->cache_directory), FLUID_DOMAIN_DIR_DEFAULT); - /* now scene data should be current according to animation system, so we fill the channels */ + BKE_reportf(reports, + RPT_ERROR, + "Fluid: Could not create cache directory '%s', reset to default '%s'", + temp_dir, + mds->cache_directory); - /* Domain time */ - /* TODO: have option for not running sim, time mangling, - * in which case second case comes in handy. */ - if (channels->DomainTime) { - time = get_fluid_rate(domainSettings) * (float)channels->aniFrameTime; - timeAtFrame = channels->timeAtFrame[i] + time; + BLI_strncpy(temp_dir, mds->cache_directory, FILE_MAXDIR); + BLI_path_abs(temp_dir, relbase); - channels->timeAtFrame[i + 1] = timeAtFrame; - set_channel(channels->DomainTime, i, &time, i, CHANNEL_FLOAT); - } - else { - timeAtFrame = channels->timeAtFrame[i + 1]; + /* Ensure whole path exists and is writable. */ + if (!BLI_dir_create_recursive(temp_dir)) { + BKE_reportf(reports, + RPT_ERROR, + "Fluid: Could not use default cache directory '%s', " + "please define a valid cache path manually", + temp_dir); } + /* Copy final dir back into domain settings */ + BLI_strncpy(mds->cache_directory, temp_dir, FILE_MAXDIR); - /* Domain properties - gravity/viscosity */ - get_fluid_gravity(gravity, scene, domainSettings); - set_channel(channels->DomainGravity, timeAtFrame, gravity, i, CHANNEL_VEC); - viscosity = get_fluid_viscosity(domainSettings); - set_channel(channels->DomainViscosity, timeAtFrame, &viscosity, i, CHANNEL_FLOAT); - - /* object movement */ - for (fobj = fobjects->first; fobj; fobj = fobj->next) { - Object *ob = fobj->object; - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType( - ob, eModifierType_Fluidsim); - float active = (float)((fluidmd->fss->flag & OB_FLUIDSIM_ACTIVE) ? 1 : 0); - float rot_d[3] = {0.f, 0.f, 0.f}, old_rot[3] = {0.f, 0.f, 0.f}; - - if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) { - continue; - } - - /* init euler rotation values and convert to elbeem format */ - /* get the rotation from ob->obmat rather than ob->rot to account for parent animations */ - if (i) { - copy_v3_v3(old_rot, fobj->Rotation + 4 * (i - 1)); - mul_v3_fl(old_rot, (float)-M_PI / 180.f); - } - - mat4_to_compatible_eulO(rot_d, old_rot, 0, ob->obmat); - mul_v3_fl(rot_d, -180.0f / (float)M_PI); - - set_channel(fobj->Translation, timeAtFrame, ob->loc, i, CHANNEL_VEC); - set_channel(fobj->Rotation, timeAtFrame, rot_d, i, CHANNEL_VEC); - set_channel(fobj->Scale, timeAtFrame, ob->scale, i, CHANNEL_VEC); - set_channel(fobj->Active, timeAtFrame, &active, i, CHANNEL_FLOAT); - set_channel(fobj->InitialVelocity, timeAtFrame, &fluidmd->fss->iniVelx, i, CHANNEL_VEC); - - // printf("Active: %f, Frame: %f\n", active, timeAtFrame); - - if (fluidmd->fss->type == OB_FLUIDSIM_CONTROL) { - set_channel(fobj->AttractforceStrength, - timeAtFrame, - &fluidmd->fss->attractforceStrength, - i, - CHANNEL_FLOAT); - set_channel(fobj->AttractforceRadius, - timeAtFrame, - &fluidmd->fss->attractforceRadius, - i, - CHANNEL_FLOAT); - set_channel(fobj->VelocityforceStrength, - timeAtFrame, - &fluidmd->fss->velocityforceStrength, - i, - CHANNEL_FLOAT); - set_channel(fobj->VelocityforceRadius, - timeAtFrame, - &fluidmd->fss->velocityforceRadius, - i, - CHANNEL_FLOAT); - } - - if (fluid_is_animated_mesh(fluidmd->fss)) { - set_vertex_channel(depsgraph, fobj->VertexCache, timeAtFrame, scene, fobj, i); - } - } + return false; } + + /* Copy final dir back into domain settings */ + BLI_strncpy(mds->cache_directory, temp_dir, FILE_MAXDIR); + return true; } -static void export_fluid_objects(Depsgraph *depsgraph, - ListBase *fobjects, - Scene *scene, - int length) +static void fluid_bake_free(void *customdata) { - FluidObject *fobj; - - for (fobj = fobjects->first; fobj; fobj = fobj->next) { - Object *ob = fobj->object; - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType( - ob, eModifierType_Fluidsim); - int modifierIndex = BLI_findindex(&ob->modifiers, fluidmd); + FluidJob *job = customdata; + MEM_freeN(job); +} - float *verts = NULL; - int *tris = NULL; - int numVerts = 0, numTris = 0; - bool deform = fluid_is_animated_mesh(fluidmd->fss); +static void fluid_bake_sequence(FluidJob *job) +{ + FluidDomainSettings *mds = job->mmd->domain; + Scene *scene = job->scene; + int frame = 1, orig_frame; + int frames; + int *pause_frame = NULL; + bool is_first_frame; - elbeemMesh fsmesh; + frames = mds->cache_frame_end - mds->cache_frame_start + 1; - if (ELEM(fluidmd->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) { - continue; - } + if (frames <= 0) { + BLI_strncpy(mds->error, N_("No frames to bake"), sizeof(mds->error)); + return; + } - elbeemResetMesh(&fsmesh); + /* Show progress bar. */ + if (job->do_update) { + *(job->do_update) = true; + } - fsmesh.type = fluidmd->fss->type; - fsmesh.name = ob->id.name; + /* Get current pause frame (pointer) - depending on bake type */ + pause_frame = job->pause_frame; - initElbeemMesh(depsgraph, scene, ob, &numVerts, &verts, &numTris, &tris, 0, modifierIndex); + /* Set frame to start point (depending on current pause frame value) */ + is_first_frame = ((*pause_frame) == 0); + frame = is_first_frame ? mds->cache_frame_start : (*pause_frame); - fsmesh.numVertices = numVerts; - fsmesh.numTriangles = numTris; - fsmesh.vertices = verts; - fsmesh.triangles = tris; + /* Save orig frame and update scene frame */ + orig_frame = CFRA; + CFRA = frame; - fsmesh.channelSizeTranslation = fsmesh.channelSizeRotation = fsmesh.channelSizeScale = - fsmesh.channelSizeInitialVel = fsmesh.channelSizeActive = length; + /* Loop through selected frames */ + for (; frame <= mds->cache_frame_end; frame++) { + const float progress = (frame - mds->cache_frame_start) / (float)frames; - fsmesh.channelTranslation = fobj->Translation; - fsmesh.channelRotation = fobj->Rotation; - fsmesh.channelScale = fobj->Scale; - fsmesh.channelActive = fobj->Active; + /* Keep track of pause frame - needed to init future loop */ + (*pause_frame) = frame; - if (ELEM(fsmesh.type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) { - fsmesh.channelInitialVel = fobj->InitialVelocity; - fsmesh.localInivelCoords = ((fluidmd->fss->typeFlags & OB_FSINFLOW_LOCALCOORD) ? 1 : 0); + /* If user requested stop, quit baking */ + if (G.is_break) { + job->success = 0; + return; } - if (fluidmd->fss->typeFlags & OB_FSBND_NOSLIP) { - fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; - } - else if (fluidmd->fss->typeFlags & OB_FSBND_PARTSLIP) { - fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP; + /* Update progress bar */ + if (job->do_update) { + *(job->do_update) = true; } - else if (fluidmd->fss->typeFlags & OB_FSBND_FREESLIP) { - fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP; + if (job->progress) { + *(job->progress) = progress; } - fsmesh.obstaclePartslip = fluidmd->fss->partSlipValue; - fsmesh.volumeInitType = fluidmd->fss->volumeInitType; - fsmesh.obstacleImpactFactor = fluidmd->fss->surfaceSmoothing; // misused value - - if (fsmesh.type == OB_FLUIDSIM_CONTROL) { - fsmesh.cpsTimeStart = fluidmd->fss->cpsTimeStart; - fsmesh.cpsTimeEnd = fluidmd->fss->cpsTimeEnd; - fsmesh.cpsQuality = fluidmd->fss->cpsQuality; - fsmesh.obstacleType = (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE); + CFRA = frame; - fsmesh.channelSizeAttractforceRadius = fsmesh.channelSizeVelocityforceStrength = - fsmesh.channelSizeVelocityforceRadius = fsmesh.channelSizeAttractforceStrength = length; - - fsmesh.channelAttractforceStrength = fobj->AttractforceStrength; - fsmesh.channelAttractforceRadius = fobj->AttractforceRadius; - fsmesh.channelVelocityforceStrength = fobj->VelocityforceStrength; - fsmesh.channelVelocityforceRadius = fobj->VelocityforceRadius; - } - else { - fsmesh.channelAttractforceStrength = fsmesh.channelAttractforceRadius = - fsmesh.channelVelocityforceStrength = fsmesh.channelVelocityforceRadius = NULL; - } - - /* animated meshes */ - if (deform) { - fsmesh.channelSizeVertices = length; - fsmesh.channelVertices = fobj->VertexCache; - - /* remove channels */ - fsmesh.channelTranslation = fsmesh.channelRotation = fsmesh.channelScale = NULL; - - /* Override user settings, only noslip is supported here! */ - if (fsmesh.type != OB_FLUIDSIM_CONTROL) { - fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP; - } - } + /* Update animation system */ + ED_update_for_newframe(job->bmain, job->depsgraph); + } - elbeemAddMesh(&fsmesh); + /* Restore frame position that we were on before bake */ + CFRA = orig_frame; +} - if (verts) { - MEM_freeN(verts); +static void fluid_bake_endjob(void *customdata) +{ + FluidJob *job = customdata; + FluidDomainSettings *mds = job->mmd->domain; + + if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) { + mds->cache_flag &= ~FLUID_DOMAIN_BAKING_NOISE; + mds->cache_flag |= FLUID_DOMAIN_BAKED_NOISE; + mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_NOISE; + } + if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) { + mds->cache_flag &= ~FLUID_DOMAIN_BAKING_MESH; + mds->cache_flag |= FLUID_DOMAIN_BAKED_MESH; + mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_MESH; + } + if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) { + mds->cache_flag &= ~FLUID_DOMAIN_BAKING_PARTICLES; + mds->cache_flag |= FLUID_DOMAIN_BAKED_PARTICLES; + mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_PARTICLES; + } + if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) { + mds->cache_flag &= ~FLUID_DOMAIN_BAKING_GUIDE; + mds->cache_flag |= FLUID_DOMAIN_BAKED_GUIDE; + mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_GUIDE; + } + if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) { + mds->cache_flag &= ~FLUID_DOMAIN_BAKING_DATA; + mds->cache_flag |= FLUID_DOMAIN_BAKED_DATA; + mds->cache_flag &= ~FLUID_DOMAIN_OUTDATED_DATA; + } + DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY); + + G.is_rendering = false; + BKE_spacedata_draw_locks(false); + WM_set_locked_interface(G_MAIN->wm.first, false); + + /* Bake was successful: + * Report for ended bake and how long it took */ + if (job->success) { + /* Show bake info */ + WM_reportf( + RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start); + } + else { + if (mds->error != NULL && mds->error[0] != '\0') { + WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error); } - if (tris) { - MEM_freeN(tris); + else { /* User canceled the bake */ + WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name); } } } -static int fluid_validate_scene(ReportList *reports, ViewLayer *view_layer, Object *fsDomain) +static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, float *progress) { - Base *base; - Object *newdomain = NULL; - int channelObjCount = 0; - int fluidInputCount = 0; - - for (base = FIRSTBASE(view_layer); base; base = base->next) { - Object *ob = base->object; - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType( - ob, eModifierType_Fluidsim); - - /* only find objects with fluid modifiers */ - if (!fluidmdtmp || ob->type != OB_MESH) { - continue; - } - - if (fluidmdtmp->fss->type == OB_FLUIDSIM_DOMAIN) { - /* if no initial domain object given, find another potential domain */ - if (!fsDomain) { - newdomain = ob; - } - /* if there's more than one domain, cancel */ - else if (fsDomain && ob != fsDomain) { - BKE_report(reports, RPT_ERROR, "There should be only one domain object"); - return 0; - } - } - - /* count number of objects needed for animation channels */ - if (!ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_DOMAIN, OB_FLUIDSIM_PARTICLE)) { - channelObjCount++; - } - - /* count number of fluid input objects */ - if (ELEM(fluidmdtmp->fss->type, OB_FLUIDSIM_FLUID, OB_FLUIDSIM_INFLOW)) { - fluidInputCount++; + FluidJob *job = customdata; + FluidDomainSettings *mds = job->mmd->domain; + + char temp_dir[FILE_MAX]; + + job->stop = stop; + job->do_update = do_update; + job->progress = progress; + job->start = PIL_check_seconds_timer(); + job->success = 1; + + G.is_break = false; + G.is_rendering = true; + BKE_spacedata_draw_locks(true); + + if (fluid_is_bake_noise(job) || fluid_is_bake_all(job)) { + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_NOISE, NULL); + BLI_dir_create_recursive(temp_dir); /* Create 'noise' subdir if it does not exist already */ + mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_OUTDATED_NOISE); + mds->cache_flag |= FLUID_DOMAIN_BAKING_NOISE; + job->pause_frame = &mds->cache_frame_pause_noise; + } + if (fluid_is_bake_mesh(job) || fluid_is_bake_all(job)) { + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_MESH, NULL); + BLI_dir_create_recursive(temp_dir); /* Create 'mesh' subdir if it does not exist already */ + mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_MESH | FLUID_DOMAIN_OUTDATED_MESH); + mds->cache_flag |= FLUID_DOMAIN_BAKING_MESH; + job->pause_frame = &mds->cache_frame_pause_mesh; + } + if (fluid_is_bake_particle(job) || fluid_is_bake_all(job)) { + BLI_path_join( + temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_PARTICLES, NULL); + BLI_dir_create_recursive( + temp_dir); /* Create 'particles' subdir if it does not exist already */ + mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_OUTDATED_PARTICLES); + mds->cache_flag |= FLUID_DOMAIN_BAKING_PARTICLES; + job->pause_frame = &mds->cache_frame_pause_particles; + } + if (fluid_is_bake_guiding(job) || fluid_is_bake_all(job)) { + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_GUIDE, NULL); + BLI_dir_create_recursive(temp_dir); /* Create 'guiding' subdir if it does not exist already */ + mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_GUIDE | FLUID_DOMAIN_OUTDATED_GUIDE); + mds->cache_flag |= FLUID_DOMAIN_BAKING_GUIDE; + job->pause_frame = &mds->cache_frame_pause_guide; + } + if (fluid_is_bake_data(job) || fluid_is_bake_all(job)) { + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_CONFIG, NULL); + BLI_dir_create_recursive(temp_dir); /* Create 'config' subdir if it does not exist already */ + + BLI_path_join(temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_DATA, NULL); + BLI_dir_create_recursive(temp_dir); /* Create 'data' subdir if it does not exist already */ + mds->cache_flag &= ~(FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_OUTDATED_DATA); + mds->cache_flag |= FLUID_DOMAIN_BAKING_DATA; + job->pause_frame = &mds->cache_frame_pause_data; + + if (mds->flags & FLUID_DOMAIN_EXPORT_MANTA_SCRIPT) { + BLI_path_join( + temp_dir, sizeof(temp_dir), mds->cache_directory, FLUID_DOMAIN_DIR_SCRIPT, NULL); + BLI_dir_create_recursive(temp_dir); /* Create 'script' subdir if it does not exist already */ } } + DEG_id_tag_update(&job->ob->id, ID_RECALC_GEOMETRY); - if (newdomain) { - fsDomain = newdomain; - } + fluid_bake_sequence(job); - if (!fsDomain) { - BKE_report(reports, RPT_ERROR, "No domain object found"); - return 0; + if (do_update) { + *do_update = true; } - - if (channelObjCount >= 255) { - BKE_report(reports, RPT_ERROR, "Cannot bake with more than 256 objects"); - return 0; + if (stop) { + *stop = 0; } - - if (fluidInputCount == 0) { - BKE_report(reports, RPT_ERROR, "No fluid input objects in the scene"); - return 0; - } - - return 1; } -# define FLUID_SUFFIX_CONFIG "fluidsim.cfg" -# define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp") -# define FLUID_SUFFIX_SURFACE "fluidsurface" - -static bool fluid_init_filepaths(Main *bmain, - ReportList *reports, - FluidsimSettings *domainSettings, - Object *fsDomain, - char *targetDir, - char *targetFile) +static void fluid_free_endjob(void *customdata) { - const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; + FluidJob *job = customdata; + FluidDomainSettings *mds = job->mmd->domain; - /* prepare names... */ - const char *relbase = modifier_path_relbase(bmain, fsDomain); + G.is_rendering = false; + BKE_spacedata_draw_locks(false); + WM_set_locked_interface(G_MAIN->wm.first, false); - /* We do not accept empty paths, they can end in random places silently, see T51176. */ - if (domainSettings->surfdataPath[0] == '\0') { - modifier_path_init(domainSettings->surfdataPath, - sizeof(domainSettings->surfdataPath), - OB_FLUIDSIM_SURF_DIR_DEFAULT); - BKE_reportf(reports, - RPT_WARNING, - "Fluidsim: empty cache path, reset to default '%s'", - domainSettings->surfdataPath); + /* Free was successful: + * Report for ended free job and how long it took */ + if (job->success) { + /* Show free job info */ + WM_reportf( + RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start); } - - BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); - BLI_path_abs(targetDir, relbase); - - /* .tmp: don't overwrite/delete original file */ - BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); - - /* Ensure whole path exists and is writeable. */ - const bool dir_exists = BLI_dir_create_recursive(targetDir); - const bool is_writable = BLI_file_is_writable(targetFile); - - /* We change path to some presumably valid default value, - * but do not allow bake process to continue, - * this gives user chance to set manually another path. */ - if (!dir_exists || !is_writable) { - modifier_path_init(domainSettings->surfdataPath, - sizeof(domainSettings->surfdataPath), - OB_FLUIDSIM_SURF_DIR_DEFAULT); - - if (!dir_exists) { - BKE_reportf(reports, - RPT_ERROR, - "Fluidsim: could not create cache directory '%s', reset to default '%s'", - targetDir, - domainSettings->surfdataPath); + else { + if (mds->error != NULL && mds->error[0] != '\0') { + WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error); } - else { - BKE_reportf(reports, - RPT_ERROR, - "Fluidsim: cache directory '%s' is not writable, reset to default '%s'", - targetDir, - domainSettings->surfdataPath); + else { /* User canceled the free job */ + WM_reportf(RPT_WARNING, "Fluid: %s canceled!", job->name); } - - BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); - BLI_path_abs(targetDir, relbase); - - /* .tmp: don't overwrite/delete original file */ - BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); - - /* Ensure whole path exists and is writeable. */ - if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) { - BKE_reportf(reports, - RPT_ERROR, - "Fluidsim: could not use default cache directory '%s', " - "please define a valid cache path manually", - targetDir); - } - return false; } - - return true; } -/* ******************************************************************************** */ -/* ********************** write fluidsim config to file ************************* */ -/* ******************************************************************************** */ +static void fluid_free_startjob(void *customdata, short *stop, short *do_update, float *progress) +{ + FluidJob *job = customdata; + FluidDomainSettings *mds = job->mmd->domain; + Scene *scene = job->scene; -typedef struct FluidBakeJob { - /* from wmJob */ - void *owner; - short *stop, *do_update; - float *progress; - int current_frame; - elbeemSimulationSettings *settings; -} FluidBakeJob; + job->stop = stop; + job->do_update = do_update; + job->progress = progress; + job->start = PIL_check_seconds_timer(); + job->success = 1; -static void fluidbake_free(void *customdata) -{ - FluidBakeJob *fb = (FluidBakeJob *)customdata; - MEM_freeN(fb); -} + G.is_break = false; + G.is_rendering = true; + BKE_spacedata_draw_locks(true); -/* called by fluidbake, only to check job 'stop' value */ -static int fluidbake_breakjob(void *customdata) -{ - FluidBakeJob *fb = (FluidBakeJob *)customdata; + int cache_map = 0; - if (fb->stop && *(fb->stop)) { - return 1; + if (fluid_is_free_data(job) || fluid_is_free_all(job)) { + cache_map |= (FLUID_DOMAIN_OUTDATED_DATA | FLUID_DOMAIN_OUTDATED_NOISE | + FLUID_DOMAIN_OUTDATED_MESH | FLUID_DOMAIN_OUTDATED_PARTICLES); + } + if (fluid_is_free_noise(job) || fluid_is_free_all(job)) { + cache_map |= FLUID_DOMAIN_OUTDATED_NOISE; + } + if (fluid_is_free_mesh(job) || fluid_is_free_all(job)) { + cache_map |= FLUID_DOMAIN_OUTDATED_MESH; + } + if (fluid_is_free_particles(job) || fluid_is_free_all(job)) { + cache_map |= FLUID_DOMAIN_OUTDATED_PARTICLES; + } + if (fluid_is_free_guiding(job) || fluid_is_free_all(job)) { + cache_map |= FLUID_DOMAIN_OUTDATED_GUIDE; } +#ifdef WITH_FLUID + BKE_fluid_cache_free(mds, job->ob, cache_map); +#endif - /* this is not nice yet, need to make the jobs list template better - * for identifying/acting upon various different jobs */ - /* but for now we'll reuse the render break... */ - return (G.is_break); -} + *do_update = true; + *stop = 0; -/* called by fluidbake, wmJob sends notifier */ -static void fluidbake_updatejob(void *customdata, float progress) -{ - FluidBakeJob *fb = (FluidBakeJob *)customdata; + /* Reset scene frame to cache frame start */ + CFRA = mds->cache_frame_start; - *(fb->do_update) = true; - *(fb->progress) = progress; + /* Update scene so that viewport shows freed up scene */ + ED_update_for_newframe(job->bmain, job->depsgraph); } -static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress) -{ - FluidBakeJob *fb = (FluidBakeJob *)customdata; +/***************************** Operators ******************************/ - fb->stop = stop; - fb->do_update = do_update; - fb->progress = progress; +static int fluid_bake_exec(struct bContext *C, struct wmOperator *op) +{ + FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob"); + char error_msg[256] = "\0"; - G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */ + if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) { + if (error_msg[0]) { + BKE_report(op->reports, RPT_ERROR, error_msg); + } + fluid_bake_free(job); + return OPERATOR_CANCELLED; + } + if (!fluid_initpaths(job, op->reports)) { + return OPERATOR_CANCELLED; + } + fluid_bake_startjob(job, NULL, NULL, NULL); + fluid_bake_endjob(job); + fluid_bake_free(job); - elbeemSimulate(); - *do_update = true; - *stop = 0; + return OPERATOR_FINISHED; } -static void fluidbake_endjob(void *customdata) +static int fluid_bake_invoke(struct bContext *C, + struct wmOperator *op, + const wmEvent *UNUSED(_event)) { - FluidBakeJob *fb = (FluidBakeJob *)customdata; + Scene *scene = CTX_data_scene(C); + FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob"); + char error_msg[256] = "\0"; - if (fb->settings) { - MEM_freeN(fb->settings); - fb->settings = NULL; + if (!fluid_initjob(C, job, op, error_msg, sizeof(error_msg))) { + if (error_msg[0]) { + BKE_report(op->reports, RPT_ERROR, error_msg); + } + fluid_bake_free(job); + return OPERATOR_CANCELLED; } -} -static int runSimulationCallback(void *data, int status, int frame) -{ - FluidBakeJob *fb = (FluidBakeJob *)data; - elbeemSimulationSettings *settings = fb->settings; - - if (status == FLUIDSIM_CBSTATUS_NEWFRAME) { - fluidbake_updatejob(fb, frame / (float)settings->noOfFrames); -# if 0 - printf("elbeem blender cb s%d, f%d, domainid:%d noOfFrames: %d\n", - status, - frame, - settings->domainId, - settings->noOfFrames); // DEBUG -# endif + if (!fluid_initpaths(job, op->reports)) { + return OPERATOR_CANCELLED; } - if (fluidbake_breakjob(fb)) { - return FLUIDSIM_CBRET_ABORT; - } + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + "Fluid Bake", + WM_JOB_PROGRESS, + WM_JOB_TYPE_OBJECT_SIM_FLUID); + + WM_jobs_customdata_set(wm_job, job, fluid_bake_free); + WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER); + WM_jobs_callbacks(wm_job, fluid_bake_startjob, NULL, NULL, fluid_bake_endjob); + + WM_set_locked_interface(CTX_wm_manager(C), true); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + WM_event_add_modal_handler(C, op); - return FLUIDSIM_CBRET_CONTINUE; + return OPERATOR_RUNNING_MODAL; } -static void fluidbake_free_data(FluidAnimChannels *channels, - ListBase *fobjects, - elbeemSimulationSettings *fsset, - FluidBakeJob *fb) +static int fluid_bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - free_domain_channels(channels); - MEM_freeN(channels); - channels = NULL; - - free_all_fluidobject_channels(fobjects); - BLI_freelistN(fobjects); - MEM_freeN(fobjects); - fobjects = NULL; - - if (fsset) { - MEM_freeN(fsset); - fsset = NULL; + /* no running blender, remove handler and pass through */ + if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) { + return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; } - if (fb) { - MEM_freeN(fb); - fb = NULL; + switch (event->type) { + case ESCKEY: + return OPERATOR_RUNNING_MODAL; } + return OPERATOR_PASS_THROUGH; } -/* copied from rna_fluidsim.c: fluidsim_find_lastframe() */ -static void fluidsim_delete_until_lastframe(FluidsimSettings *fss, const char *relbase) +static int fluid_free_exec(struct bContext *C, struct wmOperator *op) { - char targetDir[FILE_MAX], targetFile[FILE_MAX]; - char targetDirVel[FILE_MAX], targetFileVel[FILE_MAX]; - char previewDir[FILE_MAX], previewFile[FILE_MAX]; - int curFrame = 1, exists = 0; - - BLI_join_dirfile( - targetDir, sizeof(targetDir), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); - BLI_join_dirfile( - targetDirVel, sizeof(targetDirVel), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_VEL_FNAME); - BLI_join_dirfile( - previewDir, sizeof(previewDir), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME); - - BLI_path_abs(targetDir, relbase); - BLI_path_abs(targetDirVel, relbase); - BLI_path_abs(previewDir, relbase); - - do { - BLI_strncpy(targetFile, targetDir, sizeof(targetFile)); - BLI_strncpy(targetFileVel, targetDirVel, sizeof(targetFileVel)); - BLI_strncpy(previewFile, previewDir, sizeof(previewFile)); - - BLI_path_frame(targetFile, curFrame, 0); - BLI_path_frame(targetFileVel, curFrame, 0); - BLI_path_frame(previewFile, curFrame, 0); - - curFrame++; - - if ((exists = BLI_exists(targetFile))) { - BLI_delete(targetFile, false, false); - BLI_delete(targetFileVel, false, false); - BLI_delete(previewFile, false, false); - } - } while (exists); + FluidModifierData *mmd = NULL; + FluidDomainSettings *mds; + Object *ob = CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); - return; -} + /* + * Get modifier data + */ + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + if (!mmd) { + BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found"); + return OPERATOR_CANCELLED; + } + mds = mmd->domain; + if (!mds) { + BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain"); + return OPERATOR_CANCELLED; + } -static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - int i; - FluidsimSettings *domainSettings; - - char debugStrBuffer[256]; - - int gridlevels = 0; - const char *relbase = modifier_path_relbase(bmain, fsDomain); - const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp - const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; - const char *suffixSurface = FLUID_SUFFIX_SURFACE; - - char targetDir[FILE_MAX]; // store & modify output settings - char targetFile[FILE_MAX]; // temp. store filename from targetDir for access - - float domainMat[4][4]; - float invDomMat[4][4]; - - int noFrames; - int origFrame = scene->r.cfra; - - FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), - "fluid domain animation channels"); - ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects"); - FluidsimModifierData *fluidmd = NULL; - Mesh *mesh = NULL; - - FluidBakeJob *fb; - elbeemSimulationSettings *fsset = MEM_callocN(sizeof(elbeemSimulationSettings), - "Fluid sim settings"); - - fb = MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); - - if (BLI_getenv(strEnvName)) { - int dlevel = atoi(BLI_getenv(strEnvName)); - elbeemSetDebugLevel(dlevel); - BLI_snprintf(debugStrBuffer, - sizeof(debugStrBuffer), - "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n", - strEnvName); - elbeemDebugOut(debugStrBuffer); + /* Cannot free data if other bakes currently working */ + if (mmd->domain->cache_flag & (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE | + FLUID_DOMAIN_BAKING_MESH | FLUID_DOMAIN_BAKING_PARTICLES)) { + BKE_report(op->reports, RPT_ERROR, "Bake free failed: pending bake jobs found"); + return OPERATOR_CANCELLED; } - /* Make sure it corresponds to startFrame setting - * (old: noFrames = scene->r.efra - scene->r.sfra +1). */ + FluidJob *job = MEM_mallocN(sizeof(FluidJob), "FluidJob"); + job->bmain = CTX_data_main(C); + job->scene = scene; + job->depsgraph = CTX_data_depsgraph_pointer(C); + job->ob = ob; + job->mmd = mmd; + job->type = op->type->idname; + job->name = op->type->name; - noFrames = scene->r.efra - 0; - if (noFrames <= 0) { - BKE_report(reports, RPT_ERROR, "No frames to export (check your animation range settings)"); - fluidbake_free_data(channels, fobjects, fsset, fb); - return 0; + if (!fluid_initpaths(job, op->reports)) { + return OPERATOR_CANCELLED; } - /* check scene for sane object/modifier settings */ - if (!fluid_validate_scene(reports, view_layer, fsDomain)) { - fluidbake_free_data(channels, fobjects, fsset, fb); - return 0; - } + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + "Fluid Free", + WM_JOB_PROGRESS, + WM_JOB_TYPE_OBJECT_SIM_FLUID); - /* these both have to be valid, otherwise we wouldn't be here */ - fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); - domainSettings = fluidmd->fss; - mesh = fsDomain->data; - - domainSettings->bakeStart = 1; - domainSettings->bakeEnd = scene->r.efra; - - // calculate bounding box - fluid_get_bb(mesh->mvert, - mesh->totvert, - fsDomain->obmat, - domainSettings->bbStart, - domainSettings->bbSize); - - // reset last valid frame - domainSettings->lastgoodframe = -1; - - /* delete old baked files */ - fluidsim_delete_until_lastframe(domainSettings, relbase); - - /* rough check of settings... */ - if (domainSettings->previewresxyz > domainSettings->resolutionxyz) { - BLI_snprintf(debugStrBuffer, - sizeof(debugStrBuffer), - "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", - domainSettings->previewresxyz, - domainSettings->resolutionxyz); - elbeemDebugOut(debugStrBuffer); - domainSettings->previewresxyz = domainSettings->resolutionxyz; - } - // set adaptive coarsening according to resolutionxyz - // this should do as an approximation, with in/outflow - // doing this more accurate would be overkill - // perhaps add manual setting? - if (domainSettings->maxRefine < 0) { - if (domainSettings->resolutionxyz > 128) { - gridlevels = 2; - } - else if (domainSettings->resolutionxyz > 64) { - gridlevels = 1; - } - else { - gridlevels = 0; - } - } - else { - gridlevels = domainSettings->maxRefine; - } - BLI_snprintf(debugStrBuffer, - sizeof(debugStrBuffer), - "fluidsimBake::msg: Baking %s, refine: %d\n", - fsDomain->id.name, - gridlevels); - elbeemDebugOut(debugStrBuffer); - - /* ******** prepare output file paths ******** */ - if (!fluid_init_filepaths(bmain, reports, domainSettings, fsDomain, targetDir, targetFile)) { - fluidbake_free_data(channels, fobjects, fsset, fb); - return false; - } + WM_jobs_customdata_set(wm_job, job, fluid_bake_free); + WM_jobs_timer(wm_job, 0.01, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER); + WM_jobs_callbacks(wm_job, fluid_free_startjob, NULL, NULL, fluid_free_endjob); - /* DG TODO: why using endframe and not "noFrames" here? - * because "noFrames" is buggy too? (not using sfra) */ - channels->length = scene->r.efra; - channels->aniFrameTime = (double)((double)domainSettings->animEnd - - (double)domainSettings->animStart) / - (double)noFrames; - - /* ******** initialize and allocate animation channels ******** */ - fluid_init_all_channels(C, depsgraph, fsDomain, domainSettings, channels, fobjects); - - /* reset to original current frame */ - scene->r.cfra = origFrame; - ED_update_for_newframe(CTX_data_main(C), CTX_data_depsgraph_pointer(C)); - - /* ******** init domain object's matrix ******** */ - copy_m4_m4(domainMat, fsDomain->obmat); - if (!invert_m4_m4(invDomMat, domainMat)) { - BLI_snprintf( - debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n"); - elbeemDebugOut(debugStrBuffer); - BKE_report(reports, RPT_ERROR, "Invalid object matrix"); - - fluidbake_free_data(channels, fobjects, fsset, fb); - return 0; - } + WM_set_locked_interface(CTX_wm_manager(C), true); - /* ******** start writing / exporting ******** */ - // use .tmp, don't overwrite/delete original file - BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp); - - /* ******** export domain to elbeem ******** */ - elbeemResetSettings(fsset); - fsset->version = 1; - fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) : - domainSettings->threads; - // setup global settings - copy_v3_v3(fsset->geoStart, domainSettings->bbStart); - copy_v3_v3(fsset->geoSize, domainSettings->bbSize); - - // simulate with 50^3 - fsset->resolutionxyz = (int)domainSettings->resolutionxyz; - fsset->previewresxyz = (int)domainSettings->previewresxyz; - - fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings); - fsset->viscosity = get_fluid_viscosity(domainSettings); - get_fluid_gravity(fsset->gravity, scene, domainSettings); - - // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz - fsset->animStart = domainSettings->animStart; - fsset->aniFrameTime = channels->aniFrameTime; - fsset->noOfFrames = noFrames; // is otherwise subtracted in parser - - BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface); - - // defaults for compressibility and adaptive grids - fsset->gstar = domainSettings->gstar; - fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels - fsset->generateParticles = domainSettings->generateParticles; - fsset->numTracerParticles = domainSettings->generateTracers; - fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; - fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; - fsset->farFieldSize = domainSettings->farFieldSize; - BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); - - // domain channels - fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity = - channels->length; - fsset->channelFrameTime = channels->DomainTime; - fsset->channelViscosity = channels->DomainViscosity; - fsset->channelGravity = channels->DomainGravity; - - fsset->runsimCallback = &runSimulationCallback; - fsset->runsimUserData = fb; - - if (domainSettings->typeFlags & OB_FSBND_NOSLIP) { - fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP; - } - else if (domainSettings->typeFlags & OB_FSBND_PARTSLIP) { - fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP; - } - else if (domainSettings->typeFlags & OB_FSBND_FREESLIP) { - fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP; - } - fsset->domainobsPartslip = domainSettings->partSlipValue; + /* Free Fluid Geometry */ + WM_jobs_start(CTX_wm_manager(C), wm_job); + + return OPERATOR_FINISHED; +} - /* use domainobsType also for surface generation flag (bit: >=64) */ - if (domainSettings->typeFlags & OB_FSSG_NOOBS) { - fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS; +static int fluid_pause_exec(struct bContext *C, struct wmOperator *op) +{ + FluidModifierData *mmd = NULL; + FluidDomainSettings *mds; + Object *ob = CTX_data_active_object(C); + + /* + * Get modifier data + */ + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + if (!mmd) { + BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found"); + return OPERATOR_CANCELLED; } - else { - fsset->mFsSurfGenSetting = 0; // "normal" mode + mds = mmd->domain; + if (!mds) { + BKE_report(op->reports, RPT_ERROR, "Bake free failed: invalid domain"); + return OPERATOR_CANCELLED; } - fsset->generateVertexVectors = (domainSettings->domainNovecgen == 0); + G.is_break = true; - // init blender domain transform matrix - { - int j; - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - fsset->surfaceTrafo[i * 4 + j] = invDomMat[j][i]; - } - } - } + return OPERATOR_FINISHED; +} - /* ******** init solver with settings ******** */ - elbeemInit(); - elbeemAddDomain(fsset); +void FLUID_OT_bake_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Bake All"; + ot->description = "Bake Entire Fluid Simulation"; + ot->idname = FLUID_JOB_BAKE_ALL; - /* ******** export all fluid objects to elbeem ******** */ - export_fluid_objects(depsgraph, fobjects, scene, channels->length); + /* api callbacks */ + ot->exec = fluid_bake_exec; + ot->invoke = fluid_bake_invoke; + ot->modal = fluid_bake_modal; + ot->poll = ED_operator_object_active_editable; +} - /* custom data for fluid bake job */ - fb->settings = fsset; +void FLUID_OT_free_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Free All"; + ot->description = "Free Entire Fluid Simulation"; + ot->idname = FLUID_JOB_FREE_ALL; - if (do_job) { - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - scene, - "Fluid Simulation", - WM_JOB_PROGRESS, - WM_JOB_TYPE_OBJECT_SIM_FLUID); + /* api callbacks */ + ot->exec = fluid_free_exec; + ot->poll = ED_operator_object_active_editable; +} - /* setup job */ - WM_jobs_customdata_set(wm_job, fb, fluidbake_free); - WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob); +void FLUID_OT_bake_data(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Bake Data"; + ot->description = "Bake Fluid Data"; + ot->idname = FLUID_JOB_BAKE_DATA; - WM_jobs_start(CTX_wm_manager(C), wm_job); - } - else { - short dummy_stop = 0, dummy_do_update = 0; - float dummy_progress = 0.0f; + /* api callbacks */ + ot->exec = fluid_bake_exec; + ot->invoke = fluid_bake_invoke; + ot->modal = fluid_bake_modal; + ot->poll = ED_operator_object_active_editable; +} - /* blocking, use with exec() */ - fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress); - fluidbake_endjob((void *)fb); - fluidbake_free((void *)fb); - } +void FLUID_OT_free_data(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Free Data"; + ot->description = "Free Fluid Data"; + ot->idname = FLUID_JOB_FREE_DATA; + + /* api callbacks */ + ot->exec = fluid_free_exec; + ot->poll = ED_operator_object_active_editable; +} - /* ******** free stored animation data ******** */ - fluidbake_free_data(channels, fobjects, NULL, NULL); +void FLUID_OT_bake_noise(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Bake Noise"; + ot->description = "Bake Fluid Noise"; + ot->idname = FLUID_JOB_BAKE_NOISE; - // elbeemFree(); - return 1; + /* api callbacks */ + ot->exec = fluid_bake_exec; + ot->invoke = fluid_bake_invoke; + ot->modal = fluid_bake_modal; + ot->poll = ED_operator_object_active_editable; } -static void UNUSED_FUNCTION(fluidsimFreeBake)(Object *UNUSED(ob)) +void FLUID_OT_free_noise(wmOperatorType *ot) { - /* not implemented yet */ + /* identifiers */ + ot->name = "Free Noise"; + ot->description = "Free Fluid Noise"; + ot->idname = FLUID_JOB_FREE_NOISE; + + /* api callbacks */ + ot->exec = fluid_free_exec; + ot->poll = ED_operator_object_active_editable; } -#else /* WITH_MOD_FLUID */ +void FLUID_OT_bake_mesh(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Bake Mesh"; + ot->description = "Bake Fluid Mesh"; + ot->idname = FLUID_JOB_BAKE_MESH; + + /* api callbacks */ + ot->exec = fluid_bake_exec; + ot->invoke = fluid_bake_invoke; + ot->modal = fluid_bake_modal; + ot->poll = ED_operator_object_active_editable; +} -/* only compile dummy functions */ -static int fluidsimBake(bContext *UNUSED(C), - ReportList *UNUSED(reports), - Object *UNUSED(ob), - short UNUSED(do_job)) +void FLUID_OT_free_mesh(wmOperatorType *ot) { - return 0; + /* identifiers */ + ot->name = "Free Mesh"; + ot->description = "Free Fluid Mesh"; + ot->idname = FLUID_JOB_FREE_MESH; + + /* api callbacks */ + ot->exec = fluid_free_exec; + ot->poll = ED_operator_object_active_editable; } -#endif /* WITH_MOD_FLUID */ +void FLUID_OT_bake_particles(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Bake Particles"; + ot->description = "Bake Fluid Particles"; + ot->idname = FLUID_JOB_BAKE_PARTICLES; -/***************************** Operators ******************************/ + /* api callbacks */ + ot->exec = fluid_bake_exec; + ot->invoke = fluid_bake_invoke; + ot->modal = fluid_bake_modal; + ot->poll = ED_operator_object_active_editable; +} -static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +void FLUID_OT_free_particles(wmOperatorType *ot) { - /* only one bake job at a time */ - if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) { - return OPERATOR_CANCELLED; - } + /* identifiers */ + ot->name = "Free Particles"; + ot->description = "Free Fluid Particles"; + ot->idname = FLUID_JOB_FREE_PARTICLES; - if (!fluidsimBake(C, op->reports, ED_object_context(C), true)) { - return OPERATOR_CANCELLED; - } + /* api callbacks */ + ot->exec = fluid_free_exec; + ot->poll = ED_operator_object_active_editable; +} - return OPERATOR_FINISHED; +void FLUID_OT_bake_guides(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Bake Guides"; + ot->description = "Bake Fluid Guiding"; + ot->idname = FLUID_JOB_BAKE_GUIDES; + + /* api callbacks */ + ot->exec = fluid_bake_exec; + ot->invoke = fluid_bake_invoke; + ot->modal = fluid_bake_modal; + ot->poll = ED_operator_object_active_editable; } -static int fluid_bake_exec(bContext *C, wmOperator *op) +void FLUID_OT_free_guides(wmOperatorType *ot) { - if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), false)) { - return OPERATOR_CANCELLED; - } + /* identifiers */ + ot->name = "Free Guides"; + ot->description = "Free Fluid Guiding"; + ot->idname = FLUID_JOB_FREE_GUIDES; - return OPERATOR_FINISHED; + /* api callbacks */ + ot->exec = fluid_free_exec; + ot->poll = ED_operator_object_active_editable; } -void FLUID_OT_bake(wmOperatorType *ot) +void FLUID_OT_pause_bake(wmOperatorType *ot) { /* identifiers */ - ot->name = "Fluid Simulation Bake"; - ot->description = "Bake fluid simulation"; - ot->idname = "FLUID_OT_bake"; + ot->name = "Pause Bake"; + ot->description = "Pause Bake"; + ot->idname = FLUID_JOB_BAKE_PAUSE; /* api callbacks */ - ot->invoke = fluid_bake_invoke; - ot->exec = fluid_bake_exec; + ot->exec = fluid_pause_exec; ot->poll = ED_operator_object_active_editable; } diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h index fc2f3d21bb6..3af818b3a9d 100644 --- a/source/blender/editors/physics/physics_intern.h +++ b/source/blender/editors/physics/physics_intern.h @@ -103,7 +103,19 @@ void BOID_OT_state_move_up(struct wmOperatorType *ot); void BOID_OT_state_move_down(struct wmOperatorType *ot); /* physics_fluid.c */ -void FLUID_OT_bake(struct wmOperatorType *ot); +void FLUID_OT_bake_all(struct wmOperatorType *ot); +void FLUID_OT_free_all(struct wmOperatorType *ot); +void FLUID_OT_bake_data(struct wmOperatorType *ot); +void FLUID_OT_free_data(struct wmOperatorType *ot); +void FLUID_OT_bake_noise(struct wmOperatorType *ot); +void FLUID_OT_free_noise(struct wmOperatorType *ot); +void FLUID_OT_bake_mesh(struct wmOperatorType *ot); +void FLUID_OT_free_mesh(struct wmOperatorType *ot); +void FLUID_OT_bake_particles(struct wmOperatorType *ot); +void FLUID_OT_free_particles(struct wmOperatorType *ot); +void FLUID_OT_bake_guides(struct wmOperatorType *ot); +void FLUID_OT_free_guides(struct wmOperatorType *ot); +void FLUID_OT_pause_bake(struct wmOperatorType *ot); /* dynamicpaint.c */ void DPAINT_OT_bake(struct wmOperatorType *ot); diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index b1b3927d05e..d1536733b9b 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -126,7 +126,19 @@ static void operatortypes_boids(void) static void operatortypes_fluid(void) { - WM_operatortype_append(FLUID_OT_bake); + WM_operatortype_append(FLUID_OT_bake_all); + WM_operatortype_append(FLUID_OT_free_all); + WM_operatortype_append(FLUID_OT_bake_data); + WM_operatortype_append(FLUID_OT_free_data); + WM_operatortype_append(FLUID_OT_bake_noise); + WM_operatortype_append(FLUID_OT_free_noise); + WM_operatortype_append(FLUID_OT_bake_mesh); + WM_operatortype_append(FLUID_OT_free_mesh); + WM_operatortype_append(FLUID_OT_bake_particles); + WM_operatortype_append(FLUID_OT_free_particles); + WM_operatortype_append(FLUID_OT_bake_guides); + WM_operatortype_append(FLUID_OT_free_guides); + WM_operatortype_append(FLUID_OT_pause_bake); } /**************************** point cache **********************************/ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 9975c49dc54..7c47f7439ab 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4229,19 +4229,6 @@ static void SCREEN_OT_region_context_menu(wmOperatorType *ot) * Animation Step. * \{ */ -static int match_area_with_refresh(int spacetype, int refresh) -{ - switch (spacetype) { - case SPACE_TIME: - if (refresh & SPACE_TIME) { - return 1; - } - break; - } - - return 0; -} - static int match_region_with_redraws(int spacetype, int regiontype, int redraws, @@ -4524,10 +4511,6 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv } } } - - if (match_area_with_refresh(sa->spacetype, sad->refresh)) { - ED_area_tag_refresh(sa); - } } } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 06d79b8a49d..7f71110b360 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -1560,9 +1560,9 @@ static void paint_2d_canvas_free(ImagePaintState *s) } } -static void paint_2d_transform_mouse(ImagePaintState *s, const float in[2], float out[2]) +static void paint_2d_transform_mouse(View2D *v2d, const float in[2], float out[2]) { - UI_view2d_region_to_view(s->v2d, in[0], in[1], &out[0], &out[1]); + UI_view2d_region_to_view(v2d, in[0], in[1], &out[0], &out[1]); } static bool is_inside_tile(const int size[2], const float pos[2], const float brush[2]) @@ -1656,8 +1656,9 @@ void paint_2d_stroke(void *ps, brush_painter_2d_refresh_cache(s, painter, tile, new_coord, mval, pressure, distance, size); - if (paint_2d_op(s, tile, old_coord, new_coord)) + if (paint_2d_op(s, tile, old_coord, new_coord)) { tile->need_redraw = true; + } } painter->firsttouch = 0; @@ -1899,14 +1900,24 @@ void paint_2d_bucket_fill(const bContext *C, return; } + View2D *v2d = s ? s->v2d : &CTX_wm_region(C)->v2d; float uv_origin[2]; float image_init[2]; - paint_2d_transform_mouse(s, mouse_init, image_init); + paint_2d_transform_mouse(v2d, mouse_init, image_init); int tile_number = BKE_image_get_tile_from_pos(ima, image_init, image_init, uv_origin); - ImageUser *iuser = paint_2d_get_tile_iuser(s, tile_number); - if (!iuser) { - return; + + ImageUser local_iuser, *iuser; + if (s != NULL) { + iuser = paint_2d_get_tile_iuser(s, tile_number); + if (iuser == NULL) { + return; + } + } + else { + iuser = &local_iuser; + BKE_imageuser_default(iuser); + iuser->tile = tile_number; } ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); @@ -2125,8 +2136,8 @@ void paint_2d_gradient_fill( return; } - paint_2d_transform_mouse(s, mouse_final, image_final); - paint_2d_transform_mouse(s, mouse_init, image_init); + paint_2d_transform_mouse(s->v2d, mouse_final, image_final); + paint_2d_transform_mouse(s->v2d, mouse_init, image_init); sub_v2_v2(image_init, uv_origin); sub_v2_v2(image_final, uv_origin); diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 8cb0a3f3c86..ecd2b5a3697 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -770,7 +770,6 @@ const char *buttons_context_dir[] = { "cloth", "soft_body", "fluid", - "smoke", "collision", "brush", "dynamic_paint", @@ -1018,24 +1017,14 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r return 1; } } - else if (CTX_data_equals(member, "fluid")) { - PointerRNA *ptr = get_pointer_type(path, &RNA_Object); - if (ptr && ptr->data) { - Object *ob = ptr->data; - ModifierData *md = modifiers_findByType(ob, eModifierType_Fluidsim); - CTX_data_pointer_set(result, &ob->id, &RNA_FluidSimulationModifier, md); - return 1; - } - } - - else if (CTX_data_equals(member, "smoke")) { + else if (CTX_data_equals(member, "fluid")) { PointerRNA *ptr = get_pointer_type(path, &RNA_Object); if (ptr && ptr->data) { Object *ob = ptr->data; - ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke); - CTX_data_pointer_set(result, &ob->id, &RNA_SmokeModifier, md); + ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid); + CTX_data_pointer_set(result, &ob->id, &RNA_FluidModifier, md); return 1; } } diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 9a633427d82..3f563fe9033 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -549,12 +549,15 @@ static void draw_udim_label(ARegion *ar, float fx, float fy, const char *label) int textwidth = BLF_width(blf_mono_font, label, strlen(label)) + 10; float stepx = BLI_rcti_size_x(&ar->v2d.mask) / BLI_rctf_size_x(&ar->v2d.cur); float opacity; - if (textwidth < 0.5f * (stepx - 10)) + if (textwidth < 0.5f * (stepx - 10)) { opacity = 1.0f; - else if (textwidth < (stepx - 10)) + } + else if (textwidth < (stepx - 10)) { opacity = 2.0f - 2.0f * (textwidth / (stepx - 10)); - else + } + else { opacity = 0.0f; + } BLF_color4ub(blf_mono_font, 220, 220, 220, 150 * opacity); BLF_position(blf_mono_font, (int)(x + 10), (int)(y + 10), 0); BLF_draw_ascii(blf_mono_font, label, strlen(label)); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index c0c66a28ad9..c1172b0cea8 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -4419,7 +4419,7 @@ static void tile_fill_draw(bContext *UNUSED(C), wmOperator *op) void IMAGE_OT_tile_fill(wmOperatorType *ot) { /* identifiers */ - ot->name = "Fill tile"; + ot->name = "Fill Tile"; ot->description = "Fill the current tile with a generated image"; ot->idname = "IMAGE_OT_tile_fill"; diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 9a6f685f5fc..17088b0e2b4 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -2125,14 +2125,14 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case eModifierType_Surface: data.icon = ICON_MOD_PHYSICS; break; - case eModifierType_Fluidsim: + case eModifierType_Fluidsim: /* deprecated, old fluid modifier */ data.icon = ICON_MOD_FLUIDSIM; break; case eModifierType_Multires: data.icon = ICON_MOD_MULTIRES; break; - case eModifierType_Smoke: - data.icon = ICON_MOD_SMOKE; + case eModifierType_Fluid: + data.icon = ICON_MOD_FLUID; break; case eModifierType_Solidify: data.icon = ICON_MOD_SOLIDIFY; diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 2feef9e0c9a..95d7f79f666 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -32,7 +32,7 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc - ../../../../intern/smoke/extern + ../../../../intern/mantaflow/extern # dna_type_offsets.h ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern @@ -95,8 +95,8 @@ if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() -if(WITH_MOD_SMOKE) - add_definitions(-DWITH_SMOKE) +if(WITH_MOD_FLUID) + add_definitions(-DWITH_FLUID) endif() blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c index 848accb8534..f761a44fe16 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c @@ -70,19 +70,17 @@ static bool WIDGETGROUP_tool_generic_poll(const bContext *C, wmGizmoGroupType *g static wmGizmo *tool_generic_create_gizmo(const bContext *C, wmGizmoGroup *gzgroup) { - wmGizmo *gz; + wmGizmo *gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL); + gz->flag |= WM_GIZMO_OPERATOR_TOOL_INIT; - if (gzgroup->type->idname == handle_normal_id) { - gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL); - - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); - UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); + UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); + UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); - unit_m4(gz->matrix_offset); + unit_m4(gz->matrix_offset); - PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon"); - RNA_property_enum_set(gz->ptr, prop, ICON_NONE); + RNA_enum_set(gz->ptr, "icon", ICON_NONE); + if (gzgroup->type->idname == handle_normal_id) { gz->scale_basis = 0.12f; gz->matrix_offset[3][2] -= 12.0; RNA_enum_set(gz->ptr, @@ -91,17 +89,8 @@ static wmGizmo *tool_generic_create_gizmo(const bContext *C, wmGizmoGroup *gzgro ED_GIZMO_BUTTON_SHOW_OUTLINE)); } else { - gz = WM_gizmo_new("GIZMO_GT_button_2d", gzgroup, NULL); - - UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color); - UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi); - - unit_m4(gz->matrix_offset); gz->scale_basis = 0.16f * 3; - PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon"); - RNA_property_enum_set(gz->ptr, prop, ICON_NONE); - RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP); /* Make the center low alpha. */ diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index f9f6a513f63..a188e2eb829 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -26,6 +26,8 @@ /* For enum. */ #include "DNA_space_types.h" +struct SnapObjectParams; + bool peelObjectsTransform(struct TransInfo *t, const float mval[2], const bool use_peel_object, diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt index 44335f4da25..87743911add 100644 --- a/source/blender/gpencil_modifiers/CMakeLists.txt +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -30,7 +30,6 @@ set(INC ../makesdna ../makesrna ../render/extern/include - ../../../intern/elbeem/extern ../../../intern/eigen ../../../intern/guardedalloc ) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c index c71d074e564..bc545ce6ce8 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c @@ -1,6 +1,4 @@ /* - * ***** BEGIN GPL LICENSE BLOCK ***** - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -17,12 +15,9 @@ * * The Original Code is Copyright (C) 2017, Blender Foundation * This is a new part of Blender - * - * ***** END GPL LICENSE BLOCK ***** - * */ -/** \file blender/gpencil_modifiers/intern/MOD_gpencilstrokes.c +/** \file * \ingroup modifiers */ diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index bcdc1550fd2..8daeda67c80 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -44,7 +44,7 @@ set(INC ../../../intern/glew-mx ../../../intern/guardedalloc - ../../../intern/smoke/extern + ../../../intern/mantaflow/extern ) set(INC_SYS @@ -61,6 +61,7 @@ set(SRC intern/gpu_context.cpp intern/gpu_debug.c intern/gpu_draw.c + intern/gpu_draw_smoke.c intern/gpu_element.c intern/gpu_extensions.c intern/gpu_framebuffer.c @@ -319,8 +320,8 @@ data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC) data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC) -if(WITH_MOD_SMOKE) - add_definitions(-DWITH_SMOKE) +if(WITH_MOD_FLUID) + add_definitions(-DWITH_FLUID) endif() add_definitions(${GL_DEFINITIONS}) diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 6d2b0ad3be3..2ed4ee44287 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -31,12 +31,12 @@ struct CCGElem; struct CCGKey; struct DMFlagMat; struct GSet; -struct Mesh; struct MLoop; struct MLoopCol; struct MLoopTri; struct MPoly; struct MVert; +struct Mesh; struct PBVH; /* Buffers for drawing from PBVH grids. */ diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 7814c723fec..f89a76cf49c 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -28,11 +28,11 @@ extern "C" { #endif +struct FluidModifierData; struct ImBuf; struct Image; struct ImageUser; struct Main; -struct SmokeModifierData; #include "DNA_object_enums.h" @@ -83,12 +83,12 @@ void GPU_free_images(struct Main *bmain); void GPU_free_images_anim(struct Main *bmain); void GPU_free_images_old(struct Main *bmain); -/* smoke drawing functions */ -void GPU_free_smoke(struct SmokeModifierData *smd); -void GPU_free_smoke_velocity(struct SmokeModifierData *smd); -void GPU_create_smoke(struct SmokeModifierData *smd, int highres); -void GPU_create_smoke_coba_field(struct SmokeModifierData *smd); -void GPU_create_smoke_velocity(struct SmokeModifierData *smd); +/* gpu_draw_smoke.c */ +void GPU_free_smoke(struct FluidModifierData *mmd); +void GPU_free_smoke_velocity(struct FluidModifierData *mmd); +void GPU_create_smoke(struct FluidModifierData *mmd, int highres); +void GPU_create_smoke_coba_field(struct FluidModifierData *mmd); +void GPU_create_smoke_velocity(struct FluidModifierData *mmd); /* Delayed free of OpenGL buffers by main thread */ void GPU_free_unused_buffers(struct Main *bmain); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 23ea9a62ef8..ca804a26acd 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -2131,8 +2131,10 @@ GPUPass *GPU_generate_pass(GPUMaterial *material, static int count_active_texture_sampler(GPUShader *shader, char *source) { char *code = source; - int samplers_id[64]; /* Remember this is per stage. */ - int sampler_len = 0; + + /* Remember this is per stage. */ + GSet *sampler_ids = BLI_gset_int_new(__func__); + int num_samplers = 0; while ((code = strstr(code, "uniform "))) { /* Move past "uniform". */ @@ -2167,22 +2169,16 @@ static int count_active_texture_sampler(GPUShader *shader, char *source) continue; } /* Catch duplicates. */ - bool is_duplicate = false; - for (int i = 0; i < sampler_len; i++) { - if (samplers_id[i] == id) { - is_duplicate = true; - } - } - - if (!is_duplicate) { - samplers_id[sampler_len] = id; - sampler_len++; + if (BLI_gset_add(sampler_ids, POINTER_FROM_INT(id))) { + num_samplers++; } } } } - return sampler_len; + BLI_gset_free(sampler_ids, NULL); + + return num_samplers; } static bool gpu_pass_shader_validate(GPUPass *pass, GPUShader *shader) diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index d698db45b7a..95738bb1a95 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -36,17 +36,9 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" -#include "DNA_light_types.h" -#include "DNA_material_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_smoke_types.h" -#include "DNA_view3d_types.h" -#include "DNA_particle_types.h" +#include "DNA_image_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_userdef_types.h" #include "MEM_guardedalloc.h" @@ -54,14 +46,10 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "BKE_colorband.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" -#include "BKE_material.h" #include "BKE_movieclip.h" -#include "BKE_node.h" -#include "BKE_scene.h" #include "GPU_draw.h" #include "GPU_extensions.h" @@ -71,10 +59,6 @@ #include "PIL_time.h" -#ifdef WITH_SMOKE -# include "smoke_API.h" -#endif - static void gpu_free_image_immediate(Image *ima); //* Checking powers of two for images since OpenGL ES requires it */ @@ -940,372 +924,6 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i BKE_image_release_ibuf(ima, ibuf, NULL); } -/* *************************** Transfer functions *************************** */ - -enum { - TFUNC_FLAME_SPECTRUM = 0, - TFUNC_COLOR_RAMP = 1, -}; - -#define TFUNC_WIDTH 256 - -#ifdef WITH_SMOKE -static void create_flame_spectrum_texture(float *data) -{ -# define FIRE_THRESH 7 -# define MAX_FIRE_ALPHA 0.06f -# define FULL_ON_FIRE 100 - - float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); - - blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000); - - for (int i = 0; i < 16; i++) { - for (int j = 0; j < 16; j++) { - for (int k = 0; k < TFUNC_WIDTH; k++) { - int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4; - if (k >= FIRE_THRESH) { - spec_pixels[index] = (data[k * 4]); - spec_pixels[index + 1] = (data[k * 4 + 1]); - spec_pixels[index + 2] = (data[k * 4 + 2]); - spec_pixels[index + 3] = MAX_FIRE_ALPHA * - ((k > FULL_ON_FIRE) ? - 1.0f : - (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); - } - else { - zero_v4(&spec_pixels[index]); - } - } - } - } - - memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH); - - MEM_freeN(spec_pixels); - -# undef FIRE_THRESH -# undef MAX_FIRE_ALPHA -# undef FULL_ON_FIRE -} - -static void create_color_ramp(const ColorBand *coba, float *data) -{ - for (int i = 0; i < TFUNC_WIDTH; i++) { - BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); - } -} - -static GPUTexture *create_transfer_function(int type, const ColorBand *coba) -{ - float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__); - - switch (type) { - case TFUNC_FLAME_SPECTRUM: - create_flame_spectrum_texture(data); - break; - case TFUNC_COLOR_RAMP: - create_color_ramp(coba, data); - break; - } - - GPUTexture *tex = GPU_texture_create_1d(TFUNC_WIDTH, GPU_RGBA8, data, NULL); - - MEM_freeN(data); - - return tex; -} - -static void swizzle_texture_channel_rrrr(GPUTexture *tex) -{ - GPU_texture_bind(tex, 0); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); - GPU_texture_unbind(tex); -} - -static GPUTexture *create_field_texture(SmokeDomainSettings *sds) -{ - float *field = NULL; - - switch (sds->coba_field) { - case FLUID_FIELD_DENSITY: - field = smoke_get_density(sds->fluid); - break; - case FLUID_FIELD_HEAT: - field = smoke_get_heat(sds->fluid); - break; - case FLUID_FIELD_FUEL: - field = smoke_get_fuel(sds->fluid); - break; - case FLUID_FIELD_REACT: - field = smoke_get_react(sds->fluid); - break; - case FLUID_FIELD_FLAME: - field = smoke_get_flame(sds->fluid); - break; - case FLUID_FIELD_VELOCITY_X: - field = smoke_get_velocity_x(sds->fluid); - break; - case FLUID_FIELD_VELOCITY_Y: - field = smoke_get_velocity_y(sds->fluid); - break; - case FLUID_FIELD_VELOCITY_Z: - field = smoke_get_velocity_z(sds->fluid); - break; - case FLUID_FIELD_COLOR_R: - field = smoke_get_color_r(sds->fluid); - break; - case FLUID_FIELD_COLOR_G: - field = smoke_get_color_g(sds->fluid); - break; - case FLUID_FIELD_COLOR_B: - field = smoke_get_color_b(sds->fluid); - break; - case FLUID_FIELD_FORCE_X: - field = smoke_get_force_x(sds->fluid); - break; - case FLUID_FIELD_FORCE_Y: - field = smoke_get_force_y(sds->fluid); - break; - case FLUID_FIELD_FORCE_Z: - field = smoke_get_force_z(sds->fluid); - break; - default: - return NULL; - } - - GPUTexture *tex = GPU_texture_create_nD( - sds->res[0], sds->res[1], sds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); - - swizzle_texture_channel_rrrr(tex); - return tex; -} - -static GPUTexture *create_density_texture(SmokeDomainSettings *sds, int highres) -{ - float *data = NULL, *source; - int cell_count = (highres) ? smoke_turbulence_get_cells(sds->wt) : sds->total_cells; - const bool has_color = (highres) ? smoke_turbulence_has_colors(sds->wt) : - smoke_has_colors(sds->fluid); - int *dim = (highres) ? sds->res_wt : sds->res; - eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8; - - if (has_color) { - data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture"); - } - - if (highres) { - if (has_color) { - smoke_turbulence_get_rgba(sds->wt, data, 0); - } - else { - source = smoke_turbulence_get_density(sds->wt); - } - } - else { - if (has_color) { - smoke_get_rgba(sds->fluid, data, 0); - } - else { - source = smoke_get_density(sds->fluid); - } - } - - GPUTexture *tex = GPU_texture_create_nD(dim[0], - dim[1], - dim[2], - 3, - (has_color) ? data : source, - format, - GPU_DATA_FLOAT, - 0, - true, - NULL); - if (data) { - MEM_freeN(data); - } - - if (format == GPU_R8) { - /* Swizzle the RGBA components to read the Red channel so - * that the shader stay the same for colored and non color - * density textures. */ - swizzle_texture_channel_rrrr(tex); - } - return tex; -} - -static GPUTexture *create_flame_texture(SmokeDomainSettings *sds, int highres) -{ - float *source = NULL; - const bool has_fuel = (highres) ? smoke_turbulence_has_fuel(sds->wt) : - smoke_has_fuel(sds->fluid); - int *dim = (highres) ? sds->res_wt : sds->res; - - if (!has_fuel) { - return NULL; - } - - if (highres) { - source = smoke_turbulence_get_flame(sds->wt); - } - else { - source = smoke_get_flame(sds->fluid); - } - - GPUTexture *tex = GPU_texture_create_nD( - dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); - - swizzle_texture_channel_rrrr(tex); - - return tex; -} -#endif /* WITH_SMOKE */ - -void GPU_free_smoke(SmokeModifierData *smd) -{ - if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) { - if (smd->domain->tex) { - GPU_texture_free(smd->domain->tex); - } - smd->domain->tex = NULL; - - if (smd->domain->tex_shadow) { - GPU_texture_free(smd->domain->tex_shadow); - } - smd->domain->tex_shadow = NULL; - - if (smd->domain->tex_flame) { - GPU_texture_free(smd->domain->tex_flame); - } - smd->domain->tex_flame = NULL; - - if (smd->domain->tex_flame_coba) { - GPU_texture_free(smd->domain->tex_flame_coba); - } - smd->domain->tex_flame_coba = NULL; - - if (smd->domain->tex_coba) { - GPU_texture_free(smd->domain->tex_coba); - } - smd->domain->tex_coba = NULL; - - if (smd->domain->tex_field) { - GPU_texture_free(smd->domain->tex_field); - } - smd->domain->tex_field = NULL; - } -} - -void GPU_create_smoke_coba_field(SmokeModifierData *smd) -{ -#ifdef WITH_SMOKE - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - SmokeDomainSettings *sds = smd->domain; - - if (!sds->tex_field) { - sds->tex_field = create_field_texture(sds); - } - if (!sds->tex_coba) { - sds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, sds->coba); - } - } -#else // WITH_SMOKE - smd->domain->tex_field = NULL; -#endif // WITH_SMOKE -} - -void GPU_create_smoke(SmokeModifierData *smd, int highres) -{ -#ifdef WITH_SMOKE - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - SmokeDomainSettings *sds = smd->domain; - - if (!sds->tex) { - sds->tex = create_density_texture(sds, highres); - } - if (!sds->tex_flame) { - sds->tex_flame = create_flame_texture(sds, highres); - } - if (!sds->tex_flame_coba && sds->tex_flame) { - sds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL); - } - if (!sds->tex_shadow) { - sds->tex_shadow = GPU_texture_create_nD(sds->res[0], - sds->res[1], - sds->res[2], - 3, - sds->shadow, - GPU_R8, - GPU_DATA_FLOAT, - 0, - true, - NULL); - } - } -#else // WITH_SMOKE - (void)highres; - smd->domain->tex = NULL; - smd->domain->tex_flame = NULL; - smd->domain->tex_flame_coba = NULL; - smd->domain->tex_shadow = NULL; -#endif // WITH_SMOKE -} - -void GPU_create_smoke_velocity(SmokeModifierData *smd) -{ -#ifdef WITH_SMOKE - if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { - SmokeDomainSettings *sds = smd->domain; - - const float *vel_x = smoke_get_velocity_x(sds->fluid); - const float *vel_y = smoke_get_velocity_y(sds->fluid); - const float *vel_z = smoke_get_velocity_z(sds->fluid); - - if (ELEM(NULL, vel_x, vel_y, vel_z)) { - return; - } - - if (!sds->tex_velocity_x) { - sds->tex_velocity_x = GPU_texture_create_3d( - sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_x, NULL); - sds->tex_velocity_y = GPU_texture_create_3d( - sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_y, NULL); - sds->tex_velocity_z = GPU_texture_create_3d( - sds->res[0], sds->res[1], sds->res[2], GPU_R16F, vel_z, NULL); - } - } -#else // WITH_SMOKE - smd->domain->tex_velocity_x = NULL; - smd->domain->tex_velocity_y = NULL; - smd->domain->tex_velocity_z = NULL; -#endif // WITH_SMOKE -} - -/* TODO Unify with the other GPU_free_smoke. */ -void GPU_free_smoke_velocity(SmokeModifierData *smd) -{ - if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) { - if (smd->domain->tex_velocity_x) { - GPU_texture_free(smd->domain->tex_velocity_x); - } - - if (smd->domain->tex_velocity_y) { - GPU_texture_free(smd->domain->tex_velocity_y); - } - - if (smd->domain->tex_velocity_z) { - GPU_texture_free(smd->domain->tex_velocity_z); - } - - smd->domain->tex_velocity_x = NULL; - smd->domain->tex_velocity_y = NULL; - smd->domain->tex_velocity_z = NULL; - } -} - static LinkNode *image_free_queue = NULL; static ThreadMutex img_queue_mutex = BLI_MUTEX_INITIALIZER; diff --git a/source/blender/gpu/intern/gpu_draw_smoke.c b/source/blender/gpu/intern/gpu_draw_smoke.c new file mode 100644 index 00000000000..5cca472148a --- /dev/null +++ b/source/blender/gpu/intern/gpu_draw_smoke.c @@ -0,0 +1,416 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup gpu + * + * GPU fluid drawing functions. + */ + +#include <string.h> + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_modifier_types.h" +#include "DNA_fluid_types.h" + +#include "MEM_guardedalloc.h" + +#include "BKE_colorband.h" + +#include "GPU_draw.h" +#include "GPU_glew.h" +#include "GPU_texture.h" + +#ifdef WITH_FLUID +# include "manta_fluid_API.h" +#endif + +/* -------------------------------------------------------------------- */ +/** \name Private API + * \{ */ + +#ifdef WITH_FLUID + +enum { + TFUNC_FLAME_SPECTRUM = 0, + TFUNC_COLOR_RAMP = 1, +}; + +# define TFUNC_WIDTH 256 + +static void create_flame_spectrum_texture(float *data) +{ +# define FIRE_THRESH 7 +# define MAX_FIRE_ALPHA 0.06f +# define FULL_ON_FIRE 100 + + float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); + + blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000); + + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + for (int k = 0; k < TFUNC_WIDTH; k++) { + int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4; + if (k >= FIRE_THRESH) { + spec_pixels[index] = (data[k * 4]); + spec_pixels[index + 1] = (data[k * 4 + 1]); + spec_pixels[index + 2] = (data[k * 4 + 2]); + spec_pixels[index + 3] = MAX_FIRE_ALPHA * + ((k > FULL_ON_FIRE) ? + 1.0f : + (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); + } + else { + zero_v4(&spec_pixels[index]); + } + } + } + } + + memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH); + + MEM_freeN(spec_pixels); + +# undef FIRE_THRESH +# undef MAX_FIRE_ALPHA +# undef FULL_ON_FIRE +} + +static void create_color_ramp(const struct ColorBand *coba, float *data) +{ + for (int i = 0; i < TFUNC_WIDTH; i++) { + BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + } +} + +static GPUTexture *create_transfer_function(int type, const struct ColorBand *coba) +{ + float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__); + + switch (type) { + case TFUNC_FLAME_SPECTRUM: + create_flame_spectrum_texture(data); + break; + case TFUNC_COLOR_RAMP: + create_color_ramp(coba, data); + break; + } + + GPUTexture *tex = GPU_texture_create_1d(TFUNC_WIDTH, GPU_RGBA8, data, NULL); + + MEM_freeN(data); + + return tex; +} + +static void swizzle_texture_channel_rrrr(GPUTexture *tex) +{ + GPU_texture_bind(tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(tex); +} + +static GPUTexture *create_field_texture(FluidDomainSettings *mds) +{ + float *field = NULL; + + switch (mds->coba_field) { + case FLUID_DOMAIN_FIELD_DENSITY: + field = manta_smoke_get_density(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_HEAT: + field = manta_smoke_get_heat(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_FUEL: + field = manta_smoke_get_fuel(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_REACT: + field = manta_smoke_get_react(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_FLAME: + field = manta_smoke_get_flame(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_VELOCITY_X: + field = manta_get_velocity_x(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_VELOCITY_Y: + field = manta_get_velocity_y(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_VELOCITY_Z: + field = manta_get_velocity_z(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_COLOR_R: + field = manta_smoke_get_color_r(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_COLOR_G: + field = manta_smoke_get_color_g(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_COLOR_B: + field = manta_smoke_get_color_b(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_FORCE_X: + field = manta_get_force_x(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_FORCE_Y: + field = manta_get_force_y(mds->fluid); + break; + case FLUID_DOMAIN_FIELD_FORCE_Z: + field = manta_get_force_z(mds->fluid); + break; + default: + return NULL; + } + + GPUTexture *tex = GPU_texture_create_nD( + mds->res[0], mds->res[1], mds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_rrrr(tex); + return tex; +} + +static GPUTexture *create_density_texture(FluidDomainSettings *mds, int highres) +{ + float *data = NULL, *source; + int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells; + const bool has_color = (highres) ? manta_smoke_turbulence_has_colors(mds->fluid) : + manta_smoke_has_colors(mds->fluid); + int *dim = (highres) ? mds->res_noise : mds->res; + eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8; + + if (has_color) { + data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture"); + } + + if (highres) { + if (has_color) { + manta_smoke_turbulence_get_rgba(mds->fluid, data, 0); + } + else { + source = manta_smoke_turbulence_get_density(mds->fluid); + } + } + else { + if (has_color) { + manta_smoke_get_rgba(mds->fluid, data, 0); + } + else { + source = manta_smoke_get_density(mds->fluid); + } + } + + GPUTexture *tex = GPU_texture_create_nD(dim[0], + dim[1], + dim[2], + 3, + (has_color) ? data : source, + format, + GPU_DATA_FLOAT, + 0, + true, + NULL); + if (data) { + MEM_freeN(data); + } + + if (format == GPU_R8) { + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + swizzle_texture_channel_rrrr(tex); + } + return tex; +} + +static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres) +{ + float *source = NULL; + const bool has_fuel = (highres) ? manta_smoke_turbulence_has_fuel(mds->fluid) : + manta_smoke_has_fuel(mds->fluid); + int *dim = (highres) ? mds->res_noise : mds->res; + + if (!has_fuel) { + return NULL; + } + + if (highres) { + source = manta_smoke_turbulence_get_flame(mds->fluid); + } + else { + source = manta_smoke_get_flame(mds->fluid); + } + + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_rrrr(tex); + + return tex; +} + +#endif /* WITH_FLUID */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public API + * \{ */ + +void GPU_free_smoke(FluidModifierData *mmd) +{ + if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) { + if (mmd->domain->tex) { + GPU_texture_free(mmd->domain->tex); + } + mmd->domain->tex = NULL; + + if (mmd->domain->tex_shadow) { + GPU_texture_free(mmd->domain->tex_shadow); + } + mmd->domain->tex_shadow = NULL; + + if (mmd->domain->tex_flame) { + GPU_texture_free(mmd->domain->tex_flame); + } + mmd->domain->tex_flame = NULL; + + if (mmd->domain->tex_flame_coba) { + GPU_texture_free(mmd->domain->tex_flame_coba); + } + mmd->domain->tex_flame_coba = NULL; + + if (mmd->domain->tex_coba) { + GPU_texture_free(mmd->domain->tex_coba); + } + mmd->domain->tex_coba = NULL; + + if (mmd->domain->tex_field) { + GPU_texture_free(mmd->domain->tex_field); + } + mmd->domain->tex_field = NULL; + } +} + +void GPU_create_smoke_coba_field(FluidModifierData *mmd) +{ +#ifndef WITH_FLUID + UNUSED_VARS(mmd); +#else + if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { + FluidDomainSettings *mds = mmd->domain; + + if (!mds->tex_field) { + mds->tex_field = create_field_texture(mds); + } + if (!mds->tex_coba) { + mds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, mds->coba); + } + } +#endif +} + +void GPU_create_smoke(FluidModifierData *mmd, int highres) +{ +#ifndef WITH_FLUID + UNUSED_VARS(mmd, highres); +#else + if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { + FluidDomainSettings *mds = mmd->domain; + + if (!mds->tex) { + mds->tex = create_density_texture(mds, highres); + } + if (!mds->tex_flame) { + mds->tex_flame = create_flame_texture(mds, highres); + } + if (!mds->tex_flame_coba && mds->tex_flame) { + mds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL); + } + if (!mds->tex_shadow) { + mds->tex_shadow = GPU_texture_create_nD(mds->res[0], + mds->res[1], + mds->res[2], + 3, + manta_smoke_get_shadow(mds->fluid), + GPU_R8, + GPU_DATA_FLOAT, + 0, + true, + NULL); + } + } +#endif /* WITH_FLUID */ +} + +void GPU_create_smoke_velocity(FluidModifierData *mmd) +{ +#ifndef WITH_FLUID + UNUSED_VARS(mmd); +#else + if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { + FluidDomainSettings *mds = mmd->domain; + + const float *vel_x = manta_get_velocity_x(mds->fluid); + const float *vel_y = manta_get_velocity_y(mds->fluid); + const float *vel_z = manta_get_velocity_z(mds->fluid); + + if (ELEM(NULL, vel_x, vel_y, vel_z)) { + return; + } + + if (!mds->tex_velocity_x) { + mds->tex_velocity_x = GPU_texture_create_3d( + mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_x, NULL); + mds->tex_velocity_y = GPU_texture_create_3d( + mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_y, NULL); + mds->tex_velocity_z = GPU_texture_create_3d( + mds->res[0], mds->res[1], mds->res[2], GPU_R16F, vel_z, NULL); + } + } +#endif /* WITH_FLUID */ +} + +/* TODO Unify with the other GPU_free_smoke. */ +void GPU_free_smoke_velocity(FluidModifierData *mmd) +{ + if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) { + if (mmd->domain->tex_velocity_x) { + GPU_texture_free(mmd->domain->tex_velocity_x); + } + + if (mmd->domain->tex_velocity_y) { + GPU_texture_free(mmd->domain->tex_velocity_y); + } + + if (mmd->domain->tex_velocity_z) { + GPU_texture_free(mmd->domain->tex_velocity_z); + } + + mmd->domain->tex_velocity_x = NULL; + mmd->domain->tex_velocity_y = NULL; + mmd->domain->tex_velocity_z = NULL; + } +} + +/** \} */ diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h index 4ead3165715..354344328d3 100644 --- a/source/blender/makesdna/DNA_armature_types.h +++ b/source/blender/makesdna/DNA_armature_types.h @@ -182,7 +182,7 @@ typedef enum eArmature_DeformFlag { ARM_DEF_VGROUP = (1 << 0), ARM_DEF_ENVELOPE = (1 << 1), ARM_DEF_QUATERNION = (1 << 2), -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW ARM_DEF_B_BONE_REST = (1 << 3), /* deprecated */ #endif ARM_DEF_INVERT_VGROUP = (1 << 4), @@ -190,7 +190,7 @@ typedef enum eArmature_DeformFlag { /* armature->pathflag */ // XXX deprecated... old animation system (armature only viz) -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW typedef enum eArmature_PathFlag { ARM_PATH_FNUMS = (1 << 0), ARM_PATH_KFRAS = (1 << 1), @@ -228,7 +228,7 @@ typedef enum eBone_Flag { BONE_UNKEYED = (1 << 13), /** set to prevent hinge child bones from influencing the transform center */ BONE_HINGE_CHILD_TRANSFORM = (1 << 14), -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW /** No parent scale */ BONE_NO_SCALE = (1 << 15), #endif diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h index b78b2f64648..7c7d4bc182e 100644 --- a/source/blender/makesdna/DNA_camera_types.h +++ b/source/blender/makesdna/DNA_camera_types.h @@ -156,7 +156,7 @@ enum { CAM_SHOWNAME = (1 << 4), CAM_ANGLETOGGLE = (1 << 5), CAM_DS_EXPAND = (1 << 6), -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW CAM_PANORAMA = (1 << 7), /* deprecated */ #endif CAM_SHOWSENSOR = (1 << 8), diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index d7b392d5133..0baa11c3059 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -755,7 +755,7 @@ typedef enum eCopyRotation_Flags { ROTLIKE_X_INVERT = (1 << 4), ROTLIKE_Y_INVERT = (1 << 5), ROTLIKE_Z_INVERT = (1 << 6), -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW ROTLIKE_OFFSET = (1 << 7), #endif } eCopyRotation_Flags; @@ -976,7 +976,7 @@ typedef enum eSplineIK_Flags { CONSTRAINT_SPLINEIK_BOUND = (1 << 0), /* root of chain is not influenced by the constraint */ CONSTRAINT_SPLINEIK_NO_ROOT = (1 << 1), -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW /* bones in the chain should not scale to fit the curve */ CONSTRAINT_SPLINEIK_SCALE_LIMITED = (1 << 2), #endif diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 0a6423d569f..f70dc19616b 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -97,7 +97,7 @@ typedef enum CustomDataType { CD_AUTO_FROM_NAME = -1, CD_MVERT = 0, -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW CD_MSTICKY = 1, /* DEPRECATED */ #endif CD_MDEFORMVERT = 2, @@ -113,7 +113,7 @@ typedef enum CustomDataType { CD_PROP_STR = 12, CD_ORIGSPACE = 13, /* for modifier stack face location mapping */ CD_ORCO = 14, /* undeformed vertex coordinates, normalized to 0..1 range */ -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW CD_MTEXPOLY = 15, /* deprecated */ #endif CD_MLOOPUV = 16, diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h new file mode 100644 index 00000000000..e12bee13ebc --- /dev/null +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -0,0 +1,590 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup DNA + */ + +#ifndef __DNA_FLUID_TYPES_H__ +#define __DNA_FLUID_TYPES_H__ + +/* Domain flags. */ +enum { + FLUID_DOMAIN_USE_NOISE = (1 << 1), /* Use noise. */ + FLUID_DOMAIN_USE_DISSOLVE = (1 << 2), /* Let smoke dissolve. */ + FLUID_DOMAIN_USE_DISSOLVE_LOG = (1 << 3), /* Using 1/x for dissolve. */ + +#ifdef DNA_DEPRECATED_ALLOW + FLUID_DOMAIN_USE_HIGH_SMOOTH = (1 << 5), /* -- Deprecated -- */ +#endif + FLUID_DOMAIN_FILE_LOAD = (1 << 6), /* Flag for file load. */ + FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN = (1 << 7), + FLUID_DOMAIN_USE_ADAPTIVE_TIME = (1 << 8), /* Adaptive time stepping in domain. */ + FLUID_DOMAIN_USE_MESH = (1 << 9), /* Use mesh. */ + FLUID_DOMAIN_USE_GUIDE = (1 << 10), /* Use guiding. */ + FLUID_DOMAIN_USE_SPEED_VECTORS = (1 << 11), /* Generate mesh speed vectors. */ + FLUID_DOMAIN_EXPORT_MANTA_SCRIPT = (1 << 12), /* Export mantaflow script during bake. */ + FLUID_DOMAIN_USE_FRACTIONS = (1 << 13), /* Use second order obstacles. */ +}; + +/* Border collisions. */ +enum { + FLUID_DOMAIN_BORDER_FRONT = (1 << 1), + FLUID_DOMAIN_BORDER_BACK = (1 << 2), + FLUID_DOMAIN_BORDER_RIGHT = (1 << 3), + FLUID_DOMAIN_BORDER_LEFT = (1 << 4), + FLUID_DOMAIN_BORDER_TOP = (1 << 5), + FLUID_DOMAIN_BORDER_BOTTOM = (1 << 6), +}; + +/* Cache file formats. */ +enum { + FLUID_DOMAIN_FILE_UNI = (1 << 0), + FLUID_DOMAIN_FILE_OPENVDB = (1 << 1), + FLUID_DOMAIN_FILE_RAW = (1 << 2), + FLUID_DOMAIN_FILE_OBJECT = (1 << 3), + FLUID_DOMAIN_FILE_BIN_OBJECT = (1 << 4), +}; + +/* Slice method. */ +enum { + FLUID_DOMAIN_SLICE_VIEW_ALIGNED = 0, + FLUID_DOMAIN_SLICE_AXIS_ALIGNED = 1, +}; + +/* Axis aligned method. */ +enum { + AXIS_SLICE_FULL = 0, + AXIS_SLICE_SINGLE = 1, +}; + +/* Single slice direction. */ +enum { + SLICE_AXIS_AUTO = 0, + SLICE_AXIS_X = 1, + SLICE_AXIS_Y = 2, + SLICE_AXIS_Z = 3, +}; + +/* Axis aligned method. */ +enum { + VOLUME_INTERP_LINEAR = 0, + VOLUME_INTERP_CUBIC = 1, +}; + +enum { + VECTOR_DRAW_NEEDLE = 0, + VECTOR_DRAW_STREAMLINE = 1, +}; + +enum { + SNDPARTICLE_BOUNDARY_DELETE = 0, + SNDPARTICLE_BOUNDARY_PUSHOUT = 1, +}; + +enum { + SNDPARTICLE_COMBINED_EXPORT_OFF = 0, + SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM = 1, + SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE = 2, + SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE = 3, + SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE = 4, +}; + +enum { + FLUID_DOMAIN_FIELD_DENSITY = 0, + FLUID_DOMAIN_FIELD_HEAT = 1, + FLUID_DOMAIN_FIELD_FUEL = 2, + FLUID_DOMAIN_FIELD_REACT = 3, + FLUID_DOMAIN_FIELD_FLAME = 4, + FLUID_DOMAIN_FIELD_VELOCITY_X = 5, + FLUID_DOMAIN_FIELD_VELOCITY_Y = 6, + FLUID_DOMAIN_FIELD_VELOCITY_Z = 7, + FLUID_DOMAIN_FIELD_COLOR_R = 8, + FLUID_DOMAIN_FIELD_COLOR_G = 9, + FLUID_DOMAIN_FIELD_COLOR_B = 10, + FLUID_DOMAIN_FIELD_FORCE_X = 11, + FLUID_DOMAIN_FIELD_FORCE_Y = 12, + FLUID_DOMAIN_FIELD_FORCE_Z = 13, +}; + +/* Fluid domain types. */ +enum { + FLUID_DOMAIN_TYPE_GAS = 0, + FLUID_DOMAIN_TYPE_LIQUID = 1, +}; + +/* Smoke noise types. */ +enum { + FLUID_NOISE_TYPE_WAVELET = (1 << 0), +}; + +/* Mesh levelset generator types. */ +enum { + FLUID_DOMAIN_MESH_IMPROVED = 0, + FLUID_DOMAIN_MESH_UNION = 1, +}; + +/* Guiding velocity source. */ +enum { + FLUID_DOMAIN_GUIDE_SRC_DOMAIN = 0, + FLUID_DOMAIN_GUIDE_SRC_EFFECTOR = 1, +}; + +/* Fluid data fields (active_fields). */ +enum { + FLUID_DOMAIN_ACTIVE_HEAT = (1 << 0), + FLUID_DOMAIN_ACTIVE_FIRE = (1 << 1), + FLUID_DOMAIN_ACTIVE_COLORS = (1 << 2), + FLUID_DOMAIN_ACTIVE_COLOR_SET = (1 << 3), + FLUID_DOMAIN_ACTIVE_OBSTACLE = (1 << 4), + FLUID_DOMAIN_ACTIVE_GUIDE = (1 << 5), + FLUID_DOMAIN_ACTIVE_INVEL = (1 << 6), + FLUID_DOMAIN_ACTIVE_OUTFLOW = (1 << 7), +}; + +/* Particle types. */ +enum { + FLUID_DOMAIN_PARTICLE_FLIP = (1 << 0), + FLUID_DOMAIN_PARTICLE_SPRAY = (1 << 1), + FLUID_DOMAIN_PARTICLE_BUBBLE = (1 << 2), + FLUID_DOMAIN_PARTICLE_FOAM = (1 << 3), + FLUID_DOMAIN_PARTICLE_TRACER = (1 << 4), +}; + +/* Liquid simulation methods. */ +enum { + FLUID_DOMAIN_METHOD_FLIP = (1 << 0), + FLUID_DOMAIN_METHOD_APIC = (1 << 1), +}; + +/* Cache options. */ +enum { + FLUID_DOMAIN_BAKING_DATA = (1 << 0), + FLUID_DOMAIN_BAKED_DATA = (1 << 1), + FLUID_DOMAIN_BAKING_NOISE = (1 << 2), + FLUID_DOMAIN_BAKED_NOISE = (1 << 3), + FLUID_DOMAIN_BAKING_MESH = (1 << 4), + FLUID_DOMAIN_BAKED_MESH = (1 << 5), + FLUID_DOMAIN_BAKING_PARTICLES = (1 << 6), + FLUID_DOMAIN_BAKED_PARTICLES = (1 << 7), + FLUID_DOMAIN_BAKING_GUIDE = (1 << 8), + FLUID_DOMAIN_BAKED_GUIDE = (1 << 9), + FLUID_DOMAIN_OUTDATED_DATA = (1 << 10), + FLUID_DOMAIN_OUTDATED_NOISE = (1 << 11), + FLUID_DOMAIN_OUTDATED_MESH = (1 << 12), + FLUID_DOMAIN_OUTDATED_PARTICLES = (1 << 13), + FLUID_DOMAIN_OUTDATED_GUIDE = (1 << 14), +}; + +#define FLUID_DOMAIN_BAKING_ALL \ + (FLUID_DOMAIN_BAKING_DATA | FLUID_DOMAIN_BAKING_NOISE | FLUID_DOMAIN_BAKING_MESH | \ + FLUID_DOMAIN_BAKING_PARTICLES | FLUID_DOMAIN_BAKING_GUIDE) + +#define FLUID_DOMAIN_BAKED_ALL \ + (FLUID_DOMAIN_BAKED_DATA | FLUID_DOMAIN_BAKED_NOISE | FLUID_DOMAIN_BAKED_MESH | \ + FLUID_DOMAIN_BAKED_PARTICLES | FLUID_DOMAIN_BAKED_GUIDE) + +#define FLUID_DOMAIN_DIR_DEFAULT "cache_fluid" +#define FLUID_DOMAIN_DIR_CONFIG "config" +#define FLUID_DOMAIN_DIR_DATA "data" +#define FLUID_DOMAIN_DIR_NOISE "noise" +#define FLUID_DOMAIN_DIR_MESH "mesh" +#define FLUID_DOMAIN_DIR_PARTICLES "particles" +#define FLUID_DOMAIN_DIR_GUIDE "guiding" +#define FLUID_DOMAIN_DIR_SCRIPT "script" +#define FLUID_DOMAIN_SMOKE_SCRIPT "smoke_script.py" +#define FLUID_DOMAIN_LIQUID_SCRIPT "liquid_script.py" + +enum { + FLUID_DOMAIN_CACHE_REPLAY = 0, + FLUID_DOMAIN_CACHE_MODULAR = 1, + FLUID_DOMAIN_CACHE_FINAL = 2, +}; + +/* Deprecated values (i.e. all defines and enums below this line up until typedefs). */ +/* Cache compression. */ +enum { + SM_CACHE_LIGHT = 0, + SM_CACHE_HEAVY = 1, +}; + +/* High resolution sampling types. */ +enum { + SM_HRES_NEAREST = 0, + SM_HRES_LINEAR = 1, + SM_HRES_FULLSAMPLE = 2, +}; + +enum { + VDB_COMPRESSION_BLOSC = 0, + VDB_COMPRESSION_ZIP = 1, + VDB_COMPRESSION_NONE = 2, +}; + +typedef struct FluidDomainVertexVelocity { + float vel[3]; +} FluidDomainVertexVelocity; + +typedef struct FluidDomainSettings { + + /* -- Runtime-only fields (from here on). -- */ + + struct FluidModifierData *mmd; /* For fast RNA access. */ + struct MANTA *fluid; + struct MANTA *fluid_old; /* Adaptive domain needs access to old fluid state. */ + void *fluid_mutex; + struct Collection *fluid_group; + struct Collection *force_group; /* UNUSED */ + struct Collection *effector_group; /* Effector objects group. */ + struct GPUTexture *tex; + struct GPUTexture *tex_wt; + struct GPUTexture *tex_shadow; + struct GPUTexture *tex_flame; + struct GPUTexture *tex_flame_coba; + struct GPUTexture *tex_coba; + struct GPUTexture *tex_field; + struct GPUTexture *tex_velocity_x; + struct GPUTexture *tex_velocity_y; + struct GPUTexture *tex_velocity_z; + struct Object *guide_parent; + /** Vertex velocities of simulated fluid mesh. */ + struct FluidDomainVertexVelocity *mesh_velocities; + struct EffectorWeights *effector_weights; + + /* Domain object data. */ + float p0[3]; /* Start point of BB in local space + * (includes sub-cell shift for adaptive domain). */ + float p1[3]; /* End point of BB in local space. */ + float dp0[3]; /* Difference from object center to grid start point. */ + float cell_size[3]; /* Size of simulation cell in local space. */ + float global_size[3]; /* Global size of domain axises. */ + float prev_loc[3]; + int shift[3]; /* Current domain shift in simulation cells. */ + float shift_f[3]; /* Exact domain shift. */ + float obj_shift_f[3]; /* How much object has shifted since previous smoke frame (used to "lock" + * domain while drawing). */ + float imat[4][4]; /* Domain object imat. */ + float obmat[4][4]; /* Domain obmat. */ + float fluidmat[4][4]; /* Low res fluid matrix. */ + float fluidmat_wt[4][4]; /* High res fluid matrix. */ + int base_res[3]; /* Initial "non-adapted" resolution. */ + int res_min[3]; /* Cell min. */ + int res_max[3]; /* Cell max. */ + int res[3]; /* Data resolution (res_max-res_min). */ + int total_cells; + float dx; /* 1.0f / res. */ + float scale; /* Largest domain size. */ + int boundary_width; /* Usually this is just 1. */ + + /* -- User-accesible fields (from here on). -- */ + + /* Adaptive domain options. */ + int adapt_margin; + int adapt_res; + float adapt_threshold; + char _pad1[4]; /* Unused. */ + + /* Fluid domain options */ + int maxres; /* Longest axis on the BB gets this resolution assigned. */ + int solver_res; /* Dimension of manta solver, 2d or 3d. */ + int border_collisions; /* How domain border collisions are handled. */ + int flags; /* Use-mesh, use-noise, etc. */ + float gravity[3]; + int active_fields; + short type; /* Gas, liquid. */ + char _pad2[6]; /* Unused. */ + + /* Smoke domain options. */ + float alpha; + float beta; + int diss_speed; /* In frames. */ + float vorticity; + float active_color[3]; /* Monitor smoke color. */ + int highres_sampling; + + /* Flame options. */ + float burning_rate, flame_smoke, flame_vorticity; + float flame_ignition, flame_max_temp; + float flame_smoke_color[3]; + + /* Noise options. */ + float noise_strength; + float noise_pos_scale; + float noise_time_anim; + int res_noise[3]; + int noise_scale; + short noise_type; /* Noise type: wave, curl, anisotropic. */ + char _pad3[2]; /* Unused. */ + + /* Liquid domain options. */ + float particle_randomness; + int particle_number; + int particle_minimum; + int particle_maximum; + float particle_radius; + float particle_band_width; + float fractions_threshold; + float flip_ratio; + short simulation_method; + char _pad4[6]; + + /* Diffusion options. */ + float surface_tension; + float viscosity_base; + int viscosity_exponent; + float domain_size; + + /* Mesh options. */ + float mesh_concave_upper; + float mesh_concave_lower; + float mesh_particle_radius; + int mesh_smoothen_pos; + int mesh_smoothen_neg; + int mesh_scale; + int totvert; + short mesh_generator; + char _pad5[2]; /* Unused. */ + + /* Secondary particle options. */ + int particle_type; + int particle_scale; + float sndparticle_tau_min_wc; + float sndparticle_tau_max_wc; + float sndparticle_tau_min_ta; + float sndparticle_tau_max_ta; + float sndparticle_tau_min_k; + float sndparticle_tau_max_k; + int sndparticle_k_wc; + int sndparticle_k_ta; + float sndparticle_k_b; + float sndparticle_k_d; + float sndparticle_l_min; + float sndparticle_l_max; + int sndparticle_potential_radius; + int sndparticle_update_radius; + char sndparticle_boundary; + char sndparticle_combined_export; + char _pad6[6]; /* Unused. */ + + /* Fluid guiding options. */ + float guide_alpha; /* Guiding weight scalar (determines strength). */ + int guide_beta; /* Guiding blur radius (affects size of vortices). */ + float guide_vel_factor; /* Multiply guiding velocity by this factor. */ + int guide_res[3]; /* Res for velocity guide grids - independent from base res. */ + short guide_source; + char _pad7[2]; /* Unused. */ + + /* Cache options. */ + int cache_frame_start; + int cache_frame_end; + int cache_frame_pause_data; + int cache_frame_pause_noise; + int cache_frame_pause_mesh; + int cache_frame_pause_particles; + int cache_frame_pause_guide; + int cache_flag; + char cache_mesh_format; + char cache_data_format; + char cache_particle_format; + char cache_noise_format; + char cache_directory[1024]; + char error[64]; /* Bake error description. */ + short cache_type; + char _pad8[2]; /* Unused. */ + + /* Time options. */ + float dt; + float time_total; + float time_per_frame; + float frame_length; + float time_scale; + float cfl_condition; + int timesteps_minimum; + int timesteps_maximum; + + /* Display options. */ + char slice_method, axis_slice_method; + char slice_axis, draw_velocity; + float slice_per_voxel; + float slice_depth; + float display_thickness; + struct ColorBand *coba; + float vector_scale; + char vector_draw_type; + char use_coba; + char coba_field; /* Simulation field used for the color mapping. */ + char interp_method; + + /* -- Deprecated / unsed options (below). -- */ + + /* View options. */ + int viewsettings; + char _pad9[4]; /* Unused. */ + + /* OpenVDB cache options. */ + int openvdb_comp; + float clipping; + char data_depth; + char _pad10[7]; /* Unused. */ + + /* Pointcache options. */ + /* Smoke uses only one cache from now on (index [0]), but keeping the array for now for reading + * old files. */ + struct PointCache *point_cache[2]; /* Definition is in DNA_object_force_types.h. */ + struct ListBase ptcaches[2]; + int cache_comp; + int cache_high_comp; + char cache_file_format; + char _pad11[7]; /* Unused. */ + +} FluidDomainSettings; + +/* Flow types. */ +enum { + FLUID_FLOW_TYPE_SMOKE = 1, + FLUID_FLOW_TYPE_FIRE = 2, + FLUID_FLOW_TYPE_SMOKEFIRE = 3, + FLUID_FLOW_TYPE_LIQUID = 4, +}; + +/* Flow behavior types. */ +enum { + FLUID_FLOW_BEHAVIOR_INFLOW = 0, + FLUID_FLOW_BEHAVIOR_OUTFLOW = 1, + FLUID_FLOW_BEHAVIOR_GEOMETRY = 2, +}; + +/* Flow source types. */ +enum { + FLUID_FLOW_SOURCE_PARTICLES = 0, + FLUID_FLOW_SOURCE_MESH = 1, +}; + +/* Flow texture types. */ +enum { + FLUID_FLOW_TEXTURE_MAP_AUTO = 0, + FLUID_FLOW_TEXTURE_MAP_UV = 1, +}; + +/* Flow flags. */ +enum { + /* Old style emission. */ + FLUID_FLOW_ABSOLUTE = (1 << 1), + /* Passes particles speed to the smoke. */ + FLUID_FLOW_INITVELOCITY = (1 << 2), + /* Use texture to control emission speed. */ + FLUID_FLOW_TEXTUREEMIT = (1 << 3), + /* Use specific size for particles instead of closest cell. */ + FLUID_FLOW_USE_PART_SIZE = (1 << 4), + /* Control when to apply inflow. */ + FLUID_FLOW_USE_INFLOW = (1 << 5), + /* Control when to apply inflow. */ + FLUID_FLOW_USE_PLANE_INIT = (1 << 6), +}; + +typedef struct FluidFlowSettings { + + /* -- Runtime-only fields (from here on). -- */ + + /* For fast RNA access. */ + struct FluidModifierData *mmd; + struct Mesh *mesh; + struct ParticleSystem *psys; + struct Tex *noise_texture; + + /* Initial velocity. */ + /* Previous vertex positions in domain space. */ + float *verts_old; + int numverts; + float vel_multi; /* Multiplier for inherited velocity. */ + float vel_normal; + float vel_random; + float vel_coord[3]; + char _pad1[4]; + + /* -- User-accesible fields (from here on). -- */ + + /* Emission. */ + float density; + float color[3]; + float fuel_amount; + /* Delta temperature (temp - ambient temp). */ + float temperature; + /* Density emitted within mesh volume. */ + float volume_density; + /* Maximum emission distance from mesh surface. */ + float surface_distance; + float particle_size; + int subframes; + + /* Texture control. */ + float texture_size; + float texture_offset; + char _pad2[4]; + /* MAX_CUSTOMDATA_LAYER_NAME. */ + char uvlayer_name[64]; + short vgroup_density; + + short type; /* Smoke, flames, both, outflow, liquid. */ + short behavior; /* Inflow, outflow, static. */ + short source; + short texture_type; + short _pad3[3]; + int flags; /* Absolute emission etc. */ +} FluidFlowSettings; + +/* Effector types. */ +enum { + FLUID_EFFECTOR_TYPE_COLLISION = 0, + FLUID_EFFECTOR_TYPE_GUIDE = 1, +}; + +/* Guiding velocity modes. */ +enum { + FLUID_EFFECTOR_GUIDE_MAX = 0, + FLUID_EFFECTOR_GUIDE_MIN = 1, + FLUID_EFFECTOR_GUIDE_OVERRIDE = 2, + FLUID_EFFECTOR_GUIDE_AVERAGED = 3, +}; + +/* Collision objects (filled with smoke). */ +typedef struct FluidEffectorSettings { + + /* -- Runtime-only fields (from here on). -- */ + + /* For fast RNA access. */ + struct FluidModifierData *mmd; + struct Mesh *mesh; + float *verts_old; + int numverts; + + /* -- User-accesible fields (from here on). -- */ + + float surface_distance; /* Thickness of mesh surface, used in obstacle sdf. */ + int flags; + short type; + char _pad1[2]; + + /* Guiding options. */ + float vel_multi; /* Multiplier for object velocity. */ + short guide_mode; + char _pad2[2]; +} FluidEffectorSettings; + +#endif diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index e975d7acd74..1c58d03a1a8 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -184,7 +184,7 @@ typedef struct Image { enum { IMA_FLAG_UNUSED_0 = (1 << 0), /* cleared */ IMA_FLAG_UNUSED_1 = (1 << 1), /* cleared */ -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW IMA_DO_PREMUL = (1 << 2), #endif IMA_FLAG_UNUSED_4 = (1 << 4), /* cleared */ diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 60e0eb2976e..86ea22690ee 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -204,7 +204,7 @@ typedef struct Mesh { } Mesh; /* deprecated by MTFace, only here for file reading */ -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW typedef struct TFace { /** The faces image for the active UVLayer. */ void *tpage; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 44bf275d422..52e12dc4057 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -62,7 +62,9 @@ typedef enum ModifierType { eModifierType_SimpleDeform = 28, eModifierType_Multires = 29, eModifierType_Surface = 30, +#ifdef DNA_DEPRECATED_ALLOW eModifierType_Smoke = 31, +#endif eModifierType_ShapeKey = 32, eModifierType_Solidify = 33, eModifierType_Screw = 34, @@ -87,10 +89,11 @@ typedef enum ModifierType { eModifierType_SurfaceDeform = 53, eModifierType_WeightedNormal = 54, eModifierType_Weld = 55, - eModifierType_FunctionPoints = 56, + eModifierType_Fluid = 56, eModifierType_BParticles = 57, eModifierType_BParticlesOutput = 58, eModifierType_FunctionDeform = 59, + eModifierType_FunctionPoints = 58, NUM_MODIFIER_TYPES, } ModifierType; @@ -455,24 +458,24 @@ enum { MOD_BEVEL_VMESH_CUTOFF, }; -typedef struct SmokeModifierData { +typedef struct FluidModifierData { ModifierData modifier; - struct SmokeDomainSettings *domain; + struct FluidDomainSettings *domain; /** Inflow, outflow, smoke objects. */ - struct SmokeFlowSettings *flow; - /** Collision objects. */ - struct SmokeCollSettings *coll; + struct FluidFlowSettings *flow; + /** Effector objects (collision, guiding). */ + struct FluidEffectorSettings *effector; float time; /** Domain, inflow, outflow, .... */ int type; -} SmokeModifierData; +} FluidModifierData; -/* Smoke modifier flags */ +/* Fluid modifier flags */ enum { - MOD_SMOKE_TYPE_DOMAIN = (1 << 0), - MOD_SMOKE_TYPE_FLOW = (1 << 1), - MOD_SMOKE_TYPE_COLL = (1 << 2), + MOD_FLUID_TYPE_DOMAIN = (1 << 0), + MOD_FLUID_TYPE_FLOW = (1 << 1), + MOD_FLUID_TYPE_EFFEC = (1 << 2), }; typedef struct DisplaceModifierData { @@ -981,6 +984,7 @@ typedef enum { eMultiresModifierFlag_UseCrease = (1 << 2), } MultiresModifierFlag; +/* DEPRECATED, only used for versioning. */ typedef struct FluidsimModifierData { ModifierData modifier; @@ -988,6 +992,11 @@ typedef struct FluidsimModifierData { struct FluidsimSettings *fss; } FluidsimModifierData; +/* DEPRECATED, only used for versioning. */ +typedef struct SmokeModifierData { + ModifierData modifier; +} SmokeModifierData; + typedef struct ShrinkwrapModifierData { ModifierData modifier; @@ -1152,7 +1161,7 @@ enum { MOD_SOLIDIFY_EVEN = (1 << 1), MOD_SOLIDIFY_NORMAL_CALC = (1 << 2), MOD_SOLIDIFY_VGROUP_INV = (1 << 3), -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW MOD_SOLIDIFY_RIM_MATERIAL = (1 << 4), /* deprecated, used in do_versions */ #endif MOD_SOLIDIFY_FLIP = (1 << 5), @@ -1599,7 +1608,7 @@ typedef struct TriangulateModifierData { /* TriangulateModifierData.flag */ enum { -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW MOD_TRIANGULATE_BEAUTY = (1 << 0), /* deprecated */ #endif MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS = 1 << 1, diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index d94a05ccb81..22202717b0c 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1284,7 +1284,7 @@ enum { /* subsurface */ enum { -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW SHD_SUBSURFACE_COMPATIBLE = 0, // Deprecated #endif SHD_SUBSURFACE_CUBIC = 1, diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index a1ea51ab573..fbed0754046 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -371,7 +371,8 @@ typedef struct Object { struct Collection *instance_collection; /** If fluidsim enabled, store additional settings. */ - struct FluidsimSettings *fluidsimSettings; + struct FluidsimSettings *fluidsimSettings + DNA_DEPRECATED; // XXX deprecated... replaced by mantaflow, keep for readfile struct DerivedMesh *derivedDeform, *derivedFinal; diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index 4aaa1fe32f6..8bbbc9fc85d 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -273,7 +273,7 @@ typedef struct ParticleSettings { struct Collection *instance_collection; struct ListBase instance_weights; - struct Collection *eff_group DNA_DEPRECATED; // deprecated + struct Collection *force_group DNA_DEPRECATED; // deprecated struct Object *instance_object; struct Object *bb_ob; /** Old animation system, deprecated for 2.5. */ @@ -406,7 +406,7 @@ typedef enum eParticleDrawFlag { PART_DRAW_VEL = (1 << 0), PART_DRAW_GLOBAL_OB = (1 << 1), PART_DRAW_SIZE = (1 << 2), -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW /** Render emitter as well. */ PART_DRAW_EMITTER = (1 << 3), /* DEPRECATED */ #endif @@ -429,13 +429,33 @@ typedef enum eParticleDrawFlag { PART_DRAW_HAIR_GRID = (1 << 18), } eParticleDrawFlag; -/* part->type */ -/* hair is always baked static in object/geometry space */ -/* other types (normal particles) are in global space and not static baked */ -#define PART_EMITTER 0 -//#define PART_REACTOR 1 -#define PART_HAIR 2 -#define PART_FLUID 3 +/* part->type + * Hair is always baked static in object/geometry space. + * Other types (normal particles) are in global space and not static baked. */ +enum { + PART_EMITTER = (1 << 0), + /* REACTOR type currently unused */ + /* PART_REACTOR = (1 << 1), */ + PART_HAIR = (1 << 2), + PART_FLUID = (1 << 3), /* deprecated (belonged to elbeem) */ + PART_FLUID_FLIP = (1 << 4), + PART_FLUID_SPRAY = (1 << 5), + PART_FLUID_BUBBLE = (1 << 6), + PART_FLUID_FOAM = (1 << 7), + PART_FLUID_TRACER = (1 << 8), +}; + +/* Mirroring Mantaflow particle types from particle.h (Mantaflow header). */ +enum { + PARTICLE_TYPE_NONE = (0 << 0), + PARTICLE_TYPE_NEW = (1 << 0), + PARTICLE_TYPE_SPRAY = (1 << 1), + PARTICLE_TYPE_BUBBLE = (1 << 2), + PARTICLE_TYPE_FOAM = (1 << 3), + PARTICLE_TYPE_TRACER = (1 << 4), + PARTICLE_TYPE_DELETE = (1 << 10), + PARTICLE_TYPE_INVALID = (1 << 30), +}; /* part->flag */ #define PART_REACT_STA_END 1 diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 980fbfa72e0..7cfd19b4bd9 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -101,7 +101,7 @@ typedef struct AviCodecData { typedef enum eFFMpegPreset { FFM_PRESET_NONE, -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW /* Previously used by h.264 to control encoding speed vs. file size. */ FFM_PRESET_ULTRAFAST, /* DEPRECATED */ FFM_PRESET_SUPERFAST, /* DEPRECATED */ @@ -1929,7 +1929,7 @@ enum { R_COLOR_MANAGEMENT_UNUSED_1 = (1 << 1), }; -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW /* RenderData.subimtype flag options for imtype */ enum { R_OPENEXR_HALF = (1 << 0), /*deprecated*/ @@ -2169,7 +2169,7 @@ typedef enum eVGroupSelect { /* FFMpegCodecData.flags */ enum { -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW FFMPEG_MULTIPLEX_AUDIO = (1 << 0), /* deprecated, you can choose none as audiocodec now */ #endif FFMPEG_AUTOSPLIT_OUTPUT = (1 << 1), diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h deleted file mode 100644 index d795800df2f..00000000000 --- a/source/blender/makesdna/DNA_smoke_types.h +++ /dev/null @@ -1,346 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2006 by NaN Holding BV. - * All rights reserved. - */ - -/** \file - * \ingroup DNA - */ - -#ifndef __DNA_SMOKE_TYPES_H__ -#define __DNA_SMOKE_TYPES_H__ - -/* flags */ -enum { - MOD_SMOKE_HIGHRES = (1 << 1), /* enable high resolution */ - MOD_SMOKE_DISSOLVE = (1 << 2), /* let smoke dissolve */ - MOD_SMOKE_DISSOLVE_LOG = (1 << 3), /* using 1/x for dissolve */ - -#ifdef DNA_DEPRECATED - MOD_SMOKE_HIGH_SMOOTH = (1 << 5), /* -- Deprecated -- */ -#endif - MOD_SMOKE_FILE_LOAD = (1 << 6), /* flag for file load */ - MOD_SMOKE_ADAPTIVE_DOMAIN = (1 << 7), -}; - -/* noise */ -#define MOD_SMOKE_NOISEWAVE (1 << 0) -#define MOD_SMOKE_NOISEFFT (1 << 1) -#define MOD_SMOKE_NOISECURL (1 << 2) -/* viewsettings */ -#define MOD_SMOKE_VIEW_SHOW_HIGHRES (1 << 0) - -/* slice method */ -enum { - MOD_SMOKE_SLICE_VIEW_ALIGNED = 0, - MOD_SMOKE_SLICE_AXIS_ALIGNED = 1, -}; - -/* axis aligned method */ -enum { - AXIS_SLICE_FULL = 0, - AXIS_SLICE_SINGLE = 1, -}; - -/* single slice direction */ -enum { - SLICE_AXIS_AUTO = 0, - SLICE_AXIS_X = 1, - SLICE_AXIS_Y = 2, - SLICE_AXIS_Z = 3, -}; - -/* axis aligned method */ -enum { - VOLUME_INTERP_LINEAR = 0, - VOLUME_INTERP_CUBIC = 1, -}; - -enum { - VECTOR_DRAW_NEEDLE = 0, - VECTOR_DRAW_STREAMLINE = 1, -}; - -enum { - FLUID_FIELD_DENSITY = 0, - FLUID_FIELD_HEAT = 1, - FLUID_FIELD_FUEL = 2, - FLUID_FIELD_REACT = 3, - FLUID_FIELD_FLAME = 4, - FLUID_FIELD_VELOCITY_X = 5, - FLUID_FIELD_VELOCITY_Y = 6, - FLUID_FIELD_VELOCITY_Z = 7, - FLUID_FIELD_COLOR_R = 8, - FLUID_FIELD_COLOR_G = 9, - FLUID_FIELD_COLOR_B = 10, - FLUID_FIELD_FORCE_X = 11, - FLUID_FIELD_FORCE_Y = 12, - FLUID_FIELD_FORCE_Z = 13, -}; - -/* cache compression */ -#define SM_CACHE_LIGHT 0 -#define SM_CACHE_HEAVY 1 - -/* domain border collision */ -#define SM_BORDER_OPEN 0 -#define SM_BORDER_VERTICAL 1 -#define SM_BORDER_CLOSED 2 - -/* collision types */ -#define SM_COLL_STATIC 0 -#define SM_COLL_RIGID 1 -#define SM_COLL_ANIMATED 2 - -/* high resolution sampling types */ -#define SM_HRES_NEAREST 0 -#define SM_HRES_LINEAR 1 -#define SM_HRES_FULLSAMPLE 2 - -/* smoke data fields (active_fields) */ -#define SM_ACTIVE_HEAT (1 << 0) -#define SM_ACTIVE_FIRE (1 << 1) -#define SM_ACTIVE_COLORS (1 << 2) -#define SM_ACTIVE_COLOR_SET (1 << 3) - -enum { - VDB_COMPRESSION_BLOSC = 0, - VDB_COMPRESSION_ZIP = 1, - VDB_COMPRESSION_NONE = 2, -}; - -typedef struct SmokeDomainSettings { - /** For fast RNA access. */ - struct SmokeModifierData *smd; - struct FLUID_3D *fluid; - void *fluid_mutex; - struct Collection *fluid_group; - struct Collection *eff_group; // UNUSED - struct Collection *coll_group; // collision objects group - struct WTURBULENCE *wt; // WTURBULENCE object, if active - struct GPUTexture *tex; - struct GPUTexture *tex_wt; - struct GPUTexture *tex_shadow; - struct GPUTexture *tex_flame; - struct GPUTexture *tex_flame_coba; - struct GPUTexture *tex_coba; - struct GPUTexture *tex_field; - struct GPUTexture *tex_velocity_x; - struct GPUTexture *tex_velocity_y; - struct GPUTexture *tex_velocity_z; - float *shadow; - - /* simulation data */ - /** Start point of BB in local space (includes sub-cell shift for adaptive domain.)*/ - float p0[3]; - /** End point of BB in local space. */ - float p1[3]; - /** Difference from object center to grid start point. */ - float dp0[3]; - /** Size of simulation cell in local space. */ - float cell_size[3]; - /** Global size of domain axises. */ - float global_size[3]; - float prev_loc[3]; - /** Current domain shift in simulation cells. */ - int shift[3]; - /** Exact domain shift. */ - float shift_f[3]; - /** - * How much object has shifted since previous smoke frame - * (used to "lock" domain while drawing). - */ - float obj_shift_f[3]; - /** Domain object imat. */ - float imat[4][4]; - /** Domain obmat. */ - float obmat[4][4]; - /** Low res fluid matrix. */ - float fluidmat[4][4]; - /** High res fluid matrix. */ - float fluidmat_wt[4][4]; - - /** Initial "non-adapted" resolution. */ - int base_res[3]; - /** Cell min. */ - int res_min[3]; - /** Cell max. */ - int res_max[3]; - /** Data resolution (res_max-res_min). */ - int res[3]; - int total_cells; - /** 1.0f / res. */ - float dx; - /** Largest domain size. */ - float scale; - - /* user settings */ - int adapt_margin; - int adapt_res; - float adapt_threshold; - - float alpha; - float beta; - /** Wavelet amplification. */ - int amplify; - /** Longest axis on the BB gets this resolution assigned. */ - int maxres; - /** Show up-res or low res, etc. */ - int flags; - int viewsettings; - /** Noise type: wave, curl, anisotropic. */ - short noise; - short diss_percent; - /** In frames. */ - int diss_speed; - float strength; - int res_wt[3]; - float dx_wt; - /* point cache options */ - int cache_comp; - int cache_high_comp; - /* OpenVDB cache options */ - int openvdb_comp; - char cache_file_format; - char data_depth; - char _pad[2]; - - /* Smoke uses only one cache from now on (index [0]), - * but keeping the array for now for reading old files. */ - /** Definition is in DNA_object_force_types.h. */ - struct PointCache *point_cache[2]; - struct ListBase ptcaches[2]; - struct EffectorWeights *effector_weights; - /** How domain border collisions are handled. */ - int border_collisions; - float time_scale; - float vorticity; - int active_fields; - /** Monitor color situation of simulation. */ - float active_color[3]; - int highres_sampling; - - /* flame parameters */ - float burning_rate, flame_smoke, flame_vorticity; - float flame_ignition, flame_max_temp; - float flame_smoke_color[3]; - - /* Display settings */ - char slice_method, axis_slice_method; - char slice_axis, draw_velocity; - float slice_per_voxel; - float slice_depth; - float display_thickness; - - struct ColorBand *coba; - float vector_scale; - char vector_draw_type; - char use_coba; - /** Simulation field used for the color mapping. */ - char coba_field; - char interp_method; - - float clipping; - char _pad3[4]; -} SmokeDomainSettings; - -/* inflow / outflow */ - -/* type */ -#define MOD_SMOKE_FLOW_TYPE_SMOKE 0 -#define MOD_SMOKE_FLOW_TYPE_FIRE 1 -#define MOD_SMOKE_FLOW_TYPE_OUTFLOW 2 -#define MOD_SMOKE_FLOW_TYPE_SMOKEFIRE 3 - -/* flow source */ -#define MOD_SMOKE_FLOW_SOURCE_PARTICLES 0 -#define MOD_SMOKE_FLOW_SOURCE_MESH 1 - -/* flow texture type */ -#define MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO 0 -#define MOD_SMOKE_FLOW_TEXTURE_MAP_UV 1 - -/* flags */ -enum { - /** Old style emission. */ - MOD_SMOKE_FLOW_ABSOLUTE = (1 << 1), - /** Passes particles speed to the smoke. */ - MOD_SMOKE_FLOW_INITVELOCITY = (1 << 2), - /** Use texture to control emission speed. */ - MOD_SMOKE_FLOW_TEXTUREEMIT = (1 << 3), - /** Use specific size for particles instead of closest cell. */ - MOD_SMOKE_FLOW_USE_PART_SIZE = (1 << 4), -}; - -typedef struct SmokeFlowSettings { - /** For fast RNA access. */ - struct SmokeModifierData *smd; - struct Mesh *mesh; - struct ParticleSystem *psys; - struct Tex *noise_texture; - - /* initial velocity */ - /** Previous vertex positions in domain space. */ - float *verts_old; - int numverts; - float vel_multi; // Multiplier for inherited velocity - float vel_normal; - float vel_random; - /* emission */ - float density; - float color[3]; - float fuel_amount; - /** Delta temperature (temp - ambient temp). */ - float temp; - /** Density emitted within mesh volume. */ - float volume_density; - /** Maximum emission distance from mesh surface. */ - float surface_distance; - float particle_size; - int subframes; - /* texture control */ - float texture_size; - float texture_offset; - char _pad[4]; - /** MAX_CUSTOMDATA_LAYER_NAME. */ - char uvlayer_name[64]; - short vgroup_density; - - /** Smoke, flames, both, outflow. */ - short type; - short source; - short texture_type; - /** Absolute emission et.c*/ - int flags; -} SmokeFlowSettings; - -// struct BVHTreeFromMesh *bvh; -// float mat[4][4]; -// float mat_old[4][4]; - -/* collision objects (filled with smoke) */ -typedef struct SmokeCollSettings { - /** For fast RNA access. */ - struct SmokeModifierData *smd; - struct Mesh *mesh; - float *verts_old; - int numverts; - short type; // static = 0, rigid = 1, dynamic = 2 - char _pad[2]; -} SmokeCollSettings; - -#endif diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h index 1c1bb9b9ce1..81548343da0 100644 --- a/source/blender/makesdna/DNA_sound_types.h +++ b/source/blender/makesdna/DNA_sound_types.h @@ -112,7 +112,7 @@ enum { /* bSound->flags */ enum { -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW /* deprecated! used for sound actuator loading */ SOUND_FLAGS_3D = (1 << 3), #endif diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 8261b9e678b..7adba2b7dbe 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1697,7 +1697,7 @@ typedef enum eSpace_Type { SPACE_INFO = 7, SPACE_SEQ = 8, SPACE_TEXT = 9, -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW SPACE_IMASEL = 10, /* Deprecated */ SPACE_SOUND = 11, /* Deprecated */ #endif @@ -1705,11 +1705,11 @@ typedef enum eSpace_Type { SPACE_NLA = 13, /* TODO: fully deprecate */ SPACE_SCRIPT = 14, /* Deprecated */ -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW SPACE_TIME = 15, /* Deprecated */ #endif SPACE_NODE = 16, -#ifdef DNA_DEPRECATED +#ifdef DNA_DEPRECATED_ALLOW SPACE_LOGIC = 17, /* Deprecated */ #endif SPACE_CONSOLE = 18, diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index fb23b39a616..1f92b134e4c 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -1012,10 +1012,10 @@ typedef enum eUserpref_UI_Flag { USER_ZOOM_HORIZ = (1 << 26), /* for CONTINUE and DOLLY zoom */ USER_SPLASH_DISABLE = (1 << 27), USER_HIDE_RECENT = (1 << 28), -#ifdef DNA_DEPRECATED - USER_SHOW_THUMBNAILS = - (1 << 29), /* deprecated - We're just trying if there's much desire for this feature, or if - we can make it go for good. Should be cleared if so - Julian, Oct. 2019 */ +#ifdef DNA_DEPRECATED_ALLOW + /* Deprecated: We're just trying if there's much desire for this feature, + * or if we can make it go for good. Should be cleared if so - Julian, Oct. 2019. */ + USER_SHOW_THUMBNAILS = (1 << 29), #endif USER_SAVE_PROMPT = (1 << 30), USER_HIDE_SYSTEM_BOOKMARKS = (1u << 31), diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index 0bc35c15e35..404f483fde2 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -68,6 +68,13 @@ DNA_STRUCT_RENAME_ELEM(Camera, YF_dofdist, dof_distance) DNA_STRUCT_RENAME_ELEM(Camera, clipend, clip_end) DNA_STRUCT_RENAME_ELEM(Camera, clipsta, clip_start) DNA_STRUCT_RENAME_ELEM(Collection, dupli_ofs, instance_offset) +DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, cache_frame_pause_guiding, cache_frame_pause_guide) +DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_alpha, guide_alpha) +DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_beta, guide_beta) +DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_parent, guide_parent) +DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_source, guide_source) +DNA_STRUCT_RENAME_ELEM(FluidDomainSettings, guiding_vel_factor, guide_vel_factor) +DNA_STRUCT_RENAME_ELEM(FluidEffectorSettings, guiding_mode, guide_mode) DNA_STRUCT_RENAME_ELEM(Object, col, color) DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection) DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale) diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index f4bc79b786a..dc32ca7e244 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -118,7 +118,7 @@ static const char *includefiles[] = { "DNA_windowmanager_types.h", "DNA_anim_types.h", "DNA_boid_types.h", - "DNA_smoke_types.h", + "DNA_fluid_types.h", "DNA_speaker_types.h", "DNA_movieclip_types.h", "DNA_tracking_types.h", @@ -903,7 +903,8 @@ static int calculate_struct_sizes(int firststruct, FILE *file_verify, const char /* Write test to verify sizes are accurate. */ fprintf(file_verify, "/* Verify struct sizes and member offsets are as expected by DNA. */\n"); fprintf(file_verify, "#include \"BLI_assert.h\"\n\n"); - fprintf(file_verify, "#define DNA_DEPRECATED\n"); + /* Needed so we can find offsets of deprecated structs. */ + fprintf(file_verify, "#define DNA_DEPRECATED_ALLOW\n"); /* Workaround enum naming collision in static asserts * (ideally this included a unique name/id per file). */ fprintf(file_verify, "#define assert_line_ assert_line_DNA_\n"); @@ -1579,7 +1580,7 @@ int main(int argc, char **argv) #include "DNA_windowmanager_types.h" #include "DNA_anim_types.h" #include "DNA_boid_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_speaker_types.h" #include "DNA_movieclip_types.h" #include "DNA_tracking_types.h" diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 00491f25b17..f8e78e9c8fc 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -35,12 +35,12 @@ struct ID; struct IDOverrideLibrary; struct IDOverrideLibraryProperty; struct IDOverrideLibraryPropertyOperation; +struct IDProperty; struct ListBase; struct Main; struct ReportList; struct Scene; struct bContext; -struct IDProperty; /* Types */ extern BlenderRNA BLENDER_RNA; @@ -263,7 +263,6 @@ extern StructRNA RNA_FloatProperty; extern StructRNA RNA_FloorConstraint; extern StructRNA RNA_FluidFluidSettings; extern StructRNA RNA_FluidSettings; -extern StructRNA RNA_FluidSimulationModifier; extern StructRNA RNA_FollowPathConstraint; extern StructRNA RNA_FreestyleLineSet; extern StructRNA RNA_FreestyleLineStyle; @@ -597,10 +596,10 @@ extern StructRNA RNA_ShrinkwrapModifier; extern StructRNA RNA_SimpleDeformModifier; extern StructRNA RNA_SimplifyGpencilModifier; extern StructRNA RNA_SkinModifier; -extern StructRNA RNA_SmokeCollSettings; -extern StructRNA RNA_SmokeDomainSettings; -extern StructRNA RNA_SmokeFlowSettings; -extern StructRNA RNA_SmokeModifier; +extern StructRNA RNA_FluidEffectorSettings; +extern StructRNA RNA_FluidDomainSettings; +extern StructRNA RNA_FluidFlowSettings; +extern StructRNA RNA_FluidModifier; extern StructRNA RNA_SmoothGpencilModifier; extern StructRNA RNA_SmoothModifier; extern StructRNA RNA_SoftBodyModifier; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index f3ade54d5ec..3082daa83a4 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -44,7 +44,7 @@ set(DEFSRC rna_depsgraph.c rna_dynamicpaint.c rna_fcurve.c - rna_fluidsim.c + rna_fluid.c rna_gpencil.c rna_gpencil_modifier.c rna_image.c @@ -77,7 +77,6 @@ set(DEFSRC rna_sculpt_paint.c rna_sequencer.c rna_shader_fx.c - rna_smoke.c rna_sound.c rna_space.c rna_speaker.c @@ -241,16 +240,12 @@ if(WITH_CODEC_FFMPEG) add_definitions(-DWITH_FFMPEG) endif() -if(WITH_MOD_FLUID) - add_definitions(-DWITH_MOD_FLUID) -endif() - if(WITH_FFTW3) add_definitions(-DWITH_FFTW3) endif() -if(WITH_MOD_SMOKE) - add_definitions(-DWITH_SMOKE) +if(WITH_MOD_FLUID) + add_definitions(-DWITH_FLUID) endif() if(WITH_MOD_OCEANSIM) @@ -348,7 +343,7 @@ blender_include_dirs( ../../../../intern/glew-mx ../../../../intern/guardedalloc ../../../../intern/memutil - ../../../../intern/smoke/extern + ../../../../intern/mantaflow/extern ) blender_include_dirs_sys( diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index bef2e34065f..e5da9ee4ecd 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4231,7 +4231,6 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_curve.c", "rna_curve_api.c", RNA_def_curve}, {"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint}, {"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve}, - {"rna_fluidsim.c", NULL, RNA_def_fluidsim}, {"rna_gpencil.c", NULL, RNA_def_gpencil}, {"rna_image.c", "rna_image_api.c", RNA_def_image}, {"rna_key.c", NULL, RNA_def_key}, @@ -4240,6 +4239,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_layer.c", NULL, RNA_def_view_layer}, {"rna_linestyle.c", NULL, RNA_def_linestyle}, {"rna_main.c", "rna_main_api.c", RNA_def_main}, + {"rna_fluid.c", NULL, RNA_def_fluid}, {"rna_material.c", "rna_material_api.c", RNA_def_material}, {"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh}, {"rna_meta.c", "rna_meta_api.c", RNA_def_meta}, @@ -4263,7 +4263,6 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_screen.c", NULL, RNA_def_screen}, {"rna_sculpt_paint.c", NULL, RNA_def_sculpt_paint}, {"rna_sequencer.c", "rna_sequencer_api.c", RNA_def_sequencer}, - {"rna_smoke.c", NULL, RNA_def_smoke}, {"rna_space.c", "rna_space_api.c", RNA_def_space}, {"rna_speaker.c", NULL, RNA_def_speaker}, {"rna_test.c", NULL, RNA_def_test}, diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 2d70950ce7b..5b683ffd80e 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1596,6 +1596,22 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem brush_jitter_unit_items[] = { + {BRUSH_ABSOLUTE_JITTER, "VIEW", 0, "View", "Jitterring happens in screen space, in pixels"}, + {0, "BRUSH", 0, "Brush", "Jitterring happens relative to the brush size"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem falloff_shape_unit_items[] = { + {0, "SPHERE", 0, "Sphere", "Apply brush influence in a Sphere, outwards from the center"}, + {PAINT_FALLOFF_SHAPE_TUBE, + "PROJECTED", + 0, + "Projected", + "Apply brush influence in a 2D circle, projected from the view"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem brush_curve_preset_items[] = { {BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""}, {BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""}, @@ -1704,6 +1720,19 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Deformation", "Deformation type that is used in the brush"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "jitter_unit", PROP_ENUM, PROP_NONE); /* as an enum */ + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, brush_jitter_unit_items); + RNA_def_property_ui_text( + prop, "Jitter Unit", "Jitter in screen space or relative to brush size"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "falloff_shape", PROP_ENUM, PROP_NONE); /* as an enum */ + RNA_def_property_enum_bitflag_sdna(prop, NULL, "falloff_shape"); + RNA_def_property_enum_items(prop, falloff_shape_unit_items); + RNA_def_property_ui_text(prop, "Falloff Shape", "Use projected or spherical falloff"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + /* number values */ prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL); RNA_def_property_int_funcs(prop, NULL, "rna_Brush_set_size", NULL); @@ -1993,13 +2022,6 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Brush_update"); /* flag */ - /* This is an enum but its unlikely we add other shapes, so expose as a boolean. */ - prop = RNA_def_property(srna, "use_projected", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "falloff_shape", PAINT_FALLOFF_SHAPE_TUBE); - RNA_def_property_ui_text( - prop, "2D Falloff", "Apply brush influence in 2D circle instead of a sphere"); - RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_airbrush", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_AIRBRUSH); RNA_def_property_ui_text( @@ -2045,7 +2067,7 @@ static void rna_def_brush(BlenderRNA *brna) prop = RNA_def_property(srna, "use_paint_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "sampling_flag", BRUSH_PAINT_ANTIALIASING); - RNA_def_property_ui_text(prop, "Antialasing", "Smooths the edges of the strokes"); + RNA_def_property_ui_text(prop, "Anti-Aliasing", "Smooths the edges of the strokes"); prop = RNA_def_property(srna, "use_multiplane_scrape_dynamic", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag2", BRUSH_MULTIPLANE_SCRAPE_DYNAMIC); @@ -2117,13 +2139,6 @@ static void rna_def_brush(BlenderRNA *brna) prop, "Inverse Smooth Pressure", "Lighter pressure causes more smoothing to be applied"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_relative_jitter", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", BRUSH_ABSOLUTE_JITTER); - RNA_def_property_ui_icon(prop, ICON_UNLOCKED, true); - RNA_def_property_ui_text( - prop, "Absolute Jitter", "Jittering happens in screen space, not relative to brush size"); - RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_plane_trim", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_PLANE_TRIM); RNA_def_property_ui_text(prop, "Use Plane Trim", "Enable Plane Trim"); diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c new file mode 100644 index 00000000000..44bcab7d41a --- /dev/null +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -0,0 +1,2590 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup RNA + */ + +#include <stdlib.h> +#include <limits.h> + +#include "BLI_utildefines.h" +#include "BLI_path_util.h" +#include "BLI_sys_types.h" + +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "rna_internal.h" + +#include "BKE_modifier.h" +#include "BKE_fluid.h" +#include "BKE_pointcache.h" + +#include "DNA_modifier_types.h" +#include "DNA_object_force_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_fluid_types.h" +#include "DNA_particle_types.h" + +#include "WM_types.h" +#include "WM_api.h" + +#ifdef RNA_RUNTIME + +# include "BLI_math.h" +# include "BLI_threads.h" + +# include "BKE_colorband.h" +# include "BKE_context.h" +# include "BKE_particle.h" + +# include "DEG_depsgraph.h" +# include "DEG_depsgraph_build.h" + +# include "manta_fluid_API.h" + +static void rna_Fluid_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY); + + // Needed for liquid domain objects + Object *ob = (Object *)ptr->owner_id; + WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob); +} + +static void rna_Fluid_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + rna_Fluid_update(bmain, scene, ptr); + DEG_relations_tag_update(bmain); +} + +static void rna_Fluid_resetCache(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + if (settings->mmd && settings->mmd->domain) { + settings->mmd->domain->cache_flag |= (FLUID_DOMAIN_OUTDATED_DATA | + FLUID_DOMAIN_OUTDATED_NOISE | + FLUID_DOMAIN_OUTDATED_MESH | + FLUID_DOMAIN_OUTDATED_PARTICLES); + scene->r.cfra = settings->cache_frame_start; + } + DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY); +} +static void rna_Fluid_reset(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + +# ifdef WITH_FLUID + { + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + BKE_fluid_modifier_reset(settings->mmd); + } +# endif + + rna_Fluid_resetCache(bmain, scene, ptr); + + rna_Fluid_update(bmain, scene, ptr); +} + +static void rna_Fluid_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + +# ifdef WITH_FLUID + BKE_fluid_modifier_reset(settings->mmd); +# endif + + if (settings->mmd && settings->mmd->domain) { + settings->mmd->domain->point_cache[0]->flag |= PTCACHE_OUTDATED; + } + + rna_Fluid_dependency_update(bmain, scene, ptr); +} + +static void rna_Fluid_parts_create(Main *bmain, + PointerRNA *ptr, + const char *pset_name, + const char *parts_name, + const char *psys_name, + int psys_type) +{ +# ifndef WITH_FLUID + UNUSED_VARS(bmain, ptr, pset_name, parts_name, psys_name, psys_type); +# else + Object *ob = (Object *)ptr->owner_id; + BKE_fluid_particle_system_create(bmain, ob, pset_name, parts_name, psys_name, psys_type); +# endif +} + +static void rna_Fluid_parts_delete(PointerRNA *ptr, int ptype) +{ +# ifndef WITH_FLUID + UNUSED_VARS(ptr, ptype); +# else + Object *ob = (Object *)ptr->owner_id; + BKE_fluid_particle_system_destroy(ob, ptype); +# endif +} + +static bool rna_Fluid_parts_exists(PointerRNA *ptr, int ptype) +{ + Object *ob = (Object *)ptr->owner_id; + ParticleSystem *psys; + + for (psys = ob->particlesystem.first; psys; psys = psys->next) { + if (psys->part->type == ptype) { + return true; + } + } + return false; +} + +static void rna_Fluid_draw_type_update(Main *UNUSED(bmain), + Scene *UNUSED(scene), + struct PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + + /* Wireframe mode more convenient when particles present */ + if (settings->particle_type == 0) { + ob->dt = OB_SOLID; + } + else { + ob->dt = OB_WIRE; + } +} + +static void rna_Fluid_flip_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + FluidModifierData *mmd; + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FLIP); + + if (ob->type == OB_MESH && !exists) { + rna_Fluid_parts_create(bmain, + ptr, + "FlipParticleSettings", + "FLIP Particles", + "FLIP Particle System", + PART_FLUID_FLIP); + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FLIP; + } + else { + rna_Fluid_parts_delete(ptr, PART_FLUID_FLIP); + rna_Fluid_resetCache(bmain, scene, ptr); + + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FLIP; + } + rna_Fluid_draw_type_update(NULL, NULL, ptr); + rna_Fluid_reset(bmain, scene, ptr); +} + +static void rna_Fluid_spray_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + FluidModifierData *mmd; + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_SPRAY); + + if (ob->type == OB_MESH && !exists) { + rna_Fluid_parts_create(bmain, + ptr, + "SprayParticleSettings", + "Spray Particles", + "Spray Particle System", + PART_FLUID_SPRAY); + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY; + } + else { + rna_Fluid_parts_delete(ptr, PART_FLUID_SPRAY); + rna_Fluid_resetCache(bmain, scene, ptr); + + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_SPRAY; + } + rna_Fluid_draw_type_update(NULL, NULL, ptr); + rna_Fluid_reset(bmain, scene, ptr); +} + +static void rna_Fluid_bubble_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + FluidModifierData *mmd; + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_BUBBLE); + + if (ob->type == OB_MESH && !exists) { + rna_Fluid_parts_create(bmain, + ptr, + "BubbleParticleSettings", + "Bubble Particles", + "Bubble Particle System", + PART_FLUID_BUBBLE); + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE; + } + else { + rna_Fluid_parts_delete(ptr, PART_FLUID_BUBBLE); + rna_Fluid_resetCache(bmain, scene, ptr); + + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_BUBBLE; + } + rna_Fluid_draw_type_update(NULL, NULL, ptr); + rna_Fluid_reset(bmain, scene, ptr); +} + +static void rna_Fluid_foam_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + FluidModifierData *mmd; + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_FOAM); + + if (ob->type == OB_MESH && !exists) { + rna_Fluid_parts_create(bmain, + ptr, + "FoamParticleSettings", + "Foam Particles", + "Foam Particle System", + PART_FLUID_FOAM); + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM; + } + else { + rna_Fluid_parts_delete(ptr, PART_FLUID_FOAM); + rna_Fluid_resetCache(bmain, scene, ptr); + + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_FOAM; + } + rna_Fluid_draw_type_update(NULL, NULL, ptr); + rna_Fluid_reset(bmain, scene, ptr); +} + +static void rna_Fluid_tracer_parts_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + FluidModifierData *mmd; + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + bool exists = rna_Fluid_parts_exists(ptr, PART_FLUID_TRACER); + + if (ob->type == OB_MESH && !exists) { + rna_Fluid_parts_create(bmain, + ptr, + "TracerParticleSettings", + "Tracer Particles", + "Tracer Particle System", + PART_FLUID_TRACER); + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_TRACER; + } + else { + rna_Fluid_parts_delete(ptr, PART_FLUID_TRACER); + rna_Fluid_resetCache(bmain, scene, ptr); + + mmd->domain->particle_type &= ~FLUID_DOMAIN_PARTICLE_TRACER; + } + rna_Fluid_draw_type_update(NULL, NULL, ptr); + rna_Fluid_reset(bmain, scene, ptr); +} + +static void rna_Fluid_combined_export_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + FluidModifierData *mmd; + mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + + if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_OFF) { + rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE)); + + // re-add each particle type if enabled + if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) != 0) { + rna_Fluid_spray_parts_update(bmain, scene, ptr); + } + if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) != 0) { + rna_Fluid_foam_parts_update(bmain, scene, ptr); + } + if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) != 0) { + rna_Fluid_bubble_parts_update(bmain, scene, ptr); + } + } + else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM) { + if (ob->type == OB_MESH && + !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM))) { + rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM)); + } + rna_Fluid_parts_create(bmain, + ptr, + "SprayFoamParticleSettings", + "Spray + Foam Particles", + "Spray + Foam Particle System", + (PART_FLUID_SPRAY | PART_FLUID_FOAM)); + + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY; + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM; + + // re-add bubbles if enabled + if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_BUBBLE) != 0) { + rna_Fluid_bubble_parts_update(bmain, scene, ptr); + } + } + else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE) { + if (ob->type == OB_MESH && + !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_BUBBLE))) { + rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_BUBBLE)); + } + rna_Fluid_parts_create(bmain, + ptr, + "SprayBubbleParticleSettings", + "Spray + Bubble Particles", + "Spray + Bubble Particle System", + (PART_FLUID_SPRAY | PART_FLUID_BUBBLE)); + + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY; + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE; + + // re-add foam if enabled + if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_FOAM) != 0) { + rna_Fluid_foam_parts_update(bmain, scene, ptr); + } + } + else if (mmd->domain->sndparticle_combined_export == SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE) { + if (ob->type == OB_MESH && + !rna_Fluid_parts_exists(ptr, (PART_FLUID_FOAM | PART_FLUID_BUBBLE))) { + rna_Fluid_parts_delete(ptr, (PART_FLUID_FOAM | PART_FLUID_BUBBLE)); + } + rna_Fluid_parts_create(bmain, + ptr, + "FoamBubbleParticleSettings", + "Foam + Bubble Particles", + "Foam + Bubble Particle System", + (PART_FLUID_FOAM | PART_FLUID_BUBBLE)); + + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM; + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE; + + // re-add spray if enabled + if ((mmd->domain->particle_type & FLUID_DOMAIN_PARTICLE_SPRAY) != 0) { + rna_Fluid_spray_parts_update(bmain, scene, ptr); + } + } + else if (mmd->domain->sndparticle_combined_export == + SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE) { + if (ob->type == OB_MESH && + !rna_Fluid_parts_exists(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE))) { + rna_Fluid_parts_delete(ptr, (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE)); + } + rna_Fluid_parts_create(bmain, + ptr, + "SprayFoamBubbleParticleSettings", + "Spray + Foam + Bubble Particles", + "Spray + Foam + Bubble Particle System", + (PART_FLUID_SPRAY | PART_FLUID_FOAM | PART_FLUID_BUBBLE)); + + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_SPRAY; + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_FOAM; + mmd->domain->particle_type |= FLUID_DOMAIN_PARTICLE_BUBBLE; + } + else { + // sanity check, should not occur + printf("ERROR: Unexpected combined export setting encountered!"); + } + rna_Fluid_resetCache(bmain, scene, ptr); + rna_Fluid_draw_type_update(NULL, NULL, ptr); +} + +static void rna_Fluid_cachetype_mesh_set(struct PointerRNA *ptr, int value) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + + if (value != settings->cache_mesh_format) { + /* TODO (sebbas): Clear old caches. */ + settings->cache_mesh_format = value; + } +} + +static void rna_Fluid_cachetype_data_set(struct PointerRNA *ptr, int value) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + + if (value != settings->cache_data_format) { + /* TODO (sebbas): Clear old caches. */ + settings->cache_data_format = value; + } +} + +static void rna_Fluid_cachetype_particle_set(struct PointerRNA *ptr, int value) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + + if (value != settings->cache_particle_format) { + /* TODO (sebbas): Clear old caches. */ + settings->cache_particle_format = value; + } +} + +static void rna_Fluid_cachetype_noise_set(struct PointerRNA *ptr, int value) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + + if (value != settings->cache_noise_format) { + /* TODO (sebbas): Clear old caches. */ + settings->cache_noise_format = value; + } +} + +static void rna_Fluid_cachetype_set(struct PointerRNA *ptr, int value) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + + if (value != settings->cache_type) { + settings->cache_type = value; + settings->cache_flag = 0; + } +} + +static void rna_Fluid_guide_parent_set(struct PointerRNA *ptr, + struct PointerRNA value, + struct ReportList *UNUSED(reports)) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + Object *par = (Object *)value.data; + + FluidModifierData *mmd_par = NULL; + + if (par != NULL) { + mmd_par = (FluidModifierData *)modifiers_findByType(par, eModifierType_Fluid); + if (mmd_par && mmd_par->domain) { + mds->guide_parent = value.data; + copy_v3_v3_int(mds->guide_res, mmd_par->domain->res); + } + } + else { + mds->guide_parent = NULL; + } +} + +static const EnumPropertyItem *rna_Fluid_cachetype_mesh_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + EnumPropertyItem *item = NULL; + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int totitem = 0; + + tmp.value = FLUID_DOMAIN_FILE_BIN_OBJECT; + tmp.identifier = "BOBJECT"; + tmp.name = "Binary Object files"; + tmp.description = "Binary object file format"; + RNA_enum_item_add(&item, &totitem, &tmp); + + tmp.value = FLUID_DOMAIN_FILE_OBJECT; + tmp.identifier = "OBJECT"; + tmp.name = "Object files"; + tmp.description = "Object file format"; + RNA_enum_item_add(&item, &totitem, &tmp); + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static const EnumPropertyItem *rna_Fluid_cachetype_volume_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + EnumPropertyItem *item = NULL; + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int totitem = 0; + + tmp.value = FLUID_DOMAIN_FILE_UNI; + tmp.identifier = "UNI"; + tmp.name = "Uni Cache"; + tmp.description = "Uni file format"; + RNA_enum_item_add(&item, &totitem, &tmp); + +# ifdef WITH_OPENVDB + tmp.value = FLUID_DOMAIN_FILE_OPENVDB; + tmp.identifier = "OPENVDB"; + tmp.name = "OpenVDB"; + tmp.description = "OpenVDB file format"; + RNA_enum_item_add(&item, &totitem, &tmp); +# endif + + tmp.value = FLUID_DOMAIN_FILE_RAW; + tmp.identifier = "RAW"; + tmp.name = "Raw Cache"; + tmp.description = "Raw file format"; + RNA_enum_item_add(&item, &totitem, &tmp); + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static const EnumPropertyItem *rna_Fluid_cachetype_particle_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + EnumPropertyItem *item = NULL; + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int totitem = 0; + + tmp.value = FLUID_DOMAIN_FILE_UNI; + tmp.identifier = "UNI"; + tmp.name = "Uni Cache"; + tmp.description = "Uni file format"; + RNA_enum_item_add(&item, &totitem, &tmp); + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static void rna_Fluid_collisionextents_set(struct PointerRNA *ptr, int value, bool clear) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + if (clear) { + settings->border_collisions &= value; + } + else { + settings->border_collisions |= value; + } +} + +static void rna_Fluid_cache_directory_set(struct PointerRNA *ptr, const char *value) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + + if (STREQ(settings->cache_directory, value)) { + return; + } + + BLI_strncpy(settings->cache_directory, value, sizeof(settings->cache_directory)); + + /* TODO (sebbas): Read cache state in order to set cache bake flags and cache pause frames + * correctly */ + // settings->cache_flag = 0; +} + +static void rna_Fluid_domaintype_set(struct PointerRNA *ptr, int value) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + Object *ob = (Object *)ptr->owner_id; + + if (value != settings->type) { + /* Set common values for liquid/smoke domain: cache type, + * border collision and viewport draw-type. */ + if (value == FLUID_DOMAIN_TYPE_GAS) { + rna_Fluid_cachetype_mesh_set(ptr, FLUID_DOMAIN_FILE_BIN_OBJECT); + rna_Fluid_cachetype_data_set(ptr, FLUID_DOMAIN_FILE_UNI); + rna_Fluid_cachetype_particle_set(ptr, FLUID_DOMAIN_FILE_UNI); + rna_Fluid_cachetype_noise_set(ptr, FLUID_DOMAIN_FILE_UNI); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_FRONT, 1); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_BACK, 1); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_RIGHT, 1); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_LEFT, 1); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_TOP, 1); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_BOTTOM, 1); + ob->dt = OB_WIRE; + } + else if (value == FLUID_DOMAIN_TYPE_LIQUID) { + rna_Fluid_cachetype_mesh_set(ptr, FLUID_DOMAIN_FILE_BIN_OBJECT); + rna_Fluid_cachetype_data_set(ptr, FLUID_DOMAIN_FILE_UNI); + rna_Fluid_cachetype_particle_set(ptr, FLUID_DOMAIN_FILE_UNI); + rna_Fluid_cachetype_noise_set(ptr, FLUID_DOMAIN_FILE_UNI); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_FRONT, 0); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_BACK, 0); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_RIGHT, 0); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_LEFT, 0); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_TOP, 0); + rna_Fluid_collisionextents_set(ptr, FLUID_DOMAIN_BORDER_BOTTOM, 0); + ob->dt = OB_SOLID; + } + + /* Set actual domain type */ + settings->type = value; + } +} + +static char *rna_FluidDomainSettings_path(PointerRNA *ptr) +{ + FluidDomainSettings *settings = (FluidDomainSettings *)ptr->data; + ModifierData *md = (ModifierData *)settings->mmd; + char name_esc[sizeof(md->name) * 2]; + + BLI_strescape(name_esc, md->name, sizeof(name_esc)); + return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc); +} + +static char *rna_FluidFlowSettings_path(PointerRNA *ptr) +{ + FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data; + ModifierData *md = (ModifierData *)settings->mmd; + char name_esc[sizeof(md->name) * 2]; + + BLI_strescape(name_esc, md->name, sizeof(name_esc)); + return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc); +} + +static char *rna_FluidEffectorSettings_path(PointerRNA *ptr) +{ + FluidEffectorSettings *settings = (FluidEffectorSettings *)ptr->data; + ModifierData *md = (ModifierData *)settings->mmd; + char name_esc[sizeof(md->name) * 2]; + + BLI_strescape(name_esc, md->name, sizeof(name_esc)); + return BLI_sprintfN("modifiers[\"%s\"].effector_settings", name_esc); +} + +/* -------------------------------------------------------------------- */ +/** \name Grid Accessors + * \{ */ + +# ifdef WITH_FLUID + +static int rna_FluidModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + float *density = NULL; + int size = 0; + + if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) { + /* high resolution smoke */ + int res[3]; + + manta_smoke_turbulence_get_res(mds->fluid, res); + size = res[0] * res[1] * res[2]; + + density = manta_smoke_turbulence_get_density(mds->fluid); + } + else if (mds->fluid) { + /* regular resolution */ + size = mds->res[0] * mds->res[1] * mds->res[2]; + density = manta_smoke_get_density(mds->fluid); + } + + length[0] = (density) ? size : 0; + return length[0]; +} + +static int rna_FluidModifier_color_grid_get_length(PointerRNA *ptr, + int length[RNA_MAX_ARRAY_DIMENSION]) +{ + rna_FluidModifier_grid_get_length(ptr, length); + + length[0] *= 4; + return length[0]; +} + +static int rna_FluidModifier_velocity_grid_get_length(PointerRNA *ptr, + int length[RNA_MAX_ARRAY_DIMENSION]) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + float *vx = NULL; + float *vy = NULL; + float *vz = NULL; + int size = 0; + + /* Velocity data is always low-resolution. */ + if (mds->fluid) { + size = 3 * mds->res[0] * mds->res[1] * mds->res[2]; + vx = manta_get_velocity_x(mds->fluid); + vy = manta_get_velocity_y(mds->fluid); + vz = manta_get_velocity_z(mds->fluid); + } + + length[0] = (vx && vy && vz) ? size : 0; + return length[0]; +} + +static int rna_FluidModifier_heat_grid_get_length(PointerRNA *ptr, + int length[RNA_MAX_ARRAY_DIMENSION]) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + float *heat = NULL; + int size = 0; + + /* Heat data is always low-resolution. */ + if (mds->fluid) { + size = mds->res[0] * mds->res[1] * mds->res[2]; + heat = manta_smoke_get_heat(mds->fluid); + } + + length[0] = (heat) ? size : 0; + return length[0]; +} + +static void rna_FluidModifier_density_grid_get(PointerRNA *ptr, float *values) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + int length[RNA_MAX_ARRAY_DIMENSION]; + int size = rna_FluidModifier_grid_get_length(ptr, length); + float *density; + + BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ); + + if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) { + density = manta_smoke_turbulence_get_density(mds->fluid); + } + else { + density = manta_smoke_get_density(mds->fluid); + } + + memcpy(values, density, size * sizeof(float)); + + BLI_rw_mutex_unlock(mds->fluid_mutex); +} + +static void rna_FluidModifier_velocity_grid_get(PointerRNA *ptr, float *values) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + int length[RNA_MAX_ARRAY_DIMENSION]; + int size = rna_FluidModifier_velocity_grid_get_length(ptr, length); + float *vx, *vy, *vz; + int i; + + BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ); + + vx = manta_get_velocity_x(mds->fluid); + vy = manta_get_velocity_y(mds->fluid); + vz = manta_get_velocity_z(mds->fluid); + + for (i = 0; i < size; i += 3) { + *(values++) = *(vx++); + *(values++) = *(vy++); + *(values++) = *(vz++); + } + + BLI_rw_mutex_unlock(mds->fluid_mutex); +} + +static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + int length[RNA_MAX_ARRAY_DIMENSION]; + int size = rna_FluidModifier_grid_get_length(ptr, length); + + BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ); + + if (!mds->fluid) { + memset(values, 0, size * sizeof(float)); + } + else { + if (mds->flags & FLUID_DOMAIN_USE_NOISE) { + if (manta_smoke_turbulence_has_colors(mds->fluid)) { + manta_smoke_turbulence_get_rgba(mds->fluid, values, 0); + } + else { + manta_smoke_turbulence_get_rgba_from_density(mds->fluid, mds->active_color, values, 0); + } + } + else { + if (manta_smoke_has_colors(mds->fluid)) { + manta_smoke_get_rgba(mds->fluid, values, 0); + } + else { + manta_smoke_get_rgba_from_density(mds->fluid, mds->active_color, values, 0); + } + } + } + + BLI_rw_mutex_unlock(mds->fluid_mutex); +} + +static void rna_FluidModifier_flame_grid_get(PointerRNA *ptr, float *values) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + int length[RNA_MAX_ARRAY_DIMENSION]; + int size = rna_FluidModifier_grid_get_length(ptr, length); + float *flame; + + BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ); + + if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) { + flame = manta_smoke_turbulence_get_flame(mds->fluid); + } + else { + flame = manta_smoke_get_flame(mds->fluid); + } + + if (flame) { + memcpy(values, flame, size * sizeof(float)); + } + else { + memset(values, 0, size * sizeof(float)); + } + + BLI_rw_mutex_unlock(mds->fluid_mutex); +} + +static void rna_FluidModifier_heat_grid_get(PointerRNA *ptr, float *values) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + int length[RNA_MAX_ARRAY_DIMENSION]; + int size = rna_FluidModifier_heat_grid_get_length(ptr, length); + float *heat; + + BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ); + + heat = manta_smoke_get_heat(mds->fluid); + + if (heat != NULL) { + /* scale heat values from -2.0-2.0 to -1.0-1.0. */ + for (int i = 0; i < size; i++) { + values[i] = heat[i] * 0.5f; + } + } + else { + memset(values, 0, size * sizeof(float)); + } + + BLI_rw_mutex_unlock(mds->fluid_mutex); +} + +static void rna_FluidModifier_temperature_grid_get(PointerRNA *ptr, float *values) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + int length[RNA_MAX_ARRAY_DIMENSION]; + int size = rna_FluidModifier_grid_get_length(ptr, length); + float *flame; + + BLI_rw_mutex_lock(mds->fluid_mutex, THREAD_LOCK_READ); + + if (mds->flags & FLUID_DOMAIN_USE_NOISE && mds->fluid) { + flame = manta_smoke_turbulence_get_flame(mds->fluid); + } + else { + flame = manta_smoke_get_flame(mds->fluid); + } + + if (flame) { + /* Output is such that 0..1 maps to 0..1000K */ + float offset = mds->flame_ignition; + float scale = mds->flame_max_temp - mds->flame_ignition; + + for (int i = 0; i < size; i++) { + values[i] = (flame[i] > 0.01f) ? offset + flame[i] * scale : 0.0f; + } + } + else { + memset(values, 0, size * sizeof(float)); + } + + BLI_rw_mutex_unlock(mds->fluid_mutex); +} +# endif /* WITH_FLUID */ + +/** \} */ + +static void rna_FluidFlow_density_vgroup_get(PointerRNA *ptr, char *value) +{ + FluidFlowSettings *flow = (FluidFlowSettings *)ptr->data; + rna_object_vgroup_name_index_get(ptr, value, flow->vgroup_density); +} + +static int rna_FluidFlow_density_vgroup_length(PointerRNA *ptr) +{ + FluidFlowSettings *flow = (FluidFlowSettings *)ptr->data; + return rna_object_vgroup_name_index_length(ptr, flow->vgroup_density); +} + +static void rna_FluidFlow_density_vgroup_set(struct PointerRNA *ptr, const char *value) +{ + FluidFlowSettings *flow = (FluidFlowSettings *)ptr->data; + rna_object_vgroup_name_index_set(ptr, value, &flow->vgroup_density); +} + +static void rna_FluidFlow_uvlayer_set(struct PointerRNA *ptr, const char *value) +{ + FluidFlowSettings *flow = (FluidFlowSettings *)ptr->data; + rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name)); +} + +static void rna_Fluid_use_color_ramp_set(struct PointerRNA *ptr, bool value) +{ + FluidDomainSettings *mds = (FluidDomainSettings *)ptr->data; + + mds->use_coba = value; + + if (value && mds->coba == NULL) { + mds->coba = BKE_colorband_add(false); + } +} + +static void rna_Fluid_flowsource_set(struct PointerRNA *ptr, int value) +{ + FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data; + + if (value != settings->source) { + settings->source = value; + } +} + +static const EnumPropertyItem *rna_Fluid_flowsource_itemf(bContext *UNUSED(C), + PointerRNA *ptr, + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data; + + EnumPropertyItem *item = NULL; + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int totitem = 0; + + tmp.value = FLUID_FLOW_SOURCE_MESH; + tmp.identifier = "MESH"; + tmp.icon = ICON_META_CUBE; + tmp.name = "Mesh"; + tmp.description = "Emit fluid from mesh surface or volume"; + RNA_enum_item_add(&item, &totitem, &tmp); + + if (settings->type != FLUID_FLOW_TYPE_LIQUID) { + tmp.value = FLUID_FLOW_SOURCE_PARTICLES; + tmp.identifier = "PARTICLES"; + tmp.icon = ICON_PARTICLES; + tmp.name = "Particle System"; + tmp.description = "Emit smoke from particles"; + RNA_enum_item_add(&item, &totitem, &tmp); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +static void rna_Fluid_flowtype_set(struct PointerRNA *ptr, int value) +{ + FluidFlowSettings *settings = (FluidFlowSettings *)ptr->data; + + if (value != settings->type) { + settings->type = value; + + /* Force flow source to mesh */ + if (value == FLUID_FLOW_TYPE_LIQUID) { + rna_Fluid_flowsource_set(ptr, FLUID_FLOW_SOURCE_MESH); + settings->surface_distance = 0.0f; + } + else { + settings->surface_distance = 1.5f; + } + } +} + +#else + +static void rna_def_fluid_mesh_vertices(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "FluidDomainVertexVelocity", NULL); + RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh"); + RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL); + + prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY); + RNA_def_property_array(prop, 3); + RNA_def_property_float_sdna(prop, NULL, "vel"); + RNA_def_property_ui_text(prop, "Velocity", ""); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); +} + +static void rna_def_fluid_domain_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem domain_types[] = { + {FLUID_DOMAIN_TYPE_GAS, "GAS", 0, "Gas", "Create domain for gases"}, + {FLUID_DOMAIN_TYPE_LIQUID, "LIQUID", 0, "Liquid", "Create domain for liquids"}, + {0, NULL, 0, NULL, NULL}}; + + static const EnumPropertyItem prop_noise_type_items[] = { + {FLUID_NOISE_TYPE_WAVELET, "NOISEWAVE", 0, "Wavelet", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem prop_compression_items[] = { + {VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression"}, +# ifdef WITH_OPENVDB_BLOSC + {VDB_COMPRESSION_BLOSC, + "BLOSC", + 0, + "Blosc", + "Multithreaded compression, similar in size and quality as 'Zip'"}, +# endif + {VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression"}, + {0, NULL, 0, NULL, NULL}}; + + static const EnumPropertyItem cache_comp_items[] = { + {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Lite", "Fast but not so effective compression"}, + {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem smoke_highres_sampling_items[] = { + {SM_HRES_FULLSAMPLE, "FULLSAMPLE", 0, "Full Sample", ""}, + {SM_HRES_LINEAR, "LINEAR", 0, "Linear", ""}, + {SM_HRES_NEAREST, "NEAREST", 0, "Nearest", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static EnumPropertyItem cache_types[] = { + {FLUID_DOMAIN_CACHE_REPLAY, + "REPLAY", + 0, + "Replay", + "Use the timeline to bake the scene. Pausing and resuming possible."}, + {FLUID_DOMAIN_CACHE_MODULAR, + "MODULAR", + 0, + "Modular", + "Bake every stage of the simulation on its own. Can pause and resume bake jobs."}, + {FLUID_DOMAIN_CACHE_FINAL, "FINAL", 0, "Final", "Bake the entire simulation at once."}, + {0, NULL, 0, NULL, NULL}}; + + static const EnumPropertyItem smoke_data_depth_items[] = { + {16, "16", 0, "Float (Half)", "Half float (16 bit data)"}, + {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */ + {0, NULL, 0, NULL, NULL}, + }; + + static EnumPropertyItem fluid_mesh_quality_items[] = { + {FLUID_DOMAIN_MESH_IMPROVED, + "IMPROVED", + 0, + "Final", + "Use improved particle levelset (slower but more precise and with mesh smoothening " + "options)"}, + {FLUID_DOMAIN_MESH_UNION, + "UNION", + 0, + "Preview", + "Use union particle levelset (faster but lower quality)"}, + {0, NULL, 0, NULL, NULL}, + }; + + static EnumPropertyItem fluid_guide_source_items[] = { + {FLUID_DOMAIN_GUIDE_SRC_DOMAIN, + "DOMAIN", + 0, + "Domain", + "Use a fluid domain for guiding (domain needs to be baked already so that velocities can " + "be extracted but can be of any type)"}, + {FLUID_DOMAIN_GUIDE_SRC_EFFECTOR, + "EFFECTOR", + 0, + "Effector", + "Use guiding (effector) objects to create fluid guiding (guiding objects should be " + "animated and baked once set up completely)"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* Cache type - generated dynamically based on domain type */ + static EnumPropertyItem cache_file_type_items[] = { + {0, "NONE", 0, "", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem view_items[] = { + {FLUID_DOMAIN_SLICE_VIEW_ALIGNED, + "VIEW_ALIGNED", + 0, + "View", + "Slice volume parallel to the view plane"}, + {FLUID_DOMAIN_SLICE_AXIS_ALIGNED, + "AXIS_ALIGNED", + 0, + "Axis", + "Slice volume parallel to the major axis"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem axis_slice_method_items[] = { + {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"}, + {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem interp_method_item[] = { + {VOLUME_INTERP_LINEAR, "LINEAR", 0, "Linear", "Good smoothness and speed"}, + {VOLUME_INTERP_CUBIC, + "CUBIC", + 0, + "Cubic", + "Smoothed high quality interpolation, but slower"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem axis_slice_position_items[] = { + {SLICE_AXIS_AUTO, + "AUTO", + 0, + "Auto", + "Adjust slice direction according to the view direction"}, + {SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"}, + {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"}, + {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem vector_draw_items[] = { + {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Display vectors as needles"}, + {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Display vectors as streamlines"}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem sndparticle_boundary_items[] = { + {SNDPARTICLE_BOUNDARY_DELETE, + "DELETE", + 0, + "Delete", + "Delete secondary particles that are inside obstacles or left the domain"}, + {SNDPARTICLE_BOUNDARY_PUSHOUT, + "PUSHOUT", + 0, + "Push Out", + "Push secondary particles that left the domain back into the domain"}, + {0, NULL, 0, NULL, NULL}}; + + static const EnumPropertyItem sndparticle_combined_export_items[] = { + {SNDPARTICLE_COMBINED_EXPORT_OFF, + "OFF", + 0, + "Off", + "Create a seperate particle system for every secondary particle type"}, + {SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM, + "SPRAY_FOAM", + 0, + "Spray + Foam", + "Spray and foam particles are saved in the same particle system"}, + {SNDPARTICLE_COMBINED_EXPORT_SPRAY_BUBBLE, + "SPRAY_BUBBLES", + 0, + "Spray + Bubbles", + "Spray and bubble particles are saved in the same particle system"}, + {SNDPARTICLE_COMBINED_EXPORT_FOAM_BUBBLE, + "FOAM_BUBBLES", + 0, + "Foam + Bubbles", + "Foam and bubbles particles are saved in the same particle system"}, + {SNDPARTICLE_COMBINED_EXPORT_SPRAY_FOAM_BUBBLE, + "SPRAY_FOAM_BUBBLES", + 0, + "Spray + Foam + Bubbles", + "Create one particle system that contains all three secondary particle types"}, + {0, NULL, 0, NULL, NULL}}; + + static EnumPropertyItem simulation_methods[] = { + {FLUID_DOMAIN_METHOD_FLIP, "FLIP", 0, "FLIP", "Use FLIP as the simulation method"}, + /*{FLUID_DOMAIN_METHOD_APIC, "APIC", 0, "APIC", "Use APIC as the simulation method"},*/ + {0, NULL, 0, NULL, NULL}, + }; + + srna = RNA_def_struct(brna, "FluidDomainSettings", NULL); + RNA_def_struct_ui_text(srna, "Domain Settings", "Fluid domain settings"); + RNA_def_struct_sdna(srna, "FluidDomainSettings"); + RNA_def_struct_path_func(srna, "rna_FluidDomainSettings_path"); + + prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "EffectorWeights"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Effector Weights", ""); + + /* object collections */ + + prop = RNA_def_property(srna, "effector_group", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "effector_group"); + RNA_def_property_struct_type(prop, "Collection"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset_dependency"); + + prop = RNA_def_property(srna, "fluid_group", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "fluid_group"); + RNA_def_property_struct_type(prop, "Collection"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Fluid Collection", "Limit fluid objects to this collection"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset_dependency"); + + prop = RNA_def_property(srna, "force_collection", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "force_group"); + RNA_def_property_struct_type(prop, "Collection"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Force Collection", "Limit forces to this collection"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset_dependency"); + + /* grid access */ + +# ifdef WITH_FLUID + prop = RNA_def_property(srna, "density_grid", PROP_FLOAT, PROP_NONE); + RNA_def_property_array(prop, 32); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_grid_get_length"); + RNA_def_property_float_funcs(prop, "rna_FluidModifier_density_grid_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Density Grid", "Smoke density grid"); + + prop = RNA_def_property(srna, "velocity_grid", PROP_FLOAT, PROP_NONE); + RNA_def_property_array(prop, 32); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_velocity_grid_get_length"); + RNA_def_property_float_funcs(prop, "rna_FluidModifier_velocity_grid_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Velocity Grid", "Smoke velocity grid"); + + prop = RNA_def_property(srna, "flame_grid", PROP_FLOAT, PROP_NONE); + RNA_def_property_array(prop, 32); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_grid_get_length"); + RNA_def_property_float_funcs(prop, "rna_FluidModifier_flame_grid_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Flame Grid", "Smoke flame grid"); + + prop = RNA_def_property(srna, "color_grid", PROP_FLOAT, PROP_NONE); + RNA_def_property_array(prop, 32); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_color_grid_get_length"); + RNA_def_property_float_funcs(prop, "rna_FluidModifier_color_grid_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Color Grid", "Smoke color grid"); + + prop = RNA_def_property(srna, "heat_grid", PROP_FLOAT, PROP_NONE); + RNA_def_property_array(prop, 32); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_heat_grid_get_length"); + RNA_def_property_float_funcs(prop, "rna_FluidModifier_heat_grid_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid"); + + prop = RNA_def_property(srna, "temperature_grid", PROP_FLOAT, PROP_NONE); + RNA_def_property_array(prop, 32); + RNA_def_property_flag(prop, PROP_DYNAMIC); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_dynamic_array_funcs(prop, "rna_FluidModifier_grid_get_length"); + RNA_def_property_float_funcs(prop, "rna_FluidModifier_temperature_grid_get", NULL, NULL); + RNA_def_property_ui_text( + prop, "Temperature Grid", "Smoke temperature grid, range 0..1 represents 0..1000K"); +# endif /* WITH_FLUID */ + + /* domain object data */ + + prop = RNA_def_property(srna, + "start_point", + PROP_FLOAT, + PROP_XYZ); /* can change each frame when using adaptive domain */ + RNA_def_property_float_sdna(prop, NULL, "p0"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "p0", "Start point"); + + prop = RNA_def_property(srna, + "cell_size", + PROP_FLOAT, + PROP_XYZ); /* can change each frame when using adaptive domain */ + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "cell_size", "Cell Size"); + + prop = RNA_def_property(srna, + "domain_resolution", + PROP_INT, + PROP_XYZ); /* can change each frame when using adaptive domain */ + RNA_def_property_int_sdna(prop, NULL, "res"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "res", "Smoke Grid Resolution"); + + /* adaptive domain options */ + + prop = RNA_def_property(srna, "additional_res", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "adapt_res"); + RNA_def_property_range(prop, 0, 512); + RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "adapt_margin"); + RNA_def_property_range(prop, 2, 24); + RNA_def_property_ui_text( + prop, "Margin", "Margin added around fluid to minimize boundary interference"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.01, 0.5); + RNA_def_property_ui_text( + prop, "Threshold", "Maximum amount of fluid cell can contain before it is considered empty"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_ADAPTIVE_DOMAIN); + RNA_def_property_ui_text( + prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + /* fluid domain options */ + + prop = RNA_def_property(srna, "resolution_max", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "maxres"); + RNA_def_property_range(prop, 6, 10000); + RNA_def_property_ui_range(prop, 24, 10000, 2, -1); + RNA_def_property_ui_text(prop, "Max Res", "Resolution used for the fluid domain"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_collision_border_front", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_FRONT); + RNA_def_property_ui_text(prop, "Front", "Enable collisons with front domain border"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_collision_border_back", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_BACK); + RNA_def_property_ui_text(prop, "Back", "Enable collisons with back domain border"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_collision_border_right", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_RIGHT); + RNA_def_property_ui_text(prop, "Right", "Enable collisons with right domain border"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_collision_border_left", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_LEFT); + RNA_def_property_ui_text(prop, "Left", "Enable collisons with left domain border"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_collision_border_top", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_TOP); + RNA_def_property_ui_text(prop, "Top", "Enable collisons with top domain border"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_collision_border_bottom", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "border_collisions", FLUID_DOMAIN_BORDER_BOTTOM); + RNA_def_property_ui_text(prop, "Bottom", "Enable collisons with bottom domain border"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION); + RNA_def_property_float_sdna(prop, NULL, "gravity"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, -1000.1, 1000.1); + RNA_def_property_ui_text(prop, "Gravity", "Gravity in X, Y and Z direction"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "domain_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, domain_types); + RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_domaintype_set", NULL); + RNA_def_property_ui_text(prop, "Domain Type", "Change domain type of the simulation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_reset"); + + /* smoke domain options */ + + prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "alpha"); + RNA_def_property_range(prop, -5.0, 5.0); + RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5); + RNA_def_property_ui_text( + prop, + "Density", + "How much density affects smoke motion (higher value results in faster rising smoke)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "beta"); + RNA_def_property_range(prop, -5.0, 5.0); + RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5); + RNA_def_property_ui_text( + prop, + "Heat", + "How much heat affects smoke motion (higher value results in faster rising smoke)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "diss_speed"); + RNA_def_property_range(prop, 1.0, 10000.0); + RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, -1); + RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vorticity"); + RNA_def_property_range(prop, 0.0, 4.0); + RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence/rotation in fluid"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "highres_sampling", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, smoke_highres_sampling_items); + RNA_def_property_ui_text(prop, "Emitter", "Method for sampling the high resolution flow"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "use_dissolve_smoke", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_DISSOLVE); + RNA_def_property_ui_text(prop, "Dissolve Smoke", "Enable smoke to disappear over time"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_DISSOLVE_LOG); + RNA_def_property_ui_text(prop, "Logarithmic dissolve", "Using 1/x "); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + /* flame options */ + + prop = RNA_def_property(srna, "burning_rate", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.01, 4.0); + RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5); + RNA_def_property_ui_text( + prop, "Speed", "Speed of the burning reaction (use larger values for smaller flame)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 8.0); + RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5); + RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 2.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5); + RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.5, 5.0); + RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5); + RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 1.0, 10.0); + RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5); + RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + /* noise options */ + + prop = RNA_def_property(srna, "noise_strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "noise_strength"); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2); + RNA_def_property_ui_text(prop, "Strength", "Strength of noise"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "noise_pos_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "noise_pos_scale"); + RNA_def_property_range(prop, 0.0001, 10.0); + RNA_def_property_ui_text( + prop, "Scale", "Scale of noise (higher value results in larger vortices)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "noise_time_anim", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "noise_time_anim"); + RNA_def_property_range(prop, 0.0001, 10.0); + RNA_def_property_ui_text(prop, "Time", "Animation time of noise"); + + prop = RNA_def_property(srna, "noise_scale", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "noise_scale"); + RNA_def_property_range(prop, 1, 100); + RNA_def_property_ui_range(prop, 1, 10, 1, -1); + RNA_def_property_ui_text(prop, + "Noise Scale", + "Scale underlying noise grids by this factor. Noise grids have size " + "factor times base resolution"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "noise_type"); + RNA_def_property_enum_items(prop, prop_noise_type_items); + RNA_def_property_ui_text( + prop, "Noise Method", "Noise method which is used for creating the high resolution"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_noise", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_NOISE); + RNA_def_property_ui_text(prop, "Use Noise", "Enable fluid noise (using amplification)"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_update"); + + /* liquid domain options */ + + prop = RNA_def_property(srna, "simulation_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "simulation_method"); + RNA_def_property_enum_items(prop, simulation_methods); + RNA_def_property_ui_text(prop, "Simulation Method", "Change the underlying simulation method"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "flip_ratio", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text( + prop, + "FLIP Ratio", + "PIC/FLIP Ratio. A value of 1.0 will result in a completely FLIP based simulation. Use a " + "lower value for simulations which should produce smaller splashes"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "particle_randomness", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for particle sampling"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "particle_number", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 1, 5); + RNA_def_property_ui_text( + prop, "Number", "Particle number factor (higher value results in more particles)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "particle_min", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "particle_minimum"); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, + "Minimum", + "Minimum number of particles per cell (ensures that each cell has at " + "least this amount of particles)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "particle_max", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "particle_maximum"); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, + "Maximum", + "Maximum number of particles per cell (ensures that each cell has at " + "most this amount of particles)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "particle_radius", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text( + prop, + "Radius", + "Particle radius factor. Use this parameter when the simulation appears to leak volume"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "particle_band_width", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1000.0); + RNA_def_property_ui_text( + prop, + "Width", + "Particle (narrow) band width (higher value results in thicker band and more particles)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "use_flip_particles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_FLIP); + RNA_def_property_ui_text(prop, "FLIP", "Create FLIP particle system"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_Fluid_flip_parts_update"); + + prop = RNA_def_property(srna, "use_fractions", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_FRACTIONS); + RNA_def_property_ui_text( + prop, + "Fractional Obstacles", + "Fractional obstacles improve and smoothen the fluid-obstacle boundary"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "fractions_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.001, 1.0); + RNA_def_property_ui_range(prop, 0.01, 1.0, 0.05, -1); + RNA_def_property_ui_text(prop, + "Obstacle-Fluid Threshold ", + "Determines how much fluid is allowed in an obstacle cell " + "(higher values will tag a boundary cell as an obstacle easier " + "and reduce the boundary smoothening effect)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + /* diffusion options */ + + prop = RNA_def_property(srna, "surface_tension", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_text( + prop, + "Tension", + "Surface tension of liquid (higher value results in greater hydrophobic behaviour)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "viscosity_base", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "viscosity_base"); + RNA_def_property_range(prop, 0, 10); + RNA_def_property_ui_text( + prop, + "Viscosity Base", + "Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "viscosity_exponent", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "viscosity_exponent"); + RNA_def_property_range(prop, 0, 10); + RNA_def_property_ui_text( + prop, + "Viscosity Exponent", + "Negative exponent for the viscosity value (to simplify entering small values " + "e.g. 5*10^-6)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "domain_size", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.001, 10000.0); + RNA_def_property_ui_text(prop, "Meters", "Domain size in meters (longest domain side)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + /* mesh options options */ + + prop = RNA_def_property(srna, "mesh_concave_upper", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text( + prop, + "Upper Concavity", + "Upper mesh concavity bound (high values tend to smoothen and fill out concave regions)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "mesh_concave_lower", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text( + prop, + "Lower Concavity", + "Lower mesh concavity bound (high values tend to smoothen and fill out concave regions)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "mesh_smoothen_pos", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Smoothen Pos", "Positive mesh smoothening"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "mesh_smoothen_neg", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Smoothen Neg", "Negative mesh smoothening"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "mesh_scale", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "mesh_scale"); + RNA_def_property_range(prop, 1, 100); + RNA_def_property_ui_range(prop, 1, 10, 1, -1); + RNA_def_property_ui_text(prop, + "Mesh scale", + "Scale underlying mesh grids by this factor. Mesh grids have size " + "factor times base resolution"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "mesh_generator", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mesh_generator"); + RNA_def_property_enum_items(prop, fluid_mesh_quality_items); + RNA_def_property_ui_text(prop, "Mesh generator", "Which particle levelset generator to use"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update"); + + prop = RNA_def_property(srna, "mesh_vertices", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "mesh_velocities", "totvert"); + RNA_def_property_struct_type(prop, "FluidDomainVertexVelocity"); + RNA_def_property_ui_text( + prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation"); + + rna_def_fluid_mesh_vertices(brna); + + prop = RNA_def_property(srna, "use_mesh", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_MESH); + RNA_def_property_ui_text(prop, "Use Mesh", "Enable fluid mesh (using amplification)"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_update"); + + prop = RNA_def_property(srna, "use_speed_vectors", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_SPEED_VECTORS); + RNA_def_property_ui_text( + prop, + "Speed Vectors", + "Generate speed vectors (will be loaded automatically during render for motion blur)"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "mesh_particle_radius", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text( + prop, + "Radius", + "Particle radius factor (higher value results in larger (meshed) particles)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + /* secondary particles options */ + + prop = RNA_def_property(srna, "sndparticle_tau_min_wc", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1000.0); + RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3); + RNA_def_property_ui_text(prop, + "tauMin_wc", + "Lower clamping threshold for marking fluid cells as wave crests " + "(lower values result in more marked cells)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_tau_max_wc", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1000.0); + RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3); + RNA_def_property_ui_text(prop, + "tauMax_wc", + "Upper clamping threshold for marking fluid cells as wave crests " + "(higher values result in less marked cells)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_tau_min_ta", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1000.0); + RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 3); + RNA_def_property_ui_text(prop, + "tauMin_ta", + "Lower clamping threshold for marking fluid cells where air is trapped " + "(lower values result in more marked cells)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_tau_max_ta", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1000.0); + RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3); + RNA_def_property_ui_text(prop, + "tauMax_ta", + "Upper clamping threshold for marking fluid cells where air is trapped " + "(higher values result in less marked cells)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_tau_min_k", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1000.0); + RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3); + RNA_def_property_ui_text( + prop, + "tauMin_k", + "Lower clamping threshold that indicates the fluid speed where cells start to emit " + "particles (lower values result in generally more particles)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_tau_max_k", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1000.0); + RNA_def_property_ui_range(prop, 0.0, 1000.0, 100.0, 3); + RNA_def_property_ui_text( + prop, + "tauMax_k", + "Upper clamping threshold that indicates the fluid speed where cells no longer emit more " + "particles (higher values result in generally less particles)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_k_wc", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 10000); + RNA_def_property_ui_range(prop, 0, 10000, 1.0, -1); + RNA_def_property_ui_text(prop, + "Wave Crest Sampling", + "Maximum number of particles generated per wave crest cell per frame"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_k_ta", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 10000); + RNA_def_property_ui_range(prop, 0, 10000, 1.0, -1); + RNA_def_property_ui_text(prop, + "Trapped Air Sampling", + "Maximum number of particles generated per trapped air cell per frame"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_k_b", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_range(prop, 0.0, 100.0, 10.0, 2); + RNA_def_property_ui_text(prop, + "Buoyancy", + "Amount of buoyancy force that rises bubbles (high values result in " + "bubble movement mainly upwards)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_k_d", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_range(prop, 0.0, 100.0, 10.0, 2); + RNA_def_property_ui_text(prop, + "Drag", + "Amount of drag force that moves bubbles along with the fluid (high " + "values result in bubble movement mainly along with the fluid)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_l_min", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10000.0); + RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 1); + RNA_def_property_ui_text(prop, "Lifetime(min)", "Lowest possible particle lifetime"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_l_max", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10000.0); + RNA_def_property_ui_range(prop, 0.0, 10000.0, 100.0, 1); + RNA_def_property_ui_text(prop, "Lifetime(max)", "Highest possible particle lifetime"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_boundary", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "sndparticle_boundary"); + RNA_def_property_enum_items(prop, sndparticle_boundary_items); + RNA_def_property_ui_text( + prop, "Particles in Boundary", "How particles that left the domain are treated"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "sndparticle_combined_export", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "sndparticle_combined_export"); + RNA_def_property_enum_items(prop, sndparticle_combined_export_items); + RNA_def_property_ui_text( + prop, + "Combined Export", + "Determines which particle systems are created from secondary particles"); + RNA_def_property_update(prop, 0, "rna_Fluid_combined_export_update"); + + prop = RNA_def_property(srna, "sndparticle_potential_radius", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "sndparticle_potential_radius"); + RNA_def_property_range(prop, 1, 4); + RNA_def_property_ui_range(prop, 1, 4, 1, -1); + RNA_def_property_ui_text(prop, + "Potential Radius", + "Radius to compute potential for each cell (higher values are slower " + "but create smoother potential grids)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "sndparticle_update_radius", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "sndparticle_update_radius"); + RNA_def_property_range(prop, 1, 4); + RNA_def_property_ui_range(prop, 1, 4, 1, -1); + RNA_def_property_ui_text(prop, + "Update Radius", + "Radius to compute position update for each particle (higher values " + "are slower but particles move less chaotic)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "particle_scale", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "particle_scale"); + RNA_def_property_range(prop, 1, 100); + RNA_def_property_ui_range(prop, 1, 10, 1, -1); + RNA_def_property_ui_text(prop, + "Mesh scale", + "Scale underlying particle grids by this factor. Particle grids have " + "size factor times base resolution"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_spray_particles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_SPRAY); + RNA_def_property_ui_text(prop, "Spray", "Create spray particle system"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_Fluid_spray_parts_update"); + + prop = RNA_def_property(srna, "use_bubble_particles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_BUBBLE); + RNA_def_property_ui_text(prop, "Bubble", "Create bubble particle system"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_Fluid_bubble_parts_update"); + + prop = RNA_def_property(srna, "use_foam_particles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_FOAM); + RNA_def_property_ui_text(prop, "Foam", "Create foam particle system"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_Fluid_foam_parts_update"); + + prop = RNA_def_property(srna, "use_tracer_particles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "particle_type", FLUID_DOMAIN_PARTICLE_TRACER); + RNA_def_property_ui_text(prop, "Tracer", "Create tracer particle system"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, 0, "rna_Fluid_tracer_parts_update"); + + /* fluid guiding options */ + + prop = RNA_def_property(srna, "guide_alpha", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "guide_alpha"); + RNA_def_property_range(prop, 1.0, 100.0); + RNA_def_property_ui_text(prop, "Weight", "Guiding weight (higher value results in greater lag)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "guide_beta", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "guide_beta"); + RNA_def_property_range(prop, 1, 50); + RNA_def_property_ui_text(prop, "Size", "Guiding size (higher value results in larger vortices)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "guide_vel_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "guide_vel_factor"); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_text( + prop, + "Weight", + "Guiding velocity factor (higher value results in bigger guiding velocities)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "guide_source", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "guide_source"); + RNA_def_property_enum_items(prop, fluid_guide_source_items); + RNA_def_property_ui_text(prop, "Guiding source", "Choose where to get guiding velocities from"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update"); + + prop = RNA_def_property(srna, "guide_parent", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "guide_parent"); + RNA_def_property_struct_type(prop, "Object"); + RNA_def_property_pointer_funcs(prop, NULL, "rna_Fluid_guide_parent_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "", + "Use velocities from this object for the guiding effect (object needs " + "to have fluid modifier and be of type domain))"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update"); + + prop = RNA_def_property(srna, "use_guide", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_GUIDE); + RNA_def_property_ui_text(prop, "Use Guiding", "Enable fluid guiding"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + /* cache options */ + + prop = RNA_def_property(srna, "cache_frame_start", PROP_INT, PROP_TIME); + RNA_def_property_int_sdna(prop, NULL, "cache_frame_start"); + RNA_def_property_range(prop, -MAXFRAME, MAXFRAME); + RNA_def_property_ui_range(prop, 1, MAXFRAME, 1, 1); + RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts"); + + prop = RNA_def_property(srna, "cache_frame_end", PROP_INT, PROP_TIME); + RNA_def_property_int_sdna(prop, NULL, "cache_frame_end"); + RNA_def_property_range(prop, 1, MAXFRAME); + RNA_def_property_ui_text(prop, "End", "Frame on which the simulation stops"); + + prop = RNA_def_property(srna, "cache_frame_pause_data", PROP_INT, PROP_TIME); + RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_data"); + + prop = RNA_def_property(srna, "cache_frame_pause_noise", PROP_INT, PROP_TIME); + RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_noise"); + + prop = RNA_def_property(srna, "cache_frame_pause_mesh", PROP_INT, PROP_TIME); + RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_mesh"); + + prop = RNA_def_property(srna, "cache_frame_pause_particles", PROP_INT, PROP_TIME); + RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_particles"); + + prop = RNA_def_property(srna, "cache_frame_pause_guide", PROP_INT, PROP_TIME); + RNA_def_property_int_sdna(prop, NULL, "cache_frame_pause_guide"); + + prop = RNA_def_property(srna, "cache_mesh_format", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "cache_mesh_format"); + RNA_def_property_enum_items(prop, cache_file_type_items); + RNA_def_property_enum_funcs( + prop, NULL, "rna_Fluid_cachetype_mesh_set", "rna_Fluid_cachetype_mesh_itemf"); + RNA_def_property_ui_text( + prop, "File Format", "Select the file format to be used for caching surface data"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "cache_data_format", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "cache_data_format"); + RNA_def_property_enum_items(prop, cache_file_type_items); + RNA_def_property_enum_funcs( + prop, NULL, "rna_Fluid_cachetype_data_set", "rna_Fluid_cachetype_volume_itemf"); + RNA_def_property_ui_text( + prop, "File Format", "Select the file format to be used for caching volumetric data"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "cache_particle_format", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "cache_particle_format"); + RNA_def_property_enum_items(prop, cache_file_type_items); + RNA_def_property_enum_funcs( + prop, NULL, "rna_Fluid_cachetype_particle_set", "rna_Fluid_cachetype_particle_itemf"); + RNA_def_property_ui_text( + prop, "File Format", "Select the file format to be used for caching particle data"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "cache_noise_format", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "cache_noise_format"); + RNA_def_property_enum_items(prop, cache_file_type_items); + RNA_def_property_enum_funcs( + prop, NULL, "rna_Fluid_cachetype_noise_set", "rna_Fluid_cachetype_volume_itemf"); + RNA_def_property_ui_text( + prop, "File Format", "Select the file format to be used for caching noise data"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "cache_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "cache_type"); + RNA_def_property_enum_items(prop, cache_types); + RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_cachetype_set", NULL); + RNA_def_property_ui_text(prop, "Type", "Change the cache type of the simulation"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "cache_directory", PROP_STRING, PROP_DIRPATH); + RNA_def_property_string_maxlength(prop, FILE_MAX); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Fluid_cache_directory_set"); + RNA_def_property_string_sdna(prop, NULL, "cache_directory"); + RNA_def_property_ui_text(prop, "Cache directory", "Directory that contains fluid cache files"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "is_cache_baking_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_DATA); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "has_cache_baked_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_DATA); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "is_cache_baking_noise", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_NOISE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "has_cache_baked_noise", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_NOISE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "is_cache_baking_mesh", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_MESH); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "has_cache_baked_mesh", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_MESH); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "is_cache_baking_particles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_PARTICLES); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "has_cache_baked_particles", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_PARTICLES); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "is_cache_baking_guide", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_GUIDE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "has_cache_baked_guide", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_GUIDE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + /* Read only checks, avoids individually accessing flags above. */ + prop = RNA_def_property(srna, "is_cache_baking_any", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKING_ALL); + RNA_def_property_flag(prop, PROP_EDITABLE); + + prop = RNA_def_property(srna, "has_cache_baked_any", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "cache_flag", FLUID_DOMAIN_BAKED_ALL); + RNA_def_property_flag(prop, PROP_EDITABLE); + + prop = RNA_def_property(srna, "export_manta_script", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_EXPORT_MANTA_SCRIPT); + RNA_def_property_ui_text( + prop, + "Export Fluidflow Script", + "Generate and export Fluidflow script from current domain settings during bake. This is " + "only needed if you plan to analyse the cache (e.g. view grids, velocity vectors, " + "particles) in Fluidflow directly (outside of Blender) after baking the simulation"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + /* time options */ + + prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "time_scale"); + RNA_def_property_range(prop, 0.0001, 10.0); + RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "cfl_condition", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "cfl_condition"); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text( + prop, "CFL", "Maximal velocity per cell (higher value results in larger timesteps)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "use_adaptive_timesteps", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_DOMAIN_USE_ADAPTIVE_TIME); + RNA_def_property_ui_text(prop, "Use Adaptive Time Steps", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_resetCache"); + + prop = RNA_def_property(srna, "timesteps_min", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "timesteps_minimum"); + RNA_def_property_range(prop, 1, 100); + RNA_def_property_ui_range(prop, 0, 100, 1, -1); + RNA_def_property_ui_text( + prop, "Minimum", "Minimum number of simulation steps to perform for one frame"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "timesteps_max", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "timesteps_maximum"); + RNA_def_property_range(prop, 1, 100); + RNA_def_property_ui_range(prop, 0, 100, 1, -1); + RNA_def_property_ui_text( + prop, "Maximum", "Maximum number of simulation steps to perform for one frame"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + /* display settings */ + + prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "slice_method"); + RNA_def_property_enum_items(prop, view_items); + RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method"); + RNA_def_property_enum_items(prop, axis_slice_method_items); + RNA_def_property_ui_text(prop, "Method", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "slice_axis"); + RNA_def_property_enum_items(prop, axis_slice_position_items); + RNA_def_property_ui_text(prop, "Axis", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel"); + RNA_def_property_range(prop, 0.0, 100.0); + RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1); + RNA_def_property_ui_text( + prop, "Slice Per Voxel", "How many slices per voxel should be generated"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "slice_depth"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3); + RNA_def_property_ui_text(prop, "Position", "Position of the slice"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "display_thickness"); + RNA_def_property_range(prop, 0.001, 1000.0); + RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3); + RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "interp_method"); + RNA_def_property_enum_items(prop, interp_method_item); + RNA_def_property_ui_text( + prop, "Interpolation", "Interpolation method to use for smoke/fire volumes in solid mode"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "show_velocity", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0); + RNA_def_property_ui_text( + prop, "Display Velocity", "Toggle visualization of the velocity field as needles"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "vector_display_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type"); + RNA_def_property_enum_items(prop, vector_draw_items); + RNA_def_property_ui_text(prop, "Display Type", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vector_scale"); + RNA_def_property_range(prop, 0.0, 1000.0); + RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3); + RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + /* --------- Color mapping. --------- */ + + prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Fluid_use_color_ramp_set"); + RNA_def_property_ui_text( + prop, + "Use Color Ramp", + "Render a simulation field while mapping its voxels values to the colors of a ramp"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + static const EnumPropertyItem coba_field_items[] = { + {FLUID_DOMAIN_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"}, + {FLUID_DOMAIN_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"}, + {FLUID_DOMAIN_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"}, + {FLUID_DOMAIN_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"}, + {FLUID_DOMAIN_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"}, + {FLUID_DOMAIN_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"}, + {FLUID_DOMAIN_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"}, + {FLUID_DOMAIN_FIELD_VELOCITY_X, + "VELOCITY_X", + 0, + "X Velocity", + "X component of the velocity field"}, + {FLUID_DOMAIN_FIELD_VELOCITY_Y, + "VELOCITY_Y", + 0, + "Y Velocity", + "Y component of the velocity field"}, + {FLUID_DOMAIN_FIELD_VELOCITY_Z, + "VELOCITY_Z", + 0, + "Z Velocity", + "Z component of the velocity field"}, + {0, NULL, 0, NULL, NULL}, + }; + + prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "coba_field"); + RNA_def_property_enum_items(prop, coba_field_items); + RNA_def_property_ui_text(prop, "Field", "Simulation field to color map"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "coba"); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Color Ramp", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "clipping", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "clipping"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3); + RNA_def_property_ui_text( + prop, + "Clipping", + "Value under which voxels are considered empty space to optimize caching and rendering"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + /* -- Deprecated / unsed options (below)-- */ + + /* pointcache options */ + + prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]"); + RNA_def_property_struct_type(prop, "PointCache"); + RNA_def_property_ui_text(prop, "Point Cache", ""); + + prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "cache_comp"); + RNA_def_property_enum_items(prop, cache_comp_items); + RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used"); + + /* OpenVDB options */ + + prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp"); + RNA_def_property_enum_items(prop, prop_compression_items); + RNA_def_property_ui_text(prop, "Compression", "Compression method to be used"); + + prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth"); + RNA_def_property_enum_items(prop, smoke_data_depth_items); + RNA_def_property_ui_text(prop, + "Data Depth", + "Bit depth for writing all scalar (including vector) " + "lower values reduce file size"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); +} + +static void rna_def_fluid_flow_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static const EnumPropertyItem flow_types[] = { + {FLUID_FLOW_TYPE_SMOKE, "SMOKE", 0, "Smoke", "Add smoke"}, + {FLUID_FLOW_TYPE_SMOKEFIRE, "BOTH", 0, "Fire + Smoke", "Add fire and smoke"}, + {FLUID_FLOW_TYPE_FIRE, "FIRE", 0, "Fire", "Add fire"}, + {FLUID_FLOW_TYPE_LIQUID, "LIQUID", 0, "Liquid", "Add liquid"}, + {0, NULL, 0, NULL, NULL}, + }; + + static EnumPropertyItem flow_behaviors[] = { + {FLUID_FLOW_BEHAVIOR_INFLOW, "INFLOW", 0, "Inflow", "Add fluid to simulation"}, + {FLUID_FLOW_BEHAVIOR_OUTFLOW, "OUTFLOW", 0, "Outflow", "Delete fluid from simulation"}, + {FLUID_FLOW_BEHAVIOR_GEOMETRY, + "GEOMETRY", + 0, + "Geometry", + "Only use given geometry for fluid"}, + {0, NULL, 0, NULL, NULL}, + }; + + /* Flow source - generated dynamically based on flow type */ + static EnumPropertyItem flow_sources[] = { + {0, "NONE", 0, "", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const EnumPropertyItem flow_texture_types[] = { + {FLUID_FLOW_TEXTURE_MAP_AUTO, + "AUTO", + 0, + "Generated", + "Generated coordinates centered to flow object"}, + {FLUID_FLOW_TEXTURE_MAP_UV, "UV", 0, "UV", "Use UV layer for texture coordinates"}, + {0, NULL, 0, NULL, NULL}, + }; + + srna = RNA_def_struct(brna, "FluidFlowSettings", NULL); + RNA_def_struct_ui_text(srna, "Flow Settings", "Fluid flow settings"); + RNA_def_struct_sdna(srna, "FluidFlowSettings"); + RNA_def_struct_path_func(srna, "rna_FluidFlowSettings_path"); + + prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "density"); + RNA_def_property_range(prop, 0.0, 1); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4); + RNA_def_property_ui_text(prop, "Density", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "color"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10); + RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4); + RNA_def_property_ui_text(prop, "Flame Rate", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "temperature"); + RNA_def_property_range(prop, -10, 10); + RNA_def_property_ui_range(prop, -10, 10, 1, 1); + RNA_def_property_ui_text(prop, "Temp. Diff.", "Temperature difference to ambient temperature"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "psys"); + RNA_def_property_struct_type(prop, "ParticleSystem"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object"); + RNA_def_property_update(prop, 0, "rna_Fluid_reset_dependency"); + + prop = RNA_def_property(srna, "flow_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, flow_types); + RNA_def_property_enum_funcs(prop, NULL, "rna_Fluid_flowtype_set", NULL); + RNA_def_property_ui_text(prop, "Flow Type", "Change type of fluid in the simulation"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "flow_behavior", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "behavior"); + RNA_def_property_enum_items(prop, flow_behaviors); + RNA_def_property_ui_text(prop, "Flow Behavior", "Change flow behavior in the simulation"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "flow_source", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "source"); + RNA_def_property_enum_items(prop, flow_sources); + RNA_def_property_enum_funcs( + prop, NULL, "rna_Fluid_flowsource_set", "rna_Fluid_flowsource_itemf"); + RNA_def_property_ui_text(prop, "Source", "Change how fluid is emitted"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_ABSOLUTE); + RNA_def_property_ui_text(prop, + "Absolute Density", + "Only allow given density value in emitter area and will not add up"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_initial_velocity", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_INITVELOCITY); + RNA_def_property_ui_text( + prop, "Initial Velocity", "Fluid has some initial velocity when it is emitted"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vel_multi"); + RNA_def_property_range(prop, -100.0, 100.0); + RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5); + RNA_def_property_ui_text(prop, + "Source", + "Multiplier of source velocity passed to fluid (source velocity is " + "non-zero only if object is moving)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vel_normal"); + RNA_def_property_range(prop, -100.0, 100.0); + RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5); + RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vel_random"); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5); + RNA_def_property_ui_text(prop, "Random", "Amount of random velocity"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "velocity_coord", PROP_FLOAT, PROP_XYZ); + RNA_def_property_float_sdna(prop, NULL, "vel_coord"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, -1000.1, 1000.1); + RNA_def_property_ui_text(prop, "Initial", "Initial velocity in X, Y and Z direction"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5); + RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_range(prop, 0.0, 10.0, 0.05, 5); + RNA_def_property_ui_text(prop, "Surface", "Maximum distance from mesh surface to emit fluid"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_plane_init", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PLANE_INIT); + RNA_def_property_ui_text(prop, "Is Planar", "Treat this object as a planar, unclosed mesh"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "particle_size", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.1, 20.0); + RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5); + RNA_def_property_ui_text(prop, "Size", "Particle size in simulation cells"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_particle_size", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PART_SIZE); + RNA_def_property_ui_text( + prop, "Set Size", "Set particle size in simulation cells or use nearest cell"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_inflow", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_INFLOW); + RNA_def_property_ui_text(prop, "Enabled", "Control when to apply inflow"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE); + RNA_def_property_range(prop, 0, 200); + RNA_def_property_ui_range(prop, 0, 10, 1, -1); + RNA_def_property_ui_text(prop, + "Subframes", + "Number of additional samples to take between frames to improve " + "quality of fast moving flows"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, + "rna_FluidFlow_density_vgroup_get", + "rna_FluidFlow_density_vgroup_length", + "rna_FluidFlow_density_vgroup_set"); + RNA_def_property_ui_text( + prop, "Vertex Group", "Name of vertex group which determines surface emission rate"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_TEXTUREEMIT); + RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to control emission strength"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "texture_type"); + RNA_def_property_enum_items(prop, flow_texture_types); + RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "uvlayer_name"); + RNA_def_property_ui_text(prop, "UV Map", "UV map name"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_FluidFlow_uvlayer_set"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.01, 10.0); + RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5); + RNA_def_property_ui_text(prop, "Size", "Size of texture mapping"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 200.0); + RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5); + RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); +} + +static void rna_def_fluid_effector_settings(BlenderRNA *brna) +{ + static EnumPropertyItem effector_type_items[] = { + {FLUID_EFFECTOR_TYPE_COLLISION, "COLLISION", 0, "Collision", "Create collision object"}, + {FLUID_EFFECTOR_TYPE_GUIDE, "GUIDE", 0, "Guide", "Create guide object"}, + {0, NULL, 0, NULL, NULL}, + }; + + static EnumPropertyItem fluid_guide_mode_items[] = { + {FLUID_EFFECTOR_GUIDE_MAX, + "MAXIMUM", + 0, + "Maximize", + "Compare velocities from previous frame with new velocities from current frame and keep " + "the maximum"}, + {FLUID_EFFECTOR_GUIDE_MIN, + "MINIMUM", + 0, + "Minimize", + "Compare velocities from previous frame with new velocities from current frame and keep " + "the minimum"}, + {FLUID_EFFECTOR_GUIDE_OVERRIDE, + "OVERRIDE", + 0, + "Override", + "Always write new guide velocities for every frame (each frame only contains current " + "velocities from guiding objects)"}, + {FLUID_EFFECTOR_GUIDE_AVERAGED, + "AVERAGED", + 0, + "Averaged", + "Take average of velocities from previous frame and new velocities from current frame"}, + {0, NULL, 0, NULL, NULL}, + }; + + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "FluidEffectorSettings", NULL); + RNA_def_struct_ui_text(srna, "Effector Settings", "Smoke collision settings"); + RNA_def_struct_sdna(srna, "FluidEffectorSettings"); + RNA_def_struct_path_func(srna, "rna_FluidEffectorSettings_path"); + + prop = RNA_def_property(srna, "effector_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, effector_type_items); + RNA_def_property_ui_text(prop, "Effector Type", "Change type of effector in the simulation"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_range(prop, 0.0, 10.0, 0.05, 5); + RNA_def_property_ui_text( + prop, "Surface", "Distance around mesh surface to consider as effector"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "use_plane_init", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", FLUID_FLOW_USE_PLANE_INIT); + RNA_def_property_ui_text(prop, "Is Planar", "Treat this object as a planar, unclosed mesh"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vel_multi"); + RNA_def_property_range(prop, -100.0, 100.0); + RNA_def_property_ui_text(prop, "Source", "Multiplier of obstacle velocity"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_reset"); + + prop = RNA_def_property(srna, "guide_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "guide_mode"); + RNA_def_property_enum_items(prop, fluid_guide_mode_items); + RNA_def_property_ui_text(prop, "Guiding mode", "How to create guiding velocities"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Fluid_update"); +} + +void RNA_def_fluid(BlenderRNA *brna) +{ + rna_def_fluid_domain_settings(brna); + rna_def_fluid_flow_settings(brna); + rna_def_fluid_effector_settings(brna); +} + +#endif diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c deleted file mode 100644 index 2f09b90a81e..00000000000 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ /dev/null @@ -1,792 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup RNA - */ - -#include <stdlib.h> - -#include "DNA_object_fluidsim_types.h" - -#include "BLI_threads.h" -#include "BLI_utildefines.h" -#include "BLI_path_util.h" - -#include "RNA_define.h" - -#include "rna_internal.h" - -#include "WM_api.h" -#include "WM_types.h" - -#ifdef RNA_RUNTIME - -# include "MEM_guardedalloc.h" - -# include "DNA_scene_types.h" -# include "DNA_particle_types.h" - -# include "BKE_fluidsim.h" -# include "BKE_global.h" -# include "BKE_main.h" -# include "BKE_modifier.h" -# include "BKE_particle.h" -# include "BKE_pointcache.h" - -# include "DEG_depsgraph.h" - -static StructRNA *rna_FluidSettings_refine(struct PointerRNA *ptr) -{ - FluidsimSettings *fss = (FluidsimSettings *)ptr->data; - - switch (fss->type) { - case OB_FLUIDSIM_DOMAIN: - return &RNA_DomainFluidSettings; - case OB_FLUIDSIM_FLUID: - return &RNA_FluidFluidSettings; - case OB_FLUIDSIM_OBSTACLE: - return &RNA_ObstacleFluidSettings; - case OB_FLUIDSIM_INFLOW: - return &RNA_InflowFluidSettings; - case OB_FLUIDSIM_OUTFLOW: - return &RNA_OutflowFluidSettings; - case OB_FLUIDSIM_PARTICLE: - return &RNA_ParticleFluidSettings; - case OB_FLUIDSIM_CONTROL: - return &RNA_ControlFluidSettings; - default: - return &RNA_FluidSettings; - } -} - -static void rna_fluid_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) -{ - Object *ob = (Object *)ptr->owner_id; - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob); -} - -static int fluidsim_find_lastframe(Main *bmain, Object *ob, FluidsimSettings *fss) -{ - char targetFileTest[FILE_MAX]; - char targetFile[FILE_MAX]; - int curFrame = 1; - - BLI_join_dirfile( - targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); - BLI_path_abs(targetFile, modifier_path_relbase(bmain, ob)); - - do { - BLI_strncpy(targetFileTest, targetFile, sizeof(targetFileTest)); - BLI_path_frame(targetFileTest, curFrame++, 0); - } while (BLI_exists(targetFileTest)); - - return curFrame - 1; -} - -static void rna_fluid_find_enframe(Main *bmain, Scene *scene, PointerRNA *ptr) -{ - Object *ob = (Object *)ptr->owner_id; - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType( - ob, eModifierType_Fluidsim); - - if (fluidmd->fss->flag & OB_FLUIDSIM_REVERSE) { - fluidmd->fss->lastgoodframe = fluidsim_find_lastframe(bmain, ob, fluidmd->fss); - } - else { - fluidmd->fss->lastgoodframe = -1; - } - rna_fluid_update(bmain, scene, ptr); -} - -static void rna_FluidSettings_update_type(Main *bmain, Scene *scene, PointerRNA *ptr) -{ - Object *ob = (Object *)ptr->owner_id; - FluidsimModifierData *fluidmd; - ParticleSystemModifierData *psmd; - ParticleSystem *psys, *next_psys; - ParticleSettings *part; - - fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); - fluidmd->fss->flag &= ~OB_FLUIDSIM_REVERSE; /* clear flag */ - - /* remove fluidsim particle system */ - if (fluidmd->fss->type & OB_FLUIDSIM_PARTICLE) { - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - if (psys->part->type == PART_FLUID) { - break; - } - } - - if (ob->type == OB_MESH && !psys) { - /* add particle system */ - part = BKE_particlesettings_add(bmain, "ParticleSettings"); - psys = MEM_callocN(sizeof(ParticleSystem), "particle_system"); - - part->type = PART_FLUID; - psys->part = part; - psys->pointcache = BKE_ptcache_add(&psys->ptcaches); - BLI_strncpy(psys->name, "FluidParticles", sizeof(psys->name)); - BLI_addtail(&ob->particlesystem, psys); - - /* add modifier */ - psmd = (ParticleSystemModifierData *)modifier_new(eModifierType_ParticleSystem); - BLI_strncpy(psmd->modifier.name, "FluidParticleSystem", sizeof(psmd->modifier.name)); - psmd->psys = psys; - BLI_addtail(&ob->modifiers, psmd); - modifier_unique_name(&ob->modifiers, (ModifierData *)psmd); - } - } - else { - for (psys = ob->particlesystem.first; psys; psys = next_psys) { - next_psys = psys->next; - if (psys->part->type == PART_FLUID) { - /* clear modifier */ - psmd = psys_get_modifier(ob, psys); - BLI_remlink(&ob->modifiers, psmd); - modifier_free((ModifierData *)psmd); - - /* clear particle system */ - BLI_remlink(&ob->particlesystem, psys); - psys_free(ob, psys); - } - } - } - - rna_fluid_update(bmain, scene, ptr); -} - -static void rna_DomainFluidSettings_memory_estimate_get(PointerRNA *ptr, char *value) -{ -# ifndef WITH_MOD_FLUID - (void)ptr; - value[0] = '\0'; -# else - Object *ob = (Object *)ptr->owner_id; - FluidsimSettings *fss = (FluidsimSettings *)ptr->data; - - fluid_estimate_memory(ob, fss, value); -# endif -} - -static int rna_DomainFluidSettings_memory_estimate_length(PointerRNA *ptr) -{ -# ifndef WITH_MOD_FLUID - UNUSED_VARS(ptr); - return 0; -# else - char value[32]; - - rna_DomainFluidSettings_memory_estimate_get(ptr, value); - return strlen(value); -# endif -} - -static char *rna_FluidSettings_path(PointerRNA *ptr) -{ - FluidsimSettings *fss = (FluidsimSettings *)ptr->data; - ModifierData *md = (ModifierData *)fss->fmd; - char name_esc[sizeof(md->name) * 2]; - - BLI_strescape(name_esc, md->name, sizeof(name_esc)); - return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc); -} - -#else - -static void rna_def_fluidsim_slip(StructRNA *srna) -{ - PropertyRNA *prop; - - static const EnumPropertyItem slip_items[] = { - {OB_FSBND_NOSLIP, - "NOSLIP", - 0, - "No Slip", - "Obstacle causes zero normal and tangential velocity (=sticky), default for all " - "(only option for moving objects)"}, - {OB_FSBND_PARTSLIP, - "PARTIALSLIP", - 0, - "Partial Slip", - "Mix between no-slip and free-slip (non moving objects only!)"}, - {OB_FSBND_FREESLIP, - "FREESLIP", - 0, - "Free Slip", - "Obstacle only causes zero normal velocity (=not sticky, non moving objects only!)"}, - {0, NULL, 0, NULL, NULL}, - }; - - prop = RNA_def_property(srna, "slip_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "typeFlags"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_enum_items(prop, slip_items); - RNA_def_property_ui_text(prop, "Slip Type", ""); - - prop = RNA_def_property(srna, "partial_slip_factor", PROP_FLOAT, PROP_FACTOR); - RNA_def_property_float_sdna(prop, NULL, "partSlipValue"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text( - prop, - "Partial Slip Amount", - "Amount of mixing between no- and free-slip, 0 is no slip and 1 is free slip"); -} - -static void rna_def_fluid_mesh_vertices(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "FluidVertexVelocity", NULL); - RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh"); - RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL); - - prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY); - RNA_def_property_array(prop, 3); - RNA_def_property_float_sdna(prop, NULL, "vel"); - RNA_def_property_ui_text(prop, "Velocity", ""); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); -} - -static void rna_def_fluidsim_domain(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - static const EnumPropertyItem quality_items[] = { - {OB_FSDOM_GEOM, "GEOMETRY", 0, "Geometry", "Display geometry"}, - {OB_FSDOM_PREVIEW, "PREVIEW", 0, "Preview", "Display preview quality results"}, - {OB_FSDOM_FINAL, "FINAL", 0, "Final", "Display final quality results"}, - {0, NULL, 0, NULL, NULL}, - }; - - srna = RNA_def_struct(brna, "DomainFluidSettings", "FluidSettings"); - RNA_def_struct_sdna(srna, "FluidsimSettings"); - RNA_def_struct_ui_text(srna, - "Domain Fluid Simulation Settings", - "Fluid simulation settings for the domain of a fluid simulation"); - - /* standard settings */ - - prop = RNA_def_property(srna, "threads", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "threads"); - RNA_def_property_range(prop, 0, BLENDER_MAX_THREADS); - RNA_def_property_ui_text( - prop, "Simulation Threads", "Override number of threads for the simulation, 0 is automatic"); - - prop = RNA_def_property(srna, "resolution", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "resolutionxyz"); - RNA_def_property_range(prop, 1, 1024); - RNA_def_property_ui_text(prop, "Resolution", "Domain resolution in X,Y and Z direction"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - - prop = RNA_def_property(srna, "preview_resolution", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "previewresxyz"); - RNA_def_property_range(prop, 1, 100); - RNA_def_property_ui_text( - prop, "Preview Resolution", "Preview resolution in X,Y and Z direction"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - - prop = RNA_def_property(srna, "viewport_display_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "guiDisplayMode"); - RNA_def_property_enum_items(prop, quality_items); - RNA_def_property_ui_text( - prop, "Viewport Display Mode", "How to display the mesh in the viewport"); - RNA_def_property_update(prop, 0, "rna_fluid_update"); - - prop = RNA_def_property(srna, "render_display_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "renderDisplayMode"); - RNA_def_property_enum_items(prop, quality_items); - RNA_def_property_ui_text(prop, "Render Display Mode", "How to display the mesh for rendering"); - - prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_REVERSE); - RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse fluid frames"); - RNA_def_property_update(prop, 0, "rna_fluid_find_enframe"); - - prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); - RNA_def_property_string_maxlength(prop, FILE_MAX); - RNA_def_property_string_sdna(prop, NULL, "surfdataPath"); - RNA_def_property_ui_text( - prop, "Path", "Directory (and/or filename prefix) to store baked fluid simulation files in"); - RNA_def_property_update(prop, 0, "rna_fluid_update"); - - prop = RNA_def_property(srna, "memory_estimate", PROP_STRING, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_string_funcs(prop, - "rna_DomainFluidSettings_memory_estimate_get", - "rna_DomainFluidSettings_memory_estimate_length", - NULL); - RNA_def_property_ui_text( - prop, "Memory Estimate", "Estimated amount of memory needed for baking the domain"); - - /* advanced settings */ - prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION); - RNA_def_property_float_sdna(prop, NULL, "grav"); - RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, -1000.1, 1000.1); - RNA_def_property_ui_text(prop, "Gravity", "Gravity in X, Y and Z direction"); - - prop = RNA_def_property(srna, "use_time_override", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_OVERRIDE_TIME); - RNA_def_property_ui_text( - prop, - "Override Time", - "Use a custom start and end time (in seconds) instead of the scene's timeline"); - - prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME); - RNA_def_property_float_sdna(prop, NULL, "animStart"); - RNA_def_property_range(prop, 0, FLT_MAX); - RNA_def_property_ui_text( - prop, "Start Time", "Simulation time of the first blender frame (in seconds)"); - - prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME); - RNA_def_property_float_sdna(prop, NULL, "animEnd"); - RNA_def_property_range(prop, 0, FLT_MAX); - RNA_def_property_ui_text( - prop, "End Time", "Simulation time of the last blender frame (in seconds)"); - - prop = RNA_def_property(srna, "frame_offset", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "frameOffset"); - RNA_def_property_ui_text(prop, "Cache Offset", "Offset when reading baked cache"); - RNA_def_property_update(prop, NC_OBJECT, "rna_fluid_update"); - - prop = RNA_def_property(srna, "simulation_scale", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "realsize"); - RNA_def_property_range(prop, 0.001, 10); - RNA_def_property_ui_text(prop, "Real World Size", "Size of the simulation domain in meters"); - - prop = RNA_def_property(srna, "simulation_rate", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "animRate"); - RNA_def_property_range(prop, 0.0, 100.0); - RNA_def_property_ui_text( - prop, "Simulation Speed", "Fluid motion rate (0 = stationary, 1 = normal speed)"); - - prop = RNA_def_property(srna, "viscosity_base", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "viscosityValue"); - RNA_def_property_range(prop, 0, 10); - RNA_def_property_ui_text( - prop, - "Viscosity Base", - "Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1)"); - - prop = RNA_def_property(srna, "viscosity_exponent", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "viscosityExponent"); - RNA_def_property_range(prop, 0, 10); - RNA_def_property_ui_text( - prop, - "Viscosity Exponent", - "Negative exponent for the viscosity value (to simplify entering small values " - "e.g. 5*10^-6)"); - - prop = RNA_def_property(srna, "grid_levels", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "maxRefine"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, -1, 4); - RNA_def_property_ui_text( - prop, "Grid Levels", "Number of coarsened grids to use (-1 for automatic)"); - - prop = RNA_def_property(srna, "compressibility", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "gstar"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 0.001, 0.1); - RNA_def_property_ui_text(prop, - "Compressibility", - "Allowed compressibility due to gravitational force for standing fluid " - "(directly affects simulation step size)"); - - /* domain boundary settings */ - - rna_def_fluidsim_slip(srna); - - prop = RNA_def_property(srna, "surface_smooth", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "surfaceSmoothing"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 0.0, 5.0); - RNA_def_property_ui_text( - prop, - "Surface Smoothing", - "Amount of surface smoothing (a value of 0 is off, 1 is normal smoothing and " - "more than 1 is extra smoothing)"); - - prop = RNA_def_property(srna, "surface_subdivisions", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "surfaceSubdivs"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 0, 5); - RNA_def_property_ui_text( - prop, - "Surface Subdivisions", - "Number of isosurface subdivisions (this is necessary for the inclusion of particles " - "into the surface generation - WARNING: can lead to longer computation times !)"); - - prop = RNA_def_property(srna, "use_speed_vectors", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "domainNovecgen", 0); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text( - prop, "Generate Speed Vectors", "Generate speed vectors for vector blur"); - - /* no collision object surface */ - prop = RNA_def_property(srna, "use_surface_noobs", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSSG_NOOBS); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text( - prop, - "Remove Air Bubbles", - "Removes the air gap between fluid surface and obstacles - WARNING: Can result " - "in a dissolving surface in other areas"); - - /* particles */ - - prop = RNA_def_property(srna, "tracer_particles", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "generateTracers"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 0, 10000); - RNA_def_property_ui_text(prop, "Tracer Particles", "Number of tracer particles to generate"); - - prop = RNA_def_property(srna, "generate_particles", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "generateParticles"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_text( - prop, "Generate Particles", "Amount of particles to generate (0=off, 1=normal, >1=more)"); - - /* simulated fluid mesh data */ - prop = RNA_def_property(srna, "fluid_mesh_vertices", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "meshVelocities", "totvert"); - RNA_def_property_struct_type(prop, "FluidVertexVelocity"); - RNA_def_property_ui_text( - prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation"); - - rna_def_fluid_mesh_vertices(brna); -} - -static void rna_def_fluidsim_volume(StructRNA *srna) -{ - PropertyRNA *prop; - - static const EnumPropertyItem volume_type_items[] = { - {1, "VOLUME", 0, "Volume", "Use only the inner volume of the mesh"}, - {2, "SHELL", 0, "Shell", "Use only the outer shell of the mesh"}, - {3, "BOTH", 0, "Both", "Use both the inner volume and the outer shell of the mesh"}, - {0, NULL, 0, NULL, NULL}, - }; - - prop = RNA_def_property(srna, "volume_initialization", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "volumeInitType"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_enum_items(prop, volume_type_items); - RNA_def_property_ui_text( - prop, - "Volume Initialization", - "Volume initialization type " - "(WARNING: complex volumes might require too much memory and break simulation)"); - - prop = RNA_def_property(srna, "use_animated_mesh", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "domainNovecgen", 0); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text( - prop, - "Export Animated Mesh", - "Export this mesh as an animated one (slower and enforces No Slip, only use if really " - "necessary [e.g. armatures or parented objects], animated pos/rot/scale F-Curves " - "do not require it)"); -} - -static void rna_def_fluidsim_active(StructRNA *srna) -{ - PropertyRNA *prop; - - prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_ACTIVE); - RNA_def_property_ui_text(prop, "Enabled", "Object contributes to the fluid simulation"); -} - -static void rna_def_fluidsim_fluid(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "FluidFluidSettings", "FluidSettings"); - RNA_def_struct_sdna(srna, "FluidsimSettings"); - RNA_def_struct_ui_text(srna, - "Fluid Fluid Simulation Settings", - "Fluid simulation settings for the fluid in the simulation"); - - rna_def_fluidsim_active(srna); - rna_def_fluidsim_volume(srna); - - prop = RNA_def_property(srna, "initial_velocity", PROP_FLOAT, PROP_VELOCITY); - RNA_def_property_float_sdna(prop, NULL, "iniVelx"); - RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, -1000.1, 1000.1); - RNA_def_property_ui_text(prop, "Initial Velocity", "Initial velocity of fluid"); -} - -static void rna_def_fluidsim_obstacle(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "ObstacleFluidSettings", "FluidSettings"); - RNA_def_struct_sdna(srna, "FluidsimSettings"); - RNA_def_struct_ui_text(srna, - "Obstacle Fluid Simulation Settings", - "Fluid simulation settings for obstacles in the simulation"); - - rna_def_fluidsim_active(srna); - rna_def_fluidsim_volume(srna); - rna_def_fluidsim_slip(srna); - - prop = RNA_def_property(srna, "impact_factor", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "surfaceSmoothing"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, -2.0, 10.0); - RNA_def_property_ui_text( - prop, - "Impact Factor", - "This is an unphysical value for moving objects - it controls the impact an obstacle " - "has on the fluid, =0 behaves a bit like outflow (deleting fluid), =1 is default, " - "while >1 results in high forces (can be used to tweak total mass)"); -} - -static void rna_def_fluidsim_inflow(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "InflowFluidSettings", "FluidSettings"); - RNA_def_struct_sdna(srna, "FluidsimSettings"); - RNA_def_struct_ui_text(srna, - "Inflow Fluid Simulation Settings", - "Fluid simulation settings for objects adding fluids in the simulation"); - - rna_def_fluidsim_active(srna); - rna_def_fluidsim_volume(srna); - - prop = RNA_def_property(srna, "inflow_velocity", PROP_FLOAT, PROP_VELOCITY); - RNA_def_property_float_sdna(prop, NULL, "iniVelx"); - RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, -1000.1, 1000.1); - RNA_def_property_ui_text(prop, "Inflow Velocity", "Initial velocity of fluid"); - - prop = RNA_def_property(srna, "use_local_coords", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSINFLOW_LOCALCOORD); - RNA_def_property_ui_text( - prop, "Local Coordinates", "Use local coordinates for inflow (e.g. for rotating objects)"); -} - -static void rna_def_fluidsim_outflow(BlenderRNA *brna) -{ - StructRNA *srna; - - srna = RNA_def_struct(brna, "OutflowFluidSettings", "FluidSettings"); - RNA_def_struct_sdna(srna, "FluidsimSettings"); - RNA_def_struct_ui_text( - srna, - "Outflow Fluid Simulation Settings", - "Fluid simulation settings for objects removing fluids from the simulation"); - - rna_def_fluidsim_active(srna); - rna_def_fluidsim_volume(srna); -} - -static void rna_def_fluidsim_particle(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "ParticleFluidSettings", "FluidSettings"); - RNA_def_struct_sdna(srna, "FluidsimSettings"); - RNA_def_struct_ui_text(srna, - "Particle Fluid Simulation Settings", - "Fluid simulation settings for objects storing fluid particles generated" - " by the simulation"); - - prop = RNA_def_property(srna, "use_drops", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_DROP); - RNA_def_property_ui_text(prop, "Drops", "Show drop particles"); - - prop = RNA_def_property(srna, "use_floats", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_FLOAT); - RNA_def_property_ui_text(prop, "Floats", "Show floating foam particles"); - - prop = RNA_def_property(srna, "show_tracer", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "typeFlags", OB_FSPART_TRACER); - RNA_def_property_ui_text(prop, "Tracer", "Show tracer particles"); - - prop = RNA_def_property(srna, "particle_influence", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "particleInfSize"); - RNA_def_property_range(prop, 0.0, 2.0); - RNA_def_property_ui_text( - prop, - "Particle Influence", - "Amount of particle size scaling: 0=off (all same size), 1=full (range 0.2-2.0), " - ">1=stronger"); - - prop = RNA_def_property(srna, "alpha_influence", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "particleInfAlpha"); - RNA_def_property_range(prop, 0.0, 2.0); - RNA_def_property_ui_text( - prop, - "Alpha Influence", - "Amount of particle alpha change, inverse of size influence: 0=off (all same alpha), " - "1=full (larger particles get lower alphas, smaller ones higher values)"); - - prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); - RNA_def_property_string_maxlength(prop, FILE_MAX); - RNA_def_property_string_sdna(prop, NULL, "surfdataPath"); - RNA_def_property_ui_text( - prop, "Path", "Directory (and/or filename prefix) to store and load particles from"); - RNA_def_property_update(prop, 0, "rna_fluid_update"); -} - -static void rna_def_fluidsim_control(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "ControlFluidSettings", "FluidSettings"); - RNA_def_struct_sdna(srna, "FluidsimSettings"); - RNA_def_struct_ui_text( - srna, - "Control Fluid Simulation Settings", - "Fluid simulation settings for objects controlling the motion of fluid in the simulation"); - - rna_def_fluidsim_active(srna); - - prop = RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME); - RNA_def_property_float_sdna(prop, NULL, "cpsTimeStart"); - RNA_def_property_range(prop, 0.0, FLT_MAX); - RNA_def_property_ui_text(prop, "Start Time", "Time when the control particles are activated"); - - prop = RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME); - RNA_def_property_float_sdna(prop, NULL, "cpsTimeEnd"); - RNA_def_property_range(prop, 0.0, FLT_MAX); - RNA_def_property_ui_text(prop, "End Time", "Time when the control particles are deactivated"); - - prop = RNA_def_property(srna, "attraction_strength", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "attractforceStrength"); - RNA_def_property_range(prop, -10.0, 10.0); - RNA_def_property_ui_text(prop, - "Attraction Strength", - "Force strength for directional attraction towards the control object"); - - prop = RNA_def_property(srna, "attraction_radius", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "attractforceRadius"); - RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_text( - prop, "Attraction Radius", "Force field radius around the control object"); - - prop = RNA_def_property(srna, "velocity_strength", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "velocityforceStrength"); - RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_text( - prop, - "Velocity Strength", - "Force strength of how much of the control object's velocity is influencing the " - "fluid velocity"); - - prop = RNA_def_property(srna, "velocity_radius", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "velocityforceRadius"); - RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_text( - prop, "Velocity Radius", "Force field radius around the control object"); - - prop = RNA_def_property(srna, "quality", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "cpsQuality"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_range(prop, 5.0, 100.0); - RNA_def_property_ui_text( - prop, "Quality", "Quality which is used for object sampling (higher = better but slower)"); - - prop = RNA_def_property(srna, "use_reverse_frames", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", OB_FLUIDSIM_REVERSE); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Reverse Frames", "Reverse control object movement"); - RNA_def_property_update(prop, 0, "rna_fluid_find_enframe"); -} - -void RNA_def_fluidsim(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - static const EnumPropertyItem prop_fluid_type_items[] = { - {OB_FLUIDSIM_ENABLE, "NONE", 0, "None", ""}, - {OB_FLUIDSIM_DOMAIN, - "DOMAIN", - 0, - "Domain", - "Bounding box of this object represents the computational domain of the " - "fluid simulation"}, - {OB_FLUIDSIM_FLUID, - "FLUID", - 0, - "Fluid", - "Object represents a volume of fluid in the simulation"}, - {OB_FLUIDSIM_OBSTACLE, "OBSTACLE", 0, "Obstacle", "Object is a fixed obstacle"}, - {OB_FLUIDSIM_INFLOW, "INFLOW", 0, "Inflow", "Object adds fluid to the simulation"}, - {OB_FLUIDSIM_OUTFLOW, "OUTFLOW", 0, "Outflow", "Object removes fluid from the simulation"}, - {OB_FLUIDSIM_PARTICLE, - "PARTICLE", - 0, - "Particle", - "Object is made a particle system to display particles generated by a " - "fluidsim domain object"}, - {OB_FLUIDSIM_CONTROL, - "CONTROL", - 0, - "Control", - "Object is made a fluid control mesh, which influences the fluid"}, - {0, NULL, 0, NULL, NULL}, - }; - - srna = RNA_def_struct(brna, "FluidSettings", NULL); - RNA_def_struct_sdna(srna, "FluidsimSettings"); - RNA_def_struct_refine_func(srna, "rna_FluidSettings_refine"); - RNA_def_struct_path_func(srna, "rna_FluidSettings_path"); - RNA_def_struct_ui_text(srna, - "Fluid Simulation Settings", - "Fluid simulation settings for an object taking part in the simulation"); - - prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "type"); - RNA_def_property_enum_items(prop, prop_fluid_type_items); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Type", "Type of participation in the fluid simulation"); - RNA_def_property_update(prop, 0, "rna_FluidSettings_update_type"); - -# if 0 - prop = RNA_def_property(srna, "ipo", PROP_POINTER, PROP_NONE); - RNA_def_property_ui_text(prop, "IPO Curves", "IPO curves used by fluid simulation settings"); -# endif - - /* types */ - - rna_def_fluidsim_domain(brna); - rna_def_fluidsim_fluid(brna); - rna_def_fluidsim_obstacle(brna); - rna_def_fluidsim_inflow(brna); - rna_def_fluidsim_outflow(brna); - rna_def_fluidsim_particle(brna); - rna_def_fluidsim_control(brna); -} - -#endif diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 7aa3ee60c5a..2f59cde7e94 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -43,7 +43,7 @@ #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" #include "BKE_multires.h" -#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */ +#include "BKE_fluid.h" /* For BKE_fluid_modifier_free & BKE_fluid_modifier_create_type_data */ #include "RNA_access.h" #include "RNA_define.h" @@ -174,7 +174,7 @@ static const EnumPropertyItem rna_enum_time_mode_items[] = { # include "DNA_particle_types.h" # include "DNA_curve_types.h" -# include "DNA_smoke_types.h" +# include "DNA_fluid_types.h" # include "BKE_cachefile.h" # include "BKE_context.h" diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 7a03bdb952b..d07bf542954 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -317,8 +317,9 @@ static void rna_Image_active_tile_set(PointerRNA *ptr, Image *image = (Image *)ptr->data; ImageTile *tile = (ImageTile *)value.data; const int index = BLI_findindex(&image->tiles, tile); - if (index != -1) + if (index != -1) { image->active_tile_index = index; + } } static bool rna_Image_has_data_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 94394a4826b..46455a43b2e 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -155,7 +155,6 @@ void RNA_def_controller(struct BlenderRNA *brna); void RNA_def_curve(struct BlenderRNA *brna); void RNA_def_depsgraph(struct BlenderRNA *brna); void RNA_def_dynamic_paint(struct BlenderRNA *brna); -void RNA_def_fluidsim(struct BlenderRNA *brna); void RNA_def_fcurve(struct BlenderRNA *brna); void RNA_def_gpencil(struct BlenderRNA *brna); void RNA_def_greasepencil_modifier(struct BlenderRNA *brna); @@ -188,7 +187,7 @@ void RNA_def_view_layer(struct BlenderRNA *brna); void RNA_def_screen(struct BlenderRNA *brna); void RNA_def_sculpt_paint(struct BlenderRNA *brna); void RNA_def_sequencer(struct BlenderRNA *brna); -void RNA_def_smoke(struct BlenderRNA *brna); +void RNA_def_fluid(struct BlenderRNA *brna); void RNA_def_space(struct BlenderRNA *brna); void RNA_def_speaker(struct BlenderRNA *brna); void RNA_def_test(struct BlenderRNA *brna); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 7c9ac6a2072..1896c9dbec3 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -45,7 +45,7 @@ #include "BKE_mesh_remap.h" #include "BKE_multires.h" #include "BKE_ocean.h" -#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */ +#include "BKE_fluid.h" /* For BKE_fluid_modifier_free & BKE_fluid_modifier_create_type_data */ #include "RNA_access.h" #include "RNA_define.h" @@ -277,7 +277,6 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { ICON_MOD_EXPLODE, "Explode", "Break apart the mesh faces and let them follow particles"}, - {eModifierType_Fluidsim, "FLUID_SIMULATION", ICON_MOD_FLUIDSIM, "Fluid Simulation", ""}, {eModifierType_Ocean, "OCEAN", ICON_MOD_OCEAN, "Ocean", "Generate a moving ocean surface"}, {eModifierType_ParticleInstance, "PARTICLE_INSTANCE", @@ -289,7 +288,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { ICON_MOD_PARTICLES, "Particle System", "Spawn particles from the shape"}, - {eModifierType_Smoke, "SMOKE", ICON_MOD_SMOKE, "Smoke", ""}, + {eModifierType_Fluid, "FLUID", ICON_MOD_FLUIDSIM, "Fluid Simulation", ""}, {eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""}, {eModifierType_Surface, "SURFACE", ICON_MODIFIER, "Surface", ""}, {eModifierType_BParticles, "BPARTICLES", ICON_NONE, "BParticles", ""}, @@ -584,7 +583,7 @@ const EnumPropertyItem rna_enum_axis_flag_xyz_items[] = { #ifdef RNA_RUNTIME # include "DNA_particle_types.h" # include "DNA_curve_types.h" -# include "DNA_smoke_types.h" +# include "DNA_fluid_types.h" # include "BKE_cachefile.h" # include "BKE_context.h" @@ -665,8 +664,6 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr) return &RNA_BevelModifier; case eModifierType_Shrinkwrap: return &RNA_ShrinkwrapModifier; - case eModifierType_Fluidsim: - return &RNA_FluidSimulationModifier; case eModifierType_Mask: return &RNA_MaskModifier; case eModifierType_SimpleDeform: @@ -675,8 +672,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr) return &RNA_MultiresModifier; case eModifierType_Surface: return &RNA_SurfaceModifier; - case eModifierType_Smoke: - return &RNA_SmokeModifier; + case eModifierType_Fluid: + return &RNA_FluidModifier; case eModifierType_Solidify: return &RNA_SolidifyModifier; case eModifierType_Screw: @@ -732,6 +729,7 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr) case eModifierType_BParticlesOutput: return &RNA_BParticlesOutputModifier; /* Default */ + case eModifierType_Fluidsim: /* deprecated */ case eModifierType_None: case eModifierType_ShapeKey: case NUM_MODIFIER_TYPES: @@ -1041,25 +1039,27 @@ static void rna_UVProjector_object_set(PointerRNA *ptr, /* Other rna callbacks */ -static void rna_Smoke_set_type(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_fluid_set_type(Main *bmain, Scene *scene, PointerRNA *ptr) { - SmokeModifierData *smd = (SmokeModifierData *)ptr->data; + FluidModifierData *mmd = (FluidModifierData *)ptr->data; Object *ob = (Object *)ptr->owner_id; /* nothing changed */ - if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { + if ((mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { return; } - smokeModifier_free(smd); /* XXX TODO: completely free all 3 pointers */ - smokeModifier_createType(smd); /* create regarding of selected type */ +# ifdef WITH_FLUID + BKE_fluid_modifier_free(mmd); /* XXX TODO: completely free all 3 pointers */ + BKE_fluid_modifier_create_type_data(mmd); /* create regarding of selected type */ +# endif - switch (smd->type) { - case MOD_SMOKE_TYPE_DOMAIN: + switch (mmd->type) { + case MOD_FLUID_TYPE_DOMAIN: ob->dt = OB_WIRE; break; - case MOD_SMOKE_TYPE_FLOW: - case MOD_SMOKE_TYPE_COLL: + case MOD_FLUID_TYPE_FLOW: + case MOD_FLUID_TYPE_EFFEC: case 0: default: break; @@ -3619,23 +3619,23 @@ static void rna_def_modifier_cloth(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hair Grid Resolution", ""); } -static void rna_def_modifier_smoke(BlenderRNA *brna) +static void rna_def_modifier_fluid(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - static const EnumPropertyItem prop_smoke_type_items[] = { + static const EnumPropertyItem prop_fluid_type_items[] = { {0, "NONE", 0, "None", ""}, - {MOD_SMOKE_TYPE_DOMAIN, "DOMAIN", 0, "Domain", ""}, - {MOD_SMOKE_TYPE_FLOW, "FLOW", 0, "Flow", "Inflow/Outflow"}, - {MOD_SMOKE_TYPE_COLL, "COLLISION", 0, "Collision", ""}, + {MOD_FLUID_TYPE_DOMAIN, "DOMAIN", 0, "Domain", ""}, + {MOD_FLUID_TYPE_FLOW, "FLOW", 0, "Flow", "Inflow/Outflow"}, + {MOD_FLUID_TYPE_EFFEC, "EFFECTOR", 0, "Effector", ""}, {0, NULL, 0, NULL, NULL}, }; - srna = RNA_def_struct(brna, "SmokeModifier", "Modifier"); - RNA_def_struct_ui_text(srna, "Smoke Modifier", "Smoke simulation modifier"); - RNA_def_struct_sdna(srna, "SmokeModifierData"); - RNA_def_struct_ui_icon(srna, ICON_MOD_SMOKE); + srna = RNA_def_struct(brna, "FluidModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Fluid Modifier", "Fluid simulation modifier"); + RNA_def_struct_sdna(srna, "FluidModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM); prop = RNA_def_property(srna, "domain_settings", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "domain"); @@ -3645,16 +3645,16 @@ static void rna_def_modifier_smoke(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "flow"); RNA_def_property_ui_text(prop, "Flow Settings", ""); - prop = RNA_def_property(srna, "coll_settings", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "coll"); - RNA_def_property_ui_text(prop, "Collision Settings", ""); + prop = RNA_def_property(srna, "effector_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "effector"); + RNA_def_property_ui_text(prop, "Effector Settings", ""); - prop = RNA_def_property(srna, "smoke_type", PROP_ENUM, PROP_NONE); + prop = RNA_def_property(srna, "fluid_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type"); - RNA_def_property_enum_items(prop, prop_smoke_type_items); + RNA_def_property_enum_items(prop, prop_fluid_type_items); RNA_def_property_ui_text(prop, "Type", ""); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, 0, "rna_Smoke_set_type"); + RNA_def_property_update(prop, 0, "rna_fluid_set_type"); } static void rna_def_modifier_dynamic_paint(BlenderRNA *brna) @@ -4081,23 +4081,6 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Modifier_update"); } -static void rna_def_modifier_fluidsim(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "FluidSimulationModifier", "Modifier"); - RNA_def_struct_ui_text(srna, "Fluid Simulation Modifier", "Fluid simulation modifier"); - RNA_def_struct_sdna(srna, "FluidsimModifierData"); - RNA_def_struct_ui_icon(srna, ICON_MOD_FLUIDSIM); - - prop = RNA_def_property(srna, "settings", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_NEVER_NULL); - RNA_def_property_pointer_sdna(prop, NULL, "fss"); - RNA_def_property_ui_text( - prop, "Settings", "Settings for how this object is used in the fluid simulation"); -} - static void rna_def_modifier_mask(BlenderRNA *brna) { StructRNA *srna; @@ -6508,13 +6491,12 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_collision(brna); rna_def_modifier_bevel(brna); rna_def_modifier_shrinkwrap(brna); - rna_def_modifier_fluidsim(brna); rna_def_modifier_mask(brna); rna_def_modifier_simpledeform(brna); rna_def_modifier_warp(brna); rna_def_modifier_multires(brna); rna_def_modifier_surface(brna); - rna_def_modifier_smoke(brna); + rna_def_modifier_fluid(brna); rna_def_modifier_solidify(brna); rna_def_modifier_screw(brna); rna_def_modifier_uvwarp(brna); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 17e34cd60ad..68e3e522dff 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4506,7 +4506,7 @@ static void def_sh_tex_voronoi(StructRNA *srna) "SMOOTH_F1", 0, "Smooth F1", - "Smoothed version of F1. Weighted sum of neighbour voronoi cells"}, + "Smoothed version of F1. Weighted sum of neighbor voronoi cells"}, {SHD_VORONOI_DISTANCE_TO_EDGE, "DISTANCE_TO_EDGE", 0, diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 16d70e21ec2..559b8ca4cc1 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -25,7 +25,7 @@ #include "DNA_object_force_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -738,10 +738,10 @@ static char *rna_EffectorWeight_path(PointerRNA *ptr) } /* check smoke modifier */ - md = (ModifierData *)modifiers_findByType(ob, eModifierType_Smoke); + md = (ModifierData *)modifiers_findByType(ob, eModifierType_Fluid); if (md) { - SmokeModifierData *smd = (SmokeModifierData *)md; - if (smd->domain->effector_weights == ew) { + FluidModifierData *mmd = (FluidModifierData *)md; + if (mmd->domain->effector_weights == ew) { char name_esc[sizeof(md->name) * 2]; BLI_strescape(name_esc, md->name, sizeof(name_esc)); return BLI_sprintfN("modifiers[\"%s\"].settings.effector_weights", name_esc); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 211d9e19ab4..51df843947d 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -950,11 +950,12 @@ static float rna_PartSetting_linelenhead_get(struct PointerRNA *ptr) return settings->draw_line[1]; } -static bool rna_PartSettings_is_fluid_get(PointerRNA *ptr) +static int rna_PartSettings_is_fluid_get(PointerRNA *ptr) { ParticleSettings *part = (ParticleSettings *)ptr->data; - return part->type == PART_FLUID; + return (part->type & (PART_FLUID_FLIP | PART_FLUID_SPRAY | PART_FLUID_BUBBLE | PART_FLUID_FOAM | + PART_FLUID_TRACER)); } static void rna_ParticleSettings_use_clump_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c deleted file mode 100644 index c00cc789eff..00000000000 --- a/source/blender/makesrna/intern/rna_smoke.c +++ /dev/null @@ -1,1218 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup RNA - */ - -#include <stdlib.h> -#include <limits.h> - -#include "BLI_sys_types.h" - -#include "RNA_define.h" -#include "RNA_enum_types.h" - -#include "rna_internal.h" - -#include "BKE_modifier.h" -#include "BKE_smoke.h" -#include "BKE_pointcache.h" - -#include "DNA_modifier_types.h" -#include "DNA_object_force_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_smoke_types.h" - -#include "WM_types.h" - -#ifdef RNA_RUNTIME - -# include "BLI_threads.h" - -# include "BKE_colorband.h" -# include "BKE_context.h" -# include "BKE_particle.h" - -# include "DEG_depsgraph.h" -# include "DEG_depsgraph_build.h" - -# include "smoke_API.h" - -static void rna_Smoke_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) -{ - DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY); -} - -static void rna_Smoke_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr) -{ - rna_Smoke_update(bmain, scene, ptr); - DEG_relations_tag_update(bmain); -} - -static void rna_Smoke_resetCache(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) -{ - SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data; - if (settings->smd && settings->smd->domain) { - settings->point_cache[0]->flag |= PTCACHE_OUTDATED; - } - DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY); -} - -static void rna_Smoke_cachetype_set(struct PointerRNA *ptr, int value) -{ - SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data; - Object *ob = (Object *)ptr->owner_id; - - if (value != settings->cache_file_format) { - /* Clear old caches. */ - PTCacheID id; - BKE_ptcache_id_from_smoke(&id, ob, settings->smd); - BKE_ptcache_id_clear(&id, PTCACHE_CLEAR_ALL, 0); - - settings->cache_file_format = value; - } -} - -static void rna_Smoke_reset(Main *bmain, Scene *scene, PointerRNA *ptr) -{ - SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data; - - smokeModifier_reset(settings->smd); - rna_Smoke_resetCache(bmain, scene, ptr); - - rna_Smoke_update(bmain, scene, ptr); -} - -static void rna_Smoke_reset_dependency(Main *bmain, Scene *scene, PointerRNA *ptr) -{ - SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data; - - smokeModifier_reset(settings->smd); - - if (settings->smd && settings->smd->domain) { - settings->smd->domain->point_cache[0]->flag |= PTCACHE_OUTDATED; - } - - rna_Smoke_dependency_update(bmain, scene, ptr); -} - -static char *rna_SmokeDomainSettings_path(PointerRNA *ptr) -{ - SmokeDomainSettings *settings = (SmokeDomainSettings *)ptr->data; - ModifierData *md = (ModifierData *)settings->smd; - char name_esc[sizeof(md->name) * 2]; - - BLI_strescape(name_esc, md->name, sizeof(name_esc)); - return BLI_sprintfN("modifiers[\"%s\"].domain_settings", name_esc); -} - -static char *rna_SmokeFlowSettings_path(PointerRNA *ptr) -{ - SmokeFlowSettings *settings = (SmokeFlowSettings *)ptr->data; - ModifierData *md = (ModifierData *)settings->smd; - char name_esc[sizeof(md->name) * 2]; - - BLI_strescape(name_esc, md->name, sizeof(name_esc)); - return BLI_sprintfN("modifiers[\"%s\"].flow_settings", name_esc); -} - -static char *rna_SmokeCollSettings_path(PointerRNA *ptr) -{ - SmokeCollSettings *settings = (SmokeCollSettings *)ptr->data; - ModifierData *md = (ModifierData *)settings->smd; - char name_esc[sizeof(md->name) * 2]; - - BLI_strescape(name_esc, md->name, sizeof(name_esc)); - return BLI_sprintfN("modifiers[\"%s\"].coll_settings", name_esc); -} - -static int rna_SmokeModifier_grid_get_length(PointerRNA *ptr, int length[RNA_MAX_ARRAY_DIMENSION]) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - float *density = NULL; - int size = 0; - - if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { - /* high resolution smoke */ - int res[3]; - - smoke_turbulence_get_res(sds->wt, res); - size = res[0] * res[1] * res[2]; - - density = smoke_turbulence_get_density(sds->wt); - } - else if (sds->fluid) { - /* regular resolution */ - size = sds->res[0] * sds->res[1] * sds->res[2]; - density = smoke_get_density(sds->fluid); - } - - length[0] = (density) ? size : 0; -# else - (void)ptr; - length[0] = 0; -# endif - return length[0]; -} - -static int rna_SmokeModifier_color_grid_get_length(PointerRNA *ptr, - int length[RNA_MAX_ARRAY_DIMENSION]) -{ - rna_SmokeModifier_grid_get_length(ptr, length); - - length[0] *= 4; - return length[0]; -} - -static int rna_SmokeModifier_velocity_grid_get_length(PointerRNA *ptr, - int length[RNA_MAX_ARRAY_DIMENSION]) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - float *vx = NULL; - float *vy = NULL; - float *vz = NULL; - int size = 0; - - /* Velocity data is always low-resolution. */ - if (sds->fluid) { - size = 3 * sds->res[0] * sds->res[1] * sds->res[2]; - vx = smoke_get_velocity_x(sds->fluid); - vy = smoke_get_velocity_y(sds->fluid); - vz = smoke_get_velocity_z(sds->fluid); - } - - length[0] = (vx && vy && vz) ? size : 0; -# else - (void)ptr; - length[0] = 0; -# endif - return length[0]; -} - -static int rna_SmokeModifier_heat_grid_get_length(PointerRNA *ptr, - int length[RNA_MAX_ARRAY_DIMENSION]) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - float *heat = NULL; - int size = 0; - - /* Heat data is always low-resolution. */ - if (sds->fluid) { - size = sds->res[0] * sds->res[1] * sds->res[2]; - heat = smoke_get_heat(sds->fluid); - } - - length[0] = (heat) ? size : 0; -# else - (void)ptr; - length[0] = 0; -# endif - return length[0]; -} - -static void rna_SmokeModifier_density_grid_get(PointerRNA *ptr, float *values) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - int length[RNA_MAX_ARRAY_DIMENSION]; - int size = rna_SmokeModifier_grid_get_length(ptr, length); - float *density; - - BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); - - if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { - density = smoke_turbulence_get_density(sds->wt); - } - else { - density = smoke_get_density(sds->fluid); - } - - memcpy(values, density, size * sizeof(float)); - - BLI_rw_mutex_unlock(sds->fluid_mutex); -# else - UNUSED_VARS(ptr, values); -# endif -} - -static void rna_SmokeModifier_velocity_grid_get(PointerRNA *ptr, float *values) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - int length[RNA_MAX_ARRAY_DIMENSION]; - int size = rna_SmokeModifier_velocity_grid_get_length(ptr, length); - float *vx, *vy, *vz; - int i; - - BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); - - vx = smoke_get_velocity_x(sds->fluid); - vy = smoke_get_velocity_y(sds->fluid); - vz = smoke_get_velocity_z(sds->fluid); - - for (i = 0; i < size; i += 3) { - *(values++) = *(vx++); - *(values++) = *(vy++); - *(values++) = *(vz++); - } - - BLI_rw_mutex_unlock(sds->fluid_mutex); -# else - UNUSED_VARS(ptr, values); -# endif -} - -static void rna_SmokeModifier_color_grid_get(PointerRNA *ptr, float *values) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - int length[RNA_MAX_ARRAY_DIMENSION]; - int size = rna_SmokeModifier_grid_get_length(ptr, length); - - BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); - - if (!sds->fluid) { - memset(values, 0, size * sizeof(float)); - } - else { - if (sds->flags & MOD_SMOKE_HIGHRES) { - if (smoke_turbulence_has_colors(sds->wt)) { - smoke_turbulence_get_rgba(sds->wt, values, 0); - } - else { - smoke_turbulence_get_rgba_from_density(sds->wt, sds->active_color, values, 0); - } - } - else { - if (smoke_has_colors(sds->fluid)) { - smoke_get_rgba(sds->fluid, values, 0); - } - else { - smoke_get_rgba_from_density(sds->fluid, sds->active_color, values, 0); - } - } - } - - BLI_rw_mutex_unlock(sds->fluid_mutex); -# else - UNUSED_VARS(ptr, values); -# endif -} - -static void rna_SmokeModifier_flame_grid_get(PointerRNA *ptr, float *values) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - int length[RNA_MAX_ARRAY_DIMENSION]; - int size = rna_SmokeModifier_grid_get_length(ptr, length); - float *flame; - - BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); - - if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { - flame = smoke_turbulence_get_flame(sds->wt); - } - else { - flame = smoke_get_flame(sds->fluid); - } - - if (flame) { - memcpy(values, flame, size * sizeof(float)); - } - else { - memset(values, 0, size * sizeof(float)); - } - - BLI_rw_mutex_unlock(sds->fluid_mutex); -# else - UNUSED_VARS(ptr, values); -# endif -} - -static void rna_SmokeModifier_heat_grid_get(PointerRNA *ptr, float *values) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - int length[RNA_MAX_ARRAY_DIMENSION]; - int size = rna_SmokeModifier_heat_grid_get_length(ptr, length); - float *heat; - - BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); - - heat = smoke_get_heat(sds->fluid); - - if (heat != NULL) { - /* scale heat values from -2.0-2.0 to -1.0-1.0. */ - for (int i = 0; i < size; i++) { - values[i] = heat[i] * 0.5f; - } - } - else { - memset(values, 0, size * sizeof(float)); - } - - BLI_rw_mutex_unlock(sds->fluid_mutex); -# else - UNUSED_VARS(ptr, values); -# endif -} - -static void rna_SmokeModifier_temperature_grid_get(PointerRNA *ptr, float *values) -{ -# ifdef WITH_SMOKE - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - int length[RNA_MAX_ARRAY_DIMENSION]; - int size = rna_SmokeModifier_grid_get_length(ptr, length); - float *flame; - - BLI_rw_mutex_lock(sds->fluid_mutex, THREAD_LOCK_READ); - - if (sds->flags & MOD_SMOKE_HIGHRES && sds->wt) { - flame = smoke_turbulence_get_flame(sds->wt); - } - else { - flame = smoke_get_flame(sds->fluid); - } - - if (flame) { - /* Output is such that 0..1 maps to 0..1000K */ - float offset = sds->flame_ignition; - float scale = sds->flame_max_temp - sds->flame_ignition; - - for (int i = 0; i < size; i++) { - values[i] = (flame[i] > 0.01f) ? offset + flame[i] * scale : 0.0f; - } - } - else { - memset(values, 0, size * sizeof(float)); - } - - BLI_rw_mutex_unlock(sds->fluid_mutex); -# else - UNUSED_VARS(ptr, values); -# endif -} - -static void rna_SmokeFlow_density_vgroup_get(PointerRNA *ptr, char *value) -{ - SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data; - rna_object_vgroup_name_index_get(ptr, value, flow->vgroup_density); -} - -static int rna_SmokeFlow_density_vgroup_length(PointerRNA *ptr) -{ - SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data; - return rna_object_vgroup_name_index_length(ptr, flow->vgroup_density); -} - -static void rna_SmokeFlow_density_vgroup_set(PointerRNA *ptr, const char *value) -{ - SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data; - rna_object_vgroup_name_index_set(ptr, value, &flow->vgroup_density); -} - -static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value) -{ - SmokeFlowSettings *flow = (SmokeFlowSettings *)ptr->data; - rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name)); -} - -static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, bool value) -{ - SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; - - sds->use_coba = value; - - if (value && sds->coba == NULL) { - sds->coba = BKE_colorband_add(false); - } -} - -#else - -static void rna_def_smoke_domain_settings(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - static const EnumPropertyItem prop_noise_type_items[] = { - {MOD_SMOKE_NOISEWAVE, "NOISEWAVE", 0, "Wavelet", ""}, -# ifdef WITH_FFTW3 - {MOD_SMOKE_NOISEFFT, "NOISEFFT", 0, "FFT", ""}, -# endif - /* {MOD_SMOKE_NOISECURL, "NOISECURL", 0, "Curl", ""}, */ - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem prop_compression_items[] = { - {VDB_COMPRESSION_ZIP, "ZIP", 0, "Zip", "Effective but slow compression"}, -# ifdef WITH_OPENVDB_BLOSC - {VDB_COMPRESSION_BLOSC, - "BLOSC", - 0, - "Blosc", - "Multithreaded compression, similar in size and quality as 'Zip'"}, -# endif - {VDB_COMPRESSION_NONE, "NONE", 0, "None", "Do not use any compression"}, - {0, NULL, 0, NULL, NULL}}; - - static const EnumPropertyItem smoke_cache_comp_items[] = { - {SM_CACHE_LIGHT, "CACHELIGHT", 0, "Lite", "Fast but not so effective compression"}, - {SM_CACHE_HEAVY, "CACHEHEAVY", 0, "Heavy", "Effective but slow compression"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem smoke_highres_sampling_items[] = { - {SM_HRES_FULLSAMPLE, "FULLSAMPLE", 0, "Full Sample", ""}, - {SM_HRES_LINEAR, "LINEAR", 0, "Linear", ""}, - {SM_HRES_NEAREST, "NEAREST", 0, "Nearest", ""}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem smoke_data_depth_items[] = { - {16, "16", 0, "Float (Half)", "Half float (16 bit data)"}, - {0, "32", 0, "Float (Full)", "Full float (32 bit data)"}, /* default */ - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem smoke_domain_colli_items[] = { - {SM_BORDER_OPEN, "BORDEROPEN", 0, "Open", "Smoke doesn't collide with any border"}, - {SM_BORDER_VERTICAL, - "BORDERVERTICAL", - 0, - "Vertically Open", - "Smoke doesn't collide with top and bottom sides"}, - {SM_BORDER_CLOSED, "BORDERCLOSED", 0, "Collide All", "Smoke collides with every side"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem cache_file_type_items[] = { - {PTCACHE_FILE_PTCACHE, - "POINTCACHE", - 0, - "Point Cache", - "Blender specific point cache file format"}, -# ifdef WITH_OPENVDB - {PTCACHE_FILE_OPENVDB, "OPENVDB", 0, "OpenVDB", "OpenVDB file format"}, -# endif - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem smoke_view_items[] = { - {MOD_SMOKE_SLICE_VIEW_ALIGNED, - "VIEW_ALIGNED", - 0, - "View", - "Slice volume parallel to the view plane"}, - {MOD_SMOKE_SLICE_AXIS_ALIGNED, - "AXIS_ALIGNED", - 0, - "Axis", - "Slice volume parallel to the major axis"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem axis_slice_method_items[] = { - {AXIS_SLICE_FULL, "FULL", 0, "Full", "Slice the whole domain object"}, - {AXIS_SLICE_SINGLE, "SINGLE", 0, "Single", "Perform a single slice of the domain object"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem interp_method_item[] = { - {VOLUME_INTERP_LINEAR, "LINEAR", 0, "Linear", "Good smoothness and speed"}, - {VOLUME_INTERP_CUBIC, - "CUBIC", - 0, - "Cubic", - "Smoothed high quality interpolation, but slower"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem axis_slice_position_items[] = { - {SLICE_AXIS_AUTO, - "AUTO", - 0, - "Auto", - "Adjust slice direction according to the view direction"}, - {SLICE_AXIS_X, "X", 0, "X", "Slice along the X axis"}, - {SLICE_AXIS_Y, "Y", 0, "Y", "Slice along the Y axis"}, - {SLICE_AXIS_Z, "Z", 0, "Z", "Slice along the Z axis"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem vector_draw_items[] = { - {VECTOR_DRAW_NEEDLE, "NEEDLE", 0, "Needle", "Display vectors as needles"}, - {VECTOR_DRAW_STREAMLINE, "STREAMLINE", 0, "Streamlines", "Display vectors as streamlines"}, - {0, NULL, 0, NULL, NULL}, - }; - - srna = RNA_def_struct(brna, "SmokeDomainSettings", NULL); - RNA_def_struct_ui_text(srna, "Domain Settings", "Smoke domain settings"); - RNA_def_struct_sdna(srna, "SmokeDomainSettings"); - RNA_def_struct_path_func(srna, "rna_SmokeDomainSettings_path"); - - prop = RNA_def_property(srna, "resolution_max", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "maxres"); - RNA_def_property_range(prop, 6, 512); - RNA_def_property_ui_range(prop, 24, 512, 2, -1); - RNA_def_property_ui_text(prop, "Max Res", "Maximal resolution used in the fluid domain"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "amplify", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "amplify"); - RNA_def_property_range(prop, 1, 10); - RNA_def_property_ui_range(prop, 1, 10, 1, -1); - RNA_def_property_ui_text( - prop, "Amplification", "Enhance the resolution of smoke by this factor using noise"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "use_high_resolution", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGHRES); - RNA_def_property_ui_text(prop, "High Res", "Enable high resolution (using amplification)"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "show_high_resolution", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "viewsettings", MOD_SMOKE_VIEW_SHOW_HIGHRES); - RNA_def_property_ui_text( - prop, "Show High Resolution", "Show high resolution (using amplification)"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "noise_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "noise"); - RNA_def_property_enum_items(prop, prop_noise_type_items); - RNA_def_property_ui_text( - prop, "Noise Method", "Noise method which is used for creating the high resolution"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "alpha"); - RNA_def_property_range(prop, -5.0, 5.0); - RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5); - RNA_def_property_ui_text( - prop, - "Density", - "How much density affects smoke motion (higher value results in faster rising smoke)"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "beta", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "beta"); - RNA_def_property_range(prop, -5.0, 5.0); - RNA_def_property_ui_range(prop, -5.0, 5.0, 0.02, 5); - RNA_def_property_ui_text( - prop, - "Heat", - "How much heat affects smoke motion (higher value results in faster rising smoke)"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "collision_collection", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "coll_group"); - RNA_def_property_struct_type(prop, "Collection"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Collision Collection", "Limit collisions to this collection"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency"); - - prop = RNA_def_property(srna, "fluid_collection", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "fluid_group"); - RNA_def_property_struct_type(prop, "Collection"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Fluid Collection", "Limit fluid objects to this collection"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency"); - - prop = RNA_def_property(srna, "effector_collection", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "eff_group"); - RNA_def_property_struct_type(prop, "Collection"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Effector Collection", "Limit effectors to this collection"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset_dependency"); - - prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "strength"); - RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 2); - RNA_def_property_ui_text(prop, "Strength", "Strength of noise"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "dissolve_speed", PROP_INT, PROP_TIME); - RNA_def_property_int_sdna(prop, NULL, "diss_speed"); - RNA_def_property_range(prop, 1.0, 10000.0); - RNA_def_property_ui_range(prop, 1.0, 10000.0, 1, -1); - RNA_def_property_ui_text(prop, "Dissolve Speed", "Dissolve Speed"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "use_dissolve_smoke", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE); - RNA_def_property_ui_text(prop, "Dissolve Smoke", "Enable smoke to disappear over time"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "use_dissolve_smoke_log", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_DISSOLVE_LOG); - RNA_def_property_ui_text(prop, "Logarithmic Dissolve", "Using 1/x "); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_NEVER_NULL); - RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]"); - RNA_def_property_struct_type(prop, "PointCache"); - RNA_def_property_ui_text(prop, "Point Cache", ""); - - prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "cache_comp"); - RNA_def_property_enum_items(prop, smoke_cache_comp_items); - RNA_def_property_ui_text(prop, "Cache Compression", "Compression method to be used"); - - prop = RNA_def_property(srna, "openvdb_cache_compress_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "openvdb_comp"); - RNA_def_property_enum_items(prop, prop_compression_items); - RNA_def_property_ui_text(prop, "Compression", "Compression method to be used"); - - prop = RNA_def_property(srna, "data_depth", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_depth"); - RNA_def_property_enum_items(prop, smoke_data_depth_items); - RNA_def_property_ui_text(prop, - "Data Depth", - "Bit depth for writing all scalar (including vector) " - "lower values reduce file size"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); - - prop = RNA_def_property(srna, "collision_extents", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "border_collisions"); - RNA_def_property_enum_items(prop, smoke_domain_colli_items); - RNA_def_property_ui_text( - prop, "Border Collisions", "Select which domain border will be treated as collision object"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "EffectorWeights"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Effector Weights", ""); - - prop = RNA_def_property(srna, "highres_sampling", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, smoke_highres_sampling_items); - RNA_def_property_ui_text(prop, "Emitter", "Method for sampling the high resolution flow"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "time_scale"); - RNA_def_property_range(prop, 0.2, 1.5); - RNA_def_property_ui_range(prop, 0.2, 1.5, 0.02, 5); - RNA_def_property_ui_text(prop, "Time Scale", "Adjust simulation speed"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "vorticity", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "vorticity"); - RNA_def_property_range(prop, 0.01, 4.0); - RNA_def_property_ui_range(prop, 0.01, 4.0, 0.02, 5); - RNA_def_property_ui_text(prop, "Vorticity", "Amount of turbulence/rotation in fluid"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "density_grid", PROP_FLOAT, PROP_NONE); - RNA_def_property_array(prop, 32); - RNA_def_property_flag(prop, PROP_DYNAMIC); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length"); - RNA_def_property_float_funcs(prop, "rna_SmokeModifier_density_grid_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Density Grid", "Smoke density grid"); - - prop = RNA_def_property(srna, "velocity_grid", PROP_FLOAT, PROP_NONE); - RNA_def_property_array(prop, 32); - RNA_def_property_flag(prop, PROP_DYNAMIC); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_velocity_grid_get_length"); - RNA_def_property_float_funcs(prop, "rna_SmokeModifier_velocity_grid_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Velocity Grid", "Smoke velocity grid"); - - prop = RNA_def_property(srna, "flame_grid", PROP_FLOAT, PROP_NONE); - RNA_def_property_array(prop, 32); - RNA_def_property_flag(prop, PROP_DYNAMIC); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length"); - RNA_def_property_float_funcs(prop, "rna_SmokeModifier_flame_grid_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Flame Grid", "Smoke flame grid"); - - prop = RNA_def_property(srna, "color_grid", PROP_FLOAT, PROP_NONE); - RNA_def_property_array(prop, 32); - RNA_def_property_flag(prop, PROP_DYNAMIC); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_color_grid_get_length"); - RNA_def_property_float_funcs(prop, "rna_SmokeModifier_color_grid_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Color Grid", "Smoke color grid"); - - prop = RNA_def_property(srna, "heat_grid", PROP_FLOAT, PROP_NONE); - RNA_def_property_array(prop, 32); - RNA_def_property_flag(prop, PROP_DYNAMIC); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_heat_grid_get_length"); - RNA_def_property_float_funcs(prop, "rna_SmokeModifier_heat_grid_get", NULL, NULL); - RNA_def_property_ui_text(prop, "Heat Grid", "Smoke heat grid"); - - prop = RNA_def_property(srna, "temperature_grid", PROP_FLOAT, PROP_NONE); - RNA_def_property_array(prop, 32); - RNA_def_property_flag(prop, PROP_DYNAMIC); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_dynamic_array_funcs(prop, "rna_SmokeModifier_grid_get_length"); - RNA_def_property_float_funcs(prop, "rna_SmokeModifier_temperature_grid_get", NULL, NULL); - RNA_def_property_ui_text( - prop, "Temperature Grid", "Smoke temperature grid, range 0..1 represents 0..1000K"); - - prop = RNA_def_property(srna, - "cell_size", - PROP_FLOAT, - PROP_XYZ); /* can change each frame when using adaptive domain */ - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "cell_size", "Cell Size"); - - prop = RNA_def_property(srna, - "start_point", - PROP_FLOAT, - PROP_XYZ); /* can change each frame when using adaptive domain */ - RNA_def_property_float_sdna(prop, NULL, "p0"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "p0", "Start point"); - - prop = RNA_def_property(srna, - "domain_resolution", - PROP_INT, - PROP_XYZ); /* can change each frame when using adaptive domain */ - RNA_def_property_int_sdna(prop, NULL, "res"); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "res", "Smoke Grid Resolution"); - - prop = RNA_def_property(srna, "burning_rate", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.01, 4.0); - RNA_def_property_ui_range(prop, 0.01, 2.0, 1.0, 5); - RNA_def_property_ui_text( - prop, "Speed", "Speed of the burning reaction (use larger values for smaller flame)"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "flame_smoke", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.0, 8.0); - RNA_def_property_ui_range(prop, 0.0, 4.0, 1.0, 5); - RNA_def_property_ui_text(prop, "Smoke", "Amount of smoke created by burning fuel"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "flame_vorticity", PROP_FLOAT, PROP_FACTOR); - RNA_def_property_range(prop, 0.0, 2.0); - RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 5); - RNA_def_property_ui_text(prop, "Vorticity", "Additional vorticity for the flames"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "flame_ignition", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.5, 5.0); - RNA_def_property_ui_range(prop, 0.5, 2.5, 1.0, 5); - RNA_def_property_ui_text(prop, "Ignition", "Minimum temperature of flames"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "flame_max_temp", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 1.0, 10.0); - RNA_def_property_ui_range(prop, 1.0, 5.0, 1.0, 5); - RNA_def_property_ui_text(prop, "Maximum", "Maximum temperature of flames"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "flame_smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke emitted from burning fuel"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "use_adaptive_domain", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_ADAPTIVE_DOMAIN); - RNA_def_property_ui_text( - prop, "Adaptive Domain", "Adapt simulation resolution and size to fluid"); - RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "additional_res", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "adapt_res"); - RNA_def_property_range(prop, 0, 512); - RNA_def_property_ui_range(prop, 0, 512, 2, -1); - RNA_def_property_ui_text(prop, "Additional", "Maximum number of additional cells"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "adapt_margin", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "adapt_margin"); - RNA_def_property_range(prop, 2, 24); - RNA_def_property_ui_range(prop, 2, 24, 2, -1); - RNA_def_property_ui_text( - prop, "Margin", "Margin added around fluid to minimize boundary interference"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "adapt_threshold", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.01, 0.5); - RNA_def_property_ui_range(prop, 0.01, 0.5, 1.0, 5); - RNA_def_property_ui_text( - prop, "Threshold", "Maximum amount of fluid cell can contain before it is considered empty"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - prop = RNA_def_property(srna, "cache_file_format", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "cache_file_format"); - RNA_def_property_enum_items(prop, cache_file_type_items); - RNA_def_property_enum_funcs(prop, NULL, "rna_Smoke_cachetype_set", NULL); - RNA_def_property_ui_text(prop, "File Format", "Select the file format to be used for caching"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_resetCache"); - - /* display settings */ - - prop = RNA_def_property(srna, "slice_method", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "slice_method"); - RNA_def_property_enum_items(prop, smoke_view_items); - RNA_def_property_ui_text(prop, "View Method", "How to slice the volume for viewport rendering"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "axis_slice_method", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "axis_slice_method"); - RNA_def_property_enum_items(prop, axis_slice_method_items); - RNA_def_property_ui_text(prop, "Method", ""); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "slice_axis", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "slice_axis"); - RNA_def_property_enum_items(prop, axis_slice_position_items); - RNA_def_property_ui_text(prop, "Axis", ""); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "slice_per_voxel", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "slice_per_voxel"); - RNA_def_property_range(prop, 0.0, 100.0); - RNA_def_property_ui_range(prop, 0.0, 5.0, 0.1, 1); - RNA_def_property_ui_text( - prop, "Slice Per Voxel", "How many slices per voxel should be generated"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "slice_depth", PROP_FLOAT, PROP_FACTOR); - RNA_def_property_float_sdna(prop, NULL, "slice_depth"); - RNA_def_property_range(prop, 0.0, 1.0); - RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3); - RNA_def_property_ui_text(prop, "Position", "Position of the slice"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "display_thickness", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "display_thickness"); - RNA_def_property_range(prop, 0.001, 1000.0); - RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3); - RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); - - prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "interp_method"); - RNA_def_property_enum_items(prop, interp_method_item); - RNA_def_property_ui_text( - prop, "Interpolation", "Interpolation method to use for smoke/fire volumes in solid mode"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "show_velocity", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "draw_velocity", 0); - RNA_def_property_ui_text( - prop, "Display Velocity", "Toggle visualization of the velocity field as needles"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "vector_display_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "vector_draw_type"); - RNA_def_property_enum_items(prop, vector_draw_items); - RNA_def_property_ui_text(prop, "Display Type", ""); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "vector_scale", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "vector_scale"); - RNA_def_property_range(prop, 0.0, 1000.0); - RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3); - RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - /* --------- Color mapping. --------- */ - - prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0); - RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set"); - RNA_def_property_ui_text( - prop, - "Use Color Ramp", - "Render a simulation field while mapping its voxels values to the colors of a ramp"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - static const EnumPropertyItem coba_field_items[] = { - {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"}, - {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"}, - {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"}, - {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"}, - {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"}, - {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"}, - {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"}, - {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"}, - {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"}, - {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"}, - {0, NULL, 0, NULL, NULL}, - }; - - prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "coba_field"); - RNA_def_property_enum_items(prop, coba_field_items); - RNA_def_property_ui_text(prop, "Field", "Simulation field to color map"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL); - RNA_def_property_pointer_sdna(prop, NULL, "coba"); - RNA_def_property_struct_type(prop, "ColorRamp"); - RNA_def_property_ui_text(prop, "Color Ramp", ""); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); - - prop = RNA_def_property(srna, "clipping", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "clipping"); - RNA_def_property_range(prop, 0.0, 1.0); - RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 3); - RNA_def_property_ui_text( - prop, - "Clipping", - "Value under which voxels are considered empty space to optimize caching and rendering"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); -} - -static void rna_def_smoke_flow_settings(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - static const EnumPropertyItem smoke_flow_types[] = { - {MOD_SMOKE_FLOW_TYPE_OUTFLOW, "OUTFLOW", 0, "Outflow", "Delete smoke from simulation"}, - {MOD_SMOKE_FLOW_TYPE_SMOKE, "SMOKE", 0, "Smoke", "Add smoke"}, - {MOD_SMOKE_FLOW_TYPE_SMOKEFIRE, "BOTH", 0, "Fire + Smoke", "Add fire and smoke"}, - {MOD_SMOKE_FLOW_TYPE_FIRE, "FIRE", 0, "Fire", "Add fire"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem smoke_flow_sources[] = { - {MOD_SMOKE_FLOW_SOURCE_PARTICLES, - "PARTICLES", - ICON_PARTICLES, - "Particle System", - "Emit smoke from particles"}, - {MOD_SMOKE_FLOW_SOURCE_MESH, - "MESH", - ICON_META_CUBE, - "Mesh", - "Emit smoke from mesh surface or volume"}, - {0, NULL, 0, NULL, NULL}, - }; - - static const EnumPropertyItem smoke_flow_texture_types[] = { - {MOD_SMOKE_FLOW_TEXTURE_MAP_AUTO, - "AUTO", - 0, - "Generated", - "Generated coordinates centered to flow object"}, - {MOD_SMOKE_FLOW_TEXTURE_MAP_UV, "UV", 0, "UV", "Use UV layer for texture coordinates"}, - {0, NULL, 0, NULL, NULL}, - }; - - srna = RNA_def_struct(brna, "SmokeFlowSettings", NULL); - RNA_def_struct_ui_text(srna, "Flow Settings", "Smoke flow settings"); - RNA_def_struct_sdna(srna, "SmokeFlowSettings"); - RNA_def_struct_path_func(srna, "rna_SmokeFlowSettings_path"); - - prop = RNA_def_property(srna, "density", PROP_FLOAT, PROP_FACTOR); - RNA_def_property_float_sdna(prop, NULL, "density"); - RNA_def_property_range(prop, 0.0, 1); - RNA_def_property_ui_range(prop, 0.0, 1.0, 1.0, 4); - RNA_def_property_ui_text(prop, "Density", ""); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "smoke_color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "color"); - RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Smoke Color", "Color of smoke"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "fuel_amount", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.0, 10); - RNA_def_property_ui_range(prop, 0.0, 5.0, 1.0, 4); - RNA_def_property_ui_text(prop, "Flame Rate", ""); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "temperature", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "temp"); - RNA_def_property_range(prop, -10, 10); - RNA_def_property_ui_range(prop, -10, 10, 1, 1); - RNA_def_property_ui_text(prop, "Temp. Diff.", "Temperature difference to ambient temperature"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "psys"); - RNA_def_property_struct_type(prop, "ParticleSystem"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Particle Systems", "Particle systems emitted from the object"); - RNA_def_property_update(prop, 0, "rna_Smoke_reset_dependency"); - - prop = RNA_def_property(srna, "smoke_flow_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "type"); - RNA_def_property_enum_items(prop, smoke_flow_types); - RNA_def_property_ui_text(prop, "Flow Type", "Change how flow affects the simulation"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "smoke_flow_source", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "source"); - RNA_def_property_enum_items(prop, smoke_flow_sources); - RNA_def_property_ui_text(prop, "Source", "Change how smoke is emitted"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_ABSOLUTE); - RNA_def_property_ui_text( - prop, "Absolute Density", "Only allow given density value in emitter area"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "use_initial_velocity", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_INITVELOCITY); - RNA_def_property_ui_text( - prop, "Initial Velocity", "Smoke has some initial velocity when it is emitted"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "vel_multi"); - RNA_def_property_range(prop, -100.0, 100.0); - RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5); - RNA_def_property_ui_text(prop, "Source", "Multiplier of source velocity passed to smoke"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "vel_normal"); - RNA_def_property_range(prop, -100.0, 100.0); - RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5); - RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "vel_random"); - RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5); - RNA_def_property_ui_text(prop, "Random", "Amount of random velocity"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "volume_density", PROP_FLOAT, PROP_FACTOR); - RNA_def_property_range(prop, 0.0, 1.0); - RNA_def_property_ui_range(prop, 0.0, 1.0, 0.05, 5); - RNA_def_property_ui_text(prop, "Volume", "Factor for smoke emitted from inside the mesh volume"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "surface_distance", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_range(prop, 0.0, 10.0); - RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5); - RNA_def_property_ui_text(prop, "Surface", "Maximum distance from mesh surface to emit smoke"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "particle_size", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.1, 20.0); - RNA_def_property_ui_range(prop, 0.5, 5.0, 0.05, 5); - RNA_def_property_ui_text(prop, "Size", "Particle size in simulation cells"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "use_particle_size", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_USE_PART_SIZE); - RNA_def_property_ui_text( - prop, "Set Size", "Set particle size in simulation cells or use nearest cell"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "subframes", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 0, 50); - RNA_def_property_ui_range(prop, 0, 10, 1, -1); - RNA_def_property_ui_text(prop, - "Subframes", - "Number of additional samples to take between frames to improve " - "quality of fast moving flows"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "density_vertex_group", PROP_STRING, PROP_NONE); - RNA_def_property_string_funcs(prop, - "rna_SmokeFlow_density_vgroup_get", - "rna_SmokeFlow_density_vgroup_length", - "rna_SmokeFlow_density_vgroup_set"); - RNA_def_property_ui_text( - prop, "Vertex Group", "Name of vertex group which determines surface emission rate"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_TEXTUREEMIT); - RNA_def_property_ui_text(prop, "Use Texture", "Use a texture to control emission strength"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "texture_map_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "texture_type"); - RNA_def_property_enum_items(prop, smoke_flow_texture_types); - RNA_def_property_ui_text(prop, "Mapping", "Texture mapping type"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "uvlayer_name"); - RNA_def_property_ui_text(prop, "UV Map", "UV map name"); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SmokeFlow_uvlayer_set"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "noise_texture", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Texture", "Texture that controls emission strength"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "texture_size", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.01, 10.0); - RNA_def_property_ui_range(prop, 0.1, 5.0, 0.05, 5); - RNA_def_property_ui_text(prop, "Size", "Size of texture mapping"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); - - prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.0, 200.0); - RNA_def_property_ui_range(prop, 0.0, 100.0, 0.05, 5); - RNA_def_property_ui_text(prop, "Offset", "Z-offset of texture mapping"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); -} - -static void rna_def_smoke_coll_settings(BlenderRNA *brna) -{ - static const EnumPropertyItem smoke_coll_type_items[] = { - {SM_COLL_STATIC, "COLLSTATIC", 0, "Static", "Non moving obstacle"}, - {SM_COLL_RIGID, "COLLRIGID", 0, "Rigid", "Rigid obstacle"}, - {SM_COLL_ANIMATED, "COLLANIMATED", 0, "Animated", "Animated obstacle"}, - {0, NULL, 0, NULL, NULL}, - }; - - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "SmokeCollSettings", NULL); - RNA_def_struct_ui_text(srna, "Collision Settings", "Smoke collision settings"); - RNA_def_struct_sdna(srna, "SmokeCollSettings"); - RNA_def_struct_path_func(srna, "rna_SmokeCollSettings_path"); - - prop = RNA_def_property(srna, "collision_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "type"); - RNA_def_property_enum_items(prop, smoke_coll_type_items); - RNA_def_property_ui_text(prop, "Collision Type", "Collision type"); - RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset"); -} - -void RNA_def_smoke(BlenderRNA *brna) -{ - rna_def_smoke_domain_settings(brna); - rna_def_smoke_flow_settings(brna); - rna_def_smoke_coll_settings(brna); -} - -#endif diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index e0232431930..ffc7425adaa 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -31,7 +31,6 @@ set(INC ../makesdna ../makesrna ../render/extern/include - ../../../intern/elbeem/extern ../../../intern/eigen ../../../intern/guardedalloc ) @@ -59,8 +58,7 @@ set(SRC intern/MOD_dynamicpaint.c intern/MOD_edgesplit.c intern/MOD_explode.c - intern/MOD_fluidsim.c - intern/MOD_fluidsim_util.c + intern/MOD_fluid.c intern/MOD_functiondeform_cxx.cc intern/MOD_functiondeform.c intern/MOD_functionpoints_cxx.cc @@ -89,7 +87,6 @@ set(SRC intern/MOD_shrinkwrap.c intern/MOD_simpledeform.c intern/MOD_skin.c - intern/MOD_smoke.c intern/MOD_smooth.c intern/MOD_softbody.c intern/MOD_solidify.c @@ -113,7 +110,6 @@ set(SRC intern/MOD_wireframe.c MOD_modifiertypes.h - intern/MOD_fluidsim_util.h intern/MOD_meshcache_util.h intern/MOD_solidify_util.h intern/MOD_util.h @@ -148,7 +144,7 @@ if(WITH_MOD_REMESH) endif() if(WITH_MOD_FLUID) - add_definitions(-DWITH_MOD_FLUID) + add_definitions(-DWITH_FLUID) endif() if(WITH_MOD_OCEANSIM) diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h index 0560ed86c75..5668b518195 100644 --- a/source/blender/modifiers/MOD_modifiertypes.h +++ b/source/blender/modifiers/MOD_modifiertypes.h @@ -56,7 +56,7 @@ extern ModifierTypeInfo modifierType_Mask; extern ModifierTypeInfo modifierType_SimpleDeform; extern ModifierTypeInfo modifierType_Multires; extern ModifierTypeInfo modifierType_Surface; -extern ModifierTypeInfo modifierType_Smoke; +extern ModifierTypeInfo modifierType_Fluid; extern ModifierTypeInfo modifierType_ShapeKey; extern ModifierTypeInfo modifierType_Solidify; extern ModifierTypeInfo modifierType_Screw; diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_fluid.c index 34275d91ee6..b48c80d8e32 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_fluid.c @@ -30,7 +30,7 @@ #include "DNA_collection_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "DNA_smoke_types.h" +#include "DNA_fluid_types.h" #include "DNA_object_force_types.h" #include "DNA_mesh_types.h" @@ -38,7 +38,7 @@ #include "BKE_layer.h" #include "BKE_library_query.h" #include "BKE_modifier.h" -#include "BKE_smoke.h" +#include "BKE_fluid.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -49,45 +49,53 @@ static void initData(ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *)md; + FluidModifierData *mmd = (FluidModifierData *)md; - smd->domain = NULL; - smd->flow = NULL; - smd->coll = NULL; - smd->type = 0; - smd->time = -1; + mmd->domain = NULL; + mmd->flow = NULL; + mmd->effector = NULL; + mmd->type = 0; + mmd->time = -1; } static void copyData(const ModifierData *md, ModifierData *target, const int flag) { - const SmokeModifierData *smd = (const SmokeModifierData *)md; - SmokeModifierData *tsmd = (SmokeModifierData *)target; - - smokeModifier_free(tsmd); - smokeModifier_copy(smd, tsmd, flag); +#ifndef WITH_FLUID + UNUSED_VARS(md, target, flag); +#else + const FluidModifierData *mmd = (const FluidModifierData *)md; + FluidModifierData *tmmd = (FluidModifierData *)target; + + BKE_fluid_modifier_free(tmmd); + BKE_fluid_modifier_copy(mmd, tmmd, flag); +#endif /* WITH_FLUID */ } static void freeData(ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *)md; +#ifndef WITH_FLUID + UNUSED_VARS(md); +#else + FluidModifierData *mmd = (FluidModifierData *)md; - smokeModifier_free(smd); + BKE_fluid_modifier_free(mmd); +#endif /* WITH_FLUID */ } static void requiredDataMask(Object *UNUSED(ob), ModifierData *md, CustomData_MeshMasks *r_cddata_masks) { - SmokeModifierData *smd = (SmokeModifierData *)md; + FluidModifierData *mmd = (FluidModifierData *)md; - if (smd && (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) { - if (smd->flow->source == MOD_SMOKE_FLOW_SOURCE_MESH) { + if (mmd && (mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow) { + if (mmd->flow->source == FLUID_FLOW_SOURCE_MESH) { /* vertex groups */ - if (smd->flow->vgroup_density) { + if (mmd->flow->vgroup_density) { r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT; } /* uv layer */ - if (smd->flow->texture_type == MOD_SMOKE_FLOW_TEXTURE_MAP_UV) { + if (mmd->flow->texture_type == FLUID_FLOW_TEXTURE_MAP_UV) { r_cddata_masks->fmask |= CD_MASK_MTFACE; } } @@ -96,14 +104,22 @@ static void requiredDataMask(Object *UNUSED(ob), static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *me) { - SmokeModifierData *smd = (SmokeModifierData *)md; +#ifndef WITH_FLUID + UNUSED_VARS(md, ctx); + return me; +#else + FluidModifierData *mmd = (FluidModifierData *)md; + Mesh *result = NULL; if (ctx->flag & MOD_APPLY_ORCO) { return me; } Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); - return smokeModifier_do(smd, ctx->depsgraph, scene, ctx->object, me); + + result = BKE_fluid_modifier_do(mmd, ctx->depsgraph, scene, ctx->object, me); + return result ? result : me; +#endif /* WITH_FLUID */ } static bool dependsOnTime(ModifierData *UNUSED(md)) @@ -113,68 +129,78 @@ static bool dependsOnTime(ModifierData *UNUSED(md)) static bool is_flow_cb(Object *UNUSED(ob), ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *)md; - return (smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow; + FluidModifierData *mmd = (FluidModifierData *)md; + return (mmd->type & MOD_FLUID_TYPE_FLOW) && mmd->flow; } static bool is_coll_cb(Object *UNUSED(ob), ModifierData *md) { - SmokeModifierData *smd = (SmokeModifierData *)md; - return (smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll; + FluidModifierData *mmd = (FluidModifierData *)md; + return (mmd->type & MOD_FLUID_TYPE_EFFEC) && mmd->effector; } static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { - SmokeModifierData *smd = (SmokeModifierData *)md; + FluidModifierData *mmd = (FluidModifierData *)md; - if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { + if (mmd && (mmd->type & MOD_FLUID_TYPE_DOMAIN) && mmd->domain) { DEG_add_collision_relations(ctx->node, ctx->object, - smd->domain->fluid_group, - eModifierType_Smoke, + mmd->domain->fluid_group, + eModifierType_Fluid, is_flow_cb, - "Smoke Flow"); + "Fluid Flow"); DEG_add_collision_relations(ctx->node, ctx->object, - smd->domain->coll_group, - eModifierType_Smoke, + mmd->domain->effector_group, + eModifierType_Fluid, is_coll_cb, - "Smoke Coll"); + "Fluid Effector"); DEG_add_forcefield_relations(ctx->node, ctx->object, - smd->domain->effector_weights, + mmd->domain->effector_weights, true, PFIELD_SMOKEFLOW, - "Smoke Force Field"); + "Fluid Force Field"); + + if (mmd->domain->guide_parent != NULL) { + DEG_add_object_relation( + ctx->node, mmd->domain->guide_parent, DEG_OB_COMP_TRANSFORM, "Fluid Guiding Object"); + DEG_add_object_relation( + ctx->node, mmd->domain->guide_parent, DEG_OB_COMP_GEOMETRY, "Fluid Guiding Object"); + } } } static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData) { - SmokeModifierData *smd = (SmokeModifierData *)md; + FluidModifierData *mmd = (FluidModifierData *)md; + + if (mmd->type == MOD_FLUID_TYPE_DOMAIN && mmd->domain) { + walk(userData, ob, (ID **)&mmd->domain->effector_group, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&mmd->domain->fluid_group, IDWALK_CB_NOP); + walk(userData, ob, (ID **)&mmd->domain->force_group, IDWALK_CB_NOP); - if (smd->type == MOD_SMOKE_TYPE_DOMAIN && smd->domain) { - walk(userData, ob, (ID **)&smd->domain->coll_group, IDWALK_CB_NOP); - walk(userData, ob, (ID **)&smd->domain->fluid_group, IDWALK_CB_NOP); - walk(userData, ob, (ID **)&smd->domain->eff_group, IDWALK_CB_NOP); + if (mmd->domain->guide_parent) { + walk(userData, ob, (ID **)&mmd->domain->guide_parent, IDWALK_CB_NOP); + } - if (smd->domain->effector_weights) { - walk(userData, ob, (ID **)&smd->domain->effector_weights->group, IDWALK_CB_NOP); + if (mmd->domain->effector_weights) { + walk(userData, ob, (ID **)&mmd->domain->effector_weights->group, IDWALK_CB_NOP); } } - if (smd->type == MOD_SMOKE_TYPE_FLOW && smd->flow) { - walk(userData, ob, (ID **)&smd->flow->noise_texture, IDWALK_CB_USER); + if (mmd->type == MOD_FLUID_TYPE_FLOW && mmd->flow) { + walk(userData, ob, (ID **)&mmd->flow->noise_texture, IDWALK_CB_USER); } } -ModifierTypeInfo modifierType_Smoke = { - /* name */ "Smoke", - /* structName */ "SmokeModifierData", - /* structSize */ sizeof(SmokeModifierData), +ModifierTypeInfo modifierType_Fluid = { + /* name */ "Fluid", + /* structName */ "FluidModifierData", + /* structSize */ sizeof(FluidModifierData), /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_UsesPointCache | - eModifierTypeFlag_Single, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_Single, /* copyData */ copyData, diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c deleted file mode 100644 index 620b21f3e0c..00000000000 --- a/source/blender/modifiers/intern/MOD_fluidsim.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2005 by the Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup modifiers - */ - -#include "BLI_utildefines.h" - -#include "DNA_mesh_types.h" -#include "DNA_scene_types.h" -#include "DNA_object_fluidsim_types.h" -#include "DNA_object_types.h" - -#include "BKE_layer.h" -#include "BKE_modifier.h" - -#include "DEG_depsgraph_build.h" - -#include "MOD_fluidsim_util.h" -#include "MOD_modifiertypes.h" - -#include "MEM_guardedalloc.h" - -/* Fluidsim */ -static void initData(ModifierData *md) -{ - FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; - - fluidsim_init(fluidmd); -} -static void freeData(ModifierData *md) -{ - FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; - - fluidsim_free(fluidmd); -} - -static void copyData(const ModifierData *md, ModifierData *target, const int UNUSED(flag)) -{ - const FluidsimModifierData *fluidmd = (const FluidsimModifierData *)md; - FluidsimModifierData *tfluidmd = (FluidsimModifierData *)target; - - /* Free any FSS that was allocated in initData() */ - if (tfluidmd->fss) { - MEM_SAFE_FREE(tfluidmd->fss->meshVelocities); - MEM_freeN(tfluidmd->fss); - } - - if (fluidmd->fss == NULL) { - tfluidmd->fss = NULL; - return; - } - - tfluidmd->fss = MEM_dupallocN(fluidmd->fss); - if (tfluidmd->fss->meshVelocities != NULL) { - tfluidmd->fss->meshVelocities = MEM_dupallocN(tfluidmd->fss->meshVelocities); - } -} - -static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) -{ - FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; - Mesh *result = NULL; - - /* check for alloc failing */ - if (!fluidmd->fss) { - initData(md); - - if (!fluidmd->fss) { - return mesh; - } - } - - result = fluidsimModifier_do(fluidmd, ctx, mesh); - - return result ? result : mesh; -} - -static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) -{ - FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; - if (fluidmd && fluidmd->fss) { - if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) { - FOREACH_SCENE_OBJECT_BEGIN (ctx->scene, ob1) { - if (ob1 != ctx->object) { - FluidsimModifierData *fluidmdtmp = (FluidsimModifierData *)modifiers_findByType( - ob1, eModifierType_Fluidsim); - - /* Only put dependencies from NON-DOMAIN fluids in here. */ - if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) { - DEG_add_object_relation(ctx->node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object"); - } - } - } - FOREACH_SCENE_OBJECT_END; - } - } -} - -static bool dependsOnTime(ModifierData *UNUSED(md)) -{ - return true; -} - -ModifierTypeInfo modifierType_Fluidsim = { - /* name */ "Fluidsim", - /* structName */ "FluidsimModifierData", - /* structSize */ sizeof(FluidsimModifierData), - /* type */ eModifierTypeType_Nonconstructive, - - /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData | - eModifierTypeFlag_Single, - - /* copyData */ copyData, - - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, - /* applyModifier */ applyModifier, - - /* initData */ initData, - /* requiredDataMask */ NULL, - /* freeData */ freeData, - /* isDisabled */ NULL, - /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ dependsOnTime, - /* dependsOnNormals */ NULL, - /* foreachObjectLink */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, -}; diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c deleted file mode 100644 index 748bf4db4e2..00000000000 --- a/source/blender/modifiers/intern/MOD_fluidsim_util.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2005 by the Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup modifiers - */ - -#include <stddef.h> -#include <zlib.h> - -#include "BLI_utildefines.h" - -#ifdef WITH_MOD_FLUID -# include "BLI_blenlib.h" -# include "BLI_math.h" -#endif - -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_fluidsim_types.h" - -#include "BKE_fluidsim.h" /* ensure definitions here match */ -#include "BKE_mesh.h" -#ifdef WITH_MOD_FLUID -# include "BKE_global.h" -# include "BKE_library.h" -#endif - -#include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" - -#include "MOD_fluidsim_util.h" -#include "MOD_modifiertypes.h" - -#include "MEM_guardedalloc.h" - -// headers for fluidsim bobj meshes -#include "LBM_fluidsim.h" - -void fluidsim_init(FluidsimModifierData *fluidmd) -{ -#ifdef WITH_MOD_FLUID - if (fluidmd) { - FluidsimSettings *fss = MEM_callocN(sizeof(FluidsimSettings), "fluidsimsettings"); - - fluidmd->fss = fss; - - if (!fss) { - return; - } - - fss->fmd = fluidmd; - fss->type = OB_FLUIDSIM_ENABLE; - fss->threads = 0; - fss->show_advancedoptions = 0; - - fss->resolutionxyz = 65; - fss->previewresxyz = 45; - fss->realsize = 0.5; - fss->guiDisplayMode = OB_FSDOM_PREVIEW; - fss->renderDisplayMode = OB_FSDOM_FINAL; - - fss->viscosityValue = 1.0; - fss->viscosityExponent = 6; - - fss->grav[0] = 0.0; - fss->grav[1] = 0.0; - fss->grav[2] = -9.81; - - fss->animStart = 0.0; - fss->animEnd = 4.0; - fss->animRate = 1.0; - fss->gstar = 0.005; // used as normgstar - fss->maxRefine = -1; - /* maxRefine is set according to resolutionxyz during bake */ - - /* fluid/inflow settings - * fss->iniVel --> automatically set to 0 */ - - modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT); - - /* first init of bounding box */ - /* no bounding box needed */ - - /* todo - reuse default init from elbeem! */ - fss->typeFlags = OB_FSBND_PARTSLIP | OB_FSSG_NOOBS; - fss->domainNovecgen = 0; - fss->volumeInitType = 1; /* volume */ - fss->partSlipValue = 0.2; - - fss->generateTracers = 0; - fss->generateParticles = 0.0; - fss->surfaceSmoothing = 1.0; - fss->surfaceSubdivs = 0.0; - fss->particleInfSize = 0.0; - fss->particleInfAlpha = 0.0; - - /* init fluid control settings */ - fss->attractforceStrength = 0.2; - fss->attractforceRadius = 0.75; - fss->velocityforceStrength = 0.2; - fss->velocityforceRadius = 0.75; - fss->cpsTimeStart = fss->animStart; - fss->cpsTimeEnd = fss->animEnd; - fss->cpsQuality = 10.0; // 1.0 / 10.0 => means 0.1 width - - /* - * BAD TODO: this is done in buttons_object.c in the moment - * Mesh *mesh = ob->data; - * // calculate bounding box - * fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); - */ - - fss->meshVelocities = NULL; - - fss->lastgoodframe = -1; - - fss->flag |= OB_FLUIDSIM_ACTIVE; - } -#else - (void)fluidmd; /* unused */ -#endif - return; -} - -void fluidsim_free(FluidsimModifierData *fluidmd) -{ - if (fluidmd && fluidmd->fss) { - if (fluidmd->fss->meshVelocities) { - MEM_freeN(fluidmd->fss->meshVelocities); - } - MEM_SAFE_FREE(fluidmd->fss); - } - - return; -} - -#ifdef WITH_MOD_FLUID -/* read .bobj.gz file into a fluidsimMesh struct */ -static Mesh *fluidsim_read_obj(const char *filename, const MPoly *mp_example) -{ - int wri = 0, i; - int gotBytes; - gzFile gzf; - int numverts = 0, numfaces = 0; - Mesh *mesh = NULL; - MPoly *mp; - MLoop *ml; - MVert *mv; - short *normals, *no_s; - float no[3]; - - const short mp_mat_nr = mp_example->mat_nr; - const char mp_flag = mp_example->flag; - - /* ------------------------------------------------ - * get numverts + numfaces first - * ------------------------------------------------ */ - gzf = BLI_gzopen(filename, "rb"); - if (!gzf) { - return NULL; - } - - /* read numverts */ - gotBytes = gzread(gzf, &wri, sizeof(wri)); - numverts = wri; - - /* skip verts */ - gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; - - /* read number of normals */ - if (gotBytes) { - gotBytes = gzread(gzf, &wri, sizeof(wri)); - } - - /* skip normals */ - gotBytes = gzseek(gzf, numverts * 3 * sizeof(float), SEEK_CUR) != -1; - - /* get no. of triangles */ - if (gotBytes) { - gotBytes = gzread(gzf, &wri, sizeof(wri)); - } - numfaces = wri; - - gzclose(gzf); - /* ------------------------------------------------ */ - - if (!numfaces || !numverts || !gotBytes) { - return NULL; - } - - gzf = BLI_gzopen(filename, "rb"); - if (!gzf) { - return NULL; - } - - mesh = BKE_mesh_new_nomain(numverts, 0, 0, numfaces * 3, numfaces); - - if (!mesh) { - gzclose(gzf); - return NULL; - } - - /* read numverts */ - gotBytes = gzread(gzf, &wri, sizeof(wri)); - - /* read vertex position from file */ - mv = mesh->mvert; - - for (i = 0; i < numverts; i++, mv++) { - gotBytes = gzread(gzf, mv->co, sizeof(float) * 3); - } - - /* should be the same as numverts */ - gotBytes = gzread(gzf, &wri, sizeof(wri)); - if (wri != numverts) { - if (mesh) { - BKE_id_free(NULL, mesh); - } - gzclose(gzf); - return NULL; - } - - normals = MEM_calloc_arrayN(numverts, 3 * sizeof(short), "fluid_tmp_normals"); - if (!normals) { - if (mesh) { - BKE_id_free(NULL, mesh); - } - gzclose(gzf); - return NULL; - } - - /* read normals from file (but don't save them yet) */ - for (i = numverts, no_s = normals; i > 0; i--, no_s += 3) { - gotBytes = gzread(gzf, no, sizeof(float) * 3); - normal_float_to_short_v3(no_s, no); - } - - /* read no. of triangles */ - gotBytes = gzread(gzf, &wri, sizeof(wri)); - - if (wri != numfaces) { - printf("Fluidsim: error in reading data from file.\n"); - if (mesh) { - BKE_id_free(NULL, mesh); - } - gzclose(gzf); - MEM_freeN(normals); - return NULL; - } - - /* read triangles from file */ - mp = mesh->mpoly; - ml = mesh->mloop; - for (i = 0; i < numfaces; i++, mp++, ml += 3) { - int face[3]; - - gotBytes = gzread(gzf, face, sizeof(int) * 3); - - /* initialize from existing face */ - mp->mat_nr = mp_mat_nr; - mp->flag = mp_flag; - - mp->loopstart = i * 3; - mp->totloop = 3; - - ml[0].v = face[0]; - ml[1].v = face[1]; - ml[2].v = face[2]; - } - - gzclose(gzf); - - BKE_mesh_calc_edges(mesh, false, false); - BKE_mesh_vert_normals_apply(mesh, (short(*)[3])normals); - MEM_freeN(normals); - - // CDDM_calc_normals(result); - return mesh; -} - -void fluid_get_bb(MVert *mvert, - int totvert, - float obmat[4][4], - /*RET*/ float start[3], - /*RET*/ float size[3]) -{ - float bbsx = 0.0, bbsy = 0.0, bbsz = 0.0; - float bbex = 1.0, bbey = 1.0, bbez = 1.0; - int i; - float vec[3]; - - if (totvert == 0) { - zero_v3(start); - zero_v3(size); - return; - } - - copy_v3_v3(vec, mvert[0].co); - mul_m4_v3(obmat, vec); - bbsx = vec[0]; - bbsy = vec[1]; - bbsz = vec[2]; - bbex = vec[0]; - bbey = vec[1]; - bbez = vec[2]; - - for (i = 1; i < totvert; i++) { - copy_v3_v3(vec, mvert[i].co); - mul_m4_v3(obmat, vec); - - if (vec[0] < bbsx) { - bbsx = vec[0]; - } - if (vec[1] < bbsy) { - bbsy = vec[1]; - } - if (vec[2] < bbsz) { - bbsz = vec[2]; - } - if (vec[0] > bbex) { - bbex = vec[0]; - } - if (vec[1] > bbey) { - bbey = vec[1]; - } - if (vec[2] > bbez) { - bbez = vec[2]; - } - } - - /* return values... */ - if (start) { - start[0] = bbsx; - start[1] = bbsy; - start[2] = bbsz; - } - if (size) { - size[0] = bbex - bbsx; - size[1] = bbey - bbsy; - size[2] = bbez - bbsz; - } -} - -//------------------------------------------------------------------------------- -// old interface -//------------------------------------------------------------------------------- - -void fluid_estimate_memory(Object *ob, FluidsimSettings *fss, char *value) -{ - Mesh *mesh; - - value[0] = '\0'; - - if (ob->type == OB_MESH) { - /* use mesh bounding box and object scaling */ - mesh = ob->data; - - fluid_get_bb(mesh->mvert, mesh->totvert, ob->obmat, fss->bbStart, fss->bbSize); - elbeemEstimateMemreq( - fss->resolutionxyz, fss->bbSize[0], fss->bbSize[1], fss->bbSize[2], fss->maxRefine, value); - } -} - -/* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */ -static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, Mesh *mesh, char *filename) -{ - int wri, i, j; - float wrf; - gzFile gzf; - FluidsimSettings *fss = fluidmd->fss; - int len = strlen(filename); - int totvert = mesh->totvert; - FluidVertexVelocity *velarray = NULL; - - /* mesh and vverts have to be valid from loading... */ - - if (fss->meshVelocities) { - MEM_freeN(fss->meshVelocities); - } - - if (len < 7) { - return; - } - - if (fss->domainNovecgen > 0) { - return; - } - - fss->meshVelocities = MEM_calloc_arrayN( - mesh->totvert, sizeof(FluidVertexVelocity), "Fluidsim_velocities"); - fss->totvert = totvert; - - velarray = fss->meshVelocities; - - /* .bobj.gz, correct filename - * 87654321 */ - filename[len - 6] = 'v'; - filename[len - 5] = 'e'; - filename[len - 4] = 'l'; - - gzf = BLI_gzopen(filename, "rb"); - if (!gzf) { - MEM_freeN(fss->meshVelocities); - fss->meshVelocities = NULL; - return; - } - - gzread(gzf, &wri, sizeof(wri)); - if (wri != totvert) { - MEM_freeN(fss->meshVelocities); - fss->meshVelocities = NULL; - return; - } - - for (i = 0; i < totvert; i++) { - for (j = 0; j < 3; j++) { - gzread(gzf, &wrf, sizeof(wrf)); - velarray[i].vel[j] = wrf; - } - } - - gzclose(gzf); -} - -static Mesh *fluidsim_read_cache( - Object *ob, Mesh *orgmesh, FluidsimModifierData *fluidmd, int framenr, int useRenderParams) -{ - int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */ - /* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway. - * (See physics_fluid.c for that. - DG) */ - /* If we start with frame 0, we need to remap all animation channels, too, - * because they will all be 1 frame late if using frame-1! - DG */ - - char targetFile[FILE_MAX]; - FluidsimSettings *fss = fluidmd->fss; - Mesh *newmesh = NULL; - MPoly *mpoly; - MPoly mp_example = {0}; - - const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode; - - switch (displaymode) { - case OB_FSDOM_GEOM: - /* just display original object */ - return NULL; - case OB_FSDOM_PREVIEW: - /* use preview mesh */ - BLI_join_dirfile( - targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME); - break; - case OB_FSDOM_FINAL: - /* use final mesh */ - BLI_join_dirfile( - targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); - break; - default: - BLI_assert(!"Wrong fluidsim display type"); - return NULL; - } - - /* offset baked frame */ - curFrame += fss->frameOffset; - - BLI_path_abs(targetFile, modifier_path_relbase_from_global(ob)); - BLI_path_frame(targetFile, curFrame, 0); // fixed #frame-no - - /* assign material + flags to new mesh. - * if there's no faces in original mesh, keep materials and flags unchanged */ - mpoly = orgmesh->mpoly; - if (mpoly) { - mp_example = *mpoly; - } - /* else leave NULL'd */ - - newmesh = fluidsim_read_obj(targetFile, &mp_example); - - if (!newmesh) { - /* switch, abort background rendering when fluidsim mesh is missing */ - const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp - - if (G.background == 1) { - if (BLI_getenv(strEnvName2)) { - int elevel = atoi(BLI_getenv(strEnvName2)); - if (elevel > 0) { - printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n", - strEnvName2, - targetFile); - exit(1); - } - } - } - - /* display org. object upon failure which is in new mesh */ - return NULL; - } - - BKE_mesh_copy_settings(newmesh, orgmesh); - - /* Fluid simulation has a texture space that based on the bounds of the fluid mesh. - * This does not seem particularly useful, but it's backwards compatible. */ - BKE_mesh_texspace_calc(newmesh); - - /* load vertex velocities, if they exist... - * TODO? use generate flag as loading flag as well? - * warning, needs original .bobj.gz mesh loading filename */ - if (displaymode == OB_FSDOM_FINAL) { - fluidsim_read_vel_cache(fluidmd, newmesh, targetFile); - } - else { - if (fss->meshVelocities) { - MEM_freeN(fss->meshVelocities); - } - - fss->meshVelocities = NULL; - } - - return newmesh; -} -#endif // WITH_MOD_FLUID - -Mesh *fluidsimModifier_do(FluidsimModifierData *fluidmd, - const ModifierEvalContext *ctx, - Mesh *mesh) -{ -#ifdef WITH_MOD_FLUID - Object *ob = ctx->object; - Depsgraph *depsgraph = ctx->depsgraph; - const bool useRenderParams = (ctx->flag & MOD_APPLY_RENDER) != 0; - // const bool isFinalCalc = (ctx->flag & MOD_APPLY_USECACHE) != 0; - Mesh *result = NULL; - int framenr; - FluidsimSettings *fss = NULL; - - framenr = (int)DEG_get_ctime(depsgraph); - - /* only handle fluidsim domains */ - if (fluidmd && fluidmd->fss && (fluidmd->fss->type != OB_FLUIDSIM_DOMAIN)) { - return mesh; - } - - /* sanity check */ - if (!fluidmd || !fluidmd->fss) { - return mesh; - } - - fss = fluidmd->fss; - - /* timescale not supported yet - * clmd->sim_parms->timescale = timescale; */ - - /* support reversing of baked fluid frames here */ - if ((fss->flag & OB_FLUIDSIM_REVERSE) && (fss->lastgoodframe >= 0)) { - framenr = fss->lastgoodframe - framenr + 1; - CLAMP(framenr, 1, fss->lastgoodframe); - } - - /* try to read from cache */ - /* if the frame is there, fine, otherwise don't do anything */ - if ((result = fluidsim_read_cache(ob, mesh, fluidmd, framenr, useRenderParams))) { - return result; - } - - return mesh; -#else - /* unused */ - UNUSED_VARS(fluidmd, ctx, mesh); - return NULL; -#endif -} diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.h b/source/blender/modifiers/intern/MOD_fluidsim_util.h deleted file mode 100644 index da70568353e..00000000000 --- a/source/blender/modifiers/intern/MOD_fluidsim_util.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) Blender Foundation - * All rights reserved. - */ - -/** \file - * \ingroup modifiers - */ - -#ifndef __MOD_FLUIDSIM_UTIL_H__ -#define __MOD_FLUIDSIM_UTIL_H__ - -struct FluidsimModifierData; -struct Mesh; -struct ModifierEvalContext; - -/* new fluid-modifier interface */ -void fluidsim_init(struct FluidsimModifierData *fluidmd); -void fluidsim_free(struct FluidsimModifierData *fluidmd); - -struct Mesh *fluidsimModifier_do(struct FluidsimModifierData *fluidmd, - const struct ModifierEvalContext *ctx, - struct Mesh *me); - -#endif diff --git a/source/blender/modifiers/intern/MOD_solidify_util.h b/source/blender/modifiers/intern/MOD_solidify_util.h index dba360dc1ce..3a9608861dc 100644 --- a/source/blender/modifiers/intern/MOD_solidify_util.h +++ b/source/blender/modifiers/intern/MOD_solidify_util.h @@ -18,8 +18,8 @@ * \ingroup modifiers */ -#ifndef __MOD_MESHCACHE_UTIL_H__ -#define __MOD_MESHCACHE_UTIL_H__ +#ifndef __MOD_SOLIDIFY_UTIL_H__ +#define __MOD_SOLIDIFY_UTIL_H__ /* MOD_solidify_extrude.c */ Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md, @@ -31,4 +31,4 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh); -#endif /* __MOD_MESHCACHE_UTIL_H__ */ +#endif /* __MOD_SOLIDIFY_UTIL_H__ */ diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 45ec79d7801..f97fbc224cd 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -279,12 +279,11 @@ void modifier_type_init(ModifierTypeInfo *types[]) INIT_TYPE(ParticleInstance); INIT_TYPE(Explode); INIT_TYPE(Shrinkwrap); - INIT_TYPE(Fluidsim); INIT_TYPE(Mask); INIT_TYPE(SimpleDeform); INIT_TYPE(Multires); INIT_TYPE(Surface); - INIT_TYPE(Smoke); + INIT_TYPE(Fluid); INIT_TYPE(ShapeKey); INIT_TYPE(Solidify); INIT_TYPE(Screw); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index fb2cb11d269..2eb2a6b380a 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -173,11 +173,11 @@ set(SRC shader/nodes/node_shader_normal.c shader/nodes/node_shader_normal_map.c shader/nodes/node_shader_object_info.c + shader/nodes/node_shader_output_aov.c shader/nodes/node_shader_output_light.c shader/nodes/node_shader_output_linestyle.c shader/nodes/node_shader_output_material.c shader/nodes/node_shader_output_world.c - shader/nodes/node_shader_output_aov.c shader/nodes/node_shader_particle_info.c shader/nodes/node_shader_rgb.c shader/nodes/node_shader_script.c diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.c b/source/blender/nodes/composite/nodes/node_composite_denoise.c index ac30ed9576d..06c862fc3ab 100644 --- a/source/blender/nodes/composite/nodes/node_composite_denoise.c +++ b/source/blender/nodes/composite/nodes/node_composite_denoise.c @@ -1,6 +1,4 @@ /* - * ***** BEGIN GPL LICENSE BLOCK ***** - * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -19,13 +17,9 @@ * All rights reserved. * * The Original Code is: all of this file. - * - * Contributor(s): Stefan Werner - * - * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/nodes/composite/nodes/node_composite_denoise.c +/** \file * \ingroup cmpnodes */ diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index d5f0e2fb863..012492fe9a7 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -33,6 +33,7 @@ set(INC ../../windowmanager ../../../../intern/clog ../../../../intern/guardedalloc + ../../../../intern/mantaflow/extern ../../../../intern/opencolorio ) @@ -257,10 +258,6 @@ if(WITH_LIBMV) add_definitions(-DWITH_LIBMV) endif() -if(WITH_MOD_FLUID) - add_definitions(-DWITH_MOD_FLUID) -endif() - if(WITH_MOD_OCEANSIM) add_definitions(-DWITH_OCEANSIM) endif() @@ -269,8 +266,8 @@ if(WITH_MOD_REMESH) add_definitions(-DWITH_MOD_REMESH) endif() -if(WITH_MOD_SMOKE) - add_definitions(-DWITH_SMOKE) +if(WITH_MOD_FLUID) + add_definitions(-DWITH_FLUID) endif() if(WITH_OPENCOLLADA) diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index ee6a3fd41d8..7d2645e7776 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -51,16 +51,15 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"sdl_dynload", NULL}, {(char *)"jack", NULL}, {(char *)"libmv", NULL}, - {(char *)"mod_fluid", NULL}, {(char *)"mod_oceansim", NULL}, {(char *)"mod_remesh", NULL}, - {(char *)"mod_smoke", NULL}, {(char *)"collada", NULL}, {(char *)"opencolorio", NULL}, {(char *)"openmp", NULL}, {(char *)"openvdb", NULL}, {(char *)"alembic", NULL}, {(char *)"usd", NULL}, + {(char *)"fluid", NULL}, {NULL}, }; @@ -222,12 +221,6 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif -#ifdef WITH_MOD_FLUID - SetObjIncref(Py_True); -#else - SetObjIncref(Py_False); -#endif - #ifdef WITH_OCEANSIM SetObjIncref(Py_True); #else @@ -240,12 +233,6 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif -#ifdef WITH_SMOKE - SetObjIncref(Py_True); -#else - SetObjIncref(Py_False); -#endif - #ifdef WITH_COLLADA SetObjIncref(Py_True); #else @@ -282,6 +269,12 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif +#ifdef WITH_FLUID + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + #undef SetObjIncref return builtopts_info; diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 2b9556e998a..9acf05abfe2 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -197,8 +197,15 @@ void BPY_context_set(bContext *C) BPy_SetContext(C); } +#ifdef WITH_FLUID +/* defined in manta module */ +extern PyObject *Manta_initPython(void); +#endif + +#ifdef WITH_AUDASPACE /* defined in AUD_C-API.cpp */ extern PyObject *AUD_initPython(void); +#endif #ifdef WITH_CYCLES /* defined in cycles module */ @@ -225,6 +232,9 @@ static struct _inittab bpy_internal_modules[] = { {"bmesh.utils", BPyInit_bmesh_utils}, {"bmesh.utils", BPyInit_bmesh_geometry}, #endif +#ifdef WITH_FLUID + {"manta", Manta_initPython}, +#endif #ifdef WITH_AUDASPACE {"aud", AUD_initPython}, #endif @@ -285,6 +295,13 @@ void BPY_python_start(int argc, const char **argv) /* Initialize thread support (also acquires lock) */ PyEval_InitThreads(); + +# ifdef WITH_FLUID + /* Required to prevent assertion error, see: + * https://stackoverflow.com/questions/27844676 */ + Py_DECREF(PyImport_ImportModule("threading")); +# endif + #else (void)argc; (void)argv; diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index e265197646c..a92be8509d5 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -36,7 +36,7 @@ set(INC ../../../intern/atomic ../../../intern/guardedalloc ../../../intern/mikktspace - ../../../intern/smoke/extern + ../../../intern/mantaflow/extern ) set(INC_SYS @@ -86,8 +86,8 @@ if(WITH_IMAGE_OPENEXR) add_definitions(-DWITH_OPENEXR) endif() -if(WITH_MOD_SMOKE) - add_definitions(-DWITH_SMOKE) +if(WITH_MOD_FLUID) + add_definitions(-DWITH_FLUID) endif() if(WITH_FREESTYLE) diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt index 57c7345076e..6d918763996 100644 --- a/source/blender/shader_fx/CMakeLists.txt +++ b/source/blender/shader_fx/CMakeLists.txt @@ -30,7 +30,6 @@ set(INC ../makesdna ../makesrna ../render/extern/include - ../../../intern/elbeem/extern ../../../intern/eigen ../../../intern/guardedalloc ) diff --git a/source/blender/usd/intern/abstract_hierarchy_iterator.h b/source/blender/usd/intern/abstract_hierarchy_iterator.h index db1e4248cab..ea31e94cf9b 100644 --- a/source/blender/usd/intern/abstract_hierarchy_iterator.h +++ b/source/blender/usd/intern/abstract_hierarchy_iterator.h @@ -33,8 +33,8 @@ * Selections like "selected only" or "no hair systems" are left to concrete subclasses. */ -#ifndef __USD__ABSTRACT_HIERARCHY_ITERATOR_H__ -#define __USD__ABSTRACT_HIERARCHY_ITERATOR_H__ +#ifndef __ABSTRACT_HIERARCHY_ITERATOR_H__ +#define __ABSTRACT_HIERARCHY_ITERATOR_H__ #include <map> #include <string> @@ -245,4 +245,4 @@ class AbstractHierarchyIterator { } // namespace USD -#endif /* __USD__ABSTRACT_HIERARCHY_ITERATOR_H__ */ +#endif /* __ABSTRACT_HIERARCHY_ITERATOR_H__ */ diff --git a/source/blender/usd/intern/usd_exporter_context.h b/source/blender/usd/intern/usd_exporter_context.h index aaa0121807c..35ff13b2e91 100644 --- a/source/blender/usd/intern/usd_exporter_context.h +++ b/source/blender/usd/intern/usd_exporter_context.h @@ -16,8 +16,8 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#ifndef __USD__USD_EXPORTER_CONTEXT_H__ -#define __USD__USD_EXPORTER_CONTEXT_H__ +#ifndef __USD_EXPORTER_CONTEXT_H__ +#define __USD_EXPORTER_CONTEXT_H__ #include "usd.h" @@ -41,4 +41,4 @@ struct USDExporterContext { } // namespace USD -#endif /* __USD__USD_EXPORTER_CONTEXT_H__ */ +#endif /* __USD_EXPORTER_CONTEXT_H__ */ diff --git a/source/blender/usd/intern/usd_hierarchy_iterator.h b/source/blender/usd/intern/usd_hierarchy_iterator.h index a937df8f15b..90c82c6e551 100644 --- a/source/blender/usd/intern/usd_hierarchy_iterator.h +++ b/source/blender/usd/intern/usd_hierarchy_iterator.h @@ -16,8 +16,8 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#ifndef __USD__USD_HIERARCHY_ITERATOR_H__ -#define __USD__USD_HIERARCHY_ITERATOR_H__ +#ifndef __USD_HIERARCHY_ITERATOR_H__ +#define __USD_HIERARCHY_ITERATOR_H__ #include "abstract_hierarchy_iterator.h" #include "usd_exporter_context.h" @@ -68,4 +68,4 @@ class USDHierarchyIterator : public AbstractHierarchyIterator { } // namespace USD -#endif /* __USD__USD_HIERARCHY_ITERATOR_H__ */ +#endif /* __USD_HIERARCHY_ITERATOR_H__ */ diff --git a/source/blender/usd/intern/usd_writer_abstract.h b/source/blender/usd/intern/usd_writer_abstract.h index cea4685c806..8f727638704 100644 --- a/source/blender/usd/intern/usd_writer_abstract.h +++ b/source/blender/usd/intern/usd_writer_abstract.h @@ -16,8 +16,8 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#ifndef __USD__USD_WRITER_ABSTRACT_H__ -#define __USD__USD_WRITER_ABSTRACT_H__ +#ifndef __USD_WRITER_ABSTRACT_H__ +#define __USD_WRITER_ABSTRACT_H__ #include "usd_exporter_context.h" #include "abstract_hierarchy_iterator.h" @@ -75,4 +75,4 @@ class USDAbstractWriter : public AbstractHierarchyWriter { } // namespace USD -#endif /* __USD__USD_WRITER_ABSTRACT_H__ */ +#endif /* __USD_WRITER_ABSTRACT_H__ */ diff --git a/source/blender/usd/intern/usd_writer_camera.h b/source/blender/usd/intern/usd_writer_camera.h index 86b5ed464b0..971264ef11e 100644 --- a/source/blender/usd/intern/usd_writer_camera.h +++ b/source/blender/usd/intern/usd_writer_camera.h @@ -16,8 +16,8 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#ifndef __USD__USD_WRITER_CAMERA_H__ -#define __USD__USD_WRITER_CAMERA_H__ +#ifndef __USD_WRITER_CAMERA_H__ +#define __USD_WRITER_CAMERA_H__ #include "usd_writer_abstract.h" @@ -35,4 +35,4 @@ class USDCameraWriter : public USDAbstractWriter { } // namespace USD -#endif /* __USD__USD_WRITER_CAMERA_H__ */ +#endif /* __USD_WRITER_CAMERA_H__ */ diff --git a/source/blender/usd/intern/usd_writer_hair.h b/source/blender/usd/intern/usd_writer_hair.h index ccb5af76099..1e882fa1654 100644 --- a/source/blender/usd/intern/usd_writer_hair.h +++ b/source/blender/usd/intern/usd_writer_hair.h @@ -16,8 +16,8 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#ifndef __USD__USD_WRITER_HAIR_H__ -#define __USD__USD_WRITER_HAIR_H__ +#ifndef __USD_WRITER_HAIR_H__ +#define __USD_WRITER_HAIR_H__ #include "usd_writer_abstract.h" @@ -35,4 +35,4 @@ class USDHairWriter : public USDAbstractWriter { } // namespace USD -#endif /* __USD__USD_WRITER_HAIR_H__ */ +#endif /* __USD_WRITER_HAIR_H__ */ diff --git a/source/blender/usd/intern/usd_writer_light.h b/source/blender/usd/intern/usd_writer_light.h index 3813412c330..349c034b6bc 100644 --- a/source/blender/usd/intern/usd_writer_light.h +++ b/source/blender/usd/intern/usd_writer_light.h @@ -16,8 +16,8 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#ifndef __USD__USD_WRITER_LIGHT_H__ -#define __USD__USD_WRITER_LIGHT_H__ +#ifndef __USD_WRITER_LIGHT_H__ +#define __USD_WRITER_LIGHT_H__ #include "usd_writer_abstract.h" @@ -34,4 +34,4 @@ class USDLightWriter : public USDAbstractWriter { } // namespace USD -#endif /* __USD__USD_WRITER_LIGHT_H__ */ +#endif /* __USD_WRITER_LIGHT_H__ */ diff --git a/source/blender/usd/intern/usd_writer_mesh.h b/source/blender/usd/intern/usd_writer_mesh.h index 0f03c8d20ae..56738e9747d 100644 --- a/source/blender/usd/intern/usd_writer_mesh.h +++ b/source/blender/usd/intern/usd_writer_mesh.h @@ -16,8 +16,8 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#ifndef __USD__USD_WRITER_MESH_H__ -#define __USD__USD_WRITER_MESH_H__ +#ifndef __USD_WRITER_MESH_H__ +#define __USD_WRITER_MESH_H__ #include "usd_writer_abstract.h" @@ -63,4 +63,4 @@ class USDMeshWriter : public USDGenericMeshWriter { } // namespace USD -#endif /* __USD__USD_WRITER_MESH_H__ */ +#endif /* __USD_WRITER_MESH_H__ */ diff --git a/source/blender/usd/intern/usd_writer_transform.h b/source/blender/usd/intern/usd_writer_transform.h index fb591998e6a..52c4a657f33 100644 --- a/source/blender/usd/intern/usd_writer_transform.h +++ b/source/blender/usd/intern/usd_writer_transform.h @@ -16,8 +16,8 @@ * The Original Code is Copyright (C) 2019 Blender Foundation. * All rights reserved. */ -#ifndef __USD__USD_WRITER_TRANSFORM_H__ -#define __USD__USD_WRITER_TRANSFORM_H__ +#ifndef __USD_WRITER_TRANSFORM_H__ +#define __USD_WRITER_TRANSFORM_H__ #include "usd_writer_abstract.h" @@ -39,4 +39,4 @@ class USDTransformWriter : public USDAbstractWriter { } // namespace USD -#endif /* __USD__USD_WRITER_TRANSFORM_H__ */ +#endif /* __USD_WRITER_TRANSFORM_H__ */ diff --git a/source/blender/usd/usd.h b/source/blender/usd/usd.h index 412a51b8061..1a6f5819e21 100644 --- a/source/blender/usd/usd.h +++ b/source/blender/usd/usd.h @@ -17,8 +17,8 @@ * All rights reserved. */ -#ifndef __BLENDER_USD_H__ -#define __BLENDER_USD_H__ +#ifndef __USD_H__ +#define __USD_H__ #ifdef __cplusplus extern "C" { @@ -59,4 +59,4 @@ bool USD_export(struct bContext *C, } #endif -#endif /* __BLENDER_USD_H__ */ +#endif /* __USD_H__ */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 01f80ab9297..4117c036dcb 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2265,9 +2265,18 @@ static int wm_handler_operator_call(bContext *C, bool use_last_properties = true; PointerRNA tool_properties = {0}; - bToolRef *keymap_tool = ((handler_base->type == WM_HANDLER_TYPE_KEYMAP) ? - ((wmEventHandler_Keymap *)handler_base)->keymap_tool : - NULL); + bToolRef *keymap_tool = NULL; + if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) { + keymap_tool = ((wmEventHandler_Keymap *)handler_base)->keymap_tool; + } + else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) { + wmGizmoMap *gizmo_map = ((wmEventHandler_Gizmo *)handler_base)->gizmo_map; + wmGizmo *gz = wm_gizmomap_highlight_get(gizmo_map); + if (gz && (gz->flag & WM_GIZMO_OPERATOR_TOOL_INIT)) { + keymap_tool = WM_toolsystem_ref_from_context(C); + } + } + const bool is_tool = (keymap_tool != NULL); const bool use_tool_properties = is_tool; diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index a116cfcef19..e19bc01d005 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1050,7 +1050,7 @@ setup_liblinks(blender) # USD registry. # USD requires a set of JSON files that define the standard schemas. These # files are required at runtime. -if (WITH_USD) +if(WITH_USD) add_definitions(-DWITH_USD) install(DIRECTORY ${LIBDIR}/usd/lib/usd diff --git a/source/creator/creator.c b/source/creator/creator.c index 4cf0d6d40f2..5c6c1570152 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -115,13 +115,14 @@ void main_python_exit(void); #endif #ifdef WITH_USD -/* Workaround to make it possible to pass a path at runtime to USD. +/** + * Workaround to make it possible to pass a path at runtime to USD. * * USD requires some JSON files, and it uses a static constructor to determine the possible - * filesystem paths to find those files. This made it impossible for Blender to pass a path to the + * file-system paths to find those files. This made it impossible for Blender to pass a path to the * USD library at runtime, as the constructor would run before Blender's main() function. We have * patched USD (see usd.diff) to avoid that particular static constructor, and have an - * initialisation function instead. + * initialization function instead. * * This function is implemented in the USD source code, pxr/base/lib/plug/initConfig.cpp. */ |