Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

OpenRaider.cpp 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /*!
  2. * \file src/OpenRaider.cpp
  3. * \brief Main Game Object
  4. *
  5. * \author xythobuz
  6. */
  7. #include <cstdio>
  8. #include <cstring>
  9. #include "global.h"
  10. #include "Console.h"
  11. #include "Game.h"
  12. #include "math/math.h"
  13. #include "Menu.h"
  14. #include "Sound.h"
  15. #include "TombRaider.h"
  16. #include "utils/strings.h"
  17. #include "utils/time.h"
  18. #include "OpenRaider.h"
  19. OpenRaider::OpenRaider() {
  20. mRunning = false;
  21. mFPS = false;
  22. mBaseDir = NULL;
  23. mPakDir = NULL;
  24. mAudioDir = NULL;
  25. mDataDir = NULL;
  26. for (int i = 0; i < ActionEventCount; i++)
  27. keyBindings[i] = unknownKey;
  28. }
  29. OpenRaider::~OpenRaider() {
  30. if (mBaseDir)
  31. delete mBaseDir;
  32. if (mPakDir)
  33. delete mPakDir;
  34. if (mAudioDir)
  35. delete mAudioDir;
  36. if (mDataDir)
  37. delete mDataDir;
  38. }
  39. int OpenRaider::initialize() {
  40. // Initialize Windowing
  41. int error = getWindow().initialize();
  42. if (error != 0) {
  43. printf("Could not initialize Window (%d)!\n", error);
  44. return -1;
  45. }
  46. // Initialize OpenGL
  47. error = getWindow().initializeGL();
  48. if (error != 0) {
  49. printf("Could not initialize OpenGL (%d)!\n", error);
  50. return -2;
  51. }
  52. error = getWindow().initializeFont();
  53. if (error != 0) {
  54. printf("Could not initialize Font (%d)!\n", error);
  55. return -3;
  56. }
  57. error = getSound().initialize();
  58. if (error != 0) {
  59. printf("Could not initialize Sound (%d)!\n", error);
  60. return -4;
  61. }
  62. // Initialize game engine
  63. error = getGame().initialize();
  64. if (error != 0) {
  65. printf("Could not initialize Game (%d)!\n", error);
  66. return -5;
  67. }
  68. #ifdef DEBUG
  69. mFPS = true;
  70. #endif
  71. getMenu().setVisible(true);
  72. systemTimerReset();
  73. return 0;
  74. }
  75. int OpenRaider::loadConfig(const char *config) {
  76. assert(config != NULL);
  77. assert(config[0] != '\0');
  78. char *configFile = fullPath(config, 0);
  79. getConsole().print("Loading config from \"%s\"...", configFile);
  80. FILE *f = fopen(configFile, "r");
  81. if (f == NULL) {
  82. getConsole().print("Could not open file!");
  83. return -1;
  84. }
  85. char buffer[256];
  86. while (fgets(buffer, 256, f) != NULL) {
  87. int error = command(buffer);
  88. if (error != 0) {
  89. getConsole().print("Error Code: %d", error);
  90. }
  91. }
  92. fclose(f);
  93. return 0;
  94. }
  95. int OpenRaider::command(const char *command) {
  96. assert(command != NULL);
  97. assert(command[0] != '\0');
  98. int returnValue = 0;
  99. char *cmd = bufferString("%s", command);
  100. size_t length = strlen(cmd);
  101. // Command ends at '\n' or # when a comment begins
  102. for (size_t i = 0; i < length; i++) {
  103. if (cmd[i] == '\n' || cmd[i] == '#') {
  104. cmd[i] = '\0';
  105. break;
  106. }
  107. }
  108. char *token = strtok(cmd, " \t");
  109. if (token != NULL) {
  110. // token is the command to execute
  111. // get arguments
  112. std::vector<char *> args;
  113. char *next;
  114. while ((next = strtok(NULL, " \t")) != NULL) {
  115. args.push_back(next);
  116. }
  117. // Execute
  118. returnValue = this->command(token, &args);
  119. }
  120. delete [] cmd;
  121. return returnValue;
  122. }
  123. char *OpenRaider::expandDirectoryNames(const char *s) {
  124. assert(s != NULL);
  125. assert(s[0] != '\0');
  126. if (mBaseDir != NULL) {
  127. const char *base = "$(basedir)";
  128. if (strstr(s, base) != NULL) {
  129. return stringReplace(s, base, mBaseDir);
  130. }
  131. }
  132. if (mPakDir != NULL) {
  133. const char *pak = "$(pakdir)";
  134. if (strstr(s, pak) != NULL) {
  135. return stringReplace(s, pak, mPakDir);
  136. }
  137. }
  138. if (mAudioDir != NULL) {
  139. const char *audio = "$(audiodir)";
  140. if (strstr(s, audio) != NULL) {
  141. return stringReplace(s, audio, mAudioDir);
  142. }
  143. }
  144. if (mDataDir != NULL) {
  145. const char *data = "$(datadir)";
  146. if (strstr(s, data) != NULL) {
  147. return stringReplace(s, data, mDataDir);
  148. }
  149. }
  150. return NULL;
  151. }
  152. #define CHANGE_DIR_WITH_EXPANSION(a) do { \
  153. char *quotes = stringRemoveQuotes(value); \
  154. char *tmp = expandDirectoryNames(quotes); \
  155. if (tmp == NULL) { \
  156. a = fullPath(quotes, 0); \
  157. } else { \
  158. a = fullPath(tmp, 0); \
  159. delete [] tmp; \
  160. } \
  161. delete [] quotes; \
  162. } while(false)
  163. int OpenRaider::set(const char *var, const char *value) {
  164. assert(var != NULL);
  165. assert(var[0] != '\0');
  166. assert(value != NULL);
  167. assert(value[0] != '\0');
  168. if (strcmp(var, "size") == 0) {
  169. // value has format like "\"1024x768\""
  170. unsigned int w = DEFAULT_WIDTH, h = DEFAULT_HEIGHT;
  171. if (sscanf(value, "\"%5dx%5d\"", &w, &h) != 2) {
  172. getConsole().print("set-size-Error: Invalid value (%s)", value);
  173. return -2;
  174. }
  175. getWindow().setSize(w, h);
  176. } else if (strcmp(var, "fullscreen") == 0) {
  177. bool fullscreen = false;
  178. if (readBool(value, &fullscreen) != 0) {
  179. getConsole().print("set-fullscreen-Error: Invalid value (%s)", value);
  180. return -3;
  181. }
  182. getWindow().setFullscreen(fullscreen);
  183. } else if (strcmp(var, "gldriver") == 0) {
  184. getWindow().setDriver(value);
  185. } else if (strcmp(var, "audio") == 0) {
  186. bool audio = false;
  187. if (readBool(value, &audio) != 0) {
  188. getConsole().print("set-audio-Error: Invalid value (%s)", value);
  189. return -4;
  190. }
  191. getSound().setEnabled(audio);
  192. } else if (strcmp(var, "volume") == 0) {
  193. float vol = 1.0f;
  194. if (sscanf(value, "%5f", &vol) != 1) {
  195. getConsole().print("set-volume-Error: Invalid value (%s)", value);
  196. return -5;
  197. }
  198. getSound().setVolume(vol);
  199. } else if (strcmp(var, "mouse_x") == 0) {
  200. float sense = 1.0f;
  201. if (sscanf(value, "%5f", &sense) != 1) {
  202. getConsole().print("set-mouse_x-Error: Invalid value (%s)", value);
  203. return -6;
  204. }
  205. getCamera().setSensitivityX(OR_DEG_TO_RAD(sense));
  206. } else if (strcmp(var, "mouse_y") == 0) {
  207. float sense = 1.0f;
  208. if (sscanf(value, "%5f", &sense) != 1) {
  209. getConsole().print("set-mouse_y-Error: Invalid value (%s)", value);
  210. return -7;
  211. }
  212. getCamera().setSensitivityY(OR_DEG_TO_RAD(sense));
  213. } else if (strcmp(var, "fps") == 0) {
  214. bool fps = false;
  215. if (readBool(value, &fps) != 0) {
  216. getConsole().print("set-fps-Error: Invalid value (%s)", value);
  217. return -8;
  218. }
  219. mFPS = fps;
  220. } else if (strcmp(var, "basedir") == 0) {
  221. CHANGE_DIR_WITH_EXPANSION(mBaseDir);
  222. } else if (strcmp(var, "pakdir") == 0) {
  223. CHANGE_DIR_WITH_EXPANSION(mPakDir);
  224. } else if (strcmp(var, "audiodir") == 0) {
  225. CHANGE_DIR_WITH_EXPANSION(mAudioDir);
  226. } else if (strcmp(var, "datadir") == 0) {
  227. CHANGE_DIR_WITH_EXPANSION(mDataDir);
  228. } else if (strcmp(var, "font") == 0) {
  229. char *quotes = stringReplace(value, "\"", "");
  230. char *tmp = expandDirectoryNames(quotes);
  231. if (tmp == NULL) {
  232. getWindow().setFont(quotes);
  233. } else {
  234. getWindow().setFont(tmp);
  235. delete [] tmp;
  236. }
  237. delete [] quotes;
  238. } else {
  239. getConsole().print("set-Error: Unknown variable (%s = %s)", var, value);
  240. return -1;
  241. }
  242. return 0;
  243. }
  244. int OpenRaider::bind(const char *action, const char *key) {
  245. assert(action != NULL);
  246. assert(action[0] != '\0');
  247. assert(key != NULL);
  248. assert(key[0] != '\0');
  249. const char *tmp = action;
  250. if (action[0] == '+')
  251. tmp++;
  252. if (strcmp(tmp, "menu") == 0) {
  253. return bind(menuAction, key);
  254. } else if (strcmp(tmp, "console") == 0) {
  255. return bind(consoleAction, key);
  256. } else if (strcmp(tmp, "forward") == 0) {
  257. return bind(forwardAction, key);
  258. } else if (strcmp(tmp, "backward") == 0) {
  259. return bind(backwardAction, key);
  260. } else if (strcmp(tmp, "left") == 0) {
  261. return bind(leftAction, key);
  262. } else if (strcmp(tmp, "right") == 0) {
  263. return bind(rightAction, key);
  264. } else if (strcmp(tmp, "jump") == 0) {
  265. return bind(jumpAction, key);
  266. } else if (strcmp(tmp, "crouch") == 0) {
  267. return bind(crouchAction, key);
  268. } else if (strcmp(tmp, "use") == 0) {
  269. return bind(useAction, key);
  270. } else if (strcmp(tmp, "holster") == 0) {
  271. return bind(holsterAction, key);
  272. } else if (strcmp(tmp, "walk") == 0) {
  273. return bind(walkAction, key);
  274. } else {
  275. getConsole().print("bind-Error: Unknown action (%s --> %s)", key, action);
  276. return -1;
  277. }
  278. }
  279. int OpenRaider::bind(ActionEvents action, const char *key) {
  280. assert(action < ActionEventCount);
  281. assert(key != NULL);
  282. assert(key[0] != '\0');
  283. size_t length = strlen(key);
  284. if ((key[0] == '\'') && (key[length - 1] == '\'') && (length == 3)) {
  285. // Literal character like w, a, s, d, 0, 1...
  286. char c = key[1];
  287. if (((c >= '0') && (c <= '9'))
  288. || ((c >= 'a') && (c <= 'z'))) {
  289. keyBindings[action] = (KeyboardButton)c;
  290. } else {
  291. getConsole().print("bind-\'\'-Error: Unknown key (%s)", key);
  292. return -1;
  293. }
  294. } else if ((key[0] == '\"') && (key[length - 1] == '\"')) {
  295. // Special characters like tilde, esc, quote...
  296. char *tmp = stringRemoveQuotes(key);
  297. if (strcmp(tmp, "quote") == 0) {
  298. keyBindings[action] = quoteKey;
  299. } else if (strcmp(tmp, "backslash") == 0) {
  300. keyBindings[action] = backslashKey;
  301. } else if (strcmp(tmp, "backspace") == 0) {
  302. keyBindings[action] = backspaceKey;
  303. } else if (strcmp(tmp, "capslock") == 0) {
  304. keyBindings[action] = capslockKey;
  305. } else if (strcmp(tmp, "comma") == 0) {
  306. keyBindings[action] = commaKey;
  307. } else if (strcmp(tmp, "del") == 0) {
  308. keyBindings[action] = delKey;
  309. } else if (strcmp(tmp, "up") == 0) {
  310. keyBindings[action] = upKey;
  311. } else if (strcmp(tmp, "down") == 0) {
  312. keyBindings[action] = downKey;
  313. } else if (strcmp(tmp, "left") == 0) {
  314. keyBindings[action] = leftKey;
  315. } else if (strcmp(tmp, "right") == 0) {
  316. keyBindings[action] = rightKey;
  317. } else if (strcmp(tmp, "end") == 0) {
  318. keyBindings[action] = endKey;
  319. } else if (strcmp(tmp, "equals") == 0) {
  320. keyBindings[action] = equalsKey;
  321. } else if (strcmp(tmp, "escape") == 0) {
  322. keyBindings[action] = escapeKey;
  323. } else if (strcmp(tmp, "f1") == 0) {
  324. keyBindings[action] = f1Key;
  325. } else if (strcmp(tmp, "f2") == 0) {
  326. keyBindings[action] = f2Key;
  327. } else if (strcmp(tmp, "f3") == 0) {
  328. keyBindings[action] = f3Key;
  329. } else if (strcmp(tmp, "f4") == 0) {
  330. keyBindings[action] = f4Key;
  331. } else if (strcmp(tmp, "f5") == 0) {
  332. keyBindings[action] = f5Key;
  333. } else if (strcmp(tmp, "f6") == 0) {
  334. keyBindings[action] = f6Key;
  335. } else if (strcmp(tmp, "f7") == 0) {
  336. keyBindings[action] = f7Key;
  337. } else if (strcmp(tmp, "f8") == 0) {
  338. keyBindings[action] = f8Key;
  339. } else if (strcmp(tmp, "f9") == 0) {
  340. keyBindings[action] = f9Key;
  341. } else if (strcmp(tmp, "f10") == 0) {
  342. keyBindings[action] = f10Key;
  343. } else if (strcmp(tmp, "f11") == 0) {
  344. keyBindings[action] = f11Key;
  345. } else if (strcmp(tmp, "f12") == 0) {
  346. keyBindings[action] = f12Key;
  347. } else if (strcmp(tmp, "backquote") == 0) {
  348. keyBindings[action] = backquoteKey;
  349. } else if (strcmp(tmp, "home") == 0) {
  350. keyBindings[action] = homeKey;
  351. } else if (strcmp(tmp, "insert") == 0) {
  352. keyBindings[action] = insertKey;
  353. } else if (strcmp(tmp, "leftalt") == 0) {
  354. keyBindings[action] = leftaltKey;
  355. } else if (strcmp(tmp, "leftctrl") == 0) {
  356. keyBindings[action] = leftctrlKey;
  357. } else if (strcmp(tmp, "leftbracket") == 0) {
  358. keyBindings[action] = leftbracketKey;
  359. } else if (strcmp(tmp, "leftgui") == 0) {
  360. keyBindings[action] = leftguiKey;
  361. } else if (strcmp(tmp, "leftshift") == 0) {
  362. keyBindings[action] = leftshiftKey;
  363. } else if (strcmp(tmp, "minus") == 0) {
  364. keyBindings[action] = minusKey;
  365. } else if (strcmp(tmp, "numlock") == 0) {
  366. keyBindings[action] = numlockKey;
  367. } else if (strcmp(tmp, "pagedown") == 0) {
  368. keyBindings[action] = pagedownKey;
  369. } else if (strcmp(tmp, "pageup") == 0) {
  370. keyBindings[action] = pageupKey;
  371. } else if (strcmp(tmp, "pause") == 0) {
  372. keyBindings[action] = pauseKey;
  373. } else if (strcmp(tmp, "dot") == 0) {
  374. keyBindings[action] = dotKey;
  375. } else if (strcmp(tmp, "rightalt") == 0) {
  376. keyBindings[action] = rightaltKey;
  377. } else if (strcmp(tmp, "rightctrl") == 0) {
  378. keyBindings[action] = rightctrlKey;
  379. } else if (strcmp(tmp, "enter") == 0) {
  380. keyBindings[action] = enterKey;
  381. } else if (strcmp(tmp, "rightgui") == 0) {
  382. keyBindings[action] = rightguiKey;
  383. } else if (strcmp(tmp, "rightbracket") == 0) {
  384. keyBindings[action] = rightbracketKey;
  385. } else if (strcmp(tmp, "rightshift") == 0) {
  386. keyBindings[action] = rightshiftKey;
  387. } else if (strcmp(tmp, "scrolllock") == 0) {
  388. keyBindings[action] = scrolllockKey;
  389. } else if (strcmp(tmp, "semicolon") == 0) {
  390. keyBindings[action] = semicolonKey;
  391. } else if (strcmp(tmp, "slash") == 0) {
  392. keyBindings[action] = slashKey;
  393. } else if (strcmp(tmp, "space") == 0) {
  394. keyBindings[action] = spaceKey;
  395. } else if (strcmp(tmp, "tab") == 0) {
  396. keyBindings[action] = tabKey;
  397. } else if (strcmp(tmp, "leftmouse") == 0) {
  398. keyBindings[action] = leftmouseKey;
  399. } else if (strcmp(tmp, "middlemouse") == 0) {
  400. keyBindings[action] = middlemouseKey;
  401. } else if (strcmp(tmp, "rightmouse") == 0) {
  402. keyBindings[action] = rightmouseKey;
  403. } else {
  404. getConsole().print("bind-\"\"-Error: Unknown key (%s)", key);
  405. delete [] tmp;
  406. return -2;
  407. }
  408. delete [] tmp;
  409. } else {
  410. getConsole().print("bind-Error: Unknown key (%s)", key);
  411. return -3;
  412. }
  413. return 0;
  414. }
  415. void OpenRaider::run() {
  416. assert(mRunning == false);
  417. mRunning = true;
  418. while (mRunning)
  419. frame();
  420. }
  421. void OpenRaider::frame() {
  422. assert(mRunning == true);
  423. static clock_t fpsSum = 0, fpsCount = 0;
  424. static int fps = 0;
  425. clock_t startTime = systemTimerGet();
  426. // Get keyboard and mouse input
  427. getWindow().eventHandling();
  428. // Draw game scene
  429. getRender().display();
  430. // Draw 2D overlays (console and menu)
  431. getWindow().glEnter2D();
  432. getConsole().display();
  433. getMenu().display();
  434. // Draw FPS counter
  435. if (mFPS)
  436. getWindow().drawText(10, getWindow().mHeight - 20, 0.5f, OR_BLUE, "%dFPS", fps);
  437. #ifdef DEBUG
  438. // Draw debug infos
  439. if (getGame().isLoaded()) {
  440. for (int i = 0; i < 3; i++) {
  441. getWindow().drawText(10, getWindow().mHeight - ((4 - i) * 20), 0.5f, OR_BLUE, "%.2f (%.2f)",
  442. getGame().getLara().getPos(i) / 256.0f, getGame().getLara().getAngle(i));
  443. }
  444. }
  445. #endif
  446. getWindow().glExit2D();
  447. // Put new frame on screen
  448. getWindow().swapBuffersGL();
  449. // Calculate FPS display value
  450. fpsCount++;
  451. fpsSum += (systemTimerGet() - startTime);
  452. if (fpsSum >= 500) {
  453. // Update every 500ms
  454. fps = (int)((float)fpsCount * (1000.0f / (float)fpsSum));
  455. fpsCount = fpsSum = 0;
  456. }
  457. }
  458. void OpenRaider::handleKeyboard(KeyboardButton key, bool pressed) {
  459. assert(key < unknownKey);
  460. assert(mRunning == true);
  461. if ((keyBindings[menuAction] == key) && pressed) {
  462. getMenu().setVisible(!getMenu().isVisible());
  463. } else if (!getMenu().isVisible()) {
  464. if ((keyBindings[consoleAction] == key) && pressed) {
  465. getConsole().setVisible(!getConsole().isVisible());
  466. } else if (!getConsole().isVisible()) {
  467. for (int i = forwardAction; i < ActionEventCount; i++) {
  468. if (keyBindings[i] == key) {
  469. getGame().handleAction((ActionEvents)i, !pressed);
  470. }
  471. }
  472. } else {
  473. getConsole().handleKeyboard(key, pressed);
  474. }
  475. } else {
  476. getMenu().handleKeyboard(key, pressed);
  477. }
  478. getWindow().setMousegrab(!(getMenu().isVisible() || getConsole().isVisible()));
  479. }
  480. void OpenRaider::handleText(char *text, bool notFinished) {
  481. assert(text != NULL);
  482. assert(text[0] != '\0');
  483. assert(mRunning == true);
  484. if ((getConsole().isVisible()) && (!getMenu().isVisible())) {
  485. getConsole().handleText(text, notFinished);
  486. }
  487. }
  488. void OpenRaider::handleMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) {
  489. assert(button < unknownKey);
  490. assert(mRunning == true);
  491. if (getMenu().isVisible()) {
  492. getMenu().handleMouseClick(x, y, button, released);
  493. } else if (!getConsole().isVisible()) {
  494. for (int i = forwardAction; i < ActionEventCount; i++) {
  495. if (keyBindings[i] == button) {
  496. getGame().handleAction((ActionEvents)i, released);
  497. }
  498. }
  499. }
  500. }
  501. void OpenRaider::handleMouseMotion(int xrel, int yrel) {
  502. assert((xrel != 0) || (yrel != 0));
  503. assert(mRunning == true);
  504. if ((!getConsole().isVisible()) && (!getMenu().isVisible())) {
  505. getGame().handleMouseMotion(xrel, yrel);
  506. }
  507. }
  508. void OpenRaider::handleMouseScroll(int xrel, int yrel) {
  509. assert((xrel != 0) || (yrel != 0));
  510. assert(mRunning == true);
  511. if ((getConsole().isVisible()) && (!getMenu().isVisible())) {
  512. getConsole().handleMouseScroll(xrel, yrel);
  513. }
  514. }