Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: sparkling vulkano: you have to shoot, to make the effect visible

File size: 16.4 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      glDepthMask(GL_FALSE);
438      //glEnable(GL_LINE_SMOOTH);
439      glEnable(GL_BLEND);
440
441      glBegin(GL_LINES);
442      while (likely(drawPart != NULL))
443      {
444        glColor4fv(drawPart->color);
445        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
446        glVertex3f(drawPart->position.x - drawPart->velocity.x * drawPart->radius,
447                   drawPart->position.y - drawPart->velocity.y * drawPart->radius,
448                   drawPart->position.z - drawPart->velocity.z * drawPart->radius);
449        drawPart = drawPart->next;
450      }
451      glEnd();
452      break;
453
454    case PARTICLE_MODEL:
455      {
456        GLfloat matrix[4][4];
457
458        if (likely(this->model != NULL))
459          while (likely(drawPart != NULL))
460        {
461          glPushMatrix();
462          glMatrixMode(GL_MODELVIEW);
463          /* move */
464          glTranslatef(drawPart->position.x, drawPart->position.y, drawPart->position.z);
465          /* scale */
466          glScalef(drawPart->radius, drawPart->radius, drawPart->radius);
467          /* rotate */
468          drawPart->orientation.matrix (matrix);
469          glMultMatrixf((float*)matrix);
470
471          this->model->draw();
472
473          glPopMatrix();
474          drawPart = drawPart->next;
475        }
476      }
477      break;
478
479    case PARTICLE_DOT:
480      glDisable(GL_LIGHTING);
481      glBegin(GL_POINTS);
482      while (likely(drawPart != NULL))
483      {
484        glColor4fv(drawPart->color);
485
486        glLineWidth(drawPart->radius);
487
488        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
489        drawPart = drawPart->next;
490      }
491      glEnd();
492      break;
493  }
494  glPopAttrib();
495}
496
497/**
498   \brief adds a new Particle to the System
499   \param position the initial position, where the particle gets emitted.
500   \param velocity the initial velocity of the particle.
501   \param orientation the initial orientation of the Paritcle.
502   \param momentum the initial momentum of the Particle (the speed of its rotation).
503   \param data some more data given by the emitter
504*/
505void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, const Quaternion& orientation, const Quaternion& momentum, unsigned int data)
506{
507  if (this->count <= this->maxCount)
508    {
509      // if it is the first Particle
510      if (unlikely(particles == NULL))
511        {
512          if (likely(deadList != NULL))
513            {
514              this->particles = this->deadList;
515              deadList = deadList->next;
516            }
517          else
518            {
519              PRINTF(5)("Generating new Particle\n");
520              this->particles = new Particle;
521            }
522          this->particles->next = NULL;
523        }
524      // filling the List from the beginning
525      else
526        {
527          Particle* tmpPart;
528          if (likely(deadList != NULL))
529            {
530              tmpPart = this->deadList;
531              deadList = deadList->next;
532            }
533          else
534            {
535              PRINTF(5)("Generating new Particle\n");
536              tmpPart = new Particle;
537            }
538          tmpPart->next = this->particles;
539          this->particles = tmpPart;
540        }
541      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
542      particles->lifeCycle = 0.0;
543      particles->position = position;
544      particles->velocity = velocity;
545
546      particles->orientation = orientation;
547      particles->momentum = momentum;
548
549      //  particle->rotation = ; //! \todo rotation is once again something to be done.
550      particles->massRand = 2*(float)rand()/RAND_MAX -1;
551      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
552      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
553      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
554
555      ++this->count;
556    }
557  else
558    PRINTF(5)("maximum count of particles reached not adding any more\n");
559}
560
561/**
562   \brief outputs some nice debug information
563*/
564void ParticleSystem::debug(void) const
565{
566  PRINT(0)("  ParticleSystem %s\n", this->getName());
567  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
568  if (deadList)
569    {
570      PRINT(0)("  - ParticleDeadList is used: ");
571      int i = 1;
572      Particle* tmpPart = this->deadList;
573      while (tmpPart = tmpPart->next) ++i;
574      PRINT(0)("count: %d\n", i);
575    }
576}
Note: See TracBrowser for help on using the repository browser.