diff options
author | Jacques Lucke <mail@jlucke.com> | 2019-08-23 16:41:33 +0300 |
---|---|---|
committer | Jacques Lucke <mail@jlucke.com> | 2019-08-23 16:41:33 +0300 |
commit | 4d2dcb6a5fbd075df16db169460e4d3791289475 (patch) | |
tree | 37de54d82c74b652b1289123a0f9b5d578eb3c6e /source | |
parent | 9c05112910946581ccf17b23fc0ec5f0297467a3 (diff) |
Initial implementation of updated ui proposal
Diffstat (limited to 'source')
16 files changed, 579 insertions, 885 deletions
diff --git a/source/blender/blenkernel/BKE_node_tree.hpp b/source/blender/blenkernel/BKE_node_tree.hpp index e13da37887b..52998a1e5cb 100644 --- a/source/blender/blenkernel/BKE_node_tree.hpp +++ b/source/blender/blenkernel/BKE_node_tree.hpp @@ -119,6 +119,9 @@ class VirtualNode { return m_outputs[index]; } + VirtualSocket *input(uint index, StringRef expected_name); + VirtualSocket *output(uint index, StringRef expected_name); + bNode *bnode() { return m_bnode; @@ -243,4 +246,26 @@ class VirtualLink { VirtualSocket *m_to; }; +inline VirtualSocket *VirtualNode::input(uint index, StringRef expected_name) +{ + VirtualSocket *vsocket = m_inputs[index]; +#ifdef DEBUG + StringRef actual_name = vsocket->name(); + BLI_assert(actual_name == expected_name); +#endif + UNUSED_VARS_NDEBUG(expected_name); + return vsocket; +} + +inline VirtualSocket *VirtualNode::output(uint index, StringRef expected_name) +{ + VirtualSocket *vsocket = m_outputs[index]; +#ifdef DEBUG + StringRef actual_name = vsocket->name(); + BLI_assert(actual_name == expected_name); +#endif + UNUSED_VARS_NDEBUG(expected_name); + return vsocket; +} + } // namespace BKE diff --git a/source/blender/simulations/CMakeLists.txt b/source/blender/simulations/CMakeLists.txt index 0226deedb6f..5f165fc831f 100644 --- a/source/blender/simulations/CMakeLists.txt +++ b/source/blender/simulations/CMakeLists.txt @@ -42,8 +42,6 @@ set(SRC bparticles/world_state.hpp bparticles/integrator.hpp bparticles/integrator.cpp - bparticles/inserters.hpp - bparticles/inserters.cpp bparticles/node_frontend.hpp bparticles/node_frontend.cpp bparticles/particle_set.hpp diff --git a/source/blender/simulations/bparticles/action_interface.hpp b/source/blender/simulations/bparticles/action_interface.hpp index 2c1594101e9..bd6122b43ff 100644 --- a/source/blender/simulations/bparticles/action_interface.hpp +++ b/source/blender/simulations/bparticles/action_interface.hpp @@ -60,6 +60,8 @@ class Action { ActionContext *action_context = nullptr); void execute_for_subset(ArrayRef<uint> pindices, ActionInterface &action_interface); void execute_for_new_particles(ParticleSets &particle_sets, ActionInterface &action_interface); + void execute_for_new_particles(ParticleSets &particle_sets, + OffsetHandlerInterface &offset_handler_interface); }; /* ActionInterface inline functions @@ -160,6 +162,29 @@ inline void Action::execute_for_new_particles(ParticleSets &particle_sets, } } +inline void Action::execute_for_new_particles(ParticleSets &particle_sets, + OffsetHandlerInterface &offset_handler_interface) +{ + AttributesInfo info; + std::array<void *, 0> buffers; + + EmptyEventInfo empty_context; + + for (ParticleSet particles : particle_sets.sets()) { + uint min_array_size = particles.block().capacity(); + AttributeArrays offsets(info, buffers, 0, min_array_size); + TemporaryArray<float> durations(min_array_size); + durations.fill_indices(particles.pindices(), 0); + ActionInterface new_interface(offset_handler_interface.particle_allocator(), + particles, + offsets, + particles.attributes().get<float>("Birth Time"), + durations, + empty_context); + this->execute(new_interface); + } +} + inline ActionContext &ActionInterface::context() { return m_action_context; diff --git a/source/blender/simulations/bparticles/actions.cpp b/source/blender/simulations/bparticles/actions.cpp index 35b52520b69..d5cefb171ca 100644 --- a/source/blender/simulations/bparticles/actions.cpp +++ b/source/blender/simulations/bparticles/actions.cpp @@ -10,6 +10,13 @@ void NoneAction::execute(ActionInterface &UNUSED(interface)) { } +void ActionSequence::execute(ActionInterface &interface) +{ + for (auto &action : m_actions) { + action->execute(interface); + } +} + void ChangeDirectionAction::execute(ActionInterface &interface) { ParticleSet particles = interface.particles(); @@ -31,8 +38,6 @@ void ChangeDirectionAction::execute(ActionInterface &interface) velocity_offsets.value()[pindex] = float3(0); } } - - m_post_action->execute(interface); } void ChangeColorAction::execute(ActionInterface &interface) @@ -45,8 +50,6 @@ void ChangeColorAction::execute(ActionInterface &interface) rgba_f color = inputs->get<rgba_f>("Color", 0, pindex); colors[pindex] = color; } - - m_post_action->execute(interface); } void KillAction::execute(ActionInterface &interface) @@ -90,15 +93,15 @@ void ExplodeAction::execute(ActionInterface &interface) } } - auto new_particles = interface.particle_allocator().request(m_new_particle_name, - new_birth_times.size()); - new_particles.set<float3>("Position", new_positions); - new_particles.set<float3>("Velocity", new_velocities); - new_particles.fill<float>("Size", 0.1f); - new_particles.set<float>("Birth Time", new_birth_times); + for (StringRef type_name : m_types_to_emit) { + auto new_particles = interface.particle_allocator().request(type_name, new_birth_times.size()); + new_particles.set<float3>("Position", new_positions); + new_particles.set<float3>("Velocity", new_velocities); + new_particles.fill<float>("Size", 0.1f); + new_particles.set<float>("Birth Time", new_birth_times); - m_post_action->execute(interface); - m_new_particle_action->execute_for_new_particles(new_particles, interface); + m_on_birth_action->execute_for_new_particles(new_particles, interface); + } } void ConditionAction::execute(ActionInterface &interface) diff --git a/source/blender/simulations/bparticles/actions.hpp b/source/blender/simulations/bparticles/actions.hpp index 31c4ecc3ce4..0062689aec2 100644 --- a/source/blender/simulations/bparticles/actions.hpp +++ b/source/blender/simulations/bparticles/actions.hpp @@ -9,6 +9,18 @@ class NoneAction : public Action { void execute(ActionInterface &UNUSED(interface)) override; }; +class ActionSequence : public Action { + private: + Vector<std::unique_ptr<Action>> m_actions; + + public: + ActionSequence(Vector<std::unique_ptr<Action>> actions) : m_actions(std::move(actions)) + { + } + + void execute(ActionInterface &interface) override; +}; + class KillAction : public Action { void execute(ActionInterface &interface) override; }; @@ -16,12 +28,10 @@ class KillAction : public Action { class ChangeDirectionAction : public Action { private: std::unique_ptr<ParticleFunction> m_compute_inputs; - std::unique_ptr<Action> m_post_action; public: - ChangeDirectionAction(std::unique_ptr<ParticleFunction> compute_inputs, - std::unique_ptr<Action> post_action) - : m_compute_inputs(std::move(compute_inputs)), m_post_action(std::move(post_action)) + ChangeDirectionAction(std::unique_ptr<ParticleFunction> compute_inputs) + : m_compute_inputs(std::move(compute_inputs)) { } @@ -31,12 +41,10 @@ class ChangeDirectionAction : public Action { class ChangeColorAction : public Action { private: std::unique_ptr<ParticleFunction> m_compute_inputs; - std::unique_ptr<Action> m_post_action; public: - ChangeColorAction(std::unique_ptr<ParticleFunction> compute_inputs, - std::unique_ptr<Action> post_action) - : m_compute_inputs(std::move(compute_inputs)), m_post_action(std::move(post_action)) + ChangeColorAction(std::unique_ptr<ParticleFunction> compute_inputs) + : m_compute_inputs(std::move(compute_inputs)) { } @@ -45,20 +53,17 @@ class ChangeColorAction : public Action { class ExplodeAction : public Action { private: - std::string m_new_particle_name; + Vector<std::string> m_types_to_emit; std::unique_ptr<ParticleFunction> m_compute_inputs; - std::unique_ptr<Action> m_post_action; - std::unique_ptr<Action> m_new_particle_action; + std::unique_ptr<Action> m_on_birth_action; public: - ExplodeAction(StringRef new_particle_name, + ExplodeAction(Vector<std::string> types_to_emit, std::unique_ptr<ParticleFunction> compute_inputs, - std::unique_ptr<Action> post_action, - std::unique_ptr<Action> new_particle_action) - : m_new_particle_name(new_particle_name.to_std_string()), + std::unique_ptr<Action> on_birth_action) + : m_types_to_emit(std::move(types_to_emit)), m_compute_inputs(std::move(compute_inputs)), - m_post_action(std::move(post_action)), - m_new_particle_action(std::move(new_particle_action)) + m_on_birth_action(std::move(on_birth_action)) { } diff --git a/source/blender/simulations/bparticles/emitters.cpp b/source/blender/simulations/bparticles/emitters.cpp index fc539597b86..297aeffaa5c 100644 --- a/source/blender/simulations/bparticles/emitters.cpp +++ b/source/blender/simulations/bparticles/emitters.cpp @@ -37,12 +37,13 @@ void PointEmitter::emit(EmitterInterface &interface) birth_times[i] = interface.time_span().interpolate(t); } - auto new_particles = interface.particle_allocator().request(m_particle_type_name, - new_positions.size()); - new_particles.set<float3>("Position", new_positions); - new_particles.set<float3>("Velocity", new_velocities); - new_particles.set<float>("Size", new_sizes); - new_particles.set<float>("Birth Time", birth_times); + for (StringRef type : m_types_to_emit) { + auto new_particles = interface.particle_allocator().request(type, new_positions.size()); + new_particles.set<float3>("Position", new_positions); + new_particles.set<float3>("Velocity", new_velocities); + new_particles.set<float>("Size", new_sizes); + new_particles.set<float>("Birth Time", birth_times); + } } static float3 random_point_in_triangle(float3 a, float3 b, float3 c) @@ -118,76 +119,14 @@ void SurfaceEmitter::emit(EmitterInterface &interface) sizes.append(m_size); } - auto new_particles = interface.particle_allocator().request(m_particle_type_name, - positions.size()); - new_particles.set<float3>("Position", positions); - new_particles.set<float3>("Velocity", velocities); - new_particles.set<float>("Size", sizes); - new_particles.set<float>("Birth Time", birth_times); - - m_action->execute_from_emitter(new_particles, interface); -} - -void CustomFunctionEmitter::emit(EmitterInterface &interface) -{ - TupleCallBody &body = m_function->body<TupleCallBody>(); - - FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); + for (StringRef type_name : m_types_to_emit) { + auto new_particles = interface.particle_allocator().request(type_name, positions.size()); + new_particles.set<float3>("Position", positions); + new_particles.set<float3>("Velocity", velocities); + new_particles.set<float>("Size", sizes); + new_particles.set<float>("Birth Time", birth_times); - body.set_input<float>(fn_in, 0, "Start Time", interface.time_span().start()); - body.set_input<float>(fn_in, 1, "Time Step", interface.time_span().duration()); - body.call__setup_execution_context(fn_in, fn_out); - - uint new_particle_amount = 0; - for (uint i = 0; i < m_function->output_amount(); i++) { - FN::Type *type = m_function->output_type(i); - if (ELEM(type, TYPE_float_list, TYPE_float3_list, TYPE_int32_list, TYPE_rgba_f_list)) { - uint length = fn_out.get_ref<SharedList>(i)->size(); - new_particle_amount = std::max(new_particle_amount, length); - } - } - - auto new_particles = interface.particle_allocator().request(m_particle_type_name, - new_particle_amount); - new_particles.fill<float>("Birth Time", interface.time_span().end()); - - for (uint i = 0; i < m_function->output_amount(); i++) { - FN::Type *type = m_function->output_type(i); - StringRef attribute_name = m_function->output_name(i); - int attribute_index = new_particles.attributes_info().attribute_index_try(attribute_name); - - if (attribute_index == -1) { - continue; - } - - if (type == TYPE_float_list) { - auto list = fn_out.relocate_out<SharedList>(i); - new_particles.set_repeated<float>(attribute_index, list->as_array_ref<float>()); - } - else if (type == TYPE_float3_list) { - auto list = fn_out.relocate_out<SharedList>(i); - new_particles.set_repeated<float3>(attribute_index, list->as_array_ref<float3>()); - } - else if (type == TYPE_int32_list) { - auto list = fn_out.relocate_out<SharedList>(i); - new_particles.set_repeated<int32_t>(attribute_index, list->as_array_ref<int32_t>()); - } - else if (type == TYPE_rgba_f_list) { - auto list = fn_out.relocate_out<SharedList>(i); - new_particles.set_repeated<rgba_f>(attribute_index, list->as_array_ref<rgba_f>()); - } - else if (type == TYPE_float) { - new_particles.fill<float>(attribute_index, fn_out.get<float>(i)); - } - else if (type == TYPE_float3) { - new_particles.fill<float3>(attribute_index, fn_out.get<float3>(i)); - } - else if (type == TYPE_int32) { - new_particles.fill<int32_t>(attribute_index, fn_out.get<int32_t>(i)); - } - else if (type == TYPE_rgba_f) { - new_particles.fill<rgba_f>(attribute_index, fn_out.get<rgba_f>(i)); - } + m_on_birth_action->execute_from_emitter(new_particles, interface); } } @@ -208,11 +147,12 @@ void InitialGridEmitter::emit(EmitterInterface &interface) } } - auto new_particles = interface.particle_allocator().request(m_particle_type_name, - new_positions.size()); - new_particles.set<float3>("Position", new_positions); - new_particles.fill<float>("Birth Time", interface.time_span().start()); - new_particles.fill<float>("Size", m_size); + for (StringRef type_name : m_types_to_emit) { + auto new_particles = interface.particle_allocator().request(type_name, new_positions.size()); + new_particles.set<float3>("Position", new_positions); + new_particles.fill<float>("Birth Time", interface.time_span().start()); + new_particles.fill<float>("Size", m_size); + } } } // namespace BParticles diff --git a/source/blender/simulations/bparticles/emitters.hpp b/source/blender/simulations/bparticles/emitters.hpp index 5d86f536dc5..d7c60920c68 100644 --- a/source/blender/simulations/bparticles/emitters.hpp +++ b/source/blender/simulations/bparticles/emitters.hpp @@ -13,8 +13,8 @@ using FN::TupleCallBody; class SurfaceEmitter : public Emitter { private: - std::string m_particle_type_name; - std::unique_ptr<Action> m_action; + Vector<std::string> m_types_to_emit; + std::unique_ptr<Action> m_on_birth_action; Object *m_object; InterpolatedFloat4x4 m_transform; @@ -24,16 +24,16 @@ class SurfaceEmitter : public Emitter { float m_size; public: - SurfaceEmitter(StringRef particle_type_name, - std::unique_ptr<Action> action, + SurfaceEmitter(Vector<std::string> types_to_emit, + std::unique_ptr<Action> on_birth_action, Object *object, InterpolatedFloat4x4 transform, float rate, float normal_velocity, float emitter_velocity, float size) - : m_particle_type_name(particle_type_name.to_std_string()), - m_action(std::move(action)), + : m_types_to_emit(std::move(types_to_emit)), + m_on_birth_action(std::move(on_birth_action)), m_object(object), m_transform(transform), m_rate(rate), @@ -48,19 +48,19 @@ class SurfaceEmitter : public Emitter { class PointEmitter : public Emitter { private: - std::string m_particle_type_name; + Vector<std::string> m_types_to_emit; uint m_amount; InterpolatedFloat3 m_point; InterpolatedFloat3 m_velocity; InterpolatedFloat m_size; public: - PointEmitter(StringRef particle_type_name, + PointEmitter(Vector<std::string> types_to_emit, uint amount, InterpolatedFloat3 point, InterpolatedFloat3 velocity, InterpolatedFloat size) - : m_particle_type_name(particle_type_name.to_std_string()), + : m_types_to_emit(std::move(types_to_emit)), m_amount(amount), m_point(point), m_velocity(velocity), @@ -71,23 +71,9 @@ class PointEmitter : public Emitter { void emit(EmitterInterface &interface) override; }; -class CustomFunctionEmitter : public Emitter { - private: - std::string m_particle_type_name; - SharedFunction m_function; - - public: - CustomFunctionEmitter(StringRef particle_type_name, SharedFunction &function) - : m_particle_type_name(particle_type_name.to_std_string()), m_function(function) - { - } - - void emit(EmitterInterface &interface) override; -}; - class InitialGridEmitter : public Emitter { private: - std::string m_particle_type_name; + Vector<std::string> m_types_to_emit; uint m_amount_x; uint m_amount_y; float m_step_x; @@ -95,13 +81,13 @@ class InitialGridEmitter : public Emitter { float m_size; public: - InitialGridEmitter(StringRef particle_type_name, + InitialGridEmitter(Vector<std::string> types_to_emit, uint amount_x, uint amount_y, float step_x, float step_y, float size) - : m_particle_type_name(particle_type_name.to_std_string()), + : m_types_to_emit(std::move(types_to_emit)), m_amount_x(amount_x), m_amount_y(amount_y), m_step_x(step_x), diff --git a/source/blender/simulations/bparticles/events.cpp b/source/blender/simulations/bparticles/events.cpp index 114fd0ef17a..7f82080a81f 100644 --- a/source/blender/simulations/bparticles/events.cpp +++ b/source/blender/simulations/bparticles/events.cpp @@ -136,24 +136,4 @@ void MeshCollisionEvent::execute(EventExecuteInterface &interface) m_action->execute_from_event(interface, &action_context); } -void CloseByPointsEvent::filter(EventFilterInterface &interface) -{ - ParticleSet particles = interface.particles(); - auto positions = particles.attributes().get<float3>("Position"); - - for (uint pindex : particles.pindices()) { - KDTreeNearest_3d nearest; - if (BLI_kdtree_3d_find_nearest(m_kdtree, positions[pindex], &nearest) != -1) { - if (float3::distance(positions[pindex], nearest.co) < m_distance) { - interface.trigger_particle(pindex, 0.5f); - } - } - } -} - -void CloseByPointsEvent::execute(EventExecuteInterface &interface) -{ - m_action->execute_from_event(interface); -} - } // namespace BParticles diff --git a/source/blender/simulations/bparticles/events.hpp b/source/blender/simulations/bparticles/events.hpp index 62ad35d43d9..11316f83aba 100644 --- a/source/blender/simulations/bparticles/events.hpp +++ b/source/blender/simulations/bparticles/events.hpp @@ -111,32 +111,4 @@ class MeshCollisionEvent : public Event { RayCastResult ray_cast(float3 start, float3 normalized_direction, float max_distance); }; -class CloseByPointsEvent : public Event { - private: - std::string m_identifier; - KDTree_3d *m_kdtree; - float m_distance; - std::unique_ptr<Action> m_action; - - public: - CloseByPointsEvent(StringRef identifier, - KDTree_3d *kdtree, - float distance, - std::unique_ptr<Action> action) - : m_identifier(identifier.to_std_string()), - m_kdtree(kdtree), - m_distance(distance), - m_action(std::move(action)) - { - } - - ~CloseByPointsEvent() - { - BLI_kdtree_3d_free(m_kdtree); - } - - void filter(EventFilterInterface &interface) override; - void execute(EventExecuteInterface &interface) override; -}; - } // namespace BParticles diff --git a/source/blender/simulations/bparticles/forces.cpp b/source/blender/simulations/bparticles/forces.cpp index 09afd175d82..51b88d2efdf 100644 --- a/source/blender/simulations/bparticles/forces.cpp +++ b/source/blender/simulations/bparticles/forces.cpp @@ -40,33 +40,4 @@ void TurbulenceForce::add_force(ForceInterface &interface) } } -void PointForce::add_force(ForceInterface &interface) -{ - ParticlesBlock &block = interface.block(); - MutableArrayRef<float3> destination = interface.combined_destination(); - - auto inputs = m_compute_inputs->compute(interface); - - for (uint pindex = 0; pindex < block.active_amount(); pindex++) { - float3 direction = inputs->get<float3>("Direction", 0, pindex); - float strength = inputs->get<float>("Strength", 1, pindex); - float falloff = inputs->get<float>("Falloff", 2, pindex); - float distance = inputs->get<float>("Distance", 3, pindex); - bool gravitation = inputs->get<bool>("Gravitation", 4, pindex); - - if (gravitation) { - if (distance < FLT_EPSILON) { - strength = 0.0f; - } - else { - strength *= powf(distance, -2.0f); - } - } - - direction *= (strength * falloff); - - destination[pindex] += direction; - } -} - } // namespace BParticles diff --git a/source/blender/simulations/bparticles/forces.hpp b/source/blender/simulations/bparticles/forces.hpp index 961e0a8ac20..1806713752d 100644 --- a/source/blender/simulations/bparticles/forces.hpp +++ b/source/blender/simulations/bparticles/forces.hpp @@ -38,17 +38,4 @@ class TurbulenceForce : public Force { void add_force(ForceInterface &interface) override; }; -class PointForce : public Force { - private: - std::unique_ptr<ParticleFunction> m_compute_inputs; - - public: - PointForce(std::unique_ptr<ParticleFunction> compute_inputs) - : m_compute_inputs(std::move(compute_inputs)) - { - } - - void add_force(ForceInterface &interface) override; -}; - } // namespace BParticles diff --git a/source/blender/simulations/bparticles/inserters.cpp b/source/blender/simulations/bparticles/inserters.cpp deleted file mode 100644 index c12aa99f2ff..00000000000 --- a/source/blender/simulations/bparticles/inserters.cpp +++ /dev/null @@ -1,471 +0,0 @@ - -#include "FN_data_flow_nodes.hpp" -#include "FN_tuple_call.hpp" -#include "FN_dependencies.hpp" -#include "FN_types.hpp" - -#include "BLI_timeit.hpp" -#include "BLI_lazy_init.hpp" - -#include "inserters.hpp" -#include "step_description.hpp" -#include "actions.hpp" -#include "emitters.hpp" -#include "events.hpp" -#include "forces.hpp" -#include "integrator.hpp" -#include "offset_handlers.hpp" -#include "particle_function_builder.hpp" - -namespace BParticles { - -using BLI::ValueOrError; -using FN::DataSocket; -using FN::FunctionBuilder; -using FN::FunctionGraph; -using FN::SharedDataGraph; -using FN::SharedFunction; -using FN::Type; - -static ValueOrError<SharedFunction> create_function__emitter_inputs(VirtualNode *emitter_vnode, - VTreeDataGraph &data_graph) -{ - Vector<DataSocket> sockets_to_compute = find_input_data_sockets(emitter_vnode, data_graph); - auto dependencies = data_graph.find_placeholder_dependencies(sockets_to_compute); - - if (dependencies.size() > 0) { - return BLI_ERROR_CREATE("Emitter inputs cannot have dependencies currently."); - } - - FunctionGraph fgraph(data_graph.graph(), {}, sockets_to_compute); - SharedFunction fn = fgraph.new_function(emitter_vnode->name()); - FN::fgraph_add_TupleCallBody(fn, fgraph); - return fn; -} - -static std::unique_ptr<Action> build_action(BuildContext &ctx, - VirtualSocket *start, - VirtualSocket *trigger); -using ActionFromNodeCallback = - std::function<std::unique_ptr<Action>(BuildContext &ctx, - VirtualSocket *start, - VirtualSocket *trigger, - std::unique_ptr<ParticleFunction> compute_inputs_fn)>; - -static std::unique_ptr<Action> BUILD_ACTION_kill( - BuildContext &UNUSED(ctx), - VirtualSocket *UNUSED(start), - VirtualSocket *UNUSED(trigger), - std::unique_ptr<ParticleFunction> UNUSED(compute_inputs_fn)) -{ - return std::unique_ptr<Action>(new KillAction()); -} - -static std::unique_ptr<Action> BUILD_ACTION_change_direction( - BuildContext &ctx, - VirtualSocket *start, - VirtualSocket *trigger, - std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - VirtualNode *vnode = start->vnode(); - auto post_action = build_action(ctx, vnode->output(0), trigger); - - return std::unique_ptr<ChangeDirectionAction>( - new ChangeDirectionAction(std::move(compute_inputs_fn), std::move(post_action))); -} - -static std::unique_ptr<Action> BUILD_ACTION_change_color( - BuildContext &ctx, - VirtualSocket *start, - VirtualSocket *trigger, - std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - VirtualNode *vnode = start->vnode(); - auto post_action = build_action(ctx, vnode->output(0), trigger); - - return std::unique_ptr<ChangeColorAction>( - new ChangeColorAction(std::move(compute_inputs_fn), std::move(post_action))); -} - -static std::unique_ptr<Action> BUILD_ACTION_explode( - BuildContext &ctx, - VirtualSocket *start, - VirtualSocket *trigger, - std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - VirtualNode *vnode = start->vnode(); - - PointerRNA rna = vnode->rna(); - char name[65]; - RNA_string_get(&rna, "particle_type_name", name); - - auto post_action = build_action(ctx, vnode->output(0), trigger); - auto new_particles_action = build_action(ctx, vnode->output(1), trigger); - - if (ctx.type_name_exists(name)) { - return std::unique_ptr<Action>(new ExplodeAction(name, - std::move(compute_inputs_fn), - std::move(post_action), - std::move(new_particles_action))); - } - else { - return post_action; - } -} - -static std::unique_ptr<Action> BUILD_ACTION_condition( - BuildContext &ctx, - VirtualSocket *start, - VirtualSocket *trigger, - std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - VirtualNode *vnode = start->vnode(); - auto true_action = build_action(ctx, vnode->output(0), trigger); - auto false_action = build_action(ctx, vnode->output(1), trigger); - - return std::unique_ptr<Action>(new ConditionAction( - std::move(compute_inputs_fn), std::move(true_action), std::move(false_action))); -} - -BLI_LAZY_INIT_STATIC(StringMap<ActionFromNodeCallback>, get_action_builders) -{ - StringMap<ActionFromNodeCallback> map; - map.add_new("bp_KillParticleNode", BUILD_ACTION_kill); - map.add_new("bp_ChangeParticleDirectionNode", BUILD_ACTION_change_direction); - map.add_new("bp_ExplodeParticleNode", BUILD_ACTION_explode); - map.add_new("bp_ParticleConditionNode", BUILD_ACTION_condition); - map.add_new("bp_ChangeParticleColorNode", BUILD_ACTION_change_color); - return map; -} - -static std::unique_ptr<Action> build_action(BuildContext &ctx, - VirtualSocket *start, - VirtualSocket *trigger) -{ - if (start->is_output()) { - ArrayRef<VirtualSocket *> linked = start->links(); - if (linked.size() == 0) { - return std::unique_ptr<Action>(new NoneAction()); - } - else if (linked.size() == 1) { - return build_action(ctx, linked[0], trigger); - } - else { - return nullptr; - } - } - - BLI_assert(start->is_input()); - VirtualNode *vnode = start->vnode(); - - auto fn_or_error = create_particle_function(vnode, ctx.data_graph); - if (fn_or_error.is_error()) { - return std::unique_ptr<Action>(new NoneAction()); - } - - StringRef idname = start->vnode()->idname(); - auto builders = get_action_builders(); - return builders.lookup(idname)(ctx, start, trigger, fn_or_error.extract_value()); -} - -static std::unique_ptr<Action> build_action_for_trigger(BuildContext &ctx, VirtualSocket *start) -{ - return build_action(ctx, start, start); -} - -static std::unique_ptr<Force> BUILD_FORCE_gravity( - BuildContext &UNUSED(ctx), - VirtualNode *UNUSED(vnode), - std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - return std::unique_ptr<Force>(new GravityForce(std::move(compute_inputs_fn))); -} - -static std::unique_ptr<Force> BUILD_FORCE_turbulence( - BuildContext &UNUSED(ctx), - VirtualNode *UNUSED(vnode), - std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - return std::unique_ptr<Force>(new TurbulenceForce(std::move(compute_inputs_fn))); -} - -static std::unique_ptr<Force> BUILD_FORCE_point( - BuildContext &UNUSED(ctx), - VirtualNode *UNUSED(vnode), - std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - return std::unique_ptr<Force>(new PointForce(std::move(compute_inputs_fn))); -} - -static std::unique_ptr<Event> BUILD_EVENT_mesh_collision( - BuildContext &ctx, VirtualNode *vnode, std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - if (compute_inputs_fn->parameter_depends_on_particle("Object", 0)) { - return {}; - } - - SharedFunction &fn = compute_inputs_fn->function_no_deps(); - TupleCallBody &body = fn->body<TupleCallBody>(); - FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); - body.call__setup_execution_context(fn_in, fn_out); - - Object *object = body.get_output<Object *>(fn_out, 0, "Object"); - if (object == nullptr || object->type != OB_MESH) { - return {}; - } - - auto action = build_action_for_trigger(ctx, vnode->output(0)); - return std::unique_ptr<Event>(new MeshCollisionEvent(vnode->name(), object, std::move(action))); -} - -static std::unique_ptr<Event> BUILD_EVENT_age_reached( - BuildContext &ctx, VirtualNode *vnode, std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - auto action = build_action_for_trigger(ctx, vnode->output(0)); - return std::unique_ptr<Event>( - new AgeReachedEvent(vnode->name(), std::move(compute_inputs_fn), std::move(action))); -} - -static std::unique_ptr<Event> BUILD_EVENT_close_by_points( - BuildContext &ctx, VirtualNode *vnode, std::unique_ptr<ParticleFunction> compute_inputs) -{ - if (compute_inputs->parameter_depends_on_particle("Points", 0)) { - return {}; - } - - auto action = build_action_for_trigger(ctx, vnode->output(0)); - - SharedFunction &fn = compute_inputs->function_no_deps(); - BLI_assert(fn->input_amount() == 0); - TupleCallBody &body = fn->body<TupleCallBody>(); - FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); - body.call__setup_execution_context(fn_in, fn_out); - - auto vectors = fn_out.relocate_out<FN::SharedList>(0); - float distance = body.get_output<float>(fn_out, 1, "Distance"); - - KDTree_3d *kdtree = BLI_kdtree_3d_new(vectors->size()); - for (float3 vector : vectors->as_array_ref<float3>()) { - BLI_kdtree_3d_insert(kdtree, 0, vector); - } - BLI_kdtree_3d_balance(kdtree); - - return std::unique_ptr<Event>( - new CloseByPointsEvent(vnode->name(), kdtree, distance, std::move(action))); -} - -static std::unique_ptr<Emitter> BUILD_EMITTER_mesh_surface(BuildContext &ctx, - VirtualNode *vnode, - StringRef particle_type_name) -{ - auto fn_or_error = create_function__emitter_inputs(vnode, ctx.data_graph); - if (fn_or_error.is_error()) { - return {}; - } - SharedFunction fn = fn_or_error.extract_value(); - - auto &body = fn->body<TupleCallBody>(); - FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); - body.call__setup_execution_context(fn_in, fn_out); - - auto on_birth_action = build_action_for_trigger(ctx, vnode->output(0)); - - Object *object = body.get_output<Object *>(fn_out, 0, "Object"); - if (object == nullptr) { - return {}; - } - InterpolatedFloat4x4 transform = ctx.world_state.get_interpolated_value(vnode->name(), - object->obmat); - - return std::unique_ptr<SurfaceEmitter>( - new SurfaceEmitter(particle_type_name, - std::move(on_birth_action), - object, - transform, - body.get_output<float>(fn_out, 1, "Rate"), - body.get_output<float>(fn_out, 2, "Normal Velocity"), - body.get_output<float>(fn_out, 3, "Emitter Velocity"), - body.get_output<float>(fn_out, 4, "Size"))); -} - -static std::unique_ptr<Emitter> BUILD_EMITTER_moving_point(BuildContext &ctx, - VirtualNode *vnode, - StringRef particle_type_name) -{ - auto fn_or_error = create_function__emitter_inputs(vnode, ctx.data_graph); - if (fn_or_error.is_error()) { - return {}; - } - SharedFunction fn = fn_or_error.extract_value(); - - auto &body = fn->body<TupleCallBody>(); - FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); - body.call__setup_execution_context(fn_in, fn_out); - - StringRef bnode_name = vnode->name(); - - auto point = ctx.world_state.get_interpolated_value( - bnode_name + StringRef("Position"), body.get_output<float3>(fn_out, 0, "Position")); - auto velocity = ctx.world_state.get_interpolated_value( - bnode_name + StringRef("Velocity"), body.get_output<float3>(fn_out, 1, "Velocity")); - auto size = ctx.world_state.get_interpolated_value(bnode_name + StringRef("Size"), - body.get_output<float>(fn_out, 2, "Size")); - return std::unique_ptr<PointEmitter>( - new PointEmitter(particle_type_name, 10, point, velocity, size)); -} - -static void match_inputs_to_node_outputs(FN::DataGraphBuilder &builder, - FN::BuilderNode *target_node, - FN::BuilderNode *origin_node_1, - FN::BuilderNode *origin_node_2) -{ - SharedFunction &target_fn = target_node->function(); - SharedFunction &origin_fn_1 = origin_node_1->function(); - - uint offset = 0; - for (uint i = 0; i < target_fn->input_amount(); i++) { - StringRef input_name = target_fn->input_name(i); - FN::Type *input_type = target_fn->input_type(i); - - bool is_reserved_input = false; - for (uint j = 0; j < origin_fn_1->output_amount(); j++) { - if (origin_fn_1->output_name(j) == input_name && origin_fn_1->output_type(j) == input_type) { - builder.insert_link(origin_node_1->output(j), target_node->input(i)); - is_reserved_input = true; - } - } - - if (!is_reserved_input) { - builder.insert_link(origin_node_2->output(offset), target_node->input(i)); - offset++; - } - } -} - -static FN::FunctionGraph link_inputs_to_function(SharedFunction &main_fn, - SharedFunction &inputs_fn, - SharedFunction &reserved_fn) -{ - FN::DataGraphBuilder builder; - FN::BuilderNode *main_node = builder.insert_function(main_fn); - FN::BuilderNode *inputs_node = builder.insert_function(inputs_fn); - FN::BuilderNode *reserved_node = builder.insert_function(reserved_fn); - - match_inputs_to_node_outputs(builder, main_node, reserved_node, inputs_node); - - SharedDataGraph data_graph = builder.build(); - - auto final_inputs = reserved_node->built_outputs(); - auto final_outputs = main_node->built_outputs(); - return FN::FunctionGraph(data_graph, final_inputs, final_outputs); -} - -static std::unique_ptr<Emitter> BUILD_EMITTER_custom_function(BuildContext &ctx, - VirtualNode *vnode, - StringRef particle_type_name) -{ - PointerRNA rna = vnode->rna(); - bNodeTree *btree = (bNodeTree *)RNA_pointer_get(&rna, "function_tree").data; - if (btree == nullptr) { - return {}; - } - - auto fn_emitter_or_error = FN::DataFlowNodes::generate_function(btree); - auto fn_inputs_or_error = create_function__emitter_inputs(vnode, ctx.data_graph); - if (fn_emitter_or_error.is_error()) { - return {}; - } - if (fn_inputs_or_error.is_error()) { - return {}; - } - SharedFunction fn_emitter = fn_emitter_or_error.extract_value(); - SharedFunction fn_inputs = fn_inputs_or_error.extract_value(); - - FN::FunctionBuilder fn_builder; - fn_builder.add_output("Start Time", FN::Types::TYPE_float); - fn_builder.add_output("Time Step", FN::Types::TYPE_float); - SharedFunction fn_reserved_inputs = fn_builder.build("Reserved Inputs"); - - FN::FunctionGraph fgraph = link_inputs_to_function(fn_emitter, fn_inputs, fn_reserved_inputs); - auto fn = fgraph.new_function("Emitter"); - FN::fgraph_add_DependenciesBody(fn, fgraph); - FN::fgraph_add_TupleCallBody(fn, fgraph); - - return std::unique_ptr<Emitter>(new CustomFunctionEmitter(particle_type_name, fn)); -} - -static std::unique_ptr<Emitter> BUILD_EMITTER_initial_grid(BuildContext &ctx, - VirtualNode *vnode, - StringRef particle_type_name) -{ - auto fn_or_error = create_function__emitter_inputs(vnode, ctx.data_graph); - if (fn_or_error.is_error()) { - return {}; - } - - SharedFunction fn = fn_or_error.extract_value(); - TupleCallBody &body = fn->body<TupleCallBody>(); - FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); - body.call__setup_execution_context(fn_in, fn_out); - - return std::unique_ptr<Emitter>( - new InitialGridEmitter(particle_type_name, - body.get_output<uint>(fn_out, 0, "Amount X"), - body.get_output<uint>(fn_out, 1, "Amount Y"), - body.get_output<float>(fn_out, 2, "Step X"), - body.get_output<float>(fn_out, 3, "Step Y"), - body.get_output<float>(fn_out, 4, "Size"))); -} - -static std::unique_ptr<OffsetHandler> BUILD_OFFSET_HANDLER_trails( - BuildContext &ctx, VirtualNode *vnode, std::unique_ptr<ParticleFunction> compute_inputs_fn) -{ - PointerRNA rna = vnode->rna(); - char name[65]; - RNA_string_get(&rna, "particle_type_name", name); - - if (ctx.type_name_exists(name)) { - return std::unique_ptr<OffsetHandler>( - new CreateTrailHandler(name, std::move(compute_inputs_fn))); - } - else { - return {}; - } -} - -BLI_LAZY_INIT(StringMap<ForceFromNodeCallback>, get_force_builders) -{ - StringMap<ForceFromNodeCallback> map; - map.add_new("bp_GravityForceNode", BUILD_FORCE_gravity); - map.add_new("bp_TurbulenceForceNode", BUILD_FORCE_turbulence); - map.add_new("bp_PointForceNode", BUILD_FORCE_point); - return map; -} - -BLI_LAZY_INIT(StringMap<EventFromNodeCallback>, get_event_builders) -{ - StringMap<EventFromNodeCallback> map; - map.add_new("bp_MeshCollisionEventNode", BUILD_EVENT_mesh_collision); - map.add_new("bp_AgeReachedEventNode", BUILD_EVENT_age_reached); - map.add_new("bp_CloseByPointsEventNode", BUILD_EVENT_close_by_points); - return map; -} - -BLI_LAZY_INIT(StringMap<EmitterFromNodeCallback>, get_emitter_builders) -{ - StringMap<EmitterFromNodeCallback> map; - map.add_new("bp_PointEmitterNode", BUILD_EMITTER_moving_point); - map.add_new("bp_MeshEmitterNode", BUILD_EMITTER_mesh_surface); - map.add_new("bp_CustomEmitterNode", BUILD_EMITTER_custom_function); - map.add_new("bp_InitialGridEmitterNode", BUILD_EMITTER_initial_grid); - return map; -} - -BLI_LAZY_INIT(StringMap<OffsetHandlerFromNodeCallback>, get_offset_handler_builders) -{ - StringMap<OffsetHandlerFromNodeCallback> map; - map.add_new("bp_ParticleTrailsNode", BUILD_OFFSET_HANDLER_trails); - return map; -} - -} // namespace BParticles diff --git a/source/blender/simulations/bparticles/inserters.hpp b/source/blender/simulations/bparticles/inserters.hpp deleted file mode 100644 index 8fa2aa31f8c..00000000000 --- a/source/blender/simulations/bparticles/inserters.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include <functional> - -#include "BKE_node_tree.hpp" -#include "FN_data_flow_nodes.hpp" -#include "BLI_string_map.hpp" -#include "BLI_value_or_error.hpp" - -#include "world_state.hpp" -#include "step_description.hpp" -#include "forces.hpp" -#include "particle_function.hpp" - -namespace BParticles { - -using BKE::VirtualLink; -using BKE::VirtualNode; -using BKE::VirtualNodeTree; -using BKE::VirtualSocket; -using BLI::StringMap; -using BLI::ValueOrError; -using FN::DataFlowNodes::VTreeDataGraph; - -struct BuildContext { - VTreeDataGraph &data_graph; - Set<std::string> &particle_type_names; - WorldState &world_state; - - bool type_name_exists(StringRef name) - { - return this->particle_type_names.contains(name.to_std_string()); - } -}; - -using ForceFromNodeCallback = std::function<std::unique_ptr<Force>( - BuildContext &ctx, VirtualNode *vnode, std::unique_ptr<ParticleFunction> compute_inputs_fn)>; - -using EventFromNodeCallback = std::function<std::unique_ptr<Event>( - BuildContext &ctx, VirtualNode *vnode, std::unique_ptr<ParticleFunction> compute_inputs_fn)>; - -using EmitterFromNodeCallback = std::function<std::unique_ptr<Emitter>( - BuildContext &ctx, VirtualNode *vnode, StringRef particle_type_name)>; - -using OffsetHandlerFromNodeCallback = std::function<std::unique_ptr<OffsetHandler>( - BuildContext &ctx, VirtualNode *vnode, std::unique_ptr<ParticleFunction> compute_inputs_fn)>; - -StringMap<ForceFromNodeCallback> &get_force_builders(); -StringMap<EventFromNodeCallback> &get_event_builders(); -StringMap<EmitterFromNodeCallback> &get_emitter_builders(); -StringMap<OffsetHandlerFromNodeCallback> &get_offset_handler_builders(); - -} // namespace BParticles diff --git a/source/blender/simulations/bparticles/node_frontend.cpp b/source/blender/simulations/bparticles/node_frontend.cpp index fa20bf8ab12..cd2c45a9356 100644 --- a/source/blender/simulations/bparticles/node_frontend.cpp +++ b/source/blender/simulations/bparticles/node_frontend.cpp @@ -1,40 +1,437 @@ +#include "BKE_node_tree.hpp" + #include "BLI_timeit.hpp" #include "BLI_multi_map.hpp" +#include "BLI_lazy_init.hpp" #include "node_frontend.hpp" -#include "inserters.hpp" #include "integrator.hpp" #include "particle_function_builder.hpp" +#include "emitters.hpp" +#include "events.hpp" +#include "offset_handlers.hpp" namespace BParticles { +using BKE::VirtualNode; +using BKE::VirtualSocket; using BLI::MultiMap; using BLI::ValueOrError; +using FN::Function; +using FN::FunctionBuilder; +using FN::FunctionGraph; +using FN::SharedDataGraph; +using FN::DataFlowNodes::VTreeDataGraph; + +class BehaviorCollector { + public: + Vector<Emitter *> m_emitters; + MultiMap<std::string, Force *> m_forces; + MultiMap<std::string, Event *> m_events; + MultiMap<std::string, OffsetHandler *> m_offset_handlers; +}; static bool is_particle_type_node(VirtualNode *vnode) { return STREQ(vnode->bnode()->idname, "bp_ParticleTypeNode"); } -static bool is_emitter_socket(VirtualSocket *vsocket) +static std::unique_ptr<Action> build_action_list(VTreeDataGraph &vtree_data_graph, + VirtualNode *start_vnode, + StringRef name); + +static Vector<VirtualNode *> find_connected_particle_type_nodes(VirtualSocket *output_socket) { - return STREQ(vsocket->bsocket()->idname, "bp_EmitterSocket"); + BLI_assert(output_socket->is_output()); + Vector<VirtualNode *> type_nodes; + for (VirtualSocket *connected : output_socket->links()) { + VirtualNode *connected_vnode = connected->vnode(); + if (is_particle_type_node(connected_vnode)) { + type_nodes.append(connected_vnode); + } + } + return type_nodes; +} + +static Vector<std::string> find_connected_particle_type_names(VirtualSocket *output_socket) +{ + Vector<std::string> type_names; + for (VirtualNode *vnode : find_connected_particle_type_nodes(output_socket)) { + type_names.append(vnode->name()); + } + return type_names; } -static VirtualSocket *find_emitter_output(VirtualNode *vnode) +static Vector<VirtualSocket *> find_execute_sockets(VirtualNode *vnode, StringRef name_prefix) { - for (VirtualSocket *vsocket : vnode->outputs()) { - if (is_emitter_socket(vsocket)) { - return vsocket; + Vector<VirtualSocket *> execute_sockets; + for (VirtualSocket *vsocket : vnode->inputs()) { + if (StringRef(vsocket->name()).startswith(name_prefix)) { + if (STREQ(vsocket->idname(), "fn_OperatorSocket")) { + break; + } + else { + execute_sockets.append(vsocket); + } } } - BLI_assert(false); - return nullptr; + return execute_sockets; } -static ArrayRef<VirtualNode *> get_type_nodes(VirtualNodeTree &vtree) +using ActionParserCallback = std::function<std::unique_ptr<Action>( + VTreeDataGraph &vtree_data_graph, VirtualSocket *execute_vsocket)>; + +static std::unique_ptr<Action> ACTION_kill(VTreeDataGraph &UNUSED(vtree_data_graph), + VirtualSocket *UNUSED(execute_vsocket)) { - return vtree.nodes_with_idname("bp_ParticleTypeNode"); + return std::unique_ptr<Action>(new KillAction()); +} + +static std::unique_ptr<Action> ACTION_change_direction(VTreeDataGraph &vtree_data_graph, + VirtualSocket *execute_vsocket) +{ + VirtualNode *vnode = execute_vsocket->vnode(); + + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + return {}; + } + std::unique_ptr<ParticleFunction> compute_inputs_fn = fn_or_error.extract_value(); + + Action *action = new ChangeDirectionAction(std::move(compute_inputs_fn)); + return std::unique_ptr<Action>(action); +} + +static std::unique_ptr<Action> ACTION_explode(VTreeDataGraph &vtree_data_graph, + VirtualSocket *execute_vsocket) +{ + VirtualNode *vnode = execute_vsocket->vnode(); + + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + return {}; + } + std::unique_ptr<ParticleFunction> compute_inputs_fn = fn_or_error.extract_value(); + + std::unique_ptr<Action> on_birth_action = build_action_list( + vtree_data_graph, vnode, "Execute on Event"); + Vector<std::string> type_names = find_connected_particle_type_names(vnode->output(1, "Type")); + + Action *action = new ExplodeAction( + type_names, std::move(compute_inputs_fn), std::move(on_birth_action)); + return std::unique_ptr<Action>(action); +} + +static std::unique_ptr<Action> ACTION_condition(VTreeDataGraph &vtree_data_graph, + VirtualSocket *execute_vsocket) +{ + VirtualNode *vnode = execute_vsocket->vnode(); + + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + return {}; + } + std::unique_ptr<ParticleFunction> compute_inputs_fn = fn_or_error.extract_value(); + + auto action_true = build_action_list(vtree_data_graph, vnode, "Execute If True"); + auto action_false = build_action_list(vtree_data_graph, vnode, "Execute If False"); + + Action *action = new ConditionAction( + std::move(compute_inputs_fn), std::move(action_true), std::move(action_false)); + return std::unique_ptr<Action>(action); +} + +static std::unique_ptr<Action> ACTION_change_color(VTreeDataGraph &vtree_data_graph, + VirtualSocket *execute_vsocket) +{ + VirtualNode *vnode = execute_vsocket->vnode(); + + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + return {}; + } + std::unique_ptr<ParticleFunction> compute_inputs_fn = fn_or_error.extract_value(); + + Action *action = new ChangeColorAction(std::move(compute_inputs_fn)); + return std::unique_ptr<Action>(action); +} + +BLI_LAZY_INIT_STATIC(StringMap<ActionParserCallback>, get_action_parsers) +{ + StringMap<ActionParserCallback> map; + map.add_new("bp_KillParticleNode", ACTION_kill); + map.add_new("bp_ChangeParticleDirectionNode", ACTION_change_direction); + map.add_new("bp_ExplodeParticleNode", ACTION_explode); + map.add_new("bp_ParticleConditionNode", ACTION_condition); + map.add_new("bp_ChangeParticleColorNode", ACTION_change_color); + return map; +} + +static std::unique_ptr<Action> build_action(VTreeDataGraph &vtree_data_graph, VirtualSocket *start) +{ + BLI_assert(start->is_input()); + if (start->links().size() != 1) { + return std::unique_ptr<Action>(new NoneAction()); + } + + VirtualSocket *execute_socket = start->links()[0]; + if (!STREQ(execute_socket->idname(), "bp_ExecuteSocket")) { + return std::unique_ptr<Action>(new NoneAction()); + } + + StringMap<ActionParserCallback> &parsers = get_action_parsers(); + ActionParserCallback &parser = parsers.lookup(execute_socket->vnode()->idname()); + std::unique_ptr<Action> action = parser(vtree_data_graph, execute_socket); + if (action.get() == nullptr) { + return std::unique_ptr<Action>(new NoneAction()); + } + return action; +} + +static std::unique_ptr<Action> build_action_list(VTreeDataGraph &vtree_data_graph, + VirtualNode *start_vnode, + StringRef name) +{ + Vector<VirtualSocket *> execute_sockets = find_execute_sockets(start_vnode, name); + Vector<std::unique_ptr<Action>> actions; + for (VirtualSocket *socket : execute_sockets) { + actions.append(build_action(vtree_data_graph, socket)); + } + Action *sequence = new ActionSequence(std::move(actions)); + return std::unique_ptr<Action>(sequence); +} + +using ParseNodeCallback = std::function<void(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &state, + VirtualNode *vnode)>; + +static SharedFunction get_compute_data_inputs_function(VTreeDataGraph &vtree_data_graph, + VirtualNode *vnode) +{ + SharedDataGraph &data_graph = vtree_data_graph.graph(); + + SetVector<DataSocket> function_outputs; + for (VirtualSocket *vsocket : vnode->inputs()) { + if (vtree_data_graph.uses_socket(vsocket)) { + DataSocket socket = vtree_data_graph.lookup_socket(vsocket); + function_outputs.add(socket); + } + } + + FunctionGraph fgraph(data_graph, {}, function_outputs); + SharedFunction fn = fgraph.new_function(vnode->name()); + FN::fgraph_add_TupleCallBody(fn, fgraph); + FN::fgraph_add_LLVMBuildIRBody(fn, fgraph); + return fn; +} + +static void PARSE_point_emitter(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &world_state, + VirtualNode *vnode) +{ + SharedFunction compute_inputs_fn = get_compute_data_inputs_function(vtree_data_graph, vnode); + TupleCallBody &body = compute_inputs_fn->body<TupleCallBody>(); + + FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); + body.call__setup_execution_context(fn_in, fn_out); + + float3 current_position = body.get_output<float3>(fn_out, 0, "Position"); + float3 current_velocity = body.get_output<float3>(fn_out, 1, "Velocity"); + float current_size = body.get_output<float>(fn_out, 2, "Size"); + + StringRef node_name = vnode->name(); + InterpolatedFloat3 position = world_state.get_interpolated_value(node_name + "Position", + current_position); + InterpolatedFloat3 velocity = world_state.get_interpolated_value(node_name + "Velocity", + current_velocity); + InterpolatedFloat size = world_state.get_interpolated_value(node_name + "Size", current_size); + + Vector<std::string> type_names = find_connected_particle_type_names(vnode->output(0, "Emitter")); + PointEmitter *emitter = new PointEmitter(std::move(type_names), 10, position, velocity, size); + collector.m_emitters.append(emitter); +} + +static void PARSE_mesh_emitter(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &world_state, + VirtualNode *vnode) +{ + SharedFunction compute_inputs_fn = get_compute_data_inputs_function(vtree_data_graph, vnode); + TupleCallBody &body = compute_inputs_fn->body<TupleCallBody>(); + + FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); + body.call__setup_execution_context(fn_in, fn_out); + + std::unique_ptr<Action> on_birth_action = build_action_list( + vtree_data_graph, vnode, "Execute on Birth"); + + Object *object = body.get_output<Object *>(fn_out, 0, "Object"); + if (object == nullptr) { + return; + } + + InterpolatedFloat4x4 transform = world_state.get_interpolated_value(vnode->name(), + object->obmat); + Vector<std::string> type_names = find_connected_particle_type_names(vnode->output(0, "Emitter")); + Emitter *emitter = new SurfaceEmitter(std::move(type_names), + std::move(on_birth_action), + object, + transform, + body.get_output<float>(fn_out, 1, "Rate"), + body.get_output<float>(fn_out, 2, "Normal Velocity"), + body.get_output<float>(fn_out, 3, "Emitter Velocity"), + body.get_output<float>(fn_out, 4, "Size")); + collector.m_emitters.append(emitter); +} + +static void PARSE_gravity_force(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &UNUSED(world_state), + VirtualNode *vnode) +{ + Vector<std::string> type_names = find_connected_particle_type_names(vnode->output(0, "Force")); + for (std::string &type_name : type_names) { + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + continue; + } + std::unique_ptr<ParticleFunction> compute_inputs = fn_or_error.extract_value(); + + GravityForce *force = new GravityForce(std::move(compute_inputs)); + collector.m_forces.add(type_name, force); + } +} + +static void PARSE_age_reached_event(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &UNUSED(world_state), + VirtualNode *vnode) +{ + Vector<std::string> type_names = find_connected_particle_type_names(vnode->output(0, "Event")); + for (std::string &type_name : type_names) { + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + continue; + } + std::unique_ptr<ParticleFunction> compute_inputs = fn_or_error.extract_value(); + auto action = build_action_list(vtree_data_graph, vnode, "Execute on Event"); + + Event *event = new AgeReachedEvent( + vnode->name(), std::move(compute_inputs), std::move(action)); + collector.m_events.add(type_name, event); + } +} + +static void PARSE_trails(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &UNUSED(world_state), + VirtualNode *vnode) +{ + Vector<std::string> main_type_names = find_connected_particle_type_names( + vnode->output(0, "Main Type")); + Vector<std::string> trail_type_names = find_connected_particle_type_names( + vnode->output(1, "Trail Type")); + + for (std::string &main_type : main_type_names) { + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + continue; + } + std::unique_ptr<ParticleFunction> compute_inputs = fn_or_error.extract_value(); + auto action = build_action_list(vtree_data_graph, vnode, "Execute on Birth"); + + OffsetHandler *offset_handler = new CreateTrailHandler( + trail_type_names, std::move(compute_inputs), std::move(action)); + collector.m_offset_handlers.add(main_type, offset_handler); + } +} + +static void PARSE_initial_grid_emitter(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &UNUSED(world_state), + VirtualNode *vnode) +{ + SharedFunction compute_inputs_fn = get_compute_data_inputs_function(vtree_data_graph, vnode); + TupleCallBody &body = compute_inputs_fn->body<TupleCallBody>(); + + FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); + body.call__setup_execution_context(fn_in, fn_out); + + Vector<std::string> type_names = find_connected_particle_type_names(vnode->output(0, "Emitter")); + Emitter *emitter = new InitialGridEmitter(std::move(type_names), + body.get_output<uint>(fn_out, 0, "Amount X"), + body.get_output<uint>(fn_out, 1, "Amount Y"), + body.get_output<float>(fn_out, 2, "Step X"), + body.get_output<float>(fn_out, 3, "Step Y"), + body.get_output<float>(fn_out, 4, "Size")); + collector.m_emitters.append(emitter); +} + +static void PARSE_turbulence_force(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &UNUSED(world_state), + VirtualNode *vnode) +{ + Vector<std::string> type_names = find_connected_particle_type_names(vnode->output(0, "Force")); + for (std::string &type_name : type_names) { + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + continue; + } + std::unique_ptr<ParticleFunction> compute_inputs = fn_or_error.extract_value(); + + Force *force = new TurbulenceForce(std::move(compute_inputs)); + collector.m_forces.add(type_name, force); + } +} + +static void PARSE_mesh_collision(BehaviorCollector &collector, + VTreeDataGraph &vtree_data_graph, + WorldState &UNUSED(world_state), + VirtualNode *vnode) +{ + Vector<std::string> type_names = find_connected_particle_type_names(vnode->output(0, "Event")); + for (std::string &type_name : type_names) { + auto fn_or_error = create_particle_function(vnode, vtree_data_graph); + if (fn_or_error.is_error()) { + continue; + } + std::unique_ptr<ParticleFunction> compute_inputs_fn = fn_or_error.extract_value(); + + if (compute_inputs_fn->parameter_depends_on_particle("Object", 0)) { + continue; + } + + SharedFunction &fn = compute_inputs_fn->function_no_deps(); + TupleCallBody &body = fn->body<TupleCallBody>(); + FN_TUPLE_CALL_ALLOC_TUPLES(body, fn_in, fn_out); + body.call__setup_execution_context(fn_in, fn_out); + + Object *object = body.get_output<Object *>(fn_out, 0, "Object"); + if (object == nullptr || object->type != OB_MESH) { + return; + } + + auto action = build_action_list(vtree_data_graph, vnode, "Execute on Event"); + Event *event = new MeshCollisionEvent(vnode->name(), object, std::move(action)); + collector.m_events.add(type_name, event); + } +} + +BLI_LAZY_INIT_STATIC(StringMap<ParseNodeCallback>, get_node_parsers) +{ + StringMap<ParseNodeCallback> map; + map.add_new("bp_PointEmitterNode", PARSE_point_emitter); + map.add_new("bp_MeshEmitterNode", PARSE_mesh_emitter); + map.add_new("bp_GravityForceNode", PARSE_gravity_force); + map.add_new("bp_AgeReachedEventNode", PARSE_age_reached_event); + map.add_new("bp_ParticleTrailsNode", PARSE_trails); + map.add_new("bp_InitialGridEmitterNode", PARSE_initial_grid_emitter); + map.add_new("bp_TurbulenceForceNode", PARSE_turbulence_force); + map.add_new("bp_MeshCollisionEventNode", PARSE_mesh_collision); + return map; } std::unique_ptr<StepDescription> step_description_from_node_tree(VirtualNodeTree &vtree, @@ -43,128 +440,51 @@ std::unique_ptr<StepDescription> step_description_from_node_tree(VirtualNodeTree { SCOPED_TIMER(__func__); - Set<std::string> particle_type_names; - StringMap<AttributesDeclaration> declarations; - - for (VirtualNode *particle_type_node : get_type_nodes(vtree)) { - AttributesDeclaration attributes; - attributes.add<float3>("Position", {0, 0, 0}); - attributes.add<float3>("Velocity", {0, 0, 0}); - attributes.add<float>("Size", 0.01f); - attributes.add<rgba_f>("Color", {1.0f, 1.0f, 1.0f, 1.0f}); - declarations.add_new(particle_type_node->name(), attributes); - particle_type_names.add_new(particle_type_node->name()); - } - - ValueOrError<VTreeDataGraph> data_graph_or_error = FN::DataFlowNodes::generate_graph(vtree); + auto data_graph_or_error = FN::DataFlowNodes::generate_graph(vtree); if (data_graph_or_error.is_error()) { return {}; } + VTreeDataGraph vtree_data_graph = data_graph_or_error.extract_value(); - VTreeDataGraph data_graph = data_graph_or_error.extract_value(); - - BuildContext ctx = {data_graph, particle_type_names, world_state}; - - MultiMap<std::string, Force *> forces; - get_force_builders().foreach_key_value_pair( - [&vtree, &data_graph, &ctx, &forces](StringRefNull idname, - const ForceFromNodeCallback &callback) { - for (VirtualNode *vnode : vtree.nodes_with_idname(idname)) { - for (VirtualSocket *linked : vnode->output(0)->links()) { - if (is_particle_type_node(linked->vnode())) { - auto fn_or_error = create_particle_function(vnode, data_graph); - if (fn_or_error.is_error()) { - continue; - } - - auto force = callback(ctx, vnode, fn_or_error.extract_value()); - if (force) { - forces.add(linked->vnode()->name(), force.release()); - } - } - } - } - }); - - MultiMap<std::string, OffsetHandler *> offset_handlers; - get_offset_handler_builders().foreach_key_value_pair( - [&vtree, &data_graph, &ctx, &offset_handlers]( - StringRefNull idname, const OffsetHandlerFromNodeCallback &callback) { - for (VirtualNode *vnode : vtree.nodes_with_idname(idname)) { - for (VirtualSocket *linked : vnode->output(0)->links()) { - if (is_particle_type_node(linked->vnode())) { - auto fn_or_error = create_particle_function(vnode, data_graph); - if (fn_or_error.is_error()) { - continue; - } - - auto listener = callback(ctx, vnode, fn_or_error.extract_value()); - if (listener) { - offset_handlers.add(linked->vnode()->name(), listener.release()); - } - } - } - } - }); - - MultiMap<std::string, Event *> events; - get_event_builders().foreach_key_value_pair( - [&vtree, &data_graph, &ctx, &events](StringRefNull idname, - const EventFromNodeCallback &callback) { - for (VirtualNode *vnode : vtree.nodes_with_idname(idname)) { - for (VirtualSocket *linked : vnode->input(0)->links()) { - if (is_particle_type_node(linked->vnode())) { - auto fn_or_error = create_particle_function(vnode, data_graph); - if (fn_or_error.is_error()) { - continue; - } - - auto event = callback(ctx, vnode, fn_or_error.extract_value()); - if (event) { - events.add(linked->vnode()->name(), event.release()); - } - } - } - } - }); - - Vector<Emitter *> emitters; - get_emitter_builders().foreach_key_value_pair( - [&vtree, &ctx, &emitters](StringRefNull idname, const EmitterFromNodeCallback &callback) { - for (VirtualNode *vnode : vtree.nodes_with_idname(idname)) { - VirtualSocket *emitter_output = find_emitter_output(vnode); - for (VirtualSocket *linked : emitter_output->links()) { - if (is_particle_type_node(linked->vnode())) { - auto emitter = callback(ctx, vnode, linked->vnode()->name()); - if (emitter) { - emitters.append(emitter.release()); - } - } - } - } - }); - - StringMap<ParticleType *> particle_types; - for (VirtualNode *vnode : get_type_nodes(vtree)) { - std::string name = vnode->name(); - ArrayRef<Force *> forces_on_type = forces.lookup_default(name); - - Integrator *integrator = nullptr; - if (forces_on_type.size() == 0) { - integrator = new ConstantVelocityIntegrator(); - } - else { - integrator = new EulerIntegrator(forces_on_type); + BehaviorCollector collector; + + StringMap<ParseNodeCallback> &parsers = get_node_parsers(); + + for (VirtualNode *vnode : vtree.nodes()) { + StringRef idname = vnode->idname(); + ParseNodeCallback *callback = parsers.lookup_ptr(idname); + if (callback != nullptr) { + (*callback)(collector, vtree_data_graph, world_state, vnode); } + } + + StringMap<ParticleType *> types; + + Vector<std::string> type_names; + for (VirtualNode *vnode : vtree.nodes_with_idname("bp_ParticleTypeNode")) { + StringRef name = vnode->name(); + type_names.append(name.to_std_string()); + } + + for (std::string &type_name : type_names) { + AttributesDeclaration attributes; + attributes.add<float3>("Position", float3(0, 0, 0)); + attributes.add<float3>("Velocity", float3(0, 0, 0)); + attributes.add<float>("Size", 0.05f); + attributes.add<rgba_f>("Color", rgba_f(1, 1, 1, 1)); + + ArrayRef<Force *> forces = collector.m_forces.lookup_default(type_name); + EulerIntegrator *integrator = new EulerIntegrator(forces); + + ArrayRef<Event *> events = collector.m_events.lookup_default(type_name); + ArrayRef<OffsetHandler *> offset_handlers = collector.m_offset_handlers.lookup_default( + type_name); - ParticleType *particle_type = new ParticleType(declarations.lookup(name), - integrator, - events.lookup_default(name), - offset_handlers.lookup_default(name)); - particle_types.add_new(name, particle_type); + ParticleType *type = new ParticleType(attributes, integrator, events, offset_handlers); + types.add_new(type_name, type); } - StepDescription *step_description = new StepDescription(time_step, particle_types, emitters); + StepDescription *step_description = new StepDescription(time_step, types, collector.m_emitters); return std::unique_ptr<StepDescription>(step_description); } diff --git a/source/blender/simulations/bparticles/offset_handlers.cpp b/source/blender/simulations/bparticles/offset_handlers.cpp index 8a5ceceb099..400a8a1d63f 100644 --- a/source/blender/simulations/bparticles/offset_handlers.cpp +++ b/source/blender/simulations/bparticles/offset_handlers.cpp @@ -32,10 +32,13 @@ void CreateTrailHandler::execute(OffsetHandlerInterface &interface) } } - auto new_particles = interface.particle_allocator().request(m_particle_type_name, - new_positions.size()); - new_particles.set<float3>("Position", new_positions); - new_particles.set<float>("Birth Time", new_birth_times); + for (std::string &type_name : m_types_to_emit) { + auto new_particles = interface.particle_allocator().request(type_name, new_positions.size()); + new_particles.set<float3>("Position", new_positions); + new_particles.set<float>("Birth Time", new_birth_times); + + m_on_birth_action->execute_for_new_particles(new_particles, interface); + } } } // namespace BParticles diff --git a/source/blender/simulations/bparticles/offset_handlers.hpp b/source/blender/simulations/bparticles/offset_handlers.hpp index fb745255ffd..02c540562f3 100644 --- a/source/blender/simulations/bparticles/offset_handlers.hpp +++ b/source/blender/simulations/bparticles/offset_handlers.hpp @@ -7,14 +7,17 @@ namespace BParticles { class CreateTrailHandler : public OffsetHandler { private: - std::string m_particle_type_name; + Vector<std::string> m_types_to_emit; std::unique_ptr<ParticleFunction> m_compute_inputs; + std::unique_ptr<Action> m_on_birth_action; public: - CreateTrailHandler(StringRef particle_type_name, - std::unique_ptr<ParticleFunction> compute_inputs) - : m_particle_type_name(particle_type_name.to_std_string()), - m_compute_inputs(std::move(compute_inputs)) + CreateTrailHandler(Vector<std::string> types_to_emit, + std::unique_ptr<ParticleFunction> compute_inputs, + std::unique_ptr<Action> on_birth_action) + : m_types_to_emit(std::move(types_to_emit)), + m_compute_inputs(std::move(compute_inputs)), + m_on_birth_action(std::move(on_birth_action)) { } |