/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_PARTICLE #include "particle_system.h" #include "particle_emitter.h" #include "particle_engine.h" #include "compiler.h" #include "material.h" using namespace std; /** \brief standard constructor \param count the Count of particles in the System \param type The Type of the ParticleSystem \todo this constructor is not jet implemented - do it */ ParticleSystem::ParticleSystem (unsigned int maxCount, PARTICLE_TYPE type) { this->setClassName ("ParticleSystem"); this->name = NULL; this->maxCount = maxCount; this->count = 0; this->particleType = type; this->particles = NULL; this->setConserve(.8); this->setLifeSpan(.1); this->setInheritSpeed(0); this->glID = NULL; this->setRadius(1.0, 1.0, 0.0); this->setType(PARTICLE_SPRITE, 1); ParticleEngine::getInstance()->addSystem(this); } /** \brief standard deconstructor */ ParticleSystem::~ParticleSystem() { // delete what has to be deleted here ParticleEngine::getInstance()->removeSystem(this); } /** \brief sets the Name of the Particle System \param name the Name of the System */ void ParticleSystem::setName(const char* name) { if (this->name) delete this->name; this->name = new char[strlen(name)+1]; strcpy(this->name, name); } /** \returns the Name of the ParticleSystem */ const char* ParticleSystem::getName(void) const { return this->name; } /** \todo this will be different */ void ParticleSystem::setType(PARTICLE_TYPE particleType, int count) { this->particleType = particleType; this->dialectCount = count; if (glID != NULL) delete glID; glID = new GLuint[count]; for (int i = 0; i< count; i++) glID[i] = 0; glID[0] = glGenLists(count); material = new Material("transperencyMap"); material->setDiffuseMap("pictures/radialTransparency.png"); // material->setTransparency(.5); glNewList(glID[0], GL_COMPILE); glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(1, 1); glVertex3f(0.0, .5, .5); glTexCoord2f(1, 0); glVertex3f(0.0, -.5, .5); glTexCoord2f(0, 1); glVertex3f(0.0, .5, -.5); glTexCoord2f(0, 0); glVertex3f(0.0, -.5, -.5); glEnd(); glEndList(); } // setting properties void ParticleSystem::setMaterial(Material* material) { this->material = material; } /** \brief how much of the speed from the ParticleEmitter should flow onto the ParticleSystem \param value a Value between zero and one if you want to change the value of this variable during emission time (to make it more dynamic) you may want to use the animation class */ void ParticleSystem::setInheritSpeed(float value) { if (unlikely(value > 1.0)) this->inheritSpeed = 1; else if (unlikely(value < 0.0)) this->inheritSpeed = 0; else this->inheritSpeed = value; } /** \brief Sets the lifespan of newly created particles */ void ParticleSystem::setLifeSpan(float lifeSpan, float randomLifeSpan) { this->lifeSpan = lifeSpan; this->randomLifeSpan = randomLifeSpan; } /** \brief sets the radius of newly created particles */ void ParticleSystem::setRadius(float startRadius, float endRadius, float randomStartRadius, float randomEndRadius) { this->startRadius = startRadius; this->endRadius = endRadius; this->randomStartRadius = randomStartRadius; this->randomEndRadius = randomEndRadius; } /** \brief sets the conserve Factor of newly created particles */ void ParticleSystem::setConserve(float conserve) { if (conserve > 1.0) this->conserve = 1.0; else if (conserve < 0.0) this->conserve = 0.0; else this->conserve = conserve; } /** \brief ticks the system. \param dt the time to tick all the Particles of the System this is used to get all the particles some motion */ void ParticleSystem::tick(float dt) { Particle* tickPart = particles; // the particle to Tick Particle* prevPart = NULL; // while (likely(tickPart != NULL)) { tickPart->position = tickPart->position + tickPart->velocity; tickPart->radius += tickPart->radiusIt * dt; // many more to come if (this->conserve < 1.0) tickPart->velocity = tickPart->velocity * this->conserve; // find out if we have to delete tickPart if ((tickPart->timeToLive -= dt) <= 0) { // remove the particle from the list if (likely(prevPart != NULL)) { prevPart->next = tickPart->next; delete tickPart; tickPart = prevPart->next; } else { prevPart = NULL; this->particles = tickPart->next; delete tickPart; tickPart = this->particles; } --this->count; } else { prevPart = tickPart; tickPart = tickPart->next; } } } /** \brief draws all the Particles of this System */ void ParticleSystem::draw(void) { // material->select(); glMatrixMode(GL_MODELVIEW); // glDisable(GL_LIGHTING); material->select(); Particle* drawPart = particles; if (likely(drawPart != NULL)) { glBegin(GL_POINTS); while (likely(drawPart != NULL)) { // draw in DOT mode glPushMatrix(); glTranslatef(drawPart->position.x, drawPart->position.y, drawPart->position.z); glScalef(drawPart->radius, drawPart->radius, drawPart->radius); glCallList(*this->glID); // glVertex3f(drawPart->position.x, drawPart->position.y, drawPart->position.z); drawPart = drawPart->next; glPopMatrix(); } glEnd(); } } /** \brief adds a new Particle to the System \param position the position where the particle gets emitted. \param velocity the Starting velocity of the particle. \param data some more data given by the emitter */ void ParticleSystem::addParticle(const Vector& position, const Vector& velocity, unsigned int data) { if (this->count <= this->maxCount) { // if it is the first Particle if (unlikely(particles == NULL)) { this->particles = new Particle; this->particles->next = NULL; } // filling the List from the beginning else { Particle* tmpPart = new Particle; tmpPart->next = this->particles; this->particles = tmpPart; } particles->timeToLive = this->lifeSpan + (float)(random()/RAND_MAX)* this->randomLifeSpan; particles->position = position; particles->velocity = velocity; // particle->rotation = ; //! \todo rotation is once again something to be done. particles->mass = this->initialMass + (random()/RAND_MAX -.5)* this->randomInitialMass; particles->radius = this->startRadius + (random()/RAND_MAX-.5)*this->randomStartRadius; particles->radiusIt = (this->endRadius + (random()/RAND_MAX-.5)*this->randomEndRadius - particles->radius) / particles->timeToLive; ++this->count; } else PRINTF(4)("maximum count of particles reached not adding any more\n"); } /** \brief outputs some nice debug information */ void ParticleSystem::debug(void) { PRINT(0)(" ParticleSystem %s\n", this->name); PRINT(0)(" ParticleCount: %d, maximumCount: %d :: filled %d%%\n", this->count, this->maxCount, 100*this->count/this->maxCount); }