Graphics/ParticleSystem: Turn it to Renderable interface
Former-commit-id: c083f32a4bf2baed93126c30a6d05cf8ed0ba493
This commit is contained in:
parent
06b5e09935
commit
0ec0e02a5f
|
|
@ -8,20 +8,19 @@
|
||||||
#define NAZARA_PARTICLESYSTEM_HPP
|
#define NAZARA_PARTICLESYSTEM_HPP
|
||||||
|
|
||||||
#include <Nazara/Prerequesites.hpp>
|
#include <Nazara/Prerequesites.hpp>
|
||||||
#include <Nazara/Core/Updatable.hpp>
|
|
||||||
#include <Nazara/Graphics/ParticleController.hpp>
|
#include <Nazara/Graphics/ParticleController.hpp>
|
||||||
#include <Nazara/Graphics/ParticleDeclaration.hpp>
|
#include <Nazara/Graphics/ParticleDeclaration.hpp>
|
||||||
#include <Nazara/Graphics/ParticleEmitter.hpp>
|
#include <Nazara/Graphics/ParticleEmitter.hpp>
|
||||||
#include <Nazara/Graphics/ParticleGenerator.hpp>
|
#include <Nazara/Graphics/ParticleGenerator.hpp>
|
||||||
#include <Nazara/Graphics/ParticleRenderer.hpp>
|
#include <Nazara/Graphics/ParticleRenderer.hpp>
|
||||||
#include <Nazara/Graphics/SceneNode.hpp>
|
#include <Nazara/Graphics/Renderable.hpp>
|
||||||
#include <Nazara/Math/BoundingVolume.hpp>
|
#include <Nazara/Math/BoundingVolume.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class NAZARA_GRAPHICS_API NzParticleSystem : public NzSceneNode, NzUpdatable
|
class NAZARA_GRAPHICS_API NzParticleSystem : public NzRenderable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NzParticleSystem(unsigned int maxParticleCount, nzParticleLayout layout);
|
NzParticleSystem(unsigned int maxParticleCount, nzParticleLayout layout);
|
||||||
|
|
@ -32,9 +31,9 @@ class NAZARA_GRAPHICS_API NzParticleSystem : public NzSceneNode, NzUpdatable
|
||||||
void AddController(NzParticleController* controller);
|
void AddController(NzParticleController* controller);
|
||||||
void AddEmitter(NzParticleEmitter* emitter);
|
void AddEmitter(NzParticleEmitter* emitter);
|
||||||
void AddGenerator(NzParticleGenerator* generator);
|
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* CreateParticle();
|
||||||
void* CreateParticles(unsigned int count);
|
void* CreateParticles(unsigned int count);
|
||||||
|
|
@ -49,7 +48,6 @@ class NAZARA_GRAPHICS_API NzParticleSystem : public NzSceneNode, NzUpdatable
|
||||||
unsigned int GetMaxParticleCount() const;
|
unsigned int GetMaxParticleCount() const;
|
||||||
unsigned int GetParticleCount() const;
|
unsigned int GetParticleCount() const;
|
||||||
unsigned int GetParticleSize() const;
|
unsigned int GetParticleSize() const;
|
||||||
nzSceneNodeType GetSceneNodeType() const override;
|
|
||||||
|
|
||||||
bool IsDrawable() const;
|
bool IsDrawable() const;
|
||||||
bool IsFixedStepEnabled() const;
|
bool IsFixedStepEnabled() const;
|
||||||
|
|
@ -64,14 +62,14 @@ class NAZARA_GRAPHICS_API NzParticleSystem : public NzSceneNode, NzUpdatable
|
||||||
void SetFixedStepSize(float stepSize);
|
void SetFixedStepSize(float stepSize);
|
||||||
void SetRenderer(NzParticleRenderer* renderer);
|
void SetRenderer(NzParticleRenderer* renderer);
|
||||||
|
|
||||||
|
void Update(float elapsedTime);
|
||||||
|
void UpdateBoundingVolume(const NzMatrix4f& transformMatrix) override;
|
||||||
|
|
||||||
NzParticleSystem& operator=(const NzParticleSystem& emitter);
|
NzParticleSystem& operator=(const NzParticleSystem& emitter);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void MakeBoundingVolume() const override;
|
void MakeBoundingVolume() const override;
|
||||||
void Register() override;
|
|
||||||
void ResizeBuffer();
|
void ResizeBuffer();
|
||||||
void Unregister() override;
|
|
||||||
void Update() override;
|
|
||||||
|
|
||||||
std::set<unsigned int, std::greater<unsigned int>> m_dyingParticles;
|
std::set<unsigned int, std::greater<unsigned int>> m_dyingParticles;
|
||||||
mutable std::vector<nzUInt8> m_buffer;
|
mutable std::vector<nzUInt8> m_buffer;
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,9 @@ void NzParticleEmitter::Emit(NzParticleSystem& system, float elapsedTime) const
|
||||||
if (m_lagCompensationEnabled)
|
if (m_lagCompensationEnabled)
|
||||||
{
|
{
|
||||||
// On va maintenant appliquer les contrôleurs
|
// On va maintenant appliquer les contrôleurs
|
||||||
float accumulator = 0.f;
|
|
||||||
float invEmissionRate = 1.f/m_emissionRate;
|
float invEmissionRate = 1.f/m_emissionRate;
|
||||||
for (unsigned int i = 1; i <= emissionCountInt; ++i)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#include <Nazara/Core/ErrorFlags.hpp>
|
#include <Nazara/Core/ErrorFlags.hpp>
|
||||||
#include <Nazara/Core/StringStream.hpp>
|
#include <Nazara/Core/StringStream.hpp>
|
||||||
#include <Nazara/Graphics/ParticleMapper.hpp>
|
#include <Nazara/Graphics/ParticleMapper.hpp>
|
||||||
#include <Nazara/Graphics/Scene.hpp>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <Nazara/Graphics/Debug.hpp>
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
@ -19,10 +18,7 @@ NzParticleSystem(maxParticleCount, NzParticleDeclaration::Get(layout))
|
||||||
|
|
||||||
NzParticleSystem::NzParticleSystem(unsigned int maxParticleCount, const NzParticleDeclaration* declaration) :
|
NzParticleSystem::NzParticleSystem(unsigned int maxParticleCount, const NzParticleDeclaration* declaration) :
|
||||||
m_declaration(declaration),
|
m_declaration(declaration),
|
||||||
m_fixedStepEnabled(false),
|
|
||||||
m_processing(false),
|
m_processing(false),
|
||||||
m_stepAccumulator(0.f),
|
|
||||||
m_stepSize(1.f/60.f),
|
|
||||||
m_maxParticleCount(maxParticleCount),
|
m_maxParticleCount(maxParticleCount),
|
||||||
m_particleCount(0)
|
m_particleCount(0)
|
||||||
{
|
{
|
||||||
|
|
@ -35,15 +31,12 @@ m_particleCount(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
NzParticleSystem::NzParticleSystem(const NzParticleSystem& system) :
|
NzParticleSystem::NzParticleSystem(const NzParticleSystem& system) :
|
||||||
NzSceneNode(system),
|
NzRenderable(system),
|
||||||
m_controllers(system.m_controllers),
|
m_controllers(system.m_controllers),
|
||||||
m_generators(system.m_generators),
|
m_generators(system.m_generators),
|
||||||
m_declaration(system.m_declaration),
|
m_declaration(system.m_declaration),
|
||||||
m_renderer(system.m_renderer),
|
m_renderer(system.m_renderer),
|
||||||
m_fixedStepEnabled(system.m_fixedStepEnabled),
|
|
||||||
m_processing(false),
|
m_processing(false),
|
||||||
m_stepAccumulator(0.f),
|
|
||||||
m_stepSize(system.m_stepSize),
|
|
||||||
m_maxParticleCount(system.m_maxParticleCount),
|
m_maxParticleCount(system.m_maxParticleCount),
|
||||||
m_particleCount(system.m_particleCount),
|
m_particleCount(system.m_particleCount),
|
||||||
m_particleSize(system.m_particleSize)
|
m_particleSize(system.m_particleSize)
|
||||||
|
|
@ -60,22 +53,31 @@ NzParticleSystem::~NzParticleSystem() = default;
|
||||||
|
|
||||||
void NzParticleSystem::AddController(NzParticleController* controller)
|
void NzParticleSystem::AddController(NzParticleController* controller)
|
||||||
{
|
{
|
||||||
|
NazaraAssert(controller, "Invalid particle controller");
|
||||||
|
|
||||||
m_controllers.emplace_back(controller);
|
m_controllers.emplace_back(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NzParticleSystem::AddEmitter(NzParticleEmitter* emitter)
|
void NzParticleSystem::AddEmitter(NzParticleEmitter* emitter)
|
||||||
{
|
{
|
||||||
|
NazaraAssert(controller, "Invalid particle emitter");
|
||||||
|
|
||||||
m_emitters.emplace_back(emitter);
|
m_emitters.emplace_back(emitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NzParticleSystem::AddGenerator(NzParticleGenerator* generator)
|
void NzParticleSystem::AddGenerator(NzParticleGenerator* generator)
|
||||||
{
|
{
|
||||||
|
NazaraAssert(controller, "Invalid particle generator");
|
||||||
|
|
||||||
m_generators.emplace_back(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)
|
if (m_particleCount > 0)
|
||||||
{
|
{
|
||||||
NzParticleMapper mapper(m_buffer.data(), m_declaration);
|
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()
|
void* NzParticleSystem::CreateParticle()
|
||||||
{
|
{
|
||||||
return CreateParticles(1);
|
return CreateParticles(1);
|
||||||
|
|
@ -93,7 +125,7 @@ void* NzParticleSystem::CreateParticles(unsigned int count)
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (m_particleCount+count > m_maxParticleCount)
|
if (m_particleCount + count > m_maxParticleCount)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
unsigned int particlesIndex = m_particleCount;
|
unsigned int particlesIndex = m_particleCount;
|
||||||
|
|
@ -102,16 +134,6 @@ void* NzParticleSystem::CreateParticles(unsigned int count)
|
||||||
return &m_buffer[particlesIndex*m_particleSize];
|
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()
|
void* NzParticleSystem::GenerateParticle()
|
||||||
{
|
{
|
||||||
return GenerateParticles(1);
|
return GenerateParticles(1);
|
||||||
|
|
@ -155,21 +177,11 @@ unsigned int NzParticleSystem::GetParticleSize() const
|
||||||
return m_particleSize;
|
return m_particleSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
nzSceneNodeType NzParticleSystem::GetSceneNodeType() const
|
|
||||||
{
|
|
||||||
return nzSceneNodeType_ParticleEmitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NzParticleSystem::IsDrawable() const
|
bool NzParticleSystem::IsDrawable() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NzParticleSystem::IsFixedStepEnabled() const
|
|
||||||
{
|
|
||||||
return m_fixedStepEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleSystem::KillParticle(unsigned int index)
|
void NzParticleSystem::KillParticle(unsigned int index)
|
||||||
{
|
{
|
||||||
///FIXME: Vérifier index
|
///FIXME: Vérifier index
|
||||||
|
|
@ -222,15 +234,36 @@ void NzParticleSystem::SetRenderer(NzParticleRenderer* renderer)
|
||||||
m_renderer = 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)
|
NzParticleSystem& NzParticleSystem::operator=(const NzParticleSystem& system)
|
||||||
{
|
{
|
||||||
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
|
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
|
||||||
|
|
||||||
NzSceneNode::operator=(system);
|
NzRenderable::operator=(system);
|
||||||
|
|
||||||
m_controllers = system.m_controllers;
|
m_controllers = system.m_controllers;
|
||||||
m_declaration = system.m_declaration;
|
m_declaration = system.m_declaration;
|
||||||
m_fixedStepEnabled = system.m_fixedStepEnabled;
|
|
||||||
m_generators = system.m_generators;
|
m_generators = system.m_generators;
|
||||||
m_maxParticleCount = system.m_maxParticleCount;
|
m_maxParticleCount = system.m_maxParticleCount;
|
||||||
m_particleCount = system.m_particleCount;
|
m_particleCount = system.m_particleCount;
|
||||||
|
|
@ -252,61 +285,12 @@ NzParticleSystem& NzParticleSystem::operator=(const NzParticleSystem& system)
|
||||||
return *this;
|
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
|
void NzParticleSystem::MakeBoundingVolume() const
|
||||||
{
|
{
|
||||||
///TODO: Calculer l'AABB (prendre la taille des particules en compte s'il y a)
|
///TODO: Calculer l'AABB (prendre la taille des particules en compte s'il y a)
|
||||||
m_boundingVolume.MakeInfinite();
|
m_boundingVolume.MakeInfinite();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NzParticleSystem::Register()
|
|
||||||
{
|
|
||||||
m_scene->RegisterForUpdate(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleSystem::ResizeBuffer()
|
void NzParticleSystem::ResizeBuffer()
|
||||||
{
|
{
|
||||||
// Histoire de décrire un peu mieux l'erreur en cas d'échec
|
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue