Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6621 was 6621, checked in by bensch, 18 years ago

orxonox/trunk: particle derivate… still working on this

File size: 14.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_GRAPHICS
17
18#include "particle_system.h"
19
20#include "particle_emitter.h"
21
22#include "field.h"
23#include "model.h"
24
25#include "load_param.h"
26#include "factory.h"
27#include "material.h"
28#include "state.h"
29#include "shell_command.h"
30
31#include "parser/tinyxml/tinyxml.h"
32#include <algorithm>
33
34using namespace std;
35
36/**
37 *  standard constructor
38 * @param maxCount the Count of particles in the System
39 * @param type The Type of the ParticleSystem
40*/
41ParticleSystem::ParticleSystem (unsigned int maxCount)
42{
43  this->init();
44
45  this->setMaxCount(maxCount);
46}
47
48/**
49 * @brief creates a Particle System out of a XML-element
50 * @param root: the XML-element to load from
51 */
52ParticleSystem::ParticleSystem(const TiXmlElement* root)
53{
54  this->init();
55
56  this->loadParams(root);
57}
58
59/**
60 *  standard deconstructor
61*/
62ParticleSystem::~ParticleSystem()
63{
64   // deleting all the living Particles
65   while (this->particles)
66     {
67       Particle* tmpDelPart = this->particles;
68       this->particles = this->particles->next;
69       delete tmpDelPart;
70     }
71
72   // deleting all the dead particles
73   while (this->deadList)
74     {
75       Particle* tmpDelPart = this->deadList;
76       this->deadList = this->deadList->next;
77       delete tmpDelPart;
78     }
79
80   if (this->material)
81     delete this->material;
82}
83
84/**
85  \brief initializes the ParticleSystem with default values
86*/
87void ParticleSystem::init()
88{
89  this->setClassID(CL_PARTICLE_SYSTEM, "ParticleSystem");
90
91  this->material = NULL;
92  this->setMaxCount(PARTICLE_DEFAULT_MAX_COUNT);
93  this->count = 0;
94  this->particles = NULL;
95  this->deadList = NULL;
96  this->setConserve(1);
97  this->setLifeSpan(1);
98  this->glID = NULL;
99
100  this->toList(OM_ENVIRON);
101}
102
103
104/**
105 * loads Parameters from a TiXmlElement
106 * @param root the XML-element to load from.
107 */
108void ParticleSystem::loadParams(const TiXmlElement* root)
109{
110  WorldEntity::loadParams(root);
111  PhysicsInterface::loadParams(root);
112
113  LoadParam(root, "max-count", this, ParticleSystem, setMaxCount)
114      .describe("the maximal count of Particles, that can be emitted into this system");
115
116  LoadParam(root, "life-span", this, ParticleSystem, setLifeSpan)
117      .describe("sets the life-span of the Particles.");
118
119  LoadParam(root, "conserve", this, ParticleSystem, setConserve)
120      .describe("sets the Conserve factor of the Particles (1.0: they keep all their energy, 0.0:they keep no energy)");
121
122  LoadParam(root, "texture", this, ParticleSystem, setMaterialTexture);
123  LoadParamXML(root, "emitter", this, ParticleSystem, addEmitterXML);
124
125  LOAD_PARAM_START_CYCLE(root, element);
126  {
127    element->ToText();
128  // PER-PARTICLE-ATTRIBUTES:
129    LoadParam_CYCLE(element, "radius", this, ParticleSystem, setRadius)
130        .describe("The Radius of each particle over time (TimeIndex [0-1], radius at TimeIndex, randomRadius at TimeIndex)");
131
132    LoadParam_CYCLE(element, "mass", this, ParticleSystem, setMass)
133        .describe("The Mass of each particle over time (TimeIndex: [0-1], mass at TimeIndex, randomMass at TimeIndex)");
134
135    LoadParam_CYCLE(element, "color", this, ParticleSystem, setColor)
136        .describe("The Color of each particle over time (TimeIndex: [0-1], red: [0-1], green: [0-1], blue: [0-1], alpha: [0-1])");
137  }
138  LOAD_PARAM_END_CYCLE(element);
139}
140
141/**
142* @param maxCount the maximum count of particles that can be emitted
143 */
144void ParticleSystem::setMaxCount(int maxCount)
145{
146  this->maxCount = maxCount;
147}
148
149// setting properties
150/**
151 *  sets the material to an external material
152 * @param material: the material to set this material to.
153
154   !! important if the extern material gets deleted it MUST be unregistered here or segfault !!
155*/
156void ParticleSystem::setMaterial(Material* material)
157{
158  this->material = material;
159}
160
161void ParticleSystem::setMaterialTexture(const char* textureFile)
162{
163  if (this->material != NULL)
164    this->material->setDiffuseMap(textureFile);
165}
166
167/**
168 *  Sets the lifespan of newly created particles
169*/
170void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan)
171{
172  this->lifeSpan = lifeSpan;
173  this->randomLifeSpan = randomLifeSpan;
174}
175
176/**
177 *  sets the conserve Factor of newly created particles
178*/
179void ParticleSystem::setConserve(float conserve)
180{
181  if (conserve > 1.0)
182    this->conserve = 1.0;
183  else if (conserve < 0.0)
184    this->conserve = 0.0;
185  else
186    this->conserve = conserve;
187}
188
189/////////////////////////////
190/* Per-Particle Attributes */
191/////////////////////////////
192/**
193 *  sets a key in the radius-animation on a per-particle basis
194 * @param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
195 * @param radius the radius at this position
196 * @param randRadius the randRadius at this position
197*/
198void ParticleSystem::setRadius(float lifeCycleTime, float radius, float randRadius)
199{
200  this->radiusAnim.changeEntry(lifeCycleTime, radius);
201  this->randRadiusAnim.changeEntry(lifeCycleTime, randRadius);
202}
203
204/**
205 *  sets a key in the mass-animation on a per-particle basis
206 * @param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
207 * @param mass the mass at this position
208 * @param randMass the randomMass at this position
209*/
210void ParticleSystem::setMass(float lifeCycleTime, float mass, float randMass)
211{
212  this->massAnim.changeEntry(lifeCycleTime, mass);
213  this->randMassAnim.changeEntry(lifeCycleTime, randMass);
214}
215
216/**
217 *  sets a key in the color-animation on a per-particle basis
218 * @param lifeCycleTime: the time (partilceLifeTime/particleAge) [0-1]
219 * @param red: red
220 * @param green: green
221 * @param blue: blue
222 * @param alpha: alpha
223*/
224void ParticleSystem::setColor(float lifeCycleTime, float red, float green, float blue, float alpha)
225{
226  this->colorAnim[0].changeEntry(lifeCycleTime, red);
227  this->colorAnim[1].changeEntry(lifeCycleTime, green);
228  this->colorAnim[2].changeEntry(lifeCycleTime, blue);
229  this->colorAnim[3].changeEntry(lifeCycleTime, alpha);
230}
231
232
233void ParticleSystem::addEmitter(ParticleEmitter* emitter)
234{
235  assert (emitter != NULL);
236  if (emitter->getSystem() != NULL)
237    emitter->getSystem()->removeEmitter(emitter);
238  this->emitters.push_back(emitter);
239}
240
241void ParticleSystem::addEmitterXML(const TiXmlElement* emitterRoot)
242{
243  ParticleEmitter* emitter = new ParticleEmitter(emitterRoot);
244  this->addEmitter(emitter);
245}
246
247
248void ParticleSystem::removeEmitter(ParticleEmitter* emitter)
249{
250  std::list<ParticleEmitter*>::iterator it = std::find(this->emitters.begin(), this->emitters.end(), emitter);
251  if (it != this->emitters.end())
252    this->emitters.erase(it);
253}
254
255/**
256 *  ticks the system.
257 * @param dt the time to tick all the Particles of the System
258
259   this is used to get all the particles some motion
260*/
261void ParticleSystem::tick(float dt)
262{
263  Particle* tickPart = particles;  // the particle to Tick
264  Particle* prevPart = NULL;
265  while (likely(tickPart != NULL))
266    {
267      // applying force to the System.
268      if (likely (tickPart->mass > 0.0))
269        tickPart->velocity += tickPart->extForce / tickPart->mass * dt;
270      // rendering new position.
271      tickPart->position += tickPart->velocity * dt;
272      tickPart->orientation += tickPart->momentum *dt;
273
274      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
275        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
276
277      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
278        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
279
280      tickPart->extForce = Vector(0,0,0);
281
282      // applying Color
283      tickPart->color[0] = this->colorAnim[0].getValue(tickPart->lifeCycle);
284      tickPart->color[1] = this->colorAnim[1].getValue(tickPart->lifeCycle);
285      tickPart->color[2] = this->colorAnim[2].getValue(tickPart->lifeCycle);
286      tickPart->color[3] = this->colorAnim[3].getValue(tickPart->lifeCycle);
287
288      // many more to come
289
290      if (this->conserve < 1.0)
291      {
292        tickPart->velocity *= this->conserve;
293        tickPart->momentum *= this->conserve;
294      }
295      // find out if we have to delete tickPart
296      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
297        {
298          // remove the particle from the list
299          if (likely(prevPart != NULL))
300            {
301              prevPart->next = tickPart->next;
302              tickPart->next = this->deadList;
303              this->deadList = tickPart;
304              tickPart = prevPart->next;
305            }
306          else
307            {
308              prevPart = NULL;
309              this->particles = tickPart->next;
310              tickPart->next = this->deadList;
311              this->deadList = tickPart;
312              tickPart = this->particles;
313            }
314          --this->count;
315        }
316      else
317        {
318          prevPart = tickPart;
319          tickPart = tickPart->next;
320        }
321    }
322
323    std::list<ParticleEmitter*>::iterator emitter;
324    for (emitter = this->emitters.begin(); emitter != this->emitters.end(); emitter++)
325      (*emitter)->tick(dt);
326}
327
328/**
329  *  applies some force to a Particle.
330  * @param field the Field to apply.
331 */
332void ParticleSystem::applyField(Field* field)
333{
334  Particle* tickPart = particles;
335  while (tickPart)
336    {
337      tickPart->extForce += field->calcForce(tickPart->position);
338      tickPart = tickPart->next;
339    }
340}
341
342
343/**
344 * @returns the count of Faces of this ParticleSystem
345 */
346unsigned int ParticleSystem::getFaceCount() const
347{
348  return this->count;
349}
350
351
352/**
353 *  draws all the Particles of this System
354
355   The Cases in this Function all do the same:
356   Drawing all the particles with the appropriate Type.
357   This is just the fastest Way to do this, but will most likely be changed in the future.
358 */
359// void ParticleSystem::draw() const
360// {
361//   glPushAttrib(GL_ENABLE_BIT);
362//
363//   Particle* drawPart = particles;
364//
365//   switch (this->particleType)
366//   {
367//     case PARTICLE_SPARK:
368//       glDisable(GL_LIGHTING);
369//       glDepthMask(GL_FALSE);
370//       //glEnable(GL_LINE_SMOOTH);
371//       glEnable(GL_BLEND);
372//
373//       glBegin(GL_LINES);
374//       while (likely(drawPart != NULL))
375//       {
376//         glColor4fv(drawPart->color);
377//         glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
378//         glVertex3f(drawPart->position.x - drawPart->velocity.x * drawPart->radius,
379//                    drawPart->position.y - drawPart->velocity.y * drawPart->radius,
380//                    drawPart->position.z - drawPart->velocity.z * drawPart->radius);
381//         drawPart = drawPart->next;
382//       }
383//       glEnd();
384//       break;
385//
386//     case PARTICLE_MODEL:
387//       {
388//         GLfloat matrix[4][4];
389//
390//         if (likely(this->getModel() != NULL))
391//           while (likely(drawPart != NULL))
392//         {
393//           glPushMatrix();
394//           glMatrixMode(GL_MODELVIEW);
395//           /* move */
396//           glTranslatef(drawPart->position.x, drawPart->position.y, drawPart->position.z);
397//           /* scale */
398//           glScalef(drawPart->radius, drawPart->radius, drawPart->radius);
399//           /* rotate */
400//           drawPart->orientation.matrix (matrix);
401//           glMultMatrixf((float*)matrix);
402//
403//           this->getModel()->draw();
404//
405//           glPopMatrix();
406//           drawPart = drawPart->next;
407//         }
408//         else
409//           PRINTF(2)("no model loaded onto ParticleSystem-%s\n", this->getName());
410//       }
411//       break;
412//
413//     case PARTICLE_DOT:
414//       glDisable(GL_LIGHTING);
415//       glBegin(GL_POINTS);
416//       while (likely(drawPart != NULL))
417//       {
418//         glColor4fv(drawPart->color);
419//
420//         glLineWidth(drawPart->radius);
421//
422//         glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
423//         drawPart = drawPart->next;
424//       }
425//       glEnd();
426//       break;
427//   }
428//   glPopAttrib();
429// }
430
431/**
432 *  adds a new Particle to the System
433 * @param position the initial position, where the particle gets emitted.
434 * @param velocity the initial velocity of the particle.
435 * @param orientation the initial orientation of the Paritcle.
436 * @param momentum the initial momentum of the Particle (the speed of its rotation).
437 * @param data some more data given by the emitter
438*/
439void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, const Quaternion& orientation, const Quaternion& momentum, unsigned int data)
440{
441  if (this->count <= this->maxCount)
442    {
443      // if it is the first Particle
444      if (unlikely(particles == NULL))
445        {
446          if (likely(deadList != NULL))
447            {
448              this->particles = this->deadList;
449              deadList = deadList->next;
450            }
451          else
452            {
453              PRINTF(5)("Generating new Particle\n");
454              this->particles = new Particle;
455            }
456          this->particles->next = NULL;
457        }
458      // filling the List from the beginning
459      else
460        {
461          Particle* tmpPart;
462          if (likely(deadList != NULL))
463            {
464              tmpPart = this->deadList;
465              deadList = deadList->next;
466            }
467          else
468            {
469              PRINTF(5)("Generating new Particle\n");
470              tmpPart = new Particle;
471            }
472          tmpPart->next = this->particles;
473          this->particles = tmpPart;
474        }
475      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
476      particles->lifeCycle = 0.0;
477      particles->position = position;
478      particles->velocity = velocity;
479
480      particles->orientation = orientation;
481      particles->momentum = momentum;
482
483      //  particle->rotation = ; //! @todo rotation is once again something to be done.
484      particles->massRand = 2*(float)rand()/RAND_MAX -1;
485      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
486      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
487      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
488
489      ++this->count;
490    }
491  else
492    PRINTF(5)("maximum count of particles reached not adding any more\n");
493}
494
495/**
496 *  outputs some nice debug information
497*/
498void ParticleSystem::debug() const
499{
500  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
501  if (deadList)
502    {
503      PRINT(0)("  - ParticleDeadList is used: ");
504      int i = 1;
505      Particle* tmpPart = this->deadList;
506      while (tmpPart = tmpPart->next) ++i;
507      PRINT(0)("count: %d\n", i);
508    }
509}
Note: See TracBrowser for help on using the repository browser.