diff --git a/include/Nazara/Graphics/ParticleSystem.hpp b/include/Nazara/Graphics/ParticleSystem.hpp index 36f5969c6..f343db8ad 100644 --- a/include/Nazara/Graphics/ParticleSystem.hpp +++ b/include/Nazara/Graphics/ParticleSystem.hpp @@ -8,20 +8,19 @@ #define NAZARA_PARTICLESYSTEM_HPP #include -#include #include #include #include #include #include -#include +#include #include #include #include #include #include -class NAZARA_GRAPHICS_API NzParticleSystem : public NzSceneNode, NzUpdatable +class NAZARA_GRAPHICS_API NzParticleSystem : public NzRenderable { public: NzParticleSystem(unsigned int maxParticleCount, nzParticleLayout layout); @@ -32,9 +31,9 @@ class NAZARA_GRAPHICS_API NzParticleSystem : public NzSceneNode, NzUpdatable void AddController(NzParticleController* controller); void AddEmitter(NzParticleEmitter* emitter); void AddGenerator(NzParticleGenerator* generator); - void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const; + void AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const; - void ApplyControllers(NzParticleMapper& mapper, unsigned int particleCount, float elapsedTime, float& stepAccumulator); + void ApplyControllers(NzParticleMapper& mapper, unsigned int particleCount, float elapsedTime); void* CreateParticle(); void* CreateParticles(unsigned int count); @@ -49,7 +48,6 @@ class NAZARA_GRAPHICS_API NzParticleSystem : public NzSceneNode, NzUpdatable unsigned int GetMaxParticleCount() const; unsigned int GetParticleCount() const; unsigned int GetParticleSize() const; - nzSceneNodeType GetSceneNodeType() const override; bool IsDrawable() const; bool IsFixedStepEnabled() const; @@ -64,14 +62,14 @@ class NAZARA_GRAPHICS_API NzParticleSystem : public NzSceneNode, NzUpdatable void SetFixedStepSize(float stepSize); void SetRenderer(NzParticleRenderer* renderer); + void Update(float elapsedTime); + void UpdateBoundingVolume(const NzMatrix4f& transformMatrix) override; + NzParticleSystem& operator=(const NzParticleSystem& emitter); private: void MakeBoundingVolume() const override; - void Register() override; void ResizeBuffer(); - void Unregister() override; - void Update() override; std::set> m_dyingParticles; mutable std::vector m_buffer; diff --git a/src/Nazara/Graphics/ParticleEmitter.cpp b/src/Nazara/Graphics/ParticleEmitter.cpp index c38233630..6dae5c6fd 100644 --- a/src/Nazara/Graphics/ParticleEmitter.cpp +++ b/src/Nazara/Graphics/ParticleEmitter.cpp @@ -52,10 +52,9 @@ void NzParticleEmitter::Emit(NzParticleSystem& system, float elapsedTime) const if (m_lagCompensationEnabled) { // On va maintenant appliquer les contrôleurs - float accumulator = 0.f; float invEmissionRate = 1.f/m_emissionRate; for (unsigned int i = 1; i <= emissionCountInt; ++i) - system.ApplyControllers(mapper, std::min(m_emissionCount*i, particleCount), 20*invEmissionRate, accumulator); + system.ApplyControllers(mapper, std::min(m_emissionCount*i, particleCount), invEmissionRate); } } } diff --git a/src/Nazara/Graphics/ParticleSystem.cpp b/src/Nazara/Graphics/ParticleSystem.cpp index 3a7351b2c..92d42d18c 100644 --- a/src/Nazara/Graphics/ParticleSystem.cpp +++ b/src/Nazara/Graphics/ParticleSystem.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -19,10 +18,7 @@ NzParticleSystem(maxParticleCount, NzParticleDeclaration::Get(layout)) NzParticleSystem::NzParticleSystem(unsigned int maxParticleCount, const NzParticleDeclaration* declaration) : m_declaration(declaration), -m_fixedStepEnabled(false), m_processing(false), -m_stepAccumulator(0.f), -m_stepSize(1.f/60.f), m_maxParticleCount(maxParticleCount), m_particleCount(0) { @@ -35,15 +31,12 @@ m_particleCount(0) } NzParticleSystem::NzParticleSystem(const NzParticleSystem& system) : -NzSceneNode(system), +NzRenderable(system), m_controllers(system.m_controllers), m_generators(system.m_generators), m_declaration(system.m_declaration), m_renderer(system.m_renderer), -m_fixedStepEnabled(system.m_fixedStepEnabled), m_processing(false), -m_stepAccumulator(0.f), -m_stepSize(system.m_stepSize), m_maxParticleCount(system.m_maxParticleCount), m_particleCount(system.m_particleCount), m_particleSize(system.m_particleSize) @@ -60,22 +53,31 @@ NzParticleSystem::~NzParticleSystem() = default; void NzParticleSystem::AddController(NzParticleController* controller) { + NazaraAssert(controller, "Invalid particle controller"); + m_controllers.emplace_back(controller); } void NzParticleSystem::AddEmitter(NzParticleEmitter* emitter) { + NazaraAssert(controller, "Invalid particle emitter"); + m_emitters.emplace_back(emitter); } void NzParticleSystem::AddGenerator(NzParticleGenerator* generator) { + NazaraAssert(controller, "Invalid particle generator"); + m_generators.emplace_back(generator); } -void NzParticleSystem::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const +void NzParticleSystem::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const NzMatrix4f& transformMatrix) const { - ///FIXME: Vérifier le renderer + NazaraAssert(m_renderer, "Invalid particle renderer"); + NazaraAssert(renderQueue, "Invalid renderqueue"); + NazaraUnused(transformMatrix); + if (m_particleCount > 0) { NzParticleMapper mapper(m_buffer.data(), m_declaration); @@ -83,6 +85,36 @@ void NzParticleSystem::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) cons } } +void NzParticleSystem::ApplyControllers(NzParticleMapper& mapper, unsigned int particleCount, float elapsedTime) +{ + m_processing = true; + + // Pour éviter un verrouillage en cas d'exception + NzCallOnExit onExit([this]() + { + m_processing = false; + }); + + for (NzParticleController* controller : m_controllers) + controller->Apply(*this, mapper, 0, particleCount-1, elapsedTime); + + onExit.CallAndReset(); + + // On tue maintenant les particules mortes durant la mise à jour + if (m_dyingParticles.size() < m_particleCount) + { + // On tue les particules depuis la dernière vers la première (en terme de place), le std::set étant trié via std::greater + // La raison est simple, étant donné que la mort d'une particule signifie le déplacement de la dernière particule du buffer, + // sans cette solution certaines particules pourraient échapper à la mort + for (unsigned int index : m_dyingParticles) + KillParticle(index); + } + else + KillParticles(); // Toutes les particules sont mortes, ceci est beaucoup plus rapide + + m_dyingParticles.clear(); +} + void* NzParticleSystem::CreateParticle() { return CreateParticles(1); @@ -93,7 +125,7 @@ void* NzParticleSystem::CreateParticles(unsigned int count) if (count == 0) return nullptr; - if (m_particleCount+count > m_maxParticleCount) + if (m_particleCount + count > m_maxParticleCount) return nullptr; unsigned int particlesIndex = m_particleCount; @@ -102,16 +134,6 @@ void* NzParticleSystem::CreateParticles(unsigned int count) return &m_buffer[particlesIndex*m_particleSize]; } -void NzParticleSystem::EnableFixedStep(bool fixedStep) -{ - // On teste pour empêcher que cette méthode ne remette systématiquement le step accumulator à zéro - if (m_fixedStepEnabled != fixedStep) - { - m_fixedStepEnabled = fixedStep; - m_stepAccumulator = 0.f; - } -} - void* NzParticleSystem::GenerateParticle() { return GenerateParticles(1); @@ -155,21 +177,11 @@ unsigned int NzParticleSystem::GetParticleSize() const return m_particleSize; } -nzSceneNodeType NzParticleSystem::GetSceneNodeType() const -{ - return nzSceneNodeType_ParticleEmitter; -} - bool NzParticleSystem::IsDrawable() const { return true; } -bool NzParticleSystem::IsFixedStepEnabled() const -{ - return m_fixedStepEnabled; -} - void NzParticleSystem::KillParticle(unsigned int index) { ///FIXME: Vérifier index @@ -222,15 +234,36 @@ void NzParticleSystem::SetRenderer(NzParticleRenderer* renderer) m_renderer = renderer; } +void NzParticleSystem::Update(float elapsedTime) +{ + // Émission + for (NzParticleEmitter* emitter : m_emitters) + emitter->Emit(*this, elapsedTime); + + // Mise à jour + if (m_particleCount > 0) + { + ///TODO: Mettre à jour en utilisant des threads + NzParticleMapper mapper(m_buffer.data(), m_declaration); + ApplyControllers(mapper, m_particleCount, elapsedTime); + } +} + +void NzParticleSystem::UpdateBoundingVolume(const NzMatrix4f& transformMatrix) +{ + NazaraUnused(transformMatrix); + + // Nothing to do here (our bounding volume is global) +} + NzParticleSystem& NzParticleSystem::operator=(const NzParticleSystem& system) { NzErrorFlags flags(nzErrorFlag_ThrowException, true); - NzSceneNode::operator=(system); + NzRenderable::operator=(system); m_controllers = system.m_controllers; m_declaration = system.m_declaration; - m_fixedStepEnabled = system.m_fixedStepEnabled; m_generators = system.m_generators; m_maxParticleCount = system.m_maxParticleCount; m_particleCount = system.m_particleCount; @@ -252,61 +285,12 @@ NzParticleSystem& NzParticleSystem::operator=(const NzParticleSystem& system) return *this; } -void NzParticleSystem::ApplyControllers(NzParticleMapper& mapper, unsigned int particleCount, float elapsedTime, float& stepAccumulator) -{ - m_processing = true; - - // Pour éviter un verrouillage en cas d'exception - NzCallOnExit onExit([this]() - { - m_processing = false; - }); - - if (m_fixedStepEnabled) - { - stepAccumulator += elapsedTime; - while (stepAccumulator >= m_stepSize) - { - for (NzParticleController* controller : m_controllers) - controller->Apply(*this, mapper, 0, particleCount-1, m_stepSize); - - stepAccumulator -= m_stepSize; - } - } - else - { - for (NzParticleController* controller : m_controllers) - controller->Apply(*this, mapper, 0, particleCount-1, elapsedTime); - } - - onExit.CallAndReset(); - - // On tue maintenant les particules mortes durant la mise à jour - if (m_dyingParticles.size() < m_particleCount) - { - // On tue les particules depuis la dernière vers la première (en terme de place), le std::set étant trié via std::greater - // La raison est simple, étant donné que la mort d'une particule signifie le déplacement de la dernière particule du buffer, - // sans cette solution certaines particules pourraient échapper à la mort - for (unsigned int index : m_dyingParticles) - KillParticle(index); - } - else - KillParticles(); // Toutes les particules sont mortes, ceci est beaucoup plus rapide - - m_dyingParticles.clear(); -} - void NzParticleSystem::MakeBoundingVolume() const { ///TODO: Calculer l'AABB (prendre la taille des particules en compte s'il y a) m_boundingVolume.MakeInfinite(); } -void NzParticleSystem::Register() -{ - m_scene->RegisterForUpdate(this); -} - void NzParticleSystem::ResizeBuffer() { // Histoire de décrire un peu mieux l'erreur en cas d'échec @@ -323,24 +307,3 @@ void NzParticleSystem::ResizeBuffer() } } -void NzParticleSystem::Unregister() -{ - m_scene->UnregisterForUpdate(this); -} - -void NzParticleSystem::Update() -{ - float elapsedTime = m_scene->GetUpdateTime(); - - // Émission - for (NzParticleEmitter* emitter : m_emitters) - emitter->Emit(*this, elapsedTime); - - // Mise à jour - if (m_particleCount > 0) - { - ///TODO: Mettre à jour en utilisant des threads - NzParticleMapper mapper(m_buffer.data(), m_declaration); - ApplyControllers(mapper, m_particleCount, elapsedTime, m_stepAccumulator); - } -}