mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Adds sort mode to particles
This commit is contained in:
parent
88dc947b6a
commit
2e0c34d479
4 changed files with 107 additions and 13 deletions
|
|
@ -18,6 +18,17 @@
|
|||
</attribute>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="sort">
|
||||
<attribute name="mode">
|
||||
<choice>
|
||||
<value>closest_in_front</value>
|
||||
<value>youngest_in_front</value>
|
||||
<value>oldest_in_front</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="start_full">
|
||||
<!-- flag; true if present -->
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -25,9 +25,11 @@
|
|||
#include "graphics/ParticleManager.h"
|
||||
#include "graphics/RenderableObject.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "lib/allocators/STLAllocators.h"
|
||||
#include "lib/debug.h"
|
||||
#include "lib/types.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "ps/memory/LinearAllocator.h"
|
||||
#include "ps/CStrIntern.h"
|
||||
#include "ps/CStrInternStatic.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
|
@ -42,6 +44,37 @@
|
|||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct ParticleYoungestInFrontCompare
|
||||
{
|
||||
bool operator()(const SParticle& lhs, const SParticle& rhs) const
|
||||
{
|
||||
return lhs.age > rhs.age;
|
||||
}
|
||||
};
|
||||
|
||||
struct ParticleOldestInFrontCompare
|
||||
{
|
||||
bool operator()(const SParticle& lhs, const SParticle& rhs) const
|
||||
{
|
||||
return lhs.age < rhs.age;
|
||||
}
|
||||
};
|
||||
|
||||
struct ParticleClosestInFrontCompare
|
||||
{
|
||||
bool operator()(const SParticle& lhs, const SParticle& rhs) const
|
||||
{
|
||||
return cameraForward.Dot(lhs.pos) > cameraForward.Dot(rhs.pos);
|
||||
}
|
||||
|
||||
CVector3D cameraForward;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
|
||||
m_Type(type), m_Active(true), m_NextParticleIdx(0), m_EmissionRoundingError(0.f),
|
||||
m_LastUpdateTime(type->m_Manager.GetCurrentTime()),
|
||||
|
|
@ -115,6 +148,11 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
|||
if (m_LastFrameNumber == frameNumber)
|
||||
return;
|
||||
|
||||
PS::Memory::ScopedLinearAllocator scopedLinearAllocator{g_Renderer.GetLinearAllocator()};
|
||||
|
||||
using ParticlesVector = std::vector<SParticle, ProxyAllocator<SParticle, PS::Memory::ScopedLinearAllocator>>;
|
||||
ParticlesVector sortedParticles((ParticlesVector::allocator_type(scopedLinearAllocator)));
|
||||
|
||||
m_LastFrameNumber = frameNumber;
|
||||
|
||||
// Update m_Particles
|
||||
|
|
@ -132,24 +170,48 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
|||
|
||||
CBoundingBoxAligned bounds;
|
||||
|
||||
for (size_t i = 0; i < m_Particles.size(); ++i)
|
||||
if (m_Type->m_SortMode != CParticleEmitterType::SortMode::UNSPECIFIED)
|
||||
{
|
||||
sortedParticles.insert(sortedParticles.end(), m_Particles.begin(), m_Particles.end());
|
||||
|
||||
switch (m_Type->m_SortMode)
|
||||
{
|
||||
case CParticleEmitterType::SortMode::YOUNGEST_IN_FRONT:
|
||||
std::sort(sortedParticles.begin(), sortedParticles.end(), ParticleYoungestInFrontCompare{});
|
||||
break;
|
||||
case CParticleEmitterType::SortMode::OLDEST_IN_FRONT:
|
||||
std::sort(sortedParticles.begin(), sortedParticles.end(), ParticleOldestInFrontCompare{});
|
||||
break;
|
||||
case CParticleEmitterType::SortMode::CLOSEST_IN_FRONT:
|
||||
std::sort(sortedParticles.begin(), sortedParticles.end(), ParticleClosestInFrontCompare{
|
||||
g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetIn()});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const std::span<SParticle> particles{
|
||||
m_Type->m_SortMode == CParticleEmitterType::SortMode::UNSPECIFIED ?
|
||||
std::span<SParticle>{m_Particles} : std::span<SParticle>{sortedParticles}};
|
||||
for (const SParticle& particle : particles)
|
||||
{
|
||||
// TODO: for more efficient rendering, maybe we should replace this with
|
||||
// a degenerate quad if alpha is 0
|
||||
|
||||
bounds += m_Particles[i].pos;
|
||||
bounds += particle.pos;
|
||||
|
||||
*attrPos++ = m_Particles[i].pos;
|
||||
*attrPos++ = m_Particles[i].pos;
|
||||
*attrPos++ = m_Particles[i].pos;
|
||||
*attrPos++ = m_Particles[i].pos;
|
||||
*attrPos++ = particle.pos;
|
||||
*attrPos++ = particle.pos;
|
||||
*attrPos++ = particle.pos;
|
||||
*attrPos++ = particle.pos;
|
||||
|
||||
// Compute corner offsets, split into sin/cos components so the vertex
|
||||
// shader can multiply by the camera-right (or left?) and camera-up vectors
|
||||
// to get rotating billboards:
|
||||
|
||||
float s = sin(m_Particles[i].angle) * m_Particles[i].size/2.f;
|
||||
float c = cos(m_Particles[i].angle) * m_Particles[i].size/2.f;
|
||||
float s = sin(particle.angle) * particle.size * 0.5f;
|
||||
float c = cos(particle.angle) * particle.size * 0.5f;
|
||||
|
||||
(*attrAxis)[0] = c;
|
||||
(*attrAxis)[1] = s;
|
||||
|
|
@ -177,7 +239,7 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
|||
(*attrUV)[1] = 1;
|
||||
++attrUV;
|
||||
|
||||
SColor4ub color = m_Particles[i].color;
|
||||
SColor4ub color{particle.color};
|
||||
|
||||
// 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.)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -366,6 +366,7 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
|||
m_Variables[VAR_COLOR_G] = IParticleVarPtr(new CParticleVarConstant(1.f));
|
||||
m_Variables[VAR_COLOR_B] = IParticleVarPtr(new CParticleVarConstant(1.f));
|
||||
m_BlendMode = BlendMode::ADD;
|
||||
m_SortMode = SortMode::UNSPECIFIED;
|
||||
m_StartFull = false;
|
||||
m_UseRelativeVelocity = false;
|
||||
m_Texture = g_Renderer.GetTextureManager().GetErrorTexture();
|
||||
|
|
@ -383,6 +384,7 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
|||
EL(start_full);
|
||||
EL(use_relative_velocity);
|
||||
EL(constant);
|
||||
EL(sort);
|
||||
EL(uniform);
|
||||
EL(copy);
|
||||
EL(expr);
|
||||
|
|
@ -423,6 +425,16 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
|||
else if (mode == "multiply")
|
||||
m_BlendMode = BlendMode::MULTIPLY;
|
||||
}
|
||||
else if (Child.GetNodeName() == el_sort)
|
||||
{
|
||||
const CStr mode{Child.GetAttributes().GetNamedItem(at_mode)};
|
||||
if (mode == "closest_in_front")
|
||||
m_SortMode = SortMode::CLOSEST_IN_FRONT;
|
||||
else if (mode == "youngest_in_front")
|
||||
m_SortMode = SortMode::YOUNGEST_IN_FRONT;
|
||||
else if (mode == "oldest_in_front")
|
||||
m_SortMode = SortMode::OLDEST_IN_FRONT;
|
||||
}
|
||||
else if (Child.GetNodeName() == el_start_full)
|
||||
{
|
||||
m_StartFull = true;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2025 Wildfire Games.
|
||||
/* Copyright (C) 2026 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -87,6 +87,14 @@ private:
|
|||
MULTIPLY
|
||||
};
|
||||
|
||||
enum class SortMode
|
||||
{
|
||||
UNSPECIFIED,
|
||||
YOUNGEST_IN_FRONT,
|
||||
OLDEST_IN_FRONT,
|
||||
CLOSEST_IN_FRONT
|
||||
};
|
||||
|
||||
int GetVariableID(const std::string& name);
|
||||
|
||||
bool LoadXML(const VfsPath& path);
|
||||
|
|
@ -106,7 +114,8 @@ private:
|
|||
|
||||
CTexturePtr m_Texture;
|
||||
|
||||
BlendMode m_BlendMode = BlendMode::ADD;
|
||||
BlendMode m_BlendMode{BlendMode::ADD};
|
||||
SortMode m_SortMode{SortMode::UNSPECIFIED};
|
||||
bool m_StartFull;
|
||||
bool m_UseRelativeVelocity;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue