diff options
Diffstat (limited to 'source/blender/simulation/intern/simulation_solver_influences.hh')
-rw-r--r-- | source/blender/simulation/intern/simulation_solver_influences.hh | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/source/blender/simulation/intern/simulation_solver_influences.hh b/source/blender/simulation/intern/simulation_solver_influences.hh new file mode 100644 index 00000000000..f7b8affd88d --- /dev/null +++ b/source/blender/simulation/intern/simulation_solver_influences.hh @@ -0,0 +1,237 @@ +/* + * 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. + */ + +#ifndef __SIM_SIMULATION_SOLVER_INFLUENCES_HH__ +#define __SIM_SIMULATION_SOLVER_INFLUENCES_HH__ + +#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 ParticleEmitterContext; +struct ParticleForceContext; +struct ParticleActionContext; +struct ParticleEventFilterContext; + +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 (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 + +#endif /* __SIM_SIMULATION_SOLVER_INFLUENCES_HH__ */ |