Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: more loading procedures

File size: 17.8 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#include "objModel.h"
29
30#include "tinyxml.h"
31
32CREATE_FACTORY(ParticleSystem);
33
34
35using namespace std;
36
37/**
38   \brief standard constructor
39   \param maxCount the Count of particles in the System
40   \param type The Type of the ParticleSystem
41*/
42ParticleSystem::ParticleSystem (unsigned int maxCount, PARTICLE_TYPE type) : PhysicsInterface(this)
43{
44  this->init();
45
46  this->setMaxCount(maxCount);
47  this->setType(type, 1);
48}
49
50/**
51  \brief creates a Particle System out of a XML-element
52  \param root: the XML-element to load from
53 */
54ParticleSystem::ParticleSystem(const TiXmlElement* root) : PhysicsInterface(this)
55{
56  this->init();
57
58  this->loadParams(root);
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   ResourceManager::getInstance()->unload(this->model);
89}
90
91/**
92  \brief initializes the ParticleSystem with default values
93*/
94void ParticleSystem::init(void)
95{
96  this->setClassID(CL_PARTICLE_SYSTEM, "ParticleSystem");
97
98  this->material = NULL;
99  this->model = NULL;
100  this->setMaxCount(PARTICLE_DEFAULT_MAX_COUNT);
101  this->count = 0;
102  this->particles = NULL;
103  this->deadList = NULL;
104  this->setConserve(1);
105  this->setLifeSpan(1);
106  this->glID = NULL;
107  this->setType(PARTICLE_DEFAULT_TYPE, 1);
108  ParticleEngine::getInstance()->addSystem(this);
109}
110
111
112/**
113 * loads Parameters from a TiXmlElement
114 * @param root the XML-element to load from.
115 */
116void ParticleSystem::loadParams(const TiXmlElement* root)
117{
118  static_cast<WorldEntity*>(this)->loadParams(root);
119  static_cast<PhysicsInterface*>(this)->loadParams(root);
120
121  LoadParam<ParticleSystem>(root, "max-count", this, &ParticleSystem::setMaxCount)
122      .describe("the maximal count of Particles, that can be emitted into this system");
123
124  //LoadParam<ParticleSystem>(root, "type", this, &ParticleSystem::setType);
125  LoadParam<ParticleSystem>(root, "life-span", this, &ParticleSystem::setLifeSpan)
126      .describe("sets the life-span of the Particles.");
127
128  LoadParam<ParticleSystem>(root, "conserve", this, &ParticleSystem::setConserve)
129      .describe("sets the Conserve facrot of the Particles (1.0: they keep all their energy, 0.0:they keep no energy)");
130
131  const TiXmlElement* element = root->FirstChildElement();
132  while (element != NULL)
133  {
134    LoadParam<ParticleSystem>(element, "type", this, &ParticleSystem::setType, true)
135        .describe("sets the type of the Particles, (dot, spark, sprite or model)");
136
137  // PER-PARTICLE-ATTRIBUTES:
138    LoadParam<ParticleSystem>(element, "radius", this, &ParticleSystem::setRadius, true)
139        .describe("The Radius of each particle over time (TimeIndex [0-1], radius at TimeIndex, randomRadius at TimeIndex)");
140
141    LoadParam<ParticleSystem>(element, "mass", this, &ParticleSystem::setMass, true)
142        .describe("The Mass of each particle over time (TimeIndex: [0-1], mass at TimeIndex, randomMass at TimeIndex)");
143
144    LoadParam<ParticleSystem>(element, "color", this, &ParticleSystem::setColor, true)
145        .describe("The Color of each particle over time (TimeIndex: [0-1], red: [0-1], green: [0-1], blue: [0-1], alpha: [0-1])");
146    element = element->NextSiblingElement();
147  }
148
149}
150
151/**
152  \param maxCount the maximum count of particles that can be emitted
153 */
154void ParticleSystem::setMaxCount(int maxCount)
155{
156  this->maxCount = maxCount;
157}
158
159
160/**
161   \param particleType the type of particles in this System
162   \param count how many particles (in PARTICLE_MULTI-mode)
163   \todo this will be different
164*/
165void ParticleSystem::setType(const char* particleType)
166{
167  if (!strcmp(particleType, "dot"))
168    this->setType(PARTICLE_DOT);
169  else if(!strcmp(particleType, "spark"))
170    this->setType(PARTICLE_SPARK);
171  else if(!strcmp(particleType, "model"))
172    this->setType(PARTICLE_MODEL);
173  else // if (strcmp(particleType, "SPRITE"))
174    this->setType(PARTICLE_SPRITE);
175}
176
177/**
178   \param particleType the type of particles in this System
179   \param count how many particles (in PARTICLE_MULTI-mode)
180   \todo this will be different
181*/
182void ParticleSystem::setType(PARTICLE_TYPE particleType, int count)
183{
184  this->particleType = particleType;
185  this->dialectCount = count;
186  //  if (glID != NULL)
187  //    delete glID;
188
189  //  glID = new GLuint[count];
190  //  for (int i = 0; i< count; i++)
191  //    glID[i] = 0;
192
193  //  glID[0] = glGenLists(count);
194  if (this->material)
195    delete this->material;
196  this->material = NULL;
197
198  switch (this->particleType)
199    {
200      case PARTICLE_SPRITE:
201        this->material = new Material("transperencyMap");
202        this->material->setDiffuseMap("pictures/radialTransparency.png");
203      //  material->setTransparency(.5);
204        break;
205  }
206}
207
208// setting properties
209/**
210   \brief sets the material to an external material
211   \param material: the material to set this material to.
212
213   !! important if the extern material gets deleted it MUST be unregistered here or segfault !!
214*/
215void ParticleSystem::setMaterial(Material* material)
216{
217  this->material = material;
218}
219
220/**
221   \brief Sets the lifespan of newly created particles
222*/
223void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan)
224{
225  this->lifeSpan = lifeSpan;
226  this->randomLifeSpan = randomLifeSpan;
227}
228
229/**
230   \brief sets the conserve Factor of newly created particles
231*/
232void ParticleSystem::setConserve(float conserve)
233{
234  if (conserve > 1.0)
235    this->conserve = 1.0;
236  else if (conserve < 0.0)
237    this->conserve = 0.0;
238  else
239    this->conserve = conserve;
240}
241
242/////////////////////////////
243/* Per-Particle Attributes */
244/////////////////////////////
245/**
246   \brief sets a key in the radius-animation on a per-particle basis
247   \param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
248   \param radius the radius at this position
249   \param randRadius the randRadius at this position
250*/
251void ParticleSystem::setRadius(float lifeCycleTime, float radius, float randRadius)
252{
253  this->radiusAnim.changeEntry(lifeCycleTime, radius);
254  this->randRadiusAnim.changeEntry(lifeCycleTime, randRadius);
255}
256
257/**
258   \brief sets a key in the mass-animation on a per-particle basis
259   \param lifeCycleTime the time (partilceLifeTime/particleAge) [0-1]
260   \param mass the mass at this position
261   \param randMass the randomMass at this position
262*/
263void ParticleSystem::setMass(float lifeCycleTime, float mass, float randMass)
264{
265  this->massAnim.changeEntry(lifeCycleTime, mass);
266  this->randMassAnim.changeEntry(lifeCycleTime, randMass);
267}
268
269/**
270   \brief sets a key in the color-animation on a per-particle basis
271   \param lifeCycleTime: the time (partilceLifeTime/particleAge) [0-1]
272   \param red: red
273   \param green: green
274   \param blue: blue
275   \param alpha: alpha
276*/
277void ParticleSystem::setColor(float lifeCycleTime, float red, float green, float blue, float alpha)
278{
279  this->colorAnim[0].changeEntry(lifeCycleTime, red);
280  this->colorAnim[1].changeEntry(lifeCycleTime, green);
281  this->colorAnim[2].changeEntry(lifeCycleTime, blue);
282  this->colorAnim[3].changeEntry(lifeCycleTime, alpha);
283}
284
285/**
286   \brief ticks the system.
287   \param dt the time to tick all the Particles of the System
288
289   this is used to get all the particles some motion
290*/
291void ParticleSystem::tick(float dt)
292{
293  Particle* tickPart = particles;  // the particle to Tick
294  Particle* prevPart = NULL;
295  while (likely(tickPart != NULL))
296    {
297      // applying force to the System.
298      if (likely (tickPart->mass > 0.0))
299        tickPart->velocity += tickPart->extForce / tickPart->mass * dt;
300      // rendering new position.
301      tickPart->position += tickPart->velocity * dt;
302      tickPart->orientation += tickPart->momentum *dt;
303
304      tickPart->radius = radiusAnim.getValue(tickPart->lifeCycle)
305        + randRadiusAnim.getValue(tickPart->lifeCycle) * tickPart->radiusRand;
306
307      tickPart->mass = massAnim.getValue(tickPart->lifeCycle)
308        + randMassAnim.getValue(tickPart->lifeCycle) * tickPart->massRand;
309
310      tickPart->extForce = Vector(0,0,0);
311
312      // applying Color
313      tickPart->color[0] = this->colorAnim[0].getValue(tickPart->lifeCycle);
314      tickPart->color[1] = this->colorAnim[1].getValue(tickPart->lifeCycle);
315      tickPart->color[2] = this->colorAnim[2].getValue(tickPart->lifeCycle);
316      tickPart->color[3] = this->colorAnim[3].getValue(tickPart->lifeCycle);
317
318      // many more to come
319
320      if (this->conserve < 1.0)
321      {
322        tickPart->velocity *= this->conserve;
323        tickPart->momentum *= this->conserve;
324      }
325      // find out if we have to delete tickPart
326      if (unlikely((tickPart->lifeCycle += dt/tickPart->lifeTime) >= 1.0))
327        {
328          // remove the particle from the list
329          if (likely(prevPart != NULL))
330            {
331              prevPart->next = tickPart->next;
332              tickPart->next = this->deadList;
333              this->deadList = tickPart;
334              tickPart = prevPart->next;
335            }
336          else
337            {
338              prevPart = NULL;
339              this->particles = tickPart->next;
340              tickPart->next = this->deadList;
341              this->deadList = tickPart;
342              tickPart = this->particles;
343            }
344          --this->count;
345        }
346      else
347        {
348          prevPart = tickPart;
349          tickPart = tickPart->next;
350        }
351    }
352}
353
354/**
355    \brief applies some force to a Particle.
356    \param field the Field to apply.
357 */
358void ParticleSystem::applyField(Field* field)
359{
360  Particle* tickPart = particles;
361  while (tickPart)
362    {
363      tickPart->extForce += field->calcForce(tickPart->position);
364      tickPart = tickPart->next;
365    }
366}
367
368
369/**
370 * \returns the count of Faces of this ParticleSystem
371 */
372unsigned int ParticleSystem::getFaceCount(void) const
373{
374  switch (this->particleType)
375  {
376    case PARTICLE_SPRITE:
377      return this->count;
378      break;
379    case PARTICLE_MODEL:
380      if (this->model)
381        return this->count * this->model->getFaceCount();
382      break;
383  }
384}
385
386
387/**
388   \brief draws all the Particles of this System
389
390   The Cases in this Function all do the same:
391   Drawing all the particles with the appropriate Type.
392   This is just the fastest Way to do this, but will most likely be changed in the future.
393 */
394void ParticleSystem::draw(void) const
395{
396  glPushAttrib(GL_ENABLE_BIT);
397
398  Particle* drawPart = particles;
399
400  switch (this->particleType)
401  {
402    default:
403    case PARTICLE_SPRITE:
404      glDisable(GL_LIGHTING);
405      glMatrixMode(GL_MODELVIEW);
406      glDepthMask(GL_FALSE);
407
408      material->select();
409      //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
410
411
412      while (likely(drawPart != NULL))
413      {
414        glColor4fv(drawPart->color);
415          //! \todo implement a faster code for the look-at Camera algorithm.
416
417        const PNode* camera = State::getInstance()->getCamera();  //!< \todo MUST be different
418        Vector cameraPos = camera->getAbsCoor();
419        Vector cameraTargetPos = State::getInstance()->getCameraTarget()->getAbsCoor();
420        Vector view = cameraTargetPos - cameraPos;
421        Vector up = Vector(0, 1, 0);
422        up = camera->getAbsDir().apply(up);
423        Vector h = up.cross(view);
424        Vector v = h.cross(view);
425        h.normalize();
426        v.normalize();
427        v *= .5 * drawPart->radius;
428        h *= .5 * drawPart->radius;
429
430        glBegin(GL_TRIANGLE_STRIP);
431        glTexCoord2i(1, 1);
432        glVertex3f(drawPart->position.x - h.x - v.x,
433                   drawPart->position.y - h.y - v.y,
434                   drawPart->position.z - h.z - v.z);
435        glTexCoord2i(0, 1);
436        glVertex3f(drawPart->position.x - h.x + v.x,
437                   drawPart->position.y - h.y + v.y,
438                   drawPart->position.z - h.z + v.z);
439        glTexCoord2i(1, 0);
440        glVertex3f(drawPart->position.x + h.x - v.x,
441                   drawPart->position.y + h.y - v.y,
442                   drawPart->position.z + h.z - v.z);
443        glTexCoord2i(0, 0);
444        glVertex3f(drawPart->position.x + h.x + v.x,
445                   drawPart->position.y + h.y + v.y,
446                   drawPart->position.z + h.z + v.z);
447
448        glEnd();
449
450        drawPart = drawPart->next;
451      }
452      glDepthMask(GL_TRUE);
453      break;
454
455    case PARTICLE_SPARK:
456      glDisable(GL_LIGHTING);
457      glDepthMask(GL_FALSE);
458      //glEnable(GL_LINE_SMOOTH);
459      glEnable(GL_BLEND);
460
461      glBegin(GL_LINES);
462      while (likely(drawPart != NULL))
463      {
464        glColor4fv(drawPart->color);
465        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
466        glVertex3f(drawPart->position.x - drawPart->velocity.x * drawPart->radius,
467                   drawPart->position.y - drawPart->velocity.y * drawPart->radius,
468                   drawPart->position.z - drawPart->velocity.z * drawPart->radius);
469        drawPart = drawPart->next;
470      }
471      glEnd();
472      break;
473
474    case PARTICLE_MODEL:
475      {
476        GLfloat matrix[4][4];
477
478        if (likely(this->model != NULL))
479          while (likely(drawPart != NULL))
480        {
481          glPushMatrix();
482          glMatrixMode(GL_MODELVIEW);
483          /* move */
484          glTranslatef(drawPart->position.x, drawPart->position.y, drawPart->position.z);
485          /* scale */
486          glScalef(drawPart->radius, drawPart->radius, drawPart->radius);
487          /* rotate */
488          drawPart->orientation.matrix (matrix);
489          glMultMatrixf((float*)matrix);
490
491          this->model->draw();
492
493          glPopMatrix();
494          drawPart = drawPart->next;
495        }
496        else
497          printf("no model loaded onto ParticleSystem-%s\n", this->getName());
498      }
499      break;
500
501    case PARTICLE_DOT:
502      glDisable(GL_LIGHTING);
503      glBegin(GL_POINTS);
504      while (likely(drawPart != NULL))
505      {
506        glColor4fv(drawPart->color);
507
508        glLineWidth(drawPart->radius);
509
510        glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
511        drawPart = drawPart->next;
512      }
513      glEnd();
514      break;
515  }
516  glPopAttrib();
517}
518
519/**
520   \brief adds a new Particle to the System
521   \param position the initial position, where the particle gets emitted.
522   \param velocity the initial velocity of the particle.
523   \param orientation the initial orientation of the Paritcle.
524   \param momentum the initial momentum of the Particle (the speed of its rotation).
525   \param data some more data given by the emitter
526*/
527void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, const Quaternion& orientation, const Quaternion& momentum, unsigned int data)
528{
529  if (this->count <= this->maxCount)
530    {
531      // if it is the first Particle
532      if (unlikely(particles == NULL))
533        {
534          if (likely(deadList != NULL))
535            {
536              this->particles = this->deadList;
537              deadList = deadList->next;
538            }
539          else
540            {
541              PRINTF(5)("Generating new Particle\n");
542              this->particles = new Particle;
543            }
544          this->particles->next = NULL;
545        }
546      // filling the List from the beginning
547      else
548        {
549          Particle* tmpPart;
550          if (likely(deadList != NULL))
551            {
552              tmpPart = this->deadList;
553              deadList = deadList->next;
554            }
555          else
556            {
557              PRINTF(5)("Generating new Particle\n");
558              tmpPart = new Particle;
559            }
560          tmpPart->next = this->particles;
561          this->particles = tmpPart;
562        }
563      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
564      particles->lifeCycle = 0.0;
565      particles->position = position;
566      particles->velocity = velocity;
567
568      particles->orientation = orientation;
569      particles->momentum = momentum;
570
571      //  particle->rotation = ; //! \todo rotation is once again something to be done.
572      particles->massRand = 2*(float)rand()/RAND_MAX -1;
573      particles->radiusRand = 2* (float)rand()/RAND_MAX -1;
574      particles->mass = this->massAnim.getValue(0.0) + this->randMassAnim.getValue(0.0)*particles->massRand;
575      particles->radius = this->radiusAnim.getValue(0.0) + this->randRadiusAnim.getValue(0.0)*particles->radiusRand;
576
577      ++this->count;
578    }
579  else
580    PRINTF(5)("maximum count of particles reached not adding any more\n");
581}
582
583/**
584   \brief outputs some nice debug information
585*/
586void ParticleSystem::debug(void) const
587{
588  PRINT(0)("  ParticleSystem %s, type: ", this->getName());
589  {
590      if (this->particleType == PARTICLE_MODEL)
591        PRINT(0)("model");
592      else if (this->particleType == PARTICLE_SPRITE)
593        PRINT(0)("sprite");
594      else if (this->particleType == PARTICLE_DOT)
595        PRINT(0)("dot");
596      else if (this->particleType == PARTICLE_SPARK)
597        PRINT(0)("spark");
598
599      PRINT(0)("\n");
600  }
601
602  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
603  if (deadList)
604    {
605      PRINT(0)("  - ParticleDeadList is used: ");
606      int i = 1;
607      Particle* tmpPart = this->deadList;
608      while (tmpPart = tmpPart->next) ++i;
609      PRINT(0)("count: %d\n", i);
610    }
611}
Note: See TracBrowser for help on using the repository browser.