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
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   ResourceManager::getInstance()->unload(this->model);
85}
86
87/**
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;
95  this->model = NULL;
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/**
131   \param particleType the type of particles in this System
132   \param count how many particles (in PARTICLE_MULTI-mode)
133   \todo this will be different
134*/
135void ParticleSystem::setType(PARTICLE_TYPE particleType, int count)
136{
137  this->particleType = particleType;
138  this->dialectCount = count;
139  //  if (glID != NULL)
140  //    delete glID;
141
142  //  glID = new GLuint[count];
143  //  for (int i = 0; i< count; i++)
144  //    glID[i] = 0;
145
146  //  glID[0] = glGenLists(count);
147  if (this->material)
148    delete this->material;
149  this->material = NULL;
150
151  switch (this->particleType)
152    {
153      case PARTICLE_SPRITE:
154        this->material = new Material("transperencyMap");
155        this->material->setDiffuseMap("pictures/radialTransparency.png");
156      //  material->setTransparency(.5);
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;
165    }
166}
167
168// setting properties
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*/
175void ParticleSystem::setMaterial(Material* material)
176{
177  this->material = material;
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    ResourceManager::getInstance()->unload(this->model);
188  if (modelName)
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  }
198}
199
200/**
201   \brief Sets the lifespan of newly created particles
202*/
203void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan)
204{
205  this->lifeSpan = lifeSpan;
206  this->randomLifeSpan = randomLifeSpan;
207}
208
209/**
210   \brief sets the conserve Factor of newly created particles
211*/
212void ParticleSystem::setConserve(float conserve)
213{
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;
220}
221
222/////////////////////////////
223/* Per-Particle Attributes */
224/////////////////////////////
225/**
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
230*/
231void ParticleSystem::setRadius(float lifeCycleTime, float radius, float randRadius)
232{
233  this->radiusAnim.changeEntry(lifeCycleTime, radius);
234  this->randRadiusAnim.changeEntry(lifeCycleTime, randRadius);
235}
236
237/**
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
242*/
243void ParticleSystem::setMass(float lifeCycleTime, float mass, float randMass)
244{
245  this->massAnim.changeEntry(lifeCycleTime, mass);
246  this->randMassAnim.changeEntry(lifeCycleTime, randMass);
247}
248
249/**
250   \brief sets a key in the color-animation on a per-particle basis
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
256*/
257void ParticleSystem::setColor(float lifeCycleTime, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
258{
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);
263}
264
265/**
266   \brief ticks the system.
267   \param dt the time to tick all the Particles of the System
268
269   this is used to get all the particles some motion
270*/
271void ParticleSystem::tick(float dt)
272{
273  Particle* tickPart = particles;  // the particle to Tick
274  Particle* prevPart = NULL;
275  while (likely(tickPart != NULL))
276    {
277      // applying force to the System.
278      if (likely (tickPart->mass > 0.0))
279        tickPart->velocity += tickPart->extForce / tickPart->mass * dt;
280      // rendering new position.
281      tickPart->position += tickPart->velocity * dt;
282      tickPart->orientation += tickPart->momentum *dt;
283
284      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
285        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
286
287      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
288        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
289
290      tickPart->extForce = Vector(0,0,0);
291
292      // applying Color
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
298      // many more to come
299
300      if (this->conserve < 1.0)
301      {
302        tickPart->velocity *= this->conserve;
303        tickPart->momentum *= this->conserve;
304      }
305      // find out if we have to delete tickPart
306      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
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        }
326      else
327        {
328          prevPart = tickPart;
329          tickPart = tickPart->next;
330        }
331    }
332}
333
334/**
335    \brief applies some force to a Particle.
336    \param field the Field to apply.
337 */
338void ParticleSystem::applyField(Field* field)
339{
340  Particle* tickPart = particles;
341  while (tickPart)
342    {
343      tickPart->extForce += field->calcForce(tickPart->position);
344      tickPart = tickPart->next;
345    }
346}
347
348
349/**
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/**
368   \brief draws all the Particles of this System
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.
373 */
374void ParticleSystem::draw(void) const
375{
376  glPushAttrib(GL_ENABLE_BIT);
377
378  Particle* drawPart = particles;
379
380  switch (this->particleType)
381  {
382    default:
383    case PARTICLE_SPRITE:
384      glDisable(GL_LIGHTING);
385      glMatrixMode(GL_MODELVIEW);
386      glDepthMask(GL_FALSE);
387
388      material->select();
389      //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
390
391
392      while (likely(drawPart != NULL))
393      {
394        glColor4fv(drawPart->color);
395          //! \todo implement a faster code for the look-at Camera algorithm.
396
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;
409
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);
427
428        glEnd();
429
430        drawPart = drawPart->next;
431      }
432      glDepthMask(GL_TRUE);
433      break;
434
435    case PARTICLE_SPARK:
436      glDisable(GL_LIGHTING);
437      glEnable(GL_LINE_SMOOTH);
438      glBegin(GL_LINES);
439      while (likely(drawPart != NULL))
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      }
448      glEnd();
449      break;
450
451    case PARTICLE_MODEL:
452      {
453        GLfloat matrix[4][4];
454
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);
467
468          this->model->draw();
469
470          glPopMatrix();
471          drawPart = drawPart->next;
472        }
473      }
474      break;
475
476    case PARTICLE_DOT:
477      glDisable(GL_LIGHTING);
478      glBegin(GL_POINTS);
479      while (likely(drawPart != NULL))
480      {
481        glColor4fv(drawPart->color);
482
483        glLineWidth(drawPart->radius);
484
485        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
486        drawPart = drawPart->next;
487      }
488      glEnd();
489      break;
490  }
491  glPopAttrib();
492}
493
494/**
495   \brief adds a new Particle to the System
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).
500   \param data some more data given by the emitter
501*/
502void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, const Quaternion& orientation, const Quaternion& momentum, unsigned int data)
503{
504  if (this->count <= this->maxCount)
505    {
506      // if it is the first Particle
507      if (unlikely(particles == NULL))
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        }
521      // filling the List from the beginning
522      else
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        }
538      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
539      particles->lifeCycle = 0.0;
540      particles->position = position;
541      particles->velocity = velocity;
542
543      particles->orientation = orientation;
544      particles->momentum = momentum;
545
546      //  particle->rotation = ; //! \todo rotation is once again something to be done.
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;
551
552      ++this->count;
553    }
554  else
555    PRINTF(5)("maximum count of particles reached not adding any more\n");
556}
557
558/**
559   \brief outputs some nice debug information
560*/
561void ParticleSystem::debug(void) const
562{
563  PRINT(0)("  ParticleSystem %s\n", this->getName());
564  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
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    }
573}
Note: See TracBrowser for help on using the repository browser.