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
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
274      // rendering new position.
275      tickPart->position += tickPart->velocity * dt;
276      tickPart->orientation += tickPart->momentum *dt;
277
278      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
279        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
280
281      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
282        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
283
284      tickPart->extForce = Vector(0,0,0);
285
286      // applying Color
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
292      // many more to come
293
294      if (this->conserve < 1.0)
295        tickPart->velocity = tickPart->velocity * this->conserve;
296      // find out if we have to delete tickPart
297      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
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        }
317      else
318        {
319          prevPart = tickPart;
320          tickPart = tickPart->next;
321        }
322    }
323}
324
325/**
326    \brief applies some force to a Particle.
327    \param field the Field to apply.
328 */
329void ParticleSystem::applyField(Field* field)
330{
331  Particle* tickPart = particles;
332  while (tickPart)
333    {
334      tickPart->extForce += field->calcForce(tickPart->position);
335      tickPart = tickPart->next;
336    }
337}
338
339
340/**
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/**
359   \brief draws all the Particles of this System
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.
364 */
365void ParticleSystem::draw(void) const
366{
367  glPushAttrib(GL_ENABLE_BIT);
368
369  Particle* drawPart = particles;
370
371  switch (this->particleType)
372  {
373    default:
374    case PARTICLE_SPRITE:
375      glDisable(GL_LIGHTING);
376      glMatrixMode(GL_MODELVIEW);
377      glDepthMask(GL_FALSE);
378
379      material->select();
380      //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
381
382
383      while (likely(drawPart != NULL))
384      {
385        glColor4fv(drawPart->color);
386          //! \todo implement a faster code for the look-at Camera algorithm.
387
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;
400
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);
418
419        glEnd();
420
421        drawPart = drawPart->next;
422      }
423      glDepthMask(GL_TRUE);
424      break;
425
426    case PARTICLE_SPARK:
427      glDisable(GL_LIGHTING);
428      glEnable(GL_LINE_SMOOTH);
429      glBegin(GL_LINES);
430      while (likely(drawPart != NULL))
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      }
439      glEnd();
440      break;
441
442    case PARTICLE_MODEL:
443      {
444        GLfloat matrix[4][4];
445
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);
458
459          this->model->draw();
460
461          glPopMatrix();
462          drawPart = drawPart->next;
463        }
464      }
465      break;
466
467    case PARTICLE_DOT:
468      glDisable(GL_LIGHTING);
469      glBegin(GL_POINTS);
470      while (likely(drawPart != NULL))
471      {
472        glColor4fv(drawPart->color);
473
474        glLineWidth(drawPart->radius);
475
476        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
477        drawPart = drawPart->next;
478      }
479      glEnd();
480      break;
481  }
482  glPopAttrib();
483}
484
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*/
491void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, unsigned int data)
492{
493  if (this->count <= this->maxCount)
494    {
495      // if it is the first Particle
496      if (unlikely(particles == NULL))
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        }
510      // filling the List from the beginning
511      else
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        }
527      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
528      particles->lifeCycle = 0.0;
529      particles->position = position;
530      particles->velocity = velocity;
531
532      particles->orientation = Quaternion(.4, velocity.getNormalized());
533      particles->momentum = Quaternion(.4, velocity.getNormalized());
534
535      //  particle->rotation = ; //! \todo rotation is once again something to be done.
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;
540
541      ++this->count;
542    }
543  else
544    PRINTF(5)("maximum count of particles reached not adding any more\n");
545}
546
547/**
548   \brief outputs some nice debug information
549*/
550void ParticleSystem::debug(void)
551{
552  PRINT(0)("  ParticleSystem %s\n", this->getName());
553  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
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    }
562}
Note: See TracBrowser for help on using the repository browser.