Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/lib/particles/particle_system.cc @ 4484

Last change on this file since 4484 was 4478, checked in by bensch, 20 years ago

orxonox/trunk: particles documented

File size: 12.7 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_PARTICLE
17
18#include "particle_system.h"
19
20#include "particle_emitter.h"
21#include "particle_engine.h"
22
23#include "field.h"
24
25#include "compiler.h"
26#include "material.h"
27#include "state.h"
28
29
30// needed to find the Position of the Camera
31#include "world.h"
32
33using namespace std;
34
35/**
36   \brief standard constructor
37   \param maxCount the Count of particles in the System
38   \param type The Type of the ParticleSystem
39*/
40ParticleSystem::ParticleSystem (unsigned int maxCount, PARTICLE_TYPE type) : PhysicsInterface(this)
41{
42  this->setClassID(CL_PARTICLE_SYSTEM, "ParticleSystem");
43  this->material = NULL;
44  this->name = NULL;
45  this->maxCount = maxCount;
46  this->count = 0;
47  this->particles = NULL;
48  this->deadList = NULL;
49  this->setConserve(1);
50  this->setLifeSpan(1);
51  this->setInheritSpeed(0);
52  this->glID = NULL;
53  this->setType(type, 1);
54  ParticleEngine::getInstance()->addSystem(this);
55}
56
57
58/**
59   \brief standard deconstructor
60*/
61ParticleSystem::~ParticleSystem()
62{
63  // delete what has to be deleted here
64   ParticleEngine::getInstance()->removeSystem(this);
65
66   // deleting all the living Particles
67   while (this->particles)
68     {
69       Particle* tmpDelPart = this->particles;
70       this->particles = this->particles->next;
71       delete tmpDelPart;
72     }
73
74   // deleting all the dead particles
75   while (this->deadList)
76     {
77       Particle* tmpDelPart = this->deadList;
78       this->deadList = this->deadList->next;
79       delete tmpDelPart;
80     }
81
82   if (this->material)
83     delete this->material;
84}
85
86/**
87   \param particleType the type of particles in this System
88   \param count how many particles (in PARTICLE_MULTI-mode)
89   \todo this will be different
90*/
91void ParticleSystem::setType(PARTICLE_TYPE particleType, int count)
92{
93  this->particleType = particleType;
94  this->dialectCount = count;
95  //  if (glID != NULL)
96  //    delete glID;
97
98  //  glID = new GLuint[count];
99  //  for (int i = 0; i< count; i++)
100  //    glID[i] = 0;
101
102  //  glID[0] = glGenLists(count);
103  if (this->material)
104    delete this->material;
105  this->material = NULL;
106
107  if (this->particleType == PARTICLE_SPRITE)
108    {
109      this->material = new Material("transperencyMap");
110      this->material->setDiffuseMap("pictures/radialTransparency.png");
111      //  material->setTransparency(.5);
112    }
113}
114
115// setting properties
116/**
117   \brief sets the material to an external material
118   \param material: the material to set this material to.
119
120   !! important if the extern material gets deleted it MUST be unregistered here or segfault !!
121*/
122void ParticleSystem::setMaterial(Material* material)
123{
124  this->material = material;
125}
126
127/**
128   \brief how much of the speed from the ParticleEmitter should flow onto the ParticleSystem
129   \param value a Value between zero and one
130
131   if you want to change the value of this variable during emission time (to make it more dynamic)
132   you may want to use the animation class
133*/
134void ParticleSystem::setInheritSpeed(float value)
135{
136  if (unlikely(value > 1.0))
137    this->inheritSpeed = 1;
138  else if (unlikely(value < 0.0))
139    this->inheritSpeed = 0;
140  else
141    this->inheritSpeed = value;
142}
143
144/**
145   \brief Sets the lifespan of newly created particles
146*/   
147void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan)
148{
149  this->lifeSpan = lifeSpan;
150  this->randomLifeSpan = randomLifeSpan;
151}
152
153/**
154   \brief sets the conserve Factor of newly created particles
155*/
156void ParticleSystem::setConserve(float conserve)
157{
158  if (conserve > 1.0)
159    this->conserve = 1.0;
160  else if (conserve < 0.0)
161    this->conserve = 0.0;
162  else
163    this->conserve = conserve;
164}
165
166/////////////////////////////
167/* Per-Particle Attributes */
168/////////////////////////////
169/**
170   \brief sets a key in the radius-animation on a per-particle basis
171   \param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
172   \param radius the radius at this position
173   \param randRadius the randRadius at this position
174*/
175void ParticleSystem::setRadius(float lifeCycleTime, float radius, float randRadius)
176{
177  this->radiusAnim.addEntry(lifeCycleTime, radius);
178  this->randRadiusAnim.addEntry(lifeCycleTime, randRadius);
179}
180
181/**
182   \brief sets a key in the mass-animation on a per-particle basis
183   \param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
184   \param mass the mass at this position
185   \param randMass the randomMass at this position
186*/
187void ParticleSystem::setMass(float lifeCycleTime, float mass, float randMass)
188{
189  this->massAnim.addEntry(lifeCycleTime, mass);
190  this->randMassAnim.addEntry(lifeCycleTime, randMass);
191}
192
193/**
194   \brief sets a key in the color-animation on a per-particle basis
195   \param lifeCycleTime: the time (partilceLifeTime/particleAge) [0-1]
196   \param red: red
197   \param green: green
198   \param blue: blue
199   \param alpha: alpha
200*/
201void ParticleSystem::setColor(float lifeCycleTime, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
202{
203  this->colorAnim[0].addEntry(lifeCycleTime, red);
204  this->colorAnim[1].addEntry(lifeCycleTime, green);
205  this->colorAnim[2].addEntry(lifeCycleTime, blue);
206  this->colorAnim[3].addEntry(lifeCycleTime, alpha);
207}
208
209/**
210   \brief ticks the system.
211   \param dt the time to tick all the Particles of the System
212
213   this is used to get all the particles some motion
214*/
215void ParticleSystem::tick(float dt)
216{
217  Particle* tickPart = particles;  // the particle to Tick
218  Particle* prevPart = NULL;       //
219  while (likely(tickPart != NULL))
220    {
221      // applying force to the System.
222      if (likely (tickPart->mass > 0.0))
223        tickPart->velocity += tickPart->extForce / tickPart->mass * dt;
224
225      // rendering new position.
226      tickPart->position = tickPart->position + tickPart->velocity * dt;
227      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
228        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
229
230      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
231        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
232     
233      tickPart->extForce = Vector(0,0,0);
234
235      // applying Color
236      tickPart->color[0] = this->colorAnim[0].getValue(tickPart->lifeCycle);
237      tickPart->color[1] = this->colorAnim[1].getValue(tickPart->lifeCycle);
238      tickPart->color[2] = this->colorAnim[2].getValue(tickPart->lifeCycle);
239      tickPart->color[3] = this->colorAnim[3].getValue(tickPart->lifeCycle);
240
241      // many more to come
242
243      if (this->conserve < 1.0)
244        tickPart->velocity = tickPart->velocity * this->conserve;
245      // find out if we have to delete tickPart
246      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
247        {
248          // remove the particle from the list
249          if (likely(prevPart != NULL))
250            {
251              prevPart->next = tickPart->next;
252              tickPart->next = this->deadList;
253              this->deadList = tickPart;
254              tickPart = prevPart->next;
255            }
256          else
257            {
258              prevPart = NULL;
259              this->particles = tickPart->next;
260              tickPart->next = this->deadList;
261              this->deadList = tickPart;
262              tickPart = this->particles;
263            }
264          --this->count;
265        }
266      else
267        {     
268          prevPart = tickPart;
269          tickPart = tickPart->next;
270        }
271    }
272}
273
274/**
275    \brief applies some force to a Particle.
276    \param field the Field to apply.
277 */
278void ParticleSystem::applyField(Field* field)
279{
280  Particle* tickPart = particles;
281  while (tickPart)
282    {
283      tickPart->extForce += field->calcForce(tickPart->position);
284      tickPart = tickPart->next;
285    }
286}
287
288
289/**
290   \brief draws all the Particles of this System
291
292   The Cases in this Function all do the same:
293   Drawing all the particles with the appropriate Type.
294   This is just the fastest Way to do this, but will most likely be changed in the future.
295*/
296void ParticleSystem::draw(void) const
297{
298  glPushAttrib(GL_ENABLE_BIT);
299  glDisable(GL_LIGHTING);
300
301  Particle* drawPart = particles;
302     
303  switch (this->particleType)
304    {
305    default:
306    case PARTICLE_SPRITE:
307      glMatrixMode(GL_MODELVIEW);
308      glDisable(GL_DEPTH_TEST);
309
310      material->select(); 
311      //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
312     
313
314      while (likely(drawPart != NULL))
315        {
316          glColor4fv(drawPart->color);
317          //! \todo implement a faster code for the look-at Camera algorithm.
318
319          const PNode* camera = State::getInstance()->getCamera();  //!< \todo MUST be different
320          Vector cameraPos = camera->getAbsCoor();
321          Vector cameraTargetPos = State::getInstance()->getCameraTarget()->getAbsCoor();
322          Vector view = cameraTargetPos - cameraPos;
323          Vector up = Vector(0, 1, 0);
324          up = camera->getAbsDir().apply(up);
325          Vector h = up.cross(view);
326          Vector v = h.cross(view);
327          h.normalize();
328          v.normalize();
329          v *= .5 * drawPart->radius;
330          h *= .5 * drawPart->radius;
331
332          glBegin(GL_TRIANGLE_STRIP);
333          glTexCoord2i(1, 1);
334          glVertex3f(drawPart->position.x - h.x - v.x,
335                     drawPart->position.y - h.y - v.y,
336                     drawPart->position.z - h.z - v.z);
337          glTexCoord2i(0, 1);
338          glVertex3f(drawPart->position.x - h.x + v.x,
339                     drawPart->position.y - h.y + v.y,
340                     drawPart->position.z - h.z + v.z);
341          glTexCoord2i(1, 0);
342          glVertex3f(drawPart->position.x + h.x - v.x,
343                     drawPart->position.y + h.y - v.y,
344                     drawPart->position.z + h.z - v.z);
345          glTexCoord2i(0, 0);
346          glVertex3f(drawPart->position.x + h.x + v.x,
347                     drawPart->position.y + h.y + v.y,
348                     drawPart->position.z + h.z + v.z);
349
350          glEnd();
351 
352          drawPart = drawPart->next;
353        }
354
355     
356      break;
357
358    case PARTICLE_SPARK:
359      glEnable(GL_LINE_SMOOTH);
360      glBegin(GL_LINES);
361      while (likely(drawPart != NULL))
362        {
363          glColor4fv(drawPart->color);
364          glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
365          glVertex3f(drawPart->position.x - drawPart->velocity.x,
366                     drawPart->position.y - drawPart->velocity.y,
367                     drawPart->position.z - drawPart->velocity.z);
368          drawPart = drawPart->next;
369        }
370      glEnd();
371      break;
372     
373    case PARTICLE_DOT:
374      glBegin(GL_POINTS);
375      while (likely(drawPart != NULL))
376        {
377          glColor4fv(drawPart->color);
378
379          glLineWidth(drawPart->radius);
380
381          glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
382          drawPart = drawPart->next;
383        }
384      glEnd();
385      break;
386    }
387  glPopAttrib();
388}
389
390/**
391   \brief adds a new Particle to the System
392   \param position the position where the particle gets emitted.
393   \param velocity the Starting velocity of the particle.
394   \param data some more data given by the emitter
395*/
396void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, unsigned int data)
397{
398  if (this->count <= this->maxCount)
399    {
400      // if it is the first Particle
401      if (unlikely(particles == NULL))
402        {
403          if (likely(deadList != NULL))
404            {
405              this->particles = this->deadList;
406              deadList = deadList->next;
407            }
408          else
409            {
410              PRINTF(5)("Generating new Particle\n");
411              this->particles = new Particle;
412            }
413          this->particles->next = NULL;
414        }
415      // filling the List from the beginning
416      else
417        {
418          Particle* tmpPart;
419          if (likely(deadList != NULL))
420            {
421              tmpPart = this->deadList;
422              deadList = deadList->next;
423            }
424          else
425            {
426              PRINTF(5)("Generating new Particle\n");
427              tmpPart = new Particle;
428            }
429          tmpPart->next = this->particles;
430          this->particles = tmpPart;
431        }
432     
433      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
434      particles->lifeCycle = 0.0;
435      particles->position = position;
436      particles->velocity = velocity;
437
438      //  particle->rotation = ; //! \todo rotation is once again something to be done.
439      particles->massRand = 2*(float)rand()/RAND_MAX -1;
440      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
441      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
442      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
443
444      ++this->count;
445    }
446  else
447    PRINTF(5)("maximum count of particles reached not adding any more\n");
448}
449
450/**
451   \brief outputs some nice debug information
452*/
453void ParticleSystem::debug(void)
454{
455  PRINT(0)("  ParticleSystem %s\n", this->name);
456  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
457  if (deadList)
458    {
459      PRINT(0)("  - ParticleDeadList is used: ");
460      int i = 1;
461      Particle* tmpPart = this->deadList;
462      while (tmpPart = tmpPart->next) ++i;
463      PRINT(0)("count: %d\n", i);
464    }
465}
Note: See TracBrowser for help on using the repository browser.