Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: PerParticle-animations work as expected

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) : 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 sets a key in the color-animation on a per-particle basis
211   \param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
212   \param red red
213   \param green green
214   \param blue blue
215*/
216void ParticleSystem::setColor(float lifeCycleTime, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
217{
218  this->colorAnim[0].addEntry(lifeCycleTime, red);
219  this->colorAnim[1].addEntry(lifeCycleTime, green);
220  this->colorAnim[2].addEntry(lifeCycleTime, blue);
221  this->colorAnim[3].addEntry(lifeCycleTime, alpha);
222}
223
224/**
225   \brief ticks the system.
226   \param dt the time to tick all the Particles of the System
227
228   this is used to get all the particles some motion
229*/
230void ParticleSystem::tick(float dt)
231{
232  Particle* tickPart = particles;  // the particle to Tick
233  Particle* prevPart = NULL;       //
234  while (likely(tickPart != NULL))
235    {
236      // applying force to the System.
237      if (likely (tickPart->mass > 0.0))
238        tickPart->velocity += tickPart->extForce / tickPart->mass * dt;
239
240      // rendering new position.
241      tickPart->position = tickPart->position + tickPart->velocity * dt;
242      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
243        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
244
245      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
246        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
247     
248      tickPart->extForce = Vector(0,0,0);
249
250      // applying Color
251      tickPart->color[0] = this->colorAnim[0].getValue(tickPart->lifeCycle);
252      tickPart->color[1] = this->colorAnim[1].getValue(tickPart->lifeCycle);
253      tickPart->color[2] = this->colorAnim[2].getValue(tickPart->lifeCycle);
254      tickPart->color[3] = this->colorAnim[3].getValue(tickPart->lifeCycle);
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 (unlikely((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)
295{
296  Particle* tickPart = particles;
297  while (tickPart)
298    {
299      tickPart->extForce += field->calcForce(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->massRand = 2*(float)rand()/RAND_MAX -1;
457      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
458      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
459      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
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.