Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/physics/src/lib/graphics/particles/particle_system.cc @ 4192

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

orxonox/branches/physics: reimplemented the lifeTime function of particles (a little bit slower, but much more efficient)
Color also implemented with the new TimeCode

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