diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_pointcache.h | 5 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_simulation.h | 15 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcache.c | 87 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/simulation.cc | 277 | ||||
-rw-r--r-- | source/blender/blenloader/intern/readfile.c | 12 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 48 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_simulation_types.h | 23 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_simulation.cc | 16 | ||||
-rw-r--r-- | source/blender/simulation/intern/simulation_collect_influences.cc | 51 | ||||
-rw-r--r-- | source/blender/simulation/intern/simulation_collect_influences.hh | 35 | ||||
-rw-r--r-- | source/blender/simulation/intern/simulation_solver.cc | 15 | ||||
-rw-r--r-- | source/blender/simulation/intern/simulation_solver.hh | 57 | ||||
-rw-r--r-- | source/blender/simulation/intern/simulation_update.cc | 85 |
13 files changed, 426 insertions, 300 deletions
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index a9abe2d0f6d..dc99ec7f56f 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -86,12 +86,10 @@ struct ListBase; struct Main; struct Object; struct ParticleKey; -struct ParticleSimulationState; struct ParticleSystem; struct PointCache; struct RigidBodyWorld; struct Scene; -struct Simulation; struct SoftBody; struct ViewLayer; @@ -296,9 +294,6 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface); void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw); -void BKE_ptcache_id_from_sim_particles(PTCacheID *pid, - struct ParticleSimulationState *state_orig, - struct ParticleSimulationState *state_cow); PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache); void BKE_ptcache_ids_from_object(struct ListBase *lb, diff --git a/source/blender/blenkernel/BKE_simulation.h b/source/blender/blenkernel/BKE_simulation.h index 36f4122f4dc..5aa71b6381d 100644 --- a/source/blender/blenkernel/BKE_simulation.h +++ b/source/blender/blenkernel/BKE_simulation.h @@ -34,13 +34,26 @@ void BKE_simulation_data_update(struct Depsgraph *depsgraph, struct Simulation *simulation); SimulationState *BKE_simulation_state_add(Simulation *simulation, - eSimulationStateType type, + const char *type, const char *name); void BKE_simulation_state_remove(Simulation *simulation, SimulationState *state); void BKE_simulation_state_remove_all(Simulation *simulation); +void BKE_simulation_state_reset(Simulation *simulation, SimulationState *state); +void BKE_simulation_state_reset_all(Simulation *simulation); +SimulationState *BKE_simulation_state_try_find_by_name(Simulation *simulation, const char *name); +SimulationState *BKE_simulation_state_try_find_by_name_and_type(Simulation *simulation, + const char *name, + const char *type); +void BKE_simulation_state_copy_data(const SimulationState *src_state, SimulationState *dst_state); #ifdef __cplusplus } #endif +#ifdef __cplusplus + +template<typename StateType> const char *BKE_simulation_get_state_type_name(); + +#endif + #endif /* __BKE_SIMULATION_H__ */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index aa93c6cb854..4b09f7542c7 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1885,81 +1885,6 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r pid->file_type = PTCACHE_FILE_PTCACHE; } -static int ptcache_sim_particle_totpoint(void *state_v, int UNUSED(cfra)) -{ - ParticleSimulationState *state = (ParticleSimulationState *)state_v; - return state->tot_particles; -} - -static void ptcache_sim_particle_error(void *UNUSED(state_v), const char *UNUSED(message)) -{ -} - -static int ptcache_sim_particle_write(int index, void *state_v, void **data, int UNUSED(cfra)) -{ - ParticleSimulationState *state = (ParticleSimulationState *)state_v; - - const float *positions = (const float *)CustomData_get_layer_named( - &state->attributes, CD_PROP_FLOAT3, "Position"); - - PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, positions + (index * 3)); - - return 1; -} -static void ptcache_sim_particle_read( - int index, void *state_v, void **data, float UNUSED(cfra), const float *UNUSED(old_data)) -{ - ParticleSimulationState *state = (ParticleSimulationState *)state_v; - - BLI_assert(index < state->tot_particles); - float *positions = (float *)CustomData_get_layer_named( - &state->attributes, CD_PROP_FLOAT3, "Position"); - - PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, positions + (index * 3)); -} - -void BKE_ptcache_id_from_sim_particles(PTCacheID *pid, - ParticleSimulationState *state_orig, - ParticleSimulationState *state_cow) -{ - memset(pid, 0, sizeof(PTCacheID)); - - pid->calldata = state_cow; - pid->type = PTCACHE_TYPE_SIM_PARTICLES; - pid->cache = state_orig->point_cache; - pid->cache_ptr = &state_orig->point_cache; - pid->ptcaches = &state_orig->ptcaches; - pid->totpoint = ptcache_sim_particle_totpoint; - pid->totwrite = ptcache_sim_particle_totpoint; - pid->error = ptcache_sim_particle_error; - - pid->write_point = ptcache_sim_particle_write; - pid->read_point = ptcache_sim_particle_read; - pid->interpolate_point = NULL; - - pid->write_stream = NULL; - pid->read_stream = NULL; - - pid->write_openvdb_stream = NULL; - pid->read_openvdb_stream = NULL; - - pid->write_extra_data = NULL; - pid->read_extra_data = NULL; - pid->interpolate_extra_data = NULL; - - pid->write_header = NULL; - pid->read_header = NULL; - - pid->data_types = 1 << BPHYS_DATA_LOCATION; - pid->info_types = 0; - - pid->stack_index = 0; - - pid->default_step = 1; - pid->max_step = 1; - pid->file_type = PTCACHE_FILE_PTCACHE; -} - /** * \param ob: Optional, may be NULL. * \param scene: Optional may be NULL. @@ -2059,17 +1984,7 @@ static bool foreach_object_modifier_ptcache(Object *object, } } else if (md->type == eModifierType_Simulation) { - SimulationModifierData *smd = (SimulationModifierData *)md; - if (smd->simulation) { - LISTBASE_FOREACH (SimulationState *, state, &smd->simulation->states) { - switch ((eSimulationStateType)state->type) { - case SIM_STATE_TYPE_PARTICLES: { - /* TODO(jacques) */ - break; - } - } - } - } + /* TODO(jacques) */ } } return true; diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 1f11869e21c..95340e4e29c 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -51,6 +51,7 @@ #include "NOD_node_tree_multi_function.hh" #include "NOD_simulation.h" +#include "BLI_map.hh" #include "BLT_translation.h" #include "FN_attributes_ref.hh" @@ -62,6 +63,22 @@ #include "SIM_simulation_update.hh" +using StateInitFunction = void (*)(SimulationState *state); +using StateResetFunction = void (*)(SimulationState *state); +using StateRemoveFunction = void (*)(SimulationState *state); +using StateCopyFunction = void (*)(const SimulationState *src, SimulationState *dst); + +struct SimulationStateType { + const char *name; + int size; + StateInitFunction init; + StateResetFunction reset; + StateRemoveFunction remove; + StateCopyFunction copy; +}; + +static const SimulationStateType *try_get_state_type(blender::StringRefNull type_name); + static void simulation_init_data(ID *id) { Simulation *simulation = (Simulation *)id; @@ -76,7 +93,7 @@ static void simulation_init_data(ID *id) static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag) { Simulation *simulation_dst = (Simulation *)id_dst; - Simulation *simulation_src = (Simulation *)id_src; + const Simulation *simulation_src = (const Simulation *)id_src; /* We always need allocation of our private ID data. */ const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE; @@ -89,76 +106,16 @@ static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons } BLI_listbase_clear(&simulation_dst->states); + LISTBASE_FOREACH (const SimulationState *, state_src, &simulation_src->states) { + SimulationState *state_dst = BKE_simulation_state_add( + simulation_dst, state_src->type, state_src->name); + BKE_simulation_state_copy_data(state_src, state_dst); + } BLI_duplicatelist(&simulation_dst->persistent_data_handles, &simulation_src->persistent_data_handles); } -static void free_simulation_state_head(SimulationState *state) -{ - MEM_freeN(state->name); -} - -static void free_particle_simulation_state(ParticleSimulationState *state) -{ - free_simulation_state_head(&state->head); - CustomData_free(&state->attributes, state->tot_particles); - BKE_ptcache_free_list(&state->ptcaches); - MEM_freeN(state); -} - -SimulationState *BKE_simulation_state_add(Simulation *simulation, - eSimulationStateType type, - const char *name) -{ - BLI_assert(simulation != nullptr); - BLI_assert(name != nullptr); - - bool is_cow_simulation = DEG_is_evaluated_id(&simulation->id); - - switch (type) { - case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *state = (ParticleSimulationState *)MEM_callocN(sizeof(*state), AT); - state->head.type = SIM_STATE_TYPE_PARTICLES; - state->head.name = BLI_strdup(name); - CustomData_reset(&state->attributes); - - if (!is_cow_simulation) { - state->point_cache = BKE_ptcache_add(&state->ptcaches); - } - - BLI_addtail(&simulation->states, state); - return &state->head; - } - } - - BLI_assert(false); - return nullptr; -} - -void BKE_simulation_state_remove(Simulation *simulation, SimulationState *state) -{ - BLI_assert(simulation != nullptr); - BLI_assert(state != nullptr); - BLI_assert(BLI_findindex(&simulation->states, state) >= 0); - - BLI_remlink(&simulation->states, state); - switch ((eSimulationStateType)state->type) { - case SIM_STATE_TYPE_PARTICLES: { - free_particle_simulation_state((ParticleSimulationState *)state); - break; - } - } -} - -void BKE_simulation_state_remove_all(Simulation *simulation) -{ - BLI_assert(simulation != nullptr); - while (!BLI_listbase_is_empty(&simulation->states)) { - BKE_simulation_state_remove(simulation, (SimulationState *)simulation->states.first); - } -} - static void simulation_free_data(ID *id) { Simulation *simulation = (Simulation *)id; @@ -215,7 +172,195 @@ void *BKE_simulation_add(Main *bmain, const char *name) return simulation; } +SimulationState *BKE_simulation_state_add(Simulation *simulation, + const char *type, + const char *name) +{ + BLI_assert(simulation != nullptr); + BLI_assert(name != nullptr); + + const SimulationStateType *state_type = try_get_state_type(type); + BLI_assert(state_type != nullptr); + + SimulationState *state = (SimulationState *)MEM_callocN(state_type->size, AT); + state->type = BLI_strdup(type); + state->name = BLI_strdup(name); + + state_type->init(state); + BLI_addtail(&simulation->states, state); + return state; +} + +void BKE_simulation_state_remove(Simulation *simulation, SimulationState *state) +{ + BLI_assert(simulation != nullptr); + BLI_assert(state != nullptr); + BLI_assert(BLI_findindex(&simulation->states, state) >= 0); + + BLI_remlink(&simulation->states, state); + const SimulationStateType *state_type = try_get_state_type(state->type); + BLI_assert(state_type != nullptr); + state_type->remove(state); + MEM_freeN(state->name); + MEM_freeN(state->type); + MEM_freeN(state); +} + +void BKE_simulation_state_remove_all(Simulation *simulation) +{ + BLI_assert(simulation != nullptr); + + while (!BLI_listbase_is_empty(&simulation->states)) { + BKE_simulation_state_remove(simulation, (SimulationState *)simulation->states.first); + } +} + +void BKE_simulation_state_reset(Simulation *UNUSED(simulation), SimulationState *state) +{ + BLI_assert(state != nullptr); + + const SimulationStateType *state_type = try_get_state_type(state->type); + BLI_assert(state_type != nullptr); + state_type->reset(state); +} + +void BKE_simulation_state_reset_all(Simulation *simulation) +{ + BLI_assert(simulation != nullptr); + + LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { + BKE_simulation_state_reset(simulation, state); + } +} + +void BKE_simulation_state_copy_data(const SimulationState *src_state, SimulationState *dst_state) +{ + BLI_assert(src_state != nullptr); + BLI_assert(dst_state != nullptr); + BLI_assert(STREQ(src_state->type, dst_state->type)); + + const SimulationStateType *state_type = try_get_state_type(src_state->type); + BLI_assert(state_type != nullptr); + state_type->copy(src_state, dst_state); +} + +SimulationState *BKE_simulation_state_try_find_by_name(Simulation *simulation, const char *name) +{ + if (simulation == nullptr) { + return nullptr; + } + if (name == nullptr) { + return nullptr; + } + + LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { + if (STREQ(state->name, name)) { + return state; + } + } + return nullptr; +} + +SimulationState *BKE_simulation_state_try_find_by_name_and_type(Simulation *simulation, + const char *name, + const char *type) +{ + if (type == nullptr) { + return nullptr; + } + + SimulationState *state = BKE_simulation_state_try_find_by_name(simulation, name); + if (state == nullptr) { + return nullptr; + } + if (STREQ(state->type, type)) { + return state; + } + return nullptr; +} + void BKE_simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation) { blender::sim::update_simulation_in_depsgraph(depsgraph, scene, simulation); } + +using StateTypeMap = blender::Map<std::string, std::unique_ptr<SimulationStateType>>; + +template<typename T> +static void add_state_type(StateTypeMap &map, + const char *name, + void (*init)(T *state), + void (*reset)(T *state), + void (*remove)(T *state), + void (*copy)(const T *src, T *dst)) +{ + SimulationStateType state_type{ + name, + (int)sizeof(T), + (StateInitFunction)init, + (StateResetFunction)reset, + (StateRemoveFunction)remove, + (StateCopyFunction)copy, + }; + map.add_new(name, std::make_unique<SimulationStateType>(state_type)); +} + +static StateTypeMap init_state_types() +{ + StateTypeMap map; + add_state_type<ParticleSimulationState>( + map, + SIM_TYPE_NAME_PARTICLE_SIMULATION, + [](ParticleSimulationState *state) { CustomData_reset(&state->attributes); }, + [](ParticleSimulationState *state) { + CustomData_free(&state->attributes, state->tot_particles); + state->tot_particles = 0; + state->next_particle_id = 0; + }, + [](ParticleSimulationState *state) { + CustomData_free(&state->attributes, state->tot_particles); + }, + [](const ParticleSimulationState *src, ParticleSimulationState *dst) { + CustomData_free(&dst->attributes, dst->tot_particles); + dst->tot_particles = src->tot_particles; + dst->next_particle_id = src->next_particle_id; + CustomData_copy( + &src->attributes, &dst->attributes, CD_MASK_ALL, CD_DUPLICATE, src->tot_particles); + }); + + add_state_type<ParticleMeshEmitterSimulationState>( + map, + SIM_TYPE_NAME_PARTICLE_MESH_EMITTER, + [](ParticleMeshEmitterSimulationState *UNUSED(state)) {}, + [](ParticleMeshEmitterSimulationState *state) { state->last_birth_time = 0.0f; }, + [](ParticleMeshEmitterSimulationState *UNUSED(state)) {}, + [](const ParticleMeshEmitterSimulationState *src, ParticleMeshEmitterSimulationState *dst) { + dst->last_birth_time = src->last_birth_time; + }); + return map; +} + +static StateTypeMap &get_state_types() +{ + static StateTypeMap state_type_map = init_state_types(); + return state_type_map; +} + +static const SimulationStateType *try_get_state_type(blender::StringRefNull type_name) +{ + std::unique_ptr<SimulationStateType> *type = get_state_types().lookup_ptr_as(type_name); + if (type == nullptr) { + return nullptr; + } + return type->get(); +} + +template<> const char *BKE_simulation_get_state_type_name<ParticleSimulationState>() +{ + return SIM_TYPE_NAME_PARTICLE_SIMULATION; +} + +template<> const char *BKE_simulation_get_state_type_name<ParticleMeshEmitterSimulationState>() +{ + return SIM_TYPE_NAME_PARTICLE_MESH_EMITTER; +} diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f443859e62c..9320187f2a0 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8691,14 +8691,10 @@ static void direct_link_simulation(BlendDataReader *reader, Simulation *simulati BLO_read_list(reader, &simulation->states); LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { BLO_read_data_address(reader, &state->name); - switch ((eSimulationStateType)state->type) { - case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *particle_state = (ParticleSimulationState *)state; - direct_link_customdata(reader, &particle_state->attributes, particle_state->tot_particles); - direct_link_pointcache_list( - reader, &particle_state->ptcaches, &particle_state->point_cache, 0); - break; - }; + BLO_read_data_address(reader, &state->type); + if (STREQ(state->type, SIM_TYPE_NAME_PARTICLE_SIMULATION)) { + ParticleSimulationState *particle_state = (ParticleSimulationState *)state; + direct_link_customdata(reader, &particle_state->attributes, particle_state->tot_particles); } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d33d8032ed1..46ac6b43c92 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -3833,31 +3833,33 @@ static void write_simulation(BlendWriter *writer, Simulation *simulation, const LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { BLO_write_string(writer, state->name); - switch ((eSimulationStateType)state->type) { - case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *particle_state = (ParticleSimulationState *)state; - BLO_write_struct(writer, ParticleSimulationState, particle_state); - - CustomDataLayer *layers = NULL; - CustomDataLayer layers_buff[CD_TEMP_CHUNK_SIZE]; - CustomData_file_write_prepare( - &particle_state->attributes, &layers, layers_buff, ARRAY_SIZE(layers_buff)); - - write_customdata(writer, - &simulation->id, - particle_state->tot_particles, - &particle_state->attributes, - layers, - CD_MASK_ALL); - - if (layers != NULL && layers != layers_buff) { - MEM_freeN(layers); - } - - write_pointcaches(writer, &particle_state->ptcaches); - break; + BLO_write_string(writer, state->type); + /* TODO: Decentralize this part. */ + if (STREQ(state->type, SIM_TYPE_NAME_PARTICLE_SIMULATION)) { + ParticleSimulationState *particle_state = (ParticleSimulationState *)state; + BLO_write_struct(writer, ParticleSimulationState, particle_state); + + CustomDataLayer *layers = NULL; + CustomDataLayer layers_buff[CD_TEMP_CHUNK_SIZE]; + CustomData_file_write_prepare( + &particle_state->attributes, &layers, layers_buff, ARRAY_SIZE(layers_buff)); + + write_customdata(writer, + &simulation->id, + particle_state->tot_particles, + &particle_state->attributes, + layers, + CD_MASK_ALL); + + if (layers != NULL && layers != layers_buff) { + MEM_freeN(layers); } } + else if (STREQ(state->type, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER)) { + ParticleMeshEmitterSimulationState *emitter_state = (ParticleMeshEmitterSimulationState *) + state; + BLO_write_struct(writer, ParticleMeshEmitterSimulationState, emitter_state); + } } BLO_write_struct_list(writer, PersistentDataHandleItem, &simulation->persistent_data_handles); diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h index f7a7f94da53..5bb0e50e089 100644 --- a/source/blender/makesdna/DNA_simulation_types.h +++ b/source/blender/makesdna/DNA_simulation_types.h @@ -46,10 +46,7 @@ typedef struct SimulationState { struct SimulationState *next; struct SimulationState *prev; - /** eSimulationStateType */ - int type; - int _pad; - + char *type; char *name; } SimulationState; @@ -60,13 +57,15 @@ typedef struct ParticleSimulationState { int tot_particles; int next_particle_id; struct CustomData attributes; - - /** Caches the state of the particles over time. The cache only exists on the original data - * block, not on cow copies. */ - struct PointCache *point_cache; - struct ListBase ptcaches; } ParticleSimulationState; +typedef struct ParticleMeshEmitterSimulationState { + SimulationState head; + + float last_birth_time; + char _pad[4]; +} ParticleMeshEmitterSimulationState; + /** Stores a mapping between an integer handle and a corresponding ID data block. */ typedef struct PersistentDataHandleItem { struct PersistentDataHandleItem *next; @@ -81,9 +80,7 @@ enum { SIM_DS_EXPAND = (1 << 0), }; -/* SimulationCache.type */ -typedef enum eSimulationStateType { - SIM_STATE_TYPE_PARTICLES = 0, -} eSimulationStateType; +#define SIM_TYPE_NAME_PARTICLE_SIMULATION "Particle Simulation" +#define SIM_TYPE_NAME_PARTICLE_MESH_EMITTER "Particle Mesh Emitter" #endif /* __DNA_SIMULATION_TYPES_H__ */ diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc index 819ed320255..d9cc9840e08 100644 --- a/source/blender/modifiers/intern/MOD_simulation.cc +++ b/source/blender/modifiers/intern/MOD_simulation.cc @@ -93,20 +93,8 @@ static bool isDisabled(const struct Scene *UNUSED(scene), static const ParticleSimulationState *find_particle_state(SimulationModifierData *smd) { - if (smd->simulation == nullptr) { - return nullptr; - } - if (smd->data_path == nullptr) { - return nullptr; - } - LISTBASE_FOREACH (const SimulationState *, state, &smd->simulation->states) { - if (STREQ(smd->data_path, state->name)) { - if (state->type == SIM_STATE_TYPE_PARTICLES) { - return (ParticleSimulationState *)state; - } - } - } - return nullptr; + return (const ParticleSimulationState *)BKE_simulation_state_try_find_by_name_and_type( + smd->simulation, smd->data_path, SIM_TYPE_NAME_PARTICLE_SIMULATION); } static PointCloud *modifyPointCloud(ModifierData *md, diff --git a/source/blender/simulation/intern/simulation_collect_influences.cc b/source/blender/simulation/intern/simulation_collect_influences.cc index 4760063daca..764e587d157 100644 --- a/source/blender/simulation/intern/simulation_collect_influences.cc +++ b/source/blender/simulation/intern/simulation_collect_influences.cc @@ -280,17 +280,30 @@ static void collect_forces(nodes::MFNetworkTreeMap &network_map, class MyBasicEmitter : public ParticleEmitter { private: Array<std::string> names_; + std::string my_state_; const fn::MultiFunction &inputs_fn_; uint32_t seed_; public: - MyBasicEmitter(Array<std::string> names, const fn::MultiFunction &inputs_fn, uint32_t seed) - : names_(std::move(names)), inputs_fn_(inputs_fn), seed_(seed) + MyBasicEmitter(Array<std::string> names, + std::string my_state, + const fn::MultiFunction &inputs_fn, + uint32_t seed) + : names_(std::move(names)), + my_state_(std::move(my_state)), + inputs_fn_(inputs_fn), + seed_(seed) { } void emit(ParticleEmitterContext &context) const override { + auto *state = context.solve_context().state_map().lookup<ParticleMeshEmitterSimulationState>( + my_state_); + if (state == nullptr) { + return; + } + fn::MFContextBuilder mf_context; mf_context.add_global_context("PersistentDataHandleMap", &context.solve_context().handle_map()); @@ -311,15 +324,17 @@ class MyBasicEmitter : public ParticleEmitter { Vector<float3> new_velocities; Vector<float> new_birth_times; - float start_time = context.simulation_time_interval().start(); + TimeInterval time_interval = context.simulation_time_interval(); + float start_time = time_interval.start(); RandomNumberGenerator rng{(*(uint32_t *)&start_time) ^ seed_}; - int amount = rate * 10; - for (int i : IndexRange(amount)) { - UNUSED_VARS(i); + const float time_between_particles = 1.0f / rate; + while (state->last_birth_time + time_between_particles < time_interval.end()) { new_positions.append(rng.get_unit_float3() * 0.3 + float3(object->loc)); new_velocities.append(rng.get_unit_float3()); - new_birth_times.append(context.simulation_time_interval().start()); + const float birth_time = state->last_birth_time + time_between_particles; + new_birth_times.append(birth_time); + state->last_birth_time = birth_time; } for (StringRef name : names_) { @@ -328,6 +343,7 @@ class MyBasicEmitter : public ParticleEmitter { return; } + int amount = new_positions.size(); fn::MutableAttributesRef attributes = allocator->allocate(amount); initialized_copy_n(new_positions.data(), amount, attributes.get<float3>("Position").data()); @@ -352,7 +368,8 @@ static Vector<const nodes::DNode *> find_linked_particle_simulations( static ParticleEmitter *create_particle_emitter(const nodes::DNode &dnode, ResourceCollector &resources, - nodes::MFNetworkTreeMap &network_map) + nodes::MFNetworkTreeMap &network_map, + RequiredStates &r_required_states) { Vector<const nodes::DNode *> simulation_dnodes = find_linked_particle_simulations( dnode.output(0)); @@ -377,19 +394,23 @@ static ParticleEmitter *create_particle_emitter(const nodes::DNode &dnode, fn::MultiFunction &inputs_fn = resources.construct<fn::MFNetworkEvaluator>( AT, Span<const fn::MFOutputSocket *>(), input_sockets.as_span()); - uint32_t seed = DefaultHash<std::string>{}(dnode_to_path(dnode)); + std::string my_state_name = dnode_to_path(dnode); + r_required_states.add(my_state_name, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER); + uint32_t seed = DefaultHash<std::string>{}(my_state_name); ParticleEmitter &emitter = resources.construct<MyBasicEmitter>( - AT, std::move(names), inputs_fn, seed); + AT, std::move(names), std::move(my_state_name), inputs_fn, seed); return &emitter; } static void collect_emitters(nodes::MFNetworkTreeMap &network_map, ResourceCollector &resources, - SimulationInfluences &r_influences) + SimulationInfluences &r_influences, + RequiredStates &r_required_states) { for (const nodes::DNode *dnode : network_map.tree().nodes_by_type("SimulationNodeParticleMeshEmitter")) { - ParticleEmitter *emitter = create_particle_emitter(*dnode, resources, network_map); + ParticleEmitter *emitter = create_particle_emitter( + *dnode, resources, network_map, r_required_states); if (emitter != nullptr) { r_influences.particle_emitters.append(emitter); } @@ -433,7 +454,7 @@ static void find_used_data_blocks(const nodes::DerivedNodeTree &tree, void collect_simulation_influences(Simulation &simulation, ResourceCollector &resources, SimulationInfluences &r_influences, - SimulationStatesInfo &r_states_info) + RequiredStates &r_required_states) { nodes::NodeTreeRefMap tree_refs; const nodes::DerivedNodeTree tree{simulation.nodetree, tree_refs}; @@ -452,10 +473,10 @@ void collect_simulation_influences(Simulation &simulation, // WM_clipboard_text_set(network.to_dot().c_str(), false); collect_forces(network_map, resources, data_sources, r_influences); - collect_emitters(network_map, resources, r_influences); + collect_emitters(network_map, resources, r_influences, r_required_states); for (const nodes::DNode *dnode : get_particle_simulation_nodes(tree)) { - r_states_info.particle_simulation_names.add(dnode_to_path(*dnode)); + r_required_states.add(dnode_to_path(*dnode), SIM_TYPE_NAME_PARTICLE_SIMULATION); } find_used_data_blocks(tree, r_influences); diff --git a/source/blender/simulation/intern/simulation_collect_influences.hh b/source/blender/simulation/intern/simulation_collect_influences.hh index cca396ffa66..42cbea6977e 100644 --- a/source/blender/simulation/intern/simulation_collect_influences.hh +++ b/source/blender/simulation/intern/simulation_collect_influences.hh @@ -25,14 +25,43 @@ namespace blender::sim { -struct SimulationStatesInfo { - VectorSet<std::string> particle_simulation_names; +class RequiredStates { + private: + Map<std::string, const char *> state_type_by_state_name_; + + public: + void add(std::string state_name, const char *state_type) + { + BLI_assert(state_type != nullptr); + const char *type_name = state_type_by_state_name_.lookup_default(state_name, nullptr); + if (type_name != nullptr) { + if (!STREQ(state_type, type_name)) { + std::cout << "Warning: Tried to have two different states with the same name.\n"; + std::cout << " Name: " << state_name << "\n"; + std::cout << " Type 1: " << state_type << "\n"; + std::cout << " Type 2: " << type_name << "\n"; + } + return; + } + + state_type_by_state_name_.add(std::move(state_name), state_type); + } + + const Map<std::string, const char *> &states() const + { + return state_type_by_state_name_; + } + + bool is_required(StringRef state_name, StringRef state_type) const + { + return state_type_by_state_name_.lookup_default_as(state_name, "") == state_type; + } }; void collect_simulation_influences(Simulation &simulation, ResourceCollector &resources, SimulationInfluences &r_influences, - SimulationStatesInfo &r_states_info); + RequiredStates &r_required_states); } // namespace blender::sim diff --git a/source/blender/simulation/intern/simulation_solver.cc b/source/blender/simulation/intern/simulation_solver.cc index 158c50957df..ee7a8d40035 100644 --- a/source/blender/simulation/intern/simulation_solver.cc +++ b/source/blender/simulation/intern/simulation_solver.cc @@ -312,20 +312,21 @@ void solve_simulation_time_step(Simulation &simulation, handle_map.add(handle->handle, *handle->id); } + SimulationStateMap state_map; + LISTBASE_FOREACH (SimulationState *, state, &simulation.states) { + state_map.add(state); + } + SimulationSolveContext solve_context{simulation, depsgraph, influences, TimeInterval(simulation.current_simulation_time, time_step), + state_map, handle_map}; TimeInterval simulation_time_interval{simulation.current_simulation_time, time_step}; - Vector<SimulationState *> simulation_states{simulation.states}; - Vector<ParticleSimulationState *> particle_simulation_states; - for (SimulationState *state : simulation_states) { - if (state->type == SIM_STATE_TYPE_PARTICLES) { - particle_simulation_states.append((ParticleSimulationState *)state); - } - } + Span<ParticleSimulationState *> particle_simulation_states = + state_map.lookup<ParticleSimulationState>(); Map<std::string, std::unique_ptr<fn::AttributesInfo>> attribute_infos; Map<std::string, std::unique_ptr<ParticleAllocator>> particle_allocators_map; diff --git a/source/blender/simulation/intern/simulation_solver.hh b/source/blender/simulation/intern/simulation_solver.hh index 1d1b9935661..2dc0921ad9e 100644 --- a/source/blender/simulation/intern/simulation_solver.hh +++ b/source/blender/simulation/intern/simulation_solver.hh @@ -25,6 +25,7 @@ #include "FN_attributes_ref.hh" #include "BKE_persistent_data_handle.hh" +#include "BKE_simulation.h" #include "particle_allocator.hh" #include "time_interval.hh" @@ -55,12 +56,61 @@ struct SimulationInfluences { VectorSet<ID *> used_data_blocks; }; +class SimulationStateMap { + private: + Map<StringRefNull, SimulationState *> states_by_name_; + Map<StringRefNull, Vector<SimulationState *>> states_by_type_; + + public: + void add(SimulationState *state) + { + states_by_name_.add_new(state->name, state); + states_by_type_.lookup_or_add_default(state->type).append(state); + } + + template<typename StateType> StateType *lookup(StringRef name) const + { + const char *type = BKE_simulation_get_state_type_name<StateType>(); + return (StateType *)this->lookup_name_type(name, type); + } + + template<typename StateType> Span<StateType *> lookup() const + { + const char *type = BKE_simulation_get_state_type_name<StateType>(); + return this->lookup_type(type).cast<StateType *>(); + } + + SimulationState *lookup_name_type(StringRef name, StringRef type) const + { + SimulationState *state = states_by_name_.lookup_default_as(name, nullptr); + if (state == nullptr) { + return nullptr; + } + if (state->type == type) { + return state; + } + return nullptr; + } + + Span<SimulationState *> lookup_type(StringRef type) const + { + const Vector<SimulationState *> *states = states_by_type_.lookup_ptr_as(type); + if (states == nullptr) { + return {}; + } + else { + return states->as_span(); + } + } +}; + class SimulationSolveContext { private: Simulation &simulation_; Depsgraph &depsgraph_; const SimulationInfluences &influences_; TimeInterval solve_interval_; + const SimulationStateMap &state_map_; const bke::PersistentDataHandleMap &id_handle_map_; public: @@ -68,11 +118,13 @@ class SimulationSolveContext { Depsgraph &depsgraph, const SimulationInfluences &influences, TimeInterval solve_interval, + const SimulationStateMap &state_map, const bke::PersistentDataHandleMap &handle_map) : simulation_(simulation), depsgraph_(depsgraph), influences_(influences), solve_interval_(solve_interval), + state_map_(state_map), id_handle_map_(handle_map) { } @@ -91,6 +143,11 @@ class SimulationSolveContext { { return id_handle_map_; } + + const SimulationStateMap &state_map() const + { + return state_map_; + } }; class ParticleAllocators { diff --git a/source/blender/simulation/intern/simulation_update.cc b/source/blender/simulation/intern/simulation_update.cc index 5328304863b..09219e0238f 100644 --- a/source/blender/simulation/intern/simulation_update.cc +++ b/source/blender/simulation/intern/simulation_update.cc @@ -37,88 +37,55 @@ namespace blender::sim { -static void copy_states_to_cow(Simulation *simulation_orig, Simulation *simulation_cow) +static void copy_states_to_cow(const Simulation *simulation_orig, Simulation *simulation_cow) { BKE_simulation_state_remove_all(simulation_cow); simulation_cow->current_frame = simulation_orig->current_frame; - LISTBASE_FOREACH (SimulationState *, state_orig, &simulation_orig->states) { - switch ((eSimulationStateType)state_orig->type) { - case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *particle_state_orig = (ParticleSimulationState *)state_orig; - ParticleSimulationState *particle_state_cow = (ParticleSimulationState *) - BKE_simulation_state_add(simulation_cow, SIM_STATE_TYPE_PARTICLES, state_orig->name); - particle_state_cow->tot_particles = particle_state_orig->tot_particles; - CustomData_copy(&particle_state_orig->attributes, - &particle_state_cow->attributes, - CD_MASK_ALL, - CD_DUPLICATE, - particle_state_orig->tot_particles); - break; - } - } + LISTBASE_FOREACH (const SimulationState *, state_orig, &simulation_orig->states) { + SimulationState *state_cow = BKE_simulation_state_add( + simulation_cow, state_orig->type, state_orig->name); + BKE_simulation_state_copy_data(state_orig, state_cow); } } -static void remove_unused_states(Simulation *simulation, const VectorSet<std::string> &state_names) +static void remove_unused_states(Simulation *simulation, const RequiredStates &required_states) { LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) { - if (!state_names.contains(state->name)) { + if (!required_states.is_required(state->name, state->type)) { BKE_simulation_state_remove(simulation, state); } } } -static void reset_states(Simulation *simulation) +static void add_missing_states(Simulation *simulation, const RequiredStates &required_states) { - LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { - switch ((eSimulationStateType)state->type) { - case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *particle_state = (ParticleSimulationState *)state; - CustomData_free(&particle_state->attributes, particle_state->tot_particles); - particle_state->tot_particles = 0; - break; - } - } - } -} + for (auto &&item : required_states.states().items()) { + const char *name = item.key.c_str(); + const char *type = item.value; -static SimulationState *try_find_state_by_name(Simulation *simulation, StringRef name) -{ - LISTBASE_FOREACH (SimulationState *, state, &simulation->states) { - if (state->name == name) { - return state; - } - } - return nullptr; -} + SimulationState *state = BKE_simulation_state_try_find_by_name_and_type( + simulation, name, type); -static void add_missing_particle_states(Simulation *simulation, Span<std::string> state_names) -{ - for (StringRefNull name : state_names) { - SimulationState *state = try_find_state_by_name(simulation, name); - if (state != nullptr) { - BLI_assert(state->type == SIM_STATE_TYPE_PARTICLES); - continue; + if (state == nullptr) { + BKE_simulation_state_add(simulation, type, name); } - - BKE_simulation_state_add(simulation, SIM_STATE_TYPE_PARTICLES, name.c_str()); } } static void reinitialize_empty_simulation_states(Simulation *simulation, - const SimulationStatesInfo &states_info) + const RequiredStates &required_states) { - remove_unused_states(simulation, states_info.particle_simulation_names); - reset_states(simulation); - add_missing_particle_states(simulation, states_info.particle_simulation_names); + remove_unused_states(simulation, required_states); + BKE_simulation_state_reset_all(simulation); + add_missing_states(simulation, required_states); } static void update_simulation_state_list(Simulation *simulation, - const SimulationStatesInfo &states_info) + const RequiredStates &required_states) { - remove_unused_states(simulation, states_info.particle_simulation_names); - add_missing_particle_states(simulation, states_info.particle_simulation_names); + remove_unused_states(simulation, required_states); + add_missing_states(simulation, required_states); } void update_simulation_in_depsgraph(Depsgraph *depsgraph, @@ -139,13 +106,13 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph, ResourceCollector resources; SimulationInfluences influences; - SimulationStatesInfo states_info; + RequiredStates required_states; /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */ - collect_simulation_influences(*simulation_orig, resources, influences, states_info); + collect_simulation_influences(*simulation_orig, resources, influences, required_states); if (current_frame == 1) { - reinitialize_empty_simulation_states(simulation_orig, states_info); + reinitialize_empty_simulation_states(simulation_orig, required_states); initialize_simulation_states(*simulation_orig, *depsgraph, influences); simulation_orig->current_frame = 1; @@ -153,7 +120,7 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph, copy_states_to_cow(simulation_orig, simulation_cow); } else if (current_frame == simulation_orig->current_frame + 1) { - update_simulation_state_list(simulation_orig, states_info); + update_simulation_state_list(simulation_orig, required_states); float time_step = 1.0f / 24.0f; solve_simulation_time_step(*simulation_orig, *depsgraph, influences, time_step); |