Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <mail@jlucke.com>2019-08-23 16:41:33 +0300
committerJacques Lucke <mail@jlucke.com>2019-08-23 16:41:33 +0300
commit4d2dcb6a5fbd075df16db169460e4d3791289475 (patch)
tree37de54d82c74b652b1289123a0f9b5d578eb3c6e /source/blender/simulations/bparticles
parent9c05112910946581ccf17b23fc0ec5f0297467a3 (diff)
Initial implementation of updated ui proposal
Diffstat (limited to 'source/blender/simulations/bparticles')
-rw-r--r--source/blender/simulations/bparticles/action_interface.hpp25
-rw-r--r--source/blender/simulations/bparticles/actions.cpp27
-rw-r--r--source/blender/simulations/bparticles/actions.hpp39
-rw-r--r--source/blender/simulations/bparticles/emitters.cpp100
-rw-r--r--source/blender/simulations/bparticles/emitters.hpp38
-rw-r--r--source/blender/simulations/bparticles/events.cpp20
-rw-r--r--source/blender/simulations/bparticles/events.hpp28
-rw-r--r--source/blender/simulations/bparticles/forces.cpp29
-rw-r--r--source/blender/simulations/bparticles/forces.hpp13
-rw-r--r--source/blender/simulations/bparticles/inserters.cpp471
-rw-r--r--source/blender/simulations/bparticles/inserters.hpp53
-rw-r--r--source/blender/simulations/bparticles/node_frontend.cpp570
-rw-r--r--source/blender/simulations/bparticles/offset_handlers.cpp11
-rw-r--r--source/blender/simulations/bparticles/offset_handlers.hpp13
14 files changed, 554 insertions, 883 deletions
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))
{
}