OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Particles.h
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2013-2016, The OpenClonk Team and contributors
5  *
6  * Distributed under the terms of the ISC license; see accompanying file
7  * "COPYING" for details.
8  *
9  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10  * See accompanying file "TRADEMARK" for details.
11  *
12  * To redistribute this file separately, substitute the full license texts
13  * for the above references.
14  */
15 
17 #include "graphics/C4FacetEx.h"
18 #include "lib/C4Random.h"
19 
20 #include "platform/StdScheduler.h"
21 
22 #include <pcg/pcg_random.hpp>
23 #ifndef USE_CONSOLE
24 #include <GL/glew.h>
25 #endif
26 #include "graphics/C4Shader.h"
27 
28 #ifndef INC_C4Particles
29 #define INC_C4Particles
30 
32 {
44 };
45 
47 {
52 };
53 
55 {
59 };
60 
61 class C4ParticleDefCore;
62 class C4ParticleDef;
63 class C4ParticleList;
64 class C4ParticleChunk;
65 class C4Particle;
68 
69 // core for particle defs
71 {
72 public:
73  StdStrBuf Name; // name
74  C4Rect GfxFace; // rect for graphics
75 
76  C4ParticleDefCore(); // ctor
77  void CompileFunc(StdCompiler * compiler);
78 
79  bool Compile(char *particle_source, const char *name); // compile from def file
80 };
81 
82 // one particle definition
84 {
85 public:
86  C4ParticleDef *previous, *next; // linked list members
87 
88  StdStrBuf Filename; // path to group this particle was loaded from (for EM reloading)
89 
90  C4FacetSurface Gfx; // graphics
91  int32_t Length; // number of phases in gfx
92  int32_t PhasesX; // number of phases per line in gfx
93  float Aspect; // height:width
94 
95  C4ParticleDef(); // ctor
96  ~C4ParticleDef(); // dtor
97 
98  void Clear(); // free mem associated with this class
99 
100  bool Load(C4Group &group); // load particle from group; assume file to be accessed already
101  bool Reload(); // reload particle from stored position
102 };
103 
106 
107 #ifndef USE_CONSOLE
108 // the value providers are used to change the attributes of a particle over the lifetime
110 {
111 private:
112  float startValue, endValue;
113 
114  // used by Random
115  float currentValue;
116 
117  union
118  {
119  int rerollInterval; // for Random
120  float delay; // for Step
121  float speedFactor; // for Speed & Wind & Gravity
122  float parameterValue; // for Sin
123  };
124 
125  union
126  {
127  int alreadyRolled; // for Random
128  int smoothing; // for KeyFrames
129  float maxValue; // for Step & Sin
130  };
131 
132  pcg32 rng; // for Random
133 
134  size_t keyFrameCount;
135  std::vector<float> keyFrames;
136 
137  C4ParticleValueProviderFunction valueFunction;
138  bool isConstant;
139 
140  std::vector<C4ParticleValueProvider*> childrenValueProviders;
141 
142  union
143  {
144  float C4ParticleValueProvider::*floatValueToChange;
145  int C4ParticleValueProvider::*intValueToChange;
146  size_t keyFrameIndex;
147  };
148  enum
149  {
150  VAL_TYPE_INT,
151  VAL_TYPE_FLOAT,
152  VAL_TYPE_KEYFRAMES,
153  };
154  int typeOfValueToChange;
155 
156 public:
157  bool IsConstant() const { return isConstant; }
158  bool IsRandom() const { return valueFunction == &C4ParticleValueProvider::Random; }
160  startValue(0.f), endValue(0.f), currentValue(0.f), rerollInterval(0), smoothing(0), keyFrameCount(0), valueFunction(0), isConstant(true), floatValueToChange(0), typeOfValueToChange(VAL_TYPE_FLOAT)
161  { }
163  {
164  for (std::vector<C4ParticleValueProvider*>::iterator iter = childrenValueProviders.begin(); iter != childrenValueProviders.end(); ++iter)
165  delete *iter;
166  }
167  C4ParticleValueProvider(const C4ParticleValueProvider &other) { *this = other; }
169 
170  // divides by denominator
171  void Floatify(float denominator);
172 
173  void Set(const C4Value &value);
174  void Set(const C4ValueArray &fromArray);
175  void Set(float to); // constant
176  float GetValue(C4Particle *forParticle);
177 
178 private:
179  void UpdatePointerValue(C4Particle *particle, C4ParticleValueProvider *parent);
180  void UpdateChildren(C4Particle *particle);
181  void FloatifyParameterValue(float C4ParticleValueProvider::*value, float denominator, size_t keyFrameIndex = 0);
182  void SetParameterValue(int type, const C4Value &value, float C4ParticleValueProvider::*floatVal, int C4ParticleValueProvider::*intVal = 0, size_t keyFrameIndex = 0);
183 
184  void SetType(C4ParticleValueProviderID what = C4PV_Const);
185  float Linear(C4Particle *forParticle);
186  float Const(C4Particle *forParticle);
187  float Random(C4Particle *forParticle);
188  float KeyFrames(C4Particle *forParticle);
189  float Sin(C4Particle *forParticle);
190  float Cos(C4Particle *forParticle);
191  float Direction(C4Particle *forParticle);
192  float Step(C4Particle *forParticle);
193  float Speed(C4Particle *forParticle);
194  float Wind(C4Particle *forParticle);
195  float Gravity(C4Particle *forParticle);
196 };
197 
198 // the properties are part of every particle and contain certain changeable attributes
200 {
201 public:
204 
212 
213  float bouncyness;
215  void SetCollisionFunc(const C4Value &source);
216 
217  uint32_t blitMode;
218 
219  uint32_t attachment;
220 
222 
223 
224  void Set(C4PropList *dataSource);
225  // divides ints in certain properties by 1000f and in the color properties by 255f
226  void Floatify();
227 
228 
229  bool CollisionDie(C4Particle *forParticle) { return false; }
230  bool CollisionBounce(C4Particle *forParticle);
231  bool CollisionStop(C4Particle *forParticle);
232 };
233 
234 // one single particle
236 {
237 public:
238 
239  struct DrawingData
240  {
241  static const int vertexCountPerParticle;
242 
243  struct Vertex
244  {
245  float x;
246  float y;
247 
248  float u;
249  float v;
250 
251  float r;
252  float g;
253  float b;
254  float alpha;
255  };
257 
258  int phase;
259 
262  float sizeX, sizeY;
263  float aspect;
264 
265  float offsetX, offsetY;
266 
267  void SetOffset(float x, float y)
268  {
269  offsetX = x;
270  offsetY = y;
271  }
272 
273  void SetPointer(Vertex *startingVertex, bool initial = false)
274  {
275  vertices = startingVertex;
276 
277  if (initial)
278  {
279  vertices[0].u = 0.f; vertices[0].v = 1.f;
280  vertices[1].u = 0.f; vertices[1].v = 0.f;
281  vertices[2].u = 1.f; vertices[2].v = 1.f;
282  vertices[3].u = 1.f; vertices[3].v = 0.f;
283 
284  SetColor(1.f, 1.f, 1.f, 1.f);
285 
286  phase = -1;
287  }
288  }
289 
290  void SetColor(float r, float g, float b, float a = 1.0f)
291  {
292  for (int vertex = 0; vertex < 4; ++vertex)
293  {
294  vertices[vertex].r = r;
295  vertices[vertex].g = g;
296  vertices[vertex].b = b;
297  vertices[vertex].alpha = a;
298  }
299  }
300 
301  void SetPosition(float x, float y, float size, float rotation = 0.f, float stretch = 1.f);
302  void SetPhase(int phase, C4ParticleDef *sourceDef);
303 
304  DrawingData() : currentStretch(1.f), originalSize(0.0001f), aspect(1.f), offsetX(0.f), offsetY(0.f)
305  {
306  }
307 
308  } drawingData;
309 protected:
313 
315 
316 public:
317  float GetAge() const { return startingLifetime - lifetime; }
318  float GetLifetime() const { return lifetime; }
319  float GetRelativeAge() const { return (startingLifetime != 0.f) ? (1.0f - (lifetime / startingLifetime)) : 0.f; }
320 
321  void Init();
322  C4Particle() { Init(); }
323 
324  void SetPosition(float x, float y)
325  {
326  positionX = x;
327  positionY = y;
328  drawingData.SetPosition(positionX, positionY, properties.size.GetValue(this), properties.rotation.GetValue(this));
329  }
330 
331  bool Exec(C4Object *obj, float timeDelta, C4ParticleDef *sourceDef);
332 
333  friend class C4ParticleProperties;
335  friend class C4ParticleChunk;
336  friend class C4ParticleSystem;
337 };
338 
339 // a chunk contains all of the single particles that can be drawn with one draw call (~"have certain similar attributes")
341 {
342 private:
343  C4ParticleDef *sourceDefinition;
344 
345  uint32_t blitMode;
346 
347  // whether the particles are translated according to the object's position
348  uint32_t attachment;
349 
350  std::vector<C4Particle*> particles;
351  std::vector<C4Particle::DrawingData::Vertex> vertexCoordinates;
352  size_t particleCount;
353 
354  // OpenGL optimizations
355  GLuint drawingDataVertexBufferObject;
356  unsigned int drawingDataVertexArraysObject;
357  void ClearBufferObjects();
358 
359  // delete the particle at indexTo. If possible, replace it with the particle at indexFrom to keep the particles tighly packed
360  void DeleteAndReplaceParticle(size_t indexToReplace, size_t indexFrom);
361 
362 public:
363  C4ParticleChunk() : sourceDefinition(0), blitMode(0), attachment(C4ATTACH_None), particleCount(0), drawingDataVertexBufferObject(0), drawingDataVertexArraysObject(0)
364  {
365 
366  }
367  // this is noncopyable to make sure that the OpenGL buffers are never freed multiple times
368  C4ParticleChunk(const C4ParticleChunk&) = delete;
369  C4ParticleChunk& operator=(const C4ParticleChunk&) = delete;
371  {
372  Clear();
373  }
374  // removes all particles
375  void Clear();
376  bool Exec(C4Object *obj, float timeDelta);
377  void Draw(C4TargetFacet cgo, C4Object *obj, C4ShaderCall& call, int texUnit, const StdProjectionMatrix& modelview);
378  bool IsOfType(C4ParticleDef *def, uint32_t _blitMode, uint32_t attachment) const;
379  bool IsEmpty() const { return !particleCount; }
380 
381  // before adding a particle, you should ReserveSpace for it
383  // sets up internal data structures to be large enough for the passed amount of ADDITIONAL particles
384  void ReserveSpace(uint32_t forAmount);
385 
386  friend class C4ParticleList;
387 };
388 
389 // this class must not be copied, because deleting the contained CStdCSec twice would be fatal
390 // a particle list belongs to a game-world entity (objects or global particles) and contains the chunks associated with that entity
392 {
393 private:
394  std::list<C4ParticleChunk*> particleChunks;
395 
396  C4Object *targetObject;
397 
398  // caching..
399  C4ParticleChunk *lastAccessedChunk;
400 
401  // for making sure that the list is not drawn and calculated at the same time
402  CStdCSec accessMutex;
403 
404 public:
405  C4ParticleList(C4Object *obj = 0) : targetObject(obj), lastAccessedChunk(0)
406  {
407 
408  }
409  // non-copyable
410  C4ParticleList(const C4ParticleList&) = delete;
411  C4ParticleList& operator=(const C4ParticleList&) = delete;
412 
414 
415  // this enables third-parties to lock the particle list (for example because a particle in the list is modified from outside)
416  void Lock() { accessMutex.Enter(); }
417  void Unlock() { accessMutex.Leave(); }
418 
419  // deletes all the particles
420  void Clear();
421 
422  void Exec(float timeDelta = 1.f);
423  void Draw(C4TargetFacet cgo, C4Object *obj);
424  C4ParticleChunk *GetFittingParticleChunk(C4ParticleDef *def, uint32_t blitMode, uint32_t attachment, bool alreadyLocked);
425  C4Particle *AddNewParticle(C4ParticleDef *def, uint32_t blitMode, uint32_t attachment, bool alreadyLocked, int remaining = 0);
426 };
427 #endif
428 
429 // cares for the management of particle definitions
431 {
432 private:
433  // pointers to the last and first element of linked list of particle definitions
434  C4ParticleDef *first, *last;
435 public:
436  C4ParticleSystemDefinitionList() : first(0), last(0) {}
437  void Clear();
438  C4ParticleDef *GetDef(const char *name, C4ParticleDef *exclude=0);
439 
440  friend class C4ParticleDef;
441 };
442 
443 // the global particle system interface class
445 {
446 #ifndef USE_CONSOLE
447  class CalculationThread : public StdThread
448  {
449  protected:
450  virtual void Execute();
451  public:
453  };
454  friend class CalculationThread;
455 
456 private:
457  // contains an array with indices for vertices, separated by a primitive restart index
458  GLuint ibo;
459  size_t ibo_size;
460  std::list<C4ParticleList> particleLists;
461  void PreparePrimitiveRestartIndices(uint32_t forSize);
462 
463  CStdCSec particleListAccessMutex;
464  CStdEvent frameCounterAdvancedEvent;
465  CalculationThread calculationThread;
466 
467  int currentSimulationTime; // in game time
468 
469  // calculates the physics in all of the existing particle lists
470  void ExecuteCalculation();
471 
472  C4ParticleList *globalParticles;
473 #endif
474 
475 public:
476 #ifndef USE_CONSOLE
479 #endif
480  // called to allow the particle system the simulation of another step
482  {
483 #ifndef USE_CONSOLE
484  frameCounterAdvancedEvent.Set();
485 #endif
486  }
487  // resets the internal state of the particle system and unloads all definitions
488  void Clear();
490  {
491 #ifndef USE_CONSOLE
492  if (globalParticles) globalParticles->Draw(cgo, 0);
493 #endif
494  }
495 
497  {
498 #ifndef USE_CONSOLE
499  return globalParticles;
500 #else
501  return 0;
502 #endif
503  }
504 
505  C4ParticleList *GetNewParticleList(C4Object *forTarget = 0);
506  // releases up to 2 lists
507  void ReleaseParticleList(C4ParticleList *first, C4ParticleList *second = 0);
508 
509  // interface for particle definitions
511 
512 #ifndef USE_CONSOLE
513  // Returns the IBO ID that contains the PRI data.
514  // This makes sure that the IBO contains enough indices for at least 'forParticleAmount' particles.
515  GLuint GetIBO(size_t forParticleAmount);
516 
517  // creates a new particle
518  void Create(C4ParticleDef *of_def, C4ParticleValueProvider &x, C4ParticleValueProvider &y, C4ParticleValueProvider &speedX, C4ParticleValueProvider &speedY, C4ParticleValueProvider &lifetime, C4PropList *properties, int amount = 1, C4Object *object=nullptr);
519 
520 #endif
521 
522  // removes all of the existing particles (used f.e. for scenario section loading)
523  void ClearAllParticles();
524 
525  friend class C4ParticleList;
526 
527 
528 };
529 
531 
532 #endif
void Floatify(float denominator)
float GetLifetime() const
Definition: C4Particles.h:318
void Draw(C4TargetFacet cgo, C4Object *obj, C4ShaderCall &call, int texUnit, const StdProjectionMatrix &modelview)
C4ParticleProperties properties
Definition: C4Particles.h:314
C4ParticleValueProvider forceY
Definition: C4Particles.h:206
C4ParticleValueProvider phase
Definition: C4Particles.h:210
C4ParticleValueProvider stretch
Definition: C4Particles.h:205
#define b
C4ParticleValueProvider forceX
Definition: C4Particles.h:206
bool CollisionBounce(C4Particle *forParticle)
bool CollisionDie(C4Particle *forParticle)
Definition: C4Particles.h:229
C4ParticleChunk * GetFittingParticleChunk(C4ParticleDef *def, uint32_t blitMode, uint32_t attachment, bool alreadyLocked)
C4ParticleValueProvider colorG
Definition: C4Particles.h:208
static const int vertexCountPerParticle
Definition: C4Particles.h:241
int32_t PhasesX
Definition: C4Particles.h:92
bool IsOfType(C4ParticleDef *def, uint32_t _blitMode, uint32_t attachment) const
int32_t Length
Definition: C4Particles.h:91
Definition: C4Rect.h:29
void DrawGlobalParticles(C4TargetFacet cgo)
Definition: C4Particles.h:489
C4Particle * AddNewParticle()
friend class CalculationThread
Definition: C4Particles.h:454
void SetPhase(int phase, C4ParticleDef *sourceDef)
#define a
C4FacetSurface Gfx
Definition: C4Particles.h:90
float positionY
Definition: C4Particles.h:311
float startingLifetime
Definition: C4Particles.h:312
bool Exec(C4Object *obj, float timeDelta)
bool Start()
C4ParticleValueProvider colorAlpha
Definition: C4Particles.h:208
C4ParticleList * GetNewParticleList(C4Object *forTarget=0)
void Set(C4PropList *dataSource)
bool IsConstant() const
Definition: C4Particles.h:157
void ReleaseParticleList(C4ParticleList *first, C4ParticleList *second=0)
bool Load(C4Group &group)
Definition: C4Particles.cpp:91
float(C4ParticleValueProvider::* C4ParticleValueProviderFunction)(C4Particle *)
Definition: C4Particles.h:104
float lifetime
Definition: C4Particles.h:312
C4ParticleSystem Particles
void SetCollisionFunc(const C4Value &source)
void ReserveSpace(uint32_t forAmount)
float currentSpeedX
Definition: C4Particles.h:310
GLuint GetIBO(size_t forParticleAmount)
bool IsRandom() const
Definition: C4Particles.h:158
StdStrBuf Filename
Definition: C4Particles.h:88
C4ParticleValueProvider(const C4ParticleValueProvider &other)
Definition: C4Particles.h:167
float GetValue(C4Particle *forParticle)
float currentSpeedY
Definition: C4Particles.h:310
bool(C4ParticleProperties::* C4ParticleCollisionCallback)(C4Particle *)
Definition: C4Particles.h:105
C4ParticleCollisionFuncID
Definition: C4Particles.h:54
C4ParticleValueProvider rotation
Definition: C4Particles.h:209
C4ParticleSystemDefinitionList definitions
Definition: C4Particles.h:510
void Exec(float timeDelta=1.f)
bool Compile(char *particle_source, const char *name)
Definition: C4Particles.cpp:52
C4ParticleCollisionCallback collisionCallback
Definition: C4Particles.h:214
void SetPosition(float x, float y)
Definition: C4Particles.h:324
void SetColor(float r, float g, float b, float a=1.0f)
Definition: C4Particles.h:290
virtual void Leave()
Definition: StdSync.h:151
void Set(const C4Value &value)
C4ParticleValueProvider speedDampingX
Definition: C4Particles.h:207
void SetPointer(Vertex *startingVertex, bool initial=false)
Definition: C4Particles.h:273
void Create(C4ParticleDef *of_def, C4ParticleValueProvider &x, C4ParticleValueProvider &y, C4ParticleValueProvider &speedX, C4ParticleValueProvider &speedY, C4ParticleValueProvider &lifetime, C4PropList *properties, int amount=1, C4Object *object=nullptr)
virtual void Enter()
Definition: StdSync.h:150
C4ParticleList(C4Object *obj=0)
Definition: C4Particles.h:405
bool IsEmpty() const
Definition: C4Particles.h:379
void Set()
Definition: StdSync.h:158
C4ParticleValueProvider speedDampingY
Definition: C4Particles.h:207
C4ParticleAttachmentPropertyID
Definition: C4Particles.h:46
C4ParticleDef * previous
Definition: C4Particles.h:86
C4ParticleValueProvider collisionVertex
Definition: C4Particles.h:211
float GetAge() const
Definition: C4Particles.h:317
C4ParticleChunk & operator=(const C4ParticleChunk &)=delete
C4ParticleValueProvider collisionDensity
Definition: C4Particles.h:211
C4ParticleValueProvider colorB
Definition: C4Particles.h:208
bool Exec(C4Object *obj, float timeDelta, C4ParticleDef *sourceDef)
C4ParticleList * GetGlobalParticles()
Definition: C4Particles.h:496
float GetRelativeAge() const
Definition: C4Particles.h:319
C4ParticleValueProvider & operator=(const C4ParticleValueProvider &other)
void Draw(C4TargetFacet cgo, C4Object *obj)
StdStrBuf Name
Definition: C4Particles.h:73
C4ParticleValueProvider colorR
Definition: C4Particles.h:208
C4Particle * AddNewParticle(C4ParticleDef *def, uint32_t blitMode, uint32_t attachment, bool alreadyLocked, int remaining=0)
void CompileFunc(StdCompiler *compiler)
Definition: C4Particles.cpp:41
struct C4Particle::DrawingData drawingData
void SetPosition(float x, float y, float size, float rotation=0.f, float stretch=1.f)
C4ParticleList & operator=(const C4ParticleList &)=delete
C4ParticleDef * GetDef(const char *name, C4ParticleDef *exclude=0)
C4ParticleValueProvider size
Definition: C4Particles.h:205
C4ParticleValueProviderID
Definition: C4Particles.h:31
void SetOffset(float x, float y)
Definition: C4Particles.h:267
float positionX
Definition: C4Particles.h:311
void CalculateNextStep()
Definition: C4Particles.h:481
C4ParticleDef * next
Definition: C4Particles.h:86
bool CollisionStop(C4Particle *forParticle)