ParticleEngine.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <graph/ParticleEngine.h>
00022 #include <graph/OptionsDisplay.h>
00023 #include <common/OptionsTransient.h>
00024 #include <client/ScorchedClient.h>
00025 #include <GLEXT/GLState.h>
00026 #include <GLEXT/GLCamera.h>
00027 #include <algorithm>
00028 
00029 float ParticleEngine::speed_ = 1.0f;
00030 
00031 ParticleEngine::ParticleEngine(GLCamera *camera, 
00032         unsigned int maxParticles) :
00033         GameStateI("ParticleEngine"),
00034         camera_(camera),
00035         particlesOnScreen_(0), particles_(0), 
00036         freeParticles_(0), usedParticles_(0),
00037         totalTime_(0.0f), allowSorting_(true)
00038 {
00039         setMaxParticles(maxParticles);
00040 }
00041 
00042 ParticleEngine::~ParticleEngine()
00043 {
00044         delete [] particles_;
00045         delete [] freeParticles_;
00046         delete [] usedParticles_;
00047         particles_ = 0;
00048         freeParticles_ = 0;
00049         usedParticles_ = 0;
00050 }
00051 
00052 void ParticleEngine::setMaxParticles(unsigned int maxParticles)
00053 {
00054         maxParticles_ = maxParticles;
00055         delete [] particles_;
00056         delete [] freeParticles_;
00057         delete [] usedParticles_;
00058         freeParticles_ = new Particle*[maxParticles];
00059         particles_  = new Particle[maxParticles];
00060         usedParticles_ = new Particle*[maxParticles];
00061 
00062         killAll();
00063 }
00064 
00065 unsigned int ParticleEngine::getMaxParticles()
00066 {
00067         return maxParticles_;
00068 }
00069 
00070 unsigned int ParticleEngine::getParticlesOnScreen()
00071 {
00072         return particlesOnScreen_;
00073 }
00074 
00075 void ParticleEngine::killAll()
00076 {
00077         for (unsigned int i=0; i<maxParticles_; i++)
00078         {
00079                 Particle &particle = particles_[i];
00080                 particle.engine_ = this;
00081                 if (particle.life_ > 0.0f)
00082                 {
00083                         if (particle.renderer_)
00084                         {
00085                                 particle.renderer_->recycleParticle(particle);
00086                         }
00087 
00088                         particle.unsetParticle();
00089                         particle.life_ = -1.0f;
00090                 }
00091 
00092                 freeParticles_[i] = &particles_[i];
00093         }
00094         particlesOnScreen_ = 0;
00095 }
00096 
00097 void ParticleEngine::draw(const unsigned state)
00098 {
00099         if (OptionsDisplay::instance()->getNoDrawParticles()) return;
00100 
00101         GLState glstate(GLState::TEXTURE_ON | GLState::BLEND_ON | GLState::DEPTH_ON);
00102         glDepthMask(GL_FALSE);
00103         
00104         for (unsigned int i=0; i<particlesOnScreen_; i++)
00105         {
00106                 Particle *particle = usedParticles_[i];
00107                 if (particle->renderer_ &&
00108                         particle->simulated_)
00109                 {
00110                         particle->renderer_->renderParticle(*particle);
00111                 }
00112         }
00113 
00114         glDepthMask(GL_TRUE);
00115 }
00116 
00117 static inline bool lt_distance(Particle *o1, Particle *o2) 
00118 { 
00119         return o1->distance_ > o2->distance_;
00120 }
00121 
00122 static inline float approx_distance(float  dx, float dy, float dz, float w)
00123 {
00124         float approx = (dx * dx) + (dy * dy) + (dz * dz);
00125         return approx;
00126 }
00127 
00128 void ParticleEngine::simulate(const unsigned state, float time)
00129 {
00130         if (speed_ != 1.0f) time *= speed_;
00131 
00132         const float StepTime = 0.05f;
00133         totalTime_ += time;
00134         while (totalTime_ > StepTime)
00135         {
00136                 totalTime_ -= StepTime;
00137                 normalizedSimulate(StepTime);
00138         }
00139 }
00140 
00141 void ParticleEngine::normalizedSimulate(float time)
00142 {
00143         Vector momentum;
00144         Vector &cameraPos = camera_->getCurrentPos();
00145 
00146         unsigned int currentParticles = particlesOnScreen_;
00147         unsigned int putPos = 0;
00148         for (unsigned int i=0; i<currentParticles; i++)
00149         {
00150                 Particle *particle = usedParticles_[i];
00151 
00152                 particle->life_ -= time;
00153                 if (particle->life_ > 0.0f)
00154                 {
00155                         particle->simulated_ = true;
00156                         momentum = particle->velocity_ * particle->mass_;
00157 
00158                         //update the particle's position
00159                         particle->position_ += momentum * time;
00160                         
00161                         //interpolate the color, alpha value, and size
00162                         particle->color_ += particle->colorCounter_ * time;
00163                         particle->alpha_ += particle->alphaCounter_ * time;
00164                         particle->size_ += particle->sizeCounter_ * time;
00165                         particle->percent_ += particle->percentCounter_ * time;
00166 
00167                         // now its time for the external forces to take their toll
00168                         particle->velocity_ *= 1.0f - (particle->friction_ * time);
00169                         particle->velocity_ += particle->gravity_ * time * time;
00170 
00171                         // Wind
00172                         if (particle->windAffect_)
00173                         {
00174                                 particle->velocity_ += ScorchedClient::instance()->getOptionsTransient().getWindDirection().asVector() * 
00175                                         ScorchedClient::instance()->getOptionsTransient().getWindSpeed().asFloat() * 80.0f * time * time;
00176                         }
00177 
00178                         // Simulate the particle
00179                         if (particle->renderer_ && 
00180                                 !OptionsDisplay::instance()->getNoSimulateParticles())
00181                         {
00182                                 particle->renderer_->simulateParticle(*particle, time);
00183                         }
00184                         particle->distance_ = approx_distance(
00185                                 cameraPos[0] - particle->position_[0],
00186                                 cameraPos[1] - particle->position_[1],
00187                                 cameraPos[2] - particle->position_[2],
00188                                 particle->size_[0]);
00189 
00190                         usedParticles_[putPos] = particle;
00191                         putPos++;
00192                 }
00193                 else
00194                 {
00195                         if (particle->renderer_)
00196                         {
00197                                 particle->renderer_->recycleParticle(*particle);
00198                         }
00199 
00200                         particlesOnScreen_--;
00201                         freeParticles_[particlesOnScreen_] = particle;
00202                         particle->unsetParticle();
00203                 }
00204         }
00205 
00206         if (allowSorting_ &&
00207                 !OptionsDisplay::instance()->getNoDepthSorting() &&
00208                 particlesOnScreen_ > 0)
00209         {
00210                 // sort by distance
00211                 std::sort(usedParticles_, usedParticles_ + particlesOnScreen_, lt_distance);
00212         }
00213 }
00214 
00215 Particle *ParticleEngine::getNextAliveParticle()
00216 {
00217         Particle *particle = 0;
00218         if (particlesOnScreen_ < maxParticles_)
00219         {
00220                 particle = freeParticles_[particlesOnScreen_];
00221                 usedParticles_[particlesOnScreen_] = particle;
00222                 particlesOnScreen_ ++;  
00223         }
00224 
00225         return particle;
00226 }
00227 

Generated on Mon Feb 16 15:14:46 2009 for Scorched3D by  doxygen 1.5.3