Separated ParticleEmitter
Renamed ParticleEmitter to ParticleSystem Added class ParticleEmitter (First implementation, this will probably change) Former-commit-id: a1f80db340983da5e85cedc974dd6b24a98e25b0
This commit is contained in:
parent
54382afc37
commit
ea43edbaf3
|
|
@ -12,8 +12,8 @@
|
||||||
#include <Nazara/Core/ResourceRef.hpp>
|
#include <Nazara/Core/ResourceRef.hpp>
|
||||||
|
|
||||||
class NzParticleController;
|
class NzParticleController;
|
||||||
class NzParticleEmitter;
|
|
||||||
class NzParticleMapper;
|
class NzParticleMapper;
|
||||||
|
class NzParticleSystem;
|
||||||
|
|
||||||
using NzParticleControllerConstRef = NzResourceRef<const NzParticleController>;
|
using NzParticleControllerConstRef = NzResourceRef<const NzParticleController>;
|
||||||
using NzParticleControllerRef = NzResourceRef<NzParticleController>;
|
using NzParticleControllerRef = NzResourceRef<NzParticleController>;
|
||||||
|
|
@ -25,7 +25,7 @@ class NAZARA_API NzParticleController : public NzResource
|
||||||
NzParticleController(const NzParticleController& controller);
|
NzParticleController(const NzParticleController& controller);
|
||||||
virtual ~NzParticleController();
|
virtual ~NzParticleController();
|
||||||
|
|
||||||
virtual void Apply(NzParticleEmitter& emitter, NzParticleMapper& mapper, unsigned int startId, unsigned int endId, float elapsedTime) = 0;
|
virtual void Apply(NzParticleSystem& system, NzParticleMapper& mapper, unsigned int startId, unsigned int endId, float elapsedTime) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NAZARA_PARTICLECONTROLLER_HPP
|
#endif // NAZARA_PARTICLECONTROLLER_HPP
|
||||||
|
|
|
||||||
|
|
@ -8,92 +8,36 @@
|
||||||
#define NAZARA_PARTICLEEMITTER_HPP
|
#define NAZARA_PARTICLEEMITTER_HPP
|
||||||
|
|
||||||
#include <Nazara/Prerequesites.hpp>
|
#include <Nazara/Prerequesites.hpp>
|
||||||
#include <Nazara/Core/Updatable.hpp>
|
#include <Nazara/Utility/Node.hpp>
|
||||||
#include <Nazara/Graphics/ParticleController.hpp>
|
|
||||||
#include <Nazara/Graphics/ParticleDeclaration.hpp>
|
|
||||||
#include <Nazara/Graphics/ParticleGenerator.hpp>
|
|
||||||
#include <Nazara/Graphics/ParticleRenderer.hpp>
|
|
||||||
#include <Nazara/Graphics/SceneNode.hpp>
|
|
||||||
#include <Nazara/Math/BoundingVolume.hpp>
|
|
||||||
#include <memory>
|
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class NAZARA_API NzParticleEmitter : public NzSceneNode, NzUpdatable
|
class NzParticleMapper;
|
||||||
|
class NzParticleSystem;
|
||||||
|
|
||||||
|
class NAZARA_API NzParticleEmitter : public NzNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NzParticleEmitter(unsigned int maxParticleCount, nzParticleLayout layout);
|
NzParticleEmitter();
|
||||||
NzParticleEmitter(unsigned int maxParticleCount, NzParticleDeclaration* declaration);
|
NzParticleEmitter(const NzParticleEmitter& emitter) = default;
|
||||||
NzParticleEmitter(const NzParticleEmitter& emitter);
|
|
||||||
NzParticleEmitter(NzParticleEmitter&& emitter) = default;
|
NzParticleEmitter(NzParticleEmitter&& emitter) = default;
|
||||||
~NzParticleEmitter();
|
virtual ~NzParticleEmitter();
|
||||||
|
|
||||||
void AddController(NzParticleController* controller);
|
virtual void Emit(NzParticleSystem& system, float elapsedTime) const;
|
||||||
void AddGenerator(NzParticleGenerator* generator);
|
|
||||||
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const;
|
|
||||||
|
|
||||||
void* CreateParticle();
|
|
||||||
void* CreateParticles(unsigned int count);
|
|
||||||
|
|
||||||
void EnableFixedStep(bool fixedStep);
|
|
||||||
|
|
||||||
void* GenerateParticle();
|
|
||||||
void* GenerateParticles(unsigned int count);
|
|
||||||
|
|
||||||
const NzBoundingVolumef& GetBoundingVolume() const override;
|
|
||||||
|
|
||||||
unsigned int GetEmissionCount() const;
|
unsigned int GetEmissionCount() const;
|
||||||
float GetEmissionRate() const;
|
float GetEmissionRate() const;
|
||||||
float GetFixedStepSize() const;
|
|
||||||
unsigned int GetMaxParticleCount() const;
|
|
||||||
unsigned int GetParticleCount() const;
|
|
||||||
unsigned int GetParticleSize() const;
|
|
||||||
|
|
||||||
nzSceneNodeType GetSceneNodeType() const override;
|
|
||||||
|
|
||||||
bool IsDrawable() const;
|
|
||||||
bool IsFixedStepEnabled() const;
|
|
||||||
|
|
||||||
void KillParticle(unsigned int index);
|
|
||||||
void KillParticles();
|
|
||||||
|
|
||||||
void RemoveController(NzParticleController* controller);
|
|
||||||
void RemoveGenerator(NzParticleGenerator* generator);
|
|
||||||
|
|
||||||
void SetEmissionCount(unsigned int count);
|
void SetEmissionCount(unsigned int count);
|
||||||
void SetEmissionRate(float rate);
|
void SetEmissionRate(float rate);
|
||||||
void SetFixedStepSize(float stepSize);
|
|
||||||
void SetRenderer(NzParticleRenderer* renderer);
|
|
||||||
|
|
||||||
NzParticleEmitter& operator=(const NzParticleEmitter& emitter);
|
NzParticleEmitter& operator=(const NzParticleEmitter& emitter) = default;
|
||||||
NzParticleEmitter& operator=(NzParticleEmitter&& emitter) = default;
|
NzParticleEmitter& operator=(NzParticleEmitter&& emitter) = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GenerateAABB() const;
|
virtual void SetupParticles(NzParticleMapper& mapper, unsigned int count) const = 0;
|
||||||
void Register() override;
|
|
||||||
void ResizeBuffer();
|
|
||||||
void Unregister() override;
|
|
||||||
void UpdateBoundingVolume() const;
|
|
||||||
void Update() override;
|
|
||||||
|
|
||||||
std::set<unsigned int, std::greater<unsigned int>> m_dyingParticles;
|
mutable float m_emissionAccumulator;
|
||||||
mutable std::vector<nzUInt8> m_buffer;
|
|
||||||
std::vector<NzParticleControllerRef> m_controllers;
|
|
||||||
std::vector<NzParticleGeneratorRef> m_generators;
|
|
||||||
mutable NzBoundingVolumef m_boundingVolume;
|
|
||||||
NzParticleDeclarationConstRef m_declaration;
|
|
||||||
NzParticleRendererRef m_renderer;
|
|
||||||
mutable bool m_boundingVolumeUpdated;
|
|
||||||
bool m_fixedStepEnabled;
|
|
||||||
bool m_processing;
|
|
||||||
float m_emissionAccumulator;
|
|
||||||
float m_emissionRate;
|
float m_emissionRate;
|
||||||
float m_stepAccumulator;
|
|
||||||
float m_stepSize;
|
|
||||||
unsigned int m_emissionCount;
|
unsigned int m_emissionCount;
|
||||||
unsigned int m_maxParticleCount;
|
|
||||||
unsigned int m_particleCount;
|
|
||||||
unsigned int m_particleSize;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NAZARA_PARTICLEEMITTER_HPP
|
#endif // NAZARA_PARTICLEEMITTER_HPP
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@
|
||||||
#include <Nazara/Core/Resource.hpp>
|
#include <Nazara/Core/Resource.hpp>
|
||||||
#include <Nazara/Core/ResourceRef.hpp>
|
#include <Nazara/Core/ResourceRef.hpp>
|
||||||
|
|
||||||
class NzParticleEmitter;
|
|
||||||
class NzParticleGenerator;
|
class NzParticleGenerator;
|
||||||
class NzParticleMapper;
|
class NzParticleMapper;
|
||||||
|
class NzParticleSystem;
|
||||||
|
|
||||||
using NzParticleGeneratorConstRef = NzResourceRef<const NzParticleGenerator>;
|
using NzParticleGeneratorConstRef = NzResourceRef<const NzParticleGenerator>;
|
||||||
using NzParticleGeneratorRef = NzResourceRef<NzParticleGenerator>;
|
using NzParticleGeneratorRef = NzResourceRef<NzParticleGenerator>;
|
||||||
|
|
@ -25,7 +25,7 @@ class NAZARA_API NzParticleGenerator : public NzResource
|
||||||
NzParticleGenerator(const NzParticleGenerator& generator);
|
NzParticleGenerator(const NzParticleGenerator& generator);
|
||||||
virtual ~NzParticleGenerator();
|
virtual ~NzParticleGenerator();
|
||||||
|
|
||||||
virtual void Generate(NzParticleEmitter& emitter, NzParticleMapper& mapper, unsigned int startId, unsigned int endId) = 0;
|
virtual void Generate(NzParticleSystem& system, NzParticleMapper& mapper, unsigned int startId, unsigned int endId) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NAZARA_PARTICLEGENERATOR_HPP
|
#endif // NAZARA_PARTICLEGENERATOR_HPP
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@
|
||||||
#include <Nazara/Core/ResourceRef.hpp>
|
#include <Nazara/Core/ResourceRef.hpp>
|
||||||
|
|
||||||
class NzAbstractRenderQueue;
|
class NzAbstractRenderQueue;
|
||||||
class NzParticleEmitter;
|
|
||||||
class NzParticleMapper;
|
class NzParticleMapper;
|
||||||
class NzParticleRenderer;
|
class NzParticleRenderer;
|
||||||
|
class NzParticleSystem;
|
||||||
|
|
||||||
using NzParticleRendererConstRef = NzResourceRef<const NzParticleRenderer>;
|
using NzParticleRendererConstRef = NzResourceRef<const NzParticleRenderer>;
|
||||||
using NzParticleRendererRef = NzResourceRef<NzParticleRenderer>;
|
using NzParticleRendererRef = NzResourceRef<NzParticleRenderer>;
|
||||||
|
|
@ -26,7 +26,7 @@ class NAZARA_API NzParticleRenderer : public NzResource
|
||||||
NzParticleRenderer(const NzParticleRenderer& renderer);
|
NzParticleRenderer(const NzParticleRenderer& renderer);
|
||||||
virtual ~NzParticleRenderer();
|
virtual ~NzParticleRenderer();
|
||||||
|
|
||||||
virtual void Render(const NzParticleEmitter& emitter, const NzParticleMapper& mapper, unsigned int startId, unsigned int endId, NzAbstractRenderQueue* renderQueue) = 0;
|
virtual void Render(const NzParticleSystem& system, const NzParticleMapper& mapper, unsigned int startId, unsigned int endId, NzAbstractRenderQueue* renderQueue) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NAZARA_PARTICLERENDERER_HPP
|
#endif // NAZARA_PARTICLERENDERER_HPP
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
// Copyright (C) 2014 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_PARTICLESYSTEM_HPP
|
||||||
|
#define NAZARA_PARTICLESYSTEM_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Core/Updatable.hpp>
|
||||||
|
#include <Nazara/Graphics/ParticleController.hpp>
|
||||||
|
#include <Nazara/Graphics/ParticleDeclaration.hpp>
|
||||||
|
#include <Nazara/Graphics/ParticleEmitter.hpp>
|
||||||
|
#include <Nazara/Graphics/ParticleGenerator.hpp>
|
||||||
|
#include <Nazara/Graphics/ParticleRenderer.hpp>
|
||||||
|
#include <Nazara/Graphics/SceneNode.hpp>
|
||||||
|
#include <Nazara/Math/BoundingVolume.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class NAZARA_API NzParticleSystem : public NzSceneNode, NzUpdatable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NzParticleSystem(unsigned int maxParticleCount, nzParticleLayout layout);
|
||||||
|
NzParticleSystem(unsigned int maxParticleCount, const NzParticleDeclaration* declaration);
|
||||||
|
NzParticleSystem(const NzParticleSystem& emitter);
|
||||||
|
NzParticleSystem(NzParticleSystem&& emitter) = default;
|
||||||
|
~NzParticleSystem();
|
||||||
|
|
||||||
|
void AddController(NzParticleController* controller);
|
||||||
|
void AddEmitter(NzParticleEmitter* emitter);
|
||||||
|
void AddGenerator(NzParticleGenerator* generator);
|
||||||
|
void AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const;
|
||||||
|
|
||||||
|
void* CreateParticle();
|
||||||
|
void* CreateParticles(unsigned int count);
|
||||||
|
|
||||||
|
void EnableFixedStep(bool fixedStep);
|
||||||
|
|
||||||
|
void* GenerateParticle();
|
||||||
|
void* GenerateParticles(unsigned int count);
|
||||||
|
|
||||||
|
const NzBoundingVolumef& GetBoundingVolume() const override;
|
||||||
|
const NzParticleDeclaration* GetDeclaration() const;
|
||||||
|
float GetFixedStepSize() const;
|
||||||
|
unsigned int GetMaxParticleCount() const;
|
||||||
|
unsigned int GetParticleCount() const;
|
||||||
|
unsigned int GetParticleSize() const;
|
||||||
|
nzSceneNodeType GetSceneNodeType() const override;
|
||||||
|
|
||||||
|
bool IsDrawable() const;
|
||||||
|
bool IsFixedStepEnabled() const;
|
||||||
|
|
||||||
|
void KillParticle(unsigned int index);
|
||||||
|
void KillParticles();
|
||||||
|
|
||||||
|
void RemoveController(NzParticleController* controller);
|
||||||
|
void RemoveEmitter(NzParticleEmitter* emitter);
|
||||||
|
void RemoveGenerator(NzParticleGenerator* generator);
|
||||||
|
|
||||||
|
void SetFixedStepSize(float stepSize);
|
||||||
|
void SetRenderer(NzParticleRenderer* renderer);
|
||||||
|
|
||||||
|
NzParticleSystem& operator=(const NzParticleSystem& emitter);
|
||||||
|
NzParticleSystem& operator=(NzParticleSystem&& emitter) = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void GenerateAABB() const;
|
||||||
|
void Register() override;
|
||||||
|
void ResizeBuffer();
|
||||||
|
void Unregister() override;
|
||||||
|
void UpdateBoundingVolume() const;
|
||||||
|
void Update() override;
|
||||||
|
|
||||||
|
std::set<unsigned int, std::greater<unsigned int>> m_dyingParticles;
|
||||||
|
mutable std::vector<nzUInt8> m_buffer;
|
||||||
|
std::vector<NzParticleControllerRef> m_controllers;
|
||||||
|
std::vector<NzParticleEmitter*> m_emitters;
|
||||||
|
std::vector<NzParticleGeneratorRef> m_generators;
|
||||||
|
mutable NzBoundingVolumef m_boundingVolume;
|
||||||
|
NzParticleDeclarationConstRef m_declaration;
|
||||||
|
NzParticleRendererRef m_renderer;
|
||||||
|
mutable bool m_boundingVolumeUpdated;
|
||||||
|
bool m_fixedStepEnabled;
|
||||||
|
bool m_processing;
|
||||||
|
float m_stepAccumulator;
|
||||||
|
float m_stepSize;
|
||||||
|
unsigned int m_maxParticleCount;
|
||||||
|
unsigned int m_particleCount;
|
||||||
|
unsigned int m_particleSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NAZARA_PARTICLESYSTEM_HPP
|
||||||
|
|
@ -7,319 +7,22 @@
|
||||||
#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/ParticleSystem.hpp>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <Nazara/Graphics/Debug.hpp>
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
NzParticleEmitter::NzParticleEmitter(unsigned int maxParticleCount, nzParticleLayout layout) :
|
NzParticleEmitter::NzParticleEmitter() :
|
||||||
NzParticleEmitter(maxParticleCount, NzParticleDeclaration::Get(layout))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NzParticleEmitter::NzParticleEmitter(unsigned int maxParticleCount, NzParticleDeclaration* declaration) :
|
|
||||||
m_declaration(declaration),
|
|
||||||
m_boundingVolumeUpdated(false),
|
|
||||||
m_fixedStepEnabled(false),
|
|
||||||
m_processing(false),
|
|
||||||
m_emissionAccumulator(0.f),
|
m_emissionAccumulator(0.f),
|
||||||
m_emissionRate(0.f),
|
m_emissionRate(0.f),
|
||||||
m_stepAccumulator(0.f),
|
m_emissionCount(1)
|
||||||
m_stepSize(1.f/60.f),
|
|
||||||
m_emissionCount(1),
|
|
||||||
m_maxParticleCount(maxParticleCount),
|
|
||||||
m_particleCount(0)
|
|
||||||
{
|
{
|
||||||
// En cas d'erreur, un constructeur ne peut que lancer une exception
|
|
||||||
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
|
|
||||||
|
|
||||||
m_particleSize = m_declaration->GetStride(); // La taille de chaque particule
|
|
||||||
|
|
||||||
ResizeBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
NzParticleEmitter::NzParticleEmitter(const NzParticleEmitter& emitter) :
|
|
||||||
NzSceneNode(emitter),
|
|
||||||
m_controllers(emitter.m_controllers),
|
|
||||||
m_generators(emitter.m_generators),
|
|
||||||
m_boundingVolume(emitter.m_boundingVolume),
|
|
||||||
m_declaration(emitter.m_declaration),
|
|
||||||
m_renderer(emitter.m_renderer),
|
|
||||||
m_boundingVolumeUpdated(emitter.m_boundingVolumeUpdated),
|
|
||||||
m_fixedStepEnabled(emitter.m_fixedStepEnabled),
|
|
||||||
m_processing(false),
|
|
||||||
m_emissionAccumulator(0.f),
|
|
||||||
m_emissionRate(emitter.m_emissionRate),
|
|
||||||
m_stepAccumulator(0.f),
|
|
||||||
m_stepSize(emitter.m_stepSize),
|
|
||||||
m_emissionCount(emitter.m_emissionCount),
|
|
||||||
m_maxParticleCount(emitter.m_maxParticleCount),
|
|
||||||
m_particleCount(emitter.m_particleCount),
|
|
||||||
m_particleSize(emitter.m_particleSize)
|
|
||||||
{
|
|
||||||
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
|
|
||||||
|
|
||||||
ResizeBuffer();
|
|
||||||
|
|
||||||
// On ne copie que les particules vivantes
|
|
||||||
std::memcpy(m_buffer.data(), emitter.m_buffer.data(), emitter.m_particleCount*m_particleSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NzParticleEmitter::~NzParticleEmitter() = default;
|
NzParticleEmitter::~NzParticleEmitter() = default;
|
||||||
|
|
||||||
void NzParticleEmitter::AddController(NzParticleController* controller)
|
void NzParticleEmitter::Emit(NzParticleSystem& system, float elapsedTime) const
|
||||||
{
|
{
|
||||||
m_controllers.emplace_back(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::AddGenerator(NzParticleGenerator* generator)
|
|
||||||
{
|
|
||||||
m_generators.emplace_back(generator);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
|
|
||||||
{
|
|
||||||
///FIXME: Vérifier le renderer
|
|
||||||
if (m_particleCount > 0)
|
|
||||||
{
|
|
||||||
NzParticleMapper mapper(m_buffer.data(), m_declaration);
|
|
||||||
m_renderer->Render(*this, mapper, 0, m_particleCount-1, renderQueue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* NzParticleEmitter::CreateParticle()
|
|
||||||
{
|
|
||||||
return CreateParticles(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* NzParticleEmitter::CreateParticles(unsigned int count)
|
|
||||||
{
|
|
||||||
if (m_particleCount+count > m_maxParticleCount)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
unsigned int particlesIndex = m_particleCount;
|
|
||||||
m_particleCount += count;
|
|
||||||
|
|
||||||
return &m_buffer[particlesIndex*m_particleSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::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* NzParticleEmitter::GenerateParticle()
|
|
||||||
{
|
|
||||||
return GenerateParticles(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* NzParticleEmitter::GenerateParticles(unsigned int count)
|
|
||||||
{
|
|
||||||
void* ptr = CreateParticles(count);
|
|
||||||
if (!ptr)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
NzParticleMapper mapper(ptr, m_declaration);
|
|
||||||
for (NzParticleGenerator* generator : m_generators)
|
|
||||||
generator->Generate(*this, mapper, 0, m_particleCount-1);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NzBoundingVolumef& NzParticleEmitter::GetBoundingVolume() const
|
|
||||||
{
|
|
||||||
if (!m_boundingVolumeUpdated)
|
|
||||||
UpdateBoundingVolume();
|
|
||||||
|
|
||||||
return m_boundingVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int NzParticleEmitter::GetEmissionCount() const
|
|
||||||
{
|
|
||||||
return m_emissionCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
float NzParticleEmitter::GetEmissionRate() const
|
|
||||||
{
|
|
||||||
return m_emissionRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
float NzParticleEmitter::GetFixedStepSize() const
|
|
||||||
{
|
|
||||||
return m_stepSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int NzParticleEmitter::GetMaxParticleCount() const
|
|
||||||
{
|
|
||||||
return m_maxParticleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int NzParticleEmitter::GetParticleCount() const
|
|
||||||
{
|
|
||||||
return m_particleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int NzParticleEmitter::GetParticleSize() const
|
|
||||||
{
|
|
||||||
return m_particleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
nzSceneNodeType NzParticleEmitter::GetSceneNodeType() const
|
|
||||||
{
|
|
||||||
return nzSceneNodeType_ParticleEmitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NzParticleEmitter::IsDrawable() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NzParticleEmitter::IsFixedStepEnabled() const
|
|
||||||
{
|
|
||||||
return m_fixedStepEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::KillParticle(unsigned int index)
|
|
||||||
{
|
|
||||||
///FIXME: Vérifier index
|
|
||||||
|
|
||||||
if (m_processing)
|
|
||||||
{
|
|
||||||
// Le buffer est en train d'être modifié, nous ne pouvons pas réduire sa taille, on place alors la particule dans une liste de secours
|
|
||||||
m_dyingParticles.insert(index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// On déplace la dernière particule vivante à la place de celle-ci
|
|
||||||
if (--m_particleCount > 0)
|
|
||||||
std::memcpy(&m_buffer[index*m_particleSize], &m_buffer[m_particleCount*m_particleSize], m_particleSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::KillParticles()
|
|
||||||
{
|
|
||||||
m_particleCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::RemoveController(NzParticleController* controller)
|
|
||||||
{
|
|
||||||
auto it = std::find(m_controllers.begin(), m_controllers.end(), controller);
|
|
||||||
if (it != m_controllers.end())
|
|
||||||
m_controllers.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::RemoveGenerator(NzParticleGenerator* generator)
|
|
||||||
{
|
|
||||||
auto it = std::find(m_generators.begin(), m_generators.end(), generator);
|
|
||||||
if (it != m_generators.end())
|
|
||||||
m_generators.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::SetEmissionCount(unsigned int count)
|
|
||||||
{
|
|
||||||
m_emissionCount = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::SetEmissionRate(float rate)
|
|
||||||
{
|
|
||||||
m_emissionRate = rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::SetFixedStepSize(float stepSize)
|
|
||||||
{
|
|
||||||
m_stepSize = stepSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::SetRenderer(NzParticleRenderer* renderer)
|
|
||||||
{
|
|
||||||
m_renderer = renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
NzParticleEmitter& NzParticleEmitter::operator=(const NzParticleEmitter& emitter)
|
|
||||||
{
|
|
||||||
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
|
|
||||||
|
|
||||||
NzSceneNode::operator=(emitter);
|
|
||||||
|
|
||||||
m_boundingVolume = emitter.m_boundingVolume;
|
|
||||||
m_boundingVolumeUpdated = emitter.m_boundingVolumeUpdated;
|
|
||||||
m_controllers = emitter.m_controllers;
|
|
||||||
m_declaration = emitter.m_declaration;
|
|
||||||
m_emissionCount = emitter.m_emissionCount;
|
|
||||||
m_emissionRate = emitter.m_emissionRate;
|
|
||||||
m_fixedStepEnabled = emitter.m_fixedStepEnabled;
|
|
||||||
m_generators = emitter.m_generators;
|
|
||||||
m_maxParticleCount = emitter.m_maxParticleCount;
|
|
||||||
m_particleCount = emitter.m_particleCount;
|
|
||||||
m_particleSize = emitter.m_particleSize;
|
|
||||||
m_renderer = emitter.m_renderer;
|
|
||||||
m_stepSize = emitter.m_stepSize;
|
|
||||||
|
|
||||||
// La copie ne peut pas (ou plutôt ne devrait pas) avoir lieu pendant une mise à jour, inutile de copier
|
|
||||||
m_dyingParticles.clear();
|
|
||||||
m_emissionAccumulator = 0.f;
|
|
||||||
m_processing = false;
|
|
||||||
m_stepAccumulator = 0.f;
|
|
||||||
|
|
||||||
m_buffer.clear(); // Pour éviter une recopie lors du resize() qui ne servira pas à grand chose
|
|
||||||
ResizeBuffer();
|
|
||||||
|
|
||||||
// On ne copie que les particules vivantes
|
|
||||||
std::memcpy(m_buffer.data(), emitter.m_buffer.data(), emitter.m_particleCount*m_particleSize);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::GenerateAABB() const
|
|
||||||
{
|
|
||||||
m_boundingVolume.MakeInfinite();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::Register()
|
|
||||||
{
|
|
||||||
m_scene->RegisterForUpdate(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::ResizeBuffer()
|
|
||||||
{
|
|
||||||
// Histoire de décrire un peu mieux l'erreur en cas d'échec
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_buffer.resize(m_maxParticleCount*m_particleSize);
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
NzStringStream stream;
|
|
||||||
stream << "Failed to allocate particle buffer (" << e.what() << ") for " << m_maxParticleCount << " particles of size " << m_particleSize;
|
|
||||||
|
|
||||||
NazaraError(stream.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::Unregister()
|
|
||||||
{
|
|
||||||
m_scene->UnregisterForUpdate(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::UpdateBoundingVolume() const
|
|
||||||
{
|
|
||||||
if (m_boundingVolume.IsNull())
|
|
||||||
GenerateAABB();
|
|
||||||
|
|
||||||
if (!m_transformMatrixUpdated)
|
|
||||||
UpdateTransformMatrix();
|
|
||||||
|
|
||||||
m_boundingVolume.Update(m_transformMatrix);
|
|
||||||
m_boundingVolumeUpdated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NzParticleEmitter::Update()
|
|
||||||
{
|
|
||||||
float elapsedTime = m_scene->GetUpdateTime();
|
|
||||||
|
|
||||||
if (m_emissionRate > 0.f)
|
if (m_emissionRate > 0.f)
|
||||||
{
|
{
|
||||||
// On accumule la partie réelle (pour éviter qu'un taux d'update élevé empêche des particules de se former)
|
// On accumule la partie réelle (pour éviter qu'un taux d'update élevé empêche des particules de se former)
|
||||||
|
|
@ -334,57 +37,33 @@ void NzParticleEmitter::Update()
|
||||||
unsigned int maxParticleCount = static_cast<unsigned int>(emissionCount)*m_emissionCount;
|
unsigned int maxParticleCount = static_cast<unsigned int>(emissionCount)*m_emissionCount;
|
||||||
|
|
||||||
// On récupère le nombre de particules qu'il est possible de créer selon l'espace libre
|
// On récupère le nombre de particules qu'il est possible de créer selon l'espace libre
|
||||||
unsigned int particleCount = std::min(maxParticleCount, m_maxParticleCount - m_particleCount);
|
unsigned int particleCount = std::min(maxParticleCount, system.GetMaxParticleCount() - system.GetParticleCount());
|
||||||
|
|
||||||
// Et on émet nos particules
|
// Et on émet nos particules
|
||||||
GenerateParticles(particleCount);
|
void* particles = system.GenerateParticles(particleCount);
|
||||||
|
NzParticleMapper mapper(particles, system.GetDeclaration());
|
||||||
|
|
||||||
|
SetupParticles(mapper, particleCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (m_particleCount > 0)
|
|
||||||
{
|
unsigned int NzParticleEmitter::GetEmissionCount() const
|
||||||
NzParticleMapper mapper(m_buffer.data(), m_declaration);
|
{
|
||||||
|
return m_emissionCount;
|
||||||
m_processing = true;
|
}
|
||||||
|
|
||||||
// Pour éviter un verrouillage en cas d'exception
|
float NzParticleEmitter::GetEmissionRate() const
|
||||||
NzCallOnExit onExit([this]()
|
{
|
||||||
{
|
return m_emissionRate;
|
||||||
m_processing = false;
|
}
|
||||||
});
|
|
||||||
|
void NzParticleEmitter::SetEmissionCount(unsigned int count)
|
||||||
if (m_fixedStepEnabled)
|
{
|
||||||
{
|
m_emissionCount = count;
|
||||||
m_stepAccumulator += elapsedTime;
|
}
|
||||||
while (m_stepAccumulator >= m_stepSize)
|
|
||||||
{
|
void NzParticleEmitter::SetEmissionRate(float rate)
|
||||||
for (NzParticleController* controller : m_controllers)
|
{
|
||||||
controller->Apply(*this, mapper, 0, m_particleCount-1, m_stepAccumulator);
|
m_emissionRate = rate;
|
||||||
|
|
||||||
m_stepAccumulator -= m_stepSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (NzParticleController* controller : m_controllers)
|
|
||||||
controller->Apply(*this, mapper, 0, m_particleCount-1, elapsedTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_processing = false;
|
|
||||||
onExit.Reset();
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,366 @@
|
||||||
|
// Copyright (C) 2014 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Graphics module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Graphics/ParticleSystem.hpp>
|
||||||
|
#include <Nazara/Core/CallOnExit.hpp>
|
||||||
|
#include <Nazara/Core/ErrorFlags.hpp>
|
||||||
|
#include <Nazara/Core/StringStream.hpp>
|
||||||
|
#include <Nazara/Graphics/ParticleMapper.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <memory>
|
||||||
|
#include <Nazara/Graphics/Debug.hpp>
|
||||||
|
|
||||||
|
NzParticleSystem::NzParticleSystem(unsigned int maxParticleCount, nzParticleLayout layout) :
|
||||||
|
NzParticleSystem(maxParticleCount, NzParticleDeclaration::Get(layout))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NzParticleSystem::NzParticleSystem(unsigned int maxParticleCount, const NzParticleDeclaration* declaration) :
|
||||||
|
m_declaration(declaration),
|
||||||
|
m_boundingVolumeUpdated(false),
|
||||||
|
m_fixedStepEnabled(false),
|
||||||
|
m_processing(false),
|
||||||
|
m_stepAccumulator(0.f),
|
||||||
|
m_stepSize(1.f/60.f),
|
||||||
|
m_maxParticleCount(maxParticleCount),
|
||||||
|
m_particleCount(0)
|
||||||
|
{
|
||||||
|
// En cas d'erreur, un constructeur ne peut que lancer une exception
|
||||||
|
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
|
||||||
|
|
||||||
|
m_particleSize = m_declaration->GetStride(); // La taille de chaque particule
|
||||||
|
|
||||||
|
ResizeBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
NzParticleSystem::NzParticleSystem(const NzParticleSystem& system) :
|
||||||
|
NzSceneNode(system),
|
||||||
|
m_controllers(system.m_controllers),
|
||||||
|
m_generators(system.m_generators),
|
||||||
|
m_boundingVolume(system.m_boundingVolume),
|
||||||
|
m_declaration(system.m_declaration),
|
||||||
|
m_renderer(system.m_renderer),
|
||||||
|
m_boundingVolumeUpdated(system.m_boundingVolumeUpdated),
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
|
||||||
|
|
||||||
|
ResizeBuffer();
|
||||||
|
|
||||||
|
// On ne copie que les particules vivantes
|
||||||
|
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
NzParticleSystem::~NzParticleSystem() = default;
|
||||||
|
|
||||||
|
void NzParticleSystem::AddController(NzParticleController* controller)
|
||||||
|
{
|
||||||
|
m_controllers.emplace_back(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::AddEmitter(NzParticleEmitter* emitter)
|
||||||
|
{
|
||||||
|
m_emitters.emplace_back(emitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::AddGenerator(NzParticleGenerator* generator)
|
||||||
|
{
|
||||||
|
m_generators.emplace_back(generator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::AddToRenderQueue(NzAbstractRenderQueue* renderQueue) const
|
||||||
|
{
|
||||||
|
///FIXME: Vérifier le renderer
|
||||||
|
if (m_particleCount > 0)
|
||||||
|
{
|
||||||
|
NzParticleMapper mapper(m_buffer.data(), m_declaration);
|
||||||
|
m_renderer->Render(*this, mapper, 0, m_particleCount-1, renderQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* NzParticleSystem::CreateParticle()
|
||||||
|
{
|
||||||
|
return CreateParticles(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* NzParticleSystem::CreateParticles(unsigned int count)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (m_particleCount+count > m_maxParticleCount)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
unsigned int particlesIndex = m_particleCount;
|
||||||
|
m_particleCount += 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* NzParticleSystem::GenerateParticles(unsigned int count)
|
||||||
|
{
|
||||||
|
void* ptr = CreateParticles(count);
|
||||||
|
if (!ptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
NzParticleMapper mapper(ptr, m_declaration);
|
||||||
|
for (NzParticleGenerator* generator : m_generators)
|
||||||
|
generator->Generate(*this, mapper, 0, m_particleCount-1);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NzBoundingVolumef& NzParticleSystem::GetBoundingVolume() const
|
||||||
|
{
|
||||||
|
if (!m_boundingVolumeUpdated)
|
||||||
|
UpdateBoundingVolume();
|
||||||
|
|
||||||
|
return m_boundingVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NzParticleDeclaration* NzParticleSystem::GetDeclaration() const
|
||||||
|
{
|
||||||
|
return m_declaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
float NzParticleSystem::GetFixedStepSize() const
|
||||||
|
{
|
||||||
|
return m_stepSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int NzParticleSystem::GetMaxParticleCount() const
|
||||||
|
{
|
||||||
|
return m_maxParticleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int NzParticleSystem::GetParticleCount() const
|
||||||
|
{
|
||||||
|
return m_particleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
if (m_processing)
|
||||||
|
{
|
||||||
|
// Le buffer est en train d'être modifié, nous ne pouvons pas réduire sa taille, on place alors la particule dans une liste de secours
|
||||||
|
m_dyingParticles.insert(index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On déplace la dernière particule vivante à la place de celle-ci
|
||||||
|
if (--m_particleCount > 0)
|
||||||
|
std::memcpy(&m_buffer[index*m_particleSize], &m_buffer[m_particleCount*m_particleSize], m_particleSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::KillParticles()
|
||||||
|
{
|
||||||
|
m_particleCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::RemoveController(NzParticleController* controller)
|
||||||
|
{
|
||||||
|
auto it = std::find(m_controllers.begin(), m_controllers.end(), controller);
|
||||||
|
if (it != m_controllers.end())
|
||||||
|
m_controllers.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::RemoveEmitter(NzParticleEmitter* emitter)
|
||||||
|
{
|
||||||
|
auto it = std::find(m_emitters.begin(), m_emitters.end(), emitter);
|
||||||
|
if (it != m_emitters.end())
|
||||||
|
m_emitters.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::RemoveGenerator(NzParticleGenerator* generator)
|
||||||
|
{
|
||||||
|
auto it = std::find(m_generators.begin(), m_generators.end(), generator);
|
||||||
|
if (it != m_generators.end())
|
||||||
|
m_generators.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::SetFixedStepSize(float stepSize)
|
||||||
|
{
|
||||||
|
m_stepSize = stepSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::SetRenderer(NzParticleRenderer* renderer)
|
||||||
|
{
|
||||||
|
m_renderer = renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
NzParticleSystem& NzParticleSystem::operator=(const NzParticleSystem& system)
|
||||||
|
{
|
||||||
|
NzErrorFlags flags(nzErrorFlag_ThrowException, true);
|
||||||
|
|
||||||
|
NzSceneNode::operator=(system);
|
||||||
|
|
||||||
|
m_boundingVolume = system.m_boundingVolume;
|
||||||
|
m_boundingVolumeUpdated = system.m_boundingVolumeUpdated;
|
||||||
|
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;
|
||||||
|
m_particleSize = system.m_particleSize;
|
||||||
|
m_renderer = system.m_renderer;
|
||||||
|
m_stepSize = system.m_stepSize;
|
||||||
|
|
||||||
|
// La copie ne peut pas (ou plutôt ne devrait pas) avoir lieu pendant une mise à jour, inutile de copier
|
||||||
|
m_dyingParticles.clear();
|
||||||
|
m_processing = false;
|
||||||
|
m_stepAccumulator = 0.f;
|
||||||
|
|
||||||
|
m_buffer.clear(); // Pour éviter une recopie lors du resize() qui ne servira pas à grand chose
|
||||||
|
ResizeBuffer();
|
||||||
|
|
||||||
|
// On ne copie que les particules vivantes
|
||||||
|
std::memcpy(m_buffer.data(), system.m_buffer.data(), system.m_particleCount*m_particleSize);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::GenerateAABB() const
|
||||||
|
{
|
||||||
|
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
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_buffer.resize(m_maxParticleCount*m_particleSize);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
NzStringStream stream;
|
||||||
|
stream << "Failed to allocate particle buffer (" << e.what() << ") for " << m_maxParticleCount << " particles of size " << m_particleSize;
|
||||||
|
|
||||||
|
NazaraError(stream.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::Unregister()
|
||||||
|
{
|
||||||
|
m_scene->UnregisterForUpdate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::UpdateBoundingVolume() const
|
||||||
|
{
|
||||||
|
if (m_boundingVolume.IsNull())
|
||||||
|
GenerateAABB();
|
||||||
|
|
||||||
|
if (!m_transformMatrixUpdated)
|
||||||
|
UpdateTransformMatrix();
|
||||||
|
|
||||||
|
m_boundingVolume.Update(m_transformMatrix);
|
||||||
|
m_boundingVolumeUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzParticleSystem::Update()
|
||||||
|
{
|
||||||
|
float elapsedTime = m_scene->GetUpdateTime();
|
||||||
|
|
||||||
|
// Émission
|
||||||
|
for (NzParticleEmitter* emitter : m_emitters)
|
||||||
|
emitter->Emit(*this, elapsedTime);
|
||||||
|
|
||||||
|
// Mise à jour
|
||||||
|
if (m_particleCount > 0)
|
||||||
|
{
|
||||||
|
NzParticleMapper mapper(m_buffer.data(), m_declaration);
|
||||||
|
|
||||||
|
m_processing = true;
|
||||||
|
|
||||||
|
// Pour éviter un verrouillage en cas d'exception
|
||||||
|
NzCallOnExit onExit([this]()
|
||||||
|
{
|
||||||
|
m_processing = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (m_fixedStepEnabled)
|
||||||
|
{
|
||||||
|
m_stepAccumulator += elapsedTime;
|
||||||
|
while (m_stepAccumulator >= m_stepSize)
|
||||||
|
{
|
||||||
|
for (NzParticleController* controller : m_controllers)
|
||||||
|
controller->Apply(*this, mapper, 0, m_particleCount-1, m_stepAccumulator);
|
||||||
|
|
||||||
|
m_stepAccumulator -= m_stepSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (NzParticleController* controller : m_controllers)
|
||||||
|
controller->Apply(*this, mapper, 0, m_particleCount-1, elapsedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_processing = false;
|
||||||
|
onExit.Reset();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue