main.cpp 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190
  1. /** Example 021 Quake3 Explorer
  2. This tutorial shows how to load different Quake 3 maps.
  3. Features:
  4. - Load BSP Archives at Runtime from the menu
  5. - Load a Map from the menu. Showing with Screenshot
  6. - Set the VideoDriver at runtime from menu
  7. - Adjust GammaLevel at runtime
  8. - Create SceneNodes for the Shaders
  9. - Load EntityList and create Entity SceneNodes
  10. - Create Players with Weapons and with Collision Response
  11. - Play music
  12. You can download the Quake III Arena demo ( copyright id software )
  13. at the following location:
  14. ftp://ftp.idsoftware.com/idstuff/quake3/win32/q3ademo.exe
  15. Copyright 2006-2011 Burningwater, Thomas Alten
  16. */
  17. #include <irrlicht.h>
  18. #include "driverChoice.h"
  19. #include "exampleHelper.h"
  20. #include "q3factory.h"
  21. #include "sound.h"
  22. /*
  23. Game Data is used to hold Data which is needed to drive the game
  24. */
  25. struct GameData
  26. {
  27. GameData ( const path &startupDir) :
  28. retVal(0), StartupDir(startupDir), createExDevice(0), Device(0)
  29. {
  30. setDefault ();
  31. }
  32. void setDefault ();
  33. s32 save ( const path &filename );
  34. s32 load ( const path &filename );
  35. s32 debugState;
  36. s32 gravityState;
  37. s32 flyTroughState;
  38. s32 wireFrame;
  39. s32 guiActive;
  40. s32 guiInputActive;
  41. f32 GammaValue;
  42. s32 retVal;
  43. s32 sound;
  44. path StartupDir;
  45. stringw CurrentMapName;
  46. array<path> CurrentArchiveList;
  47. vector3df PlayerPosition;
  48. vector3df PlayerRotation;
  49. tQ3EntityList Variable;
  50. Q3LevelLoadParameter loadParam;
  51. SIrrlichtCreationParameters deviceParam;
  52. funcptr_createDeviceEx createExDevice;
  53. IrrlichtDevice *Device;
  54. };
  55. /*
  56. set default settings
  57. */
  58. void GameData::setDefault ()
  59. {
  60. debugState = EDS_OFF;
  61. gravityState = 1;
  62. flyTroughState = 0;
  63. wireFrame = 0;
  64. guiActive = 1;
  65. guiInputActive = 0;
  66. GammaValue = 1.f;
  67. // default deviceParam;
  68. #if defined ( _IRR_WINDOWS_ )
  69. deviceParam.DriverType = EDT_DIRECT3D9;
  70. #else
  71. deviceParam.DriverType = EDT_OPENGL;
  72. #endif
  73. deviceParam.WindowSize.Width = 800;
  74. deviceParam.WindowSize.Height = 600;
  75. deviceParam.Fullscreen = false;
  76. deviceParam.Bits = 24;
  77. deviceParam.ZBufferBits = 16;
  78. deviceParam.Vsync = false;
  79. deviceParam.AntiAlias = false;
  80. // default Quake3 loadParam
  81. loadParam.defaultLightMapMaterial = EMT_LIGHTMAP;
  82. loadParam.defaultModulate = EMFN_MODULATE_1X;
  83. loadParam.defaultFilter = EMF_ANISOTROPIC_FILTER;
  84. loadParam.verbose = 2;
  85. loadParam.mergeShaderBuffer = 1; // merge meshbuffers with same material
  86. loadParam.cleanUnResolvedMeshes = 1; // should unresolved meshes be cleaned. otherwise blue texture
  87. loadParam.loadAllShaders = 1; // load all scripts in the script directory
  88. loadParam.loadSkyShader = 0; // load sky Shader
  89. loadParam.alpharef = 1;
  90. sound = 0;
  91. CurrentMapName = "";
  92. CurrentArchiveList.clear ();
  93. const io::path mediaPath = getExampleMediaPath();
  94. // Explorer Media directory
  95. CurrentArchiveList.push_back ( StartupDir + mediaPath );
  96. // Add the original quake3 files before you load your custom map
  97. // Most mods are using the original shaders, models&items&weapons
  98. CurrentArchiveList.push_back("/q/baseq3/");
  99. CurrentArchiveList.push_back(StartupDir + mediaPath + "map-20kdm2.pk3");
  100. }
  101. /*
  102. Load the current game State from a typical quake3 cfg file
  103. */
  104. s32 GameData::load ( const path &filename )
  105. {
  106. if (!Device)
  107. return 0;
  108. // the quake3 mesh loader can also handle *.shader and *.cfg file
  109. IQ3LevelMesh* mesh = (IQ3LevelMesh*) Device->getSceneManager()->getMesh ( filename );
  110. if (!mesh)
  111. return 0;
  112. tQ3EntityList &entityList = mesh->getEntityList ();
  113. stringc s;
  114. u32 pos;
  115. for ( u32 e = 0; e != entityList.size (); ++e )
  116. {
  117. //dumpShader ( s, &entityList[e], false );
  118. //printf ( s.c_str () );
  119. for ( u32 g = 0; g != entityList[e].getGroupSize (); ++g )
  120. {
  121. const SVarGroup *group = entityList[e].getGroup ( g );
  122. for ( u32 index = 0; index < group->Variable.size (); ++index )
  123. {
  124. const SVariable &v = group->Variable[index];
  125. pos = 0;
  126. if ( v.name == "playerposition" )
  127. {
  128. PlayerPosition = getAsVector3df ( v.content, pos );
  129. }
  130. else
  131. if ( v.name == "playerrotation" )
  132. {
  133. PlayerRotation = getAsVector3df ( v.content, pos );
  134. }
  135. }
  136. }
  137. }
  138. return 1;
  139. }
  140. /*
  141. Store the current game State in a quake3 configuration file
  142. */
  143. s32 GameData::save ( const path &filename )
  144. {
  145. return 0;
  146. if (!Device)
  147. return 0;
  148. c8 buf[128];
  149. u32 i;
  150. // Store current Archive for restart
  151. CurrentArchiveList.clear();
  152. IFileSystem *fs = Device->getFileSystem();
  153. for ( i = 0; i != fs->getFileArchiveCount(); ++i )
  154. {
  155. CurrentArchiveList.push_back ( fs->getFileArchive(i)->getFileList()->getPath() );
  156. }
  157. // Store Player Position and Rotation
  158. ICameraSceneNode * camera = Device->getSceneManager()->getActiveCamera ();
  159. if ( camera )
  160. {
  161. PlayerPosition = camera->getPosition ();
  162. PlayerRotation = camera->getRotation ();
  163. }
  164. IWriteFile *file = fs->createAndWriteFile ( filename );
  165. if (!file)
  166. return 0;
  167. snprintf_irr ( buf, 128, "playerposition %.f %.f %.f\nplayerrotation %.f %.f %.f\n",
  168. PlayerPosition.X, PlayerPosition.Z, PlayerPosition.Y,
  169. PlayerRotation.X, PlayerRotation.Z, PlayerRotation.Y);
  170. file->write ( buf, (s32) strlen ( buf ) );
  171. for ( i = 0; i != fs->getFileArchiveCount(); ++i )
  172. {
  173. snprintf_irr ( buf, 128, "archive %s\n",stringc ( fs->getFileArchive(i)->getFileList()->getPath() ).c_str () );
  174. file->write ( buf, (s32) strlen ( buf ) );
  175. }
  176. file->drop ();
  177. return 1;
  178. }
  179. /*
  180. Representing a player
  181. */
  182. struct Q3Player : public IAnimationEndCallBack
  183. {
  184. Q3Player ()
  185. : Device(0), MapParent(0), Mesh(0), WeaponNode(0), StartPositionCurrent(0)
  186. {
  187. animation[0] = 0;
  188. memset(Anim, 0, sizeof(TimeFire)*4);
  189. }
  190. virtual void OnAnimationEnd(IAnimatedMeshSceneNode* node);
  191. void create ( IrrlichtDevice *device,
  192. IQ3LevelMesh* mesh,
  193. ISceneNode *mapNode,
  194. IMetaTriangleSelector *meta
  195. );
  196. void shutdown ();
  197. void setAnim ( const c8 *name );
  198. void respawn ();
  199. void setpos ( const vector3df &pos, const vector3df& rotation );
  200. ISceneNodeAnimatorCollisionResponse * cam() { return camCollisionResponse ( Device ); }
  201. IrrlichtDevice *Device;
  202. ISceneNode* MapParent;
  203. IQ3LevelMesh* Mesh;
  204. IAnimatedMeshSceneNode* WeaponNode;
  205. s32 StartPositionCurrent;
  206. TimeFire Anim[4];
  207. c8 animation[64];
  208. c8 buf[64];
  209. };
  210. /* End player
  211. */
  212. void Q3Player::shutdown ()
  213. {
  214. setAnim ( 0 );
  215. dropElement (WeaponNode);
  216. if ( Device )
  217. {
  218. ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera();
  219. dropElement ( camera );
  220. Device = 0;
  221. }
  222. MapParent = 0;
  223. Mesh = 0;
  224. }
  225. /* create a new player
  226. */
  227. void Q3Player::create ( IrrlichtDevice *device, IQ3LevelMesh* mesh, ISceneNode *mapNode, IMetaTriangleSelector *meta )
  228. {
  229. setTimeFire ( Anim + 0, 200, FIRED );
  230. setTimeFire ( Anim + 1, 5000 );
  231. if (!device)
  232. return;
  233. // load FPS weapon to Camera
  234. Device = device;
  235. Mesh = mesh;
  236. MapParent = mapNode;
  237. ISceneManager *smgr = device->getSceneManager ();
  238. IVideoDriver * driver = device->getVideoDriver();
  239. ICameraSceneNode* camera = 0;
  240. core::array<SKeyMap> keyMap;
  241. keyMap.set_used(12);
  242. keyMap[0].Action = EKA_MOVE_FORWARD;
  243. keyMap[0].KeyCode = KEY_UP;
  244. keyMap[1].Action = EKA_MOVE_FORWARD;
  245. keyMap[1].KeyCode = KEY_KEY_W;
  246. keyMap[2].Action = EKA_MOVE_BACKWARD;
  247. keyMap[2].KeyCode = KEY_DOWN;
  248. keyMap[3].Action = EKA_MOVE_BACKWARD;
  249. keyMap[3].KeyCode = KEY_KEY_S;
  250. keyMap[4].Action = EKA_STRAFE_LEFT;
  251. keyMap[4].KeyCode = KEY_LEFT;
  252. keyMap[5].Action = EKA_STRAFE_LEFT;
  253. keyMap[5].KeyCode = KEY_KEY_A;
  254. keyMap[6].Action = EKA_STRAFE_RIGHT;
  255. keyMap[6].KeyCode = KEY_RIGHT;
  256. keyMap[7].Action = EKA_STRAFE_RIGHT;
  257. keyMap[7].KeyCode = KEY_KEY_D;
  258. keyMap[8].Action = EKA_JUMP_UP;
  259. keyMap[8].KeyCode = KEY_KEY_J;
  260. keyMap[9].Action = EKA_CROUCH;
  261. keyMap[9].KeyCode = KEY_KEY_C;
  262. keyMap[10].Action = EKA_ROTATE_LEFT;
  263. keyMap[10].KeyCode = KEY_KEY_Q;
  264. keyMap[11].Action = EKA_ROTATE_RIGHT;
  265. keyMap[11].KeyCode = KEY_KEY_E;
  266. camera = smgr->addCameraSceneNodeFPS(0, 100.0f, 0.6f, -1, keyMap.pointer(), keyMap.size(), false, 600.f);
  267. camera->setName ( "First Person Camera" );
  268. //camera->setFOV ( 100.f * core::DEGTORAD );
  269. camera->setFarValue( 20000.f );
  270. IAnimatedMeshMD2* weaponMesh = (IAnimatedMeshMD2*) smgr->getMesh("gun.md2");
  271. if ( 0 == weaponMesh )
  272. return;
  273. if ( weaponMesh->getMeshType() == EAMT_MD2 )
  274. {
  275. s32 count = weaponMesh->getAnimationCount();
  276. for ( s32 i = 0; i != count; ++i )
  277. {
  278. snprintf_irr ( buf, 64, "Animation: %s", weaponMesh->getAnimationName(i) );
  279. device->getLogger()->log(buf, ELL_INFORMATION);
  280. }
  281. }
  282. WeaponNode = smgr->addAnimatedMeshSceneNode(
  283. weaponMesh,
  284. smgr->getActiveCamera(),
  285. 10,
  286. vector3df( 0, 0, 0),
  287. vector3df(-90,-90,90)
  288. );
  289. WeaponNode->setMaterialFlag(EMF_LIGHTING, false);
  290. WeaponNode->setMaterialTexture(0, driver->getTexture( "gun.jpg"));
  291. WeaponNode->setLoopMode ( false );
  292. WeaponNode->setName ( "tommi the gun man" );
  293. //create a collision auto response animator
  294. ISceneNodeAnimator* anim =
  295. smgr->createCollisionResponseAnimator( meta, camera,
  296. vector3df(30,45,30),
  297. getGravity ( "earth" ),
  298. vector3df(0,40,0),
  299. 0.0005f
  300. );
  301. camera->addAnimator( anim );
  302. anim->drop();
  303. if ( meta )
  304. {
  305. meta->drop ();
  306. }
  307. respawn ();
  308. setAnim ( "idle" );
  309. }
  310. /*
  311. so we need a good starting Position in the level.
  312. we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch"
  313. */
  314. void Q3Player::respawn ()
  315. {
  316. if (!Device)
  317. return;
  318. ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera();
  319. Device->getLogger()->log( "respawn" );
  320. if (StartPositionCurrent >= Q3StartPosition(Mesh, camera,
  321. StartPositionCurrent, cam()->getEllipsoidTranslation()))
  322. StartPositionCurrent = 0;
  323. else
  324. ++StartPositionCurrent;
  325. }
  326. /*
  327. set Player position from saved coordinates
  328. */
  329. void Q3Player::setpos ( const vector3df &pos, const vector3df &rotation )
  330. {
  331. if (!Device)
  332. return;
  333. Device->getLogger()->log( "setpos" );
  334. ICameraSceneNode* camera = Device->getSceneManager()->getActiveCamera();
  335. if ( camera )
  336. {
  337. camera->setPosition ( pos );
  338. camera->setRotation ( rotation );
  339. //! New. FPSCamera and animators catches reset on animate 0
  340. camera->OnAnimate ( 0 );
  341. }
  342. }
  343. /* set the Animation of the player and weapon
  344. */
  345. void Q3Player::setAnim ( const c8 *name )
  346. {
  347. if ( name )
  348. {
  349. snprintf_irr ( animation, 64, "%s", name );
  350. if ( WeaponNode )
  351. {
  352. WeaponNode->setAnimationEndCallback ( this );
  353. WeaponNode->setMD2Animation ( animation );
  354. }
  355. }
  356. else
  357. {
  358. animation[0] = 0;
  359. if ( WeaponNode )
  360. {
  361. WeaponNode->setAnimationEndCallback ( 0 );
  362. }
  363. }
  364. }
  365. // Callback
  366. void Q3Player::OnAnimationEnd(IAnimatedMeshSceneNode* node)
  367. {
  368. setAnim ( 0 );
  369. }
  370. /* GUI Elements
  371. */
  372. struct GUI
  373. {
  374. GUI ()
  375. {
  376. memset ( this, 0, sizeof ( *this ) );
  377. }
  378. void drop()
  379. {
  380. dropElement ( Window );
  381. dropElement ( Logo );
  382. }
  383. IGUIComboBox* VideoDriver;
  384. IGUIComboBox* VideoMode;
  385. IGUICheckBox* FullScreen;
  386. IGUICheckBox* Bit32;
  387. IGUIScrollBar* MultiSample;
  388. IGUIButton* SetVideoMode;
  389. IGUIScrollBar* Tesselation;
  390. IGUIScrollBar* Gamma;
  391. IGUICheckBox* Collision;
  392. IGUICheckBox* Visible_Map;
  393. IGUICheckBox* Visible_Shader;
  394. IGUICheckBox* Visible_Fog;
  395. IGUICheckBox* Visible_Unresolved;
  396. IGUICheckBox* Visible_Skydome;
  397. IGUIButton* Respawn;
  398. IGUITable* ArchiveList;
  399. IGUIButton* ArchiveAdd;
  400. IGUIButton* ArchiveRemove;
  401. IGUIFileOpenDialog* ArchiveFileOpen;
  402. IGUIButton* ArchiveUp;
  403. IGUIButton* ArchiveDown;
  404. IGUIListBox* MapList;
  405. IGUITreeView* SceneTree;
  406. IGUIStaticText* StatusLine;
  407. IGUIImage* Logo;
  408. IGUIWindow* Window;
  409. };
  410. /*
  411. CQuake3EventHandler controls the game
  412. */
  413. class CQuake3EventHandler : public IEventReceiver
  414. {
  415. public:
  416. CQuake3EventHandler( GameData *gameData );
  417. virtual ~CQuake3EventHandler ();
  418. void Animate();
  419. void Render();
  420. void AddArchive ( const path& archiveName );
  421. void LoadMap ( const stringw& mapName, s32 collision );
  422. void CreatePlayers();
  423. void AddSky( u32 dome, const c8 *texture );
  424. Q3Player *GetPlayer ( u32 index ) { return &Player[index]; }
  425. void CreateGUI();
  426. void SetGUIActive( s32 command);
  427. bool OnEvent(const SEvent& eve);
  428. private:
  429. GameData *Game;
  430. IQ3LevelMesh* Mesh;
  431. ISceneNode* MapParent;
  432. ISceneNode* ShaderParent;
  433. ISceneNode* ItemParent;
  434. ISceneNode* UnresolvedParent;
  435. ISceneNode* BulletParent;
  436. ISceneNode* FogParent;
  437. ISceneNode * SkyNode;
  438. IMetaTriangleSelector *Meta;
  439. c8 buf[256];
  440. Q3Player Player[2];
  441. struct SParticleImpact
  442. {
  443. u32 when;
  444. vector3df pos;
  445. vector3df outVector;
  446. };
  447. array<SParticleImpact> Impacts;
  448. void useItem( Q3Player * player);
  449. void createParticleImpacts( u32 now );
  450. void createTextures ();
  451. void addSceneTreeItem( ISceneNode * parent, IGUITreeViewNode* nodeParent);
  452. GUI gui;
  453. void dropMap ();
  454. };
  455. /* Constructor
  456. */
  457. CQuake3EventHandler::CQuake3EventHandler( GameData *game )
  458. : Game(game), Mesh(0), MapParent(0), ShaderParent(0), ItemParent(0), UnresolvedParent(0),
  459. BulletParent(0), FogParent(0), SkyNode(0), Meta(0)
  460. {
  461. buf[0]=0;
  462. // Also use 16 Bit Textures for 16 Bit RenderDevice
  463. if ( Game->deviceParam.Bits == 16 )
  464. {
  465. game->Device->getVideoDriver()->setTextureCreationFlag(ETCF_ALWAYS_16_BIT, true);
  466. }
  467. // Quake3 Shader controls Z-Writing
  468. game->Device->getSceneManager()->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
  469. // create internal textures
  470. createTextures ();
  471. sound_init ( game->Device );
  472. Game->Device->setEventReceiver ( this );
  473. }
  474. // destructor
  475. CQuake3EventHandler::~CQuake3EventHandler ()
  476. {
  477. Player[0].shutdown ();
  478. sound_shutdown ();
  479. Game->save( "explorer.cfg" );
  480. Game->Device->drop();
  481. }
  482. // create runtime textures smog, fog
  483. void CQuake3EventHandler::createTextures()
  484. {
  485. IVideoDriver * driver = Game->Device->getVideoDriver();
  486. dimension2du dim(64, 64);
  487. video::IImage* image;
  488. u32 i;
  489. u32 x;
  490. u32 y;
  491. u32 * data;
  492. for ( i = 0; i != 8; ++i )
  493. {
  494. image = driver->createImage ( video::ECF_A8R8G8B8, dim);
  495. data = (u32*) image->getData ();
  496. for ( y = 0; y != dim.Height; ++y )
  497. {
  498. for ( x = 0; x != dim.Width; ++x )
  499. {
  500. data [x] = 0xFFFFFFFF;
  501. }
  502. data = (u32*) ( (u8*) data + image->getPitch() );
  503. }
  504. snprintf_irr ( buf, 64, "smoke_%02d", i );
  505. driver->addTexture( buf, image );
  506. image->drop ();
  507. }
  508. // fog
  509. for ( i = 0; i != 1; ++i )
  510. {
  511. image = driver->createImage ( video::ECF_A8R8G8B8, dim);
  512. data = (u32*) image->getData ();
  513. for ( y = 0; y != dim.Height; ++y )
  514. {
  515. for ( x = 0; x != dim.Width; ++x )
  516. {
  517. data [x] = 0xFFFFFFFF;
  518. }
  519. data = (u32*) ( (u8*) data + image->getPitch() );
  520. }
  521. snprintf_irr ( buf, 64, "fog_%02d", i );
  522. driver->addTexture( buf, image );
  523. image->drop ();
  524. }
  525. }
  526. /*
  527. create the GUI
  528. */
  529. void CQuake3EventHandler::CreateGUI()
  530. {
  531. IGUIEnvironment *env = Game->Device->getGUIEnvironment();
  532. IVideoDriver * driver = Game->Device->getVideoDriver();
  533. gui.drop();
  534. // set skin font
  535. IGUIFont* font = env->getFont("fontlucida.png");
  536. if (font)
  537. env->getSkin()->setFont(font);
  538. env->getSkin()->setColor ( EGDC_BUTTON_TEXT, video::SColor(240,0xAA,0xAA,0xAA) );
  539. env->getSkin()->setColor ( EGDC_3D_HIGH_LIGHT, video::SColor(240,0x22,0x22,0x22) );
  540. env->getSkin()->setColor ( EGDC_3D_FACE, video::SColor(240,0x44,0x44,0x44) );
  541. env->getSkin()->setColor ( EGDC_EDITABLE, video::SColor(240,0x44,0x44,0x44) );
  542. env->getSkin()->setColor ( EGDC_FOCUSED_EDITABLE, video::SColor(240,0x54,0x54,0x54) );
  543. env->getSkin()->setColor ( EGDC_WINDOW, video::SColor(240,0x66,0x66,0x66) );
  544. // minimal gui size 800x600
  545. dimension2d<u32> dim ( 800, 600 );
  546. dimension2d<u32> vdim ( Game->Device->getVideoDriver()->getScreenSize() );
  547. if ( vdim.Height >= dim.Height && vdim.Width >= dim.Width )
  548. {
  549. //dim = vdim;
  550. }
  551. else
  552. {
  553. }
  554. gui.Window = env->addWindow ( rect<s32> ( 0, 0, dim.Width, dim.Height ), false, L"Quake3 Explorer" );
  555. gui.Window->setToolTipText ( L"Quake3Explorer. Loads and show various BSP File Format and Shaders." );
  556. gui.Window->getCloseButton()->setToolTipText ( L"Quit Quake3 Explorer" );
  557. // add a status line help text
  558. gui.StatusLine = env->addStaticText( 0, rect<s32>( 5,dim.Height - 30,dim.Width - 5,dim.Height - 10),
  559. false, false, gui.Window, -1, true
  560. );
  561. env->addStaticText ( L"VideoDriver:", rect<s32>( dim.Width - 400, 24, dim.Width - 310, 40 ),false, false, gui.Window, -1, false );
  562. gui.VideoDriver = env->addComboBox(rect<s32>( dim.Width - 300, 24, dim.Width - 10, 40 ),gui.Window);
  563. gui.VideoDriver->addItem(L"Direct3D 9.0c", EDT_DIRECT3D9 );
  564. gui.VideoDriver->addItem(L"OpenGL 1.5", EDT_OPENGL);
  565. gui.VideoDriver->addItem(L"Software Renderer", EDT_SOFTWARE);
  566. gui.VideoDriver->addItem(L"Burning's Video (TM) Thomas Alten", EDT_BURNINGSVIDEO);
  567. gui.VideoDriver->setSelected ( gui.VideoDriver->getIndexForItemData ( Game->deviceParam.DriverType ) );
  568. gui.VideoDriver->setToolTipText ( L"Use a VideoDriver" );
  569. env->addStaticText ( L"VideoMode:", rect<s32>( dim.Width - 400, 44, dim.Width - 310, 60 ),false, false, gui.Window, -1, false );
  570. gui.VideoMode = env->addComboBox(rect<s32>( dim.Width - 300, 44, dim.Width - 10, 60 ),gui.Window);
  571. gui.VideoMode->setToolTipText ( L"Supported Screenmodes" );
  572. IVideoModeList *modeList = Game->Device->getVideoModeList();
  573. if ( modeList )
  574. {
  575. s32 i;
  576. for ( i = 0; i != modeList->getVideoModeCount (); ++i )
  577. {
  578. u16 d = modeList->getVideoModeDepth ( i );
  579. if ( d < 16 )
  580. continue;
  581. u16 w = modeList->getVideoModeResolution ( i ).Width;
  582. u16 h = modeList->getVideoModeResolution ( i ).Height;
  583. u32 val = w << 16 | h;
  584. if ( gui.VideoMode->getIndexForItemData ( val ) >= 0 )
  585. continue;
  586. f32 aspect = (f32) w / (f32) h;
  587. const c8 *a = "";
  588. if ( core::equals ( aspect, 1.3333333333f ) ) a = "4:3";
  589. else if ( core::equals ( aspect, 1.6666666f ) ) a = "15:9 widescreen";
  590. else if ( core::equals ( aspect, 1.7777777f ) ) a = "16:9 widescreen";
  591. else if ( core::equals ( aspect, 1.6f ) ) a = "16:10 widescreen";
  592. else if ( core::equals ( aspect, 2.133333f ) ) a = "20:9 widescreen";
  593. snprintf_irr ( buf, sizeof ( buf ), "%d x %d, %s",w, h, a );
  594. gui.VideoMode->addItem ( stringw ( buf ).c_str(), val );
  595. }
  596. }
  597. gui.VideoMode->setSelected ( gui.VideoMode->getIndexForItemData (
  598. Game->deviceParam.WindowSize.Width << 16 |
  599. Game->deviceParam.WindowSize.Height ) );
  600. gui.FullScreen = env->addCheckBox ( Game->deviceParam.Fullscreen, rect<s32>( dim.Width - 400, 64, dim.Width - 300, 80 ), gui.Window,-1, L"Fullscreen" );
  601. gui.FullScreen->setToolTipText ( L"Set Fullscreen or Window Mode" );
  602. gui.Bit32 = env->addCheckBox ( Game->deviceParam.Bits == 32, rect<s32>( dim.Width - 300, 64, dim.Width - 240, 80 ), gui.Window,-1, L"32Bit" );
  603. gui.Bit32->setToolTipText ( L"Use 16 or 32 Bit" );
  604. env->addStaticText ( L"MultiSample:", rect<s32>( dim.Width - 235, 64, dim.Width - 150, 80 ),false, false, gui.Window, -1, false );
  605. gui.MultiSample = env->addScrollBar( true, rect<s32>( dim.Width - 150, 64, dim.Width - 70, 80 ), gui.Window,-1 );
  606. gui.MultiSample->setMin ( 0 );
  607. gui.MultiSample->setMax ( 8 );
  608. gui.MultiSample->setSmallStep ( 1 );
  609. gui.MultiSample->setLargeStep ( 1 );
  610. gui.MultiSample->setPos ( Game->deviceParam.AntiAlias );
  611. gui.MultiSample->setToolTipText ( L"Set the MultiSample (disable, 1x, 2x, 4x, 8x )" );
  612. gui.SetVideoMode = env->addButton (rect<s32>( dim.Width - 60, 64, dim.Width - 10, 80 ), gui.Window, -1,L"set" );
  613. gui.SetVideoMode->setToolTipText ( L"Set Video Mode with current values" );
  614. env->addStaticText ( L"Gamma:", rect<s32>( dim.Width - 400, 104, dim.Width - 310, 120 ),false, false, gui.Window, -1, false );
  615. gui.Gamma = env->addScrollBar( true, rect<s32>( dim.Width - 300, 104, dim.Width - 10, 120 ), gui.Window,-1 );
  616. gui.Gamma->setMin ( 50 );
  617. gui.Gamma->setMax ( 350 );
  618. gui.Gamma->setSmallStep ( 1 );
  619. gui.Gamma->setLargeStep ( 10 );
  620. gui.Gamma->setPos ( core::floor32 ( Game->GammaValue * 100.f ) );
  621. gui.Gamma->setToolTipText ( L"Adjust Gamma Ramp ( 0.5 - 3.5)" );
  622. Game->Device->setGammaRamp ( Game->GammaValue, Game->GammaValue, Game->GammaValue, 0.f, 0.f );
  623. env->addStaticText ( L"Tesselation:", rect<s32>( dim.Width - 400, 124, dim.Width - 310, 140 ),false, false, gui.Window, -1, false );
  624. gui.Tesselation = env->addScrollBar( true, rect<s32>( dim.Width - 300, 124, dim.Width - 10, 140 ), gui.Window,-1 );
  625. gui.Tesselation->setMin ( 2 );
  626. gui.Tesselation->setMax ( 12 );
  627. gui.Tesselation->setSmallStep ( 1 );
  628. gui.Tesselation->setLargeStep ( 1 );
  629. gui.Tesselation->setPos ( Game->loadParam.patchTesselation );
  630. gui.Tesselation->setToolTipText ( L"How smooth should curved surfaces be rendered" );
  631. gui.Collision = env->addCheckBox ( true, rect<s32>( dim.Width - 400, 150, dim.Width - 300, 166 ), gui.Window,-1, L"Collision" );
  632. gui.Collision->setToolTipText ( L"Set collision on or off ( flythrough ). \nPress F7 on your Keyboard" );
  633. gui.Visible_Map = env->addCheckBox ( true, rect<s32>( dim.Width - 300, 150, dim.Width - 240, 166 ), gui.Window,-1, L"Map" );
  634. gui.Visible_Map->setToolTipText ( L"Show or not show the static part the Level. \nPress F3 on your Keyboard" );
  635. gui.Visible_Shader = env->addCheckBox ( true, rect<s32>( dim.Width - 240, 150, dim.Width - 170, 166 ), gui.Window,-1, L"Shader" );
  636. gui.Visible_Shader->setToolTipText ( L"Show or not show the Shader Nodes. \nPress F4 on your Keyboard" );
  637. gui.Visible_Fog = env->addCheckBox ( true, rect<s32>( dim.Width - 170, 150, dim.Width - 110, 166 ), gui.Window,-1, L"Fog" );
  638. gui.Visible_Fog->setToolTipText ( L"Show or not show the Fog Nodes. \nPress F5 on your Keyboard" );
  639. gui.Visible_Unresolved = env->addCheckBox ( true, rect<s32>( dim.Width - 110, 150, dim.Width - 10, 166 ), gui.Window,-1, L"Unresolved" );
  640. gui.Visible_Unresolved->setToolTipText ( L"Show the or not show the Nodes the Engine can't handle. \nPress F6 on your Keyboard" );
  641. gui.Visible_Skydome = env->addCheckBox ( true, rect<s32>( dim.Width - 110, 180, dim.Width - 10, 196 ), gui.Window,-1, L"Skydome" );
  642. gui.Visible_Skydome->setToolTipText ( L"Show the or not show the Skydome." );
  643. //Respawn = env->addButton ( rect<s32>( dim.Width - 260, 90, dim.Width - 10, 106 ), 0,-1, L"Respawn" );
  644. env->addStaticText ( L"Archives:", rect<s32>( 5, dim.Height - 530, dim.Width - 600,dim.Height - 514 ),false, false, gui.Window, -1, false );
  645. gui.ArchiveAdd = env->addButton ( rect<s32>( dim.Width - 725, dim.Height - 530, dim.Width - 665, dim.Height - 514 ), gui.Window,-1, L"add" );
  646. gui.ArchiveAdd->setToolTipText ( L"Add an archive, usually packed zip-archives (*.pk3) to the Filesystem" );
  647. gui.ArchiveRemove = env->addButton ( rect<s32>( dim.Width - 660, dim.Height - 530, dim.Width - 600, dim.Height - 514 ), gui.Window,-1, L"del" );
  648. gui.ArchiveRemove->setToolTipText ( L"Remove the selected archive from the FileSystem." );
  649. gui.ArchiveUp = env->addButton ( rect<s32>( dim.Width - 575, dim.Height - 530, dim.Width - 515, dim.Height - 514 ), gui.Window,-1, L"up" );
  650. gui.ArchiveUp->setToolTipText ( L"Arrange Archive Look-up Hirachy. Move the selected Archive up" );
  651. gui.ArchiveDown = env->addButton ( rect<s32>( dim.Width - 510, dim.Height - 530, dim.Width - 440, dim.Height - 514 ), gui.Window,-1, L"down" );
  652. gui.ArchiveDown->setToolTipText ( L"Arrange Archive Look-up Hirachy. Move the selected Archive down" );
  653. gui.ArchiveList = env->addTable ( rect<s32>( 5,dim.Height - 510, dim.Width - 450,dim.Height - 410 ), gui.Window );
  654. gui.ArchiveList->addColumn ( L"Type", 0 );
  655. gui.ArchiveList->addColumn ( L"Real File Path", 1 );
  656. gui.ArchiveList->setColumnWidth ( 0, 60 );
  657. gui.ArchiveList->setColumnWidth ( 1, 284 );
  658. gui.ArchiveList->setToolTipText ( L"Show the attached Archives" );
  659. env->addStaticText ( L"Maps:", rect<s32>( 5, dim.Height - 400, dim.Width - 450,dim.Height - 380 ),false, false, gui.Window, -1, false );
  660. gui.MapList = env->addListBox ( rect<s32>( 5,dim.Height - 380, dim.Width - 450,dim.Height - 40 ), gui.Window, -1, true );
  661. gui.MapList->setToolTipText ( L"Show the current Maps in all Archives.\n Double-Click the Map to start the level" );
  662. // create a visible Scene Tree
  663. env->addStaticText ( L"Scenegraph:", rect<s32>( dim.Width - 400, dim.Height - 400, dim.Width - 5,dim.Height - 380 ),false, false, gui.Window, -1, false );
  664. gui.SceneTree = env->addTreeView( rect<s32>( dim.Width - 400, dim.Height - 380, dim.Width - 5, dim.Height - 40 ),
  665. gui.Window, -1, true, true, false );
  666. gui.SceneTree->setToolTipText ( L"Show the current Scenegraph" );
  667. gui.SceneTree->getRoot()->clearChildren();
  668. addSceneTreeItem ( Game->Device->getSceneManager()->getRootSceneNode(), gui.SceneTree->getRoot() );
  669. IGUIImageList* imageList = env->createImageList( driver->getTexture ( "iconlist.png" ),
  670. dimension2di( 32, 32 ), true );
  671. if ( imageList )
  672. {
  673. gui.SceneTree->setImageList( imageList );
  674. imageList->drop ();
  675. }
  676. // load the engine logo
  677. gui.Logo = env->addImage( driver->getTexture("irrlichtlogo3.png"), position2d<s32>(5, 16 ), true, 0 );
  678. gui.Logo->setToolTipText ( L"The great Irrlicht Engine" );
  679. AddArchive ( "" );
  680. }
  681. /*
  682. Add an Archive to the FileSystems and updates the GUI
  683. */
  684. void CQuake3EventHandler::AddArchive ( const path& archiveName )
  685. {
  686. IFileSystem *fs = Game->Device->getFileSystem();
  687. u32 i;
  688. if ( archiveName.size () )
  689. {
  690. bool exists = false;
  691. for ( i = 0; i != fs->getFileArchiveCount(); ++i )
  692. {
  693. if ( fs->getFileArchive(i)->getFileList()->getPath() == archiveName )
  694. {
  695. exists = true;
  696. break;
  697. }
  698. }
  699. if (!exists)
  700. {
  701. fs->addFileArchive(archiveName, true, false);
  702. }
  703. }
  704. // store the current archives in game data
  705. // show the attached Archive in proper order
  706. if ( gui.ArchiveList )
  707. {
  708. gui.ArchiveList->clearRows();
  709. for ( i = 0; i != fs->getFileArchiveCount(); ++i )
  710. {
  711. IFileArchive * archive = fs->getFileArchive ( i );
  712. u32 index = gui.ArchiveList->addRow(i);
  713. core::stringw typeName;
  714. switch(archive->getType())
  715. {
  716. case io::EFAT_ZIP:
  717. typeName = "ZIP";
  718. break;
  719. case io::EFAT_GZIP:
  720. typeName = "gzip";
  721. break;
  722. case io::EFAT_FOLDER:
  723. typeName = "Mount";
  724. break;
  725. case io::EFAT_PAK:
  726. typeName = "PAK";
  727. break;
  728. case io::EFAT_TAR:
  729. typeName = "TAR";
  730. break;
  731. default:
  732. typeName = "archive";
  733. }
  734. gui.ArchiveList->setCellText ( index, 0, typeName );
  735. gui.ArchiveList->setCellText ( index, 1, archive->getFileList()->getPath() );
  736. }
  737. }
  738. // browse the archives for maps
  739. if ( gui.MapList )
  740. {
  741. gui.MapList->clear();
  742. IGUISpriteBank *bank = Game->Device->getGUIEnvironment()->getSpriteBank("sprite_q3map");
  743. if ( 0 == bank )
  744. bank = Game->Device->getGUIEnvironment()->addEmptySpriteBank("sprite_q3map");
  745. SGUISprite sprite;
  746. SGUISpriteFrame frame;
  747. core::rect<s32> r;
  748. bank->getSprites().clear();
  749. bank->getPositions().clear ();
  750. gui.MapList->setSpriteBank ( bank );
  751. u32 g = 0;
  752. core::stringw s;
  753. // browse the attached file system
  754. fs->setFileListSystem ( FILESYSTEM_VIRTUAL );
  755. fs->changeWorkingDirectoryTo ( "/maps/" );
  756. IFileList *fileList = fs->createFileList ();
  757. fs->setFileListSystem ( FILESYSTEM_NATIVE );
  758. for ( i=0; i< fileList->getFileCount(); ++i)
  759. {
  760. s = fileList->getFullFileName(i);
  761. if ( s.find ( ".bsp" ) >= 0 )
  762. {
  763. // get level screenshot. reformat texture to 128x128
  764. path c ( s );
  765. deletePathFromFilename ( c );
  766. cutFilenameExtension ( c, c );
  767. c = path ( "levelshots/" ) + c;
  768. dimension2du dim ( 128, 128 );
  769. IVideoDriver * driver = Game->Device->getVideoDriver();
  770. IImage* image = 0;
  771. ITexture *tex = 0;
  772. path filename;
  773. filename = c + ".jpg";
  774. if ( fs->existFile ( filename ) )
  775. image = driver->createImageFromFile( filename );
  776. if ( 0 == image )
  777. {
  778. filename = c + ".tga";
  779. if ( fs->existFile ( filename ) )
  780. image = driver->createImageFromFile( filename );
  781. }
  782. if ( image )
  783. {
  784. IImage* filter = driver->createImage ( video::ECF_R8G8B8, dim );
  785. image->copyToScalingBoxFilter ( filter, 0 );
  786. image->drop ();
  787. image = filter;
  788. }
  789. if ( image )
  790. {
  791. tex = driver->addTexture ( filename, image );
  792. image->drop ();
  793. }
  794. bank->setTexture ( g, tex );
  795. r.LowerRightCorner.X = dim.Width;
  796. r.LowerRightCorner.Y = dim.Height;
  797. gui.MapList->setItemHeight ( r.LowerRightCorner.Y + 4 );
  798. frame.rectNumber = bank->getPositions().size();
  799. frame.textureNumber = g;
  800. bank->getPositions().push_back(r);
  801. sprite.Frames.set_used ( 0 );
  802. sprite.Frames.push_back(frame);
  803. sprite.frameTime = 0;
  804. bank->getSprites().push_back(sprite);
  805. gui.MapList->addItem ( s.c_str (), g );
  806. g += 1;
  807. }
  808. }
  809. fileList->drop ();
  810. gui.MapList->setSelected ( -1 );
  811. IGUIScrollBar * bar = (IGUIScrollBar*)gui.MapList->getElementFromId( 0 );
  812. if ( bar )
  813. bar->setPos ( 0 );
  814. }
  815. }
  816. /*
  817. clears the Map in Memory
  818. */
  819. void CQuake3EventHandler::dropMap ()
  820. {
  821. IVideoDriver * driver = Game->Device->getVideoDriver();
  822. driver->removeAllHardwareBuffers ();
  823. driver->removeAllTextures ();
  824. Player[0].shutdown ();
  825. dropElement ( ItemParent );
  826. dropElement ( ShaderParent );
  827. dropElement ( UnresolvedParent );
  828. dropElement ( FogParent );
  829. dropElement ( BulletParent );
  830. Impacts.clear();
  831. if ( Meta )
  832. {
  833. Meta = 0;
  834. }
  835. dropElement ( MapParent );
  836. dropElement ( SkyNode );
  837. // clean out meshes, because textures are invalid
  838. // TODO: better texture handling;-)
  839. IMeshCache *cache = Game->Device->getSceneManager ()->getMeshCache();
  840. cache->clear ();
  841. Mesh = 0;
  842. }
  843. /* Load new map
  844. */
  845. void CQuake3EventHandler::LoadMap ( const stringw &mapName, s32 collision )
  846. {
  847. if ( 0 == mapName.size() )
  848. return;
  849. dropMap ();
  850. IFileSystem *fs = Game->Device->getFileSystem();
  851. ISceneManager *smgr = Game->Device->getSceneManager ();
  852. IReadFile* file = fs->createMemoryReadFile(&Game->loadParam,
  853. sizeof(Game->loadParam), L"levelparameter.cfg", false);
  854. // load cfg file
  855. smgr->getMesh( file );
  856. file->drop ();
  857. // load the actual map
  858. Mesh = (IQ3LevelMesh*) smgr->getMesh(mapName);
  859. if ( 0 == Mesh )
  860. return;
  861. /*
  862. add the geometry mesh to the Scene ( polygon & patches )
  863. The Geometry mesh is optimised for faster drawing
  864. */
  865. IMesh *geometry = Mesh->getMesh(E_Q3_MESH_GEOMETRY);
  866. if ( 0 == geometry || geometry->getMeshBufferCount() == 0)
  867. return;
  868. Game->CurrentMapName = mapName;
  869. //create a collision list
  870. Meta = 0;
  871. ITriangleSelector * selector = 0;
  872. if (collision)
  873. Meta = smgr->createMetaTriangleSelector();
  874. //IMeshBuffer *b0 = geometry->getMeshBuffer(0);
  875. //s32 minimalNodes = b0 ? core::s32_max ( 2048, b0->getVertexCount() / 32 ) : 2048;
  876. s32 minimalNodes = 2048;
  877. MapParent = smgr->addOctreeSceneNode(geometry, 0, -1, minimalNodes);
  878. MapParent->setName ( mapName );
  879. if ( Meta )
  880. {
  881. selector = smgr->createOctreeTriangleSelector( geometry,MapParent, minimalNodes);
  882. //selector = smgr->createTriangleSelector ( geometry, MapParent );
  883. Meta->addTriangleSelector( selector);
  884. selector->drop ();
  885. }
  886. // logical parent for the items
  887. ItemParent = smgr->addEmptySceneNode();
  888. if ( ItemParent )
  889. ItemParent->setName ( "Item Container" );
  890. ShaderParent = smgr->addEmptySceneNode();
  891. if ( ShaderParent )
  892. ShaderParent->setName ( "Shader Container" );
  893. UnresolvedParent = smgr->addEmptySceneNode();
  894. if ( UnresolvedParent )
  895. UnresolvedParent->setName ( "Unresolved Container" );
  896. FogParent = smgr->addEmptySceneNode();
  897. if ( FogParent )
  898. FogParent->setName ( "Fog Container" );
  899. // logical parent for the bullets
  900. BulletParent = smgr->addEmptySceneNode();
  901. if ( BulletParent )
  902. BulletParent->setName ( "Bullet Container" );
  903. /*
  904. now construct SceneNodes for each Shader
  905. The Objects are stored in the quake mesh E_Q3_MESH_ITEMS
  906. and the Shader ID is stored in the MaterialParameters
  907. mostly dark looking skulls and moving lava.. or green flashing tubes?
  908. */
  909. Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_ITEMS,ShaderParent, Meta, false );
  910. Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_FOG,FogParent, 0, false );
  911. Q3ShaderFactory ( Game->loadParam, Game->Device, Mesh, E_Q3_MESH_UNRESOLVED,UnresolvedParent, Meta, true );
  912. /*
  913. Now construct Models from Entity List
  914. */
  915. Q3ModelFactory ( Game->loadParam, Game->Device, Mesh, ItemParent, false );
  916. }
  917. /*
  918. Adds a SceneNode with an icon to the Scene Tree
  919. */
  920. void CQuake3EventHandler::addSceneTreeItem( ISceneNode * parent, IGUITreeViewNode* nodeParent)
  921. {
  922. IGUITreeViewNode* node;
  923. wchar_t msg[128];
  924. s32 imageIndex;
  925. list<ISceneNode*>::ConstIterator it = parent->getChildren().begin();
  926. for (; it != parent->getChildren().end(); ++it)
  927. {
  928. switch ( (*it)->getType () )
  929. {
  930. case ESNT_Q3SHADER_SCENE_NODE: imageIndex = 0; break;
  931. case ESNT_CAMERA: imageIndex = 1; break;
  932. case ESNT_EMPTY: imageIndex = 2; break;
  933. case ESNT_MESH: imageIndex = 3; break;
  934. case ESNT_OCTREE: imageIndex = 3; break;
  935. case ESNT_ANIMATED_MESH: imageIndex = 4; break;
  936. case ESNT_SKY_BOX: imageIndex = 5; break;
  937. case ESNT_BILLBOARD: imageIndex = 6; break;
  938. case ESNT_PARTICLE_SYSTEM: imageIndex = 7; break;
  939. case ESNT_TEXT: imageIndex = 8; break;
  940. default:imageIndex = -1; break;
  941. }
  942. if ( imageIndex < 0 )
  943. {
  944. swprintf_irr ( msg, 128, L"%hs,%hs",
  945. Game->Device->getSceneManager ()->getSceneNodeTypeName ( (*it)->getType () ),
  946. (*it)->getName()
  947. );
  948. }
  949. else
  950. {
  951. swprintf_irr ( msg, 128, L"%hs",(*it)->getName() );
  952. }
  953. node = nodeParent->addChildBack( msg, 0, imageIndex );
  954. // Add all Animators
  955. list<ISceneNodeAnimator*>::ConstIterator ait = (*it)->getAnimators().begin();
  956. for (; ait != (*it)->getAnimators().end(); ++ait)
  957. {
  958. imageIndex = -1;
  959. swprintf_irr ( msg, 128, L"%hs",
  960. Game->Device->getSceneManager ()->getAnimatorTypeName ( (*ait)->getType () )
  961. );
  962. switch ( (*ait)->getType () )
  963. {
  964. case ESNAT_FLY_CIRCLE:
  965. case ESNAT_FLY_STRAIGHT:
  966. case ESNAT_FOLLOW_SPLINE:
  967. case ESNAT_ROTATION:
  968. case ESNAT_TEXTURE:
  969. case ESNAT_DELETION:
  970. case ESNAT_COLLISION_RESPONSE:
  971. case ESNAT_CAMERA_FPS:
  972. case ESNAT_CAMERA_MAYA:
  973. default:
  974. break;
  975. }
  976. node->addChildBack( msg, 0, imageIndex );
  977. }
  978. addSceneTreeItem ( *it, node );
  979. }
  980. }
  981. // Adds life!
  982. void CQuake3EventHandler::CreatePlayers()
  983. {
  984. Player[0].create ( Game->Device, Mesh, MapParent, Meta );
  985. }
  986. // Adds a skydome to the scene
  987. void CQuake3EventHandler::AddSky( u32 dome, const c8 *texture)
  988. {
  989. ISceneManager *smgr = Game->Device->getSceneManager ();
  990. IVideoDriver * driver = Game->Device->getVideoDriver();
  991. bool oldMipMapState = driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
  992. driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
  993. if ( 0 == dome )
  994. {
  995. // irrlicht order
  996. //static const c8*p[] = { "ft", "lf", "bk", "rt", "up", "dn" };
  997. // quake3 order
  998. static const c8*p[] = { "ft", "rt", "bk", "lf", "up", "dn" };
  999. u32 i = 0;
  1000. snprintf_irr ( buf, 64, "%s_%s.jpg", texture, p[i] );
  1001. SkyNode = smgr->addSkyBoxSceneNode( driver->getTexture ( buf ), 0, 0, 0, 0, 0 );
  1002. if (SkyNode)
  1003. {
  1004. for ( i = 0; i < 6; ++i )
  1005. {
  1006. snprintf_irr ( buf, 64, "%s_%s.jpg", texture, p[i] );
  1007. SkyNode->getMaterial(i).setTexture ( 0, driver->getTexture ( buf ) );
  1008. }
  1009. }
  1010. }
  1011. else
  1012. if ( 1 == dome )
  1013. {
  1014. snprintf_irr ( buf, 64, "%s.jpg", texture );
  1015. SkyNode = smgr->addSkyDomeSceneNode(
  1016. driver->getTexture( buf ), 32,32,
  1017. 1.f, 1.f, 1000.f, 0, 11);
  1018. }
  1019. else
  1020. if ( 2 == dome )
  1021. {
  1022. snprintf_irr ( buf, 64, "%s.jpg", texture );
  1023. SkyNode = smgr->addSkyDomeSceneNode(
  1024. driver->getTexture( buf ), 16,8,
  1025. 0.95f, 2.f, 1000.f, 0, 11);
  1026. }
  1027. if (SkyNode)
  1028. SkyNode->setName("Skydome");
  1029. //SkyNode->getMaterial(0).ZBuffer = video::EMDF_DEPTH_LESS_EQUAL;
  1030. driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState);
  1031. }
  1032. // enable GUI elements
  1033. void CQuake3EventHandler::SetGUIActive( s32 command)
  1034. {
  1035. bool inputState = false;
  1036. ICameraSceneNode * camera = Game->Device->getSceneManager()->getActiveCamera ();
  1037. switch ( command )
  1038. {
  1039. case 0: Game->guiActive = 0; inputState = !Game->guiActive; break;
  1040. case 1: Game->guiActive = 1; inputState = !Game->guiActive;;break;
  1041. case 2: Game->guiActive ^= 1; inputState = !Game->guiActive;break;
  1042. case 3:
  1043. if ( camera )
  1044. inputState = !camera->isInputReceiverEnabled();
  1045. break;
  1046. }
  1047. if ( camera )
  1048. {
  1049. camera->setInputReceiverEnabled ( inputState );
  1050. Game->Device->getCursorControl()->setVisible( !inputState );
  1051. }
  1052. if ( gui.Window )
  1053. {
  1054. gui.Window->setVisible ( Game->guiActive != 0 );
  1055. }
  1056. if ( Game->guiActive &&
  1057. gui.SceneTree && Game->Device->getGUIEnvironment()->getFocus() != gui.SceneTree
  1058. )
  1059. {
  1060. gui.SceneTree->getRoot()->clearChildren();
  1061. addSceneTreeItem ( Game->Device->getSceneManager()->getRootSceneNode(), gui.SceneTree->getRoot() );
  1062. }
  1063. Game->Device->getGUIEnvironment()->setFocus ( Game->guiActive ? gui.Window: 0 );
  1064. }
  1065. /*
  1066. Handle game input
  1067. */
  1068. bool CQuake3EventHandler::OnEvent(const SEvent& eve)
  1069. {
  1070. if ( eve.EventType == EET_LOG_TEXT_EVENT )
  1071. {
  1072. return false;
  1073. }
  1074. if ( Game->guiActive && eve.EventType == EET_GUI_EVENT )
  1075. {
  1076. if ( eve.GUIEvent.Caller == gui.MapList && eve.GUIEvent.EventType == gui::EGET_LISTBOX_SELECTED_AGAIN )
  1077. {
  1078. s32 selected = gui.MapList->getSelected();
  1079. if ( selected >= 0 )
  1080. {
  1081. stringw loadMap = gui.MapList->getListItem ( selected );
  1082. if ( 0 == MapParent || loadMap != Game->CurrentMapName )
  1083. {
  1084. printf ( "Loading map %ls\n", loadMap.c_str() );
  1085. LoadMap ( loadMap , 1 );
  1086. if ( 0 == Game->loadParam.loadSkyShader )
  1087. {
  1088. AddSky ( 1, "skydome2" );
  1089. }
  1090. CreatePlayers ();
  1091. CreateGUI ();
  1092. SetGUIActive ( 0 );
  1093. return true;
  1094. }
  1095. }
  1096. }
  1097. else
  1098. if ( eve.GUIEvent.Caller == gui.ArchiveRemove && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
  1099. {
  1100. Game->Device->getFileSystem()->removeFileArchive( gui.ArchiveList->getSelected() );
  1101. Game->CurrentMapName = "";
  1102. AddArchive ( "" );
  1103. }
  1104. else
  1105. if ( eve.GUIEvent.Caller == gui.ArchiveAdd && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
  1106. {
  1107. if ( 0 == gui.ArchiveFileOpen )
  1108. {
  1109. Game->Device->getFileSystem()->setFileListSystem ( FILESYSTEM_NATIVE );
  1110. gui.ArchiveFileOpen = Game->Device->getGUIEnvironment()->addFileOpenDialog ( L"Add Game Archive" , false,gui.Window );
  1111. }
  1112. }
  1113. else
  1114. if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_FILE_SELECTED )
  1115. {
  1116. AddArchive ( gui.ArchiveFileOpen->getFileNameP() );
  1117. gui.ArchiveFileOpen = 0;
  1118. }
  1119. else
  1120. if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_DIRECTORY_SELECTED )
  1121. {
  1122. AddArchive ( gui.ArchiveFileOpen->getDirectoryName() );
  1123. }
  1124. else
  1125. if ( eve.GUIEvent.Caller == gui.ArchiveFileOpen && eve.GUIEvent.EventType == gui::EGET_FILE_CHOOSE_DIALOG_CANCELLED )
  1126. {
  1127. gui.ArchiveFileOpen = 0;
  1128. }
  1129. else
  1130. if ( ( eve.GUIEvent.Caller == gui.ArchiveUp || eve.GUIEvent.Caller == gui.ArchiveDown ) &&
  1131. eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
  1132. {
  1133. s32 rel = eve.GUIEvent.Caller == gui.ArchiveUp ? -1 : 1;
  1134. if ( Game->Device->getFileSystem()->moveFileArchive ( gui.ArchiveList->getSelected (), rel ) )
  1135. {
  1136. s32 newIndex = core::s32_clamp ( gui.ArchiveList->getSelected() + rel, 0, gui.ArchiveList->getRowCount() - 1 );
  1137. AddArchive ( "" );
  1138. gui.ArchiveList->setSelected ( newIndex );
  1139. Game->CurrentMapName = "";
  1140. }
  1141. }
  1142. else
  1143. if ( eve.GUIEvent.Caller == gui.VideoDriver && eve.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED )
  1144. {
  1145. Game->deviceParam.DriverType = (E_DRIVER_TYPE) gui.VideoDriver->getItemData ( gui.VideoDriver->getSelected() );
  1146. }
  1147. else
  1148. if ( eve.GUIEvent.Caller == gui.VideoMode && eve.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED )
  1149. {
  1150. u32 val = gui.VideoMode->getItemData ( gui.VideoMode->getSelected() );
  1151. Game->deviceParam.WindowSize.Width = val >> 16;
  1152. Game->deviceParam.WindowSize.Height = val & 0xFFFF;
  1153. }
  1154. else
  1155. if ( eve.GUIEvent.Caller == gui.FullScreen && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
  1156. {
  1157. Game->deviceParam.Fullscreen = gui.FullScreen->isChecked();
  1158. }
  1159. else
  1160. if ( eve.GUIEvent.Caller == gui.Bit32 && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
  1161. {
  1162. Game->deviceParam.Bits = gui.Bit32->isChecked() ? 32 : 16;
  1163. }
  1164. else
  1165. if ( eve.GUIEvent.Caller == gui.MultiSample && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED )
  1166. {
  1167. Game->deviceParam.AntiAlias = gui.MultiSample->getPos();
  1168. }
  1169. else
  1170. if ( eve.GUIEvent.Caller == gui.Tesselation && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED )
  1171. {
  1172. Game->loadParam.patchTesselation = gui.Tesselation->getPos ();
  1173. }
  1174. else
  1175. if ( eve.GUIEvent.Caller == gui.Gamma && eve.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED )
  1176. {
  1177. Game->GammaValue = gui.Gamma->getPos () * 0.01f;
  1178. Game->Device->setGammaRamp ( Game->GammaValue, Game->GammaValue, Game->GammaValue, 0.f, 0.f );
  1179. }
  1180. else
  1181. if ( eve.GUIEvent.Caller == gui.SetVideoMode && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
  1182. {
  1183. Game->retVal = 2;
  1184. Game->Device->closeDevice();
  1185. }
  1186. else
  1187. if ( eve.GUIEvent.Caller == gui.Window && eve.GUIEvent.EventType == gui::EGET_ELEMENT_CLOSED )
  1188. {
  1189. Game->Device->closeDevice();
  1190. }
  1191. else
  1192. if ( eve.GUIEvent.Caller == gui.Collision && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
  1193. {
  1194. // set fly through active
  1195. Game->flyTroughState ^= 1;
  1196. Player[0].cam()->setAnimateTarget ( Game->flyTroughState == 0 );
  1197. printf ( "collision %d\n", Game->flyTroughState == 0 );
  1198. }
  1199. else
  1200. if ( eve.GUIEvent.Caller == gui.Visible_Map && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
  1201. {
  1202. bool v = gui.Visible_Map->isChecked();
  1203. if ( MapParent )
  1204. {
  1205. printf ( "static node set visible %d\n",v );
  1206. MapParent->setVisible ( v );
  1207. }
  1208. }
  1209. else
  1210. if ( eve.GUIEvent.Caller == gui.Visible_Shader && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
  1211. {
  1212. bool v = gui.Visible_Shader->isChecked();
  1213. if ( ShaderParent )
  1214. {
  1215. printf ( "shader node set visible %d\n",v );
  1216. ShaderParent->setVisible ( v );
  1217. }
  1218. }
  1219. else
  1220. if ( eve.GUIEvent.Caller == gui.Visible_Skydome && eve.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED )
  1221. {
  1222. if ( SkyNode )
  1223. {
  1224. bool v = !SkyNode->isVisible();
  1225. printf ( "skynode set visible %d\n",v );
  1226. SkyNode->setVisible ( v );
  1227. }
  1228. }
  1229. else
  1230. if ( eve.GUIEvent.Caller == gui.Respawn && eve.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED )
  1231. {
  1232. Player[0].respawn ();
  1233. }
  1234. return false;
  1235. }
  1236. // fire
  1237. if ((eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_SPACE &&
  1238. eve.KeyInput.PressedDown == false) ||
  1239. (eve.EventType == EET_MOUSE_INPUT_EVENT && eve.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
  1240. )
  1241. {
  1242. ICameraSceneNode * camera = Game->Device->getSceneManager()->getActiveCamera ();
  1243. if ( camera && camera->isInputReceiverEnabled () )
  1244. {
  1245. useItem( Player + 0 );
  1246. }
  1247. }
  1248. // gui active
  1249. if ((eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_F1 &&
  1250. eve.KeyInput.PressedDown == false) ||
  1251. (eve.EventType == EET_MOUSE_INPUT_EVENT && eve.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
  1252. )
  1253. {
  1254. SetGUIActive ( 2 );
  1255. }
  1256. // check if user presses the key
  1257. if ( eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.PressedDown == false)
  1258. {
  1259. // Escape toggles camera Input
  1260. if ( eve.KeyInput.Key == irr::KEY_ESCAPE )
  1261. {
  1262. SetGUIActive ( 3 );
  1263. }
  1264. else
  1265. if (eve.KeyInput.Key == KEY_F11)
  1266. {
  1267. // screenshot are taken without gamma!
  1268. IImage* image = Game->Device->getVideoDriver()->createScreenShot();
  1269. if (image)
  1270. {
  1271. core::vector3df pos;
  1272. core::vector3df rot;
  1273. ICameraSceneNode * cam = Game->Device->getSceneManager()->getActiveCamera ();
  1274. if ( cam )
  1275. {
  1276. pos = cam->getPosition ();
  1277. rot = cam->getRotation ();
  1278. }
  1279. snprintf_irr(buf, 256, "%s_%ls_%.0f_%.0f_%.0f_%.0f_%.0f_%.0f.jpg",
  1280. DRIVER_TYPE_NAMES_SHORT[Game->Device->getVideoDriver()->getDriverType()],
  1281. Game->CurrentMapName.c_str(),
  1282. pos.X, pos.Y, pos.Z,
  1283. rot.X, rot.Y, rot.Z
  1284. );
  1285. path filename ( buf );
  1286. filename.replace ( '/', '_' );
  1287. printf ( "screenshot : %s\n", filename.c_str() );
  1288. Game->Device->getVideoDriver()->writeImageToFile(image, filename, 100 );
  1289. image->drop();
  1290. }
  1291. }
  1292. else
  1293. if (eve.KeyInput.Key == KEY_F9)
  1294. {
  1295. s32 value = EDS_OFF;
  1296. Game->debugState = ( Game->debugState + 1 ) & 3;
  1297. switch ( Game->debugState )
  1298. {
  1299. case 1: value = EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL; break;
  1300. case 2: value = EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_SKELETON; break;
  1301. }
  1302. /*
  1303. // set debug map data on/off
  1304. debugState = debugState == EDS_OFF ?
  1305. EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL:
  1306. EDS_OFF;
  1307. */
  1308. if ( ItemParent )
  1309. {
  1310. list<ISceneNode*>::ConstIterator it = ItemParent->getChildren().begin();
  1311. for (; it != ItemParent->getChildren().end(); ++it)
  1312. {
  1313. (*it)->setDebugDataVisible ( value );
  1314. }
  1315. }
  1316. if ( ShaderParent )
  1317. {
  1318. list<ISceneNode*>::ConstIterator it = ShaderParent->getChildren().begin();
  1319. for (; it != ShaderParent->getChildren().end(); ++it)
  1320. {
  1321. (*it)->setDebugDataVisible ( value );
  1322. }
  1323. }
  1324. if ( UnresolvedParent )
  1325. {
  1326. list<ISceneNode*>::ConstIterator it = UnresolvedParent->getChildren().begin();
  1327. for (; it != UnresolvedParent->getChildren().end(); ++it)
  1328. {
  1329. (*it)->setDebugDataVisible ( value );
  1330. }
  1331. }
  1332. if ( FogParent )
  1333. {
  1334. list<ISceneNode*>::ConstIterator it = FogParent->getChildren().begin();
  1335. for (; it != FogParent->getChildren().end(); ++it)
  1336. {
  1337. (*it)->setDebugDataVisible ( value );
  1338. }
  1339. }
  1340. if ( SkyNode )
  1341. {
  1342. SkyNode->setDebugDataVisible ( value );
  1343. }
  1344. }
  1345. else
  1346. if (eve.KeyInput.Key == KEY_F8)
  1347. {
  1348. // set gravity on/off
  1349. Game->gravityState ^= 1;
  1350. Player[0].cam()->setGravity ( getGravity ( Game->gravityState ? "earth" : "none" ) );
  1351. printf ( "gravity %s\n", Game->gravityState ? "earth" : "none" );
  1352. }
  1353. else
  1354. if (eve.KeyInput.Key == KEY_F7)
  1355. {
  1356. // set fly through active
  1357. Game->flyTroughState ^= 1;
  1358. Player[0].cam()->setAnimateTarget ( Game->flyTroughState == 0 );
  1359. if ( gui.Collision )
  1360. gui.Collision->setChecked ( Game->flyTroughState == 0 );
  1361. printf ( "collision %d\n", Game->flyTroughState == 0 );
  1362. }
  1363. else
  1364. if (eve.KeyInput.Key == KEY_F2)
  1365. {
  1366. Player[0].respawn ();
  1367. }
  1368. else
  1369. if (eve.KeyInput.Key == KEY_F3)
  1370. {
  1371. if ( MapParent )
  1372. {
  1373. bool v = !MapParent->isVisible ();
  1374. printf ( "static node set visible %d\n",v );
  1375. MapParent->setVisible ( v );
  1376. if ( gui.Visible_Map )
  1377. gui.Visible_Map->setChecked ( v );
  1378. }
  1379. }
  1380. else
  1381. if (eve.KeyInput.Key == KEY_F4)
  1382. {
  1383. if ( ShaderParent )
  1384. {
  1385. bool v = !ShaderParent->isVisible ();
  1386. printf ( "shader node set visible %d\n",v );
  1387. ShaderParent->setVisible ( v );
  1388. if ( gui.Visible_Shader )
  1389. gui.Visible_Shader->setChecked ( v );
  1390. }
  1391. }
  1392. else
  1393. if (eve.KeyInput.Key == KEY_F5)
  1394. {
  1395. if ( FogParent )
  1396. {
  1397. bool v = !FogParent->isVisible ();
  1398. printf ( "fog node set visible %d\n",v );
  1399. FogParent->setVisible ( v );
  1400. if ( gui.Visible_Fog )
  1401. gui.Visible_Fog->setChecked ( v );
  1402. }
  1403. }
  1404. else
  1405. if (eve.KeyInput.Key == KEY_F6)
  1406. {
  1407. if ( UnresolvedParent )
  1408. {
  1409. bool v = !UnresolvedParent->isVisible ();
  1410. printf ( "unresolved node set visible %d\n",v );
  1411. UnresolvedParent->setVisible ( v );
  1412. if ( gui.Visible_Unresolved )
  1413. gui.Visible_Unresolved->setChecked ( v );
  1414. }
  1415. }
  1416. }
  1417. // check if user presses the key C ( for crouch)
  1418. if ( eve.EventType == EET_KEY_INPUT_EVENT && eve.KeyInput.Key == KEY_KEY_C )
  1419. {
  1420. // crouch
  1421. ISceneNodeAnimatorCollisionResponse *anim = Player[0].cam ();
  1422. if ( anim && 0 == Game->flyTroughState )
  1423. {
  1424. if ( false == eve.KeyInput.PressedDown )
  1425. {
  1426. // stand up
  1427. anim->setEllipsoidRadius ( vector3df(30,45,30) );
  1428. anim->setEllipsoidTranslation ( vector3df(0,40,0));
  1429. }
  1430. else
  1431. {
  1432. // on your knees
  1433. anim->setEllipsoidRadius ( vector3df(30,20,30) );
  1434. anim->setEllipsoidTranslation ( vector3df(0,20,0));
  1435. }
  1436. return true;
  1437. }
  1438. }
  1439. return false;
  1440. }
  1441. /*
  1442. useItem
  1443. */
  1444. void CQuake3EventHandler::useItem( Q3Player * player)
  1445. {
  1446. ISceneManager* smgr = Game->Device->getSceneManager();
  1447. ICameraSceneNode* camera = smgr->getActiveCamera();
  1448. if (!camera)
  1449. return;
  1450. SParticleImpact imp;
  1451. imp.when = 0;
  1452. // get line of camera
  1453. vector3df start = camera->getPosition();
  1454. if ( player->WeaponNode )
  1455. {
  1456. start.X += 0.f;
  1457. start.Y += 0.f;
  1458. start.Z += 0.f;
  1459. }
  1460. vector3df end = (camera->getTarget() - start);
  1461. end.normalize();
  1462. start += end*20.0f;
  1463. end = start + (end * camera->getFarValue());
  1464. triangle3df triangle;
  1465. line3d<f32> line(start, end);
  1466. // get intersection point with map
  1467. scene::ISceneNode* hitNode;
  1468. if (smgr->getSceneCollisionManager()->getCollisionPoint(
  1469. line, Meta, end, triangle,hitNode))
  1470. {
  1471. // collides with wall
  1472. vector3df out = triangle.getNormal();
  1473. out.setLength(0.03f);
  1474. imp.when = 1;
  1475. imp.outVector = out;
  1476. imp.pos = end;
  1477. player->setAnim ( "pow" );
  1478. player->Anim[1].next += player->Anim[1].delta;
  1479. }
  1480. else
  1481. {
  1482. // doesnt collide with wall
  1483. vector3df start = camera->getPosition();
  1484. if ( player->WeaponNode )
  1485. {
  1486. //start.X += 10.f;
  1487. //start.Y += -5.f;
  1488. //start.Z += 1.f;
  1489. }
  1490. vector3df end = (camera->getTarget() - start);
  1491. end.normalize();
  1492. start += end*20.0f;
  1493. end = start + (end * camera->getFarValue());
  1494. }
  1495. // create fire ball
  1496. ISceneNode* node = 0;
  1497. node = smgr->addBillboardSceneNode( BulletParent,dimension2d<f32>(10,10), start);
  1498. node->setMaterialFlag(EMF_LIGHTING, false);
  1499. node->setMaterialTexture(0, Game->Device->getVideoDriver()->getTexture("fireball.bmp"));
  1500. node->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
  1501. node->setMaterialType(EMT_TRANSPARENT_ADD_COLOR);
  1502. f32 length = (f32)(end - start).getLength();
  1503. const f32 speed = 5.8f;
  1504. u32 time = (u32)(length / speed);
  1505. ISceneNodeAnimator* anim = 0;
  1506. // set flight line
  1507. anim = smgr->createFlyStraightAnimator(start, end, time);
  1508. node->addAnimator(anim);
  1509. anim->drop();
  1510. snprintf_irr ( buf, 64, "bullet: %s on %.1f,%1.f,%1.f",
  1511. imp.when ? "hit" : "nohit", end.X, end.Y, end.Z );
  1512. node->setName ( buf );
  1513. anim = smgr->createDeleteAnimator(time);
  1514. node->addAnimator(anim);
  1515. anim->drop();
  1516. if (imp.when)
  1517. {
  1518. // create impact note
  1519. imp.when = Game->Device->getTimer()->getTime() +
  1520. (time + (s32) ( ( 1.f + Noiser::get() ) * 250.f ));
  1521. Impacts.push_back(imp);
  1522. }
  1523. // play sound
  1524. }
  1525. // rendered when bullets hit something
  1526. void CQuake3EventHandler::createParticleImpacts( u32 now )
  1527. {
  1528. ISceneManager* sm = Game->Device->getSceneManager();
  1529. struct smokeLayer
  1530. {
  1531. const c8 * texture;
  1532. f32 scale;
  1533. f32 minparticleSize;
  1534. f32 maxparticleSize;
  1535. f32 boxSize;
  1536. u32 minParticle;
  1537. u32 maxParticle;
  1538. u32 fadeout;
  1539. u32 lifetime;
  1540. };
  1541. smokeLayer smoke[] =
  1542. {
  1543. { "smoke2.jpg", 0.4f, 1.5f, 18.f, 20.f, 20, 50, 2000, 10000 },
  1544. { "smoke3.jpg", 0.2f, 1.2f, 15.f, 20.f, 10, 30, 1000, 12000 }
  1545. };
  1546. u32 i;
  1547. u32 g;
  1548. s32 factor = 1;
  1549. for ( g = 0; g != 2; ++g )
  1550. {
  1551. smoke[g].minParticle *= factor;
  1552. smoke[g].maxParticle *= factor;
  1553. smoke[g].lifetime *= factor;
  1554. smoke[g].boxSize *= Noiser::get() * 0.5f;
  1555. }
  1556. for ( i=0; i < Impacts.size(); ++i)
  1557. {
  1558. if (now < Impacts[i].when)
  1559. continue;
  1560. // create smoke particle system
  1561. IParticleSystemSceneNode* pas = 0;
  1562. for ( g = 0; g != 2; ++g )
  1563. {
  1564. pas = sm->addParticleSystemSceneNode(false, BulletParent, -1, Impacts[i].pos);
  1565. snprintf_irr ( buf, 64, "bullet impact smoke at %.1f,%.1f,%1.f",
  1566. Impacts[i].pos.X,Impacts[i].pos.Y,Impacts[i].pos.Z);
  1567. pas->setName ( buf );
  1568. // create a flat smoke
  1569. vector3df direction = Impacts[i].outVector;
  1570. direction *= smoke[g].scale;
  1571. IParticleEmitter* em = pas->createBoxEmitter(
  1572. aabbox3d<f32>(-4.f,0.f,-4.f,20.f,smoke[g].minparticleSize,20.f),
  1573. direction,smoke[g].minParticle, smoke[g].maxParticle,
  1574. video::SColor(0,0,0,0),video::SColor(0,128,128,128),
  1575. 250,4000, 60);
  1576. em->setMinStartSize (dimension2d<f32>( smoke[g].minparticleSize, smoke[g].minparticleSize));
  1577. em->setMaxStartSize (dimension2d<f32>( smoke[g].maxparticleSize, smoke[g].maxparticleSize));
  1578. pas->setEmitter(em);
  1579. em->drop();
  1580. // particles get invisible
  1581. IParticleAffector* paf = pas->createFadeOutParticleAffector(
  1582. video::SColor ( 0, 0, 0, 0 ), smoke[g].fadeout);
  1583. pas->addAffector(paf);
  1584. paf->drop();
  1585. // particle system life time
  1586. ISceneNodeAnimator* anim = sm->createDeleteAnimator( smoke[g].lifetime);
  1587. pas->addAnimator(anim);
  1588. anim->drop();
  1589. pas->setMaterialFlag(video::EMF_LIGHTING, false);
  1590. pas->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
  1591. pas->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR );
  1592. pas->setMaterialTexture(0, Game->Device->getVideoDriver()->getTexture( smoke[g].texture ));
  1593. }
  1594. // play impact sound
  1595. #ifdef USE_IRRKLANG
  1596. /*
  1597. if (irrKlang)
  1598. {
  1599. audio::ISound* sound =
  1600. irrKlang->play3D(impactSound, Impacts[i].pos, false, false, true);
  1601. if (sound)
  1602. {
  1603. // adjust max value a bit to make to sound of an impact louder
  1604. sound->setMinDistance(400);
  1605. sound->drop();
  1606. }
  1607. }
  1608. */
  1609. #endif
  1610. // delete entry
  1611. Impacts.erase(i);
  1612. i--;
  1613. }
  1614. }
  1615. /*
  1616. render
  1617. */
  1618. void CQuake3EventHandler::Render()
  1619. {
  1620. IVideoDriver * driver = Game->Device->getVideoDriver();
  1621. if ( 0 == driver )
  1622. return;
  1623. // TODO: This does not work, yet.
  1624. const bool anaglyph=false;
  1625. if (anaglyph)
  1626. {
  1627. scene::ICameraSceneNode* cameraOld = Game->Device->getSceneManager()->getActiveCamera();
  1628. driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,0,0,0));
  1629. driver->getOverrideMaterial().Material.ColorMask = ECP_NONE;
  1630. driver->getOverrideMaterial().EnableFlags = EMF_COLOR_MASK;
  1631. driver->getOverrideMaterial().EnablePasses = ESNRP_SKY_BOX +
  1632. ESNRP_SOLID +
  1633. ESNRP_TRANSPARENT +
  1634. ESNRP_TRANSPARENT_EFFECT +
  1635. ESNRP_SHADOW;
  1636. Game->Device->getSceneManager()->drawAll();
  1637. driver->clearBuffers(video::ECBF_DEPTH, video::SColor(255,0,0,0));
  1638. const vector3df oldPosition = cameraOld->getPosition();
  1639. const vector3df oldTarget = cameraOld->getTarget();
  1640. const matrix4 startMatrix = cameraOld->getAbsoluteTransformation();
  1641. const vector3df focusPoint = (oldTarget -
  1642. cameraOld->getAbsolutePosition()).setLength(10000) +
  1643. cameraOld->getAbsolutePosition() ;
  1644. scene::ICameraSceneNode* camera = cameraOld;//Game->Device->getSceneManager()->addCameraSceneNode();
  1645. //Left eye...
  1646. vector3df pos;
  1647. matrix4 move;
  1648. move.setTranslation( vector3df(-1.5f,0.0f,0.0f) );
  1649. pos=(startMatrix*move).getTranslation();
  1650. driver->getOverrideMaterial().Material.ColorMask = ECP_RED;
  1651. driver->getOverrideMaterial().EnableFlags = EMF_COLOR_MASK;
  1652. driver->getOverrideMaterial().EnablePasses =
  1653. ESNRP_SKY_BOX|ESNRP_SOLID|ESNRP_TRANSPARENT|
  1654. ESNRP_TRANSPARENT_EFFECT|ESNRP_SHADOW;
  1655. camera->setPosition(pos);
  1656. camera->setTarget(focusPoint);
  1657. Game->Device->getSceneManager()->drawAll();
  1658. driver->clearBuffers(video::ECBF_DEPTH, video::SColor(255, 0, 0, 0));
  1659. //Right eye...
  1660. move.setTranslation( vector3df(1.5f,0.0f,0.0f) );
  1661. pos=(startMatrix*move).getTranslation();
  1662. driver->getOverrideMaterial().Material.ColorMask = ECP_GREEN + ECP_BLUE;
  1663. driver->getOverrideMaterial().EnableFlags = EMF_COLOR_MASK;
  1664. driver->getOverrideMaterial().EnablePasses =
  1665. ESNRP_SKY_BOX|ESNRP_SOLID|ESNRP_TRANSPARENT|
  1666. ESNRP_TRANSPARENT_EFFECT|ESNRP_SHADOW;
  1667. camera->setPosition(pos);
  1668. camera->setTarget(focusPoint);
  1669. Game->Device->getSceneManager()->drawAll();
  1670. driver->getOverrideMaterial().Material.ColorMask=ECP_ALL;
  1671. driver->getOverrideMaterial().EnableFlags=0;
  1672. driver->getOverrideMaterial().EnablePasses=0;
  1673. if (camera != cameraOld)
  1674. {
  1675. Game->Device->getSceneManager()->setActiveCamera(cameraOld);
  1676. camera->remove();
  1677. }
  1678. else
  1679. {
  1680. camera->setPosition(oldPosition);
  1681. camera->setTarget(oldTarget);
  1682. }
  1683. }
  1684. else
  1685. {
  1686. driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,0,0,0));
  1687. Game->Device->getSceneManager()->drawAll();
  1688. }
  1689. Game->Device->getGUIEnvironment()->drawAll();
  1690. driver->endScene();
  1691. }
  1692. /*
  1693. update the generic scene node
  1694. */
  1695. void CQuake3EventHandler::Animate()
  1696. {
  1697. u32 now = Game->Device->getTimer()->getTime();
  1698. Q3Player * player = Player + 0;
  1699. checkTimeFire ( player->Anim, 4, now );
  1700. // Query Scene Manager attributes
  1701. if ( player->Anim[0].flags & FIRED )
  1702. {
  1703. wchar_t msg[128];
  1704. IVideoDriver * driver = Game->Device->getVideoDriver();
  1705. #ifdef _IRR_SCENEMANAGER_DEBUG
  1706. IAttributes * attr = Game->Device->getSceneManager()->getParameters();
  1707. swprintf_irr ( msg, 128,
  1708. L"Q3 %s [%ls], FPS:%03d Tri:%.03fm Cull %d/%d nodes (%d,%d,%d)",
  1709. Game->CurrentMapName.c_str(),
  1710. driver->getName(),
  1711. driver->getFPS (),
  1712. (f32) driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ),
  1713. attr->getAttributeAsInt ( "culled" ),
  1714. attr->getAttributeAsInt ( "calls" ),
  1715. attr->getAttributeAsInt ( "drawn_solid" ),
  1716. attr->getAttributeAsInt ( "drawn_transparent" ),
  1717. attr->getAttributeAsInt ( "drawn_transparent_effect" )
  1718. );
  1719. #else
  1720. swprintf_irr ( msg, 128,
  1721. L"Q3 %s [%ls], FPS:%03d Tri:%.03fm",
  1722. Game->CurrentMapName.c_str(),
  1723. driver->getName(),
  1724. driver->getFPS (),
  1725. (f32) driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f )
  1726. );
  1727. #endif
  1728. Game->Device->setWindowCaption( msg );
  1729. swprintf_irr ( msg, 128,
  1730. L"%03d fps, F1 GUI on/off, F2 respawn, F3-F6 toggle Nodes, F7 Collision on/off"
  1731. L", F8 Gravity on/off, Right Mouse Toggle GUI",
  1732. Game->Device->getVideoDriver()->getFPS ()
  1733. );
  1734. if ( gui.StatusLine )
  1735. gui.StatusLine->setText ( msg );
  1736. player->Anim[0].flags &= ~FIRED;
  1737. }
  1738. // idle..
  1739. if ( player->Anim[1].flags & FIRED )
  1740. {
  1741. if ( strcmp ( player->animation, "idle" ) )
  1742. player->setAnim ( "idle" );
  1743. player->Anim[1].flags &= ~FIRED;
  1744. }
  1745. createParticleImpacts ( now );
  1746. }
  1747. /* The main game states
  1748. */
  1749. void runGame ( GameData *game )
  1750. {
  1751. if ( game->retVal >= 3 )
  1752. return;
  1753. game->Device = (*game->createExDevice) ( game->deviceParam );
  1754. if ( 0 == game->Device)
  1755. {
  1756. // could not create selected driver.
  1757. game->retVal = 0;
  1758. return;
  1759. }
  1760. // create an event receiver based on current game data
  1761. CQuake3EventHandler *eventHandler = new CQuake3EventHandler( game );
  1762. // load stored config
  1763. game->load ( "explorer.cfg" );
  1764. // add our media directory and archive to the file system
  1765. for ( u32 i = 0; i < game->CurrentArchiveList.size(); ++i )
  1766. {
  1767. eventHandler->AddArchive ( game->CurrentArchiveList[i] );
  1768. }
  1769. // Load a Map or startup to the GUI
  1770. if ( game->CurrentMapName.size () )
  1771. {
  1772. eventHandler->LoadMap ( game->CurrentMapName, 1 );
  1773. if ( 0 == game->loadParam.loadSkyShader )
  1774. eventHandler->AddSky ( 1, "skydome2" );
  1775. eventHandler->CreatePlayers ();
  1776. eventHandler->CreateGUI ();
  1777. eventHandler->SetGUIActive ( 0 );
  1778. // set player to last position on restart
  1779. if ( game->retVal == 2 )
  1780. {
  1781. eventHandler->GetPlayer( 0 )->setpos ( game->PlayerPosition, game->PlayerRotation );
  1782. }
  1783. }
  1784. else
  1785. {
  1786. // start up empty
  1787. eventHandler->AddSky ( 1, "skydome2" );
  1788. eventHandler->CreatePlayers ();
  1789. eventHandler->CreateGUI ();
  1790. eventHandler->SetGUIActive ( 1 );
  1791. background_music ( "IrrlichtTheme.ogg" );
  1792. }
  1793. game->retVal = 3;
  1794. while( game->Device->run() )
  1795. {
  1796. eventHandler->Animate ();
  1797. eventHandler->Render ();
  1798. //if ( !game->Device->isWindowActive() )
  1799. game->Device->yield();
  1800. }
  1801. game->Device->setGammaRamp ( 1.f, 1.f, 1.f, 0.f, 0.f );
  1802. delete eventHandler;
  1803. }
  1804. #if defined (_IRR_WINDOWS_) && 0
  1805. #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
  1806. #endif
  1807. /* The main routine, doing all setup
  1808. */
  1809. int IRRCALLCONV main(int argc, char* argv[])
  1810. {
  1811. path prgname(argv[0]);
  1812. GameData game ( deletePathFromPath ( prgname, 1 ) );
  1813. // dynamically load irrlicht
  1814. const c8 * dllName = argc > 1 ? argv[1] : "irrlicht.dll";
  1815. game.createExDevice = load_createDeviceEx ( dllName );
  1816. if ( 0 == game.createExDevice )
  1817. {
  1818. game.retVal = 3;
  1819. printf ( "Could not load %s.\n", dllName );
  1820. return game.retVal; // could not load dll
  1821. }
  1822. // start without asking for driver
  1823. game.retVal = 1;
  1824. do
  1825. {
  1826. // if driver could not created, ask for another driver
  1827. if ( game.retVal == 0 )
  1828. {
  1829. game.setDefault ();
  1830. // ask user for driver
  1831. game.deviceParam.DriverType=driverChoiceConsole();
  1832. if (game.deviceParam.DriverType==video::EDT_COUNT)
  1833. game.retVal = 3;
  1834. }
  1835. runGame ( &game );
  1836. } while ( game.retVal < 3 );
  1837. return game.retVal;
  1838. }
  1839. /*
  1840. **/