From 580d50091cfb0467cbde165058a6e78ef4898045 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 9 Jul 2020 15:40:27 +0200 Subject: Particles: Create a simulation state for every Particle Simulation node Every Particle Simulation node has a name (or a path when it is in a node group). This name has to be used in the Simulation modifier on a point cloud to see the particles. Caching has been disabled for now, because it was holding back development a bit. To reset the simulation, go back to frame 1. Currently, there is no way to influence the simulation. There are just some randomly moving points. Changing that is the next step. --- source/blender/blenkernel/BKE_pointcache.h | 4 +- source/blender/blenkernel/intern/customdata.c | 2 +- source/blender/blenkernel/intern/pointcache.c | 20 +- source/blender/blenkernel/intern/simulation.cc | 366 ++++++++++++++++----- source/blender/blenloader/intern/readfile.c | 1 + source/blender/blenloader/intern/writefile.c | 1 + .../intern/eval/deg_eval_copy_on_write.cc | 13 - source/blender/makesdna/DNA_modifier_types.h | 2 +- source/blender/makesdna/DNA_simulation_types.h | 12 +- source/blender/makesrna/intern/rna_modifier.c | 38 +++ source/blender/modifiers/intern/MOD_simulation.cc | 53 ++- 11 files changed, 387 insertions(+), 125 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index b0973ed458c..f919a31c165 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -296,7 +296,9 @@ 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); +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/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 76bc7a7bfb7..c11fa69db76 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1772,7 +1772,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* 42: CD_SCULPT_FACE_SETS */ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, /* 43: CD_LOCATION */ - {sizeof(float[3]), "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float[3]), "vec3f", 1, "Location", NULL, NULL, NULL, NULL, NULL}, /* 44: CD_RADIUS */ {sizeof(float), "MFloatProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL}, /* 45: CD_HAIRCURVE */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index dbd6d99c7fe..ce5402551b6 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1898,19 +1898,13 @@ static void ptcache_sim_particle_read( PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, positions + (index * 3)); } -void BKE_ptcache_id_from_sim_particles(PTCacheID *pid, ParticleSimulationState *state) +void BKE_ptcache_id_from_sim_particles(PTCacheID *pid, + ParticleSimulationState *state_orig, + ParticleSimulationState *state_cow) { memset(pid, 0, sizeof(PTCacheID)); - ParticleSimulationState *state_orig; - if (state->head.orig_state != NULL) { - state_orig = (ParticleSimulationState *)state->head.orig_state; - } - else { - state_orig = state; - } - - pid->calldata = state; + pid->calldata = state_cow; pid->type = PTCACHE_TYPE_SIM_PARTICLES; pid->cache = state_orig->point_cache; pid->cache_ptr = &state_orig->point_cache; @@ -2050,11 +2044,7 @@ static bool foreach_object_modifier_ptcache(Object *object, LISTBASE_FOREACH (SimulationState *, state, &smd->simulation->states) { switch ((eSimulationStateType)state->type) { case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *particle_state = (ParticleSimulationState *)state; - BKE_ptcache_id_from_sim_particles(&pid, particle_state); - if (!callback(&pid, callback_user_data)) { - return false; - } + /* TODO(jacques) */ break; } } diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index c4a35141b0d..35ef664dce3 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -31,6 +31,7 @@ #include "BLI_float3.hh" #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_rand.h" #include "BLI_span.hh" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -44,6 +45,7 @@ #include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_multi_function.hh" #include "BKE_pointcache.h" #include "BKE_simulation.h" @@ -51,9 +53,18 @@ #include "BLT_translation.h" +#include "FN_attributes_ref.hh" +#include "FN_cpp_types.hh" +#include "FN_multi_function_network_evaluation.hh" +#include "FN_multi_function_network_optimization.hh" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +extern "C" { +void WM_clipboard_text_set(const char *buf, bool selection); +} + static void simulation_init_data(ID *id) { Simulation *simulation = (Simulation *)id; @@ -63,14 +74,6 @@ static void simulation_init_data(ID *id) bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname); simulation->nodetree = ntree; - - /* Add a default particle simulation state for now. */ - ParticleSimulationState *state = (ParticleSimulationState *)MEM_callocN( - sizeof(ParticleSimulationState), __func__); - CustomData_reset(&state->attributes); - - state->point_cache = BKE_ptcache_add(&state->ptcaches); - BLI_addtail(&simulation->states, state); } static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag) @@ -89,19 +92,19 @@ 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) { - switch ((eSimulationStateType)state_src->type) { - case SIM_STATE_TYPE_PARTICLES: { - ParticleSimulationState *particle_state_dst = (ParticleSimulationState *)MEM_callocN( - sizeof(ParticleSimulationState), __func__); - CustomData_reset(&particle_state_dst->attributes); +static void free_simulation_state_head(SimulationState *state) +{ + MEM_freeN(state->name); +} - BLI_addtail(&simulation_dst->states, particle_state_dst); - break; - } - } - } +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); } static void simulation_free_data(ID *id) @@ -119,13 +122,10 @@ static void simulation_free_data(ID *id) LISTBASE_FOREACH_MUTABLE (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); - BKE_ptcache_free_list(&particle_state->ptcaches); + free_particle_simulation_state((ParticleSimulationState *)state); break; } } - MEM_freeN(state); } } @@ -166,59 +166,230 @@ void *BKE_simulation_add(Main *bmain, const char *name) namespace blender::bke { -static MutableSpan get_particle_positions(ParticleSimulationState *state) -{ - return MutableSpan( - (float3 *)CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Position"), - state->tot_particles); -} - static void ensure_attributes_exist(ParticleSimulationState *state) { if (CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Position") == nullptr) { CustomData_add_layer_named( &state->attributes, CD_LOCATION, CD_CALLOC, nullptr, state->tot_particles, "Position"); } + if (CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Velocity") == nullptr) { + CustomData_add_layer_named( + &state->attributes, CD_LOCATION, CD_CALLOC, nullptr, state->tot_particles, "Velocity"); + } } -static void copy_particle_state_to_cow(ParticleSimulationState *state_orig, - ParticleSimulationState *state_cow) +static void copy_states_to_cow(Simulation *simulation_orig, Simulation *simulation_cow) { - ensure_attributes_exist(state_cow); - CustomData_free(&state_cow->attributes, state_cow->tot_particles); - CustomData_copy(&state_orig->attributes, - &state_cow->attributes, - CD_MASK_ALL, - CD_DUPLICATE, - state_orig->tot_particles); - state_cow->current_frame = state_orig->current_frame; - state_cow->tot_particles = state_orig->tot_particles; + LISTBASE_FOREACH_MUTABLE (SimulationState *, state_cow, &simulation_cow->states) { + switch ((eSimulationStateType)state_cow->type) { + case SIM_STATE_TYPE_PARTICLES: { + BLI_remlink(&simulation_cow->states, state_cow); + free_particle_simulation_state((ParticleSimulationState *)state_cow); + break; + } + } + } + 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 *)MEM_callocN( + sizeof(*particle_state_cow), AT); + particle_state_cow->tot_particles = particle_state_orig->tot_particles; + particle_state_cow->head.name = BLI_strdup(state_orig->name); + CustomData_copy(&particle_state_orig->attributes, + &particle_state_cow->attributes, + CD_MASK_ALL, + CD_DUPLICATE, + particle_state_orig->tot_particles); + BLI_addtail(&simulation_cow->states, particle_state_cow); + break; + } + } + } } -static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation) +using AttributeNodeMap = Map>; + +static AttributeNodeMap deduplicate_attribute_nodes(fn::MFNetwork &network, + MFNetworkTreeMap &network_map, + const DerivedNodeTree &tree) { - int current_frame = scene->r.cfra; + Span attribute_dnodes = tree.nodes_by_type("SimulationNodeParticleAttribute"); + uint amount = attribute_dnodes.size(); + if (amount == 0) { + return {}; + } - ParticleSimulationState *state_cow = (ParticleSimulationState *)simulation->states.first; - ParticleSimulationState *state_orig = (ParticleSimulationState *)state_cow->head.orig_state; + Vector name_sockets; + for (const DNode *dnode : attribute_dnodes) { + fn::MFInputSocket &name_socket = network_map.lookup_dummy(dnode->input(0)); + name_sockets.append(&name_socket); + } - if (current_frame == state_cow->current_frame) { - return; + fn::MFNetworkEvaluator network_fn{{}, name_sockets.as_span()}; + + fn::MFParamsBuilder params{network_fn, 1}; + + Array attribute_names{amount, NoInitialization()}; + for (uint i : IndexRange(amount)) { + params.add_uninitialized_single_output( + fn::GMutableSpan(fn::CPPType_string, attribute_names.data() + i, 1)); + } + + fn::MFContextBuilder context; + /* Todo: Check that the names don't depend on dummy nodes. */ + network_fn.call({0}, params, context); + + Map, Vector> + attribute_nodes_by_name_and_type; + for (uint i : IndexRange(amount)) { + attribute_nodes_by_name_and_type + .lookup_or_add_default({attribute_names[i], name_sockets[i]->data_type()}) + .append(&name_sockets[i]->node()); } - /* Number of particles should be stored in the cache, but for now assume it is constant. */ - state_cow->tot_particles = state_orig->tot_particles; - CustomData_realloc(&state_cow->attributes, state_orig->tot_particles); - ensure_attributes_exist(state_cow); + AttributeNodeMap final_attribute_nodes; + for (auto item : attribute_nodes_by_name_and_type.items()) { + StringRef attribute_name = item.key.first; + fn::MFDataType data_type = item.key.second; + Span nodes = item.value; - PTCacheID pid_cow; - BKE_ptcache_id_from_sim_particles(&pid_cow, state_cow); - BKE_ptcache_id_time(&pid_cow, scene, current_frame, nullptr, nullptr, nullptr); + fn::MFOutputSocket &new_attribute_socket = network.add_input( + "Attribute '" + attribute_name + "'", data_type); + for (fn::MFNode *node : nodes) { + network.relink(node->output(0), new_attribute_socket); + } + network.remove(nodes); + + final_attribute_nodes.add_new(&new_attribute_socket.node().as_dummy(), item.key); + } + + return final_attribute_nodes; +} + +class CustomDataAttributesRef { + private: + Vector buffers_; + uint size_; + std::unique_ptr info_; + + public: + CustomDataAttributesRef(CustomData &custom_data, uint size) + { + fn::AttributesInfoBuilder builder; + for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) { + buffers_.append(layer.data); + builder.add(layer.name, {0, 0, 0}); + } + info_ = std::make_unique(builder); + size_ = size; + } + + operator fn::MutableAttributesRef() + { + return fn::MutableAttributesRef(*info_, buffers_, size_); + } - /* If successfull, this will read the state directly into the cow state. */ - int cache_result = BKE_ptcache_read(&pid_cow, current_frame, true); - if (cache_result == PTCACHE_READ_EXACT) { - state_cow->current_frame = current_frame; + operator fn::AttributesRef() const + { + return fn::AttributesRef(*info_, buffers_, size_); + } +}; + +static std::string dnode_to_path(const DNode &dnode) +{ + std::string path; + for (const DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) { + path = parent->node_ref().name() + "/" + path; + } + path = path + dnode.name(); + return path; +} + +static void remove_unused_states(Simulation *simulation, const VectorSet &state_names) +{ + LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) { + if (!state_names.contains(state->name)) { + BLI_remlink(&simulation->states, state); + free_particle_simulation_state((ParticleSimulationState *)state); + } + } +} + +static void reset_states(Simulation *simulation) +{ + 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; + } + } + } +} + +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; +} + +static void add_missing_particle_states(Simulation *simulation, Span 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; + } + + ParticleSimulationState *particle_state = (ParticleSimulationState *)MEM_callocN( + sizeof(*particle_state), AT); + particle_state->head.type = SIM_STATE_TYPE_PARTICLES; + particle_state->head.name = BLI_strdup(name.data()); + CustomData_reset(&particle_state->attributes); + particle_state->point_cache = BKE_ptcache_add(&particle_state->ptcaches); + BLI_addtail(&simulation->states, particle_state); + } +} + +static void reinitialize_empty_simulation_states(Simulation *simulation, + const DerivedNodeTree &tree) +{ + VectorSet state_names; + for (const DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) { + state_names.add(dnode_to_path(*dnode)); + } + + remove_unused_states(simulation, state_names); + reset_states(simulation); + add_missing_particle_states(simulation, state_names); +} + +static void update_simulation_state_list(Simulation *simulation, const DerivedNodeTree &tree) +{ + VectorSet state_names; + for (const DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) { + state_names.add(dnode_to_path(*dnode)); + } + + remove_unused_states(simulation, state_names); + add_missing_particle_states(simulation, state_names); +} + +static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation_cow) +{ + int current_frame = scene->r.cfra; + if (simulation_cow->current_frame == current_frame) { return; } @@ -227,34 +398,71 @@ static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulatio return; } - PTCacheID pid_orig; - BKE_ptcache_id_from_sim_particles(&pid_orig, state_orig); - BKE_ptcache_id_time(&pid_orig, scene, current_frame, nullptr, nullptr, nullptr); + Simulation *simulation_orig = (Simulation *)DEG_get_original_id(&simulation_cow->id); + + NodeTreeRefMap tree_refs; + /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */ + const DerivedNodeTree tree{simulation_orig->nodetree, tree_refs}; + fn::MFNetwork network; + ResourceCollector resources; + MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources); + AttributeNodeMap attribute_node_map = deduplicate_attribute_nodes(network, network_map, tree); + fn::mf_network_optimization::constant_folding(network, resources); + fn::mf_network_optimization::common_subnetwork_elimination(network); + fn::mf_network_optimization::dead_node_removal(network); + UNUSED_VARS(attribute_node_map); + // WM_clipboard_text_set(network.to_dot().c_str(), false); if (current_frame == 1) { - state_orig->tot_particles = 100; - state_orig->current_frame = 1; - CustomData_realloc(&state_orig->attributes, state_orig->tot_particles); - ensure_attributes_exist(state_orig); - - MutableSpan positions = get_particle_positions(state_orig); - for (uint i : positions.index_range()) { - positions[i] = {i / 10.0f, 0, 0}; + reinitialize_empty_simulation_states(simulation_orig, tree); + + RNG *rng = BLI_rng_new(0); + + simulation_orig->current_frame = 1; + LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) { + state->tot_particles = 100; + CustomData_realloc(&state->attributes, state->tot_particles); + ensure_attributes_exist(state); + + CustomDataAttributesRef custom_data_attributes{state->attributes, + (uint)state->tot_particles}; + + fn::MutableAttributesRef attributes = custom_data_attributes; + MutableSpan positions = attributes.get("Position"); + MutableSpan velocities = attributes.get("Velocity"); + + for (uint i : positions.index_range()) { + positions[i] = {i / 10.0f, 0, 0}; + velocities[i] = {0, BLI_rng_get_float(rng), BLI_rng_get_float(rng) * 2 + 1}; + } } - BKE_ptcache_write(&pid_orig, current_frame); - copy_particle_state_to_cow(state_orig, state_cow); + BLI_rng_free(rng); + + copy_states_to_cow(simulation_orig, simulation_cow); } - else if (current_frame == state_orig->current_frame + 1) { - state_orig->current_frame = current_frame; - ensure_attributes_exist(state_orig); - MutableSpan positions = get_particle_positions(state_orig); - for (float3 &position : positions) { - position.z += 0.1f; + else if (current_frame == simulation_orig->current_frame + 1) { + update_simulation_state_list(simulation_orig, tree); + float time_step = 1.0f / 24.0f; + simulation_orig->current_frame = current_frame; + + LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) { + ensure_attributes_exist(state); + + CustomDataAttributesRef custom_data_attributes{state->attributes, + (uint)state->tot_particles}; + + fn::MutableAttributesRef attributes = custom_data_attributes; + MutableSpan positions = attributes.get("Position"); + MutableSpan velocities = attributes.get("Velocity"); + + for (uint i : positions.index_range()) { + velocities[i].z += -1.0f * time_step; + positions[i] += velocities[i] * time_step; + } } - BKE_ptcache_write(&pid_orig, current_frame); - copy_particle_state_to_cow(state_orig, state_cow); + copy_states_to_cow(simulation_orig, simulation_cow); } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 274d56ac5f7..44a1a6ec44a 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8686,6 +8686,7 @@ 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; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 2ce8abff3c5..4e2b4fef9a0 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -3832,6 +3832,7 @@ 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; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 38350d50da6..79d6c8d6a77 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -711,13 +711,6 @@ void update_modifiers_orig_pointers(const Object *object_orig, Object *object_co &object_orig->modifiers, &object_cow->modifiers, &ModifierData::orig_modifier_data); } -void update_simulation_states_orig_pointers(const Simulation *simulation_orig, - Simulation *simulation_cow) -{ - update_list_orig_pointers( - &simulation_orig->states, &simulation_cow->states, &SimulationState::orig_state); -} - void update_nla_strips_orig_pointers(const ListBase *strips_orig, ListBase *strips_cow) { NlaStrip *strip_orig = reinterpret_cast(strips_orig->first); @@ -817,12 +810,6 @@ void update_id_after_copy(const Depsgraph *depsgraph, update_scene_orig_pointers(scene_orig, scene_cow); break; } - case ID_SIM: { - Simulation *simulation_cow = (Simulation *)id_cow; - const Simulation *simulation_orig = (const Simulation *)id_orig; - update_simulation_states_orig_pointers(simulation_orig, simulation_cow); - break; - } default: break; } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 60ad0eae576..50b4739e09f 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -2146,7 +2146,7 @@ typedef struct SimulationModifierData { ModifierData modifier; struct Simulation *simulation; - char data_path[64]; + char *data_path; } SimulationModifierData; #ifdef __cplusplus diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h index 93ba9c425f0..a2b81b731d3 100644 --- a/source/blender/makesdna/DNA_simulation_types.h +++ b/source/blender/makesdna/DNA_simulation_types.h @@ -31,7 +31,7 @@ typedef struct Simulation { struct bNodeTree *nodetree; int flag; - int _pad; + float current_frame; /** List containing SimulationState objects. */ struct ListBase states; @@ -41,23 +41,19 @@ typedef struct SimulationState { struct SimulationState *next; struct SimulationState *prev; - /** This is only initialized on cow copies of the simulation. It points to the state on the - * original data block. That is where the cache is stored. */ - struct SimulationState *orig_state; - /** eSimulationStateType */ int type; int _pad; - char name[64]; + char *name; } SimulationState; typedef struct ParticleSimulationState { SimulationState head; - /** Contains the state of the particles at time current_frame. */ - float current_frame; + /** Contains the state of the particles at time Simulation->current_frame. */ int tot_particles; + int _pad; struct CustomData attributes; /** Caches the state of the particles over time. The cache only exists on the original data diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index eab7326868b..20648970bd1 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1639,6 +1639,40 @@ static void rna_SimulationModifier_simulation_update(Main *bmain, Scene *scene, rna_Modifier_dependency_update(bmain, scene, ptr); } +static void rna_SimulationModifier_data_path_get(PointerRNA *ptr, char *value) +{ + SimulationModifierData *smd = ptr->data; + + if (smd->data_path) { + strcpy(value, smd->data_path); + } + else { + value[0] = '\0'; + } +} + +static int rna_SimulationModifier_data_path_length(PointerRNA *ptr) +{ + SimulationModifierData *smd = ptr->data; + return smd->data_path ? strlen(smd->data_path) : 0; +} + +static void rna_SimulationModifier_data_path_set(PointerRNA *ptr, const char *value) +{ + SimulationModifierData *smd = ptr->data; + + if (smd->data_path) { + MEM_freeN(smd->data_path); + } + + if (value[0]) { + smd->data_path = BLI_strdup(value); + } + else { + smd->data_path = NULL; + } +} + /** * Special set callback that just changes the first bit of the expansion flag. * This way the expansion state of all the sub-panels is not changed by RNA. @@ -6859,6 +6893,10 @@ static void rna_def_modifier_simulation(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_SimulationModifier_simulation_update"); prop = RNA_def_property(srna, "data_path", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, + "rna_SimulationModifier_data_path_get", + "rna_SimulationModifier_data_path_length", + "rna_SimulationModifier_data_path_set"); RNA_def_property_ui_text( prop, "Data Path", "Identifier of the simulation component that should be accessed"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc index 85eb66cd826..69a7bfd91ac 100644 --- a/source/blender/modifiers/intern/MOD_simulation.cc +++ b/source/blender/modifiers/intern/MOD_simulation.cc @@ -29,6 +29,7 @@ #include "BLI_float3.hh" #include "BLI_listbase.h" +#include "BLI_string.h" #include "BLI_utildefines.h" #include "DNA_mesh_types.h" @@ -47,6 +48,8 @@ #include "BKE_pointcloud.h" #include "BKE_simulation.h" +#include "BLO_read_write.h" + /* SpaceType struct has a member called 'new' which obviously conflicts with C++ * so temporarily redefining the new keyword to make it compile. */ #define new extern_new @@ -93,9 +96,14 @@ static const ParticleSimulationState *find_particle_state(SimulationModifierData if (smd->simulation == nullptr) { return nullptr; } + if (smd->data_path == nullptr) { + return nullptr; + } LISTBASE_FOREACH (const SimulationState *, state, &smd->simulation->states) { - if (state->type == SIM_STATE_TYPE_PARTICLES) { - return (ParticleSimulationState *)state; + if (STREQ(smd->data_path, state->name)) { + if (state->type == SIM_STATE_TYPE_PARTICLES) { + return (ParticleSimulationState *)state; + } } } return nullptr; @@ -121,7 +129,7 @@ static PointCloud *modifyPointCloud(ModifierData *md, memcpy(pointcloud->co, positions, sizeof(float3) * state->tot_particles); for (int i = 0; i < state->tot_particles; i++) { - pointcloud->radius[i] = 0.05f; + pointcloud->radius[i] = 0.1f; } return pointcloud; @@ -146,6 +154,37 @@ static void panelRegister(ARegionType *region_type) modifier_panel_register(region_type, eModifierType_Simulation, panel_draw); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + const SimulationModifierData *smd = (const SimulationModifierData *)md; + BLO_write_string(writer, smd->data_path); +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + SimulationModifierData *smd = (SimulationModifierData *)md; + BLO_read_data_address(reader, &smd->data_path); +} + +static void copyData(const ModifierData *md, ModifierData *target, const int flag) +{ + const SimulationModifierData *smd = (const SimulationModifierData *)md; + SimulationModifierData *tsmd = (SimulationModifierData *)target; + + BKE_modifier_copydata_generic(md, target, flag); + if (smd->data_path != nullptr) { + tsmd->data_path = BLI_strdup(smd->data_path); + } +} + +static void freeData(ModifierData *md) +{ + SimulationModifierData *smd = (SimulationModifierData *)md; + if (smd->data_path) { + MEM_freeN(smd->data_path); + } +} + ModifierTypeInfo modifierType_Simulation = { /* name */ "Simulation", /* structName */ "SimulationModifierData", @@ -153,7 +192,7 @@ ModifierTypeInfo modifierType_Simulation = { /* type */ eModifierTypeType_None, /* flags */ (ModifierTypeFlag)0, - /* copyData */ BKE_modifier_copydata_generic, + /* copyData */ copyData, /* deformVerts */ NULL, /* deformMatrices */ NULL, @@ -166,7 +205,7 @@ ModifierTypeInfo modifierType_Simulation = { /* initData */ NULL, /* requiredDataMask */ NULL, - /* freeData */ NULL, + /* freeData */ freeData, /* isDisabled */ isDisabled, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ NULL, @@ -176,6 +215,6 @@ ModifierTypeInfo modifierType_Simulation = { /* foreachTexLink */ NULL, /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; -- cgit v1.2.3