Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: particles now get rendered as expected

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