CDemo.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. // This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt.
  2. // This file is not documented.
  3. #include "CDemo.h"
  4. #include "exampleHelper.h"
  5. CDemo::CDemo(bool f, bool m, bool s, bool a, bool v, bool fsaa, video::E_DRIVER_TYPE d)
  6. : fullscreen(f), music(m), shadows(s), additive(a), vsync(v), aa(fsaa),
  7. driverType(d), device(0),
  8. #ifdef USE_IRRKLANG
  9. irrKlang(0), ballSound(0), impactSound(0),
  10. #endif
  11. #ifdef USE_SDL_MIXER
  12. stream(0), ballSound(0), impactSound(0),
  13. #endif
  14. currentScene(-2), backColor(0), statusText(0), inOutFader(0),
  15. quakeLevelMesh(0), quakeLevelNode(0), skyboxNode(0), model1(0), model2(0),
  16. campFire(0), metaSelector(0), mapSelector(0), sceneStartTime(0),
  17. timeForThisScene(0)
  18. {
  19. }
  20. CDemo::~CDemo()
  21. {
  22. if (mapSelector)
  23. mapSelector->drop();
  24. if (metaSelector)
  25. metaSelector->drop();
  26. #ifdef USE_IRRKLANG
  27. if (irrKlang)
  28. irrKlang->drop();
  29. #endif
  30. }
  31. void CDemo::run()
  32. {
  33. core::dimension2d<u32> resolution (800, 600);
  34. if ( driverType == video::EDT_BURNINGSVIDEO || driverType == video::EDT_SOFTWARE )
  35. {
  36. resolution.Width = 640;
  37. resolution.Height = 480;
  38. }
  39. irr::SIrrlichtCreationParameters params;
  40. params.DriverType=driverType;
  41. params.WindowSize=resolution;
  42. params.Bits=32;
  43. params.Fullscreen=fullscreen;
  44. params.Stencilbuffer=shadows;
  45. params.Vsync=vsync;
  46. params.AntiAlias=aa?8:0;
  47. params.EventReceiver=this;
  48. device = createDeviceEx(params);
  49. if (!device)
  50. return;
  51. const io::path mediaPath = getExampleMediaPath();
  52. if (device->getFileSystem()->existFile("irrlicht.dat"))
  53. device->getFileSystem()->addFileArchive("irrlicht.dat");
  54. else
  55. device->getFileSystem()->addFileArchive(mediaPath + "irrlicht.dat");
  56. if (device->getFileSystem()->existFile("map-20kdm2.pk3"))
  57. device->getFileSystem()->addFileArchive("map-20kdm2.pk3");
  58. else
  59. device->getFileSystem()->addFileArchive(mediaPath + "map-20kdm2.pk3");
  60. video::IVideoDriver* driver = device->getVideoDriver();
  61. scene::ISceneManager* smgr = device->getSceneManager();
  62. gui::IGUIEnvironment* guienv = device->getGUIEnvironment();
  63. device->setWindowCaption(L"Irrlicht Engine Demo");
  64. // set ambient light
  65. smgr->setAmbientLight ( video::SColorf ( 0x00c0c0c0 ) );
  66. wchar_t tmp[255];
  67. // draw everything
  68. s32 now = 0;
  69. s32 lastfps = 0;
  70. sceneStartTime = device->getTimer()->getTime();
  71. while(device->run() && driver)
  72. {
  73. if (device->isWindowActive())
  74. {
  75. #ifdef USE_IRRKLANG
  76. // update 3D position for sound engine
  77. scene::ICameraSceneNode* cam = smgr->getActiveCamera();
  78. if (cam && irrKlang)
  79. irrKlang->setListenerPosition(cam->getAbsolutePosition(), cam->getTarget());
  80. #endif
  81. // load next scene if necessary
  82. now = device->getTimer()->getTime();
  83. if (now - sceneStartTime > timeForThisScene && timeForThisScene!=-1)
  84. switchToNextScene();
  85. createParticleImpacts();
  86. u16 clearFlag = video::ECBF_DEPTH;
  87. if (timeForThisScene != -1)
  88. clearFlag |= video::ECBF_COLOR;
  89. driver->beginScene(clearFlag, backColor);
  90. smgr->drawAll();
  91. guienv->drawAll();
  92. driver->endScene();
  93. // write statistics
  94. const s32 nowfps = driver->getFPS();
  95. swprintf_irr(tmp, 255, L"%ls fps:%3d triangles:%0.3f mio/s",
  96. driver->getName(), driver->getFPS(),
  97. driver->getPrimitiveCountDrawn(1) * (1.f / 1000000.f));
  98. statusText->setText(tmp);
  99. if ( nowfps != lastfps )
  100. {
  101. device->setWindowCaption(tmp);
  102. lastfps = nowfps;
  103. }
  104. }
  105. }
  106. device->drop();
  107. }
  108. bool CDemo::OnEvent(const SEvent& event)
  109. {
  110. if (!device)
  111. return false;
  112. if (event.EventType == EET_KEY_INPUT_EVENT &&
  113. event.KeyInput.Key == KEY_ESCAPE &&
  114. event.KeyInput.PressedDown == false)
  115. {
  116. // user wants to quit.
  117. if (currentScene < 3)
  118. timeForThisScene = 0;
  119. else
  120. device->closeDevice();
  121. }
  122. else
  123. if (((event.EventType == EET_KEY_INPUT_EVENT &&
  124. event.KeyInput.Key == KEY_SPACE &&
  125. event.KeyInput.PressedDown == false) ||
  126. (event.EventType == EET_MOUSE_INPUT_EVENT &&
  127. event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)) &&
  128. currentScene == 3)
  129. {
  130. // shoot
  131. shoot();
  132. }
  133. else
  134. if (event.EventType == EET_KEY_INPUT_EVENT &&
  135. event.KeyInput.Key == KEY_F9 &&
  136. event.KeyInput.PressedDown == false)
  137. {
  138. video::IImage* image = device->getVideoDriver()->createScreenShot();
  139. if (image)
  140. {
  141. device->getVideoDriver()->writeImageToFile(image, "screenshot.bmp");
  142. device->getVideoDriver()->writeImageToFile(image, "screenshot.png");
  143. device->getVideoDriver()->writeImageToFile(image, "screenshot.tga");
  144. device->getVideoDriver()->writeImageToFile(image, "screenshot.ppm");
  145. device->getVideoDriver()->writeImageToFile(image, "screenshot.jpg");
  146. device->getVideoDriver()->writeImageToFile(image, "screenshot.pcx");
  147. image->drop();
  148. }
  149. }
  150. else
  151. if (device->getSceneManager()->getActiveCamera())
  152. {
  153. device->getSceneManager()->getActiveCamera()->OnEvent(event);
  154. return true;
  155. }
  156. return false;
  157. }
  158. void CDemo::switchToNextScene()
  159. {
  160. currentScene++;
  161. if (currentScene > 3)
  162. currentScene = 1;
  163. scene::ISceneManager* sm = device->getSceneManager();
  164. scene::ISceneNodeAnimator* sa = 0;
  165. scene::ICameraSceneNode* camera = 0;
  166. camera = sm->getActiveCamera();
  167. if (camera)
  168. {
  169. sm->setActiveCamera(0);
  170. camera->remove();
  171. camera = 0;
  172. }
  173. switch(currentScene)
  174. {
  175. case -1: // loading screen
  176. timeForThisScene = 0;
  177. createLoadingScreen();
  178. break;
  179. case 0: // load scene
  180. timeForThisScene = 0;
  181. loadSceneData();
  182. break;
  183. case 1: // panorama camera
  184. {
  185. currentScene += 1;
  186. //camera = sm->addCameraSceneNode(0, core::vector3df(0,0,0), core::vector3df(-586,708,52));
  187. //camera->setTarget(core::vector3df(0,400,0));
  188. core::array<core::vector3df> points;
  189. points.push_back(core::vector3df(-931.473755f, 138.300003f, 987.279114f)); // -49873
  190. points.push_back(core::vector3df(-847.902222f, 136.757553f, 915.792725f)); // -50559
  191. points.push_back(core::vector3df(-748.680420f, 152.254501f, 826.418945f)); // -51964
  192. points.push_back(core::vector3df(-708.428406f, 213.569580f, 784.466675f)); // -53251
  193. points.push_back(core::vector3df(-686.217651f, 288.141174f, 762.965576f)); // -54015
  194. points.push_back(core::vector3df(-679.685059f, 365.095612f, 756.551453f)); // -54733
  195. points.push_back(core::vector3df(-671.317871f, 447.360107f, 749.394592f)); // -55588
  196. points.push_back(core::vector3df(-669.468445f, 583.335632f, 747.711853f)); // -56178
  197. points.push_back(core::vector3df(-667.611267f, 727.313232f, 746.018250f)); // -56757
  198. points.push_back(core::vector3df(-665.853210f, 862.791931f, 744.436096f)); // -57859
  199. points.push_back(core::vector3df(-642.649597f, 1026.047607f, 724.259827f)); // -59705
  200. points.push_back(core::vector3df(-517.793884f, 838.396790f, 490.326050f)); // -60983
  201. points.push_back(core::vector3df(-474.387299f, 715.691467f, 344.639984f)); // -61629
  202. points.push_back(core::vector3df(-444.600250f, 601.155701f, 180.938095f)); // -62319
  203. points.push_back(core::vector3df(-414.808899f, 479.691406f, 4.866660f)); // -63048
  204. points.push_back(core::vector3df(-410.418945f, 429.642242f, -134.332687f)); // -63757
  205. points.push_back(core::vector3df(-399.837585f, 411.498383f, -349.350983f)); // -64418
  206. points.push_back(core::vector3df(-390.756653f, 403.970093f, -524.454407f)); // -65005
  207. points.push_back(core::vector3df(-334.864227f, 350.065491f, -732.397400f)); // -65701
  208. points.push_back(core::vector3df(-195.253387f, 349.577209f, -812.475891f)); // -66335
  209. points.push_back(core::vector3df(16.255573f, 363.743134f, -833.800415f)); // -67170
  210. points.push_back(core::vector3df(234.940964f, 352.957825f, -820.150696f)); // -67939
  211. points.push_back(core::vector3df(436.797668f, 349.236450f, -816.914185f)); // -68596
  212. points.push_back(core::vector3df(575.236206f, 356.244812f, -719.788513f)); // -69166
  213. points.push_back(core::vector3df(594.131042f, 387.173828f, -609.675598f)); // -69744
  214. points.push_back(core::vector3df(617.615234f, 412.002899f, -326.174072f)); // -70640
  215. points.push_back(core::vector3df(606.456848f, 403.221954f, -104.179291f)); // -71390
  216. points.push_back(core::vector3df(610.958252f, 407.037750f, 117.209778f)); // -72085
  217. points.push_back(core::vector3df(597.956909f, 395.167877f, 345.942200f)); // -72817
  218. points.push_back(core::vector3df(587.383118f, 391.444519f, 566.098633f)); // -73477
  219. points.push_back(core::vector3df(559.572449f, 371.991333f, 777.689453f)); // -74124
  220. points.push_back(core::vector3df(423.753204f, 329.990051f, 925.859741f)); // -74941
  221. points.push_back(core::vector3df(247.520050f, 252.818954f, 935.311829f)); // -75651
  222. points.push_back(core::vector3df(114.756012f, 199.799759f, 805.014160f));
  223. points.push_back(core::vector3df(96.783348f, 181.639481f, 648.188110f));
  224. points.push_back(core::vector3df(97.865623f, 138.905975f, 484.812561f));
  225. points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
  226. points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
  227. points.push_back(core::vector3df(99.612457f, 102.463669f, 347.603210f));
  228. timeForThisScene = (points.size()-3)* 1000;
  229. camera = sm->addCameraSceneNode(0, points[0], core::vector3df(0 ,400,0));
  230. //camera->setTarget(core::vector3df(0,400,0));
  231. sa = sm->createFollowSplineAnimator(device->getTimer()->getTime(),
  232. points);
  233. camera->addAnimator(sa);
  234. sa->drop();
  235. model1->setVisible(false);
  236. model2->setVisible(false);
  237. campFire->setVisible(false);
  238. inOutFader->fadeIn(7000);
  239. }
  240. break;
  241. case 2: // down fly anim camera
  242. camera = sm->addCameraSceneNode(0, core::vector3df(100,40,-80), core::vector3df(844,670,-885));
  243. sa = sm->createFlyStraightAnimator(core::vector3df(94, 1002, 127),
  244. core::vector3df(108, 15, -60), 10000, true);
  245. camera->addAnimator(sa);
  246. timeForThisScene = 9900;
  247. model1->setVisible(true);
  248. model2->setVisible(false);
  249. campFire->setVisible(false);
  250. sa->drop();
  251. break;
  252. case 3: // interactive, go around
  253. {
  254. model1->setVisible(true);
  255. model2->setVisible(true);
  256. campFire->setVisible(true);
  257. timeForThisScene = -1;
  258. core::array<SKeyMap> keyMap(11);
  259. keyMap.push_back( SKeyMap(EKA_MOVE_FORWARD, KEY_UP) );
  260. keyMap.push_back( SKeyMap(EKA_MOVE_FORWARD, KEY_KEY_W) );
  261. keyMap.push_back( SKeyMap(EKA_MOVE_BACKWARD, KEY_DOWN) );
  262. keyMap.push_back( SKeyMap(EKA_MOVE_BACKWARD, KEY_KEY_S) );
  263. keyMap.push_back( SKeyMap(EKA_STRAFE_LEFT, KEY_LEFT) );
  264. keyMap.push_back( SKeyMap(EKA_STRAFE_LEFT, KEY_KEY_A) );
  265. keyMap.push_back( SKeyMap(EKA_STRAFE_RIGHT, KEY_RIGHT) );
  266. keyMap.push_back( SKeyMap(EKA_STRAFE_RIGHT, KEY_KEY_D) );
  267. keyMap.push_back( SKeyMap(EKA_JUMP_UP, KEY_KEY_J) );
  268. keyMap.push_back( SKeyMap(EKA_ROTATE_LEFT, KEY_KEY_Q) );
  269. keyMap.push_back( SKeyMap(EKA_ROTATE_RIGHT, KEY_KEY_E) );
  270. camera = sm->addCameraSceneNodeFPS(0, 100.0f, .4f, -1, keyMap.pointer(), keyMap.size(), false, 300.f);
  271. camera->setPosition(core::vector3df(108,140,-140));
  272. camera->setFarValue(5000.0f);
  273. scene::ISceneNodeAnimatorCollisionResponse* collider =
  274. sm->createCollisionResponseAnimator(
  275. metaSelector, camera, core::vector3df(25,50,25),
  276. core::vector3df(0, quakeLevelMesh ? -1000.f : 0.0f,0),
  277. core::vector3df(0,45,0), 0.005f);
  278. camera->addAnimator(collider);
  279. collider->drop();
  280. }
  281. break;
  282. }
  283. sceneStartTime = device->getTimer()->getTime();
  284. }
  285. void CDemo::loadSceneData()
  286. {
  287. // load quake level
  288. video::IVideoDriver* driver = device->getVideoDriver();
  289. scene::ISceneManager* sm = device->getSceneManager();
  290. // Quake3 Shader controls Z-Writing
  291. sm->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
  292. quakeLevelMesh = (scene::IQ3LevelMesh*) sm->getMesh("maps/20kdm2.bsp");
  293. if (quakeLevelMesh)
  294. {
  295. u32 i;
  296. //move all quake level meshes (non-realtime)
  297. core::matrix4 m;
  298. m.setTranslation(core::vector3df(-1300,-70,-1249));
  299. for ( i = 0; i != scene::quake3::E_Q3_MESH_SIZE; ++i )
  300. sm->getMeshManipulator()->transform(quakeLevelMesh->getMesh(i), m);
  301. quakeLevelNode = sm->addOctreeSceneNode(
  302. quakeLevelMesh->getMesh( scene::quake3::E_Q3_MESH_GEOMETRY));
  303. if (quakeLevelNode)
  304. {
  305. //quakeLevelNode->setPosition(core::vector3df(-1300,-70,-1249));
  306. quakeLevelNode->setVisible(true);
  307. // create map triangle selector
  308. mapSelector = sm->createOctreeTriangleSelector(quakeLevelMesh->getMesh(0),
  309. quakeLevelNode, 128);
  310. // if not using shader and no gamma it's better to use more lighting, because
  311. // quake3 level are usually dark
  312. quakeLevelNode->setMaterialType ( video::EMT_LIGHTMAP_M4 );
  313. // set additive blending if wanted
  314. if (additive)
  315. quakeLevelNode->setMaterialType(video::EMT_LIGHTMAP_ADD);
  316. }
  317. // the additional mesh can be quite huge and is unoptimized
  318. scene::IMesh * additional_mesh = quakeLevelMesh->getMesh ( scene::quake3::E_Q3_MESH_ITEMS );
  319. for ( i = 0; i!= additional_mesh->getMeshBufferCount (); ++i )
  320. {
  321. scene::IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer ( i );
  322. const video::SMaterial &material = meshBuffer->getMaterial();
  323. //! The ShaderIndex is stored in the material parameter
  324. s32 shaderIndex = (s32) material.MaterialTypeParam2;
  325. // the meshbuffer can be rendered without additional support, or it has no shader
  326. const scene::quake3::IShader *shader = quakeLevelMesh->getShader ( shaderIndex );
  327. if ( 0 == shader )
  328. {
  329. continue;
  330. }
  331. // Now add the MeshBuffer(s) with the current Shader to the Manager
  332. sm->addQuake3SceneNode ( meshBuffer, shader );
  333. }
  334. }
  335. const io::path mediaPath = getExampleMediaPath();
  336. // load sydney model and create 2 instances
  337. scene::IAnimatedMesh* mesh = 0;
  338. mesh = sm->getMesh(mediaPath + "sydney.md2");
  339. if (mesh)
  340. {
  341. model1 = sm->addAnimatedMeshSceneNode(mesh);
  342. if (model1)
  343. {
  344. model1->setMaterialTexture(0, driver->getTexture(mediaPath + "spheremap.jpg"));
  345. model1->setPosition(core::vector3df(100,40,-80));
  346. model1->setScale(core::vector3df(2,2,2));
  347. model1->setMD2Animation(scene::EMAT_STAND);
  348. model1->setMaterialFlag(video::EMF_LIGHTING, true);
  349. model1->getMaterial(0).Shininess = 40.f;
  350. model1->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
  351. model1->setMaterialType(video::EMT_SPHERE_MAP);
  352. model1->setAutomaticCulling(scene::EAC_OFF); // avoid shadows not updating
  353. scene::IShadowVolumeSceneNode * shadVol = model1->addShadowVolumeSceneNode();
  354. if(shadVol) shadVol->setOptimization(scene::ESV_NONE); // Sydney has broken shadows otherwise
  355. }
  356. model2 = sm->addAnimatedMeshSceneNode(mesh);
  357. if (model2)
  358. {
  359. model2->setPosition(core::vector3df(180,15,-60));
  360. model2->setScale(core::vector3df(2,2,2));
  361. model2->setMD2Animation(scene::EMAT_RUN);
  362. model2->setMaterialTexture(0, device->getVideoDriver()->getTexture(mediaPath + "sydney.bmp"));
  363. model2->setMaterialFlag(video::EMF_LIGHTING, true);
  364. model2->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
  365. model2->setAutomaticCulling(scene::EAC_OFF); // avoid shadows not updating
  366. scene::IShadowVolumeSceneNode * shadVol = model2->addShadowVolumeSceneNode();
  367. if (shadVol) shadVol->setOptimization(scene::ESV_NONE); // Sydney has broken shadows otherwise
  368. }
  369. }
  370. scene::ISceneNodeAnimator* anim = 0;
  371. // create sky box
  372. driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
  373. skyboxNode = sm->addSkyBoxSceneNode(
  374. driver->getTexture(mediaPath + "irrlicht2_up.jpg"),
  375. driver->getTexture(mediaPath + "irrlicht2_dn.jpg"),
  376. driver->getTexture(mediaPath + "irrlicht2_lf.jpg"),
  377. driver->getTexture(mediaPath + "irrlicht2_rt.jpg"),
  378. driver->getTexture(mediaPath + "irrlicht2_ft.jpg"),
  379. driver->getTexture(mediaPath + "irrlicht2_bk.jpg"));
  380. driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
  381. // create walk-between-portals animation
  382. core::vector3df waypoint[2];
  383. waypoint[0].set(-150,40,100);
  384. waypoint[1].set(350,40,100);
  385. if (model2)
  386. {
  387. anim = device->getSceneManager()->createFlyStraightAnimator(
  388. waypoint[0], waypoint[1], 2000, true);
  389. model2->addAnimator(anim);
  390. anim->drop();
  391. }
  392. // create animation for portals;
  393. core::array<video::ITexture*> textures;
  394. for (s32 g=1; g<8; ++g)
  395. {
  396. core::stringc tmp(mediaPath + "portal");
  397. tmp += g;
  398. tmp += ".bmp";
  399. video::ITexture* t = driver->getTexture( tmp );
  400. textures.push_back(t);
  401. }
  402. anim = sm->createTextureAnimator(textures, 100);
  403. // create portals
  404. scene::IBillboardSceneNode* bill = 0;
  405. for (int r=0; r<2; ++r)
  406. {
  407. bill = sm->addBillboardSceneNode(0, core::dimension2d<f32>(100,100),
  408. waypoint[r]+ core::vector3df(0,20,0));
  409. bill->setMaterialFlag(video::EMF_LIGHTING, false);
  410. bill->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
  411. bill->setMaterialTexture(0, driver->getTexture(mediaPath + "portal1.bmp"));
  412. bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
  413. bill->addAnimator(anim);
  414. }
  415. anim->drop();
  416. // create cirlce flying dynamic light with transparent billboard attached
  417. scene::ILightSceneNode* light = 0;
  418. light = sm->addLightSceneNode(0,
  419. core::vector3df(0,0,0), video::SColorf(1.0f, 1.0f, 1.f, 1.0f), 500.f);
  420. anim = sm->createFlyCircleAnimator(
  421. core::vector3df(100,150,80), 80.0f, 0.0005f);
  422. light->addAnimator(anim);
  423. anim->drop();
  424. bill = device->getSceneManager()->addBillboardSceneNode(
  425. light, core::dimension2d<f32>(40,40));
  426. bill->setMaterialFlag(video::EMF_LIGHTING, false);
  427. bill->setMaterialTexture(0, driver->getTexture(mediaPath + "particlewhite.bmp"));
  428. bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
  429. // create meta triangle selector with all triangles selectors in it.
  430. metaSelector = sm->createMetaTriangleSelector();
  431. metaSelector->addTriangleSelector(mapSelector);
  432. // create camp fire
  433. campFire = sm->addParticleSystemSceneNode(false);
  434. campFire->setPosition(core::vector3df(100,120,600));
  435. campFire->setScale(core::vector3df(2,2,2));
  436. scene::IParticleEmitter* em = campFire->createBoxEmitter(
  437. core::aabbox3d<f32>(-7,0,-7,7,1,7),
  438. core::vector3df(0.0f,0.06f,0.0f),
  439. 80,100, video::SColor(1,255,255,255),video::SColor(1,255,255,255), 800,2000);
  440. em->setMinStartSize(core::dimension2d<f32>(20.0f, 10.0f));
  441. em->setMaxStartSize(core::dimension2d<f32>(20.0f, 10.0f));
  442. campFire->setEmitter(em);
  443. em->drop();
  444. scene::IParticleAffector* paf = campFire->createFadeOutParticleAffector();
  445. campFire->addAffector(paf);
  446. paf->drop();
  447. campFire->setMaterialFlag(video::EMF_LIGHTING, false);
  448. campFire->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
  449. campFire->setMaterialTexture(0, driver->getTexture(mediaPath + "fireball.bmp"));
  450. campFire->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
  451. // load music
  452. #ifdef USE_IRRKLANG
  453. if (music)
  454. startIrrKlang();
  455. #endif
  456. #ifdef USE_SDL_MIXER
  457. if (music)
  458. startSound();
  459. #endif
  460. }
  461. void CDemo::createLoadingScreen()
  462. {
  463. core::dimension2d<u32> size = device->getVideoDriver()->getScreenSize();
  464. device->getCursorControl()->setVisible(false);
  465. // setup loading screen
  466. backColor.set(255,90,90,156);
  467. // create in fader
  468. inOutFader = device->getGUIEnvironment()->addInOutFader();
  469. inOutFader->setColor(backColor, video::SColor ( 0, 230, 230, 230 ));
  470. const io::path mediaPath = getExampleMediaPath();
  471. // irrlicht logo
  472. device->getGUIEnvironment()->addImage(device->getVideoDriver()->getTexture(mediaPath + "irrlichtlogo3.png"),
  473. core::position2d<s32>(5,5));
  474. // loading text
  475. const int lwidth = size.Width - 20;
  476. const int lheight = 16;
  477. core::rect<int> pos(10, size.Height-lheight-10, 10+lwidth, size.Height-10);
  478. device->getGUIEnvironment()->addImage(pos);
  479. statusText = device->getGUIEnvironment()->addStaticText(L"Loading...", pos, true);
  480. statusText->setOverrideColor(video::SColor(255,205,200,200));
  481. // load bigger font
  482. device->getGUIEnvironment()->getSkin()->setFont(
  483. device->getGUIEnvironment()->getFont(mediaPath + "fonthaettenschweiler.bmp"));
  484. // set new font color
  485. device->getGUIEnvironment()->getSkin()->setColor(gui::EGDC_BUTTON_TEXT,
  486. video::SColor(255,100,100,100));
  487. }
  488. void CDemo::shoot()
  489. {
  490. scene::ISceneManager* sm = device->getSceneManager();
  491. scene::ICameraSceneNode* camera = sm->getActiveCamera();
  492. if (!camera || !mapSelector)
  493. return;
  494. SParticleImpact imp;
  495. imp.when = 0;
  496. // get line of camera
  497. core::vector3df start = camera->getPosition();
  498. core::vector3df end = (camera->getTarget() - start);
  499. end.normalize();
  500. start += end*8.0f;
  501. end = start + (end * camera->getFarValue());
  502. core::triangle3df triangle;
  503. core::line3d<f32> line(start, end);
  504. // get intersection point with map
  505. scene::ISceneNode* hitNode;
  506. if (sm->getSceneCollisionManager()->getCollisionPoint(
  507. line, mapSelector, end, triangle, hitNode))
  508. {
  509. // collides with wall
  510. core::vector3df out = triangle.getNormal();
  511. out.setLength(0.03f);
  512. imp.when = 1;
  513. imp.outVector = out;
  514. imp.pos = end;
  515. }
  516. else
  517. {
  518. // doesnt collide with wall
  519. start = camera->getPosition();
  520. end = (camera->getTarget() - start);
  521. end.normalize();
  522. start += end*8.0f;
  523. end = start + (end * camera->getFarValue());
  524. }
  525. // create fire ball
  526. scene::ISceneNode* node = 0;
  527. node = sm->addBillboardSceneNode(0,
  528. core::dimension2d<f32>(25,25), start);
  529. node->setMaterialFlag(video::EMF_LIGHTING, false);
  530. node->setMaterialTexture(0, device->getVideoDriver()->getTexture(getExampleMediaPath() + "fireball.bmp"));
  531. node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
  532. f32 length = (f32)(end - start).getLength();
  533. const f32 speed = 0.6f;
  534. u32 time = (u32)(length / speed);
  535. scene::ISceneNodeAnimator* anim = 0;
  536. // set flight line
  537. anim = sm->createFlyStraightAnimator(start, end, time);
  538. node->addAnimator(anim);
  539. anim->drop();
  540. anim = sm->createDeleteAnimator(time);
  541. node->addAnimator(anim);
  542. anim->drop();
  543. if (imp.when)
  544. {
  545. // create impact note
  546. imp.when = device->getTimer()->getTime() + (time - 100);
  547. Impacts.push_back(imp);
  548. }
  549. // play sound
  550. #ifdef USE_IRRKLANG
  551. if (ballSound)
  552. irrKlang->play2D(ballSound);
  553. #endif
  554. #ifdef USE_SDL_MIXER
  555. if (ballSound)
  556. playSound(ballSound);
  557. #endif
  558. }
  559. void CDemo::createParticleImpacts()
  560. {
  561. u32 now = device->getTimer()->getTime();
  562. scene::ISceneManager* sm = device->getSceneManager();
  563. for (s32 i=0; i<(s32)Impacts.size(); ++i)
  564. if (now > Impacts[i].when)
  565. {
  566. // create smoke particle system
  567. scene::IParticleSystemSceneNode* pas = 0;
  568. pas = sm->addParticleSystemSceneNode(false, 0, -1, Impacts[i].pos);
  569. pas->setParticleSize(core::dimension2d<f32>(10.0f, 10.0f));
  570. scene::IParticleEmitter* em = pas->createBoxEmitter(
  571. core::aabbox3d<f32>(-5,-5,-5,5,5,5),
  572. Impacts[i].outVector, 20,40, video::SColor(50,255,255,255),video::SColor(50,255,255,255),
  573. 1200,1600, 20);
  574. pas->setEmitter(em);
  575. em->drop();
  576. scene::IParticleAffector* paf = campFire->createFadeOutParticleAffector();
  577. pas->addAffector(paf);
  578. paf->drop();
  579. pas->setMaterialFlag(video::EMF_LIGHTING, false);
  580. pas->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
  581. pas->setMaterialTexture(0, device->getVideoDriver()->getTexture(getExampleMediaPath() + "smoke.bmp"));
  582. pas->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
  583. scene::ISceneNodeAnimator* anim = sm->createDeleteAnimator(2000);
  584. pas->addAnimator(anim);
  585. anim->drop();
  586. // play impact sound
  587. #ifdef USE_IRRKLANG
  588. if (irrKlang)
  589. {
  590. irrklang::ISound* sound =
  591. irrKlang->play3D(impactSound, Impacts[i].pos, false, false, true);
  592. if (sound)
  593. {
  594. // adjust max value a bit to make to sound of an impact louder
  595. sound->setMinDistance(400);
  596. sound->drop();
  597. }
  598. }
  599. #endif
  600. #ifdef USE_SDL_MIXER
  601. if (impactSound)
  602. playSound(impactSound);
  603. #endif
  604. // delete entry
  605. Impacts.erase(i);
  606. i--;
  607. }
  608. }
  609. #ifdef USE_IRRKLANG
  610. void CDemo::startIrrKlang()
  611. {
  612. irrKlang = irrklang::createIrrKlangDevice();
  613. if (!irrKlang)
  614. return;
  615. const io::path mediaPath = getExampleMediaPath();
  616. // play music
  617. irrklang::ISound* snd = irrKlang->play2D((mediaPath + "IrrlichtTheme.ogg").c_str(), true, false, true);
  618. if ( !snd )
  619. snd = irrKlang->play2D("IrrlichtTheme.ogg", true, false, true);
  620. if (snd)
  621. {
  622. snd->setVolume(0.5f); // 50% volume
  623. snd->drop();
  624. }
  625. // preload both sound effects
  626. ballSound = irrKlang->getSoundSource(mediaPath + "ball.wav");
  627. impactSound = irrKlang->getSoundSource(mediaPath + "impact.wav");
  628. }
  629. #endif
  630. #ifdef USE_SDL_MIXER
  631. void CDemo::startSound()
  632. {
  633. stream = NULL;
  634. ballSound = NULL;
  635. impactSound = NULL;
  636. SDL_Init(SDL_INIT_AUDIO);
  637. if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 4096))
  638. return;
  639. const io::path mediaPath = getExampleMediaPath();
  640. stream = Mix_LoadMUS((mediaPath + "IrrlichtTheme.ogg").c_str());
  641. if (stream)
  642. Mix_PlayMusic(stream, -1);
  643. ballSound = Mix_LoadWAV((mediaPath + "ball.wav").c_str());
  644. impactSound = Mix_LoadWAV((mediaPath + "impact.wav").c_str());
  645. }
  646. void CDemo::playSound(Mix_Chunk *sample)
  647. {
  648. if (sample)
  649. Mix_PlayChannel(-1, sample, 0);
  650. }
  651. void CDemo::pollSound(void)
  652. {
  653. SDL_Event event;
  654. while (SDL_PollEvent(&event))
  655. ;
  656. }
  657. #endif