Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: baseObject now implements loading of objectNames

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