Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ParticleEmitterType.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2011 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 #include "precompiled.h"
19 
20 #include "ParticleEmitterType.h"
21 
22 #include "graphics/Color.h"
26 #include "lib/rand.h"
27 #include "maths/MathUtil.h"
28 #include "ps/CLogger.h"
29 #include "ps/Filesystem.h"
30 #include "ps/XML/Xeromyces.h"
31 #include "renderer/Renderer.h"
32 
33 #include <boost/random/uniform_real.hpp>
34 
35 
36 /**
37  * Interface for particle state variables, which get evaluated for each newly
38  * constructed particle.
39  */
41 {
42 public:
44  virtual ~IParticleVar() {}
45 
46  /// Computes and returns a new value.
47  float Evaluate(CParticleEmitter& emitter)
48  {
49  m_LastValue = Compute(*emitter.m_Type, emitter);
50  return m_LastValue;
51  }
52 
53  /**
54  * Returns the last value that Evaluate returned.
55  * This is used for variables that depend on other variables (which is kind
56  * of fragile since it's very order-dependent), so they don't get re-randomised
57  * and don't have a danger of infinite recursion.
58  */
59  float LastValue() { return m_LastValue; }
60 
61  /**
62  * Returns the minimum value that Evaluate might ever return,
63  * for computing bounds.
64  */
65  virtual float Min(CParticleEmitterType& type) = 0;
66 
67  /**
68  * Returns the maximum value that Evaluate might ever return,
69  * for computing bounds.
70  */
71  virtual float Max(CParticleEmitterType& type) = 0;
72 
73 protected:
74  virtual float Compute(CParticleEmitterType& type, CParticleEmitter& emitter) = 0;
75 
76 private:
77  float m_LastValue;
78 };
79 
80 /**
81  * Particle variable that returns a constant value.
82  */
84 {
85 public:
86  CParticleVarConstant(float val) :
87  m_Value(val)
88  {
89  }
90 
91  virtual float Compute(CParticleEmitterType& UNUSED(type), CParticleEmitter& UNUSED(emitter))
92  {
93  return m_Value;
94  }
95 
96  virtual float Min(CParticleEmitterType& UNUSED(type))
97  {
98  return m_Value;
99  }
100 
101  virtual float Max(CParticleEmitterType& UNUSED(type))
102  {
103  return m_Value;
104  }
105 
106 private:
107  float m_Value;
108 };
109 
110 /**
111  * Particle variable that returns a uniformly-distributed random value.
112  */
114 {
115 public:
116  CParticleVarUniform(float min, float max) :
117  m_Min(min), m_Max(max)
118  {
119  }
120 
121  virtual float Compute(CParticleEmitterType& type, CParticleEmitter& UNUSED(emitter))
122  {
123  return boost::uniform_real<>(m_Min, m_Max)(type.m_Manager.m_RNG);
124  }
125 
126  virtual float Min(CParticleEmitterType& UNUSED(type))
127  {
128  return m_Min;
129  }
130 
131  virtual float Max(CParticleEmitterType& UNUSED(type))
132  {
133  return m_Max;
134  }
135 
136 private:
137  float m_Min;
138  float m_Max;
139 };
140 
141 /**
142  * Particle variable that returns the same value as some other variable
143  * (assuming that variable was evaluated before this one).
144  */
146 {
147 public:
148  CParticleVarCopy(int from) :
149  m_From(from)
150  {
151  }
152 
153  virtual float Compute(CParticleEmitterType& type, CParticleEmitter& UNUSED(emitter))
154  {
155  return type.m_Variables[m_From]->LastValue();
156  }
157 
158  virtual float Min(CParticleEmitterType& type)
159  {
160  return type.m_Variables[m_From]->Min(type);
161  }
162 
163  virtual float Max(CParticleEmitterType& type)
164  {
165  return type.m_Variables[m_From]->Max(type);
166  }
167 
168 private:
169  int m_From;
170 };
171 
172 /**
173  * A terrible ad-hoc attempt at handling some particular variable calculation,
174  * which really needs to be cleaned up and generalised.
175  */
177 {
178 public:
179  CParticleVarExpr(const CStr& from, float mul, float max) :
180  m_From(from), m_Mul(mul), m_Max(max)
181  {
182  }
183 
184  virtual float Compute(CParticleEmitterType& UNUSED(type), CParticleEmitter& emitter)
185  {
186  return std::min(m_Max, emitter.m_EntityVariables[m_From] * m_Mul);
187  }
188 
189  virtual float Min(CParticleEmitterType& UNUSED(type))
190  {
191  return 0.f;
192  }
193 
194  virtual float Max(CParticleEmitterType& UNUSED(type))
195  {
196  return m_Max;
197  }
198 
199 private:
200  CStr m_From;
201  float m_Mul;
202  float m_Max;
203 };
204 
205 
206 
207 /**
208  * Interface for particle effectors, which get evaluated every frame to
209  * update particles.
210  */
212 {
213 public:
215  virtual ~IParticleEffector() {}
216 
217  /// Updates all particles.
218  virtual void Evaluate(std::vector<SParticle>& particles, float dt) = 0;
219 
220  /// Returns maximum acceleration caused by this effector.
221  virtual CVector3D Max() = 0;
222 
223 };
224 
225 /**
226  * Particle effector that applies a constant acceleration.
227  */
229 {
230 public:
231  CParticleEffectorForce(float x, float y, float z) :
232  m_Accel(x, y, z)
233  {
234  }
235 
236  virtual void Evaluate(std::vector<SParticle>& particles, float dt)
237  {
238  CVector3D dv = m_Accel * dt;
239 
240  for (size_t i = 0; i < particles.size(); ++i)
241  particles[i].velocity += dv;
242  }
243 
244  virtual CVector3D Max()
245  {
246  return m_Accel;
247  }
248 
249 private:
251 };
252 
253 
254 
255 
257  m_Manager(manager)
258 {
259  LoadXML(path);
260  // TODO: handle load failure
261 
262  // Upper bound on number of particles depends on maximum rate and lifetime
263  m_MaxLifetime = m_Variables[VAR_LIFETIME]->Max(*this);
265 
266 
267  // Compute the worst-case bounds of all possible particles,
268  // based on the min/max values of positions and velocities and accelerations
269  // and sizes. (This isn't a guaranteed bound but it should be sufficient for
270  // culling.)
271 
272  // Assuming constant acceleration,
273  // p = p0 + v0*t + 1/2 a*t^2
274  // => dp/dt = v0 + a*t
275  // = 0 at t = -v0/a
276  // max(p) is at t=0, or t=tmax, or t=-v0/a if that's between 0 and tmax
277  // => max(p) = max(p0, p0 + v0*tmax + 1/2 a*tmax, p0 - 1/2 v0^2/a)
278 
279  // Compute combined acceleration (assume constant)
280  CVector3D accel;
281  for (size_t i = 0; i < m_Effectors.size(); ++i)
282  accel += m_Effectors[i]->Max();
283 
284  CVector3D vmin(m_Variables[VAR_VELOCITY_X]->Min(*this), m_Variables[VAR_VELOCITY_Y]->Min(*this), m_Variables[VAR_VELOCITY_Z]->Min(*this));
285  CVector3D vmax(m_Variables[VAR_VELOCITY_X]->Max(*this), m_Variables[VAR_VELOCITY_Y]->Max(*this), m_Variables[VAR_VELOCITY_Z]->Max(*this));
286 
287  // Start by assuming p0 = 0; compute each XYZ component individually
289  // Lower/upper bounds at t=0, t=tmax
290  m_MaxBounds[0].X = std::min(0.f, vmin.X*m_MaxLifetime + 0.5f*accel.X*m_MaxLifetime*m_MaxLifetime);
291  m_MaxBounds[0].Y = std::min(0.f, vmin.Y*m_MaxLifetime + 0.5f*accel.Y*m_MaxLifetime*m_MaxLifetime);
292  m_MaxBounds[0].Z = std::min(0.f, vmin.Z*m_MaxLifetime + 0.5f*accel.Z*m_MaxLifetime*m_MaxLifetime);
293  m_MaxBounds[1].X = std::max(0.f, vmax.X*m_MaxLifetime + 0.5f*accel.X*m_MaxLifetime*m_MaxLifetime);
294  m_MaxBounds[1].Y = std::max(0.f, vmax.Y*m_MaxLifetime + 0.5f*accel.Y*m_MaxLifetime*m_MaxLifetime);
295  m_MaxBounds[1].Z = std::max(0.f, vmax.Z*m_MaxLifetime + 0.5f*accel.Z*m_MaxLifetime*m_MaxLifetime);
296  // Extend bounds to include position at t where dp/dt=0, if 0 < t < tmax
297  if (accel.X && 0 < -vmin.X/accel.X && -vmin.X/accel.X < m_MaxLifetime)
298  m_MaxBounds[0].X = std::min(m_MaxBounds[0].X, -0.5f*vmin.X*vmin.X / accel.X);
299  if (accel.Y && 0 < -vmin.Y/accel.Y && -vmin.Y/accel.Y < m_MaxLifetime)
300  m_MaxBounds[0].Y = std::min(m_MaxBounds[0].Y, -0.5f*vmin.Y*vmin.Y / accel.Y);
301  if (accel.Z && 0 < -vmin.Z/accel.Z && -vmin.Z/accel.Z < m_MaxLifetime)
302  m_MaxBounds[0].Z = std::min(m_MaxBounds[0].Z, -0.5f*vmin.Z*vmin.Z / accel.Z);
303  if (accel.X && 0 < -vmax.X/accel.X && -vmax.X/accel.X < m_MaxLifetime)
304  m_MaxBounds[1].X = std::max(m_MaxBounds[1].X, -0.5f*vmax.X*vmax.X / accel.X);
305  if (accel.Y && 0 < -vmax.Y/accel.Y && -vmax.Y/accel.Y < m_MaxLifetime)
306  m_MaxBounds[1].Y = std::max(m_MaxBounds[1].Y, -0.5f*vmax.Y*vmax.Y / accel.Y);
307  if (accel.Z && 0 < -vmax.Z/accel.Z && -vmax.Z/accel.Z < m_MaxLifetime)
308  m_MaxBounds[1].Z = std::max(m_MaxBounds[1].Z, -0.5f*vmax.Z*vmax.Z / accel.Z);
309 
310  // Offset by the initial positions
313 }
314 
315 int CParticleEmitterType::GetVariableID(const std::string& name)
316 {
317  if (name == "emissionrate") return VAR_EMISSIONRATE;
318  if (name == "lifetime") return VAR_LIFETIME;
319  if (name == "position.x") return VAR_POSITION_X;
320  if (name == "position.y") return VAR_POSITION_Y;
321  if (name == "position.z") return VAR_POSITION_Z;
322  if (name == "angle") return VAR_ANGLE;
323  if (name == "velocity.x") return VAR_VELOCITY_X;
324  if (name == "velocity.y") return VAR_VELOCITY_Y;
325  if (name == "velocity.z") return VAR_VELOCITY_Z;
326  if (name == "velocity.angle") return VAR_VELOCITY_ANGLE;
327  if (name == "size") return VAR_SIZE;
328  if (name == "color.r") return VAR_COLOR_R;
329  if (name == "color.g") return VAR_COLOR_G;
330  if (name == "color.b") return VAR_COLOR_B;
331  LOGWARNING(L"Particle sets unknown variable '%hs'", name.c_str());
332  return -1;
333 }
334 
336 {
337  // Initialise with sane defaults
338  m_Variables.clear();
339  m_Variables.resize(VAR__MAX);
354  m_BlendEquation = GL_FUNC_ADD;
355  m_BlendFuncSrc = GL_SRC_ALPHA;
356  m_BlendFuncDst = GL_ONE_MINUS_SRC_ALPHA;
357  m_StartFull = false;
358  m_Texture = g_Renderer.GetTextureManager().GetErrorTexture();
359 
360  CXeromyces XeroFile;
361  PSRETURN ret = XeroFile.Load(g_VFS, path);
362  if (ret != PSRETURN_OK)
363  return false;
364 
365  // TODO: should do some RNG schema validation
366 
367  // Define all the elements and attributes used in the XML file
368 #define EL(x) int el_##x = XeroFile.GetElementID(#x)
369 #define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
370  EL(texture);
371  EL(blend);
372  EL(start_full);
373  EL(constant);
374  EL(uniform);
375  EL(copy);
376  EL(expr);
377  EL(force);
378  AT(mode);
379  AT(name);
380  AT(value);
381  AT(min);
382  AT(max);
383  AT(mul);
384  AT(from);
385  AT(x);
386  AT(y);
387  AT(z);
388 #undef AT
389 #undef EL
390 
391  XMBElement Root = XeroFile.GetRoot();
392 
393  XERO_ITER_EL(Root, Child)
394  {
395  if (Child.GetNodeName() == el_texture)
396  {
397  CTextureProperties textureProps(Child.GetText().FromUTF8());
398  textureProps.SetWrap(GL_CLAMP_TO_EDGE);
399  m_Texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
400  }
401  else if (Child.GetNodeName() == el_blend)
402  {
403  CStr mode = Child.GetAttributes().GetNamedItem(at_mode);
404  if (mode == "add")
405  {
406  m_BlendEquation = GL_FUNC_ADD;
407  m_BlendFuncSrc = GL_SRC_ALPHA;
408  m_BlendFuncDst = GL_ONE;
409  }
410  else if (mode == "subtract")
411  {
412  m_BlendEquation = GL_FUNC_REVERSE_SUBTRACT;
413  m_BlendFuncSrc = GL_SRC_ALPHA;
414  m_BlendFuncDst = GL_ONE;
415  }
416  else if (mode == "over")
417  {
418  m_BlendEquation = GL_FUNC_ADD;
419  m_BlendFuncSrc = GL_SRC_ALPHA;
420  m_BlendFuncDst = GL_ONE_MINUS_SRC_ALPHA;
421  }
422  else if (mode == "multiply")
423  {
424  m_BlendEquation = GL_FUNC_ADD;
425  m_BlendFuncSrc = GL_ZERO;
426  m_BlendFuncDst = GL_ONE_MINUS_SRC_COLOR;
427  }
428  }
429  else if (Child.GetNodeName() == el_start_full)
430  {
431  m_StartFull = true;
432  }
433  else if (Child.GetNodeName() == el_constant)
434  {
435  int id = GetVariableID(Child.GetAttributes().GetNamedItem(at_name));
436  if (id != -1)
437  {
439  Child.GetAttributes().GetNamedItem(at_value).ToFloat()
440  ));
441  }
442  }
443  else if (Child.GetNodeName() == el_uniform)
444  {
445  int id = GetVariableID(Child.GetAttributes().GetNamedItem(at_name));
446  if (id != -1)
447  {
448  float min = Child.GetAttributes().GetNamedItem(at_min).ToFloat();
449  float max = Child.GetAttributes().GetNamedItem(at_max).ToFloat();
450  // To avoid hangs in the RNG, only use it if [min, max) is non-empty
451  if (min < max)
452  m_Variables[id] = IParticleVarPtr(new CParticleVarUniform(min, max));
453  else
455  }
456  }
457  else if (Child.GetNodeName() == el_copy)
458  {
459  int id = GetVariableID(Child.GetAttributes().GetNamedItem(at_name));
460  int from = GetVariableID(Child.GetAttributes().GetNamedItem(at_from));
461  if (id != -1 && from != -1)
463  }
464  else if (Child.GetNodeName() == el_expr)
465  {
466  int id = GetVariableID(Child.GetAttributes().GetNamedItem(at_name));
467  CStr from = Child.GetAttributes().GetNamedItem(at_from);
468  float mul = Child.GetAttributes().GetNamedItem(at_mul).ToFloat();
469  float max = Child.GetAttributes().GetNamedItem(at_max).ToFloat();
470  if (id != -1)
471  m_Variables[id] = IParticleVarPtr(new CParticleVarExpr(from, mul, max));
472  }
473  else if (Child.GetNodeName() == el_force)
474  {
475  float x = Child.GetAttributes().GetNamedItem(at_x).ToFloat();
476  float y = Child.GetAttributes().GetNamedItem(at_y).ToFloat();
477  float z = Child.GetAttributes().GetNamedItem(at_z).ToFloat();
479  }
480  }
481 
482  return true;
483 }
484 
486 {
487  // If dt is very large, we should do the update in multiple small
488  // steps to prevent all the particles getting clumped together at
489  // low framerates
490 
491  const float maxStepLength = 0.2f;
492 
493  // Avoid wasting time by computing periods longer than the lifetime
494  // period of the particles
495  dt = std::min(dt, m_MaxLifetime);
496 
497  while (dt > maxStepLength)
498  {
499  UpdateEmitterStep(emitter, maxStepLength);
500  dt -= maxStepLength;
501  }
502 
503  UpdateEmitterStep(emitter, dt);
504 }
505 
507 {
508  ENSURE(emitter.m_Type.get() == this);
509 
510  if (emitter.m_Active)
511  {
512  float emissionRate = m_Variables[VAR_EMISSIONRATE]->Evaluate(emitter);
513 
514  // Find how many new particles to spawn, and accumulate any rounding errors
515  // (to maintain a constant emission rate even if dt is very small)
516  int newParticles = floor(emitter.m_EmissionRoundingError + dt*emissionRate);
517  emitter.m_EmissionRoundingError += dt*emissionRate - newParticles;
518 
519  // If dt was very large, there's no point spawning new particles that
520  // we'll immediately overwrite, so clamp it
521  newParticles = std::min(newParticles, (int)m_MaxParticles);
522 
523  for (int i = 0; i < newParticles; ++i)
524  {
525  // Compute new particle state based on variables
526  SParticle particle;
527 
528  particle.pos.X = m_Variables[VAR_POSITION_X]->Evaluate(emitter);
529  particle.pos.Y = m_Variables[VAR_POSITION_Y]->Evaluate(emitter);
530  particle.pos.Z = m_Variables[VAR_POSITION_Z]->Evaluate(emitter);
531  particle.pos += emitter.m_Pos;
532 
533  particle.velocity.X = m_Variables[VAR_VELOCITY_X]->Evaluate(emitter);
534  particle.velocity.Y = m_Variables[VAR_VELOCITY_Y]->Evaluate(emitter);
535  particle.velocity.Z = m_Variables[VAR_VELOCITY_Z]->Evaluate(emitter);
536 
537  particle.angle = m_Variables[VAR_ANGLE]->Evaluate(emitter);
538  particle.angleSpeed = m_Variables[VAR_VELOCITY_ANGLE]->Evaluate(emitter);
539 
540  particle.size = m_Variables[VAR_SIZE]->Evaluate(emitter);
541 
542  RGBColor color;
543  color.X = m_Variables[VAR_COLOR_R]->Evaluate(emitter);
544  color.Y = m_Variables[VAR_COLOR_G]->Evaluate(emitter);
545  color.Z = m_Variables[VAR_COLOR_B]->Evaluate(emitter);
546  particle.color = ConvertRGBColorTo4ub(color);
547 
548  particle.age = 0.f;
549  particle.maxAge = m_Variables[VAR_LIFETIME]->Evaluate(emitter);
550 
551  emitter.AddParticle(particle);
552  }
553  }
554 
555  // Update particle states
556  for (size_t i = 0; i < emitter.m_Particles.size(); ++i)
557  {
558  SParticle& p = emitter.m_Particles[i];
559 
560  // Don't bother updating particles already at the end of their life
561  if (p.age > p.maxAge)
562  continue;
563 
564  p.pos += p.velocity * dt;
565  p.angle += p.angleSpeed * dt;
566  p.age += dt;
567 
568  // Make alpha fade in/out nicely
569  // TODO: this should probably be done as a variable or something,
570  // instead of hardcoding
571  float ageFrac = p.age / p.maxAge;
572  float a = std::min(1.f-ageFrac, 5.f*ageFrac);
573  p.color.A = clamp((int)(a*255.f), 0, 255);
574  }
575 
576  for (size_t i = 0; i < m_Effectors.size(); ++i)
577  {
578  m_Effectors[i]->Evaluate(emitter.m_Particles, dt);
579  }
580 }
581 
583 {
585  bounds[0] += emitterPos;
586  bounds[1] += emitterPos;
587 
588  bounds += emittedBounds;
589 
590  // The current bounds is for the particles' centers, so expand by
591  // sqrt(2) * max_size/2 to ensure any rotated billboards fit in
592  bounds.Expand(m_Variables[VAR_SIZE]->Max(*this)/2.f * sqrt(2.f));
593 
594  return bounds;
595 }
shared_ptr< IParticleEffector > IParticleEffectorPtr
virtual float Compute(CParticleEmitterType &type, CParticleEmitter &emitter)
virtual CVector3D Max()=0
Returns maximum acceleration caused by this effector.
Definition: Decompose.h:22
friend class CParticleVarConstant
Particle variable that returns a constant value.
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
virtual float Compute(CParticleEmitterType &type, CParticleEmitter &emitter)=0
bool m_Active
Whether this emitter is still emitting new particles.
Particle emitter.
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Load from an XML file (with invisible XMB caching).
Definition: Xeromyces.cpp:65
Definition: Decompose.h:22
Particle emitter type - stores the common state data for all emitters of that type, and uses that data to update the emitter states.
const PSRETURN PSRETURN_OK
Definition: Errors.h:103
virtual void Evaluate(std::vector< SParticle > &particles, float dt)=0
Updates all particles.
virtual float Min(CParticleEmitterType &type)
Returns the minimum value that Evaluate might ever return, for computing bounds.
virtual CVector3D Max()
Returns maximum acceleration caused by this effector.
CParticleVarUniform(float min, float max)
Represents the filename and GL parameters of a texture, for passing to CTextureManager::CreateTexture...
void AddParticle(const SParticle &particle)
Push a new particle onto the ring buffer.
virtual float Min(CParticleEmitterType &type)
Returns the minimum value that Evaluate might ever return, for computing bounds.
#define XERO_ITER_EL(parent_element, child_element)
Definition: Xeromyces.h:91
virtual float Compute(CParticleEmitterType &type, CParticleEmitter &emitter)
Particle effector that applies a constant acceleration.
std::vector< SParticle > m_Particles
#define AT(x)
#define EL(x)
float LastValue()
Returns the last value that Evaluate returned.
CVector3D pos
#define g_Renderer
Definition: Renderer.h:61
Particle variable that returns a uniformly-distributed random value.
void UpdateEmitterStep(CParticleEmitter &emitter, float dt)
Update the state of an emitter&#39;s particles, by a short time dt that can be computed in a single step...
u8 A
Definition: SColor.h:35
#define LOGWARNING
Definition: CLogger.h:34
virtual float Max(CParticleEmitterType &type)=0
Returns the maximum value that Evaluate might ever return, for computing bounds.
Interface for particle effectors, which get evaluated every frame to update particles.
A terrible ad-hoc attempt at handling some particular variable calculation, which really needs to be ...
shared_ptr< IParticleVar > IParticleVarPtr
virtual float Compute(CParticleEmitterType &type, CParticleEmitter &emitter)
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
friend class CParticleVarUniform
boost::mt19937 m_RNG
Random number generator shared between all particle emitters.
CBoundingBoxAligned CalculateBounds(CVector3D emitterPos, CBoundingBoxAligned emittedBounds)
void UpdateEmitter(CParticleEmitter &emitter, float dt)
Update the state of an emitter&#39;s particles, by a potentially long time dt.
virtual float Min(CParticleEmitterType &type)
Returns the minimum value that Evaluate might ever return, for computing bounds.
float X
Definition: Vector3D.h:31
u32 PSRETURN
Definition: Errors.h:75
Definition: path.h:75
Interface for particle state variables, which get evaluated for each newly constructed particle...
float Y
Definition: Vector3D.h:31
virtual void Evaluate(std::vector< SParticle > &particles, float dt)
Updates all particles.
CVector3D velocity
SColor4ub(* ConvertRGBColorTo4ub)(const RGBColor &src)
Definition: Color.cpp:45
CParticleVarExpr(const CStr &from, float mul, float max)
virtual float Max(CParticleEmitterType &type)
Returns the maximum value that Evaluate might ever return, for computing bounds.
CParticleEffectorForce(float x, float y, float z)
virtual float Min(CParticleEmitterType &type)=0
Returns the minimum value that Evaluate might ever return, for computing bounds.
virtual float Compute(CParticleEmitterType &type, CParticleEmitter &emitter)
float Evaluate(CParticleEmitter &emitter)
Computes and returns a new value.
CParticleManager & m_Manager
CBoundingBoxAligned m_MaxBounds
XMBElement GetRoot() const
Definition: XeroXMB.cpp:84
Definition: Decompose.h:22
void Expand(float amount)
Expand the bounding box by the given amount in every direction.
virtual float Max(CParticleEmitterType &type)
Returns the maximum value that Evaluate might ever return, for computing bounds.
virtual float Max(CParticleEmitterType &type)
Returns the maximum value that Evaluate might ever return, for computing bounds.
Particle variable that returns the same value as some other variable (assuming that variable was eval...
CParticleEmitterType(const VfsPath &path, CParticleManager &manager)
virtual float Max(CParticleEmitterType &type)
Returns the maximum value that Evaluate might ever return, for computing bounds.
float Z
Definition: Vector3D.h:31
std::vector< IParticleEffectorPtr > m_Effectors
virtual float Min(CParticleEmitterType &type)
Returns the minimum value that Evaluate might ever return, for computing bounds.
SColor4ub color
std::map< std::string, float > m_EntityVariables
std::vector< IParticleVarPtr > m_Variables
PIVFS g_VFS
Definition: Filesystem.cpp:30
void SetWrap(GLint wrap)
Set wrapping mode (typically GL_REPEAT, GL_CLAMP_TO_EDGE, etc).
T clamp(T value, T min, T max)
Definition: MathUtil.h:32
Simulation state for a single particle.
float angleSpeed
int GetVariableID(const std::string &name)
bool LoadXML(const VfsPath &path)
CParticleEmitterTypePtr m_Type