Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4654 was 4654, checked in by bensch, 19 years ago

orxonox/trunk: speeded up the QuickAnimation-getValue-function.

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