Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: load-params in particle-system (not finished yet)

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