Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: Particles now have a momentum and an orientation

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