//////////////////////////////////////////////////////////////////////////////////
// SPARK Irrlicht Rendering library //
// Copyright (C) 2008-2011 //
// Julien Fryer -
julienfryer@gmail.com //
// Thibault Lescoat - info-tibo <at> orange <dot> fr //
// //
// //
// This software is provided 'as-is', without any express or implied //
// warranty. In no event will the authors be held liable for any damages //
// arising from the use of this software. //
// //
// Permission is granted to anyone to use this software for any purpose, //
// including commercial applications, and to alter it and redistribute it //
// freely, subject to the following restrictions: //
// //
// 1. The origin of this software must not be misrepresented; you must not //
// claim that you wrote the original software. If you use this software //
// in a product, an acknowledgment in the product documentation would be //
// appreciated but is not required. //
// 2. Altered source versions must be plainly marked as such, and must not be //
// misrepresented as being the original software. //
// 3. This notice may not be removed or altered from any source distribution. //
//////////////////////////////////////////////////////////////////////////////////
// external libs
#include <irrlicht.h>
#include <time.h>
// SPARK lib
#include <SPARK.h>
#include <SPARK_IRR.h>
// windows only
#ifdef _WIN32
#include <windows.h>
#endif
float angleX = 0.0f;
float angleY = 0.0f;
const float CAM_POS_Z = 3.0f;
unsigned int randomSeed = time(NULL);
template<typename T>
T random(T min,T max)
{
// optimized standard minimal
long tmp0 = 16807L * (randomSeed & 0xFFFFL);
long tmp1 = 16807L * (randomSeed >> 16);
long tmp2 = (tmp0 >> 16) + tmp1;
tmp0 = ((tmp0 & 0xFFFF)|((tmp2 & 0x7FFF) << 16)) + (tmp2 >> 15);
// correction of the error
if ((tmp0 & 0x80000000L) != 0)
tmp0 = (tmp0 + 1) & 0x7FFFFFFFL;
randomSeed = tmp0;
// find a random number in the interval
return static_cast<T>(min + ((randomSeed - 1) / 2147483646.0) * (max - min));
}
using namespace irr;
IrrlichtDevice* device = NULL;
irr::video::ITexture* explosionTexture;
irr::video::ITexture* flashTexture;
irr::video::ITexture* spark1Texture;
irr::video::ITexture* spark2Texture;
irr::video::ITexture* waveTexture;
// Creates the base system and returns its ID
SPK::Ref<SPK::System> createParticleSystem(const SPK::Vector3D& position)
{
///////////////
// Renderers //
///////////////
// smoke renderer
SPK::Ref<SPK::IRR::IRRQuadRenderer> smokeRenderer = SPK::IRR::IRRQuadRenderer::create(device);
smokeRenderer->setBlendMode(SPK::BLEND_MODE_ALPHA);
smokeRenderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false);
smokeRenderer->setTexture(explosionTexture);
smokeRenderer->setTexturingMode(SPK::TEXTURE_MODE_2D);
smokeRenderer->setAtlasDimensions(2,2);
// flame renderer
SPK::Ref<SPK::IRR::IRRQuadRenderer> flameRenderer = SPK::IRR::IRRQuadRenderer::create(device);
flameRenderer->setBlendMode(SPK::BLEND_MODE_ADD);
flameRenderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false);
flameRenderer->setTexture(explosionTexture);
flameRenderer->setTexturingMode(SPK::TEXTURE_MODE_2D);
flameRenderer->setAtlasDimensions(2,2);
// flash renderer
SPK::Ref<SPK::IRR::IRRQuadRenderer> flashRenderer = SPK::IRR::IRRQuadRenderer::create(device);
flashRenderer->setBlendMode(SPK::BLEND_MODE_ADD);
flashRenderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false);
flashRenderer->setTexture(flashTexture);
flashRenderer->setTexturingMode(SPK::TEXTURE_MODE_2D);
// spark 1 renderer
SPK::Ref<SPK::IRR::IRRQuadRenderer> spark1Renderer = SPK::IRR::IRRQuadRenderer::create(device);
spark1Renderer->setBlendMode(SPK::BLEND_MODE_ADD);
spark1Renderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false);
spark1Renderer->setTexture(spark1Texture);
spark1Renderer->setTexturingMode(SPK::TEXTURE_MODE_2D);
spark1Renderer->setOrientation(SPK::DIRECTION_ALIGNED); // sparks are oriented function o their velocity
spark1Renderer->setScale(0.05f,1.0f); // thin rectangles
// spark 2 renderer
SPK::Ref<SPK::IRR::IRRQuadRenderer> spark2Renderer = SPK::IRR::IRRQuadRenderer::create(device);
spark2Renderer->setBlendMode(SPK::BLEND_MODE_ADD);
spark2Renderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false);
spark2Renderer->setTexture(spark2Texture);
spark2Renderer->setTexturingMode(SPK::TEXTURE_MODE_2D);
spark2Renderer->setScale(0.02f,0.02f);
// wave renderer
SPK::Ref<SPK::IRR::IRRQuadRenderer> waveRenderer = SPK::IRR::IRRQuadRenderer::create(device);
waveRenderer->setBlendMode(SPK::BLEND_MODE_ALPHA);
waveRenderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false);
waveRenderer->enableRenderingOption(SPK::RENDERING_OPTION_ALPHA_TEST,true); // uses the alpha test
waveRenderer->setAlphaTestThreshold(0.0f);
waveRenderer->setTexture(waveTexture);
waveRenderer->setTexturingMode(SPK::TEXTURE_MODE_2D);
waveRenderer->setOrientation(SPK::FIXED_ORIENTATION); // the orientation 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
//////////////
// Emitters //
//////////////
// This zone will be used by several emitters
SPK::Ref<SPK::Sphere> explosionSphere = SPK::Sphere::create(SPK::Vector3D(0.0f,0.0f,0.0f),0.4f);
// smoke emitter
SPK::Ref<SPK::RandomEmitter> smokeEmitter = SPK::RandomEmitter::create();
smokeEmitter->setZone(SPK::Sphere::create(SPK::Vector3D(0.0f,0.0f,0.0f),0.6f),false);
smokeEmitter->setTank(15);
smokeEmitter->setFlow(-1);
smokeEmitter->setForce(0.02f,0.04f);
// flame emitter
SPK::Ref<SPK::NormalEmitter> flameEmitter = SPK::NormalEmitter::create();
flameEmitter->setZone(explosionSphere);
flameEmitter->setTank(15);
flameEmitter->setFlow(-1);
flameEmitter->setForce(0.06f,0.1f);
// flash emitter
SPK::Ref<SPK::StaticEmitter> flashEmitter = SPK::StaticEmitter::create();
flashEmitter->setZone(SPK::Sphere::create(SPK::Vector3D(0.0f,0.0f,0.0f),0.1f));
flashEmitter->setTank(3);
flashEmitter->setFlow(-1);
// spark 1 emitter
SPK::Ref<SPK::NormalEmitter> spark1Emitter = SPK::NormalEmitter::create();
spark1Emitter->setZone(explosionSphere);
spark1Emitter->setTank(20);
spark1Emitter->setFlow(-1);
spark1Emitter->setForce(2.0f,3.0f);
// spark 2 emitter
SPK::Ref<SPK::NormalEmitter> spark2Emitter = SPK::NormalEmitter::create();
spark2Emitter->setZone(explosionSphere);
spark2Emitter->setTank(400);
spark2Emitter->setFlow(-1);
spark2Emitter->setForce(0.4f,0.8f);
// wave emitter
SPK::Ref<SPK::StaticEmitter> waveEmitter = SPK::StaticEmitter::create();
waveEmitter->setZone(SPK::Point::create());
waveEmitter->setTank(1);
waveEmitter->setFlow(-1);
////////////
// System //
////////////
SPK::Ref<SPK::System> system = SPK::System::create(false);
////////////
// Groups //
////////////
// smoke group
SPK::Ref<SPK::Group> smokeGroup = system->createGroup(15);
smokeGroup->addEmitter(smokeEmitter);
smokeGroup->addModifier(SPK::Gravity::create(SPK::Vector3D(0.0f,0.05f,0.0f)));
smokeGroup->setRenderer(smokeRenderer);
smokeGroup->setLifeTime(2.5f,3.0f);
smokeGroup->setParamInterpolator(SPK::PARAM_SCALE,SPK::FloatRandomInterpolator::create(0.6f,0.8f,1.0f,1.4f));
smokeGroup->setParamInterpolator(SPK::PARAM_ANGLE,SPK::FloatRandomInterpolator::create(0.0f,irr::core::PI * 0.5f,0.0f,irr::core::PI * 0.5f));
smokeGroup->setParamInterpolator(SPK::PARAM_TEXTURE_INDEX,SPK::FloatRandomInitializer::create(0.0f,4.0f));
SPK::Ref<SPK::ColorGraphInterpolator> smokeColorInterpolator = SPK::ColorGraphInterpolator::create();
smokeColorInterpolator->addEntry(0.0f,SPK::Color(51,51,51,0));
smokeColorInterpolator->addEntry(0.4f,SPK::Color(51,51,51,102),SPK::Color(51,51,51,153));
smokeColorInterpolator->addEntry(0.6f,SPK::Color(51,51,51,102),SPK::Color(51,51,51,153));
smokeColorInterpolator->addEntry(1.0f,SPK::Color(51,51,51,0));
smokeGroup->setColorInterpolator(smokeColorInterpolator);
// flame group
SPK::Ref<SPK::Group> flameGroup = system->createGroup(15);
flameGroup->addEmitter(flameEmitter);
flameGroup->setRenderer(flameRenderer);
flameGroup->setLifeTime(1.5f,2.0f);
flameGroup->setParamInterpolator(SPK::PARAM_ANGLE,SPK::FloatRandomInterpolator::create(0.0f,irr::core::PI * 0.5f,0.0f, irr::core::PI * 0.5f));
flameGroup->setParamInterpolator(SPK::PARAM_TEXTURE_INDEX,SPK::FloatRandomInitializer::create(0.0f,4.0f));
SPK::Ref<SPK::FloatGraphInterpolator> flameSizeInterpolator = SPK::FloatGraphInterpolator::create();
flameSizeInterpolator->addEntry(0.0f,0.25f);
flameSizeInterpolator->addEntry(0.02f,0.6f,0.8f);
flameSizeInterpolator->addEntry(1.0f,1.0f,1.4f);
flameGroup->setParamInterpolator(SPK::PARAM_SCALE,flameSizeInterpolator);
SPK::Ref<SPK::ColorGraphInterpolator> flameColorInterpolator = SPK::ColorGraphInterpolator::create();
flameColorInterpolator->addEntry(0.0f,SPK::Color(255,128,51,255));
flameColorInterpolator->addEntry(0.5f,SPK::Color(153,89,51,255));
flameColorInterpolator->addEntry(1.0f,SPK::Color(51,51,51,0));
flameGroup->setColorInterpolator(flameColorInterpolator);
// flash group
SPK::Ref<SPK::Group> flashGroup = system->createGroup(3);
flashGroup->addEmitter(flashEmitter);
flashGroup->setRenderer(flashRenderer);
flashGroup->setLifeTime(0.5f,0.5f);
flashGroup->setParamInterpolator(SPK::PARAM_ANGLE,SPK::FloatRandomInitializer::create(0.0f,2.0f * irr::core::PI));
SPK::Ref<SPK::ColorGraphInterpolator> flashColorInterpolator = SPK::ColorGraphInterpolator::create();
flashColorInterpolator->addEntry(0.0f,SPK::Color(255,255,255,255));
flashColorInterpolator->addEntry(0.4f,SPK::Color(255,255,255,0));
flashGroup->setColorInterpolator(flashColorInterpolator);
SPK::Ref<SPK::FloatGraphInterpolator> flashSizeInterpolator = SPK::FloatGraphInterpolator::create();
flashSizeInterpolator->addEntry(0.0f,0.25f);
flashSizeInterpolator->addEntry(0.1f,1.0f,2.0f);
flashGroup->setParamInterpolator(SPK::PARAM_SCALE,flashSizeInterpolator);
// spark 1 group
SPK::Ref<SPK::Group> spark1Group = system->createGroup(20);
spark1Group->addEmitter(spark1Emitter);
spark1Group->addModifier(SPK::Gravity::create(SPK::Vector3D(0.0f,-1.5f,0.0f)));
spark1Group->setRenderer(spark1Renderer);
spark1Group->setLifeTime(0.2f,1.0f);
spark1Group->setParamInterpolator(SPK::PARAM_SCALE,SPK::FloatRandomInitializer::create(0.2f,0.4f));
spark1Group->setColorInterpolator(SPK::ColorSimpleInterpolator::create(SPK::Color(255,255,255,255),SPK::Color(255,255,255,0)));
// spark 2 group
SPK::Ref<SPK::Group> spark2Group = system->createGroup(400);
spark2Group->addEmitter(spark2Emitter);
spark2Group->addModifier(SPK::Gravity::create(SPK::Vector3D(0.0f,-0.3f,0.0f)));
spark2Group->addModifier(SPK::Friction::create(0.4f));
spark2Group->setRenderer(spark2Renderer);
spark2Group->setLifeTime(1.0f,3.0f);
spark2Group->setColorInterpolator(SPK::ColorRandomInterpolator::create(SPK::Color(255,255,179,255),SPK::Color(255,255,179,255),SPK::Color(255,77,77,0),SPK::Color(255,255,77,0)));
// wave group
SPK::Ref<SPK::Group> waveGroup = system->createGroup(1);
waveGroup->addEmitter(waveEmitter);
waveGroup->setRenderer(waveRenderer);
waveGroup->setLifeTime(0.8f,0.8f);
waveGroup->setColorInterpolator(SPK::ColorSimpleInterpolator::create(SPK::Color(255,255,255,51),SPK::Color(255,255,255,0)));
waveGroup->setParamInterpolator(SPK::PARAM_SCALE,SPK::FloatSimpleInterpolator::create(0.0f,4.0f));
// Finalize
system->initialize();
return system;
}
// Input Receiver
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(const SEvent& event)
{
if(event.EventType==EET_KEY_INPUT_EVENT)
{
if(event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown==false)
{
device->closeDevice();
}
else if(event.KeyInput.Key == KEY_SPACE && event.KeyInput.PressedDown==false)
{
//*
SPK::Vector3D position(random(-2.0f,2.0f),random(-2.0f,2.0f),random(-2.0f,2.0f));
SPK::Ref<SPK::System> sys = createParticleSystem(position);
irr::scene::CSPKParticleSystemNode* system = new irr::scene::CSPKParticleSystemNode(sys, device->getSceneManager()->getRootSceneNode(), device->getSceneManager(),false);
system->setPosition(SPK::IRR::spk2irr(position));
system->setID(42);
system->drop(); // We let the scene manager take care of the system life time
//*/
/*
irr::scene::CSPKParticleSystemNode* system = new irr::scene::CSPKParticleSystemNode(device->getSceneManager()->getRootSceneNode(),device->getSceneManager());
system->drop(); // We let the scene manager take care of the system life time
SPK::Ref<SPK::IRR::IRRQuadRenderer> quadRenderer = SPK::IRR::IRRQuadRenderer::create(device);
quadRenderer->setBlendMode(SPK::BLEND_MODE_ADD);
quadRenderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false);
quadRenderer->setTexture(0);
quadRenderer->setTexturingMode(SPK::TEXTURE_MODE_2D);
SPK::Ref<SPK::RandomEmitter> emitter = SPK::RandomEmitter::create(SPK::Point::create());
emitter->setForce(0.4f,0.6f);
emitter->setFlow(200);
SPK::Ref<SPK::ColorGraphInterpolator> graphInterpolator = SPK::ColorGraphInterpolator::create();
graphInterpolator->addEntry(0.0f,0xFF000088);
graphInterpolator->addEntry(0.5f,0x00FF0088);
graphInterpolator->addEntry(1.0f,0x0000FF88);
SPK::Ref<SPK::Group> group = system->createSPKGroup(400);
group->setRadius(0.15f);
group->setLifeTime(1.0f,2.0f);
group->setColorInterpolator(graphInterpolator);
group->setParamInterpolator(SPK::PARAM_SCALE,SPK::FloatRandomInterpolator::create(0.8f,1.2f,0.0f,0.0f));
group->setParamInterpolator(SPK::PARAM_ANGLE,SPK::FloatRandomInitializer::create(0.0f,2 * 3.14159f));
group->addEmitter(emitter);
group->addModifier(SPK::Gravity::create(SPK::Vector3D(0.0f,-0.5f,0.0f)));
group->addModifier(SPK::Friction::create(0.2f));
group->setRenderer(quadRenderer);
//*/
}
}
return false;
}
int oldMouseX,oldMouseY;
};
// Main function
int main(int argc, char *argv[])
{
//!IRRLICHT
video::E_DRIVER_TYPE chosenDriver = video::EDT_OPENGL;
#ifdef _WIN32
if(MessageBoxA(0,"Do you want to use DirectX 9 ? (else OpenGL)","SPARK Irrlicht test",MB_YESNO | MB_ICONQUESTION) == IDYES)
chosenDriver = video::EDT_DIRECT3D9;
#endif
//!IRRLICHT
device = createDevice(chosenDriver,
core::dimension2d<u32>(800,600),
32,
false,
false,
false,
new MyEventReceiver);
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* guienv = device->getGUIEnvironment();
device->setWindowCaption(L"SPARK Irrlicht test");
device->getCursorControl()->setVisible(false);
irr::scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(smgr->getRootSceneNode(),100.0f,0.0005f);
cam->setPosition(irr::core::vector3df(2,2,2));
cam->setTarget(irr::core::vector3df(0.0f,0.0f,0.0f));
cam->setNearValue(0.05f);
cam->setFarValue(200.0f);
// Inits Particle Engine
// Sets the update step
SPK::System::setClampStep(true,0.1f); // clamp the step to 100 ms
SPK::System::useAdaptiveStep(0.001f,0.01f); // use an adaptive step from 1ms to 10ms (1000fps to 100fps)
explosionTexture = driver->getTexture("res\\explosion.bmp");
flashTexture = driver->getTexture("res\\flash.bmp");
spark1Texture = driver->getTexture("res\\spark1.bmp");
spark2Texture = driver->getTexture("res\\point.bmp");
waveTexture = driver->getTexture("res\\wave.bmp");
int frame = 0, particleCount = 0;
irr::core::aabbox3df bbox;
while(device->run())
{
frame++;
driver->beginScene(true, true, irr::video::SColor(0,0,0,0));
// Renders scene
smgr->drawAll();
irr::core::stringw infos; infos+="FPS: "; infos+=driver->getFPS(); infos += " - Polys: "; infos += driver->getPrimitiveCountDrawn(0); infos += " - Nb particles: "; infos += particleCount;
guienv->getBuiltInFont()->draw(infos.c_str(),irr::core::rect<irr::s32>(0,0,170,20),irr::video::SColor(255,255,255,255));
driver->endScene();
// Delete sleeping systems every 10 frames
if(frame % 10 == 0)
{
irr::core::list<irr::scene::ISceneNode*> nodes = smgr->getRootSceneNode()->getChildren();
for(irr::core::list<irr::scene::ISceneNode*>::Iterator it = nodes.begin(); it != nodes.end(); ++it)
if((*it)->getID() == 42)
{
irr::scene::CSPKParticleSystemNode* node = (irr::scene::CSPKParticleSystemNode*)(*it);
if(!node->isAlive())
node->remove();
}
}
else // Else update particle count
{
particleCount = 0;
irr::core::list<irr::scene::ISceneNode*> nodes = smgr->getRootSceneNode()->getChildren();
for(irr::core::list<irr::scene::ISceneNode*>::Iterator it = nodes.begin(); it != nodes.end(); ++it)
if((*it)->getID() == 42)
particleCount += ((irr::scene::CSPKParticleSystemNode*)(*it))->getNbParticles();
}
}
device->drop();
SPK_DUMP_MEMORY
return 0;
}