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 <jacques@blender.org>2020-10-20 13:07:42 +0300
committerJacques Lucke <jacques@blender.org>2020-10-20 13:07:42 +0300
commit6ced026ae1547ac28c88516a0d061315aeacc913 (patch)
tree60c61867746df72e8cf87efd47d5d27fbbb27109 /source/blender/simulation
parent63a9f24b55d0b5d84d625bdbb44d498fb1f2ae01 (diff)
Simulation: remove particle nodes with outdated design
The design for how we approach the "Everything Nodes" project has changed. We will focus on a different part of the project initially. While future me will likely refer back to some of the code I remove here, there is no point in keeping this code around in master currently. It would just confuse other developers working on the project. This does not remove the simulation modifier and data block. Those are just cleaned up, so that the boilerplate code can be reused in the future.
Diffstat (limited to 'source/blender/simulation')
-rw-r--r--source/blender/simulation/CMakeLists.txt16
-rw-r--r--source/blender/simulation/SIM_simulation_update.hh31
-rw-r--r--source/blender/simulation/intern/particle_allocator.cc86
-rw-r--r--source/blender/simulation/intern/particle_allocator.hh98
-rw-r--r--source/blender/simulation/intern/particle_function.cc166
-rw-r--r--source/blender/simulation/intern/particle_function.hh94
-rw-r--r--source/blender/simulation/intern/particle_mesh_emitter.cc362
-rw-r--r--source/blender/simulation/intern/particle_mesh_emitter.hh49
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.cc907
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.hh65
-rw-r--r--source/blender/simulation/intern/simulation_solver.cc522
-rw-r--r--source/blender/simulation/intern/simulation_solver.hh37
-rw-r--r--source/blender/simulation/intern/simulation_solver_influences.cc57
-rw-r--r--source/blender/simulation/intern/simulation_solver_influences.hh234
-rw-r--r--source/blender/simulation/intern/simulation_update.cc357
-rw-r--r--source/blender/simulation/intern/time_interval.hh90
16 files changed, 0 insertions, 3171 deletions
diff --git a/source/blender/simulation/CMakeLists.txt b/source/blender/simulation/CMakeLists.txt
index e47586d55cc..c536d6a7d69 100644
--- a/source/blender/simulation/CMakeLists.txt
+++ b/source/blender/simulation/CMakeLists.txt
@@ -41,32 +41,16 @@ set(SRC
intern/hair_volume.cpp
intern/implicit_blender.c
intern/implicit_eigen.cpp
- intern/particle_allocator.cc
- intern/particle_function.cc
- intern/particle_mesh_emitter.cc
- intern/simulation_collect_influences.cc
- intern/simulation_solver.cc
- intern/simulation_solver_influences.cc
- intern/simulation_update.cc
intern/ConstrainedConjugateGradient.h
intern/eigen_utils.h
intern/implicit.h
- intern/particle_allocator.hh
- intern/particle_function.hh
- intern/particle_mesh_emitter.hh
- intern/simulation_collect_influences.hh
- intern/simulation_solver.hh
- intern/simulation_solver_influences.hh
- intern/time_interval.hh
SIM_mass_spring.h
- SIM_simulation_update.hh
)
set(LIB
bf_blenkernel
- bf_nodes
)
if(WITH_OPENMP_STATIC)
diff --git a/source/blender/simulation/SIM_simulation_update.hh b/source/blender/simulation/SIM_simulation_update.hh
deleted file mode 100644
index 7c2726f038e..00000000000
--- a/source/blender/simulation/SIM_simulation_update.hh
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-struct Depsgraph;
-struct Scene;
-struct Simulation;
-
-namespace blender::sim {
-
-void update_simulation_in_depsgraph(Depsgraph *depsgraph,
- Scene *scene_cow,
- Simulation *simulation_cow);
-
-bool update_simulation_dependencies(Simulation *simulation);
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_allocator.cc b/source/blender/simulation/intern/particle_allocator.cc
deleted file mode 100644
index 91ca667a239..00000000000
--- a/source/blender/simulation/intern/particle_allocator.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "particle_allocator.hh"
-
-#include "BLI_rand.hh"
-
-namespace blender::sim {
-
-AttributesAllocator::~AttributesAllocator()
-{
- for (std::unique_ptr<AttributesBlock> &block : allocated_blocks_) {
- for (int i : attributes_info_.index_range()) {
- const fn::CPPType &type = attributes_info_.type_of(i);
- type.destruct_n(block->buffers[i], block->size);
- MEM_freeN(block->buffers[i]);
- }
- }
-}
-
-fn::MutableAttributesRef AttributesAllocator::allocate_uninitialized(int size)
-{
- std::unique_ptr<AttributesBlock> block = std::make_unique<AttributesBlock>();
- block->buffers = Array<void *>(attributes_info_.size(), nullptr);
- block->size = size;
-
- for (int i : attributes_info_.index_range()) {
- const fn::CPPType &type = attributes_info_.type_of(i);
- void *buffer = MEM_mallocN_aligned(size * type.size(), type.alignment(), AT);
- block->buffers[i] = buffer;
- }
-
- fn::MutableAttributesRef attributes{attributes_info_, block->buffers, size};
-
- {
- std::lock_guard lock{mutex_};
- allocated_blocks_.append(std::move(block));
- allocated_attributes_.append(attributes);
- total_allocated_ += size;
- }
-
- return attributes;
-}
-
-fn::MutableAttributesRef ParticleAllocator::allocate(int size)
-{
- const fn::AttributesInfo &info = attributes_allocator_.attributes_info();
- fn::MutableAttributesRef attributes = attributes_allocator_.allocate_uninitialized(size);
- for (int i : info.index_range()) {
- const fn::CPPType &type = info.type_of(i);
- StringRef name = info.name_of(i);
- if (name == "ID") {
- int start_id = next_id_.fetch_add(size);
- MutableSpan<int> ids = attributes.get<int>("ID");
- for (int pindex : IndexRange(size)) {
- ids[pindex] = start_id + pindex;
- }
- }
- else if (name == "Hash") {
- MutableSpan<int> hashes = attributes.get<int>("Hash");
- RandomNumberGenerator rng(hash_seed_ ^ static_cast<uint32_t>(next_id_));
- for (int pindex : IndexRange(size)) {
- hashes[pindex] = static_cast<int>(rng.get_uint32());
- }
- }
- else {
- type.fill_uninitialized(info.default_of(i), attributes.get(i).data(), size);
- }
- }
- return attributes;
-}
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_allocator.hh b/source/blender/simulation/intern/particle_allocator.hh
deleted file mode 100644
index c0bbdb845d9..00000000000
--- a/source/blender/simulation/intern/particle_allocator.hh
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "BLI_array.hh"
-#include "BLI_vector.hh"
-
-#include "FN_attributes_ref.hh"
-
-#include <atomic>
-#include <mutex>
-
-namespace blender::sim {
-
-class AttributesAllocator : NonCopyable, NonMovable {
- private:
- struct AttributesBlock {
- Array<void *> buffers;
- int size;
- };
-
- const fn::AttributesInfo &attributes_info_;
- Vector<std::unique_ptr<AttributesBlock>> allocated_blocks_;
- Vector<fn::MutableAttributesRef> allocated_attributes_;
- int total_allocated_ = 0;
- std::mutex mutex_;
-
- public:
- AttributesAllocator(const fn::AttributesInfo &attributes_info)
- : attributes_info_(attributes_info)
- {
- }
-
- ~AttributesAllocator();
-
- Span<fn::MutableAttributesRef> get_allocations() const
- {
- return allocated_attributes_;
- }
-
- int total_allocated() const
- {
- return total_allocated_;
- }
-
- const fn::AttributesInfo &attributes_info() const
- {
- return attributes_info_;
- }
-
- fn::MutableAttributesRef allocate_uninitialized(int size);
-};
-
-class ParticleAllocator : NonCopyable, NonMovable {
- private:
- AttributesAllocator attributes_allocator_;
- std::atomic<int> next_id_;
- uint32_t hash_seed_;
-
- public:
- ParticleAllocator(const fn::AttributesInfo &attributes_info, int next_id, uint32_t hash_seed)
- : attributes_allocator_(attributes_info), next_id_(next_id), hash_seed_(hash_seed)
- {
- }
-
- const fn::AttributesInfo &attributes_info() const
- {
- return attributes_allocator_.attributes_info();
- }
-
- Span<fn::MutableAttributesRef> get_allocations() const
- {
- return attributes_allocator_.get_allocations();
- }
-
- int total_allocated() const
- {
- return attributes_allocator_.total_allocated();
- }
-
- fn::MutableAttributesRef allocate(int size);
-};
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_function.cc b/source/blender/simulation/intern/particle_function.cc
deleted file mode 100644
index 69977eb2054..00000000000
--- a/source/blender/simulation/intern/particle_function.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "particle_function.hh"
-
-namespace blender::sim {
-
-ParticleFunction::ParticleFunction(const fn::MultiFunction *global_fn,
- const fn::MultiFunction *per_particle_fn,
- Span<const ParticleFunctionInput *> global_inputs,
- Span<const ParticleFunctionInput *> per_particle_inputs,
- Span<bool> output_is_global)
- : global_fn_(global_fn),
- per_particle_fn_(per_particle_fn),
- global_inputs_(global_inputs),
- per_particle_inputs_(per_particle_inputs),
- output_is_global_(output_is_global)
-{
- for (int i : output_is_global_.index_range()) {
- if (output_is_global_[i]) {
- int param_index = global_inputs_.size() + global_output_indices_.size();
- fn::MFParamType param_type = global_fn_->param_type(param_index);
- BLI_assert(param_type.is_output());
- output_types_.append(param_type.data_type());
- output_names_.append(global_fn_->param_name(param_index));
- global_output_indices_.append(i);
- }
- else {
- int param_index = per_particle_inputs_.size() + per_particle_output_indices_.size();
- fn::MFParamType param_type = per_particle_fn_->param_type(param_index);
- BLI_assert(param_type.is_output());
- output_types_.append(param_type.data_type());
- output_names_.append(per_particle_fn_->param_name(param_index));
- per_particle_output_indices_.append(i);
- }
- }
-}
-
-ParticleFunctionEvaluator::ParticleFunctionEvaluator(const ParticleFunction &particle_fn,
- const SimulationSolveContext &solve_context,
- const ParticleChunkContext &particles)
- : particle_fn_(particle_fn),
- solve_context_(solve_context),
- particles_(particles),
- mask_(particles_.index_mask),
- outputs_(particle_fn_.output_types_.size(), nullptr)
-{
- global_context_.add_global_context("PersistentDataHandleMap", &solve_context_.handle_map);
- per_particle_context_.add_global_context("PersistentDataHandleMap", &solve_context_.handle_map);
-}
-
-ParticleFunctionEvaluator::~ParticleFunctionEvaluator()
-{
- for (int output_index : outputs_.index_range()) {
- void *buffer = outputs_[output_index];
- fn::MFDataType data_type = particle_fn_.output_types_[output_index];
- BLI_assert(data_type.is_single()); /* For now. */
- const fn::CPPType &type = data_type.single_type();
-
- if (particle_fn_.output_is_global_[output_index]) {
- type.destruct(buffer);
- }
- else {
- type.destruct_indices(outputs_[0], mask_);
- }
- }
-}
-
-void ParticleFunctionEvaluator::compute()
-{
- BLI_assert(!is_computed_);
- this->compute_globals();
- this->compute_per_particle();
- is_computed_ = true;
-}
-
-fn::GVSpan ParticleFunctionEvaluator::get(int output_index, StringRef expected_name) const
-{
-#ifdef DEBUG
- if (expected_name != "") {
- StringRef real_name = particle_fn_.output_names_[output_index];
- BLI_assert(expected_name == real_name);
- }
- BLI_assert(is_computed_);
-#endif
- UNUSED_VARS_NDEBUG(expected_name);
- const void *buffer = outputs_[output_index];
- const fn::CPPType &type = particle_fn_.output_types_[output_index].single_type();
- if (particle_fn_.output_is_global_[output_index]) {
- return fn::GVSpan::FromSingleWithMaxSize(type, buffer);
- }
-
- return fn::GVSpan(fn::GSpan(type, buffer, mask_.min_array_size()));
-}
-
-void ParticleFunctionEvaluator::compute_globals()
-{
- if (particle_fn_.global_fn_ == nullptr) {
- return;
- }
-
- fn::MFParamsBuilder params(*particle_fn_.global_fn_, mask_.min_array_size());
-
- /* Add input parameters. */
- ParticleFunctionInputContext input_context{solve_context_, particles_};
- for (const ParticleFunctionInput *input : particle_fn_.global_inputs_) {
- input->add_input(input_context, params, resources_);
- }
-
- /* Add output parameters. */
- for (int output_index : particle_fn_.global_output_indices_) {
- fn::MFDataType data_type = particle_fn_.output_types_[output_index];
- BLI_assert(data_type.is_single()); /* For now. */
-
- const fn::CPPType &type = data_type.single_type();
- void *buffer = resources_.linear_allocator().allocate(type.size(), type.alignment());
- params.add_uninitialized_single_output(fn::GMutableSpan(type, buffer, 1));
- outputs_[output_index] = buffer;
- }
-
- particle_fn_.global_fn_->call({0}, params, global_context_);
-}
-
-void ParticleFunctionEvaluator::compute_per_particle()
-{
- if (particle_fn_.per_particle_fn_ == nullptr) {
- return;
- }
-
- fn::MFParamsBuilder params(*particle_fn_.per_particle_fn_, mask_.min_array_size());
-
- /* Add input parameters. */
- ParticleFunctionInputContext input_context{solve_context_, particles_};
- for (const ParticleFunctionInput *input : particle_fn_.per_particle_inputs_) {
- input->add_input(input_context, params, resources_);
- }
-
- /* Add output parameters. */
- for (int output_index : particle_fn_.per_particle_output_indices_) {
- fn::MFDataType data_type = particle_fn_.output_types_[output_index];
- BLI_assert(data_type.is_single()); /* For now. */
-
- const fn::CPPType &type = data_type.single_type();
- void *buffer = resources_.linear_allocator().allocate(type.size() * mask_.min_array_size(),
- type.alignment());
- params.add_uninitialized_single_output(fn::GMutableSpan(type, buffer, mask_.min_array_size()));
- outputs_[output_index] = buffer;
- }
-
- particle_fn_.per_particle_fn_->call(mask_, params, global_context_);
-}
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_function.hh b/source/blender/simulation/intern/particle_function.hh
deleted file mode 100644
index ead4e6f3c31..00000000000
--- a/source/blender/simulation/intern/particle_function.hh
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "FN_attributes_ref.hh"
-#include "FN_multi_function.hh"
-
-#include "BLI_resource_collector.hh"
-
-#include "simulation_solver.hh"
-
-namespace blender::sim {
-
-struct ParticleFunctionInputContext {
- const SimulationSolveContext &solve_context;
- const ParticleChunkContext &particles;
-};
-
-class ParticleFunctionInput {
- public:
- virtual ~ParticleFunctionInput() = default;
- virtual void add_input(ParticleFunctionInputContext &context,
- fn::MFParamsBuilder &params,
- ResourceCollector &resources) const = 0;
-};
-
-class ParticleFunction {
- private:
- const fn::MultiFunction *global_fn_;
- const fn::MultiFunction *per_particle_fn_;
- Array<const ParticleFunctionInput *> global_inputs_;
- Array<const ParticleFunctionInput *> per_particle_inputs_;
- Array<bool> output_is_global_;
- Vector<int> global_output_indices_;
- Vector<int> per_particle_output_indices_;
- Vector<fn::MFDataType> output_types_;
- Vector<StringRefNull> output_names_;
-
- friend class ParticleFunctionEvaluator;
-
- public:
- ParticleFunction(const fn::MultiFunction *global_fn,
- const fn::MultiFunction *per_particle_fn,
- Span<const ParticleFunctionInput *> global_inputs,
- Span<const ParticleFunctionInput *> per_particle_inputs,
- Span<bool> output_is_global);
-};
-
-class ParticleFunctionEvaluator {
- private:
- ResourceCollector resources_;
- const ParticleFunction &particle_fn_;
- const SimulationSolveContext &solve_context_;
- const ParticleChunkContext &particles_;
- IndexMask mask_;
- fn::MFContextBuilder global_context_;
- fn::MFContextBuilder per_particle_context_;
- Vector<void *> outputs_;
- bool is_computed_ = false;
-
- public:
- ParticleFunctionEvaluator(const ParticleFunction &particle_fn,
- const SimulationSolveContext &solve_context,
- const ParticleChunkContext &particles);
- ~ParticleFunctionEvaluator();
-
- void compute();
- fn::GVSpan get(int output_index, StringRef expected_name = "") const;
-
- template<typename T> fn::VSpan<T> get(int output_index, StringRef expected_name = "") const
- {
- return this->get(output_index, expected_name).typed<T>();
- }
-
- private:
- void compute_globals();
- void compute_per_particle();
-};
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_mesh_emitter.cc b/source/blender/simulation/intern/particle_mesh_emitter.cc
deleted file mode 100644
index 3d43d4d8001..00000000000
--- a/source/blender/simulation/intern/particle_mesh_emitter.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "particle_mesh_emitter.hh"
-
-#include "BLI_float4x4.hh"
-#include "BLI_rand.hh"
-#include "BLI_vector_adaptor.hh"
-
-#include "BKE_mesh_runtime.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-
-namespace blender::sim {
-
-ParticleMeshEmitter::~ParticleMeshEmitter() = default;
-
-struct EmitterSettings {
- Object *object;
- float rate;
-};
-
-static BLI_NOINLINE void compute_birth_times(float rate,
- TimeInterval emit_interval,
- ParticleMeshEmitterSimulationState &state,
- Vector<float> &r_birth_times)
-{
- const float time_between_particles = 1.0f / rate;
- int counter = 0;
- while (true) {
- counter++;
- const float time_offset = counter * time_between_particles;
- const float birth_time = state.last_birth_time + time_offset;
- if (birth_time > emit_interval.stop()) {
- break;
- }
- if (birth_time <= emit_interval.start()) {
- continue;
- }
- r_birth_times.append(birth_time);
- }
-}
-
-static BLI_NOINLINE Span<MLoopTri> get_mesh_triangles(Mesh &mesh)
-{
- const MLoopTri *triangles = BKE_mesh_runtime_looptri_ensure(&mesh);
- int amount = BKE_mesh_runtime_looptri_len(&mesh);
- return Span(triangles, amount);
-}
-
-static BLI_NOINLINE void compute_triangle_areas(Mesh &mesh,
- Span<MLoopTri> triangles,
- MutableSpan<float> r_areas)
-{
- assert_same_size(triangles, r_areas);
-
- for (int i : triangles.index_range()) {
- const MLoopTri &tri = triangles[i];
-
- const float3 v1 = mesh.mvert[mesh.mloop[tri.tri[0]].v].co;
- const float3 v2 = mesh.mvert[mesh.mloop[tri.tri[1]].v].co;
- const float3 v3 = mesh.mvert[mesh.mloop[tri.tri[2]].v].co;
-
- const float area = area_tri_v3(v1, v2, v3);
- r_areas[i] = area;
- }
-}
-
-static BLI_NOINLINE void compute_triangle_weights(Mesh &mesh,
- Span<MLoopTri> triangles,
- MutableSpan<float> r_weights)
-{
- assert_same_size(triangles, r_weights);
- compute_triangle_areas(mesh, triangles, r_weights);
-}
-
-static BLI_NOINLINE void compute_cumulative_distribution(Span<float> weights,
- MutableSpan<float> r_cumulative_weights)
-{
- BLI_assert(weights.size() + 1 == r_cumulative_weights.size());
-
- r_cumulative_weights[0] = 0;
- for (int i : weights.index_range()) {
- r_cumulative_weights[i + 1] = r_cumulative_weights[i] + weights[i];
- }
-}
-
-static void sample_cumulative_distribution_recursive(RandomNumberGenerator &rng,
- int amount,
- int start,
- int one_after_end,
- Span<float> cumulative_weights,
- VectorAdaptor<int> &r_sampled_indices)
-{
- BLI_assert(start <= one_after_end);
- const int size = one_after_end - start;
- if (size == 0) {
- BLI_assert(amount == 0);
- }
- else if (amount == 0) {
- return;
- }
- else if (size == 1) {
- r_sampled_indices.append_n_times(start, amount);
- }
- else {
- const int middle = start + size / 2;
- const float left_weight = cumulative_weights[middle] - cumulative_weights[start];
- const float right_weight = cumulative_weights[one_after_end] - cumulative_weights[middle];
- BLI_assert(left_weight >= 0.0f && right_weight >= 0.0f);
- const float weight_sum = left_weight + right_weight;
- BLI_assert(weight_sum > 0.0f);
-
- const float left_factor = left_weight / weight_sum;
- const float right_factor = right_weight / weight_sum;
-
- int left_amount = amount * left_factor;
- int right_amount = amount * right_factor;
-
- if (left_amount + right_amount < amount) {
- BLI_assert(left_amount + right_amount + 1 == amount);
- const float weight_per_item = weight_sum / amount;
- const float total_remaining_weight = weight_sum -
- (left_amount + right_amount) * weight_per_item;
- const float left_remaining_weight = left_weight - left_amount * weight_per_item;
- const float left_remaining_factor = left_remaining_weight / total_remaining_weight;
- if (rng.get_float() < left_remaining_factor) {
- left_amount++;
- }
- else {
- right_amount++;
- }
- }
-
- sample_cumulative_distribution_recursive(
- rng, left_amount, start, middle, cumulative_weights, r_sampled_indices);
- sample_cumulative_distribution_recursive(
- rng, right_amount, middle, one_after_end, cumulative_weights, r_sampled_indices);
- }
-}
-
-static BLI_NOINLINE void sample_cumulative_distribution(RandomNumberGenerator &rng,
- Span<float> cumulative_weights,
- MutableSpan<int> r_samples)
-{
- VectorAdaptor<int> sampled_indices(r_samples);
- sample_cumulative_distribution_recursive(rng,
- r_samples.size(),
- 0,
- cumulative_weights.size() - 1,
- cumulative_weights,
- sampled_indices);
- BLI_assert(sampled_indices.is_full());
-}
-
-static BLI_NOINLINE bool sample_weighted_buckets(RandomNumberGenerator &rng,
- Span<float> weights,
- MutableSpan<int> r_samples)
-{
- Array<float> cumulative_weights(weights.size() + 1);
- compute_cumulative_distribution(weights, cumulative_weights);
-
- if (r_samples.size() > 0 && cumulative_weights.as_span().last() == 0.0f) {
- /* All weights are zero. */
- return false;
- }
-
- sample_cumulative_distribution(rng, cumulative_weights, r_samples);
- return true;
-}
-
-static BLI_NOINLINE void sample_looptris(RandomNumberGenerator &rng,
- Mesh &mesh,
- Span<MLoopTri> triangles,
- Span<int> triangles_to_sample,
- MutableSpan<float3> r_sampled_positions,
- MutableSpan<float3> r_sampled_normals)
-{
- assert_same_size(triangles_to_sample, r_sampled_positions, r_sampled_normals);
-
- MLoop *loops = mesh.mloop;
- MVert *verts = mesh.mvert;
-
- for (uint i : triangles_to_sample.index_range()) {
- const uint triangle_index = triangles_to_sample[i];
- const MLoopTri &triangle = triangles[triangle_index];
-
- const float3 v1 = verts[loops[triangle.tri[0]].v].co;
- const float3 v2 = verts[loops[triangle.tri[1]].v].co;
- const float3 v3 = verts[loops[triangle.tri[2]].v].co;
-
- const float3 bary_coords = rng.get_barycentric_coordinates();
-
- float3 position;
- interp_v3_v3v3v3(position, v1, v2, v3, bary_coords);
-
- float3 normal;
- normal_tri_v3(normal, v1, v2, v3);
-
- r_sampled_positions[i] = position;
- r_sampled_normals[i] = normal;
- }
-}
-
-static BLI_NOINLINE bool compute_new_particle_attributes(ParticleEmitterContext &context,
- EmitterSettings &settings,
- ParticleMeshEmitterSimulationState &state,
- Vector<float3> &r_positions,
- Vector<float3> &r_velocities,
- Vector<float> &r_birth_times)
-{
- if (settings.object == nullptr) {
- return false;
- }
- if (settings.rate <= 0.000001f) {
- return false;
- }
- if (settings.object->type != OB_MESH) {
- return false;
- }
- Mesh &mesh = *static_cast<Mesh *>(settings.object->data);
- if (mesh.totvert == 0) {
- return false;
- }
-
- const float start_time = context.emit_interval.start();
- const uint32_t seed = DefaultHash<StringRef>{}(state.head.name);
- RandomNumberGenerator rng{*reinterpret_cast<const uint32_t *>(&start_time) ^ seed};
-
- compute_birth_times(settings.rate, context.emit_interval, state, r_birth_times);
- const int particle_amount = r_birth_times.size();
- if (particle_amount == 0) {
- return false;
- }
-
- const float last_birth_time = r_birth_times.last();
- rng.shuffle(r_birth_times.as_mutable_span());
-
- Span<MLoopTri> triangles = get_mesh_triangles(mesh);
- if (triangles.is_empty()) {
- return false;
- }
-
- Array<float> triangle_weights(triangles.size());
- compute_triangle_weights(mesh, triangles, triangle_weights);
-
- Array<int> triangles_to_sample(particle_amount);
- if (!sample_weighted_buckets(rng, triangle_weights, triangles_to_sample)) {
- return false;
- }
-
- r_positions.resize(particle_amount);
- r_velocities.resize(particle_amount);
- sample_looptris(rng, mesh, triangles, triangles_to_sample, r_positions, r_velocities);
-
- if (context.solve_context.dependency_animations.is_object_transform_changing(*settings.object)) {
- Array<float4x4> local_to_world_matrices(particle_amount);
- context.solve_context.dependency_animations.get_object_transforms(
- *settings.object, r_birth_times, local_to_world_matrices);
-
- for (int i : IndexRange(particle_amount)) {
- const float4x4 &position_to_world = local_to_world_matrices[i];
- const float4x4 normal_to_world = position_to_world.inverted_transposed_affine();
- r_positions[i] = position_to_world * r_positions[i];
- r_velocities[i] = normal_to_world * r_velocities[i];
- }
- }
- else {
- const float4x4 position_to_world = settings.object->obmat;
- const float4x4 normal_to_world = position_to_world.inverted_transposed_affine();
- for (int i : IndexRange(particle_amount)) {
- r_positions[i] = position_to_world * r_positions[i];
- r_velocities[i] = normal_to_world * r_velocities[i];
- }
- }
-
- for (int i : IndexRange(particle_amount)) {
- r_velocities[i].normalize();
- }
-
- state.last_birth_time = last_birth_time;
- return true;
-}
-
-static BLI_NOINLINE EmitterSettings compute_settings(const fn::MultiFunction &inputs_fn,
- ParticleEmitterContext &context)
-{
- EmitterSettings parameters;
-
- fn::MFContextBuilder mf_context;
- mf_context.add_global_context("PersistentDataHandleMap", &context.solve_context.handle_map);
-
- fn::MFParamsBuilder mf_params{inputs_fn, 1};
- bke::PersistentObjectHandle object_handle;
- mf_params.add_uninitialized_single_output(&object_handle, "Object");
- mf_params.add_uninitialized_single_output(&parameters.rate, "Rate");
-
- inputs_fn.call(IndexRange(1), mf_params, mf_context);
-
- parameters.object = context.solve_context.handle_map.lookup(object_handle);
- return parameters;
-}
-
-void ParticleMeshEmitter::emit(ParticleEmitterContext &context) const
-{
- auto *state = context.lookup_state<ParticleMeshEmitterSimulationState>(own_state_name_);
- if (state == nullptr) {
- return;
- }
-
- EmitterSettings settings = compute_settings(inputs_fn_, context);
-
- Vector<float3> new_positions;
- Vector<float3> new_velocities;
- Vector<float> new_birth_times;
-
- if (!compute_new_particle_attributes(
- context, settings, *state, new_positions, new_velocities, new_birth_times)) {
- return;
- }
-
- for (StringRef name : particle_names_) {
- ParticleAllocator *allocator = context.try_get_particle_allocator(name);
- if (allocator == nullptr) {
- continue;
- }
-
- int amount = new_positions.size();
- fn::MutableAttributesRef attributes = allocator->allocate(amount);
-
- attributes.get<float3>("Position").copy_from(new_positions);
- attributes.get<float3>("Velocity").copy_from(new_velocities);
- attributes.get<float>("Birth Time").copy_from(new_birth_times);
-
- if (action_ != nullptr) {
- ParticleChunkContext particles{
- *context.solve_context.state_map.lookup<ParticleSimulationState>(name),
- IndexRange(amount),
- attributes,
- nullptr};
- ParticleActionContext action_context{context.solve_context, particles};
- action_->execute(action_context);
- }
- }
-}
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_mesh_emitter.hh b/source/blender/simulation/intern/particle_mesh_emitter.hh
deleted file mode 100644
index cdcf2a34e16..00000000000
--- a/source/blender/simulation/intern/particle_mesh_emitter.hh
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "simulation_solver_influences.hh"
-
-#include "FN_multi_function.hh"
-
-namespace blender::sim {
-
-class ParticleMeshEmitter final : public ParticleEmitter {
- private:
- std::string own_state_name_;
- Array<std::string> particle_names_;
- const fn::MultiFunction &inputs_fn_;
- const ParticleAction *action_;
-
- public:
- ParticleMeshEmitter(std::string own_state_name,
- Array<std::string> particle_names,
- const fn::MultiFunction &inputs_fn,
- const ParticleAction *action)
- : own_state_name_(std::move(own_state_name)),
- particle_names_(particle_names),
- inputs_fn_(inputs_fn),
- action_(action)
- {
- }
-
- ~ParticleMeshEmitter();
-
- void emit(ParticleEmitterContext &context) const override;
-};
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_collect_influences.cc b/source/blender/simulation/intern/simulation_collect_influences.cc
deleted file mode 100644
index 818415e5d88..00000000000
--- a/source/blender/simulation/intern/simulation_collect_influences.cc
+++ /dev/null
@@ -1,907 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "simulation_collect_influences.hh"
-#include "particle_function.hh"
-#include "particle_mesh_emitter.hh"
-
-#include "FN_attributes_ref.hh"
-#include "FN_multi_function_network_evaluation.hh"
-#include "FN_multi_function_network_optimization.hh"
-
-#include "NOD_node_tree_multi_function.hh"
-
-#include "DEG_depsgraph_query.h"
-
-#include "BLI_hash.h"
-#include "BLI_rand.hh"
-#include "BLI_set.hh"
-
-namespace blender::sim {
-
-using fn::GVSpan;
-using fn::MFContextBuilder;
-using fn::MFDataType;
-using fn::MFDummyNode;
-using fn::MFFunctionNode;
-using fn::MFInputSocket;
-using fn::MFNetwork;
-using fn::MFNetworkEvaluator;
-using fn::MFNode;
-using fn::MFOutputSocket;
-using fn::MFParamsBuilder;
-using fn::MFParamType;
-using fn::MultiFunction;
-using fn::VSpan;
-using nodes::DerivedNodeTree;
-using nodes::DInputSocket;
-using nodes::DNode;
-using nodes::DOutputSocket;
-using nodes::DParentNode;
-using nodes::MFNetworkTreeMap;
-using nodes::NodeTreeRefMap;
-
-struct DummyDataSources {
- Map<const MFOutputSocket *, std::string> particle_attributes;
- Set<const MFOutputSocket *> simulation_time;
- Set<const MFOutputSocket *> scene_time;
-};
-
-extern "C" {
-void WM_clipboard_text_set(const char *buf, bool selection);
-}
-
-static std::string dnode_to_path(const DNode &dnode)
-{
- std::string path;
- for (const DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) {
- path = parent->node_ref().name() + "/" + path;
- }
- path = path + dnode.name();
- return path;
-}
-
-struct CollectContext : NonCopyable, NonMovable {
- SimulationInfluences &influences;
- RequiredStates &required_states;
- ResourceCollector &resources;
- MFNetworkTreeMap &network_map;
- MFNetwork &network;
- const DerivedNodeTree &tree;
-
- DummyDataSources data_sources;
- Span<const DNode *> particle_simulation_nodes;
- Map<const DNode *, std::string> node_paths;
-
- CollectContext(SimulationInfluences &influences,
- RequiredStates &required_states,
- ResourceCollector &resources,
- MFNetworkTreeMap &network_map)
- : influences(influences),
- required_states(required_states),
- resources(resources),
- network_map(network_map),
- network(network_map.network()),
- tree(network_map.tree())
- {
- particle_simulation_nodes = tree.nodes_by_type("SimulationNodeParticleSimulation");
- }
-};
-
-static const ParticleAction *create_particle_action(CollectContext &context,
- const DOutputSocket &dsocket,
- Span<StringRefNull> particle_names);
-
-static const ParticleAction *create_particle_action(CollectContext &context,
- const DInputSocket &dsocket,
- Span<StringRefNull> particle_names)
-{
- BLI_assert(dsocket.bsocket()->type == SOCK_CONTROL_FLOW);
- if (dsocket.linked_sockets().size() != 1) {
- return nullptr;
- }
- return create_particle_action(context, *dsocket.linked_sockets()[0], particle_names);
-}
-
-static StringRefNull get_identifier(CollectContext &context, const DNode &dnode)
-{
- return context.node_paths.lookup_or_add_cb(&dnode, [&]() { return dnode_to_path(dnode); });
-}
-
-static Span<const DNode *> nodes_by_type(CollectContext &context, StringRefNull idname)
-{
- return context.tree.nodes_by_type(idname);
-}
-
-static Array<StringRefNull> find_linked_particle_simulations(CollectContext &context,
- const DOutputSocket &output_socket)
-{
- VectorSet<StringRefNull> names;
- for (const DInputSocket *target_socket : output_socket.linked_sockets()) {
- if (target_socket->node().idname() == "SimulationNodeParticleSimulation") {
- names.add(get_identifier(context, target_socket->node()));
- }
- }
- return names.as_span();
-}
-
-/* Returns true on success. */
-static bool compute_global_inputs(MFNetworkTreeMap &network_map,
- ResourceCollector &resources,
- Span<const MFInputSocket *> sockets,
- MutableSpan<GMutableSpan> r_results)
-{
- int amount = sockets.size();
- if (amount == 0) {
- return true;
- }
-
- if (network_map.network().have_dummy_or_unlinked_dependencies(sockets)) {
- return false;
- }
-
- MFNetworkEvaluator network_fn{{}, sockets};
- MFParamsBuilder params{network_fn, 1};
- for (int param_index : network_fn.param_indices()) {
- MFParamType param_type = network_fn.param_type(param_index);
- BLI_assert(param_type.category() == MFParamType::Category::SingleOutput); /* For now. */
- const CPPType &type = param_type.data_type().single_type();
- void *buffer = resources.linear_allocator().allocate(type.size(), type.alignment());
- resources.add(buffer, type.destruct_cb(), AT);
- GMutableSpan span{type, buffer, 1};
- r_results[param_index] = span;
- params.add_uninitialized_single_output(span);
- }
- MFContextBuilder context;
- network_fn.call(IndexRange(1), params, context);
- return true;
-}
-
-static std::optional<Array<std::string>> compute_global_string_inputs(
- MFNetworkTreeMap &network_map, Span<const MFInputSocket *> sockets)
-{
- ResourceCollector local_resources;
- Array<GMutableSpan> computed_values(sockets.size(), NoInitialization());
- if (!compute_global_inputs(network_map, local_resources, sockets, computed_values)) {
- return {};
- }
-
- Array<std::string> strings(sockets.size());
- for (int i : sockets.index_range()) {
- strings[i] = std::move(computed_values[i].typed<std::string>()[0]);
- }
- return strings;
-}
-
-/**
- * This will find all the particle attribute input nodes. Then it will compute the attribute names
- * by evaluating the network (those names should not depend on per particle data). In the end,
- * input nodes that access the same attribute are combined.
- */
-static void prepare_particle_attribute_nodes(CollectContext &context)
-{
- Span<const DNode *> attribute_dnodes = nodes_by_type(context, "SimulationNodeParticleAttribute");
-
- Vector<MFInputSocket *> name_sockets;
- for (const DNode *dnode : attribute_dnodes) {
- MFInputSocket &name_socket = context.network_map.lookup_dummy(dnode->input(0));
- name_sockets.append(&name_socket);
- }
-
- std::optional<Array<std::string>> attribute_names = compute_global_string_inputs(
- context.network_map, name_sockets);
- if (!attribute_names.has_value()) {
- return;
- }
-
- MultiValueMap<std::pair<std::string, MFDataType>, MFNode *> attribute_nodes_by_name_and_type;
- for (int i : attribute_names->index_range()) {
- attribute_nodes_by_name_and_type.add(
- {(*attribute_names)[i], name_sockets[i]->node().output(0).data_type()},
- &name_sockets[i]->node());
- }
-
- Map<const MFOutputSocket *, std::string> attribute_inputs;
- for (auto item : attribute_nodes_by_name_and_type.items()) {
- StringRef attribute_name = item.key.first;
- MFDataType data_type = item.key.second;
- Span<MFNode *> nodes = item.value;
-
- MFOutputSocket &new_attribute_socket = context.network.add_input(
- "Attribute '" + attribute_name + "'", data_type);
- for (MFNode *node : nodes) {
- context.network.relink(node->output(0), new_attribute_socket);
- }
- context.network.remove(nodes);
-
- context.data_sources.particle_attributes.add_new(&new_attribute_socket, attribute_name);
- }
-}
-
-static void prepare_time_input_nodes(CollectContext &context)
-{
- Span<const DNode *> time_input_dnodes = nodes_by_type(context, "SimulationNodeTime");
- Vector<const DNode *> simulation_time_inputs;
- Vector<const DNode *> scene_time_inputs;
- for (const DNode *dnode : time_input_dnodes) {
- NodeSimInputTimeType type = (NodeSimInputTimeType)dnode->node_ref().bnode()->custom1;
- switch (type) {
- case NODE_SIM_INPUT_SIMULATION_TIME: {
- simulation_time_inputs.append(dnode);
- break;
- }
- case NODE_SIM_INPUT_SCENE_TIME: {
- scene_time_inputs.append(dnode);
- break;
- }
- }
- }
-
- if (simulation_time_inputs.size() > 0) {
- MFOutputSocket &new_socket = context.network.add_input("Simulation Time",
- MFDataType::ForSingle<float>());
- for (const DNode *dnode : simulation_time_inputs) {
- MFOutputSocket &old_socket = context.network_map.lookup_dummy(dnode->output(0));
- context.network.relink(old_socket, new_socket);
- context.network.remove(old_socket.node());
- }
- context.data_sources.simulation_time.add(&new_socket);
- }
- if (scene_time_inputs.size() > 0) {
- MFOutputSocket &new_socket = context.network.add_input("Scene Time",
- MFDataType::ForSingle<float>());
- for (const DNode *dnode : scene_time_inputs) {
- MFOutputSocket &old_socket = context.network_map.lookup_dummy(dnode->output(0));
- context.network.relink(old_socket, new_socket);
- context.network.remove(old_socket.node());
- }
- context.data_sources.scene_time.add(&new_socket);
- }
-}
-
-class ParticleAttributeInput : public ParticleFunctionInput {
- private:
- std::string attribute_name_;
- const CPPType &attribute_type_;
-
- public:
- ParticleAttributeInput(std::string attribute_name, const CPPType &attribute_type)
- : attribute_name_(std::move(attribute_name)), attribute_type_(attribute_type)
- {
- }
-
- void add_input(ParticleFunctionInputContext &context,
- MFParamsBuilder &params,
- ResourceCollector &UNUSED(resources)) const override
- {
- std::optional<GSpan> span = context.particles.attributes.try_get(attribute_name_,
- attribute_type_);
- if (span.has_value()) {
- params.add_readonly_single_input(*span);
- }
- else {
- params.add_readonly_single_input(GVSpan::FromDefault(attribute_type_));
- }
- }
-};
-
-class SceneTimeInput : public ParticleFunctionInput {
- void add_input(ParticleFunctionInputContext &context,
- MFParamsBuilder &params,
- ResourceCollector &resources) const override
- {
- const float time = DEG_get_ctime(&context.solve_context.depsgraph);
- float *time_ptr = &resources.construct<float>(AT, time);
- params.add_readonly_single_input(time_ptr);
- }
-};
-
-class SimulationTimeInput : public ParticleFunctionInput {
- void add_input(ParticleFunctionInputContext &context,
- MFParamsBuilder &params,
- ResourceCollector &resources) const override
- {
- /* TODO: Vary this per particle. */
- const float time = context.solve_context.solve_interval.stop();
- float *time_ptr = &resources.construct<float>(AT, time);
- params.add_readonly_single_input(time_ptr);
- }
-};
-
-static const ParticleFunction *create_particle_function_for_inputs(
- CollectContext &context, Span<const MFInputSocket *> sockets_to_compute)
-{
- BLI_assert(sockets_to_compute.size() >= 1);
- const MFNetwork &network = sockets_to_compute[0]->node().network();
-
- VectorSet<const MFOutputSocket *> dummy_deps;
- VectorSet<const MFInputSocket *> unlinked_input_deps;
- network.find_dependencies(sockets_to_compute, dummy_deps, unlinked_input_deps);
- BLI_assert(unlinked_input_deps.size() == 0);
-
- Vector<const ParticleFunctionInput *> per_particle_inputs;
- for (const MFOutputSocket *socket : dummy_deps) {
- if (context.data_sources.particle_attributes.contains(socket)) {
- const std::string *attribute_name = context.data_sources.particle_attributes.lookup_ptr(
- socket);
- if (attribute_name == nullptr) {
- return nullptr;
- }
- per_particle_inputs.append(&context.resources.construct<ParticleAttributeInput>(
- AT, *attribute_name, socket->data_type().single_type()));
- }
- else if (context.data_sources.scene_time.contains(socket)) {
- per_particle_inputs.append(&context.resources.construct<SceneTimeInput>(AT));
- }
- else if (context.data_sources.simulation_time.contains(socket)) {
- per_particle_inputs.append(&context.resources.construct<SimulationTimeInput>(AT));
- }
- }
-
- const MultiFunction &per_particle_fn = context.resources.construct<MFNetworkEvaluator>(
- AT, dummy_deps.as_span(), sockets_to_compute);
-
- Array<bool> output_is_global(sockets_to_compute.size(), false);
-
- const ParticleFunction &particle_fn = context.resources.construct<ParticleFunction>(
- AT,
- nullptr,
- &per_particle_fn,
- Span<const ParticleFunctionInput *>(),
- per_particle_inputs.as_span(),
- output_is_global.as_span());
-
- return &particle_fn;
-}
-
-static const ParticleFunction *create_particle_function_for_inputs(
- CollectContext &context, Span<const DInputSocket *> dsockets_to_compute)
-{
- Vector<const MFInputSocket *> sockets_to_compute;
- for (const DInputSocket *dsocket : dsockets_to_compute) {
- const MFInputSocket &socket = context.network_map.lookup_dummy(*dsocket);
- sockets_to_compute.append(&socket);
- }
- return create_particle_function_for_inputs(context, sockets_to_compute);
-}
-
-class ParticleFunctionForce : public ParticleForce {
- private:
- const ParticleFunction &particle_fn_;
-
- public:
- ParticleFunctionForce(const ParticleFunction &particle_fn) : particle_fn_(particle_fn)
- {
- }
-
- void add_force(ParticleForceContext &context) const override
- {
- IndexMask mask = context.particles.index_mask;
- MutableSpan<float3> r_combined_force = context.force_dst;
-
- ParticleFunctionEvaluator evaluator{particle_fn_, context.solve_context, context.particles};
- evaluator.compute();
- VSpan<float3> forces = evaluator.get<float3>(0, "Force");
-
- for (int64_t i : mask) {
- r_combined_force[i] += forces[i];
- }
- }
-};
-
-static void create_forces_for_particle_simulation(CollectContext &context,
- const DNode &simulation_node)
-{
- Vector<const ParticleForce *> forces;
- for (const DOutputSocket *origin_socket : simulation_node.input(2, "Forces").linked_sockets()) {
- const DNode &origin_node = origin_socket->node();
- if (origin_node.idname() != "SimulationNodeForce") {
- continue;
- }
-
- const ParticleFunction *particle_fn = create_particle_function_for_inputs(
- context, {&origin_node.input(0, "Force")});
-
- if (particle_fn == nullptr) {
- continue;
- }
-
- const ParticleForce &force = context.resources.construct<ParticleFunctionForce>(AT,
- *particle_fn);
- forces.append(&force);
- }
-
- StringRef particle_name = get_identifier(context, simulation_node);
- context.influences.particle_forces.add_multiple_as(particle_name, forces);
-}
-
-static void collect_forces(CollectContext &context)
-{
- for (const DNode *dnode : context.particle_simulation_nodes) {
- create_forces_for_particle_simulation(context, *dnode);
- }
-}
-
-static ParticleEmitter *create_particle_emitter(CollectContext &context, const DNode &dnode)
-{
- Array<StringRefNull> names = find_linked_particle_simulations(context, dnode.output(0));
- if (names.size() == 0) {
- return nullptr;
- }
-
- Array<const MFInputSocket *> input_sockets{2};
- for (int i : input_sockets.index_range()) {
- input_sockets[i] = &context.network_map.lookup_dummy(dnode.input(i));
- }
-
- if (context.network.have_dummy_or_unlinked_dependencies(input_sockets)) {
- return nullptr;
- }
-
- MultiFunction &inputs_fn = context.resources.construct<MFNetworkEvaluator>(
- AT, Span<const MFOutputSocket *>(), input_sockets.as_span());
-
- const ParticleAction *birth_action = create_particle_action(
- context, dnode.input(2, "Execute"), names);
-
- StringRefNull own_state_name = get_identifier(context, dnode);
- context.required_states.add(own_state_name, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER);
- ParticleEmitter &emitter = context.resources.construct<ParticleMeshEmitter>(
- AT, own_state_name, names.as_span(), inputs_fn, birth_action);
- return &emitter;
-}
-
-static void collect_emitters(CollectContext &context)
-{
- for (const DNode *dnode : nodes_by_type(context, "SimulationNodeParticleMeshEmitter")) {
- ParticleEmitter *emitter = create_particle_emitter(context, *dnode);
- if (emitter != nullptr) {
- context.influences.particle_emitters.append(emitter);
- }
- }
-}
-
-static void collect_birth_events(CollectContext &context)
-{
- for (const DNode *event_dnode : nodes_by_type(context, "SimulationNodeParticleBirthEvent")) {
- const DInputSocket &execute_input = event_dnode->input(0);
- if (execute_input.linked_sockets().size() != 1) {
- continue;
- }
-
- Array<StringRefNull> particle_names = find_linked_particle_simulations(context,
- event_dnode->output(0));
-
- const DOutputSocket &execute_source = *execute_input.linked_sockets()[0];
- const ParticleAction *action = create_particle_action(context, execute_source, particle_names);
- if (action == nullptr) {
- continue;
- }
-
- for (StringRefNull particle_name : particle_names) {
- context.influences.particle_birth_actions.add_as(particle_name, action);
- }
- }
-}
-
-static void collect_time_step_events(CollectContext &context)
-{
- for (const DNode *event_dnode : nodes_by_type(context, "SimulationNodeParticleTimeStepEvent")) {
- const DInputSocket &execute_input = event_dnode->input(0);
- Array<StringRefNull> particle_names = find_linked_particle_simulations(context,
- event_dnode->output(0));
-
- const ParticleAction *action = create_particle_action(context, execute_input, particle_names);
- if (action == nullptr) {
- continue;
- }
-
- NodeSimParticleTimeStepEventType type =
- (NodeSimParticleTimeStepEventType)event_dnode->node_ref().bnode()->custom1;
- if (type == NODE_PARTICLE_TIME_STEP_EVENT_BEGIN) {
- for (StringRefNull particle_name : particle_names) {
- context.influences.particle_time_step_begin_actions.add_as(particle_name, action);
- }
- }
- else {
- for (StringRefNull particle_name : particle_names) {
- context.influences.particle_time_step_end_actions.add_as(particle_name, action);
- }
- }
- }
-}
-
-class SequenceParticleAction : public ParticleAction {
- private:
- Vector<const ParticleAction *> actions_;
-
- public:
- SequenceParticleAction(Span<const ParticleAction *> actions) : actions_(std::move(actions))
- {
- }
-
- void execute(ParticleActionContext &context) const override
- {
- for (const ParticleAction *action : actions_) {
- action->execute(context);
- }
- }
-};
-
-class SetParticleAttributeAction : public ParticleAction {
- private:
- std::string attribute_name_;
- const CPPType &cpp_type_;
- const ParticleFunction &inputs_fn_;
-
- public:
- SetParticleAttributeAction(std::string attribute_name,
- const CPPType &cpp_type,
- const ParticleFunction &inputs_fn)
- : attribute_name_(std::move(attribute_name)), cpp_type_(cpp_type), inputs_fn_(inputs_fn)
- {
- }
-
- void execute(ParticleActionContext &context) const override
- {
- std::optional<GMutableSpan> attribute_array = context.particles.attributes.try_get(
- attribute_name_, cpp_type_);
- if (!attribute_array.has_value()) {
- return;
- }
-
- ParticleFunctionEvaluator evaluator{inputs_fn_, context.solve_context, context.particles};
- evaluator.compute();
- GVSpan values = evaluator.get(0);
-
- if (values.is_single_element()) {
- cpp_type_.fill_initialized_indices(
- values.as_single_element(), attribute_array->data(), context.particles.index_mask);
- }
- else {
- GSpan value_array = values.as_full_array();
- cpp_type_.copy_to_initialized_indices(
- value_array.data(), attribute_array->data(), context.particles.index_mask);
- }
-
- if (attribute_name_ == "Velocity") {
- context.particles.update_diffs_after_velocity_change();
- }
- }
-};
-
-static const ParticleAction *concatenate_actions(CollectContext &context,
- Span<const ParticleAction *> actions)
-{
- Vector<const ParticleAction *> non_null_actions;
- for (const ParticleAction *action : actions) {
- if (action != nullptr) {
- non_null_actions.append(action);
- }
- }
- if (non_null_actions.size() == 0) {
- return nullptr;
- }
- if (non_null_actions.size() == 1) {
- return non_null_actions[0];
- }
- return &context.resources.construct<SequenceParticleAction>(AT, std::move(non_null_actions));
-}
-
-static const ParticleAction *create_set_particle_attribute_action(
- CollectContext &context, const DOutputSocket &dsocket, Span<StringRefNull> particle_names)
-{
- const DNode &dnode = dsocket.node();
-
- const ParticleAction *previous_action = create_particle_action(
- context, dnode.input(0), particle_names);
-
- MFInputSocket &name_socket = context.network_map.lookup_dummy(dnode.input(1));
- MFInputSocket &value_socket = name_socket.node().input(1);
- std::optional<Array<std::string>> names = compute_global_string_inputs(context.network_map,
- {&name_socket});
- if (!names.has_value()) {
- return previous_action;
- }
-
- std::string attribute_name = (*names)[0];
- if (attribute_name.empty()) {
- return previous_action;
- }
- const CPPType &attribute_type = value_socket.data_type().single_type();
-
- const ParticleFunction *inputs_fn = create_particle_function_for_inputs(context,
- {&value_socket});
- if (inputs_fn == nullptr) {
- return previous_action;
- }
-
- for (StringRef particle_name : particle_names) {
- context.influences.particle_attributes_builder.lookup_as(particle_name)
- ->add(attribute_name, attribute_type);
- }
-
- ParticleAction &this_action = context.resources.construct<SetParticleAttributeAction>(
- AT, attribute_name, attribute_type, *inputs_fn);
-
- return concatenate_actions(context, {previous_action, &this_action});
-}
-
-class ParticleConditionAction : public ParticleAction {
- private:
- const ParticleFunction &inputs_fn_;
- const ParticleAction *action_true_;
- const ParticleAction *action_false_;
-
- public:
- ParticleConditionAction(const ParticleFunction &inputs_fn,
- const ParticleAction *action_true,
- const ParticleAction *action_false)
- : inputs_fn_(inputs_fn), action_true_(action_true), action_false_(action_false)
- {
- }
-
- void execute(ParticleActionContext &context) const override
- {
- ParticleFunctionEvaluator evaluator{inputs_fn_, context.solve_context, context.particles};
- evaluator.compute();
- VSpan<bool> conditions = evaluator.get<bool>(0, "Condition");
-
- if (conditions.is_single_element()) {
- const bool condition = conditions.as_single_element();
- if (condition) {
- if (action_true_ != nullptr) {
- action_true_->execute(context);
- }
- }
- else {
- if (action_false_ != nullptr) {
- action_false_->execute(context);
- }
- }
- }
- else {
- Span<bool> conditions_array = conditions.as_full_array();
-
- Vector<int64_t> true_indices;
- Vector<int64_t> false_indices;
- for (int i : context.particles.index_mask) {
- if (conditions_array[i]) {
- true_indices.append(i);
- }
- else {
- false_indices.append(i);
- }
- }
-
- if (action_true_ != nullptr) {
- ParticleChunkContext chunk_context{context.particles.state,
- true_indices.as_span(),
- context.particles.attributes,
- context.particles.integration};
- ParticleActionContext action_context{context.solve_context, chunk_context};
- action_true_->execute(action_context);
- }
- if (action_false_ != nullptr) {
- ParticleChunkContext chunk_context{context.particles.state,
- false_indices.as_span(),
- context.particles.attributes,
- context.particles.integration};
- ParticleActionContext action_context{context.solve_context, chunk_context};
- action_false_->execute(action_context);
- }
- }
- }
-};
-
-static const ParticleAction *create_particle_condition_action(CollectContext &context,
- const DOutputSocket &dsocket,
- Span<StringRefNull> particle_names)
-{
- const DNode &dnode = dsocket.node();
-
- const ParticleFunction *inputs_fn = create_particle_function_for_inputs(
- context, {&dnode.input(0, "Condition")});
- if (inputs_fn == nullptr) {
- return nullptr;
- }
-
- const ParticleAction *true_action = create_particle_action(
- context, dnode.input(1), particle_names);
- const ParticleAction *false_action = create_particle_action(
- context, dnode.input(2), particle_names);
-
- if (true_action == nullptr && false_action == nullptr) {
- return nullptr;
- }
- return &context.resources.construct<ParticleConditionAction>(
- AT, *inputs_fn, true_action, false_action);
-}
-
-class KillParticleAction : public ParticleAction {
- public:
- void execute(ParticleActionContext &context) const override
- {
- MutableSpan<int> dead_states = context.particles.attributes.get<int>("Dead");
- for (int i : context.particles.index_mask) {
- dead_states[i] = true;
- }
- }
-};
-
-static const ParticleAction *create_particle_action(CollectContext &context,
- const DOutputSocket &dsocket,
- Span<StringRefNull> particle_names)
-{
- const DNode &dnode = dsocket.node();
- StringRef idname = dnode.idname();
- if (idname == "SimulationNodeSetParticleAttribute") {
- return create_set_particle_attribute_action(context, dsocket, particle_names);
- }
- if (idname == "SimulationNodeExecuteCondition") {
- return create_particle_condition_action(context, dsocket, particle_names);
- }
- if (idname == "SimulationNodeKillParticle") {
- return &context.resources.construct<KillParticleAction>(AT);
- }
- return nullptr;
-}
-
-static void initialize_particle_attribute_builders(CollectContext &context)
-{
- for (const DNode *dnode : context.particle_simulation_nodes) {
- StringRef name = get_identifier(context, *dnode);
- AttributesInfoBuilder &attributes_builder = context.resources.construct<AttributesInfoBuilder>(
- AT);
- attributes_builder.add<float3>("Position", {0, 0, 0});
- attributes_builder.add<float3>("Velocity", {0, 0, 0});
- attributes_builder.add<int>("ID", 0);
- /* TODO: Use bool property, but need to add CD_PROP_BOOL first. */
- attributes_builder.add<int>("Dead", 0);
- /* TODO: Use uint32_t, but we don't have a corresponding custom property type. */
- attributes_builder.add<int>("Hash", 0);
- attributes_builder.add<float>("Birth Time", 0.0f);
- attributes_builder.add<float>("Radius", 0.02f);
- context.influences.particle_attributes_builder.add_new(name, &attributes_builder);
- }
-}
-
-static void optimize_function_network(CollectContext &context)
-{
- fn::mf_network_optimization::constant_folding(context.network, context.resources);
- fn::mf_network_optimization::common_subnetwork_elimination(context.network);
- fn::mf_network_optimization::dead_node_removal(context.network);
- // WM_clipboard_text_set(network.to_dot().c_str(), false);
-}
-
-class AgeReachedEvent : public ParticleEvent {
- private:
- std::string attribute_name_;
- const ParticleFunction &inputs_fn_;
- const ParticleAction &action_;
-
- public:
- AgeReachedEvent(std::string attribute_name,
- const ParticleFunction &inputs_fn,
- const ParticleAction &action)
- : attribute_name_(std::move(attribute_name)), inputs_fn_(inputs_fn), action_(action)
- {
- }
-
- void filter(ParticleEventFilterContext &context) const override
- {
- Span<float> birth_times = context.particles.attributes.get<float>("Birth Time");
- std::optional<Span<int>> has_been_triggered = context.particles.attributes.try_get<int>(
- attribute_name_);
- if (!has_been_triggered.has_value()) {
- return;
- }
-
- ParticleFunctionEvaluator evaluator{inputs_fn_, context.solve_context, context.particles};
- evaluator.compute();
- VSpan<float> trigger_ages = evaluator.get<float>(0, "Age");
-
- const float end_time = context.particles.integration->end_time;
- for (int i : context.particles.index_mask) {
- if ((*has_been_triggered)[i]) {
- continue;
- }
- const float trigger_age = trigger_ages[i];
- const float birth_time = birth_times[i];
- const float trigger_time = birth_time + trigger_age;
- if (trigger_time > end_time) {
- continue;
- }
-
- const float duration = context.particles.integration->durations[i];
- TimeInterval interval(end_time - duration, duration);
- const float time_factor = interval.safe_factor_at_time(trigger_time);
-
- context.factor_dst[i] = std::max<float>(0.0f, time_factor);
- }
- }
-
- void execute(ParticleActionContext &context) const override
- {
- MutableSpan<int> has_been_triggered = context.particles.attributes.get<int>(attribute_name_);
- for (int i : context.particles.index_mask) {
- has_been_triggered[i] = 1;
- }
- action_.execute(context);
- }
-};
-
-static void collect_age_reached_events(CollectContext &context)
-{
- for (const DNode *dnode : nodes_by_type(context, "SimulationNodeAgeReachedEvent")) {
- const DInputSocket &age_input = dnode->input(0, "Age");
- const DInputSocket &execute_input = dnode->input(1, "Execute");
- Array<StringRefNull> particle_names = find_linked_particle_simulations(context,
- dnode->output(0));
- const ParticleAction *action = create_particle_action(context, execute_input, particle_names);
- if (action == nullptr) {
- continue;
- }
- const ParticleFunction *inputs_fn = create_particle_function_for_inputs(context, {&age_input});
- if (inputs_fn == nullptr) {
- continue;
- }
-
- std::string attribute_name = get_identifier(context, *dnode);
- const ParticleEvent &event = context.resources.construct<AgeReachedEvent>(
- AT, attribute_name, *inputs_fn, *action);
- for (StringRefNull particle_name : particle_names) {
- const bool added_attribute = context.influences.particle_attributes_builder
- .lookup_as(particle_name)
- ->add<int>(attribute_name, 0);
- if (added_attribute) {
- context.influences.particle_events.add_as(particle_name, &event);
- }
- }
- }
-}
-
-void collect_simulation_influences(Simulation &simulation,
- ResourceCollector &resources,
- SimulationInfluences &r_influences,
- RequiredStates &r_required_states)
-{
- NodeTreeRefMap tree_refs;
- const DerivedNodeTree tree{simulation.nodetree, tree_refs};
-
- MFNetwork &network = resources.construct<MFNetwork>(AT);
- MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources);
-
- CollectContext context{r_influences, r_required_states, resources, network_map};
- initialize_particle_attribute_builders(context);
-
- prepare_particle_attribute_nodes(context);
- prepare_time_input_nodes(context);
-
- collect_forces(context);
- collect_emitters(context);
- collect_birth_events(context);
- collect_time_step_events(context);
- collect_age_reached_events(context);
-
- optimize_function_network(context);
-
- for (const DNode *dnode : context.particle_simulation_nodes) {
- r_required_states.add(get_identifier(context, *dnode), SIM_TYPE_NAME_PARTICLE_SIMULATION);
- }
-}
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_collect_influences.hh b/source/blender/simulation/intern/simulation_collect_influences.hh
deleted file mode 100644
index 8673a308b04..00000000000
--- a/source/blender/simulation/intern/simulation_collect_influences.hh
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "NOD_derived_node_tree.hh"
-
-#include "BLI_resource_collector.hh"
-
-#include "simulation_solver_influences.hh"
-
-namespace blender::sim {
-
-class RequiredStates {
- private:
- Map<std::string, const char *> state_type_by_state_name_;
-
- public:
- void add(std::string state_name, const char *state_type)
- {
- BLI_assert(state_type != nullptr);
- const char *type_name = state_type_by_state_name_.lookup_default(state_name, nullptr);
- if (type_name != nullptr) {
- if (!STREQ(state_type, type_name)) {
- std::cout << "Warning: Tried to have two different states with the same name.\n";
- std::cout << " Name: " << state_name << "\n";
- std::cout << " Type 1: " << state_type << "\n";
- std::cout << " Type 2: " << type_name << "\n";
- }
- return;
- }
-
- state_type_by_state_name_.add(std::move(state_name), state_type);
- }
-
- const Map<std::string, const char *> &states() const
- {
- return state_type_by_state_name_;
- }
-
- bool is_required(StringRef state_name, StringRef state_type) const
- {
- return state_type_by_state_name_.lookup_default_as(state_name, "") == state_type;
- }
-};
-
-void collect_simulation_influences(Simulation &simulation,
- ResourceCollector &resources,
- SimulationInfluences &r_influences,
- RequiredStates &r_required_states);
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver.cc b/source/blender/simulation/intern/simulation_solver.cc
deleted file mode 100644
index d53ccd2bd49..00000000000
--- a/source/blender/simulation/intern/simulation_solver.cc
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "simulation_solver.hh"
-
-#include "BKE_customdata.h"
-#include "BKE_persistent_data_handle.hh"
-
-#include "BLI_rand.hh"
-#include "BLI_set.hh"
-
-#include "DEG_depsgraph_query.h"
-
-namespace blender::sim {
-
-static CustomDataType cpp_to_custom_data_type(const CPPType &type)
-{
- if (type.is<float3>()) {
- return CD_PROP_FLOAT3;
- }
- if (type.is<float>()) {
- return CD_PROP_FLOAT;
- }
- if (type.is<int32_t>()) {
- return CD_PROP_INT32;
- }
- BLI_assert(false);
- return CD_PROP_FLOAT;
-}
-
-static const CPPType &custom_to_cpp_data_type(CustomDataType type)
-{
- switch (type) {
- case CD_PROP_FLOAT3:
- return CPPType::get<float3>();
- case CD_PROP_FLOAT:
- return CPPType::get<float>();
- case CD_PROP_INT32:
- return CPPType::get<int32_t>();
- default:
- BLI_assert(false);
- return CPPType::get<float>();
- }
-}
-
-class CustomDataAttributesRef {
- private:
- Array<void *> buffers_;
- int64_t size_;
- const AttributesInfo &info_;
-
- public:
- CustomDataAttributesRef(CustomData &custom_data, int64_t size, const AttributesInfo &info)
- : buffers_(info.size(), nullptr), size_(size), info_(info)
- {
- for (int attribute_index : info.index_range()) {
- StringRefNull name = info.name_of(attribute_index);
- const CPPType &cpp_type = info.type_of(attribute_index);
- CustomDataType custom_type = cpp_to_custom_data_type(cpp_type);
- void *data = CustomData_get_layer_named(&custom_data, custom_type, name.c_str());
- buffers_[attribute_index] = data;
- }
- }
-
- operator MutableAttributesRef()
- {
- return MutableAttributesRef(info_, buffers_, size_);
- }
-
- operator AttributesRef() const
- {
- return AttributesRef(info_, buffers_, size_);
- }
-};
-
-static void ensure_attributes_exist(ParticleSimulationState *state, const AttributesInfo &info)
-{
- bool found_layer_to_remove;
- do {
- found_layer_to_remove = false;
- for (int layer_index = 0; layer_index < state->attributes.totlayer; layer_index++) {
- CustomDataLayer *layer = &state->attributes.layers[layer_index];
- BLI_assert(layer->name != nullptr);
- const CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer->type);
- StringRefNull name = layer->name;
- if (!info.has_attribute(name, cpp_type)) {
- found_layer_to_remove = true;
- CustomData_free_layer(&state->attributes, layer->type, state->tot_particles, layer_index);
- break;
- }
- }
- } while (found_layer_to_remove);
-
- for (int attribute_index : info.index_range()) {
- StringRefNull attribute_name = info.name_of(attribute_index);
- const CPPType &cpp_type = info.type_of(attribute_index);
- CustomDataType custom_type = cpp_to_custom_data_type(cpp_type);
- if (CustomData_get_layer_named(&state->attributes, custom_type, attribute_name.c_str()) ==
- nullptr) {
- void *data = CustomData_add_layer_named(&state->attributes,
- custom_type,
- CD_CALLOC,
- nullptr,
- state->tot_particles,
- attribute_name.c_str());
- cpp_type.fill_uninitialized(info.default_of(attribute_index), data, state->tot_particles);
- }
- }
-}
-
-BLI_NOINLINE static void apply_remaining_diffs(ParticleChunkContext &context)
-{
- BLI_assert(context.integration != nullptr);
- MutableSpan<float3> positions = context.attributes.get<float3>("Position");
- MutableSpan<float3> velocities = context.attributes.get<float3>("Velocity");
-
- for (int i : context.index_mask) {
- positions[i] += context.integration->position_diffs[i];
- velocities[i] += context.integration->velocity_diffs[i];
- }
-}
-
-BLI_NOINLINE static void find_next_event_per_particle(
- SimulationSolveContext &solve_context,
- ParticleChunkContext &particles,
- Span<const ParticleEvent *> events,
- MutableSpan<int> r_next_event_indices,
- MutableSpan<float> r_time_factors_to_next_event)
-{
- r_next_event_indices.fill_indices(particles.index_mask, -1);
- r_time_factors_to_next_event.fill_indices(particles.index_mask, 1.0f);
-
- Array<float> time_factors(particles.index_mask.min_array_size());
- for (int event_index : events.index_range()) {
- time_factors.fill(-1.0f);
- ParticleEventFilterContext event_context{solve_context, particles, time_factors};
- const ParticleEvent &event = *events[event_index];
- event.filter(event_context);
-
- for (int i : particles.index_mask) {
- const float time_factor = time_factors[i];
- const float previously_smallest_time_factor = r_time_factors_to_next_event[i];
- if (time_factor >= 0.0f && time_factor <= previously_smallest_time_factor) {
- r_time_factors_to_next_event[i] = time_factor;
- r_next_event_indices[i] = event_index;
- }
- }
- }
-}
-
-BLI_NOINLINE static void forward_particles_to_next_event_or_end(
- ParticleChunkContext &particles, Span<float> time_factors_to_next_event)
-{
- MutableSpan<float3> positions = particles.attributes.get<float3>("Position");
- MutableSpan<float3> velocities = particles.attributes.get<float3>("Velocity");
-
- MutableSpan<float3> position_diffs = particles.integration->position_diffs;
- MutableSpan<float3> velocity_diffs = particles.integration->velocity_diffs;
- MutableSpan<float> durations = particles.integration->durations;
-
- for (int i : particles.index_mask) {
- const float time_factor = time_factors_to_next_event[i];
- positions[i] += position_diffs[i] * time_factor;
- velocities[i] += velocity_diffs[i] * time_factor;
-
- const float remaining_time_factor = 1.0f - time_factor;
- position_diffs[i] *= remaining_time_factor;
- velocity_diffs[i] *= remaining_time_factor;
- durations[i] *= remaining_time_factor;
- }
-}
-
-BLI_NOINLINE static void group_particles_by_event(
- IndexMask mask,
- Span<int> next_event_indices,
- MutableSpan<Vector<int64_t>> r_particles_per_event)
-{
- for (int i : mask) {
- int event_index = next_event_indices[i];
- if (event_index >= 0) {
- r_particles_per_event[event_index].append(i);
- }
- }
-}
-
-BLI_NOINLINE static void execute_events(SimulationSolveContext &solve_context,
- ParticleChunkContext &all_particles,
- Span<const ParticleEvent *> events,
- Span<Vector<int64_t>> particles_per_event)
-{
- for (int event_index : events.index_range()) {
- Span<int64_t> pindices = particles_per_event[event_index];
- if (pindices.is_empty()) {
- continue;
- }
-
- const ParticleEvent &event = *events[event_index];
- ParticleChunkContext particles{
- all_particles.state, pindices, all_particles.attributes, all_particles.integration};
- ParticleActionContext action_context{solve_context, particles};
- event.execute(action_context);
- }
-}
-
-BLI_NOINLINE static void find_unfinished_particles(IndexMask index_mask,
- Span<float> time_factors_to_next_event,
- Vector<int64_t> &r_unfinished_pindices)
-{
- for (int i : index_mask) {
- float time_factor = time_factors_to_next_event[i];
- if (time_factor < 1.0f) {
- r_unfinished_pindices.append(i);
- }
- }
-}
-
-BLI_NOINLINE static void simulate_to_next_event(SimulationSolveContext &solve_context,
- ParticleChunkContext &particles,
- Span<const ParticleEvent *> events,
- Vector<int64_t> &r_unfinished_pindices)
-{
- int array_size = particles.index_mask.min_array_size();
- Array<int> next_event_indices(array_size);
- Array<float> time_factors_to_next_event(array_size);
-
- find_next_event_per_particle(
- solve_context, particles, events, next_event_indices, time_factors_to_next_event);
-
- forward_particles_to_next_event_or_end(particles, time_factors_to_next_event);
-
- Array<Vector<int64_t>> particles_per_event(events.size());
- group_particles_by_event(particles.index_mask, next_event_indices, particles_per_event);
-
- execute_events(solve_context, particles, events, particles_per_event);
- find_unfinished_particles(
- particles.index_mask, time_factors_to_next_event, r_unfinished_pindices);
-}
-
-BLI_NOINLINE static void simulate_with_max_n_events(SimulationSolveContext &solve_context,
- ParticleSimulationState &state,
- ParticleChunkContext &particles,
- int max_events)
-{
- Span<const ParticleEvent *> events = solve_context.influences.particle_events.lookup_as(
- state.head.name);
- if (events.size() == 0) {
- apply_remaining_diffs(particles);
- return;
- }
-
- Vector<int64_t> unfininished_pindices = particles.index_mask.indices();
- for (int iteration : IndexRange(max_events)) {
- UNUSED_VARS(iteration);
- if (unfininished_pindices.is_empty()) {
- break;
- }
-
- Vector<int64_t> new_unfinished_pindices;
- ParticleChunkContext remaining_particles{particles.state,
- unfininished_pindices.as_span(),
- particles.attributes,
- particles.integration};
- simulate_to_next_event(solve_context, remaining_particles, events, new_unfinished_pindices);
- unfininished_pindices = std::move(new_unfinished_pindices);
- }
-
- if (!unfininished_pindices.is_empty()) {
- ParticleChunkContext remaining_particles{particles.state,
- unfininished_pindices.as_span(),
- particles.attributes,
- particles.integration};
- apply_remaining_diffs(remaining_particles);
- }
-}
-
-BLI_NOINLINE static void simulate_particle_chunk(SimulationSolveContext &solve_context,
- ParticleSimulationState &state,
- MutableAttributesRef attributes,
- MutableSpan<float> remaining_durations,
- float end_time)
-{
- int particle_amount = attributes.size();
-
- Span<const ParticleAction *> begin_actions =
- solve_context.influences.particle_time_step_begin_actions.lookup_as(state.head.name);
- for (const ParticleAction *action : begin_actions) {
- ParticleChunkContext particles{state, IndexMask(particle_amount), attributes};
- ParticleActionContext action_context{solve_context, particles};
- action->execute(action_context);
- }
-
- Array<float3> force_vectors{particle_amount, {0, 0, 0}};
- Span<const ParticleForce *> forces = solve_context.influences.particle_forces.lookup_as(
- state.head.name);
- for (const ParticleForce *force : forces) {
- ParticleChunkContext particles{state, IndexMask(particle_amount), attributes};
- ParticleForceContext particle_force_context{solve_context, particles, force_vectors};
- force->add_force(particle_force_context);
- }
-
- MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
-
- Array<float3> position_diffs(particle_amount);
- Array<float3> velocity_diffs(particle_amount);
- for (int i : IndexRange(particle_amount)) {
- const float time_step = remaining_durations[i];
- velocity_diffs[i] = force_vectors[i] * time_step;
- position_diffs[i] = (velocities[i] + velocity_diffs[i] / 2.0f) * time_step;
- }
-
- ParticleChunkIntegrationContext integration_context = {
- position_diffs, velocity_diffs, remaining_durations, end_time};
- ParticleChunkContext particle_chunk_context{
- state, IndexMask(particle_amount), attributes, &integration_context};
-
- simulate_with_max_n_events(solve_context, state, particle_chunk_context, 10);
-
- Span<const ParticleAction *> end_actions =
- solve_context.influences.particle_time_step_end_actions.lookup_as(state.head.name);
- for (const ParticleAction *action : end_actions) {
- ParticleChunkContext particles{state, IndexMask(particle_amount), attributes};
- ParticleActionContext action_context{solve_context, particles};
- action->execute(action_context);
- }
-}
-
-BLI_NOINLINE static void simulate_existing_particles(SimulationSolveContext &solve_context,
- ParticleSimulationState &state,
- const AttributesInfo &attributes_info)
-{
- CustomDataAttributesRef custom_data_attributes{
- state.attributes, state.tot_particles, attributes_info};
- MutableAttributesRef attributes = custom_data_attributes;
-
- Array<float> remaining_durations(state.tot_particles, solve_context.solve_interval.duration());
- simulate_particle_chunk(
- solve_context, state, attributes, remaining_durations, solve_context.solve_interval.stop());
-}
-
-BLI_NOINLINE static void run_emitters(SimulationSolveContext &solve_context,
- ParticleAllocators &particle_allocators)
-{
- for (const ParticleEmitter *emitter : solve_context.influences.particle_emitters) {
- ParticleEmitterContext emitter_context{
- solve_context, particle_allocators, solve_context.solve_interval};
- emitter->emit(emitter_context);
- }
-}
-
-BLI_NOINLINE static int count_particles_after_time_step(ParticleSimulationState &state,
- ParticleAllocator &allocator)
-{
- CustomDataAttributesRef custom_data_attributes{
- state.attributes, state.tot_particles, allocator.attributes_info()};
- MutableAttributesRef attributes = custom_data_attributes;
- int new_particle_amount = attributes.get<int>("Dead").count(0);
-
- for (MutableAttributesRef emitted_attributes : allocator.get_allocations()) {
- new_particle_amount += emitted_attributes.get<int>("Dead").count(0);
- }
-
- return new_particle_amount;
-}
-
-BLI_NOINLINE static void remove_dead_and_add_new_particles(ParticleSimulationState &state,
- ParticleAllocator &allocator)
-{
- const int new_particle_amount = count_particles_after_time_step(state, allocator);
-
- CustomDataAttributesRef custom_data_attributes{
- state.attributes, state.tot_particles, allocator.attributes_info()};
-
- Vector<MutableAttributesRef> particle_sources;
- particle_sources.append(custom_data_attributes);
- particle_sources.extend(allocator.get_allocations());
-
- CustomDataLayer *dead_layer = nullptr;
-
- for (CustomDataLayer &layer : MutableSpan(state.attributes.layers, state.attributes.totlayer)) {
- StringRefNull name = layer.name;
- if (name == "Dead") {
- dead_layer = &layer;
- continue;
- }
- const CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer.type);
- GMutableSpan new_buffer{
- cpp_type,
- MEM_mallocN_aligned(new_particle_amount * cpp_type.size(), cpp_type.alignment(), AT),
- new_particle_amount};
-
- int current = 0;
- for (MutableAttributesRef attributes : particle_sources) {
- Span<int> dead_states = attributes.get<int>("Dead");
- GSpan source_buffer = attributes.get(name);
- BLI_assert(source_buffer.type() == cpp_type);
- for (int i : attributes.index_range()) {
- if (dead_states[i] == 0) {
- cpp_type.copy_to_uninitialized(source_buffer[i], new_buffer[current]);
- current++;
- }
- }
- }
-
- if (layer.data != nullptr) {
- MEM_freeN(layer.data);
- }
- layer.data = new_buffer.data();
- }
-
- BLI_assert(dead_layer != nullptr);
- if (dead_layer->data != nullptr) {
- MEM_freeN(dead_layer->data);
- }
- dead_layer->data = MEM_callocN(sizeof(int) * new_particle_amount, AT);
-
- state.tot_particles = new_particle_amount;
- state.next_particle_id += allocator.total_allocated();
-}
-
-void initialize_simulation_states(Simulation &simulation,
- Depsgraph &UNUSED(depsgraph),
- const SimulationInfluences &UNUSED(influences),
- const bke::PersistentDataHandleMap &UNUSED(handle_map))
-{
- simulation.current_simulation_time = 0.0f;
-}
-
-void solve_simulation_time_step(Simulation &simulation,
- Depsgraph &depsgraph,
- const SimulationInfluences &influences,
- const bke::PersistentDataHandleMap &handle_map,
- const DependencyAnimations &dependency_animations,
- float time_step)
-{
- SimulationStateMap state_map;
- LISTBASE_FOREACH (SimulationState *, state, &simulation.states) {
- state_map.add(state);
- }
-
- SimulationSolveContext solve_context{simulation,
- depsgraph,
- influences,
- TimeInterval(simulation.current_simulation_time, time_step),
- state_map,
- handle_map,
- dependency_animations};
-
- Span<ParticleSimulationState *> particle_simulation_states =
- state_map.lookup<ParticleSimulationState>();
-
- Map<std::string, std::unique_ptr<AttributesInfo>> attribute_infos;
- Map<std::string, std::unique_ptr<ParticleAllocator>> particle_allocators_map;
- for (ParticleSimulationState *state : particle_simulation_states) {
- const AttributesInfoBuilder &builder = *influences.particle_attributes_builder.lookup_as(
- state->head.name);
- auto info = std::make_unique<AttributesInfo>(builder);
-
- ensure_attributes_exist(state, *info);
-
- uint32_t hash_seed = DefaultHash<StringRef>{}(state->head.name);
- particle_allocators_map.add_new(
- state->head.name,
- std::make_unique<ParticleAllocator>(*info, state->next_particle_id, hash_seed));
- attribute_infos.add_new(state->head.name, std::move(info));
- }
-
- ParticleAllocators particle_allocators{particle_allocators_map};
-
- for (ParticleSimulationState *state : particle_simulation_states) {
- const AttributesInfo &attributes_info = *attribute_infos.lookup_as(state->head.name);
- simulate_existing_particles(solve_context, *state, attributes_info);
- }
-
- run_emitters(solve_context, particle_allocators);
-
- for (ParticleSimulationState *state : particle_simulation_states) {
- ParticleAllocator &allocator = *particle_allocators.try_get_allocator(state->head.name);
-
- for (MutableAttributesRef attributes : allocator.get_allocations()) {
- Span<const ParticleAction *> actions = influences.particle_birth_actions.lookup_as(
- state->head.name);
- for (const ParticleAction *action : actions) {
- ParticleChunkContext chunk_context{*state, IndexRange(attributes.size()), attributes};
- ParticleActionContext action_context{solve_context, chunk_context};
- action->execute(action_context);
- }
- }
- }
-
- for (ParticleSimulationState *state : particle_simulation_states) {
- ParticleAllocator &allocator = *particle_allocators.try_get_allocator(state->head.name);
-
- for (MutableAttributesRef attributes : allocator.get_allocations()) {
- Array<float> remaining_durations(attributes.size());
- Span<float> birth_times = attributes.get<float>("Birth Time");
- const float end_time = solve_context.solve_interval.stop();
- for (int i : attributes.index_range()) {
- remaining_durations[i] = end_time - birth_times[i];
- }
- simulate_particle_chunk(solve_context, *state, attributes, remaining_durations, end_time);
- }
-
- remove_dead_and_add_new_particles(*state, allocator);
- }
-
- simulation.current_simulation_time = solve_context.solve_interval.stop();
-}
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver.hh b/source/blender/simulation/intern/simulation_solver.hh
deleted file mode 100644
index 2cf8eb2aa27..00000000000
--- a/source/blender/simulation/intern/simulation_solver.hh
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "simulation_collect_influences.hh"
-
-struct Depsgraph;
-
-namespace blender::sim {
-
-void initialize_simulation_states(Simulation &simulation,
- Depsgraph &depsgraph,
- const SimulationInfluences &influences,
- const bke::PersistentDataHandleMap &handle_map);
-
-void solve_simulation_time_step(Simulation &simulation,
- Depsgraph &depsgraph,
- const SimulationInfluences &influences,
- const bke::PersistentDataHandleMap &handle_map,
- const DependencyAnimations &dependency_animations,
- float time_step);
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver_influences.cc b/source/blender/simulation/intern/simulation_solver_influences.cc
deleted file mode 100644
index 3485d7c7bfb..00000000000
--- a/source/blender/simulation/intern/simulation_solver_influences.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "simulation_solver_influences.hh"
-
-#include "DNA_object_types.h"
-
-namespace blender::sim {
-
-ParticleForce::~ParticleForce()
-{
-}
-
-ParticleEmitter::~ParticleEmitter()
-{
-}
-
-ParticleAction::~ParticleAction()
-{
-}
-
-ParticleEvent::~ParticleEvent()
-{
-}
-
-DependencyAnimations::~DependencyAnimations()
-{
-}
-
-bool DependencyAnimations::is_object_transform_changing(Object &UNUSED(object)) const
-{
- return false;
-}
-
-void DependencyAnimations::get_object_transforms(Object &object,
- Span<float> simulation_times,
- MutableSpan<float4x4> r_transforms) const
-{
- assert_same_size(simulation_times, r_transforms);
- float4x4 world_matrix = object.obmat;
- r_transforms.fill(world_matrix);
-}
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver_influences.hh b/source/blender/simulation/intern/simulation_solver_influences.hh
deleted file mode 100644
index d33aec855b2..00000000000
--- a/source/blender/simulation/intern/simulation_solver_influences.hh
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "BLI_float3.hh"
-#include "BLI_float4x4.hh"
-#include "BLI_multi_value_map.hh"
-#include "BLI_span.hh"
-
-#include "DNA_simulation_types.h"
-
-#include "FN_attributes_ref.hh"
-
-#include "BKE_persistent_data_handle.hh"
-#include "BKE_simulation.h"
-
-#include "particle_allocator.hh"
-#include "time_interval.hh"
-
-namespace blender::sim {
-
-using fn::AttributesInfo;
-using fn::AttributesInfoBuilder;
-using fn::AttributesRef;
-using fn::CPPType;
-using fn::GMutableSpan;
-using fn::GSpan;
-using fn::MutableAttributesRef;
-
-struct ParticleActionContext;
-struct ParticleEmitterContext;
-struct ParticleEventFilterContext;
-struct ParticleForceContext;
-
-class ParticleEmitter {
- public:
- virtual ~ParticleEmitter();
- virtual void emit(ParticleEmitterContext &context) const = 0;
-};
-
-class ParticleForce {
- public:
- virtual ~ParticleForce();
- virtual void add_force(ParticleForceContext &context) const = 0;
-};
-
-class ParticleAction {
- public:
- virtual ~ParticleAction();
- virtual void execute(ParticleActionContext &context) const = 0;
-};
-
-class ParticleEvent {
- public:
- virtual ~ParticleEvent();
- virtual void filter(ParticleEventFilterContext &context) const = 0;
- virtual void execute(ParticleActionContext &context) const = 0;
-};
-
-struct SimulationInfluences {
- MultiValueMap<std::string, const ParticleForce *> particle_forces;
- MultiValueMap<std::string, const ParticleAction *> particle_birth_actions;
- MultiValueMap<std::string, const ParticleAction *> particle_time_step_begin_actions;
- MultiValueMap<std::string, const ParticleAction *> particle_time_step_end_actions;
- MultiValueMap<std::string, const ParticleEvent *> particle_events;
- Map<std::string, AttributesInfoBuilder *> particle_attributes_builder;
- Vector<const ParticleEmitter *> particle_emitters;
-};
-
-class SimulationStateMap {
- private:
- Map<StringRefNull, SimulationState *> states_by_name_;
- MultiValueMap<StringRefNull, SimulationState *> states_by_type_;
-
- public:
- void add(SimulationState *state)
- {
- states_by_name_.add_new(state->name, state);
- states_by_type_.add(state->type, state);
- }
-
- template<typename StateType> StateType *lookup(StringRef name) const
- {
- const char *type = BKE_simulation_get_state_type_name<StateType>();
- return reinterpret_cast<StateType *>(this->lookup_name_type(name, type));
- }
-
- template<typename StateType> Span<StateType *> lookup() const
- {
- const char *type = BKE_simulation_get_state_type_name<StateType>();
- return this->lookup_type(type).cast<StateType *>();
- }
-
- SimulationState *lookup_name_type(StringRef name, StringRef type) const
- {
- SimulationState *state = states_by_name_.lookup_default_as(name, nullptr);
- if (state == nullptr) {
- return nullptr;
- }
- if (state->type == type) {
- return state;
- }
- return nullptr;
- }
-
- Span<SimulationState *> lookup_type(StringRef type) const
- {
- return states_by_type_.lookup_as(type);
- }
-};
-
-class DependencyAnimations {
- public:
- ~DependencyAnimations();
-
- virtual bool is_object_transform_changing(Object &object) const;
- virtual void get_object_transforms(Object &object,
- Span<float> simulation_times,
- MutableSpan<float4x4> r_transforms) const;
-};
-
-struct SimulationSolveContext {
- Simulation &simulation;
- Depsgraph &depsgraph;
- const SimulationInfluences &influences;
- TimeInterval solve_interval;
- const SimulationStateMap &state_map;
- const bke::PersistentDataHandleMap &handle_map;
- const DependencyAnimations &dependency_animations;
-};
-
-class ParticleAllocators {
- private:
- Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators_;
-
- public:
- ParticleAllocators(Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators)
- : allocators_(allocators)
- {
- }
-
- ParticleAllocator *try_get_allocator(StringRef particle_simulation_name)
- {
- auto *ptr = allocators_.lookup_ptr_as(particle_simulation_name);
- if (ptr != nullptr) {
- return ptr->get();
- }
- else {
- return nullptr;
- }
- }
-};
-
-struct ParticleChunkIntegrationContext {
- MutableSpan<float3> position_diffs;
- MutableSpan<float3> velocity_diffs;
- MutableSpan<float> durations;
- float end_time;
-};
-
-struct ParticleChunkContext {
- ParticleSimulationState &state;
- IndexMask index_mask;
- MutableAttributesRef attributes;
- ParticleChunkIntegrationContext *integration = nullptr;
-
- void update_diffs_after_velocity_change()
- {
- if (integration == nullptr) {
- return;
- }
-
- Span<float> remaining_durations = integration->durations;
- MutableSpan<float3> position_diffs = integration->position_diffs;
- Span<float3> velocities = attributes.get<float3>("Velocity");
-
- for (int i : index_mask) {
- const float duration = remaining_durations[i];
- /* This is certainly not a perfect way to "re-integrate" the velocity, but it should be good
- * enough for most use cases. Changing the velocity in an instant is not physically correct
- * anyway. */
- position_diffs[i] = velocities[i] * duration;
- }
- }
-};
-
-struct ParticleEmitterContext {
- SimulationSolveContext &solve_context;
- ParticleAllocators &particle_allocators;
- TimeInterval emit_interval;
-
- template<typename StateType> StateType *lookup_state(StringRef name)
- {
- return solve_context.state_map.lookup<StateType>(name);
- }
-
- ParticleAllocator *try_get_particle_allocator(StringRef particle_simulation_name)
- {
- return particle_allocators.try_get_allocator(particle_simulation_name);
- }
-};
-
-struct ParticleForceContext {
- SimulationSolveContext &solve_context;
- ParticleChunkContext &particles;
- MutableSpan<float3> force_dst;
-};
-
-struct ParticleActionContext {
- SimulationSolveContext &solve_context;
- ParticleChunkContext &particles;
-};
-
-struct ParticleEventFilterContext {
- SimulationSolveContext &solve_context;
- ParticleChunkContext &particles;
- MutableSpan<float> factor_dst;
-};
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_update.cc b/source/blender/simulation/intern/simulation_update.cc
deleted file mode 100644
index 452b222bb08..00000000000
--- a/source/blender/simulation/intern/simulation_update.cc
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include "SIM_simulation_update.hh"
-
-#include "BKE_customdata.h"
-#include "BKE_lib_id.h"
-#include "BKE_object.h"
-#include "BKE_simulation.h"
-
-#include "DNA_modifier_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_simulation_types.h"
-
-#include "DEG_depsgraph_query.h"
-
-#include "BLI_array.hh"
-#include "BLI_float3.hh"
-#include "BLI_listbase.h"
-#include "BLI_map.hh"
-#include "BLI_rand.h"
-#include "BLI_set.hh"
-#include "BLI_vector.hh"
-
-#include "NOD_node_tree_dependencies.hh"
-
-#include "particle_function.hh"
-#include "simulation_collect_influences.hh"
-#include "simulation_solver.hh"
-
-namespace blender::sim {
-
-static void copy_states_to_cow(const Simulation *simulation_orig, Simulation *simulation_cow)
-{
- BKE_simulation_state_remove_all(simulation_cow);
- simulation_cow->current_frame = simulation_orig->current_frame;
-
- LISTBASE_FOREACH (const SimulationState *, state_orig, &simulation_orig->states) {
- SimulationState *state_cow = BKE_simulation_state_add(
- simulation_cow, state_orig->type, state_orig->name);
- BKE_simulation_state_copy_data(state_orig, state_cow);
- }
-}
-
-static void remove_unused_states(Simulation *simulation, const RequiredStates &required_states)
-{
- LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) {
- if (!required_states.is_required(state->name, state->type)) {
- BKE_simulation_state_remove(simulation, state);
- }
- }
-}
-
-static void add_missing_states(Simulation *simulation, const RequiredStates &required_states)
-{
- for (auto &&item : required_states.states().items()) {
- const char *name = item.key.c_str();
- const char *type = item.value;
-
- SimulationState *state = BKE_simulation_state_try_find_by_name_and_type(
- simulation, name, type);
-
- if (state == nullptr) {
- BKE_simulation_state_add(simulation, type, name);
- }
- }
-}
-
-static void reinitialize_empty_simulation_states(Simulation *simulation,
- const RequiredStates &required_states)
-{
- remove_unused_states(simulation, required_states);
- BKE_simulation_state_reset_all(simulation);
- add_missing_states(simulation, required_states);
-}
-
-static void update_simulation_state_list(Simulation *simulation,
- const RequiredStates &required_states)
-{
- remove_unused_states(simulation, required_states);
- add_missing_states(simulation, required_states);
-}
-
-class SampledDependencyAnimations : public DependencyAnimations {
- private:
- TimeInterval simulation_time_interval_;
- MultiValueMap<Object *, float4x4> object_transforms_cache_;
-
- public:
- SampledDependencyAnimations(TimeInterval simulation_time_interval)
- : simulation_time_interval_(simulation_time_interval)
- {
- }
-
- void add_object_transforms(Object &object, Span<float4x4> transforms)
- {
- object_transforms_cache_.add_multiple(&object, transforms);
- }
-
- bool is_object_transform_changing(Object &object) const
- {
- return object_transforms_cache_.lookup(&object).size() >= 2;
- }
-
- void get_object_transforms(Object &object,
- Span<float> simulation_times,
- MutableSpan<float4x4> r_transforms) const
- {
- assert_same_size(simulation_times, r_transforms);
- Span<float4x4> cached_transforms = object_transforms_cache_.lookup(&object);
- if (cached_transforms.size() == 0) {
- r_transforms.fill(object.obmat);
- return;
- }
- if (cached_transforms.size() == 1) {
- r_transforms.fill(cached_transforms[0]);
- return;
- }
-
- for (int i : simulation_times.index_range()) {
- const float simulation_time = simulation_times[i];
- if (simulation_time <= simulation_time_interval_.start()) {
- r_transforms[i] = cached_transforms.first();
- continue;
- }
- if (simulation_time >= simulation_time_interval_.stop()) {
- r_transforms[i] = cached_transforms.last();
- continue;
- }
- const float factor = simulation_time_interval_.factor_at_time(simulation_time);
- BLI_assert(factor > 0.0f && factor < 1.0f);
- const float scaled_factor = factor * (cached_transforms.size() - 1);
- const int lower_sample = static_cast<int>(scaled_factor);
- const int upper_sample = lower_sample + 1;
- const float mix_factor = scaled_factor - lower_sample;
- r_transforms[i] = float4x4::interpolate(
- cached_transforms[lower_sample], cached_transforms[upper_sample], mix_factor);
- }
- }
-};
-
-static void sample_object_transforms(Object &object,
- Depsgraph &depsgraph,
- Scene &scene,
- TimeInterval scene_frame_interval,
- MutableSpan<float4x4> r_transforms)
-{
- if (r_transforms.size() == 0) {
- return;
- }
- if (r_transforms.size() == 1) {
- r_transforms[0] = object.obmat;
- return;
- }
-
- Array<float> frames(r_transforms.size());
- scene_frame_interval.compute_uniform_samples(frames);
-
- for (int i : frames.index_range()) {
- float frame = frames[i];
- const int recursion_depth = 5;
- BKE_object_modifier_update_subframe(
- &depsgraph, &scene, &object, false, recursion_depth, frame, eModifierType_None);
- r_transforms[i] = object.obmat;
- }
-}
-
-template<typename T> static bool all_values_equal(Span<T> values)
-{
- if (values.size() == 0) {
- return true;
- }
- for (const T &value : values.drop_front(1)) {
- if (value != values[0]) {
- return false;
- }
- }
- return true;
-}
-
-static void prepare_dependency_animations(Depsgraph &depsgraph,
- Scene &scene,
- Simulation &simulation,
- TimeInterval scene_frame_interval,
- SampledDependencyAnimations &r_dependency_animations)
-{
- LISTBASE_FOREACH (SimulationDependency *, dependency, &simulation.dependencies) {
- ID *id_cow = DEG_get_evaluated_id(&depsgraph, dependency->id);
- if (id_cow == nullptr) {
- continue;
- }
- if (GS(id_cow->name) != ID_OB) {
- continue;
- }
- Object &object_cow = *reinterpret_cast<Object *>(id_cow);
- constexpr int sample_count = 10;
- Array<float4x4, sample_count> transforms(sample_count);
- sample_object_transforms(object_cow, depsgraph, scene, scene_frame_interval, transforms);
-
- /* If all samples are the same, only store one. */
- Span<float4x4> transforms_to_use = (all_values_equal(transforms.as_span())) ?
- transforms.as_span().take_front(1) :
- transforms.as_span();
-
- r_dependency_animations.add_object_transforms(object_cow, transforms_to_use);
- }
-}
-
-void update_simulation_in_depsgraph(Depsgraph *depsgraph,
- Scene *scene_cow,
- Simulation *simulation_cow)
-{
- int current_frame = scene_cow->r.cfra;
- if (simulation_cow->current_frame == current_frame) {
- return;
- }
-
- /* Below we modify the original state/cache. Only the active depsgraph is allowed to do that. */
- if (!DEG_is_active(depsgraph)) {
- return;
- }
-
- Simulation *simulation_orig = reinterpret_cast<Simulation *>(
- DEG_get_original_id(&simulation_cow->id));
-
- ResourceCollector resources;
- SimulationInfluences influences;
- RequiredStates required_states;
-
- collect_simulation_influences(*simulation_cow, resources, influences, required_states);
-
- bke::PersistentDataHandleMap handle_map;
- LISTBASE_FOREACH (SimulationDependency *, dependency, &simulation_orig->dependencies) {
- ID *id_cow = DEG_get_evaluated_id(depsgraph, dependency->id);
- if (id_cow != nullptr) {
- handle_map.add(dependency->handle, *id_cow);
- }
- }
-
- if (current_frame == 1) {
- reinitialize_empty_simulation_states(simulation_orig, required_states);
-
- initialize_simulation_states(*simulation_orig, *depsgraph, influences, handle_map);
- simulation_orig->current_frame = 1;
-
- copy_states_to_cow(simulation_orig, simulation_cow);
- }
- else if (current_frame == simulation_orig->current_frame + 1) {
- update_simulation_state_list(simulation_orig, required_states);
-
- const float fps = scene_cow->r.frs_sec / scene_cow->r.frs_sec_base;
- const float time_step = 1.0f / fps;
- TimeInterval scene_frame_interval(current_frame - 1, 1);
- TimeInterval simulation_time_interval(simulation_orig->current_simulation_time, time_step);
- SampledDependencyAnimations dependency_animations{simulation_time_interval};
- prepare_dependency_animations(
- *depsgraph, *scene_cow, *simulation_orig, scene_frame_interval, dependency_animations);
-
- solve_simulation_time_step(
- *simulation_orig, *depsgraph, influences, handle_map, dependency_animations, time_step);
- simulation_orig->current_frame = current_frame;
-
- copy_states_to_cow(simulation_orig, simulation_cow);
- }
-}
-
-/* Returns true when dependencies have changed. */
-bool update_simulation_dependencies(Simulation *simulation)
-{
- nodes::NodeTreeDependencies dependencies = nodes::find_node_tree_dependencies(
- *simulation->nodetree);
-
- ListBase *dependency_list = &simulation->dependencies;
-
- bool dependencies_changed = false;
-
- Map<ID *, SimulationDependency *> dependency_by_id;
- Map<SimulationDependency *, int> old_flag_by_dependency;
- Set<int> used_handles;
-
- /* Remove unused handle items and clear flags that are reinitialized later. */
- LISTBASE_FOREACH_MUTABLE (SimulationDependency *, dependency, dependency_list) {
- if (dependencies.depends_on(dependency->id)) {
- dependency_by_id.add_new(dependency->id, dependency);
- used_handles.add_new(dependency->handle);
- old_flag_by_dependency.add_new(dependency, dependency->flag);
- dependency->flag &= ~(SIM_DEPENDS_ON_TRANSFORM | SIM_DEPENDS_ON_GEOMETRY);
- }
- else {
- if (dependency->id != nullptr) {
- id_us_min(dependency->id);
- }
- BLI_remlink(dependency_list, dependency);
- MEM_freeN(dependency);
- dependencies_changed = true;
- }
- }
-
- /* Add handle items for new id dependencies. */
- int next_handle = 0;
- for (ID *id : dependencies.id_dependencies()) {
- dependency_by_id.lookup_or_add_cb(id, [&]() {
- while (used_handles.contains(next_handle)) {
- next_handle++;
- }
- used_handles.add_new(next_handle);
-
- SimulationDependency *dependency = static_cast<SimulationDependency *>(
- MEM_callocN(sizeof(*dependency), AT));
- id_us_plus(id);
- dependency->id = id;
- dependency->handle = next_handle;
- BLI_addtail(dependency_list, dependency);
-
- return dependency;
- });
- }
-
- /* Set appropriate dependency flags. */
- for (Object *object : dependencies.transform_dependencies()) {
- SimulationDependency *dependency = dependency_by_id.lookup(&object->id);
- dependency->flag |= SIM_DEPENDS_ON_TRANSFORM;
- }
- for (Object *object : dependencies.geometry_dependencies()) {
- SimulationDependency *dependency = dependency_by_id.lookup(&object->id);
- dependency->flag |= SIM_DEPENDS_ON_GEOMETRY;
- }
-
- if (!dependencies_changed) {
- /* Check if any flags have changed. */
- LISTBASE_FOREACH (SimulationDependency *, dependency, dependency_list) {
- uint32_t old_flag = old_flag_by_dependency.lookup_default(dependency, 0);
- uint32_t new_flag = dependency->flag;
- if (old_flag != new_flag) {
- dependencies_changed = true;
- break;
- }
- }
- }
-
- return dependencies_changed;
-}
-
-} // namespace blender::sim
diff --git a/source/blender/simulation/intern/time_interval.hh b/source/blender/simulation/intern/time_interval.hh
deleted file mode 100644
index 034628fa9be..00000000000
--- a/source/blender/simulation/intern/time_interval.hh
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#pragma once
-
-#include "BLI_utildefines.h"
-
-namespace blender::sim {
-
-/**
- * The start time is exclusive and the end time is inclusive. If the duration is zero, the interval
- * describes a single point in time.
- */
-class TimeInterval {
- private:
- float start_;
- float duration_;
-
- public:
- TimeInterval(float start, float duration) : start_(start), duration_(duration)
- {
- BLI_assert(duration_ >= 0.0f);
- }
-
- float start() const
- {
- return start_;
- }
-
- float stop() const
- {
- return start_ + duration_;
- }
-
- float duration() const
- {
- return duration_;
- }
-
- float time_at_factor(float factor) const
- {
- return start_ + factor * duration_;
- }
-
- float factor_at_time(float time) const
- {
- BLI_assert(duration_ > 0.0f);
- return (time - start_) / duration_;
- }
-
- float safe_factor_at_time(float time) const
- {
- if (duration_ > 0.0f) {
- return this->factor_at_time(time);
- }
- return 0.0f;
- }
-
- void compute_uniform_samples(MutableSpan<float> r_samples) const
- {
- int64_t amount = r_samples.size();
- if (amount == 0) {
- return;
- }
- if (amount == 1) {
- r_samples[0] = this->time_at_factor(0.5f);
- return;
- }
-
- const float step = duration_ / (float)(amount - 1);
- for (int64_t i : r_samples.index_range()) {
- r_samples[i] = start_ + i * step;
- }
- }
-};
-
-} // namespace blender::sim