Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6623 was 6623, checked in by bensch, 18 years ago

orxonox/trunk: particle Systems and Emitters are loaded and cleaned up nicely

File size: 14.3 KB
RevLine 
[4597]1/*
[1853]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.
[1855]10
11   ### File Specific:
[3925]12   main-programmer: Benjamin Grauer
[1855]13   co-programmer: ...
[1853]14*/
15
[5357]16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_GRAPHICS
[1853]17
[3925]18#include "particle_system.h"
[1853]19
[3930]20#include "particle_emitter.h"
[4338]21
22#include "field.h"
[5511]23#include "model.h"
[4338]24
[5155]25#include "load_param.h"
[5652]26#include "factory.h"
[3942]27#include "material.h"
[4338]28#include "state.h"
[5446]29#include "shell_command.h"
[3930]30
[5944]31#include "parser/tinyxml/tinyxml.h"
[6612]32#include <algorithm>
[4338]33
[1856]34using namespace std;
[1853]35
[3245]36/**
[4836]37 *  standard constructor
38 * @param maxCount the Count of particles in the System
39 * @param type The Type of the ParticleSystem
[3245]40*/
[6621]41ParticleSystem::ParticleSystem (unsigned int maxCount)
[3365]42{
[4602]43  this->init();
[4597]44
[4727]45  this->setMaxCount(maxCount);
[3365]46}
[1853]47
[4677]48/**
[4836]49 *  standard deconstructor
[3245]50*/
[4176]51ParticleSystem::~ParticleSystem()
[3543]52{
[4123]53   // deleting all the living Particles
54   while (this->particles)
55     {
56       Particle* tmpDelPart = this->particles;
57       this->particles = this->particles->next;
58       delete tmpDelPart;
59     }
60
61   // deleting all the dead particles
62   while (this->deadList)
63     {
64       Particle* tmpDelPart = this->deadList;
65       this->deadList = this->deadList->next;
66       delete tmpDelPart;
67     }
[4176]68
[6623]69     while(!this->emitters.empty())
70     {
71       this->removeEmitter(this->emitters.front());
72     }
73
[3543]74}
[1853]75
[3945]76/**
[4602]77  \brief initializes the ParticleSystem with default values
78*/
[4746]79void ParticleSystem::init()
[4602]80{
81  this->setClassID(CL_PARTICLE_SYSTEM, "ParticleSystem");
82
[4727]83  this->setMaxCount(PARTICLE_DEFAULT_MAX_COUNT);
[4602]84  this->count = 0;
85  this->particles = NULL;
86  this->deadList = NULL;
87  this->setConserve(1);
88  this->setLifeSpan(1);
[6612]89
90  this->toList(OM_ENVIRON);
[4602]91}
92
93
94/**
95 * loads Parameters from a TiXmlElement
96 * @param root the XML-element to load from.
97 */
98void ParticleSystem::loadParams(const TiXmlElement* root)
99{
[6512]100  WorldEntity::loadParams(root);
101  PhysicsInterface::loadParams(root);
[4602]102
[5671]103  LoadParam(root, "max-count", this, ParticleSystem, setMaxCount)
[4727]104      .describe("the maximal count of Particles, that can be emitted into this system");
105
[5671]106  LoadParam(root, "life-span", this, ParticleSystem, setLifeSpan)
[4725]107      .describe("sets the life-span of the Particles.");
[4602]108
[5671]109  LoadParam(root, "conserve", this, ParticleSystem, setConserve)
[5652]110      .describe("sets the Conserve factor of the Particles (1.0: they keep all their energy, 0.0:they keep no energy)");
[4725]111
[6623]112  LoadParamXML(root, "emitters", this, ParticleSystem, loadEmitters);
[6222]113
[5654]114  LOAD_PARAM_START_CYCLE(root, element);
[4727]115  {
[5654]116    element->ToText();
[4725]117  // PER-PARTICLE-ATTRIBUTES:
[5654]118    LoadParam_CYCLE(element, "radius", this, ParticleSystem, setRadius)
[4727]119        .describe("The Radius of each particle over time (TimeIndex [0-1], radius at TimeIndex, randomRadius at TimeIndex)");
[4725]120
[5654]121    LoadParam_CYCLE(element, "mass", this, ParticleSystem, setMass)
[4727]122        .describe("The Mass of each particle over time (TimeIndex: [0-1], mass at TimeIndex, randomMass at TimeIndex)");
[4725]123
[5654]124    LoadParam_CYCLE(element, "color", this, ParticleSystem, setColor)
[4727]125        .describe("The Color of each particle over time (TimeIndex: [0-1], red: [0-1], green: [0-1], blue: [0-1], alpha: [0-1])");
126  }
[5654]127  LOAD_PARAM_END_CYCLE(element);
[4602]128}
[4727]129
[4725]130/**
[6623]131 * @brief loads the Emitters from An XML-Root
132 * @param root the XML-Element to load all emitters from
133 */
134void ParticleSystem::loadEmitters(const TiXmlElement* root)
135{
136  LOAD_PARAM_START_CYCLE(root, element);
137  {
138    BaseObject* emitter = Factory::fabricate(element);
139    if (emitter->isA(CL_PARTICLE_EMITTER))
140      this->addEmitter(dynamic_cast<ParticleEmitter*>(emitter));
141    else
142    {
143      PRINTF(2)("Tried to load an Element of type '%s' that should be a ParticleEmitter onto '%s::%s'.\n",
144                emitter->getClassName(), this->getClassName(), this->getName());
145      delete emitter;
146    }
147  }
148  LOAD_PARAM_END_CYCLE(element);
149}
150
151/**
[4836]152* @param maxCount the maximum count of particles that can be emitted
[4727]153 */
154void ParticleSystem::setMaxCount(int maxCount)
155{
156  this->maxCount = maxCount;
157}
158
[3932]159// setting properties
[4478]160/**
[4836]161 *  Sets the lifespan of newly created particles
[4597]162*/
[3932]163void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan)
164{
[3934]165  this->lifeSpan = lifeSpan;
166  this->randomLifeSpan = randomLifeSpan;
[3932]167}
168
[3945]169/**
[4836]170 *  sets the conserve Factor of newly created particles
[3945]171*/
[4430]172void ParticleSystem::setConserve(float conserve)
[3932]173{
[4430]174  if (conserve > 1.0)
175    this->conserve = 1.0;
176  else if (conserve < 0.0)
177    this->conserve = 0.0;
178  else
179    this->conserve = conserve;
[3932]180}
181
[4430]182/////////////////////////////
183/* Per-Particle Attributes */
184/////////////////////////////
[3945]185/**
[4836]186 *  sets a key in the radius-animation on a per-particle basis
187 * @param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
188 * @param radius the radius at this position
189 * @param randRadius the randRadius at this position
[4378]190*/
[4430]191void ParticleSystem::setRadius(float lifeCycleTime, float radius, float randRadius)
[4378]192{
[4649]193  this->radiusAnim.changeEntry(lifeCycleTime, radius);
194  this->randRadiusAnim.changeEntry(lifeCycleTime, randRadius);
[4378]195}
196
197/**
[4836]198 *  sets a key in the mass-animation on a per-particle basis
199 * @param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
200 * @param mass the mass at this position
201 * @param randMass the randomMass at this position
[3945]202*/
[4430]203void ParticleSystem::setMass(float lifeCycleTime, float mass, float randMass)
[3932]204{
[4649]205  this->massAnim.changeEntry(lifeCycleTime, mass);
206  this->randMassAnim.changeEntry(lifeCycleTime, randMass);
[3932]207}
208
[3945]209/**
[4836]210 *  sets a key in the color-animation on a per-particle basis
211 * @param lifeCycleTime: the time (partilceLifeTime/particleAge) [0-1]
212 * @param red: red
213 * @param green: green
214 * @param blue: blue
215 * @param alpha: alpha
[4338]216*/
[4725]217void ParticleSystem::setColor(float lifeCycleTime, float red, float green, float blue, float alpha)
[4338]218{
[4649]219  this->colorAnim[0].changeEntry(lifeCycleTime, red);
220  this->colorAnim[1].changeEntry(lifeCycleTime, green);
221  this->colorAnim[2].changeEntry(lifeCycleTime, blue);
222  this->colorAnim[3].changeEntry(lifeCycleTime, alpha);
[4338]223}
224
[6612]225
226void ParticleSystem::addEmitter(ParticleEmitter* emitter)
227{
[6619]228  assert (emitter != NULL);
229  if (emitter->getSystem() != NULL)
230    emitter->getSystem()->removeEmitter(emitter);
[6612]231  this->emitters.push_back(emitter);
232}
233
234
235void ParticleSystem::removeEmitter(ParticleEmitter* emitter)
236{
237  std::list<ParticleEmitter*>::iterator it = std::find(this->emitters.begin(), this->emitters.end(), emitter);
238  if (it != this->emitters.end())
239    this->emitters.erase(it);
240}
241
[4338]242/**
[4836]243 *  ticks the system.
244 * @param dt the time to tick all the Particles of the System
[3932]245
[3945]246   this is used to get all the particles some motion
247*/
[3931]248void ParticleSystem::tick(float dt)
249{
[3934]250  Particle* tickPart = particles;  // the particle to Tick
[4692]251  Particle* prevPart = NULL;
[3934]252  while (likely(tickPart != NULL))
[3932]253    {
[4378]254      // applying force to the System.
[4385]255      if (likely (tickPart->mass > 0.0))
[4597]256        tickPart->velocity += tickPart->extForce / tickPart->mass * dt;
[4378]257      // rendering new position.
[4687]258      tickPart->position += tickPart->velocity * dt;
259      tickPart->orientation += tickPart->momentum *dt;
260
[4434]261      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
[4597]262        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
[4434]263
264      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
[4597]265        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
266
[4338]267      tickPart->extForce = Vector(0,0,0);
268
269      // applying Color
[4431]270      tickPart->color[0] = this->colorAnim[0].getValue(tickPart->lifeCycle);
271      tickPart->color[1] = this->colorAnim[1].getValue(tickPart->lifeCycle);
272      tickPart->color[2] = this->colorAnim[2].getValue(tickPart->lifeCycle);
273      tickPart->color[3] = this->colorAnim[3].getValue(tickPart->lifeCycle);
274
[3932]275      // many more to come
276
[3935]277      if (this->conserve < 1.0)
[4691]278      {
279        tickPart->velocity *= this->conserve;
280        tickPart->momentum *= this->conserve;
281      }
[3934]282      // find out if we have to delete tickPart
[4385]283      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
[4597]284        {
285          // remove the particle from the list
286          if (likely(prevPart != NULL))
287            {
288              prevPart->next = tickPart->next;
289              tickPart->next = this->deadList;
290              this->deadList = tickPart;
291              tickPart = prevPart->next;
292            }
293          else
294            {
295              prevPart = NULL;
296              this->particles = tickPart->next;
297              tickPart->next = this->deadList;
298              this->deadList = tickPart;
299              tickPart = this->particles;
300            }
301          --this->count;
302        }
[3934]303      else
[4597]304        {
305          prevPart = tickPart;
306          tickPart = tickPart->next;
307        }
[3932]308    }
[6612]309
310    std::list<ParticleEmitter*>::iterator emitter;
311    for (emitter = this->emitters.begin(); emitter != this->emitters.end(); emitter++)
[6620]312      (*emitter)->tick(dt);
[3932]313}
314
[4597]315/**
[4836]316  *  applies some force to a Particle.
317  * @param field the Field to apply.
[4338]318 */
[4395]319void ParticleSystem::applyField(Field* field)
[4338]320{
321  Particle* tickPart = particles;
322  while (tickPart)
323    {
[4395]324      tickPart->extForce += field->calcForce(tickPart->position);
[4338]325      tickPart = tickPart->next;
326    }
327}
328
329
[3945]330/**
[4836]331 * @returns the count of Faces of this ParticleSystem
[4677]332 */
[4746]333unsigned int ParticleSystem::getFaceCount() const
[4677]334{
[6621]335  return this->count;
[4677]336}
337
338
339/**
[4836]340 *  draws all the Particles of this System
[4338]341
342   The Cases in this Function all do the same:
343   Drawing all the particles with the appropriate Type.
344   This is just the fastest Way to do this, but will most likely be changed in the future.
[4663]345 */
[6621]346// void ParticleSystem::draw() const
347// {
348//   glPushAttrib(GL_ENABLE_BIT);
349//
350//   Particle* drawPart = particles;
351//
352//   switch (this->particleType)
353//   {
354//     case PARTICLE_SPARK:
355//       glDisable(GL_LIGHTING);
356//       glDepthMask(GL_FALSE);
357//       //glEnable(GL_LINE_SMOOTH);
358//       glEnable(GL_BLEND);
359//
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 * drawPart->radius,
366//                    drawPart->position.y - drawPart->velocity.y * drawPart->radius,
367//                    drawPart->position.z - drawPart->velocity.z * drawPart->radius);
368//         drawPart = drawPart->next;
369//       }
370//       glEnd();
371//       break;
372//
373//     case PARTICLE_MODEL:
374//       {
375//         GLfloat matrix[4][4];
376//
377//         if (likely(this->getModel() != NULL))
378//           while (likely(drawPart != NULL))
379//         {
380//           glPushMatrix();
381//           glMatrixMode(GL_MODELVIEW);
382//           /* move */
383//           glTranslatef(drawPart->position.x, drawPart->position.y, drawPart->position.z);
384//           /* scale */
385//           glScalef(drawPart->radius, drawPart->radius, drawPart->radius);
386//           /* rotate */
387//           drawPart->orientation.matrix (matrix);
388//           glMultMatrixf((float*)matrix);
389//
390//           this->getModel()->draw();
391//
392//           glPopMatrix();
393//           drawPart = drawPart->next;
394//         }
395//         else
396//           PRINTF(2)("no model loaded onto ParticleSystem-%s\n", this->getName());
397//       }
398//       break;
399//
400//     case PARTICLE_DOT:
401//       glDisable(GL_LIGHTING);
402//       glBegin(GL_POINTS);
403//       while (likely(drawPart != NULL))
404//       {
405//         glColor4fv(drawPart->color);
406//
407//         glLineWidth(drawPart->radius);
408//
409//         glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
410//         drawPart = drawPart->next;
411//       }
412//       glEnd();
413//       break;
414//   }
415//   glPopAttrib();
416// }
[4338]417
[3945]418/**
[4836]419 *  adds a new Particle to the System
420 * @param position the initial position, where the particle gets emitted.
421 * @param velocity the initial velocity of the particle.
422 * @param orientation the initial orientation of the Paritcle.
423 * @param momentum the initial momentum of the Particle (the speed of its rotation).
424 * @param data some more data given by the emitter
[3945]425*/
[4690]426void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, const Quaternion& orientation, const Quaternion& momentum, unsigned int data)
[3932]427{
[3934]428  if (this->count <= this->maxCount)
[3932]429    {
[3934]430      // if it is the first Particle
431      if (unlikely(particles == NULL))
[4597]432        {
433          if (likely(deadList != NULL))
434            {
435              this->particles = this->deadList;
436              deadList = deadList->next;
437            }
438          else
439            {
440              PRINTF(5)("Generating new Particle\n");
441              this->particles = new Particle;
442            }
443          this->particles->next = NULL;
444        }
[3934]445      // filling the List from the beginning
446      else
[4597]447        {
448          Particle* tmpPart;
449          if (likely(deadList != NULL))
450            {
451              tmpPart = this->deadList;
452              deadList = deadList->next;
453            }
454          else
455            {
456              PRINTF(5)("Generating new Particle\n");
457              tmpPart = new Particle;
458            }
459          tmpPart->next = this->particles;
460          this->particles = tmpPart;
461        }
[4338]462      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
463      particles->lifeCycle = 0.0;
[3934]464      particles->position = position;
465      particles->velocity = velocity;
[3951]466
[4690]467      particles->orientation = orientation;
468      particles->momentum = momentum;
[4687]469
[4836]470      //  particle->rotation = ; //! @todo rotation is once again something to be done.
[4434]471      particles->massRand = 2*(float)rand()/RAND_MAX -1;
472      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
473      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
474      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
[3934]475
476      ++this->count;
[3932]477    }
478  else
[4017]479    PRINTF(5)("maximum count of particles reached not adding any more\n");
[3932]480}
[3931]481
[3944]482/**
[4836]483 *  outputs some nice debug information
[3944]484*/
[4746]485void ParticleSystem::debug() const
[3944]486{
487  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
[4123]488  if (deadList)
489    {
490      PRINT(0)("  - ParticleDeadList is used: ");
491      int i = 1;
492      Particle* tmpPart = this->deadList;
493      while (tmpPart = tmpPart->next) ++i;
494      PRINT(0)("count: %d\n", i);
495    }
[3944]496}
Note: See TracBrowser for help on using the repository browser.