Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: small efficiency update

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