Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: momentum works correct now (i think)

File size: 16.1 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#include "objModel.h"
29
30#include "tinyxml.h"
31
32using namespace std;
33
34/**
35   \brief standard constructor
36   \param maxCount the Count of particles in the System
37   \param type The Type of the ParticleSystem
38*/
39ParticleSystem::ParticleSystem (unsigned int maxCount, PARTICLE_TYPE type) : PhysicsInterface(this)
40{
41  this->init();
42
43  this->maxCount = maxCount;
44  this->setType(type, 1);
45}
46
47/**
48  \brief creates a Particle System out of a XML-element
49  \param root: the XML-element to load from
50 */
51ParticleSystem::ParticleSystem(const TiXmlElement* root) : PhysicsInterface(this)
52{
53  this->init();
54  this->loadParams(root);
55}
56
57/**
58   \brief standard deconstructor
59*/
60ParticleSystem::~ParticleSystem()
61{
62  // delete what has to be deleted here
63   ParticleEngine::getInstance()->removeSystem(this);
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     }
80
81   if (this->material)
82     delete this->material;
83}
84
85/**
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;
93  this->model = NULL;
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/**
129   \param particleType the type of particles in this System
130   \param count how many particles (in PARTICLE_MULTI-mode)
131   \todo this will be different
132*/
133void ParticleSystem::setType(PARTICLE_TYPE particleType, int count)
134{
135  this->particleType = particleType;
136  this->dialectCount = count;
137  //  if (glID != NULL)
138  //    delete glID;
139
140  //  glID = new GLuint[count];
141  //  for (int i = 0; i< count; i++)
142  //    glID[i] = 0;
143
144  //  glID[0] = glGenLists(count);
145  if (this->material)
146    delete this->material;
147  this->material = NULL;
148
149  switch (this->particleType)
150    {
151      case PARTICLE_SPRITE:
152        this->material = new Material("transperencyMap");
153        this->material->setDiffuseMap("pictures/radialTransparency.png");
154      //  material->setTransparency(.5);
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;
163    }
164}
165
166// setting properties
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*/
173void ParticleSystem::setMaterial(Material* material)
174{
175  this->material = material;
176}
177
178
179
180/**
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/**
194   \brief Sets the lifespan of newly created particles
195*/
196void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan)
197{
198  this->lifeSpan = lifeSpan;
199  this->randomLifeSpan = randomLifeSpan;
200}
201
202/**
203   \brief sets the conserve Factor of newly created particles
204*/
205void ParticleSystem::setConserve(float conserve)
206{
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;
213}
214
215/////////////////////////////
216/* Per-Particle Attributes */
217/////////////////////////////
218/**
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
223*/
224void ParticleSystem::setRadius(float lifeCycleTime, float radius, float randRadius)
225{
226  this->radiusAnim.changeEntry(lifeCycleTime, radius);
227  this->randRadiusAnim.changeEntry(lifeCycleTime, randRadius);
228}
229
230/**
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
235*/
236void ParticleSystem::setMass(float lifeCycleTime, float mass, float randMass)
237{
238  this->massAnim.changeEntry(lifeCycleTime, mass);
239  this->randMassAnim.changeEntry(lifeCycleTime, randMass);
240}
241
242/**
243   \brief sets a key in the color-animation on a per-particle basis
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
249*/
250void ParticleSystem::setColor(float lifeCycleTime, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
251{
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);
256}
257
258/**
259   \brief ticks the system.
260   \param dt the time to tick all the Particles of the System
261
262   this is used to get all the particles some motion
263*/
264void ParticleSystem::tick(float dt)
265{
266  Particle* tickPart = particles;  // the particle to Tick
267  Particle* prevPart = NULL;       //
268  while (likely(tickPart != NULL))
269    {
270      // applying force to the System.
271      if (likely (tickPart->mass > 0.0))
272        tickPart->velocity += tickPart->extForce / tickPart->mass * dt;
273      // rendering new position.
274      tickPart->position += tickPart->velocity * dt;
275      tickPart->orientation += tickPart->momentum *dt;
276
277      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
278        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
279
280      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
281        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
282
283      tickPart->extForce = Vector(0,0,0);
284
285      // applying Color
286      tickPart->color[0] = this->colorAnim[0].getValue(tickPart->lifeCycle);
287      tickPart->color[1] = this->colorAnim[1].getValue(tickPart->lifeCycle);
288      tickPart->color[2] = this->colorAnim[2].getValue(tickPart->lifeCycle);
289      tickPart->color[3] = this->colorAnim[3].getValue(tickPart->lifeCycle);
290
291      // many more to come
292
293      if (this->conserve < 1.0)
294      {
295        tickPart->velocity *= this->conserve;
296        tickPart->momentum *= this->conserve;
297      }
298      // find out if we have to delete tickPart
299      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
300        {
301          // remove the particle from the list
302          if (likely(prevPart != NULL))
303            {
304              prevPart->next = tickPart->next;
305              tickPart->next = this->deadList;
306              this->deadList = tickPart;
307              tickPart = prevPart->next;
308            }
309          else
310            {
311              prevPart = NULL;
312              this->particles = tickPart->next;
313              tickPart->next = this->deadList;
314              this->deadList = tickPart;
315              tickPart = this->particles;
316            }
317          --this->count;
318        }
319      else
320        {
321          prevPart = tickPart;
322          tickPart = tickPart->next;
323        }
324    }
325}
326
327/**
328    \brief applies some force to a Particle.
329    \param field the Field to apply.
330 */
331void ParticleSystem::applyField(Field* field)
332{
333  Particle* tickPart = particles;
334  while (tickPart)
335    {
336      tickPart->extForce += field->calcForce(tickPart->position);
337      tickPart = tickPart->next;
338    }
339}
340
341
342/**
343 * \returns the count of Faces of this ParticleSystem
344 */
345unsigned int ParticleSystem::getFaceCount(void) const
346{
347  switch (this->particleType)
348  {
349    case PARTICLE_SPRITE:
350      return this->count;
351      break;
352    case PARTICLE_MODEL:
353      if (this->model)
354        return this->count * this->model->getFaceCount();
355      break;
356  }
357}
358
359
360/**
361   \brief draws all the Particles of this System
362
363   The Cases in this Function all do the same:
364   Drawing all the particles with the appropriate Type.
365   This is just the fastest Way to do this, but will most likely be changed in the future.
366 */
367void ParticleSystem::draw(void) const
368{
369  glPushAttrib(GL_ENABLE_BIT);
370
371  Particle* drawPart = particles;
372
373  switch (this->particleType)
374  {
375    default:
376    case PARTICLE_SPRITE:
377      glDisable(GL_LIGHTING);
378      glMatrixMode(GL_MODELVIEW);
379      glDepthMask(GL_FALSE);
380
381      material->select();
382      //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
383
384
385      while (likely(drawPart != NULL))
386      {
387        glColor4fv(drawPart->color);
388          //! \todo implement a faster code for the look-at Camera algorithm.
389
390        const PNode* camera = State::getInstance()->getCamera();  //!< \todo MUST be different
391        Vector cameraPos = camera->getAbsCoor();
392        Vector cameraTargetPos = State::getInstance()->getCameraTarget()->getAbsCoor();
393        Vector view = cameraTargetPos - cameraPos;
394        Vector up = Vector(0, 1, 0);
395        up = camera->getAbsDir().apply(up);
396        Vector h = up.cross(view);
397        Vector v = h.cross(view);
398        h.normalize();
399        v.normalize();
400        v *= .5 * drawPart->radius;
401        h *= .5 * drawPart->radius;
402
403        glBegin(GL_TRIANGLE_STRIP);
404        glTexCoord2i(1, 1);
405        glVertex3f(drawPart->position.x - h.x - v.x,
406                   drawPart->position.y - h.y - v.y,
407                   drawPart->position.z - h.z - v.z);
408        glTexCoord2i(0, 1);
409        glVertex3f(drawPart->position.x - h.x + v.x,
410                   drawPart->position.y - h.y + v.y,
411                   drawPart->position.z - h.z + v.z);
412        glTexCoord2i(1, 0);
413        glVertex3f(drawPart->position.x + h.x - v.x,
414                   drawPart->position.y + h.y - v.y,
415                   drawPart->position.z + h.z - v.z);
416        glTexCoord2i(0, 0);
417        glVertex3f(drawPart->position.x + h.x + v.x,
418                   drawPart->position.y + h.y + v.y,
419                   drawPart->position.z + h.z + v.z);
420
421        glEnd();
422
423        drawPart = drawPart->next;
424      }
425      glDepthMask(GL_TRUE);
426      break;
427
428    case PARTICLE_SPARK:
429      glDisable(GL_LIGHTING);
430      glEnable(GL_LINE_SMOOTH);
431      glBegin(GL_LINES);
432      while (likely(drawPart != NULL))
433      {
434        glColor4fv(drawPart->color);
435        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
436        glVertex3f(drawPart->position.x - drawPart->velocity.x,
437                   drawPart->position.y - drawPart->velocity.y,
438                   drawPart->position.z - drawPart->velocity.z);
439        drawPart = drawPart->next;
440      }
441      glEnd();
442      break;
443
444    case PARTICLE_MODEL:
445      {
446        GLfloat matrix[4][4];
447
448        if (likely(this->model != NULL))
449          while (likely(drawPart != NULL))
450        {
451          glPushMatrix();
452          glMatrixMode(GL_MODELVIEW);
453          /* move */
454          glTranslatef(drawPart->position.x, drawPart->position.y, drawPart->position.z);
455          /* scale */
456          glScalef(drawPart->radius, drawPart->radius, drawPart->radius);
457          /* rotate */
458          drawPart->orientation.matrix (matrix);
459          glMultMatrixf((float*)matrix);
460
461          this->model->draw();
462
463          glPopMatrix();
464          drawPart = drawPart->next;
465        }
466      }
467      break;
468
469    case PARTICLE_DOT:
470      glDisable(GL_LIGHTING);
471      glBegin(GL_POINTS);
472      while (likely(drawPart != NULL))
473      {
474        glColor4fv(drawPart->color);
475
476        glLineWidth(drawPart->radius);
477
478        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
479        drawPart = drawPart->next;
480      }
481      glEnd();
482      break;
483  }
484  glPopAttrib();
485}
486
487/**
488   \brief adds a new Particle to the System
489   \param position the initial position, where the particle gets emitted.
490   \param velocity the initial velocity of the particle.
491   \param orientation the initial orientation of the Paritcle.
492   \param momentum the initial momentum of the Particle (the speed of its rotation).
493   \param data some more data given by the emitter
494*/
495void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, const Quaternion& orientation, const Quaternion& momentum, unsigned int data)
496{
497  if (this->count <= this->maxCount)
498    {
499      // if it is the first Particle
500      if (unlikely(particles == NULL))
501        {
502          if (likely(deadList != NULL))
503            {
504              this->particles = this->deadList;
505              deadList = deadList->next;
506            }
507          else
508            {
509              PRINTF(5)("Generating new Particle\n");
510              this->particles = new Particle;
511            }
512          this->particles->next = NULL;
513        }
514      // filling the List from the beginning
515      else
516        {
517          Particle* tmpPart;
518          if (likely(deadList != NULL))
519            {
520              tmpPart = this->deadList;
521              deadList = deadList->next;
522            }
523          else
524            {
525              PRINTF(5)("Generating new Particle\n");
526              tmpPart = new Particle;
527            }
528          tmpPart->next = this->particles;
529          this->particles = tmpPart;
530        }
531      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
532      particles->lifeCycle = 0.0;
533      particles->position = position;
534      particles->velocity = velocity;
535
536      particles->orientation = orientation;
537      particles->momentum = momentum;
538
539      //  particle->rotation = ; //! \todo rotation is once again something to be done.
540      particles->massRand = 2*(float)rand()/RAND_MAX -1;
541      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
542      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
543      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
544
545      ++this->count;
546    }
547  else
548    PRINTF(5)("maximum count of particles reached not adding any more\n");
549}
550
551/**
552   \brief outputs some nice debug information
553*/
554void ParticleSystem::debug(void) const
555{
556  PRINT(0)("  ParticleSystem %s\n", this->getName());
557  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
558  if (deadList)
559    {
560      PRINT(0)("  - ParticleDeadList is used: ");
561      int i = 1;
562      Particle* tmpPart = this->deadList;
563      while (tmpPart = tmpPart->next) ++i;
564      PRINT(0)("count: %d\n", i);
565    }
566}
Note: See TracBrowser for help on using the repository browser.