Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: applying force works for particle-systems again

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