Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: more momentum implementation in particles

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
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 initial position, where the particle gets emitted.
488   \param velocity the initial velocity of the particle.
489   \param orientation the initial orientation of the Paritcle.
490   \param momentum the initial momentum of the Particle (the speed of its rotation).
491   \param data some more data given by the emitter
492*/
493void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, const Quaternion& orientation, const Quaternion& momentum, unsigned int data)
494{
495  if (this->count <= this->maxCount)
496    {
497      // if it is the first Particle
498      if (unlikely(particles == NULL))
499        {
500          if (likely(deadList != NULL))
501            {
502              this->particles = this->deadList;
503              deadList = deadList->next;
504            }
505          else
506            {
507              PRINTF(5)("Generating new Particle\n");
508              this->particles = new Particle;
509            }
510          this->particles->next = NULL;
511        }
512      // filling the List from the beginning
513      else
514        {
515          Particle* tmpPart;
516          if (likely(deadList != NULL))
517            {
518              tmpPart = this->deadList;
519              deadList = deadList->next;
520            }
521          else
522            {
523              PRINTF(5)("Generating new Particle\n");
524              tmpPart = new Particle;
525            }
526          tmpPart->next = this->particles;
527          this->particles = tmpPart;
528        }
529      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
530      particles->lifeCycle = 0.0;
531      particles->position = position;
532      particles->velocity = velocity;
533
534      particles->orientation = orientation;
535      particles->momentum = momentum;
536
537      //  particle->rotation = ; //! \todo rotation is once again something to be done.
538      particles->massRand = 2*(float)rand()/RAND_MAX -1;
539      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
540      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
541      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
542
543      ++this->count;
544    }
545  else
546    PRINTF(5)("maximum count of particles reached not adding any more\n");
547}
548
549/**
550   \brief outputs some nice debug information
551*/
552void ParticleSystem::debug(void)
553{
554  PRINT(0)("  ParticleSystem %s\n", this->getName());
555  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
556  if (deadList)
557    {
558      PRINT(0)("  - ParticleDeadList is used: ");
559      int i = 1;
560      Particle* tmpPart = this->deadList;
561      while (tmpPart = tmpPart->next) ++i;
562      PRINT(0)("count: %d\n", i);
563    }
564}
Note: See TracBrowser for help on using the repository browser.