Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: inheritSpeed now property of particle_emitter. system not friend emitter anymore

File size: 12.1 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      glDisable(GL_DEPTH_TEST);
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
336     
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.