Line data Source code
1 : /* Copyright (C) 2023 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
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.
8 : *
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.
13 : *
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/>.
16 : */
17 :
18 : #ifndef INCLUDED_PARTICLEEMITTER
19 : #define INCLUDED_PARTICLEEMITTER
20 :
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"
27 :
28 : #include <map>
29 :
30 : /**
31 : * Simulation state for a single particle.
32 : */
33 0 : struct SParticle
34 : {
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;
44 : };
45 :
46 : typedef std::shared_ptr<CParticleEmitter> CParticleEmitterPtr;
47 :
48 : /**
49 : * Particle emitter.
50 : *
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.
57 : *
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.
64 : *
65 : * (It's quite likely this could be made more efficient, if the overhead of any added
66 : * complexity is not high.)
67 : */
68 0 : class CParticleEmitter
69 : {
70 : public:
71 : CParticleEmitter(const CParticleEmitterTypePtr& type);
72 :
73 : /**
74 : * Set the position to be used for emission of new particles.
75 : */
76 0 : void SetPosition(const CVector3D& pos)
77 : {
78 0 : m_Pos = pos;
79 0 : }
80 :
81 0 : CVector3D GetPosition() const
82 : {
83 0 : return m_Pos;
84 : }
85 :
86 : /**
87 : * Set the rotation to be used for emission of new particles (note: depends on particles).
88 : */
89 0 : void SetRotation(const CQuaternion& rot)
90 : {
91 0 : m_Rot = rot;
92 0 : }
93 :
94 0 : const CQuaternion& GetRotation() const
95 : {
96 0 : return m_Rot;
97 : }
98 :
99 : /**
100 : * Get the bounding box of the center points of particles at their current positions.
101 : */
102 0 : const CBoundingBoxAligned& GetParticleBounds() const { return m_ParticleBounds; }
103 :
104 : /**
105 : * Push a new particle onto the ring buffer. (May overwrite an old particle.)
106 : */
107 : void AddParticle(const SParticle& particle);
108 :
109 : /**
110 : * Update particle and vertex array data. Must be called before RenderArray.
111 : *
112 : * If frameNumber is the same as the previous call to UpdateArrayData,
113 : * then the function will do no work and return immediately.
114 : */
115 : void UpdateArrayData(int frameNumber);
116 :
117 : /**
118 : * Make the vertex data available for subsequent binding and rendering.
119 : */
120 : void PrepareForRendering();
121 :
122 : /**
123 : * Upload the vertex data to the backend.
124 : */
125 : void UploadData(
126 : Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
127 :
128 : /**
129 : * Bind rendering state (textures and blend modes).
130 : */
131 : void Bind(
132 : Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
133 : Renderer::Backend::IShaderProgram* shader);
134 :
135 : /**
136 : * Draw the vertex array.
137 : */
138 : void RenderArray(
139 : Renderer::Backend::IDeviceCommandContext* deviceCommandContext);
140 :
141 : /**
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
147 : */
148 : void Unattach(const CParticleEmitterPtr& self);
149 :
150 : void SetEntityVariable(const std::string& name, float value);
151 :
152 : CParticleEmitterTypePtr m_Type;
153 :
154 : /// Whether this emitter is still emitting new particles
155 : bool m_Active;
156 :
157 : CVector3D m_Pos;
158 : CQuaternion m_Rot;
159 :
160 : std::map<std::string, float> m_EntityVariables;
161 :
162 : std::vector<SParticle> m_Particles;
163 : size_t m_NextParticleIdx;
164 :
165 : float m_LastUpdateTime;
166 : float m_EmissionRoundingError;
167 :
168 : private:
169 : /// Bounding box of the current particle center points
170 : CBoundingBoxAligned m_ParticleBounds;
171 :
172 : VertexIndexArray m_IndexArray;
173 :
174 : VertexArray m_VertexArray;
175 : VertexArray::Attribute m_AttributePos;
176 : VertexArray::Attribute m_AttributeAxis;
177 : VertexArray::Attribute m_AttributeUV;
178 : VertexArray::Attribute m_AttributeColor;
179 :
180 : Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr;
181 :
182 : int m_LastFrameNumber;
183 : };
184 :
185 : /**
186 : * Particle emitter model, for attaching emitters as props on other models.
187 : */
188 : class CModelParticleEmitter : public CModelAbstract
189 : {
190 : public:
191 : CModelParticleEmitter(const CParticleEmitterTypePtr& type);
192 : ~CModelParticleEmitter();
193 :
194 : /// Dynamic cast
195 0 : virtual CModelParticleEmitter* ToCModelParticleEmitter()
196 : {
197 0 : return this;
198 : }
199 :
200 : virtual CModelAbstract* Clone() const;
201 :
202 0 : virtual void SetTerrainDirty(ssize_t UNUSED(i0), ssize_t UNUSED(j0), ssize_t UNUSED(i1), ssize_t UNUSED(j1))
203 : {
204 0 : }
205 :
206 : virtual void SetEntityVariable(const std::string& name, float value);
207 :
208 : virtual void CalcBounds();
209 : virtual void ValidatePosition();
210 : virtual void InvalidatePosition();
211 : virtual void SetTransform(const CMatrix3D& transform);
212 :
213 : CParticleEmitterTypePtr m_Type;
214 : CParticleEmitterPtr m_Emitter;
215 : };
216 :
217 : #endif // INCLUDED_PARTICLEEMITTER
|