Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: vulcan spy some Splinters

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