Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: mass and radius are animateable

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