Change from dimension2d<s32> to dimension2d<u32> where practical. IImage and ITexture now have unsigned dimensions, as does screen size. This has had a significant knock-on through the code base, but it is more technically correct - the BEST KIND of correct. GUI elements and draw2DImage methods still have and take signed dimensions, but we can look into this in future. Regression tested with the test suite and the example apps. Note that createDevice() now takes dimension2d<u32>! git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2092 dfc29bdd-3216-0410-991c-e03cc46cb475
831 lines
24 KiB
C++
831 lines
24 KiB
C++
// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt.
|
|
// This file is not documented.
|
|
|
|
#include "CDemo.h"
|
|
|
|
CDemo::CDemo(bool f, bool m, bool s, bool a, bool v, bool fsaa, video::E_DRIVER_TYPE d)
|
|
: fullscreen(f), music(m), shadows(s), additive(a), vsync(v), aa(fsaa),
|
|
driverType(d), device(0),
|
|
#ifdef USE_IRRKLANG
|
|
irrKlang(0), ballSound(0), impactSound(0),
|
|
#endif
|
|
#ifdef USE_SDL_MIXER
|
|
stream(0), ballSound(0), impactSound(0),
|
|
#endif
|
|
currentScene(-2), backColor(0), statusText(0), inOutFader(0),
|
|
quakeLevelMesh(0), quakeLevelNode(0), skyboxNode(0), model1(0), model2(0),
|
|
campFire(0), metaSelector(0), mapSelector(0), sceneStartTime(0),
|
|
timeForThisScene(0)
|
|
{
|
|
}
|
|
|
|
|
|
CDemo::~CDemo()
|
|
{
|
|
if (mapSelector)
|
|
mapSelector->drop();
|
|
|
|
if (metaSelector)
|
|
metaSelector->drop();
|
|
|
|
#ifdef USE_IRRKLANG
|
|
if (irrKlang)
|
|
irrKlang->drop();
|
|
#endif
|
|
}
|
|
|
|
|
|
void CDemo::run()
|
|
{
|
|
core::dimension2d<u32> resolution ( 800, 600 );
|
|
|
|
if ( driverType == video::EDT_BURNINGSVIDEO || driverType == video::EDT_SOFTWARE )
|
|
{
|
|
resolution.Width = 640;
|
|
resolution.Height = 480;
|
|
}
|
|
|
|
irr::SIrrlichtCreationParameters params;
|
|
params.DriverType=driverType;
|
|
params.WindowSize=resolution;
|
|
params.Bits=32;
|
|
params.Fullscreen=fullscreen;
|
|
params.Stencilbuffer=shadows;
|
|
params.Vsync=vsync;
|
|
params.AntiAlias=aa;
|
|
params.EventReceiver=this;
|
|
|
|
device = createDeviceEx(params);
|
|
if (!device)
|
|
return;
|
|
|
|
if (device->getFileSystem()->existFile("irrlicht.dat"))
|
|
device->getFileSystem()->addZipFileArchive("irrlicht.dat");
|
|
else
|
|
device->getFileSystem()->addZipFileArchive("../../media/irrlicht.dat");
|
|
if (device->getFileSystem()->existFile("map-20kdm2.pk3"))
|
|
device->getFileSystem()->addZipFileArchive("map-20kdm2.pk3");
|
|
else
|
|
device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
|
|
|
|
video::IVideoDriver* driver = device->getVideoDriver();
|
|
scene::ISceneManager* smgr = device->getSceneManager();
|
|
gui::IGUIEnvironment* guienv = device->getGUIEnvironment();
|
|
|
|
device->setWindowCaption(L"Irrlicht Engine Demo");
|
|
|
|
// set ambient light
|
|
smgr->setAmbientLight ( video::SColorf ( 0x00c0c0c0 ) );
|
|
|
|
|
|
wchar_t tmp[255];
|
|
|
|
// draw everything
|
|
|
|
s32 now = 0;
|
|
sceneStartTime = device->getTimer()->getTime();
|
|
while(device->run() && driver)
|
|
{
|
|
if (device->isWindowActive())
|
|
{
|
|
#ifdef USE_IRRKLANG
|
|
// update 3D position for sound engine
|
|
scene::ICameraSceneNode* cam = smgr->getActiveCamera();
|
|
if (cam && irrKlang)
|
|
irrKlang->setListenerPosition(cam->getAbsolutePosition(), cam->getTarget());
|
|
#endif
|
|
|
|
// load next scene if necessary
|
|
now = device->getTimer()->getTime();
|
|
if (now - sceneStartTime > timeForThisScene && timeForThisScene!=-1)
|
|
switchToNextScene();
|
|
|
|
createParticleImpacts();
|
|
|
|
driver->beginScene(timeForThisScene != -1, true, backColor);
|
|
|
|
smgr->drawAll();
|
|
guienv->drawAll();
|
|
|
|
driver->endScene();
|
|
|
|
// write statistics
|
|
static s32 lastfps = 0;
|
|
s32 nowfps = driver->getFPS();
|
|
|
|
swprintf(tmp, 255, L"%ls fps:%3d triangles:%0.3f mio",
|
|
driver->getName(),
|
|
driver->getFPS(),
|
|
(f32) driver->getPrimitiveCountDrawn( 1 ) * ( 1.f / 1000000.f )
|
|
);
|
|
|
|
statusText->setText(tmp);
|
|
if ( nowfps != lastfps )
|
|
{
|
|
device->setWindowCaption ( tmp );
|
|
lastfps = nowfps;
|
|
}
|
|
}
|
|
}
|
|
|
|
device->drop();
|
|
}
|
|
|
|
|
|
bool CDemo::OnEvent(const SEvent& event)
|
|
{
|
|
if (!device)
|
|
return false;
|
|
|
|
if (event.EventType == EET_KEY_INPUT_EVENT &&
|
|
event.KeyInput.Key == KEY_ESCAPE &&
|
|
event.KeyInput.PressedDown == false)
|
|
{
|
|
// user wants to quit.
|
|
if (currentScene < 3)
|
|
timeForThisScene = 0;
|
|
else
|
|
device->closeDevice();
|
|
}
|
|
else
|
|
if ((event.EventType == EET_KEY_INPUT_EVENT &&
|
|
event.KeyInput.Key == KEY_SPACE &&
|
|
event.KeyInput.PressedDown == false) ||
|
|
(event.EventType == EET_MOUSE_INPUT_EVENT &&
|
|
event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) &&
|
|
currentScene == 3)
|
|
{
|
|
// shoot
|
|
shoot();
|
|
}
|
|
else
|
|
if (event.EventType == EET_KEY_INPUT_EVENT &&
|
|
event.KeyInput.Key == KEY_F9 &&
|
|
event.KeyInput.PressedDown == false)
|
|
{
|
|
video::IImage* image = device->getVideoDriver()->createScreenShot();
|
|
if (image)
|
|
{
|
|
device->getVideoDriver()->writeImageToFile(image, "screenshot.bmp");
|
|
device->getVideoDriver()->writeImageToFile(image, "screenshot.png");
|
|
device->getVideoDriver()->writeImageToFile(image, "screenshot.tga");
|
|
device->getVideoDriver()->writeImageToFile(image, "screenshot.ppm");
|
|
device->getVideoDriver()->writeImageToFile(image, "screenshot.jpg");
|
|
device->getVideoDriver()->writeImageToFile(image, "screenshot.pcx");
|
|
image->drop();
|
|
}
|
|
}
|
|
else
|
|
if (device->getSceneManager()->getActiveCamera())
|
|
{
|
|
device->getSceneManager()->getActiveCamera()->OnEvent(event);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void CDemo::switchToNextScene()
|
|
{
|
|
currentScene++;
|
|
if (currentScene > 3)
|
|
currentScene = 1;
|
|
|
|
scene::ISceneManager* sm = device->getSceneManager();
|
|
scene::ISceneNodeAnimator* sa = 0;
|
|
scene::ICameraSceneNode* camera = 0;
|
|
|
|
camera = sm->getActiveCamera();
|
|
if (camera)
|
|
{
|
|
sm->setActiveCamera(0);
|
|
camera->remove();
|
|
camera = 0;
|
|
}
|
|
|
|
switch(currentScene)
|
|
{
|
|
case -1: // loading screen
|
|
timeForThisScene = 0;
|
|
createLoadingScreen();
|
|
break;
|
|
|
|
case 0: // load scene
|
|
timeForThisScene = 0;
|
|
loadSceneData();
|
|
break;
|
|
|
|
case 1: // panorama camera
|
|
{
|
|
currentScene += 1;
|
|
//camera = sm->addCameraSceneNode(0, core::vector3df(0,0,0), core::vector3df(-586,708,52));
|
|
//camera->setTarget(core::vector3df(0,400,0));
|
|
|
|
core::array<core::vector3df> points;
|
|
|
|
points.push_back(core::vector3df(-931.473755f, 138.300003f, 987.279114f)); // -49873
|
|
points.push_back(core::vector3df(-847.902222f, 136.757553f, 915.792725f)); // -50559
|
|
points.push_back(core::vector3df(-748.680420f, 152.254501f, 826.418945f)); // -51964
|
|
points.push_back(core::vector3df(-708.428406f, 213.569580f, 784.466675f)); // -53251
|
|
points.push_back(core::vector3df(-686.217651f, 288.141174f, 762.965576f)); // -54015
|
|
points.push_back(core::vector3df(-679.685059f, 365.095612f, 756.551453f)); // -54733
|
|
points.push_back(core::vector3df(-671.317871f, 447.360107f, 749.394592f)); // -55588
|
|
points.push_back(core::vector3df(-669.468445f, 583.335632f, 747.711853f)); // -56178
|
|
points.push_back(core::vector3df(-667.611267f, 727.313232f, 746.018250f)); // -56757
|
|
points.push_back(core::vector3df(-665.853210f, 862.791931f, 744.436096f)); // -57859
|
|
points.push_back(core::vector3df(-642.649597f, 1026.047607f, 724.259827f)); // -59705
|
|
points.push_back(core::vector3df(-517.793884f, 838.396790f, 490.326050f)); // -60983
|
|
points.push_back(core::vector3df(-474.387299f, 715.691467f, 344.639984f)); // -61629
|
|
points.push_back(core::vector3df(-444.600250f, 601.155701f, 180.938095f)); // -62319
|
|
points.push_back(core::vector3df(-414.808899f, 479.691406f, 4.866660f)); // -63048
|
|
points.push_back(core::vector3df(-410.418945f, 429.642242f, -134.332687f)); // -63757
|
|
points.push_back(core::vector3df(-399.837585f, 411.498383f, -349.350983f)); // -64418
|
|
points.push_back(core::vector3df(-390.756653f, 403.970093f, -524.454407f)); // -65005
|
|
points.push_back(core::vector3df(-334.864227f, 350.065491f, -732.397400f)); // -65701
|
|
points.push_back(core::vector3df(-195.253387f, 349.577209f, -812.475891f)); // -66335
|
|
points.push_back(core::vector3df(16.255573f, 363.743134f, -833.800415f)); // -67170
|
|
points.push_back(core::vector3df(234.940964f, 352.957825f, -820.150696f)); // -67939
|
|
points.push_back(core::vector3df(436.797668f, 349.236450f, -816.914185f)); // -68596
|
|
points.push_back(core::vector3df(575.236206f, 356.244812f, -719.788513f)); // -69166
|
|
points.push_back(core::vector3df(594.131042f, 387.173828f, -609.675598f)); // -69744
|
|
points.push_back(core::vector3df(617.615234f, 412.002899f, -326.174072f)); // -70640
|
|
points.push_back(core::vector3df(606.456848f, 403.221954f, -104.179291f)); // -71390
|
|
points.push_back(core::vector3df(610.958252f, 407.037750f, 117.209778f)); // -72085
|
|
points.push_back(core::vector3df(597.956909f, 395.167877f, 345.942200f)); // -72817
|
|
points.push_back(core::vector3df(587.383118f, 391.444519f, 566.098633f)); // -73477
|
|
points.push_back(core::vector3df(559.572449f, 371.991333f, 777.689453f)); // -74124
|
|
points.push_back(core::vector3df(423.753204f, 329.990051f, 925.859741f)); // -74941
|
|
points.push_back(core::vector3df(247.520050f, 252.818954f, 935.311829f)); // -75651
|
|
points.push_back(core::vector3df(114.756012f, 199.799759f, 805.014160f));
|
|
points.push_back(core::vector3df(96.783348f, 181.639481f, 648.188110f));
|
|
points.push_back(core::vector3df(97.865623f, 138.905975f, 484.812561f));
|
|
points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
|
|
points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
|
|
points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
|
|
|
|
timeForThisScene = (points.size()-3)* 1000;
|
|
|
|
camera = sm->addCameraSceneNode(0, points[0], core::vector3df(0 ,400,0));
|
|
//camera->setTarget(core::vector3df(0,400,0));
|
|
|
|
sa = sm->createFollowSplineAnimator(device->getTimer()->getTime(),
|
|
points);
|
|
camera->addAnimator(sa);
|
|
sa->drop();
|
|
|
|
model1->setVisible(false);
|
|
model2->setVisible(false);
|
|
campFire->setVisible(false);
|
|
inOutFader->fadeIn(7000);
|
|
}
|
|
break;
|
|
|
|
case 2: // down fly anim camera
|
|
camera = sm->addCameraSceneNode(0, core::vector3df(100,40,-80), core::vector3df(844,670,-885));
|
|
sa = sm->createFlyStraightAnimator(core::vector3df(94, 1002, 127),
|
|
core::vector3df(108, 15, -60), 10000, true);
|
|
camera->addAnimator(sa);
|
|
timeForThisScene = 9900;
|
|
model1->setVisible(true);
|
|
model2->setVisible(false);
|
|
campFire->setVisible(false);
|
|
sa->drop();
|
|
break;
|
|
|
|
case 3: // interactive, go around
|
|
{
|
|
model1->setVisible(true);
|
|
model2->setVisible(true);
|
|
campFire->setVisible(true);
|
|
timeForThisScene = -1;
|
|
|
|
SKeyMap keyMap[9];
|
|
keyMap[0].Action = EKA_MOVE_FORWARD;
|
|
keyMap[0].KeyCode = KEY_UP;
|
|
keyMap[1].Action = EKA_MOVE_FORWARD;
|
|
keyMap[1].KeyCode = KEY_KEY_W;
|
|
|
|
keyMap[2].Action = EKA_MOVE_BACKWARD;
|
|
keyMap[2].KeyCode = KEY_DOWN;
|
|
keyMap[3].Action = EKA_MOVE_BACKWARD;
|
|
keyMap[3].KeyCode = KEY_KEY_S;
|
|
|
|
keyMap[4].Action = EKA_STRAFE_LEFT;
|
|
keyMap[4].KeyCode = KEY_LEFT;
|
|
keyMap[5].Action = EKA_STRAFE_LEFT;
|
|
keyMap[5].KeyCode = KEY_KEY_A;
|
|
|
|
keyMap[6].Action = EKA_STRAFE_RIGHT;
|
|
keyMap[6].KeyCode = KEY_RIGHT;
|
|
keyMap[7].Action = EKA_STRAFE_RIGHT;
|
|
keyMap[7].KeyCode = KEY_KEY_D;
|
|
|
|
keyMap[8].Action = EKA_JUMP_UP;
|
|
keyMap[8].KeyCode = KEY_KEY_J;
|
|
|
|
camera = sm->addCameraSceneNodeFPS(0, 100.0f, .4f, -1, keyMap, 9, false, 3.f);
|
|
camera->setPosition(core::vector3df(108,140,-140));
|
|
|
|
scene::ISceneNodeAnimatorCollisionResponse* collider =
|
|
sm->createCollisionResponseAnimator(
|
|
metaSelector, camera, core::vector3df(25,50,25),
|
|
core::vector3df(0, quakeLevelMesh ? -10.f : 0.0f,0),
|
|
core::vector3df(0,45,0), 0.005f);
|
|
|
|
camera->addAnimator(collider);
|
|
collider->drop();
|
|
}
|
|
break;
|
|
}
|
|
|
|
sceneStartTime = device->getTimer()->getTime();
|
|
|
|
}
|
|
|
|
|
|
void CDemo::loadSceneData()
|
|
{
|
|
// load quake level
|
|
|
|
video::IVideoDriver* driver = device->getVideoDriver();
|
|
scene::ISceneManager* sm = device->getSceneManager();
|
|
|
|
quakeLevelMesh = (scene::IQ3LevelMesh*) sm->getMesh("maps/20kdm2.bsp");
|
|
|
|
if (quakeLevelMesh)
|
|
{
|
|
u32 i;
|
|
|
|
//move all quake level meshes (non-realtime)
|
|
core::matrix4 m;
|
|
m.setTranslation ( core::vector3df(-1300,-70,-1249) );
|
|
|
|
for ( i = 0; i!= scene::quake3::E_Q3_MESH_SIZE; ++i )
|
|
{
|
|
sm->getMeshManipulator()->transformMesh ( quakeLevelMesh->getMesh(i), m );
|
|
}
|
|
|
|
quakeLevelNode = sm->addOctTreeSceneNode(
|
|
quakeLevelMesh->getMesh( scene::quake3::E_Q3_MESH_GEOMETRY)
|
|
);
|
|
if (quakeLevelNode)
|
|
{
|
|
//quakeLevelNode->setPosition(core::vector3df(-1300,-70,-1249));
|
|
quakeLevelNode->setVisible(true);
|
|
|
|
// create map triangle selector
|
|
mapSelector = sm->createOctTreeTriangleSelector(quakeLevelMesh->getMesh(0),
|
|
quakeLevelNode, 128);
|
|
|
|
// if not using shader and no gamma it's better to use more lighting, because
|
|
// quake3 level are usually dark
|
|
quakeLevelNode->setMaterialType ( video::EMT_LIGHTMAP_M4 );
|
|
|
|
// set additive blending if wanted
|
|
if (additive)
|
|
quakeLevelNode->setMaterialType(video::EMT_LIGHTMAP_ADD);
|
|
}
|
|
|
|
// the additional mesh can be quite huge and is unoptimized
|
|
scene::IMesh * additional_mesh = quakeLevelMesh->getMesh ( scene::quake3::E_Q3_MESH_ITEMS );
|
|
|
|
for ( i = 0; i!= additional_mesh->getMeshBufferCount (); ++i )
|
|
{
|
|
scene::IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer ( i );
|
|
const video::SMaterial &material = meshBuffer->getMaterial();
|
|
|
|
//! The ShaderIndex is stored in the material parameter
|
|
s32 shaderIndex = (s32) material.MaterialTypeParam2;
|
|
|
|
// the meshbuffer can be rendered without additional support, or it has no shader
|
|
const scene::quake3::SShader *shader = quakeLevelMesh->getShader ( shaderIndex );
|
|
if ( 0 == shader )
|
|
{
|
|
continue;
|
|
}
|
|
// Now add the MeshBuffer(s) with the current Shader to the Manager
|
|
sm->addQuake3SceneNode ( meshBuffer, shader );
|
|
}
|
|
|
|
// original mesh is not needed anymore
|
|
quakeLevelMesh->releaseMesh ( scene::quake3::E_Q3_MESH_ITEMS );
|
|
|
|
}
|
|
|
|
// load sydney model and create 2 instances
|
|
|
|
scene::IAnimatedMesh* mesh = 0;
|
|
mesh = sm->getMesh("../../media/sydney.md2");
|
|
if (mesh)
|
|
{
|
|
model1 = sm->addAnimatedMeshSceneNode(mesh);
|
|
if (model1)
|
|
{
|
|
model1->setMaterialTexture(0, driver->getTexture("../../media/spheremap.jpg"));
|
|
model1->setPosition(core::vector3df(100,40,-80));
|
|
model1->setScale(core::vector3df(2,2,2));
|
|
model1->setMD2Animation(scene::EMAT_STAND);
|
|
model1->setMaterialFlag(video::EMF_LIGHTING, false);
|
|
model1->setMaterialType(video::EMT_SPHERE_MAP);
|
|
model1->addShadowVolumeSceneNode();
|
|
model1->setAutomaticCulling ( scene::EAC_BOX );
|
|
}
|
|
|
|
model2 = sm->addAnimatedMeshSceneNode(mesh);
|
|
if (model2)
|
|
{
|
|
model2->setPosition(core::vector3df(180,15,-60));
|
|
model2->setScale(core::vector3df(2,2,2));
|
|
model2->setMD2Animation(scene::EMAT_RUN);
|
|
model2->setMaterialTexture(0, device->getVideoDriver()->getTexture("../../media/sydney.bmp"));
|
|
model2->setMaterialFlag(video::EMF_LIGHTING, true);
|
|
model2->addShadowVolumeSceneNode();
|
|
model2->setAutomaticCulling ( scene::EAC_BOX );
|
|
}
|
|
}
|
|
|
|
scene::ISceneNodeAnimator* anim = 0;
|
|
|
|
// create sky box
|
|
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
|
|
skyboxNode = sm->addSkyBoxSceneNode(
|
|
driver->getTexture("../../media/irrlicht2_up.jpg"),
|
|
driver->getTexture("../../media/irrlicht2_dn.jpg"),
|
|
driver->getTexture("../../media/irrlicht2_lf.jpg"),
|
|
driver->getTexture("../../media/irrlicht2_rt.jpg"),
|
|
driver->getTexture("../../media/irrlicht2_ft.jpg"),
|
|
driver->getTexture("../../media/irrlicht2_bk.jpg"));
|
|
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
|
|
|
|
//driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
|
|
|
|
// create walk-between-portals animation
|
|
|
|
core::vector3df waypoint[2];
|
|
waypoint[0].set(-150,40,100);
|
|
waypoint[1].set(350,40,100);
|
|
|
|
if (model2)
|
|
{
|
|
anim = device->getSceneManager()->createFlyStraightAnimator(waypoint[0],
|
|
waypoint[1], 2000, true);
|
|
model2->addAnimator(anim);
|
|
anim->drop();
|
|
}
|
|
|
|
// create animation for portals;
|
|
|
|
core::array<video::ITexture*> textures;
|
|
for (s32 g=1; g<8; ++g)
|
|
{
|
|
core::stringc tmp("../../media/portal");
|
|
tmp += g;
|
|
tmp += ".bmp";
|
|
video::ITexture* t = driver->getTexture( tmp.c_str () );
|
|
textures.push_back(t);
|
|
}
|
|
|
|
anim = sm->createTextureAnimator(textures, 100);
|
|
|
|
// create portals
|
|
|
|
scene::IBillboardSceneNode* bill = 0;
|
|
|
|
for (int r=0; r<2; ++r)
|
|
{
|
|
bill = sm->addBillboardSceneNode(0, core::dimension2d<f32>(100,100),
|
|
waypoint[r]+ core::vector3df(0,20,0));
|
|
bill->setMaterialFlag(video::EMF_LIGHTING, false);
|
|
bill->setMaterialTexture(0, driver->getTexture("../../media/portal1.bmp"));
|
|
bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
|
|
bill->addAnimator(anim);
|
|
}
|
|
|
|
anim->drop();
|
|
|
|
// create cirlce flying dynamic light with transparent billboard attached
|
|
|
|
scene::ILightSceneNode* light = 0;
|
|
|
|
light = sm->addLightSceneNode(0,
|
|
core::vector3df(0,0,0), video::SColorf(1.0f, 1.0f, 1.f, 1.0f), 500.f);
|
|
|
|
anim = sm->createFlyCircleAnimator(
|
|
core::vector3df(100,150,80), 80.0f, 0.0005f);
|
|
|
|
light->addAnimator(anim);
|
|
anim->drop();
|
|
|
|
bill = device->getSceneManager()->addBillboardSceneNode(
|
|
light, core::dimension2d<f32>(40,40));
|
|
bill->setMaterialFlag(video::EMF_LIGHTING, false);
|
|
bill->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp"));
|
|
bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
|
|
|
|
// create meta triangle selector with all triangles selectors in it.
|
|
metaSelector = sm->createMetaTriangleSelector();
|
|
metaSelector->addTriangleSelector(mapSelector);
|
|
|
|
// create camp fire
|
|
|
|
campFire = sm->addParticleSystemSceneNode(false);
|
|
campFire->setPosition(core::vector3df(100,120,600));
|
|
campFire->setScale(core::vector3df(2,2,2));
|
|
|
|
|
|
scene::IParticleEmitter* em = campFire->createBoxEmitter(
|
|
core::aabbox3d<f32>(-7,0,-7,7,1,7),
|
|
core::vector3df(0.0f,0.06f,0.0f),
|
|
80,100, video::SColor(0,255,255,255),video::SColor(0,255,255,255), 800,2000);
|
|
|
|
em->setMinStartSize(core::dimension2d<f32>(20.0f, 10.0f));
|
|
em->setMaxStartSize(core::dimension2d<f32>(20.0f, 10.0f));
|
|
campFire->setEmitter(em);
|
|
em->drop();
|
|
|
|
scene::IParticleAffector* paf = campFire->createFadeOutParticleAffector();
|
|
campFire->addAffector(paf);
|
|
paf->drop();
|
|
|
|
campFire->setMaterialFlag(video::EMF_LIGHTING, false);
|
|
campFire->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
|
|
campFire->setMaterialTexture(0, driver->getTexture("../../media/fireball.bmp"));
|
|
campFire->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);
|
|
|
|
// load music
|
|
|
|
#ifdef USE_IRRKLANG
|
|
if (music)
|
|
startIrrKlang();
|
|
#endif
|
|
#ifdef USE_SDL_MIXER
|
|
if (music)
|
|
startSound();
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDemo::createLoadingScreen()
|
|
{
|
|
core::dimension2d<u32> size = device->getVideoDriver()->getScreenSize();
|
|
|
|
device->getCursorControl()->setVisible(false);
|
|
|
|
// setup loading screen
|
|
|
|
backColor.set(255,90,90,156);
|
|
|
|
// create in fader
|
|
|
|
inOutFader = device->getGUIEnvironment()->addInOutFader();
|
|
inOutFader->setColor(backColor, video::SColor ( 0, 230, 230, 230 ));
|
|
|
|
// irrlicht logo
|
|
device->getGUIEnvironment()->addImage(device->getVideoDriver()->getTexture("../../media/irrlichtlogo2.png"),
|
|
core::position2d<s32>(5,5));
|
|
|
|
// loading text
|
|
|
|
const int lwidth = size.Width - 20;
|
|
const int lheight = 16;
|
|
|
|
core::rect<int> pos(10, size.Height-lheight-10, 10+lwidth, size.Height-10);
|
|
|
|
device->getGUIEnvironment()->addImage(pos);
|
|
statusText = device->getGUIEnvironment()->addStaticText(L"Loading...", pos, true);
|
|
statusText->setOverrideColor(video::SColor(255,205,200,200));
|
|
|
|
// load bigger font
|
|
|
|
device->getGUIEnvironment()->getSkin()->setFont(
|
|
device->getGUIEnvironment()->getFont("../../media/fonthaettenschweiler.bmp"));
|
|
|
|
// set new font color
|
|
|
|
device->getGUIEnvironment()->getSkin()->setColor(gui::EGDC_BUTTON_TEXT,
|
|
video::SColor(255,100,100,100));
|
|
}
|
|
|
|
|
|
|
|
void CDemo::shoot()
|
|
{
|
|
scene::ISceneManager* sm = device->getSceneManager();
|
|
scene::ICameraSceneNode* camera = sm->getActiveCamera();
|
|
|
|
if (!camera || !mapSelector)
|
|
return;
|
|
|
|
SParticleImpact imp;
|
|
imp.when = 0;
|
|
|
|
// get line of camera
|
|
|
|
core::vector3df start = camera->getPosition();
|
|
core::vector3df end = (camera->getTarget() - start);
|
|
end.normalize();
|
|
start += end*8.0f;
|
|
end = start + (end * camera->getFarValue());
|
|
|
|
core::triangle3df triangle;
|
|
|
|
core::line3d<f32> line(start, end);
|
|
|
|
// get intersection point with map
|
|
|
|
if (sm->getSceneCollisionManager()->getCollisionPoint(
|
|
line, mapSelector, end, triangle))
|
|
{
|
|
// collides with wall
|
|
core::vector3df out = triangle.getNormal();
|
|
out.setLength(0.03f);
|
|
|
|
imp.when = 1;
|
|
imp.outVector = out;
|
|
imp.pos = end;
|
|
}
|
|
else
|
|
{
|
|
// doesnt collide with wall
|
|
core::vector3df start = camera->getPosition();
|
|
core::vector3df end = (camera->getTarget() - start);
|
|
end.normalize();
|
|
start += end*8.0f;
|
|
end = start + (end * camera->getFarValue());
|
|
}
|
|
|
|
// create fire ball
|
|
scene::ISceneNode* node = 0;
|
|
node = sm->addBillboardSceneNode(0,
|
|
core::dimension2d<f32>(25,25), start);
|
|
|
|
node->setMaterialFlag(video::EMF_LIGHTING, false);
|
|
node->setMaterialTexture(0, device->getVideoDriver()->getTexture("../../media/fireball.bmp"));
|
|
node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
|
|
|
|
f32 length = (f32)(end - start).getLength();
|
|
const f32 speed = 0.6f;
|
|
u32 time = (u32)(length / speed);
|
|
|
|
scene::ISceneNodeAnimator* anim = 0;
|
|
|
|
// set flight line
|
|
|
|
anim = sm->createFlyStraightAnimator(start, end, time);
|
|
node->addAnimator(anim);
|
|
anim->drop();
|
|
|
|
anim = sm->createDeleteAnimator(time);
|
|
node->addAnimator(anim);
|
|
anim->drop();
|
|
|
|
if (imp.when)
|
|
{
|
|
// create impact note
|
|
imp.when = device->getTimer()->getTime() + (time - 100);
|
|
Impacts.push_back(imp);
|
|
}
|
|
|
|
// play sound
|
|
#ifdef USE_IRRKLANG
|
|
if (ballSound)
|
|
irrKlang->play2D(ballSound);
|
|
#endif
|
|
#ifdef USE_SDL_MIXER
|
|
if (ballSound)
|
|
playSound(ballSound);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void CDemo::createParticleImpacts()
|
|
{
|
|
u32 now = device->getTimer()->getTime();
|
|
scene::ISceneManager* sm = device->getSceneManager();
|
|
|
|
for (s32 i=0; i<(s32)Impacts.size(); ++i)
|
|
if (now > Impacts[i].when)
|
|
{
|
|
// create smoke particle system
|
|
scene::IParticleSystemSceneNode* pas = 0;
|
|
|
|
pas = sm->addParticleSystemSceneNode(false, 0, -1, Impacts[i].pos);
|
|
|
|
pas->setParticleSize(core::dimension2d<f32>(10.0f, 10.0f));
|
|
|
|
scene::IParticleEmitter* em = pas->createBoxEmitter(
|
|
core::aabbox3d<f32>(-5,-5,-5,5,5,5),
|
|
Impacts[i].outVector, 20,40, video::SColor(0,255,255,255),video::SColor(0,255,255,255),
|
|
1200,1600, 20);
|
|
|
|
pas->setEmitter(em);
|
|
em->drop();
|
|
|
|
scene::IParticleAffector* paf = campFire->createFadeOutParticleAffector();
|
|
pas->addAffector(paf);
|
|
paf->drop();
|
|
|
|
pas->setMaterialFlag(video::EMF_LIGHTING, false);
|
|
pas->setMaterialTexture(0, device->getVideoDriver()->getTexture("../../media/smoke.bmp"));
|
|
pas->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);
|
|
|
|
scene::ISceneNodeAnimator* anim = sm->createDeleteAnimator(2000);
|
|
pas->addAnimator(anim);
|
|
anim->drop();
|
|
|
|
// play impact sound
|
|
#ifdef USE_IRRKLANG
|
|
if (irrKlang)
|
|
{
|
|
irrklang::ISound* sound =
|
|
irrKlang->play3D(impactSound, Impacts[i].pos, false, false, true);
|
|
|
|
if (sound)
|
|
{
|
|
// adjust max value a bit to make to sound of an impact louder
|
|
sound->setMinDistance(400);
|
|
sound->drop();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_SDL_MIXER
|
|
if (impactSound)
|
|
playSound(impactSound);
|
|
#endif
|
|
|
|
// delete entry
|
|
Impacts.erase(i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_IRRKLANG
|
|
void CDemo::startIrrKlang()
|
|
{
|
|
irrKlang = irrklang::createIrrKlangDevice();
|
|
|
|
if (!irrKlang)
|
|
return;
|
|
|
|
// play music
|
|
|
|
irrklang::ISound* snd = irrKlang->play2D("../../media/IrrlichtTheme.ogg", true, false, true);
|
|
if ( !snd )
|
|
snd = irrKlang->play2D("IrrlichtTheme.ogg", true, false, true);
|
|
|
|
if (snd)
|
|
{
|
|
snd->setVolume(0.5f); // 50% volume
|
|
snd->drop();
|
|
}
|
|
|
|
// preload both sound effects
|
|
|
|
ballSound = irrKlang->getSoundSource("../../media/ball.wav");
|
|
impactSound = irrKlang->getSoundSource("../../media/impact.wav");
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef USE_SDL_MIXER
|
|
void CDemo::startSound()
|
|
{
|
|
stream = NULL;
|
|
ballSound = NULL;
|
|
impactSound = NULL;
|
|
|
|
SDL_Init(SDL_INIT_AUDIO);
|
|
|
|
if (Mix_OpenAudio(22050, AUDIO_S16, 2, 128))
|
|
return;
|
|
|
|
stream = Mix_LoadMUS("../../media/IrrlichtTheme.ogg");
|
|
if (stream)
|
|
Mix_PlayMusic(stream, -1);
|
|
|
|
ballSound = Mix_LoadWAV("../../media/ball.wav");
|
|
impactSound = Mix_LoadWAV("../../media/impact.wav");
|
|
}
|
|
|
|
void CDemo::playSound(Mix_Chunk *sample)
|
|
{
|
|
if (sample)
|
|
Mix_PlayChannel(-1, sample, 0);
|
|
}
|
|
|
|
void CDemo::pollSound(void)
|
|
{
|
|
SDL_Event event;
|
|
|
|
while (SDL_PollEvent(&event))
|
|
;
|
|
}
|
|
#endif
|