Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/physics: color-space

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