Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/physics/src/lib/graphics/particles/particle_system.cc @ 4330

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

orxonox/branches/physics: more threading capabilities

File size: 12.7 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)
43{
44  this->setClassName ("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->setRadius(1.0, 1.0, 0.0);
56  this->setType(type, 1);
57  this->setColor(1.0,1.0,1.0,1.0, .5,.5,.5,.5, .0,.0,.0,.0);
58  ParticleEngine::getInstance()->addSystem(this);
59}
60
61
62/**
63   \brief standard deconstructor
64*/
65ParticleSystem::~ParticleSystem()
66{
67  // delete what has to be deleted here
68   ParticleEngine::getInstance()->removeSystem(this);
69
70   // deleting all the living Particles
71   while (this->particles)
72     {
73       Particle* tmpDelPart = this->particles;
74       this->particles = this->particles->next;
75       delete tmpDelPart;
76     }
77
78   // deleting all the dead particles
79   while (this->deadList)
80     {
81       Particle* tmpDelPart = this->deadList;
82       this->deadList = this->deadList->next;
83       delete tmpDelPart;
84     }
85
86   if (this->material)
87     delete this->material;
88}
89
90/**
91   \brief sets the Name of the Particle System
92   \param name the Name of the System
93*/
94void ParticleSystem::setName(const char* name)
95{
96  if (this->name)
97    delete this->name;
98  this->name = new char[strlen(name)+1];
99  strcpy(this->name, name);
100}
101
102/**
103   \returns the Name of the ParticleSystem
104*/
105const char* ParticleSystem::getName(void) const
106{
107  return this->name;
108}
109
110/**
111   \todo this will be different
112*/
113void ParticleSystem::setType(PARTICLE_TYPE particleType, int count)
114{
115  this->particleType = particleType;
116  this->dialectCount = count;
117  //  if (glID != NULL)
118  //    delete glID;
119
120  //  glID = new GLuint[count];
121  //  for (int i = 0; i< count; i++)
122  //    glID[i] = 0;
123
124  //  glID[0] = glGenLists(count);
125  if (material)
126    delete material;
127  material = NULL;
128
129  if (particleType == PARTICLE_SPRITE)
130    {
131      material = new Material("transperencyMap");
132      material->setDiffuseMap("pictures/radialTransparency.png");
133      //  material->setTransparency(.5);
134    }
135}
136
137// setting properties
138void ParticleSystem::setMaterial(Material* material)
139{
140  this->material = material;
141}
142
143
144
145/**
146   \brief how much of the speed from the ParticleEmitter should flow onto the ParticleSystem
147   \param value a Value between zero and one
148
149   
150   if you want to change the value of this variable during emission time (to make it more dynamic)
151   you may want to use the animation class
152*/
153void ParticleSystem::setInheritSpeed(float value)
154{
155  if (unlikely(value > 1.0))
156    this->inheritSpeed = 1;
157  else if (unlikely(value < 0.0))
158    this->inheritSpeed = 0;
159  else
160    this->inheritSpeed = value;
161}
162
163/**
164   \brief Sets the lifespan of newly created particles
165*/   
166void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan)
167{
168  this->lifeSpan = lifeSpan;
169  this->randomLifeSpan = randomLifeSpan;
170}
171
172/**
173   \brief sets the radius of newly created particles
174*/
175void ParticleSystem::setRadius(float startRadius, float endRadius, float randomStartRadius, float randomEndRadius)
176{
177  this->startRadius = startRadius;
178  this->endRadius = endRadius;
179  this->randomStartRadius = randomStartRadius;
180  this->randomEndRadius = randomEndRadius;
181}
182
183/**
184   \brief sets the conserve Factor of newly created particles
185*/
186void ParticleSystem::setConserve(float conserve)
187{
188  if (conserve > 1.0)
189    this->conserve = 1.0;
190  else if (conserve < 0.0)
191    this->conserve = 0.0;
192  else
193    this->conserve = conserve;
194}
195
196
197/**
198   \brief Tells the ParticleSystem how it should iterate the color over time
199   \param ....
200*/
201void ParticleSystem::setColor(GLfloat br, GLfloat bg, GLfloat bb, GLfloat ba,
202                              GLfloat mr, GLfloat mg, GLfloat mb, GLfloat ma,
203                              GLfloat er, GLfloat eg, GLfloat eb, GLfloat ea)
204{
205  this->startColor[0] = br;
206  this->startColor[1] = bg;
207  this->startColor[2] = bb;
208  this->startColor[3] = ba;
209
210  this->midColor[0] = mr;
211  this->midColor[1] = mg;
212  this->midColor[2] = mb;
213  this->midColor[3] = ma;
214
215  this->endColor[0] = er;
216  this->endColor[1] = eg;
217  this->endColor[2] = eb;
218  this->endColor[3] = ea;
219}
220
221/**
222   \brief ticks the system.
223   \param dt the time to tick all the Particles of the System
224
225   this is used to get all the particles some motion
226*/
227void ParticleSystem::tick(float dt)
228{
229  Particle* tickPart = particles;  // the particle to Tick
230  Particle* prevPart = NULL;       //
231  while (likely(tickPart != NULL))
232    {
233      tickPart->position = tickPart->position + tickPart->velocity;
234      tickPart->radius += tickPart->radiusIt * dt;
235
236      // applying force to the System.
237      tickPart->velocity += tickPart->extForce * tickPart->mass;
238      tickPart->extForce = Vector(0,0,0);
239
240      // applying Color
241      //! \todo better algorithm to do this \todo also implement the midColor
242      if (tickPart->lifeCycle < .5)
243        {
244          tickPart->color[0] = this->startColor[0] *(1.0-tickPart->lifeCycle*2.0) + this->midColor[0] *(tickPart->lifeCycle*2);
245          tickPart->color[1] = this->startColor[1] *(1.0-tickPart->lifeCycle*2.0) + this->midColor[1] *(tickPart->lifeCycle*2);
246          tickPart->color[2] = this->startColor[2] *(1.0-tickPart->lifeCycle*2.0) + this->midColor[2] *(tickPart->lifeCycle*2);
247          tickPart->color[3] = this->startColor[3] *(1.0-tickPart->lifeCycle*2.0) + this->midColor[3] *(tickPart->lifeCycle*2);
248        }
249      else
250        {
251          tickPart->color[0] = this->midColor[0] *(2.0-tickPart->lifeCycle*2.0) + this->endColor[0] *(tickPart->lifeCycle*2);
252          tickPart->color[1] = this->midColor[1] *(2.0-tickPart->lifeCycle*2.0) + this->endColor[1] *(tickPart->lifeCycle*2);
253          tickPart->color[2] = this->midColor[2] *(2.0-tickPart->lifeCycle*2.0) + this->endColor[2] *(tickPart->lifeCycle*2);
254          tickPart->color[3] = this->midColor[3] *(2.0-tickPart->lifeCycle*2.0) + this->endColor[3] *(tickPart->lifeCycle*2);
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 ((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 */
292void ParticleSystem::applyField(float dt, Field* field)
293{
294  Particle* tickPart = particles;
295  while (tickPart)
296    {
297      tickPart->extForce += field->calcForce(dt, tickPart->position);
298      tickPart = tickPart->next;
299    }
300}
301
302
303/**
304   \brief draws all the Particles of this System
305   \param the time passed in seconds (since the last draw)
306
307   The Cases in this Function all do the same:
308   Drawing all the particles with the appropriate Type.
309   This is just the fastest Way to do this, but will most likely be changed in the future.
310*/
311void ParticleSystem::draw(float dt)
312{
313  glPushAttrib(GL_ENABLE_BIT);
314  glDisable(GL_LIGHTING);
315
316  Particle* drawPart = particles;
317     
318  switch (this->particleType)
319    {
320    default:
321    case PARTICLE_SPRITE:
322      glMatrixMode(GL_MODELVIEW);
323      glDisable(GL_DEPTH_TEST);
324
325      material->select(); 
326      //      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE);
327     
328
329      while (likely(drawPart != NULL))
330        {
331          glColor4fv(drawPart->color);
332          //! \todo implement a faster code for the look-at Camera algorithm.
333
334          const PNode* camera = State::getInstance()->getCamera();  //!< \todo MUST be different
335          Vector cameraPos = camera->getAbsCoor();
336          Vector cameraTargetPos = State::getInstance()->getCameraTarget()->getAbsCoor();
337          Vector view = cameraTargetPos - cameraPos;
338          Vector up = Vector(0, 1, 0);
339          up = camera->getAbsDir().apply(up);
340          Vector h = up.cross(view);
341          Vector v = h.cross(view);
342          h.normalize();
343          v.normalize();
344          v *= .5 * drawPart->radius;
345          h *= .5 * drawPart->radius;
346
347          glBegin(GL_TRIANGLE_STRIP);
348          glTexCoord2i(1, 1);
349          glVertex3f(drawPart->position.x - h.x - v.x,
350                     drawPart->position.y - h.y - v.y,
351                     drawPart->position.z - h.z - v.z);
352          glTexCoord2i(0, 1);
353          glVertex3f(drawPart->position.x - h.x + v.x,
354                     drawPart->position.y - h.y + v.y,
355                     drawPart->position.z - h.z + v.z);
356          glTexCoord2i(1, 0);
357          glVertex3f(drawPart->position.x + h.x - v.x,
358                     drawPart->position.y + h.y - v.y,
359                     drawPart->position.z + h.z - v.z);
360          glTexCoord2i(0, 0);
361          glVertex3f(drawPart->position.x + h.x + v.x,
362                     drawPart->position.y + h.y + v.y,
363                     drawPart->position.z + h.z + v.z);
364
365          glEnd();
366 
367          drawPart = drawPart->next;
368        }
369
370     
371      break;
372
373    case PARTICLE_SPARK:
374      glEnable(GL_LINE_SMOOTH);
375      glBegin(GL_LINES);
376      while (likely(drawPart != NULL))
377        {
378          glColor4fv(drawPart->color);
379          glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
380          glVertex3f(drawPart->position.x - drawPart->velocity.x,
381                     drawPart->position.y - drawPart->velocity.y,
382                     drawPart->position.z - drawPart->velocity.z);
383          drawPart = drawPart->next;
384        }
385      glEnd();
386      break;
387     
388    case PARTICLE_DOT:
389      glBegin(GL_POINTS);
390      while (likely(drawPart != NULL))
391        {
392          glColor4fv(drawPart->color);
393
394          glLineWidth(drawPart->radius);
395
396          glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
397          drawPart = drawPart->next;
398        }
399      glEnd();
400      break;
401    }
402  glPopAttrib();
403}
404
405/**
406   \brief adds a new Particle to the System
407   \param position the position where the particle gets emitted.
408   \param velocity the Starting velocity of the particle.
409   \param data some more data given by the emitter
410*/
411void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, unsigned int data)
412{
413  if (this->count <= this->maxCount)
414    {
415      // if it is the first Particle
416      if (unlikely(particles == NULL))
417        {
418          if (likely(deadList != NULL))
419            {
420              this->particles = this->deadList;
421              deadList = deadList->next;
422            }
423          else
424            {
425              PRINTF(5)("Generating new Particle\n");
426              this->particles = new Particle;
427            }
428          this->particles->next = NULL;
429        }
430      // filling the List from the beginning
431      else
432        {
433          Particle* tmpPart;
434          if (likely(deadList != NULL))
435            {
436              tmpPart = this->deadList;
437              deadList = deadList->next;
438            }
439          else
440            {
441              PRINTF(5)("Generating new Particle\n");
442              tmpPart = new Particle;
443            }
444          tmpPart->next = this->particles;
445          this->particles = tmpPart;
446        }
447     
448      particles->lifeTime = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
449      particles->lifeCycle = 0.0;
450      particles->position = position;
451      particles->velocity = velocity;
452
453      //  particle->rotation = ; //! \todo rotation is once again something to be done.
454      particles->mass = this->initialMass + (rand()/RAND_MAX -.5)* this->randomInitialMass;
455      particles->radius = this->startRadius + (rand()/RAND_MAX-.5)*this->randomStartRadius;
456     
457      particles->radiusIt = (this->endRadius + (rand()/RAND_MAX-.5)*this->randomEndRadius - particles->radius) / particles->lifeTime;
458
459      ++this->count;
460    }
461  else
462    PRINTF(5)("maximum count of particles reached not adding any more\n");
463}
464
465/**
466   \brief outputs some nice debug information
467*/
468void ParticleSystem::debug(void)
469{
470  PRINT(0)("  ParticleSystem %s\n", this->name);
471  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
472  if (deadList)
473    {
474      PRINT(0)("  - ParticleDeadList is used: ");
475      int i = 1;
476      Particle* tmpPart = this->deadList;
477      while (tmpPart = tmpPart->next) ++i;
478      PRINT(0)("count: %d\n", i);
479    }
480}
Note: See TracBrowser for help on using the repository browser.