Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: lifetime-animation works now via the quickAnimation (only for radius)

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