Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/physics: particles get rendered with facing toward Camera (in PARTICLE_SPRITE-mode)

File size: 10.9 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#include "compiler.h"
23#include "material.h"
24
25#include "field.h"
26
27// needed to find the Position of the Camera
28#include "world.h"
29#include "camera.h"
30
31using namespace std;
32
33/**
34   \brief standard constructor
35   \param count the Count of particles in the System
36   \param type The Type of the ParticleSystem
37
38   \todo this constructor is not jet implemented - do it
39*/
40ParticleSystem::ParticleSystem (unsigned int maxCount, PARTICLE_TYPE type)
41{
42  this->setClassName ("ParticleSystem");
43  this->material = NULL;
44  this->name = NULL;
45  this->maxCount = maxCount;
46  this->count = 0;
47  this->particles = NULL;
48  this->deadList = NULL;
49  this->setConserve(1);
50  this->setLifeSpan(1);
51  this->setInheritSpeed(0);
52  this->glID = NULL;
53  this->setRadius(1.0, 1.0, 0.0);
54  this->setType(type, 1);
55  ParticleEngine::getInstance()->addSystem(this);
56}
57
58
59/**
60   \brief standard deconstructor
61*/
62ParticleSystem::~ParticleSystem()
63{
64  // delete what has to be deleted here
65   ParticleEngine::getInstance()->removeSystem(this);
66
67   // deleting all the living Particles
68   while (this->particles)
69     {
70       Particle* tmpDelPart = this->particles;
71       this->particles = this->particles->next;
72       delete tmpDelPart;
73     }
74
75   // deleting all the dead particles
76   while (this->deadList)
77     {
78       Particle* tmpDelPart = this->deadList;
79       this->deadList = this->deadList->next;
80       delete tmpDelPart;
81     }
82
83   if (this->material)
84     delete this->material;
85}
86
87/**
88   \brief sets the Name of the Particle System
89   \param name the Name of the System
90*/
91void ParticleSystem::setName(const char* name)
92{
93  if (this->name)
94    delete this->name;
95  this->name = new char[strlen(name)+1];
96  strcpy(this->name, name);
97}
98
99/**
100   \returns the Name of the ParticleSystem
101*/
102const char* ParticleSystem::getName(void) const
103{
104  return this->name;
105}
106
107/**
108   \todo this will be different
109*/
110void ParticleSystem::setType(PARTICLE_TYPE particleType, int count)
111{
112  this->particleType = particleType;
113  this->dialectCount = count;
114  if (glID != NULL)
115    delete glID;
116
117  glID = new GLuint[count];
118  for (int i = 0; i< count; i++)
119    glID[i] = 0;
120
121  glID[0] = glGenLists(count);
122 
123  material = new Material("transperencyMap");
124  material->setDiffuseMap("pictures/radialTransparency.png");
125  //  material->setTransparency(.5);
126
127  glNewList(glID[0], GL_COMPILE);
128  glBegin(GL_TRIANGLE_STRIP);
129  glTexCoord2f(1, 1);
130  glVertex3f(0.0, .5, .5);
131  glTexCoord2f(1, 0);
132  glVertex3f(0.0, -.5, .5);
133  glTexCoord2f(0, 1);
134  glVertex3f(0.0, .5, -.5);
135  glTexCoord2f(0, 0);
136  glVertex3f(0.0, -.5, -.5);
137  glEnd();
138  glEndList();
139}
140
141// setting properties
142void ParticleSystem::setMaterial(Material* material)
143{
144  this->material = material;
145}
146
147
148
149/**
150   \brief how much of the speed from the ParticleEmitter should flow onto the ParticleSystem
151   \param value a Value between zero and one
152
153   
154   if you want to change the value of this variable during emission time (to make it more dynamic)
155   you may want to use the animation class
156*/
157void ParticleSystem::setInheritSpeed(float value)
158{
159  if (unlikely(value > 1.0))
160    this->inheritSpeed = 1;
161  else if (unlikely(value < 0.0))
162    this->inheritSpeed = 0;
163  else
164    this->inheritSpeed = value;
165}
166
167/**
168   \brief 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   \brief sets the radius of newly created particles
178*/
179void ParticleSystem::setRadius(float startRadius, float endRadius, float randomStartRadius, float randomEndRadius)
180{
181  this->startRadius = startRadius;
182  this->endRadius = endRadius;
183  this->randomStartRadius = randomStartRadius;
184  this->randomEndRadius = randomEndRadius;
185}
186
187/**
188   \brief sets the conserve Factor of newly created particles
189*/
190void ParticleSystem::setConserve(float conserve)
191{
192  if (conserve > 1.0)
193    this->conserve = 1.0;
194  else if (conserve < 0.0)
195    this->conserve = 0.0;
196  else
197    this->conserve = conserve;
198}
199
200/**
201   \brief ticks the system.
202   \param dt the time to tick all the Particles of the System
203
204   this is used to get all the particles some motion
205*/
206void ParticleSystem::tick(float dt)
207{
208  Particle* tickPart = particles;  // the particle to Tick
209  Particle* prevPart = NULL;       //
210  while (likely(tickPart != NULL))
211    {
212      tickPart->position = tickPart->position + tickPart->velocity;
213      tickPart->radius += tickPart->radiusIt * dt;
214
215      // applying force to the System.
216      tickPart->velocity += tickPart->extForce * tickPart->mass;
217      tickPart->extForce = Vector(0,0,0);
218
219      // many more to come
220
221      if (this->conserve < 1.0)
222        tickPart->velocity = tickPart->velocity * this->conserve;
223      // find out if we have to delete tickPart
224      if ((tickPart->timeToLive -= dt) <= 0)
225        {
226          // remove the particle from the list
227          if (likely(prevPart != NULL))
228            {
229              prevPart->next = tickPart->next;
230              tickPart->next = this->deadList;
231              this->deadList = tickPart;
232              tickPart = prevPart->next;
233            }
234          else
235            {
236              prevPart = NULL;
237              this->particles = tickPart->next;
238              tickPart->next = this->deadList;
239              this->deadList = tickPart;
240              tickPart = this->particles;
241            }
242          --this->count;
243        }
244      else
245        {     
246          prevPart = tickPart;
247          tickPart = tickPart->next;
248        }
249    }
250}
251
252/**
253    \brief applies some force to a Particle.
254 */
255void ParticleSystem::applyField(float dt, Field* field)
256{
257  Particle* tickPart = particles;
258  while (tickPart)
259    {
260      tickPart->extForce += field->calcForce(dt, tickPart->position);
261      tickPart = tickPart->next;
262    }
263}
264
265
266/**
267   \brief draws all the Particles of this System
268   \param the time passed in seconds (since the last draw)
269*/
270void ParticleSystem::draw(float dt)
271{
272  glPushAttrib(GL_ENABLE_BIT);
273  //  material->select();
274  Particle* drawPart = particles;
275
276  switch (this->particleType)
277    {
278    case PARTICLE_SPRITE:
279      GLdouble projMat[16];
280      GLfloat drawPartPos[4];
281      glGetDoublev(GL_PROJECTION_MATRIX, projMat);
282     
283      glMatrixMode(GL_MODELVIEW);
284      glDisable(GL_DEPTH_TEST);
285      glDisable(GL_LIGHTING);
286           material->select(); 
287     
288
289      while (likely(drawPart != NULL))
290        {
291          //! \todo implement a faster code for the look-at Camera algorithm.
292
293          Camera* camera = WorldInterface::getInstance()->getCurrentWorld()->getLocalCamera();
294          Vector cameraPos = camera->getAbsCoor();
295          Vector cameraTargetPos = camera->getTarget()->getAbsCoor();
296          Vector view = cameraTargetPos - cameraPos;
297          Vector up = Vector(0, 1, 0);
298          up = camera->getAbsDir().apply(up);
299          Vector h = up.cross(view);
300          Vector v = h.cross(view);
301          h.normalize();
302          v.normalize();
303          v *= .5 * drawPart->radius;
304          h *= .5 * drawPart->radius;
305
306          glBegin(GL_TRIANGLE_STRIP);
307          glTexCoord2i(1, 1);
308          glVertex3f(drawPart->position.x - h.x - v.x,
309                     drawPart->position.y - h.y - v.y,
310                     drawPart->position.z - h.z - v.z);
311          glTexCoord2i(0, 1);
312          glVertex3f(drawPart->position.x - h.x + v.x,
313                     drawPart->position.y - h.y + v.y,
314                     drawPart->position.z - h.z + v.z);
315          glTexCoord2i(1, 0);
316          glVertex3f(drawPart->position.x + h.x - v.x,
317                     drawPart->position.y + h.y - v.y,
318                     drawPart->position.z + h.z - v.z);
319          glTexCoord2i(0, 0);
320          glVertex3f(drawPart->position.x + h.x + v.x,
321                     drawPart->position.y + h.y + v.y,
322                     drawPart->position.z + h.z + v.z);
323
324          glEnd();
325 
326          drawPart = drawPart->next;
327        }
328      glEnable(GL_LIGHTING);
329      glEnable(GL_DEPTH_TEST);
330
331     
332      break;
333    default:
334
335    case PARTICLE_SPARK:
336      glEnable(GL_LINE_SMOOTH);
337      glBegin(GL_LINES);
338      while (likely(drawPart != NULL))
339        {
340          glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
341          glVertex3f(drawPart->position.x - drawPart->velocity.x,
342                     drawPart->position.y - drawPart->velocity.y,
343                     drawPart->position.z - drawPart->velocity.z);
344          drawPart = drawPart->next;
345        }
346      glEnd();
347      break;
348     
349    case PARTICLE_DOT:
350      glBegin(GL_POINTS);
351      while (likely(drawPart != NULL))
352        {
353          glLineWidth(drawPart->radius);
354
355          glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z);
356          drawPart = drawPart->next;
357        }
358      glEnd();
359      break;
360    }
361  glPopAttrib();
362}
363
364/**
365   \brief adds a new Particle to the System
366   \param position the position where the particle gets emitted.
367   \param velocity the Starting velocity of the particle.
368   \param data some more data given by the emitter
369*/
370void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, unsigned int data)
371{
372  if (this->count <= this->maxCount)
373    {
374      // if it is the first Particle
375      if (unlikely(particles == NULL))
376        {
377          if (likely(deadList != NULL))
378            {
379              this->particles = this->deadList;
380              deadList = deadList->next;
381            }
382          else
383            {
384              PRINTF(5)("Generating new Particle\n");
385              this->particles = new Particle;
386            }
387          this->particles->next = NULL;
388        }
389      // filling the List from the beginning
390      else
391        {
392          Particle* tmpPart;
393          if (likely(deadList != NULL))
394            {
395              tmpPart = this->deadList;
396              deadList = deadList->next;
397            }
398          else
399            {
400              PRINTF(5)("Generating new Particle\n");
401              tmpPart = new Particle;
402            }
403          tmpPart->next = this->particles;
404          this->particles = tmpPart;
405        }
406     
407      particles->timeToLive = this->lifeSpan + (float)(rand()/RAND_MAX)* this->randomLifeSpan;
408      particles->position = position;
409      particles->velocity = velocity;
410
411      //  particle->rotation = ; //! \todo rotation is once again something to be done.
412      particles->mass = this->initialMass + (rand()/RAND_MAX -.5)* this->randomInitialMass;
413      particles->radius = this->startRadius + (rand()/RAND_MAX-.5)*this->randomStartRadius;
414     
415      particles->radiusIt = (this->endRadius + (rand()/RAND_MAX-.5)*this->randomEndRadius - particles->radius) / particles->timeToLive;
416
417      ++this->count;
418    }
419  else
420    PRINTF(5)("maximum count of particles reached not adding any more\n");
421}
422
423/**
424   \brief outputs some nice debug information
425*/
426void ParticleSystem::debug(void)
427{
428  PRINT(0)("  ParticleSystem %s\n", this->name);
429  PRINT(0)("  ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount);
430  if (deadList)
431    {
432      PRINT(0)("  - ParticleDeadList is used: ");
433      int i = 1;
434      Particle* tmpPart = this->deadList;
435      while (tmpPart = tmpPart->next) ++i;
436      PRINT(0)("count: %d\n", i);
437    }
438}
Note: See TracBrowser for help on using the repository browser.