Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: setClassID implemented in all files

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