Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: ParticleSystem is now a PhysicsInterface

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