Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: possibility to return the count of faces of some Object

File size: 15.5 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->position + tickPart->velocity * dt;
276      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
277        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
278
279      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
280        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
281
282      tickPart->extForce = Vector(0,0,0);
283
284      // applying Color
285      tickPart->color[0] = this->colorAnim[0].getValue(tickPart->lifeCycle);
286      tickPart->color[1] = this->colorAnim[1].getValue(tickPart->lifeCycle);
287      tickPart->color[2] = this->colorAnim[2].getValue(tickPart->lifeCycle);
288      tickPart->color[3] = this->colorAnim[3].getValue(tickPart->lifeCycle);
289
290      // many more to come
291
292      if (this->conserve < 1.0)
293        tickPart->velocity = tickPart->velocity * this->conserve;
294      // find out if we have to delete tickPart
295      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
296        {
297          // remove the particle from the list
298          if (likely(prevPart != NULL))
299            {
300              prevPart->next = tickPart->next;
301              tickPart->next = this->deadList;
302              this->deadList = tickPart;
303              tickPart = prevPart->next;
304            }
305          else
306            {
307              prevPart = NULL;
308              this->particles = tickPart->next;
309              tickPart->next = this->deadList;
310              this->deadList = tickPart;
311              tickPart = this->particles;
312            }
313          --this->count;
314        }
315      else
316        {
317          prevPart = tickPart;
318          tickPart = tickPart->next;
319        }
320    }
321}
322
323/**
324    \brief applies some force to a Particle.
325    \param field the Field to apply.
326 */
327void ParticleSystem::applyField(Field* field)
328{
329  Particle* tickPart = particles;
330  while (tickPart)
331    {
332      tickPart->extForce += field->calcForce(tickPart->position);
333      tickPart = tickPart->next;
334    }
335}
336
337
338/**
339 * \returns the count of Faces of this ParticleSystem
340 */
341unsigned int ParticleSystem::getFaceCount(void) const
342{
343  switch (this->particleType)
344  {
345    case PARTICLE_SPRITE:
346      return this->count;
347      break;
348    case PARTICLE_MODEL:
349      if (this->model)
350        return this->count * this->model->getFaceCount();
351      break;
352  }
353}
354
355
356/**
357   \brief draws all the Particles of this System
358
359   The Cases in this Function all do the same:
360   Drawing all the particles with the appropriate Type.
361   This is just the fastest Way to do this, but will most likely be changed in the future.
362 */
363void ParticleSystem::draw(void) const
364{
365  glPushAttrib(GL_ENABLE_BIT);
366
367  Particle* drawPart = particles;
368
369  switch (this->particleType)
370  {
371    default:
372    case PARTICLE_SPRITE:
373      glDisable(GL_LIGHTING);
374      glMatrixMode(GL_MODELVIEW);
375      glDepthMask(GL_FALSE);
376
377      material->select();
378      //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
379
380
381      while (likely(drawPart != NULL))
382      {
383        glColor4fv(drawPart->color);
384          //! \todo implement a faster code for the look-at Camera algorithm.
385
386        const PNode* camera = State::getInstance()->getCamera();  //!< \todo MUST be different
387        Vector cameraPos = camera->getAbsCoor();
388        Vector cameraTargetPos = State::getInstance()->getCameraTarget()->getAbsCoor();
389        Vector view = cameraTargetPos - cameraPos;
390        Vector up = Vector(0, 1, 0);
391        up = camera->getAbsDir().apply(up);
392        Vector h = up.cross(view);
393        Vector v = h.cross(view);
394        h.normalize();
395        v.normalize();
396        v *= .5 * drawPart->radius;
397        h *= .5 * drawPart->radius;
398
399        glBegin(GL_TRIANGLE_STRIP);
400        glTexCoord2i(1, 1);
401        glVertex3f(drawPart->position.x - h.x - v.x,
402                   drawPart->position.y - h.y - v.y,
403                   drawPart->position.z - h.z - v.z);
404        glTexCoord2i(0, 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(1, 0);
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(0, 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
417        glEnd();
418
419        drawPart = drawPart->next;
420      }
421      glDepthMask(GL_TRUE);
422      break;
423
424    case PARTICLE_SPARK:
425      glDisable(GL_LIGHTING);
426      glEnable(GL_LINE_SMOOTH);
427      glBegin(GL_LINES);
428      while (likely(drawPart != NULL))
429      {
430        glColor4fv(drawPart->color);
431        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
432        glVertex3f(drawPart->position.x - drawPart->velocity.x,
433                   drawPart->position.y - drawPart->velocity.y,
434                   drawPart->position.z - drawPart->velocity.z);
435        drawPart = drawPart->next;
436      }
437      glEnd();
438      break;
439
440    case PARTICLE_MODEL:
441      if (likely(this->model != NULL))
442        while (likely(drawPart != NULL))
443      {
444        glPushMatrix();
445        glMatrixMode(GL_MODELVIEW);
446
447        glTranslatef(drawPart->position.x, drawPart->position.y, drawPart->position.z);
448        glScalef(drawPart->radius, drawPart->radius, drawPart->radius);
449
450        this->model->draw();
451
452        glPopMatrix();
453        drawPart = drawPart->next;
454      }
455      break;
456
457    case PARTICLE_DOT:
458      glDisable(GL_LIGHTING);
459      glBegin(GL_POINTS);
460      while (likely(drawPart != NULL))
461      {
462        glColor4fv(drawPart->color);
463
464        glLineWidth(drawPart->radius);
465
466        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
467        drawPart = drawPart->next;
468      }
469      glEnd();
470      break;
471  }
472  glPopAttrib();
473}
474
475/**
476   \brief adds a new Particle to the System
477   \param position the position where the particle gets emitted.
478   \param velocity the Starting velocity of the particle.
479   \param data some more data given by the emitter
480*/
481void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, unsigned int data)
482{
483  if (this->count <= this->maxCount)
484    {
485      // if it is the first Particle
486      if (unlikely(particles == NULL))
487        {
488          if (likely(deadList != NULL))
489            {
490              this->particles = this->deadList;
491              deadList = deadList->next;
492            }
493          else
494            {
495              PRINTF(5)("Generating new Particle\n");
496              this->particles = new Particle;
497            }
498          this->particles->next = NULL;
499        }
500      // filling the List from the beginning
501      else
502        {
503          Particle* tmpPart;
504          if (likely(deadList != NULL))
505            {
506              tmpPart = this->deadList;
507              deadList = deadList->next;
508            }
509          else
510            {
511              PRINTF(5)("Generating new Particle\n");
512              tmpPart = new Particle;
513            }
514          tmpPart->next = this->particles;
515          this->particles = tmpPart;
516        }
517
518      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
519      particles->lifeCycle = 0.0;
520      particles->position = position;
521      particles->velocity = velocity;
522
523      //  particle->rotation = ; //! \todo rotation is once again something to be done.
524      particles->massRand = 2*(float)rand()/RAND_MAX -1;
525      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
526      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
527      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
528
529      ++this->count;
530    }
531  else
532    PRINTF(5)("maximum count of particles reached not adding any more\n");
533}
534
535/**
536   \brief outputs some nice debug information
537*/
538void ParticleSystem::debug(void)
539{
540  PRINT(0)("  ParticleSystem %s\n", this->getName());
541  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
542  if (deadList)
543    {
544      PRINT(0)("  - ParticleDeadList is used: ");
545      int i = 1;
546      Particle* tmpPart = this->deadList;
547      while (tmpPart = tmpPart->next) ++i;
548      PRINT(0)("count: %d\n", i);
549    }
550}
Note: See TracBrowser for help on using the repository browser.