mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-08-15 14:43:32 -07:00
Removes std::shared_ptr usages from particles
This commit is contained in:
parent
d2375de187
commit
5778ef6cac
8 changed files with 127 additions and 102 deletions
|
|
@ -112,7 +112,14 @@ bool CObjectEntry::BuildVariation(const std::vector<const std::set<CStr>*>& comp
|
||||||
|
|
||||||
if (!variation.particles.empty())
|
if (!variation.particles.empty())
|
||||||
{
|
{
|
||||||
m_Model = std::make_unique<CModelParticleEmitter>(g_Renderer.GetSceneRenderer().GetParticleManager().LoadEmitterType(variation.particles));
|
CParticleEmitterType* particleEmitterType{
|
||||||
|
g_Renderer.GetSceneRenderer().GetParticleManager().LoadEmitterType(variation.particles)};
|
||||||
|
if (!particleEmitterType)
|
||||||
|
{
|
||||||
|
LOGERROR("CObjectEntry::BuildVariation(): Failed to load particles %s", variation.particles.string8());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_Model = std::make_unique<CModelParticleEmitter>(*particleEmitterType);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,14 +75,14 @@ struct ParticleClosestInFrontCompare
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
|
CParticleEmitter::CParticleEmitter(const CParticleEmitterType& type) :
|
||||||
m_Type(type), m_LastUpdateTime(type->m_Manager.GetCurrentTime()),
|
m_Type(type), m_LastUpdateTime(type.m_Manager.GetCurrentTime()),
|
||||||
m_IndexArray(Renderer::Backend::IBuffer::Usage::TRANSFER_DST),
|
m_IndexArray(Renderer::Backend::IBuffer::Usage::TRANSFER_DST),
|
||||||
m_VertexArray(Renderer::Backend::IBuffer::Type::VERTEX,
|
m_VertexArray(Renderer::Backend::IBuffer::Type::VERTEX,
|
||||||
Renderer::Backend::IBuffer::Usage::DYNAMIC | Renderer::Backend::IBuffer::Usage::TRANSFER_DST),
|
Renderer::Backend::IBuffer::Usage::DYNAMIC | Renderer::Backend::IBuffer::Usage::TRANSFER_DST),
|
||||||
m_VertexUVArray(Renderer::Backend::IBuffer::Type::VERTEX,
|
m_VertexUVArray(Renderer::Backend::IBuffer::Type::VERTEX,
|
||||||
Renderer::Backend::IBuffer::Usage::TRANSFER_DST),
|
Renderer::Backend::IBuffer::Usage::TRANSFER_DST),
|
||||||
m_LastFrameNumber(-1), m_UseInstancing{type->m_Manager.ShouldUseInstancing()}
|
m_LastFrameNumber(-1), m_UseInstancing{type.m_Manager.ShouldUseInstancing()}
|
||||||
{
|
{
|
||||||
// If we should start with particles fully emitted, pretend that we
|
// If we should start with particles fully emitted, pretend that we
|
||||||
// were created in the past so the first update will produce lots of
|
// were created in the past so the first update will produce lots of
|
||||||
|
|
@ -91,10 +91,10 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
|
||||||
// lifetime-length update of all emitters when the game first starts
|
// lifetime-length update of all emitters when the game first starts
|
||||||
// (so that e.g. buildings constructed later on won't have fully-started
|
// (so that e.g. buildings constructed later on won't have fully-started
|
||||||
// emitters, but those at the start will)?
|
// emitters, but those at the start will)?
|
||||||
if (m_Type->m_StartFull)
|
if (m_Type.m_StartFull)
|
||||||
m_LastUpdateTime -= m_Type->m_MaxLifetime;
|
m_LastUpdateTime -= m_Type.m_MaxLifetime;
|
||||||
|
|
||||||
m_Particles.reserve(m_Type->m_MaxParticles);
|
m_Particles.reserve(m_Type.m_MaxParticles);
|
||||||
|
|
||||||
m_AttributePos.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
|
m_AttributePos.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
|
||||||
m_VertexArray.AddAttribute(&m_AttributePos);
|
m_VertexArray.AddAttribute(&m_AttributePos);
|
||||||
|
|
@ -108,17 +108,17 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
|
||||||
m_AttributeAxisY.format = Renderer::Backend::Format::R32G32B32A32_SFLOAT;
|
m_AttributeAxisY.format = Renderer::Backend::Format::R32G32B32A32_SFLOAT;
|
||||||
m_VertexArray.AddAttribute(&m_AttributeAxisY);
|
m_VertexArray.AddAttribute(&m_AttributeAxisY);
|
||||||
|
|
||||||
m_VertexArray.SetNumberOfVertices(m_UseInstancing ? m_Type->m_MaxParticles : m_Type->m_MaxParticles * 4);
|
m_VertexArray.SetNumberOfVertices(m_UseInstancing ? m_Type.m_MaxParticles : m_Type.m_MaxParticles * 4);
|
||||||
m_VertexArray.Layout();
|
m_VertexArray.Layout();
|
||||||
|
|
||||||
m_AttributeUV.format = Renderer::Backend::Format::R32G32_SFLOAT;
|
m_AttributeUV.format = Renderer::Backend::Format::R32G32_SFLOAT;
|
||||||
m_VertexUVArray.AddAttribute(&m_AttributeUV);
|
m_VertexUVArray.AddAttribute(&m_AttributeUV);
|
||||||
|
|
||||||
m_VertexUVArray.SetNumberOfVertices(m_UseInstancing ? 4 : m_Type->m_MaxParticles * 4);
|
m_VertexUVArray.SetNumberOfVertices(m_UseInstancing ? 4 : m_Type.m_MaxParticles * 4);
|
||||||
m_VertexUVArray.Layout();
|
m_VertexUVArray.Layout();
|
||||||
|
|
||||||
VertexArrayIterator<float[2]> attrUV = m_AttributeUV.GetIterator<float[2]>();
|
VertexArrayIterator<float[2]> attrUV = m_AttributeUV.GetIterator<float[2]>();
|
||||||
for (uint32_t index{0}; index < (m_UseInstancing ? 1u : m_Type->m_MaxParticles); ++index)
|
for (uint32_t index{0}; index < (m_UseInstancing ? 1u : m_Type.m_MaxParticles); ++index)
|
||||||
{
|
{
|
||||||
(*attrUV)[0] = 1;
|
(*attrUV)[0] = 1;
|
||||||
(*attrUV)[1] = 0;
|
(*attrUV)[1] = 0;
|
||||||
|
|
@ -137,10 +137,10 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
|
||||||
m_VertexUVArray.Upload();
|
m_VertexUVArray.Upload();
|
||||||
m_VertexUVArray.FreeBackingStore();
|
m_VertexUVArray.FreeBackingStore();
|
||||||
|
|
||||||
m_IndexArray.SetNumberOfVertices(m_UseInstancing ? 6 : m_Type->m_MaxParticles * 6);
|
m_IndexArray.SetNumberOfVertices(m_UseInstancing ? 6 : m_Type.m_MaxParticles * 6);
|
||||||
m_IndexArray.Layout();
|
m_IndexArray.Layout();
|
||||||
VertexArrayIterator<u16> index = m_IndexArray.GetIterator();
|
VertexArrayIterator<u16> index = m_IndexArray.GetIterator();
|
||||||
for (u16 i = 0; i < (m_UseInstancing ? 1 : m_Type->m_MaxParticles); ++i)
|
for (u16 i = 0; i < (m_UseInstancing ? 1 : m_Type.m_MaxParticles); ++i)
|
||||||
{
|
{
|
||||||
*index++ = i*4 + 0;
|
*index++ = i*4 + 0;
|
||||||
*index++ = i*4 + 1;
|
*index++ = i*4 + 1;
|
||||||
|
|
@ -190,8 +190,8 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
||||||
m_LastFrameNumber = frameNumber;
|
m_LastFrameNumber = frameNumber;
|
||||||
|
|
||||||
// Update m_Particles
|
// Update m_Particles
|
||||||
m_Type->UpdateEmitter(*this, m_Type->m_Manager.GetCurrentTime() - m_LastUpdateTime);
|
m_Type.UpdateEmitter(*this, m_Type.m_Manager.GetCurrentTime() - m_LastUpdateTime);
|
||||||
m_LastUpdateTime = m_Type->m_Manager.GetCurrentTime();
|
m_LastUpdateTime = m_Type.m_Manager.GetCurrentTime();
|
||||||
|
|
||||||
// Regenerate the vertex array data:
|
// Regenerate the vertex array data:
|
||||||
|
|
||||||
|
|
@ -200,15 +200,15 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
||||||
VertexArrayIterator<CVector4D> attrAxisX = m_AttributeAxisX.GetIterator<CVector4D>();
|
VertexArrayIterator<CVector4D> attrAxisX = m_AttributeAxisX.GetIterator<CVector4D>();
|
||||||
VertexArrayIterator<CVector4D> attrAxisY = m_AttributeAxisY.GetIterator<CVector4D>();
|
VertexArrayIterator<CVector4D> attrAxisY = m_AttributeAxisY.GetIterator<CVector4D>();
|
||||||
|
|
||||||
ENSURE(m_Particles.size() <= m_Type->m_MaxParticles);
|
ENSURE(m_Particles.size() <= m_Type.m_MaxParticles);
|
||||||
|
|
||||||
CBoundingBoxAligned bounds;
|
CBoundingBoxAligned bounds;
|
||||||
|
|
||||||
if (m_Type->m_SortMode != CParticleEmitterType::SortMode::UNSPECIFIED)
|
if (m_Type.m_SortMode != CParticleEmitterType::SortMode::UNSPECIFIED)
|
||||||
{
|
{
|
||||||
sortedParticles.insert(sortedParticles.end(), m_Particles.begin(), m_Particles.end());
|
sortedParticles.insert(sortedParticles.end(), m_Particles.begin(), m_Particles.end());
|
||||||
|
|
||||||
switch (m_Type->m_SortMode)
|
switch (m_Type.m_SortMode)
|
||||||
{
|
{
|
||||||
case CParticleEmitterType::SortMode::YOUNGEST_IN_FRONT:
|
case CParticleEmitterType::SortMode::YOUNGEST_IN_FRONT:
|
||||||
std::sort(sortedParticles.begin(), sortedParticles.end(), ParticleYoungestInFrontCompare{});
|
std::sort(sortedParticles.begin(), sortedParticles.end(), ParticleYoungestInFrontCompare{});
|
||||||
|
|
@ -228,7 +228,7 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
||||||
m_NumberOfVisibleParticles = 0;
|
m_NumberOfVisibleParticles = 0;
|
||||||
|
|
||||||
const std::span<SParticle> particles{
|
const std::span<SParticle> particles{
|
||||||
m_Type->m_SortMode == CParticleEmitterType::SortMode::UNSPECIFIED ?
|
m_Type.m_SortMode == CParticleEmitterType::SortMode::UNSPECIFIED ?
|
||||||
std::span<SParticle>{m_Particles} : std::span<SParticle>{sortedParticles}};
|
std::span<SParticle>{m_Particles} : std::span<SParticle>{sortedParticles}};
|
||||||
|
|
||||||
if (m_UseInstancing)
|
if (m_UseInstancing)
|
||||||
|
|
@ -248,8 +248,8 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
||||||
|
|
||||||
// Special case: If the blending depends on the source color, not the source alpha,
|
// Special case: If the blending depends on the source color, not the source alpha,
|
||||||
// then pre-multiply by the alpha. (This is kind of a hack.)
|
// then pre-multiply by the alpha. (This is kind of a hack.)
|
||||||
if (m_Type->m_BlendMode == CParticleEmitterType::BlendMode::OVERLAY ||
|
if (m_Type.m_BlendMode == CParticleEmitterType::BlendMode::OVERLAY ||
|
||||||
m_Type->m_BlendMode == CParticleEmitterType::BlendMode::MULTIPLY)
|
m_Type.m_BlendMode == CParticleEmitterType::BlendMode::MULTIPLY)
|
||||||
{
|
{
|
||||||
color.R = (color.R * color.A) / 255;
|
color.R = (color.R * color.A) / 255;
|
||||||
color.G = (color.G * color.A) / 255;
|
color.G = (color.G * color.A) / 255;
|
||||||
|
|
@ -287,8 +287,8 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
||||||
|
|
||||||
// Special case: If the blending depends on the source color, not the source alpha,
|
// Special case: If the blending depends on the source color, not the source alpha,
|
||||||
// then pre-multiply by the alpha. (This is kind of a hack.)
|
// then pre-multiply by the alpha. (This is kind of a hack.)
|
||||||
if (m_Type->m_BlendMode == CParticleEmitterType::BlendMode::OVERLAY ||
|
if (m_Type.m_BlendMode == CParticleEmitterType::BlendMode::OVERLAY ||
|
||||||
m_Type->m_BlendMode == CParticleEmitterType::BlendMode::MULTIPLY)
|
m_Type.m_BlendMode == CParticleEmitterType::BlendMode::MULTIPLY)
|
||||||
{
|
{
|
||||||
color.R = (color.R * color.A) / 255;
|
color.R = (color.R * color.A) / 255;
|
||||||
color.G = (color.G * color.A) / 255;
|
color.G = (color.G * color.A) / 255;
|
||||||
|
|
@ -339,7 +339,7 @@ void CParticleEmitter::Bind(
|
||||||
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
|
||||||
Renderer::Backend::IShaderProgram* shader)
|
Renderer::Backend::IShaderProgram* shader)
|
||||||
{
|
{
|
||||||
m_Type->m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
m_Type.m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||||
|
|
||||||
CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture();
|
CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture();
|
||||||
deviceCommandContext->SetTexture(
|
deviceCommandContext->SetTexture(
|
||||||
|
|
@ -351,7 +351,7 @@ void CParticleEmitter::Bind(
|
||||||
g_Renderer.GetSceneRenderer().GetLightEnv().Bind(deviceCommandContext, shader);
|
g_Renderer.GetSceneRenderer().GetLightEnv().Bind(deviceCommandContext, shader);
|
||||||
|
|
||||||
deviceCommandContext->SetTexture(
|
deviceCommandContext->SetTexture(
|
||||||
shader->GetBindingSlot(str_baseTex), m_Type->m_Texture->GetBackendTexture());
|
shader->GetBindingSlot(str_baseTex), m_Type.m_Texture->GetBackendTexture());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CParticleEmitter::RenderArray(
|
void CParticleEmitter::RenderArray(
|
||||||
|
|
@ -388,7 +388,7 @@ void CParticleEmitter::AddParticle(const SParticle& particle)
|
||||||
else
|
else
|
||||||
m_Particles[m_NextParticleIdx] = particle;
|
m_Particles[m_NextParticleIdx] = particle;
|
||||||
|
|
||||||
m_NextParticleIdx = (m_NextParticleIdx + 1) % m_Type->m_MaxParticles;
|
m_NextParticleIdx = (m_NextParticleIdx + 1) % m_Type.m_MaxParticles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CParticleEmitter::SetEntityVariable(const std::string& name, float value)
|
void CParticleEmitter::SetEntityVariable(const std::string& name, float value)
|
||||||
|
|
@ -396,15 +396,14 @@ void CParticleEmitter::SetEntityVariable(const std::string& name, float value)
|
||||||
m_EntityVariables[name] = value;
|
m_EntityVariables[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
CModelParticleEmitter::CModelParticleEmitter(const CParticleEmitterTypePtr& type) :
|
CModelParticleEmitter::CModelParticleEmitter(const CParticleEmitterType& type)
|
||||||
m_Type(type)
|
: m_Type{type}, m_Emitter{std::make_unique<CParticleEmitter>(m_Type)}
|
||||||
{
|
{
|
||||||
m_Emitter = CParticleEmitterPtr(new CParticleEmitter(m_Type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CModelParticleEmitter::~CModelParticleEmitter()
|
CModelParticleEmitter::~CModelParticleEmitter()
|
||||||
{
|
{
|
||||||
m_Type->m_Manager.AddUnattachedEmitter(std::move(m_Emitter));
|
m_Type.m_Manager.AddUnattachedEmitter(std::move(m_Emitter));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CModelParticleEmitter::SetEntityVariable(const std::string& name, float value)
|
void CModelParticleEmitter::SetEntityVariable(const std::string& name, float value)
|
||||||
|
|
@ -423,7 +422,7 @@ void CModelParticleEmitter::CalcBounds()
|
||||||
// current computed particle positions plus the emitter type's largest
|
// current computed particle positions plus the emitter type's largest
|
||||||
// potential bounding box at the current position
|
// potential bounding box at the current position
|
||||||
|
|
||||||
m_WorldBounds = m_Type->CalculateBounds(m_Emitter->GetPosition(), m_Emitter->GetParticleBounds());
|
m_WorldBounds = m_Type.CalculateBounds(m_Emitter->GetPosition(), m_Emitter->GetParticleBounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CModelParticleEmitter::ValidatePosition()
|
void CModelParticleEmitter::ValidatePosition()
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,6 @@ struct SParticle
|
||||||
CVector3D axisX, axisY;
|
CVector3D axisX, axisY;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<CParticleEmitter> CParticleEmitterPtr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Particle emitter.
|
* Particle emitter.
|
||||||
*
|
*
|
||||||
|
|
@ -80,7 +78,7 @@ typedef std::shared_ptr<CParticleEmitter> CParticleEmitterPtr;
|
||||||
class CParticleEmitter
|
class CParticleEmitter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CParticleEmitter(const CParticleEmitterTypePtr& type);
|
CParticleEmitter(const CParticleEmitterType& type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the position to be used for emission of new particles.
|
* Set the position to be used for emission of new particles.
|
||||||
|
|
@ -152,7 +150,7 @@ public:
|
||||||
|
|
||||||
void SetEntityVariable(const std::string& name, float value);
|
void SetEntityVariable(const std::string& name, float value);
|
||||||
|
|
||||||
CParticleEmitterTypePtr m_Type;
|
const CParticleEmitterType& m_Type;
|
||||||
|
|
||||||
/// Whether this emitter is still emitting new particles
|
/// Whether this emitter is still emitting new particles
|
||||||
bool m_Active{true};
|
bool m_Active{true};
|
||||||
|
|
@ -194,7 +192,7 @@ private:
|
||||||
class CModelParticleEmitter : public CModelAbstract
|
class CModelParticleEmitter : public CModelAbstract
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CModelParticleEmitter(const CParticleEmitterTypePtr& type);
|
CModelParticleEmitter(const CParticleEmitterType& type);
|
||||||
~CModelParticleEmitter() override;
|
~CModelParticleEmitter() override;
|
||||||
|
|
||||||
/// Dynamic cast
|
/// Dynamic cast
|
||||||
|
|
@ -216,8 +214,8 @@ public:
|
||||||
void InvalidatePosition() override;
|
void InvalidatePosition() override;
|
||||||
void SetTransform(const CMatrix3D& transform) override;
|
void SetTransform(const CMatrix3D& transform) override;
|
||||||
|
|
||||||
CParticleEmitterTypePtr m_Type;
|
const CParticleEmitterType& m_Type;
|
||||||
CParticleEmitterPtr m_Emitter;
|
std::unique_ptr<CParticleEmitter> m_Emitter;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDED_PARTICLEEMITTER
|
#endif // INCLUDED_PARTICLEEMITTER
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ public:
|
||||||
/// Computes and returns a new value.
|
/// Computes and returns a new value.
|
||||||
float Evaluate(CParticleEmitter& emitter)
|
float Evaluate(CParticleEmitter& emitter)
|
||||||
{
|
{
|
||||||
m_LastValue = Compute(*emitter.m_Type, emitter);
|
m_LastValue = Compute(emitter.m_Type, emitter);
|
||||||
return m_LastValue;
|
return m_LastValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,11 +268,15 @@ private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CParticleEmitterType::CParticleEmitterType(const VfsPath& path, CParticleManager& manager) :
|
CParticleEmitterType::CParticleEmitterType(CParticleManager& manager) :
|
||||||
m_Manager(manager)
|
m_Manager(manager)
|
||||||
{
|
{
|
||||||
LoadXML(path);
|
}
|
||||||
// TODO: handle load failure
|
|
||||||
|
bool CParticleEmitterType::Load(const VfsPath& path)
|
||||||
|
{
|
||||||
|
if (!LoadXML(path))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Upper bound on number of particles depends on maximum rate and lifetime
|
// Upper bound on number of particles depends on maximum rate and lifetime
|
||||||
m_MaxLifetime = m_Variables[VAR_LIFETIME]->Max(*this);
|
m_MaxLifetime = m_Variables[VAR_LIFETIME]->Max(*this);
|
||||||
|
|
@ -336,8 +340,12 @@ CParticleEmitterType::CParticleEmitterType(const VfsPath& path, CParticleManager
|
||||||
// Offset by the initial positions
|
// Offset by the initial positions
|
||||||
m_MaxBounds[0] += CVector3D(m_Variables[VAR_POSITION_X]->Min(*this), m_Variables[VAR_POSITION_Y]->Min(*this), m_Variables[VAR_POSITION_Z]->Min(*this));
|
m_MaxBounds[0] += CVector3D(m_Variables[VAR_POSITION_X]->Min(*this), m_Variables[VAR_POSITION_Y]->Min(*this), m_Variables[VAR_POSITION_Z]->Min(*this));
|
||||||
m_MaxBounds[1] += CVector3D(m_Variables[VAR_POSITION_X]->Max(*this), m_Variables[VAR_POSITION_Y]->Max(*this), m_Variables[VAR_POSITION_Z]->Max(*this));
|
m_MaxBounds[1] += CVector3D(m_Variables[VAR_POSITION_X]->Max(*this), m_Variables[VAR_POSITION_Y]->Max(*this), m_Variables[VAR_POSITION_Z]->Max(*this));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CParticleEmitterType::~CParticleEmitterType() = default;
|
||||||
|
|
||||||
int CParticleEmitterType::GetVariableID(const std::string& name)
|
int CParticleEmitterType::GetVariableID(const std::string& name)
|
||||||
{
|
{
|
||||||
if (name == "emissionrate") return VAR_EMISSIONRATE;
|
if (name == "emissionrate") return VAR_EMISSIONRATE;
|
||||||
|
|
@ -364,21 +372,21 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
||||||
// Initialise with sane defaults
|
// Initialise with sane defaults
|
||||||
m_Variables.clear();
|
m_Variables.clear();
|
||||||
m_Variables.resize(VAR__MAX);
|
m_Variables.resize(VAR__MAX);
|
||||||
m_Variables[VAR_EMISSIONRATE] = IParticleVarPtr(new CParticleVarConstant(10.f));
|
m_Variables[VAR_EMISSIONRATE] = std::make_unique<CParticleVarConstant>(10.f);
|
||||||
m_Variables[VAR_LIFETIME] = IParticleVarPtr(new CParticleVarConstant(3.f));
|
m_Variables[VAR_LIFETIME] = std::make_unique<CParticleVarConstant>(3.f);
|
||||||
m_Variables[VAR_POSITION_X] = IParticleVarPtr(new CParticleVarConstant(0.f));
|
m_Variables[VAR_POSITION_X] = std::make_unique<CParticleVarConstant>(0.f);
|
||||||
m_Variables[VAR_POSITION_Y] = IParticleVarPtr(new CParticleVarConstant(0.f));
|
m_Variables[VAR_POSITION_Y] = std::make_unique<CParticleVarConstant>(0.f);
|
||||||
m_Variables[VAR_POSITION_Z] = IParticleVarPtr(new CParticleVarConstant(0.f));
|
m_Variables[VAR_POSITION_Z] = std::make_unique<CParticleVarConstant>(0.f);
|
||||||
m_Variables[VAR_ANGLE] = IParticleVarPtr(new CParticleVarConstant(0.f));
|
m_Variables[VAR_ANGLE] = std::make_unique<CParticleVarConstant>(0.f);
|
||||||
m_Variables[VAR_VELOCITY_X] = IParticleVarPtr(new CParticleVarConstant(0.f));
|
m_Variables[VAR_VELOCITY_X] = std::make_unique<CParticleVarConstant>(0.f);
|
||||||
m_Variables[VAR_VELOCITY_Y] = IParticleVarPtr(new CParticleVarConstant(1.f));
|
m_Variables[VAR_VELOCITY_Y] = std::make_unique<CParticleVarConstant>(1.f);
|
||||||
m_Variables[VAR_VELOCITY_Z] = IParticleVarPtr(new CParticleVarConstant(0.f));
|
m_Variables[VAR_VELOCITY_Z] = std::make_unique<CParticleVarConstant>(0.f);
|
||||||
m_Variables[VAR_VELOCITY_ANGLE] = IParticleVarPtr(new CParticleVarConstant(0.f));
|
m_Variables[VAR_VELOCITY_ANGLE] = std::make_unique<CParticleVarConstant>(0.f);
|
||||||
m_Variables[VAR_SIZE] = IParticleVarPtr(new CParticleVarConstant(1.f));
|
m_Variables[VAR_SIZE] = std::make_unique<CParticleVarConstant>(1.f);
|
||||||
m_Variables[VAR_SIZE_GROWTHRATE] = IParticleVarPtr(new CParticleVarConstant(0.f));
|
m_Variables[VAR_SIZE_GROWTHRATE] = std::make_unique<CParticleVarConstant>(0.f);
|
||||||
m_Variables[VAR_COLOR_R] = IParticleVarPtr(new CParticleVarConstant(1.f));
|
m_Variables[VAR_COLOR_R] = std::make_unique<CParticleVarConstant>(1.f);
|
||||||
m_Variables[VAR_COLOR_G] = IParticleVarPtr(new CParticleVarConstant(1.f));
|
m_Variables[VAR_COLOR_G] = std::make_unique<CParticleVarConstant>(1.f);
|
||||||
m_Variables[VAR_COLOR_B] = IParticleVarPtr(new CParticleVarConstant(1.f));
|
m_Variables[VAR_COLOR_B] = std::make_unique<CParticleVarConstant>(1.f);
|
||||||
m_BlendMode = BlendMode::ADD;
|
m_BlendMode = BlendMode::ADD;
|
||||||
m_SortMode = SortMode::UNSPECIFIED;
|
m_SortMode = SortMode::UNSPECIFIED;
|
||||||
m_StartFull = false;
|
m_StartFull = false;
|
||||||
|
|
@ -390,7 +398,10 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
||||||
CXeromyces XeroFile;
|
CXeromyces XeroFile;
|
||||||
PSRETURN ret = XeroFile.Load(g_VFS, path, "particle");
|
PSRETURN ret = XeroFile.Load(g_VFS, path, "particle");
|
||||||
if (ret != PSRETURN_OK)
|
if (ret != PSRETURN_OK)
|
||||||
|
{
|
||||||
|
LOGERROR("Failed to load particle: '%s'", path.string8());
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Define all the elements and attributes used in the XML file
|
// Define all the elements and attributes used in the XML file
|
||||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||||
|
|
@ -476,9 +487,9 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
||||||
int id = GetVariableID(Child.GetAttributes().GetNamedItem(at_name));
|
int id = GetVariableID(Child.GetAttributes().GetNamedItem(at_name));
|
||||||
if (id != -1)
|
if (id != -1)
|
||||||
{
|
{
|
||||||
m_Variables[id] = IParticleVarPtr(new CParticleVarConstant(
|
m_Variables[id] = std::make_unique<CParticleVarConstant>(
|
||||||
Child.GetAttributes().GetNamedItem(at_value).ToFloat()
|
Child.GetAttributes().GetNamedItem(at_value).ToFloat()
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Child.GetNodeName() == el_uniform)
|
else if (Child.GetNodeName() == el_uniform)
|
||||||
|
|
@ -490,9 +501,9 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
||||||
float max = Child.GetAttributes().GetNamedItem(at_max).ToFloat();
|
float max = Child.GetAttributes().GetNamedItem(at_max).ToFloat();
|
||||||
// To avoid hangs in the RNG, only use it if [min, max) is non-empty
|
// To avoid hangs in the RNG, only use it if [min, max) is non-empty
|
||||||
if (min < max)
|
if (min < max)
|
||||||
m_Variables[id] = IParticleVarPtr(new CParticleVarUniform(min, max));
|
m_Variables[id] = std::make_unique<CParticleVarUniform>(min, max);
|
||||||
else
|
else
|
||||||
m_Variables[id] = IParticleVarPtr(new CParticleVarConstant(min));
|
m_Variables[id] = std::make_unique<CParticleVarConstant>(min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Child.GetNodeName() == el_copy)
|
else if (Child.GetNodeName() == el_copy)
|
||||||
|
|
@ -500,7 +511,7 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
||||||
int id = GetVariableID(Child.GetAttributes().GetNamedItem(at_name));
|
int id = GetVariableID(Child.GetAttributes().GetNamedItem(at_name));
|
||||||
int from = GetVariableID(Child.GetAttributes().GetNamedItem(at_from));
|
int from = GetVariableID(Child.GetAttributes().GetNamedItem(at_from));
|
||||||
if (id != -1 && from != -1)
|
if (id != -1 && from != -1)
|
||||||
m_Variables[id] = IParticleVarPtr(new CParticleVarCopy(from));
|
m_Variables[id] = std::make_unique<CParticleVarCopy>(from);
|
||||||
}
|
}
|
||||||
else if (Child.GetNodeName() == el_expr)
|
else if (Child.GetNodeName() == el_expr)
|
||||||
{
|
{
|
||||||
|
|
@ -509,14 +520,14 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
||||||
float mul = Child.GetAttributes().GetNamedItem(at_mul).ToFloat();
|
float mul = Child.GetAttributes().GetNamedItem(at_mul).ToFloat();
|
||||||
float max = Child.GetAttributes().GetNamedItem(at_max).ToFloat();
|
float max = Child.GetAttributes().GetNamedItem(at_max).ToFloat();
|
||||||
if (id != -1)
|
if (id != -1)
|
||||||
m_Variables[id] = IParticleVarPtr(new CParticleVarExpr(from, mul, max));
|
m_Variables[id] = std::make_unique<CParticleVarExpr>(from, mul, max);
|
||||||
}
|
}
|
||||||
else if (Child.GetNodeName() == el_force)
|
else if (Child.GetNodeName() == el_force)
|
||||||
{
|
{
|
||||||
float x = Child.GetAttributes().GetNamedItem(at_x).ToFloat();
|
float x = Child.GetAttributes().GetNamedItem(at_x).ToFloat();
|
||||||
float y = Child.GetAttributes().GetNamedItem(at_y).ToFloat();
|
float y = Child.GetAttributes().GetNamedItem(at_y).ToFloat();
|
||||||
float z = Child.GetAttributes().GetNamedItem(at_z).ToFloat();
|
float z = Child.GetAttributes().GetNamedItem(at_z).ToFloat();
|
||||||
m_Effectors.push_back(IParticleEffectorPtr(new CParticleEffectorForce(x, y, z)));
|
m_Effectors.push_back(std::make_unique<CParticleEffectorForce>(x, y, z));
|
||||||
}
|
}
|
||||||
else if (Child.GetNodeName() == el_particle)
|
else if (Child.GetNodeName() == el_particle)
|
||||||
{
|
{
|
||||||
|
|
@ -576,7 +587,7 @@ void CParticleEmitterType::UpdateEmitter(CParticleEmitter& emitter, float dt) co
|
||||||
|
|
||||||
void CParticleEmitterType::UpdateEmitterStep(CParticleEmitter& emitter, float dt) const
|
void CParticleEmitterType::UpdateEmitterStep(CParticleEmitter& emitter, float dt) const
|
||||||
{
|
{
|
||||||
ENSURE(emitter.m_Type.get() == this);
|
ENSURE(&emitter.m_Type == this);
|
||||||
|
|
||||||
if (emitter.m_Active)
|
if (emitter.m_Active)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,13 @@ class CParticleEmitterType
|
||||||
{
|
{
|
||||||
NONCOPYABLE(CParticleEmitterType); // reference member
|
NONCOPYABLE(CParticleEmitterType); // reference member
|
||||||
public:
|
public:
|
||||||
CParticleEmitterType(const VfsPath& path, CParticleManager& manager);
|
CParticleEmitterType(CParticleManager& manager);
|
||||||
|
~CParticleEmitterType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if the emitter type was successfuly loaded.
|
||||||
|
*/
|
||||||
|
bool Load(const VfsPath& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class CModelParticleEmitter;
|
friend class CModelParticleEmitter;
|
||||||
|
|
@ -130,15 +136,10 @@ private:
|
||||||
u16 m_MaxParticles;
|
u16 m_MaxParticles;
|
||||||
CBoundingBoxAligned m_MaxBounds;
|
CBoundingBoxAligned m_MaxBounds;
|
||||||
|
|
||||||
typedef std::shared_ptr<IParticleVar> IParticleVarPtr;
|
std::vector<std::unique_ptr<IParticleVar>> m_Variables;
|
||||||
std::vector<IParticleVarPtr> m_Variables;
|
std::vector<std::unique_ptr<IParticleEffector>> m_Effectors;
|
||||||
|
|
||||||
typedef std::shared_ptr<IParticleEffector> IParticleEffectorPtr;
|
|
||||||
std::vector<IParticleEffectorPtr> m_Effectors;
|
|
||||||
|
|
||||||
CParticleManager& m_Manager;
|
CParticleManager& m_Manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<CParticleEmitterType> CParticleEmitterTypePtr;
|
|
||||||
|
|
||||||
#endif // INCLUDED_PARTICLEEMITTERTYPE
|
#endif // INCLUDED_PARTICLEEMITTERTYPE
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include "renderer/backend/IDevice.h"
|
#include "renderer/backend/IDevice.h"
|
||||||
#include "renderer/Scene.h"
|
#include "renderer/Scene.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
@ -48,21 +49,23 @@ CParticleManager::~CParticleManager()
|
||||||
UnregisterFileReloadFunc(ReloadChangedFileCB, this);
|
UnregisterFileReloadFunc(ReloadChangedFileCB, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
CParticleEmitterTypePtr CParticleManager::LoadEmitterType(const VfsPath& path)
|
CParticleEmitterType* CParticleManager::LoadEmitterType(const VfsPath& path)
|
||||||
{
|
{
|
||||||
std::unordered_map<VfsPath, CParticleEmitterTypePtr>::iterator it = m_EmitterTypes.find(path);
|
if (auto it{m_EmitterTypes.find(path)}; it != m_EmitterTypes.end())
|
||||||
if (it != m_EmitterTypes.end())
|
return it->second.get();
|
||||||
return it->second;
|
|
||||||
|
|
||||||
CParticleEmitterTypePtr emitterType(new CParticleEmitterType(path, *this));
|
std::unique_ptr<CParticleEmitterType> emitterType{
|
||||||
m_EmitterTypes[path] = emitterType;
|
std::make_unique<CParticleEmitterType>(*this)};
|
||||||
return emitterType;
|
if (!emitterType->Load(path))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return m_EmitterTypes.emplace(path, std::move(emitterType)).first->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CParticleManager::AddUnattachedEmitter(const CParticleEmitterPtr& emitter)
|
void CParticleManager::AddUnattachedEmitter(std::unique_ptr<CParticleEmitter> emitter)
|
||||||
{
|
{
|
||||||
emitter->m_Active = false;
|
emitter->m_Active = false;
|
||||||
m_UnattachedEmitters.push_back(emitter);
|
m_UnattachedEmitters.emplace_back(std::move(emitter));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CParticleManager::ClearUnattachedEmitters()
|
void CParticleManager::ClearUnattachedEmitters()
|
||||||
|
|
@ -75,18 +78,19 @@ void CParticleManager::Interpolate(const float simFrameLength)
|
||||||
m_CurrentTime += simFrameLength;
|
m_CurrentTime += simFrameLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ParticleAlive
|
||||||
|
{
|
||||||
|
bool operator()(const SParticle& particle) const
|
||||||
|
{
|
||||||
|
return particle.age < particle.maxAge;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct EmitterHasNoParticles
|
struct EmitterHasNoParticles
|
||||||
{
|
{
|
||||||
bool operator()(const CParticleEmitterPtr& emitterPtr)
|
bool operator()(const std::unique_ptr<CParticleEmitter>& emitter) const
|
||||||
{
|
{
|
||||||
CParticleEmitter& emitter = *emitterPtr.get();
|
return std::none_of(emitter->m_Particles.begin(), emitter->m_Particles.end(), ParticleAlive{});
|
||||||
for (size_t i = 0; i < emitter.m_Particles.size(); ++i)
|
|
||||||
{
|
|
||||||
SParticle& p = emitter.m_Particles[i];
|
|
||||||
if (p.age < p.maxAge)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -95,16 +99,21 @@ void CParticleManager::RenderSubmit(SceneCollector& collector, const CFrustum&)
|
||||||
PROFILE("submit unattached particles");
|
PROFILE("submit unattached particles");
|
||||||
|
|
||||||
// Delete any unattached emitters that have no particles left
|
// Delete any unattached emitters that have no particles left
|
||||||
m_UnattachedEmitters.remove_if(EmitterHasNoParticles());
|
std::erase_if(m_UnattachedEmitters, EmitterHasNoParticles());
|
||||||
|
|
||||||
// TODO: should do some frustum culling
|
// TODO: should do some frustum culling
|
||||||
|
|
||||||
for (std::list<CParticleEmitterPtr>::iterator it = m_UnattachedEmitters.begin(); it != m_UnattachedEmitters.end(); ++it)
|
for (std::unique_ptr<CParticleEmitter>& emitter : m_UnattachedEmitters)
|
||||||
collector.Submit(it->get());
|
collector.Submit(emitter.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
Status CParticleManager::ReloadChangedFile(const VfsPath& path)
|
Status CParticleManager::ReloadChangedFile(const VfsPath& path)
|
||||||
{
|
{
|
||||||
m_EmitterTypes.erase(path);
|
if (auto it = m_EmitterTypes.find(path); it != m_EmitterTypes.end())
|
||||||
|
{
|
||||||
|
// We can't erase an emitter type because emitters might hold
|
||||||
|
// a reference to it.
|
||||||
|
it->second->Load(path);
|
||||||
|
}
|
||||||
return INFO::OK;
|
return INFO::OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@
|
||||||
#include "lib/path.h"
|
#include "lib/path.h"
|
||||||
#include "lib/status.h"
|
#include "lib/status.h"
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CFrustum;
|
class CFrustum;
|
||||||
class SceneCollector;
|
class SceneCollector;
|
||||||
|
|
@ -39,7 +39,7 @@ public:
|
||||||
CParticleManager(Renderer::Backend::IDevice& device);
|
CParticleManager(Renderer::Backend::IDevice& device);
|
||||||
~CParticleManager();
|
~CParticleManager();
|
||||||
|
|
||||||
CParticleEmitterTypePtr LoadEmitterType(const VfsPath& path);
|
CParticleEmitterType* LoadEmitterType(const VfsPath& path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the manager to handle rendering of an emitter that is no longer
|
* Tell the manager to handle rendering of an emitter that is no longer
|
||||||
|
|
@ -49,7 +49,7 @@ public:
|
||||||
* will carry on rendering (until all particles have dissipated)
|
* will carry on rendering (until all particles have dissipated)
|
||||||
* even when it's no longer attached to a model.
|
* even when it's no longer attached to a model.
|
||||||
*/
|
*/
|
||||||
void AddUnattachedEmitter(const CParticleEmitterPtr& emitter);
|
void AddUnattachedEmitter(std::unique_ptr<CParticleEmitter> emitter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete unattached emitters if we don't wish to see them anymore (like in actor viewer)
|
* Delete unattached emitters if we don't wish to see them anymore (like in actor viewer)
|
||||||
|
|
@ -72,9 +72,9 @@ public:
|
||||||
private:
|
private:
|
||||||
float m_CurrentTime{0.0f};
|
float m_CurrentTime{0.0f};
|
||||||
|
|
||||||
std::list<CParticleEmitterPtr> m_UnattachedEmitters;
|
std::vector<std::unique_ptr<CParticleEmitter>> m_UnattachedEmitters;
|
||||||
|
|
||||||
std::unordered_map<VfsPath, CParticleEmitterTypePtr> m_EmitterTypes;
|
std::unordered_map<VfsPath, std::unique_ptr<CParticleEmitterType>> m_EmitterTypes;
|
||||||
|
|
||||||
bool m_UseInstancing{false};
|
bool m_UseInstancing{false};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ void ParticleRenderer::RenderParticles(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (emitter->m_Type->m_BlendMode)
|
switch (emitter->m_Type.m_BlendMode)
|
||||||
{
|
{
|
||||||
case CParticleEmitterType::BlendMode::ADD: currentTech = m->techAdd.get(); break;
|
case CParticleEmitterType::BlendMode::ADD: currentTech = m->techAdd.get(); break;
|
||||||
case CParticleEmitterType::BlendMode::SUBTRACT: currentTech = m->techSubtract.get(); break;
|
case CParticleEmitterType::BlendMode::SUBTRACT: currentTech = m->techSubtract.get(); break;
|
||||||
|
|
@ -195,7 +195,7 @@ void ParticleRenderer::RenderParticles(
|
||||||
|
|
||||||
const CMatrix3D rotationMatrix{emitter->GetRotation().ToMatrix()};
|
const CMatrix3D rotationMatrix{emitter->GetRotation().ToMatrix()};
|
||||||
CMatrix3D spaceTransform;
|
CMatrix3D spaceTransform;
|
||||||
if (emitter->m_Type->m_UseLocalSpace)
|
if (emitter->m_Type.m_UseLocalSpace)
|
||||||
{
|
{
|
||||||
spaceTransform = rotationMatrix;
|
spaceTransform = rotationMatrix;
|
||||||
spaceTransform.Translate(emitter->GetPosition());
|
spaceTransform.Translate(emitter->GetPosition());
|
||||||
|
|
@ -219,7 +219,7 @@ void ParticleRenderer::RenderBounds(Renderer::Backend::IDeviceCommandContext& de
|
||||||
for (const CParticleEmitter* emitter : m->emitters[cullGroup])
|
for (const CParticleEmitter* emitter : m->emitters[cullGroup])
|
||||||
{
|
{
|
||||||
const CBoundingBoxAligned bounds =
|
const CBoundingBoxAligned bounds =
|
||||||
emitter->m_Type->CalculateBounds(emitter->GetPosition(), emitter->GetParticleBounds());
|
emitter->m_Type.CalculateBounds(emitter->GetPosition(), emitter->GetParticleBounds());
|
||||||
|
|
||||||
g_Renderer.GetDebugRenderer().DrawBoundingBox(deviceCommandContext, bounds, CColor(0.0f, 1.0f, 0.0f, 1.0f), true);
|
g_Renderer.GetDebugRenderer().DrawBoundingBox(deviceCommandContext, bounds, CColor(0.0f, 1.0f, 0.0f, 1.0f), true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue