Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/physics/src/lib/graphics/particles/particle_system.cc @ 4293

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

orxonox/branches/physics: intoducing state: stors the Camera position globally somewhere we have to store this data

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