352 lines
12 KiB
C++
352 lines
12 KiB
C++
|
/*
|
||
|
* Explosion.cpp
|
||
|
*
|
||
|
* Created on: 05.01.2011
|
||
|
* Author: gmueller
|
||
|
*/
|
||
|
|
||
|
#include "Explosion.h"
|
||
|
|
||
|
using namespace SPK;
|
||
|
using namespace SPK::GL;
|
||
|
|
||
|
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<System*>::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<System*>::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;
|
||
|
}
|
||
|
}
|