Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: removed debug-stuff

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