[Gameplay] Reduce loom cost
[0ad.git] / source / graphics / ParticleEmitter.h
blob0cc4a72bafa77efd9407a459939c9f88f1c43c42
1 /* Copyright (C) 2023 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #ifndef INCLUDED_PARTICLEEMITTER
19 #define INCLUDED_PARTICLEEMITTER
21 #include "graphics/ModelAbstract.h"
22 #include "graphics/ParticleEmitterType.h"
23 #include "maths/Quaternion.h"
24 #include "renderer/backend/IDeviceCommandContext.h"
25 #include "renderer/backend/IShaderProgram.h"
26 #include "renderer/VertexArray.h"
28 #include <map>
30 /**
31 * Simulation state for a single particle.
33 struct SParticle
35 CVector3D pos;
36 CVector3D velocity;
37 float angle;
38 float angleSpeed;
39 float size;
40 float sizeGrowthRate;
41 SColor4ub color;
42 float age;
43 float maxAge;
46 typedef std::shared_ptr<CParticleEmitter> CParticleEmitterPtr;
48 /**
49 * Particle emitter.
51 * Emitters store particle data in two forms:
52 * * m_Particles contains the raw data used for the CPU particle simulation.
53 * * m_VertexArray contains the data required for rendering.
54 * Particles are rendered as billboard quads, so the vertex array contains four vertices
55 * per particle with different UV coordinates. The billboard position computation is
56 * performed by a vertex shader.
58 * The number of particles is a constant for the entire life of the emitter,
59 * to simplify the updating and rendering.
60 * m_Particles acts like a ring buffer, so we don't have to worry about dynamically
61 * allocating particles. If particles have variable lifetimes, they'll exist in the
62 * array with alpha=0 until they're overwritten by a new particle after the maximum
63 * lifetime.
65 * (It's quite likely this could be made more efficient, if the overhead of any added
66 * complexity is not high.)
68 class CParticleEmitter
70 public:
71 CParticleEmitter(const CParticleEmitterTypePtr& type);
73 /**
74 * Set the position to be used for emission of new particles.
76 void SetPosition(const CVector3D& pos)
78 m_Pos = pos;
81 CVector3D GetPosition() const
83 return m_Pos;
86 /**
87 * Set the rotation to be used for emission of new particles (note: depends on particles).
89 void SetRotation(const CQuaternion& rot)
91 m_Rot = rot;
94 const CQuaternion& GetRotation() const
96 return m_Rot;
99 /**
100 * Get the bounding box of the center points of particles at their current positions.
102 const CBoundingBoxAligned& GetParticleBounds() const { return m_ParticleBounds; }
105 * Push a new particle onto the ring buffer. (May overwrite an old particle.)
107 void AddParticle(const SParticle& particle);
110 * Update particle and vertex array data. Must be called before RenderArray.
112 * If frameNumber is the same as the previous call to UpdateArrayData,
113 * then the function will do no work and return immediately.
115 void UpdateArrayData(int frameNumber);
118 * Make the vertex data available for subsequent binding and rendering.
120 void PrepareForRendering();
123 * Upload the vertex data to the backend.
125 void UploadData(
126 Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
129 * Bind rendering state (textures and blend modes).
131 void Bind(
132 Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
133 Renderer::Backend::IShaderProgram* shader);
136 * Draw the vertex array.
138 void RenderArray(
139 Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
142 * Stop this emitter emitting new particles, and pass responsibility for rendering
143 * to the CParticleManager. This should be called before dropping the last std::shared_ptr
144 * to this object so that it will carry on rendering (until all particles have dissipated)
145 * even when it's no longer attached to a model.
146 * @param self the std::shared_ptr you're about to drop
148 void Unattach(const CParticleEmitterPtr& self);
150 void SetEntityVariable(const std::string& name, float value);
152 CParticleEmitterTypePtr m_Type;
154 /// Whether this emitter is still emitting new particles
155 bool m_Active;
157 CVector3D m_Pos;
158 CQuaternion m_Rot;
160 std::map<std::string, float> m_EntityVariables;
162 std::vector<SParticle> m_Particles;
163 size_t m_NextParticleIdx;
165 float m_LastUpdateTime;
166 float m_EmissionRoundingError;
168 private:
169 /// Bounding box of the current particle center points
170 CBoundingBoxAligned m_ParticleBounds;
172 VertexIndexArray m_IndexArray;
174 VertexArray m_VertexArray;
175 VertexArray::Attribute m_AttributePos;
176 VertexArray::Attribute m_AttributeAxis;
177 VertexArray::Attribute m_AttributeUV;
178 VertexArray::Attribute m_AttributeColor;
180 Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr;
182 int m_LastFrameNumber;
186 * Particle emitter model, for attaching emitters as props on other models.
188 class CModelParticleEmitter : public CModelAbstract
190 public:
191 CModelParticleEmitter(const CParticleEmitterTypePtr& type);
192 ~CModelParticleEmitter();
194 /// Dynamic cast
195 virtual CModelParticleEmitter* ToCModelParticleEmitter()
197 return this;
200 virtual std::unique_ptr<CModelAbstract> Clone() const;
202 virtual void SetTerrainDirty(ssize_t UNUSED(i0), ssize_t UNUSED(j0), ssize_t UNUSED(i1), ssize_t UNUSED(j1))
206 virtual void SetEntityVariable(const std::string& name, float value);
208 virtual void CalcBounds();
209 virtual void ValidatePosition();
210 virtual void InvalidatePosition();
211 virtual void SetTransform(const CMatrix3D& transform);
213 CParticleEmitterTypePtr m_Type;
214 CParticleEmitterPtr m_Emitter;
217 #endif // INCLUDED_PARTICLEEMITTER