00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00159 particle->position_ += momentum * time;
00160
00161
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
00168 particle->velocity_ *= 1.0f - (particle->friction_ * time);
00169 particle->velocity_ += particle->gravity_ * time * time;
00170
00171
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
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
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