Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: particles: color is animatable too

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