#include "Explosion.h" using namespace SPK; using namespace SPK::GL; namespace gln { Explosion::~Explosion() { SPKFactory::getInstance().destroyAll(); } void Explosion::initialize(GLuint textureExplosion, GLuint textureFlash, GLuint textureSpark, GLuint texturePoint, GLuint textureWave) { /////////////// // Renderers // /////////////// double scale = 50.0; // smoke renderer GLQuadRenderer* smokeRenderer = GLQuadRenderer::create(); smokeRenderer->setTexturingMode(TEXTURE_2D); smokeRenderer->setTexture(textureExplosion); smokeRenderer->setTextureBlending(GL_MODULATE); smokeRenderer->setAtlasDimensions(2, 2); // uses 4 different patterns in the texture smokeRenderer->setBlending(BLENDING_ALPHA); smokeRenderer->enableRenderingHint(DEPTH_WRITE, false); smokeRenderer->setShared(true); smokeRenderer->setScale(scale, scale); // flame renderer GLQuadRenderer* flameRenderer = GLQuadRenderer::create(); flameRenderer->setTexturingMode(TEXTURE_2D); flameRenderer->setTexture(textureExplosion); flameRenderer->setTextureBlending(GL_MODULATE); flameRenderer->setAtlasDimensions(2, 2); flameRenderer->setBlending(BLENDING_ADD); flameRenderer->enableRenderingHint(DEPTH_WRITE, false); flameRenderer->setShared(true); flameRenderer->setScale(scale, scale); // flash renderer GLQuadRenderer* flashRenderer = GLQuadRenderer::create(); flashRenderer->setTexturingMode(TEXTURE_2D); flashRenderer->setTexture(textureFlash); flashRenderer->setTextureBlending(GL_REPLACE); flashRenderer->setBlending(BLENDING_ADD); flashRenderer->enableRenderingHint(DEPTH_WRITE, false); flashRenderer->setShared(true); flashRenderer->setScale(scale, scale); // spark 1 renderer GLQuadRenderer* spark1Renderer = GLQuadRenderer::create(); spark1Renderer->setTexturingMode(TEXTURE_2D); spark1Renderer->setTexture(textureSpark); spark1Renderer->setTextureBlending(GL_REPLACE); spark1Renderer->setBlending(BLENDING_ADD); spark1Renderer->enableRenderingHint(DEPTH_WRITE, false); spark1Renderer->setOrientation(DIRECTION_ALIGNED); // sparks are oriented function o their velocity spark1Renderer->setScale(0.05f * scale, 1.0f * scale); // thin rectangles spark1Renderer->setShared(true); // spark 2 renderer GLRenderer* spark2Renderer = NULL; if (GLPointRenderer::loadGLExtPointSprite() && GLPointRenderer::loadGLExtPointParameter()) // uses point sprite if possible { //GLPointRenderer::setPixelPerUnit(45.0f * PI / 180.f, scale * 1024); GLPointRenderer* pointRenderer = GLPointRenderer::create(); pointRenderer->setType(POINT_SPRITE); pointRenderer->setTexture(texturePoint); pointRenderer->setTextureBlending(GL_MODULATE); pointRenderer->enableWorldSize(true); pointRenderer->setSize(0.02f * scale); spark2Renderer = pointRenderer; } else { GLQuadRenderer* quadRenderer = GLQuadRenderer::create(); quadRenderer->setTexturingMode(TEXTURE_2D); quadRenderer->setTexture(texturePoint); quadRenderer->setTextureBlending(GL_MODULATE); quadRenderer->setScale(0.02f * scale, 0.02f * scale); spark2Renderer = quadRenderer; } spark2Renderer->setBlending(BLENDING_ADD); spark2Renderer->enableRenderingHint(DEPTH_WRITE, false); spark2Renderer->setShared(true); // wave renderer GLQuadRenderer* waveRenderer = GLQuadRenderer::create(); waveRenderer->setTexturingMode(TEXTURE_2D); waveRenderer->setTexture(textureWave); waveRenderer->setTextureBlending(GL_MODULATE); waveRenderer->setBlending(BLENDING_ALPHA); waveRenderer->enableRenderingHint(DEPTH_WRITE, false); waveRenderer->enableRenderingHint(ALPHA_TEST, true); // uses the alpha test waveRenderer->setAlphaTestThreshold(0.0f); waveRenderer->setOrientation(FIXED_ORIENTATION); // the orientatin is fixed waveRenderer->lookVector.set(0.0f, 1.0f, 0.0f); waveRenderer->upVector.set(1.0f, 0.0f, 0.0f); // we dont really care about the up axis waveRenderer->setShared(true); waveRenderer->setScale(scale, scale); //////////// // Models // //////////// Interpolator* interpolator = NULL; // pointer to an interpolator that is used to retrieve interpolators // smoke model Model* smokeModel = Model::create( FLAG_RED | FLAG_GREEN | FLAG_BLUE | FLAG_ALPHA | FLAG_SIZE | FLAG_ANGLE | FLAG_TEXTURE_INDEX, FLAG_SIZE | FLAG_ANGLE, FLAG_SIZE | FLAG_ANGLE | FLAG_TEXTURE_INDEX, FLAG_ALPHA); smokeModel->setParam(PARAM_RED, 0.2f); smokeModel->setParam(PARAM_GREEN, 0.2f); smokeModel->setParam(PARAM_BLUE, 0.2f); smokeModel->setParam(PARAM_SIZE, 0.6f, 0.8f, 1.0f, 1.4f); smokeModel->setParam(PARAM_TEXTURE_INDEX, 0.0f, 4.0f); smokeModel->setParam(PARAM_ANGLE, 0.0f, M_PI * 0.5f, 0.0f, M_PI * 0.5f); smokeModel->setLifeTime(2.5f, 3.0f); smokeModel->setShared(true); interpolator = smokeModel->getInterpolator(PARAM_ALPHA); interpolator->addEntry(0.0f, 0.0f); interpolator->addEntry(0.4f, 0.4f, 0.6f); interpolator->addEntry(0.6f, 0.4f, 0.6f); interpolator->addEntry(1.0f, 0.0f); // flame model Model* flameModel = Model::create( FLAG_RED | FLAG_GREEN | FLAG_BLUE | FLAG_ALPHA | FLAG_SIZE | FLAG_ANGLE | FLAG_TEXTURE_INDEX, FLAG_ANGLE | FLAG_RED | FLAG_GREEN | FLAG_BLUE, FLAG_ANGLE | FLAG_TEXTURE_INDEX, FLAG_SIZE | FLAG_ALPHA); flameModel->setParam(PARAM_RED, 1.0f, 0.2f); flameModel->setParam(PARAM_GREEN, 0.5f, 0.2f); flameModel->setParam(PARAM_BLUE, 0.2f, 0.2f); flameModel->setParam(PARAM_TEXTURE_INDEX, 0.0f, 4.0f); flameModel->setParam(PARAM_ANGLE, 0.0f, M_PI * 0.5f, 0.0f, M_PI * 0.5f); flameModel->setLifeTime(1.5f, 2.0f); flameModel->setShared(true); interpolator = flameModel->getInterpolator(PARAM_SIZE); interpolator->addEntry(0.0f, 0.25f); interpolator->addEntry(0.02f, 0.6f, 0.8f); interpolator->addEntry(1.0f, 1.0f, 1.4f); interpolator = flameModel->getInterpolator(PARAM_ALPHA); interpolator->addEntry(0.5f, 1.0f); interpolator->addEntry(1.0f, 0.0f); // flash model Model* flashModel = Model::create(FLAG_ALPHA | FLAG_SIZE | FLAG_ANGLE, FLAG_NONE, FLAG_ANGLE, FLAG_ALPHA | FLAG_SIZE); flashModel->setParam(PARAM_ANGLE, 0.0f, 2.0f * M_PI); flashModel->setLifeTime(0.5f, 0.5f); flashModel->setShared(true); interpolator = flashModel->getInterpolator(PARAM_SIZE); interpolator->addEntry(0.0f, 0.25f); interpolator->addEntry(0.1f, 1.0f, 2.0f); interpolator = flashModel->getInterpolator(PARAM_ALPHA); interpolator->addEntry(0.0f, 1.0f); interpolator->addEntry(0.4f, 0.0f); // spark 1 model Model* spark1Model = Model::create(FLAG_SIZE | FLAG_ALPHA, FLAG_ALPHA, FLAG_SIZE); spark1Model->setParam(PARAM_ALPHA, 1.0f, 0.0f); spark1Model->setParam(PARAM_SIZE, 0.2f, 0.4f); spark1Model->setLifeTime(0.2f, 1.0f); spark1Model->setShared(true); // spark 2 model Model* spark2Model = Model::create( FLAG_RED | FLAG_GREEN | FLAG_BLUE | FLAG_ALPHA, FLAG_GREEN | FLAG_BLUE | FLAG_ALPHA, FLAG_GREEN); spark2Model->setParam(PARAM_ALPHA, 1.0f, 0.0f); spark2Model->setParam(PARAM_RED, 1.0f); spark2Model->setParam(PARAM_GREEN, 1.0f, 1.0f, 0.3f, 1.0f); spark2Model->setParam(PARAM_BLUE, 0.7f, 0.3f); spark2Model->setLifeTime(1.0f, 3.0f); spark2Model->setShared(true); // wave model Model* waveModel = Model::create(FLAG_ALPHA | FLAG_SIZE, FLAG_SIZE | FLAG_ALPHA); waveModel->setParam(PARAM_SIZE, 0.0f, 4.0f); waveModel->setParam(PARAM_ALPHA, 0.2f, 0.0f); waveModel->setLifeTime(0.8f, 0.8f); waveModel->setShared(true); ////////////// // Emitters // ////////////// // This zone will be used by several emitters Sphere* explosionSphere = Sphere::create(Vector3D(0.0f, 0.0f, 0.0f), 0.4f * scale); Sphere* explosionSphere2 = Sphere::create(Vector3D(0.0f, 0.0f, 0.0f), 0.4f * 2.5 * scale); // smoke emitter RandomEmitter* smokeEmitter = RandomEmitter::create(); smokeEmitter->setZone(Sphere::create(Vector3D(0.0f, 0.0f, 0.0f), 0.6f), false); smokeEmitter->setFlow(-1); smokeEmitter->setTank(1); smokeEmitter->setForce(0.02f, 10.04f); // flame emitter NormalEmitter* flameEmitter = NormalEmitter::create(); flameEmitter->setZone(explosionSphere); flameEmitter->setFlow(-1); flameEmitter->setTank(1); flameEmitter->setForce(0.06f, 10.1f); // flash emitter StaticEmitter* flashEmitter = StaticEmitter::create(); flashEmitter->setZone(Sphere::create(Vector3D(0.0f, 0.0f, 0.0f), 0.1f)); flashEmitter->setFlow(-1); flashEmitter->setTank(2); // spark 1 emitter NormalEmitter* spark1Emitter = NormalEmitter::create(); spark1Emitter->setZone(explosionSphere2); spark1Emitter->setFlow(-1); spark1Emitter->setTank(5); spark1Emitter->setForce(2.0f, 3.0f); // spark 2 emitter NormalEmitter* spark2Emitter = NormalEmitter::create(); spark2Emitter->setZone(explosionSphere); spark2Emitter->setFlow(-1); spark2Emitter->setTank(2); spark2Emitter->setForce(0.4f, 0.8f); // wave emitter StaticEmitter* waveEmitter = StaticEmitter::create(); waveEmitter->setZone(Point::create()); waveEmitter->setFlow(-1); waveEmitter->setTank(1); //////////// // Groups // //////////// // smoke group Group* smokeGroup = Group::create(smokeModel, 15); smokeGroup->addEmitter(smokeEmitter); smokeGroup->setRenderer(smokeRenderer); // flame group Group* flameGroup = Group::create(flameModel, 15); flameGroup->addEmitter(flameEmitter); flameGroup->setRenderer(flameRenderer); // flash group Group* flashGroup = Group::create(flashModel, 3); flashGroup->addEmitter(flashEmitter); flashGroup->setRenderer(flashRenderer); // spark 1 group Group* spark1Group = Group::create(spark1Model, 20); spark1Group->addEmitter(spark1Emitter); spark1Group->setRenderer(spark1Renderer); // spark 2 group Group* spark2Group = Group::create(spark2Model, 400); spark2Group->addEmitter(spark2Emitter); spark2Group->setRenderer(spark2Renderer); // wave group Group* waveGroup = Group::create(waveModel, 1); waveGroup->addEmitter(waveEmitter); waveGroup->setRenderer(waveRenderer); //////////// // System // //////////// System* system = System::create(); system->addGroup(waveGroup); system->addGroup(smokeGroup); system->addGroup(flameGroup); system->addGroup(flashGroup); system->addGroup(spark1Group); system->addGroup(spark2Group); // Gets a pointer to the base system_id = system->getSPKID(); // Sets the update step // clamp the step to 100 ms System::setClampStep(true, 0.1f); // use an adaptive step from 1ms to 10ms (1000fps to 100fps) System::useAdaptiveStep(0.001f, 0.01f); } // Renders the scene void Explosion::render() { GLRenderer::saveGLStates(); // Renders all the particle systems for (std::list::const_iterator it = particleSystems.begin(); it != particleSystems.end(); ++it) (*it)->render(); GLRenderer::restoreGLStates(); } void Explosion::add(double x, double y, double z) { Vector3D pos(x, y, z); // Creates a copy of the base system System* system = SPK_Copy(System,system_id); // Locates the system at the given position system->setTransformPosition(pos); // updates the world transform of system and its children system->updateTransform(); particleSystems.push_back(system); } // This function is used to sort the systems from front to back struct cmpDistToCamera { Vector3D camera; bool operator()(System* &system0, System* &system1) { return getSqrDist(system0->getWorldTransformPos(), camera) > getSqrDist(system1->getWorldTransformPos(), camera); } }; void Explosion::update(double dt, double cx, double cy, double cz) { cmpDistToCamera cmp; cmp.camera.x = cx; cmp.camera.y = cy; cmp.camera.z = cz; particleSystems.sort(cmp); std::list::iterator it = particleSystems.begin(); while (it != particleSystems.end()) { // Updates the particle systems if (!(*it)->update(dt * 0.001f)) { // If a system is sleeping, destroys it SPK_Destroy(*it); // And erases its entry in the container it = particleSystems.erase(it); } else ++it; } } } // namespace grln