Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: load-params in particle-system (not finished yet)

File size: 14.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
29#include "tinyxml.h"
30
31using namespace std;
32
33/**
34   \brief standard constructor
35   \param maxCount the Count of particles in the System
36   \param type The Type of the ParticleSystem
37*/
38ParticleSystem::ParticleSystem (unsigned int maxCount, PARTICLE_TYPE type) : PhysicsInterface(this)
39{
40  this->init();
41
42  this->maxCount = maxCount;
43  this->setType(type, 1);
44}
45
46ParticleSystem::ParticleSystem(const TiXmlElement* root) : PhysicsInterface(this)
47{
48  this->init();
49  this->loadParams(root);
50}
51
52/**
53   \brief standard deconstructor
54*/
55ParticleSystem::~ParticleSystem()
56{
57  // delete what has to be deleted here
58   ParticleEngine::getInstance()->removeSystem(this);
59
60   // deleting all the living Particles
61   while (this->particles)
62     {
63       Particle* tmpDelPart = this->particles;
64       this->particles = this->particles->next;
65       delete tmpDelPart;
66     }
67
68   // deleting all the dead particles
69   while (this->deadList)
70     {
71       Particle* tmpDelPart = this->deadList;
72       this->deadList = this->deadList->next;
73       delete tmpDelPart;
74     }
75
76   if (this->material)
77     delete this->material;
78}
79
80/**
81  \brief initializes the ParticleSystem with default values
82*/
83void ParticleSystem::init(void)
84{
85  this->setClassID(CL_PARTICLE_SYSTEM, "ParticleSystem");
86
87  this->material = NULL;
88  this->maxCount = PARTICLE_DEFAULT_MAX_COUNT;
89  this->count = 0;
90  this->particles = NULL;
91  this->deadList = NULL;
92  this->setConserve(1);
93  this->setLifeSpan(1);
94  this->glID = NULL;
95  this->setType(PARTICLE_DEFAULT_TYPE, 1);
96  ParticleEngine::getInstance()->addSystem(this);
97}
98
99
100/**
101 * loads Parameters from a TiXmlElement
102 * @param root the XML-element to load from.
103 */
104void ParticleSystem::loadParams(const TiXmlElement* root)
105{
106  static_cast<WorldEntity*>(this)->loadParams(root);
107  static_cast<PhysicsInterface*>(this)->loadParams(root);
108
109  //LoadParam<ParticleSystem>(root, "type", this, &ParticleSystem::setType);
110  LoadParam<ParticleSystem>(root, "life-span", this, &ParticleSystem::setLifeSpan);
111  LoadParam<ParticleSystem>(root, "conserve", this, &ParticleSystem::setConserve);
112//   void setLifeSpan(float lifeSpan, float randomLifeSpan = 0.0);
113//   void setConserve(float conserve);
114//
115//   /* Per-Particle-Attributes */
116//   void setRadius(float lifeCycleTime, float radius, float randRadius = 0.0);
117//   void setMass(float lifeCycleTime, float mass, float randMass = 0.0);
118//   void setColor(float lifeCycleTime, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
119
120}
121
122/**
123   \param particleType the type of particles in this System
124   \param count how many particles (in PARTICLE_MULTI-mode)
125   \todo this will be different
126*/
127void ParticleSystem::setType(PARTICLE_TYPE particleType, int count)
128{
129  this->particleType = particleType;
130  this->dialectCount = count;
131  //  if (glID != NULL)
132  //    delete glID;
133
134  //  glID = new GLuint[count];
135  //  for (int i = 0; i< count; i++)
136  //    glID[i] = 0;
137
138  //  glID[0] = glGenLists(count);
139  if (this->material)
140    delete this->material;
141  this->material = NULL;
142
143  if (this->particleType == PARTICLE_SPRITE)
144    {
145      this->material = new Material("transperencyMap");
146      this->material->setDiffuseMap("pictures/radialTransparency.png");
147      //  material->setTransparency(.5);
148    }
149}
150
151// setting properties
152/**
153   \brief sets the material to an external material
154   \param material: the material to set this material to.
155
156   !! important if the extern material gets deleted it MUST be unregistered here or segfault !!
157*/
158void ParticleSystem::setMaterial(Material* material)
159{
160  this->material = material;
161}
162
163/**
164   \brief Sets the lifespan of newly created particles
165*/
166void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan)
167{
168  this->lifeSpan = lifeSpan;
169  this->randomLifeSpan = randomLifeSpan;
170}
171
172/**
173   \brief sets the conserve Factor of newly created particles
174*/
175void ParticleSystem::setConserve(float conserve)
176{
177  if (conserve > 1.0)
178    this->conserve = 1.0;
179  else if (conserve < 0.0)
180    this->conserve = 0.0;
181  else
182    this->conserve = conserve;
183}
184
185/////////////////////////////
186/* Per-Particle Attributes */
187/////////////////////////////
188/**
189   \brief sets a key in the radius-animation on a per-particle basis
190   \param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
191   \param radius the radius at this position
192   \param randRadius the randRadius at this position
193*/
194void ParticleSystem::setRadius(float lifeCycleTime, float radius, float randRadius)
195{
196  this->radiusAnim.addEntry(lifeCycleTime, radius);
197  this->randRadiusAnim.addEntry(lifeCycleTime, randRadius);
198}
199
200/**
201   \brief sets a key in the mass-animation on a per-particle basis
202   \param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
203   \param mass the mass at this position
204   \param randMass the randomMass at this position
205*/
206void ParticleSystem::setMass(float lifeCycleTime, float mass, float randMass)
207{
208  this->massAnim.addEntry(lifeCycleTime, mass);
209  this->randMassAnim.addEntry(lifeCycleTime, randMass);
210}
211
212/**
213   \brief sets a key in the color-animation on a per-particle basis
214   \param lifeCycleTime: the time (partilceLifeTime/particleAge) [0-1]
215   \param red: red
216   \param green: green
217   \param blue: blue
218   \param alpha: alpha
219*/
220void ParticleSystem::setColor(float lifeCycleTime, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
221{
222  this->colorAnim[0].addEntry(lifeCycleTime, red);
223  this->colorAnim[1].addEntry(lifeCycleTime, green);
224  this->colorAnim[2].addEntry(lifeCycleTime, blue);
225  this->colorAnim[3].addEntry(lifeCycleTime, alpha);
226}
227
228/**
229   \brief ticks the system.
230   \param dt the time to tick all the Particles of the System
231
232   this is used to get all the particles some motion
233*/
234void ParticleSystem::tick(float dt)
235{
236  Particle* tickPart = particles;  // the particle to Tick
237  Particle* prevPart = NULL;       //
238  while (likely(tickPart != NULL))
239    {
240      // applying force to the System.
241      if (likely (tickPart->mass > 0.0))
242        tickPart->velocity += tickPart->extForce / tickPart->mass * dt;
243
244      // rendering new position.
245      tickPart->position = tickPart->position + tickPart->velocity * dt;
246      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
247        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
248
249      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
250        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
251
252      tickPart->extForce = Vector(0,0,0);
253
254      // applying Color
255      tickPart->color[0] = this->colorAnim[0].getValue(tickPart->lifeCycle);
256      tickPart->color[1] = this->colorAnim[1].getValue(tickPart->lifeCycle);
257      tickPart->color[2] = this->colorAnim[2].getValue(tickPart->lifeCycle);
258      tickPart->color[3] = this->colorAnim[3].getValue(tickPart->lifeCycle);
259
260      // many more to come
261
262      if (this->conserve < 1.0)
263        tickPart->velocity = tickPart->velocity * this->conserve;
264      // find out if we have to delete tickPart
265      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
266        {
267          // remove the particle from the list
268          if (likely(prevPart != NULL))
269            {
270              prevPart->next = tickPart->next;
271              tickPart->next = this->deadList;
272              this->deadList = tickPart;
273              tickPart = prevPart->next;
274            }
275          else
276            {
277              prevPart = NULL;
278              this->particles = tickPart->next;
279              tickPart->next = this->deadList;
280              this->deadList = tickPart;
281              tickPart = this->particles;
282            }
283          --this->count;
284        }
285      else
286        {
287          prevPart = tickPart;
288          tickPart = tickPart->next;
289        }
290    }
291}
292
293/**
294    \brief applies some force to a Particle.
295    \param field the Field to apply.
296 */
297void ParticleSystem::applyField(Field* field)
298{
299  Particle* tickPart = particles;
300  while (tickPart)
301    {
302      tickPart->extForce += field->calcForce(tickPart->position);
303      tickPart = tickPart->next;
304    }
305}
306
307
308/**
309   \brief draws all the Particles of this System
310
311   The Cases in this Function all do the same:
312   Drawing all the particles with the appropriate Type.
313   This is just the fastest Way to do this, but will most likely be changed in the future.
314*/
315void ParticleSystem::draw(void) const
316{
317  glPushAttrib(GL_ENABLE_BIT);
318  glDisable(GL_LIGHTING);
319
320  Particle* drawPart = particles;
321
322  switch (this->particleType)
323    {
324    default:
325    case PARTICLE_SPRITE:
326      glMatrixMode(GL_MODELVIEW);
327      glDepthMask(GL_FALSE);
328
329      material->select();
330      //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
331
332
333      while (likely(drawPart != NULL))
334        {
335          glColor4fv(drawPart->color);
336          //! \todo implement a faster code for the look-at Camera algorithm.
337
338          const PNode* camera = State::getInstance()->getCamera();  //!< \todo MUST be different
339          Vector cameraPos = camera->getAbsCoor();
340          Vector cameraTargetPos = State::getInstance()->getCameraTarget()->getAbsCoor();
341          Vector view = cameraTargetPos - cameraPos;
342          Vector up = Vector(0, 1, 0);
343          up = camera->getAbsDir().apply(up);
344          Vector h = up.cross(view);
345          Vector v = h.cross(view);
346          h.normalize();
347          v.normalize();
348          v *= .5 * drawPart->radius;
349          h *= .5 * drawPart->radius;
350
351          glBegin(GL_TRIANGLE_STRIP);
352          glTexCoord2i(1, 1);
353          glVertex3f(drawPart->position.x - h.x - v.x,
354                     drawPart->position.y - h.y - v.y,
355                     drawPart->position.z - h.z - v.z);
356          glTexCoord2i(0, 1);
357          glVertex3f(drawPart->position.x - h.x + v.x,
358                     drawPart->position.y - h.y + v.y,
359                     drawPart->position.z - h.z + v.z);
360          glTexCoord2i(1, 0);
361          glVertex3f(drawPart->position.x + h.x - v.x,
362                     drawPart->position.y + h.y - v.y,
363                     drawPart->position.z + h.z - v.z);
364          glTexCoord2i(0, 0);
365          glVertex3f(drawPart->position.x + h.x + v.x,
366                     drawPart->position.y + h.y + v.y,
367                     drawPart->position.z + h.z + v.z);
368
369          glEnd();
370
371          drawPart = drawPart->next;
372        }
373      glDepthMask(GL_TRUE);
374      break;
375
376    case PARTICLE_SPARK:
377      glEnable(GL_LINE_SMOOTH);
378      glBegin(GL_LINES);
379      while (likely(drawPart != NULL))
380        {
381          glColor4fv(drawPart->color);
382          glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
383          glVertex3f(drawPart->position.x - drawPart->velocity.x,
384                     drawPart->position.y - drawPart->velocity.y,
385                     drawPart->position.z - drawPart->velocity.z);
386          drawPart = drawPart->next;
387        }
388      glEnd();
389      break;
390
391    case PARTICLE_DOT:
392      glBegin(GL_POINTS);
393      while (likely(drawPart != NULL))
394        {
395          glColor4fv(drawPart->color);
396
397          glLineWidth(drawPart->radius);
398
399          glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
400          drawPart = drawPart->next;
401        }
402      glEnd();
403      break;
404    }
405  glPopAttrib();
406}
407
408/**
409   \brief adds a new Particle to the System
410   \param position the position where the particle gets emitted.
411   \param velocity the Starting velocity of the particle.
412   \param data some more data given by the emitter
413*/
414void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, unsigned int data)
415{
416  if (this->count <= this->maxCount)
417    {
418      // if it is the first Particle
419      if (unlikely(particles == NULL))
420        {
421          if (likely(deadList != NULL))
422            {
423              this->particles = this->deadList;
424              deadList = deadList->next;
425            }
426          else
427            {
428              PRINTF(5)("Generating new Particle\n");
429              this->particles = new Particle;
430            }
431          this->particles->next = NULL;
432        }
433      // filling the List from the beginning
434      else
435        {
436          Particle* tmpPart;
437          if (likely(deadList != NULL))
438            {
439              tmpPart = this->deadList;
440              deadList = deadList->next;
441            }
442          else
443            {
444              PRINTF(5)("Generating new Particle\n");
445              tmpPart = new Particle;
446            }
447          tmpPart->next = this->particles;
448          this->particles = tmpPart;
449        }
450
451      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
452      particles->lifeCycle = 0.0;
453      particles->position = position;
454      particles->velocity = velocity;
455
456      //  particle->rotation = ; //! \todo rotation is once again something to be done.
457      particles->massRand = 2*(float)rand()/RAND_MAX -1;
458      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
459      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
460      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
461
462      ++this->count;
463    }
464  else
465    PRINTF(5)("maximum count of particles reached not adding any more\n");
466}
467
468/**
469   \brief outputs some nice debug information
470*/
471void ParticleSystem::debug(void)
472{
473  PRINT(0)("  ParticleSystem %s\n", this->getName());
474  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
475  if (deadList)
476    {
477      PRINT(0)("  - ParticleDeadList is used: ");
478      int i = 1;
479      Particle* tmpPart = this->deadList;
480      while (tmpPart = tmpPart->next) ++i;
481      PRINT(0)("count: %d\n", i);
482    }
483}
Note: See TracBrowser for help on using the repository browser.