0ad/source/graphics/ParticleEmitter.h
bb 157c6af18e Make the space in 0 A.D. non-breaking throughout the codebase.
Avoid cases of filenames
Update years in terms and other legal(ish) documents
Don't update years in license headers, since change is not meaningful

Will add linter rule in seperate commit

Happy recompiling everyone!

Original Patch By: Nescio
Comment By: Gallaecio
Differential Revision: D2620
This was SVN commit r27786.
2023-07-27 20:54:46 +00:00

218 lines
5.8 KiB
C++

/* Copyright (C) 2023 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_PARTICLEEMITTER
#define INCLUDED_PARTICLEEMITTER
#include "graphics/ModelAbstract.h"
#include "graphics/ParticleEmitterType.h"
#include "maths/Quaternion.h"
#include "renderer/backend/IDeviceCommandContext.h"
#include "renderer/backend/IShaderProgram.h"
#include "renderer/VertexArray.h"
#include <map>
/**
* Simulation state for a single particle.
*/
struct SParticle
{
CVector3D pos;
CVector3D velocity;
float angle;
float angleSpeed;
float size;
float sizeGrowthRate;
SColor4ub color;
float age;
float maxAge;
};
typedef std::shared_ptr<CParticleEmitter> CParticleEmitterPtr;
/**
* Particle emitter.
*
* Emitters store particle data in two forms:
* * m_Particles contains the raw data used for the CPU particle simulation.
* * m_VertexArray contains the data required for rendering.
* Particles are rendered as billboard quads, so the vertex array contains four vertices
* per particle with different UV coordinates. The billboard position computation is
* performed by a vertex shader.
*
* The number of particles is a constant for the entire life of the emitter,
* to simplify the updating and rendering.
* m_Particles acts like a ring buffer, so we don't have to worry about dynamically
* allocating particles. If particles have variable lifetimes, they'll exist in the
* array with alpha=0 until they're overwritten by a new particle after the maximum
* lifetime.
*
* (It's quite likely this could be made more efficient, if the overhead of any added
* complexity is not high.)
*/
class CParticleEmitter
{
public:
CParticleEmitter(const CParticleEmitterTypePtr& type);
/**
* Set the position to be used for emission of new particles.
*/
void SetPosition(const CVector3D& pos)
{
m_Pos = pos;
}
CVector3D GetPosition() const
{
return m_Pos;
}
/**
* Set the rotation to be used for emission of new particles (note: depends on particles).
*/
void SetRotation(const CQuaternion& rot)
{
m_Rot = rot;
}
const CQuaternion& GetRotation() const
{
return m_Rot;
}
/**
* Get the bounding box of the center points of particles at their current positions.
*/
const CBoundingBoxAligned& GetParticleBounds() const { return m_ParticleBounds; }
/**
* Push a new particle onto the ring buffer. (May overwrite an old particle.)
*/
void AddParticle(const SParticle& particle);
/**
* Update particle and vertex array data. Must be called before RenderArray.
*
* If frameNumber is the same as the previous call to UpdateArrayData,
* then the function will do no work and return immediately.
*/
void UpdateArrayData(int frameNumber);
/**
* Make the vertex data available for subsequent binding and rendering.
*/
void PrepareForRendering();
/**
* Upload the vertex data to the backend.
*/
void UploadData(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
/**
* Bind rendering state (textures and blend modes).
*/
void Bind(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
Renderer::Backend::IShaderProgram* shader);
/**
* Draw the vertex array.
*/
void RenderArray(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
/**
* Stop this emitter emitting new particles, and pass responsibility for rendering
* to the CParticleManager. This should be called before dropping the last std::shared_ptr
* to this object so that it will carry on rendering (until all particles have dissipated)
* even when it's no longer attached to a model.
* @param self the std::shared_ptr you're about to drop
*/
void Unattach(const CParticleEmitterPtr& self);
void SetEntityVariable(const std::string& name, float value);
CParticleEmitterTypePtr m_Type;
/// Whether this emitter is still emitting new particles
bool m_Active;
CVector3D m_Pos;
CQuaternion m_Rot;
std::map<std::string, float> m_EntityVariables;
std::vector<SParticle> m_Particles;
size_t m_NextParticleIdx;
float m_LastUpdateTime;
float m_EmissionRoundingError;
private:
/// Bounding box of the current particle center points
CBoundingBoxAligned m_ParticleBounds;
VertexIndexArray m_IndexArray;
VertexArray m_VertexArray;
VertexArray::Attribute m_AttributePos;
VertexArray::Attribute m_AttributeAxis;
VertexArray::Attribute m_AttributeUV;
VertexArray::Attribute m_AttributeColor;
Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr;
int m_LastFrameNumber;
};
/**
* Particle emitter model, for attaching emitters as props on other models.
*/
class CModelParticleEmitter : public CModelAbstract
{
public:
CModelParticleEmitter(const CParticleEmitterTypePtr& type);
~CModelParticleEmitter();
/// Dynamic cast
virtual CModelParticleEmitter* ToCModelParticleEmitter()
{
return this;
}
virtual CModelAbstract* Clone() const;
virtual void SetTerrainDirty(ssize_t UNUSED(i0), ssize_t UNUSED(j0), ssize_t UNUSED(i1), ssize_t UNUSED(j1))
{
}
virtual void SetEntityVariable(const std::string& name, float value);
virtual void CalcBounds();
virtual void ValidatePosition();
virtual void InvalidatePosition();
virtual void SetTransform(const CMatrix3D& transform);
CParticleEmitterTypePtr m_Type;
CParticleEmitterPtr m_Emitter;
};
#endif // INCLUDED_PARTICLEEMITTER