Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: more loading procedures, fixed small bugs in loadparam

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