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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /*!
  2. * \file src/OpenRaider.cpp
  3. * \brief Main Game Object
  4. *
  5. * \author xythobuz
  6. */
  7. #include <cstdio>
  8. #include <cstring>
  9. #include <assert.h>
  10. #include "config.h"
  11. #include "Console.h"
  12. #include "Game.h"
  13. #include "main.h"
  14. #include "math/math.h"
  15. #include "Menu.h"
  16. #include "Sound.h"
  17. #include "TombRaider.h"
  18. #include "utils/strings.h"
  19. #include "utils/time.h"
  20. #include "OpenRaider.h"
  21. OpenRaider::OpenRaider() {
  22. mRunning = false;
  23. mFPS = false;
  24. mBaseDir = NULL;
  25. mPakDir = NULL;
  26. mAudioDir = NULL;
  27. mDataDir = NULL;
  28. for (int i = 0; i < ActionEventCount; i++)
  29. keyBindings[i] = unknownKey;
  30. }
  31. OpenRaider::~OpenRaider() {
  32. if (mBaseDir)
  33. delete mBaseDir;
  34. if (mPakDir)
  35. delete mPakDir;
  36. if (mAudioDir)
  37. delete mAudioDir;
  38. if (mDataDir)
  39. delete mDataDir;
  40. }
  41. int OpenRaider::initialize() {
  42. // Initialize Windowing
  43. int error = getWindow().initialize();
  44. if (error != 0) {
  45. printf("Could not initialize Window (%d)!\n", error);
  46. return -1;
  47. }
  48. // Initialize OpenGL
  49. error = getWindow().initializeGL();
  50. if (error != 0) {
  51. printf("Could not initialize OpenGL (%d)!\n", error);
  52. return -2;
  53. }
  54. error = getWindow().initializeFont();
  55. if (error != 0) {
  56. printf("Could not initialize SDL-TTF (%d)!\n", error);
  57. return -3;
  58. }
  59. error = getSound().initialize();
  60. if (error != 0) {
  61. printf("Could not initialize Sound (%d)!\n", error);
  62. return -4;
  63. }
  64. // Initialize game engine
  65. error = getGame().initialize();
  66. if (error != 0) {
  67. printf("Could not initialize Game Engine (%d)!\n", error);
  68. return -5;
  69. }
  70. #ifdef DEBUG
  71. mFPS = true;
  72. #endif
  73. getMenu().setVisible(true);
  74. systemTimerReset();
  75. return 0;
  76. }
  77. int OpenRaider::loadConfig(const char *config) {
  78. assert(config != NULL);
  79. assert(config[0] != '\0');
  80. char *configFile = fullPath(config, 0);
  81. getConsole().print("Loading config from \"%s\"...", configFile);
  82. FILE *f = fopen(configFile, "r");
  83. if (f == NULL) {
  84. getConsole().print("Could not open file!");
  85. return -1;
  86. }
  87. char buffer[256];
  88. while (fgets(buffer, 256, f) != NULL) {
  89. int error = command(buffer);
  90. if (error != 0) {
  91. getConsole().print("Error Code: %d", error);
  92. }
  93. }
  94. fclose(f);
  95. return 0;
  96. }
  97. int OpenRaider::command(const char *command) {
  98. assert(command != NULL);
  99. assert(command[0] != '\0');
  100. int returnValue = 0;
  101. char *cmd = bufferString("%s", command);
  102. size_t length = strlen(cmd);
  103. // Command ends at '\n' or # when a comment begins
  104. for (size_t i = 0; i < length; i++) {
  105. if (cmd[i] == '\n' || cmd[i] == '#') {
  106. cmd[i] = '\0';
  107. break;
  108. }
  109. }
  110. char *token = strtok(cmd, " \t");
  111. if (token != NULL) {
  112. // token is the command to execute
  113. // get arguments
  114. std::vector<char *> args;
  115. char *next;
  116. while ((next = strtok(NULL, " \t")) != NULL) {
  117. args.push_back(next);
  118. }
  119. // Execute
  120. returnValue = this->command(token, &args);
  121. }
  122. free(cmd);
  123. return returnValue;
  124. }
  125. char *OpenRaider::expandDirectoryNames(const char *s) {
  126. assert(s != NULL);
  127. assert(s[0] != '\0');
  128. if (mBaseDir != NULL) {
  129. const char *base = "$(basedir)";
  130. if (strstr(s, base) != NULL) {
  131. return stringReplace(s, base, mBaseDir);
  132. }
  133. }
  134. if (mPakDir != NULL) {
  135. const char *pak = "$(pakdir)";
  136. if (strstr(s, pak) != NULL) {
  137. return stringReplace(s, pak, mPakDir);
  138. }
  139. }
  140. if (mAudioDir != NULL) {
  141. const char *audio = "$(audiodir)";
  142. if (strstr(s, audio) != NULL) {
  143. return stringReplace(s, audio, mAudioDir);
  144. }
  145. }
  146. if (mDataDir != NULL) {
  147. const char *data = "$(datadir)";
  148. if (strstr(s, data) != NULL) {
  149. return stringReplace(s, data, mDataDir);
  150. }
  151. }
  152. return NULL;
  153. }
  154. #define CHANGE_DIR_WITH_EXPANSION(a) do { \
  155. char *quotes = stringRemoveQuotes(value); \
  156. char *tmp = expandDirectoryNames(quotes); \
  157. if (tmp == NULL) { \
  158. a = fullPath(quotes, 0); \
  159. } else { \
  160. a = fullPath(tmp, 0); \
  161. delete [] tmp; \
  162. } \
  163. delete [] quotes; \
  164. } while(false)
  165. int OpenRaider::set(const char *var, const char *value) {
  166. assert(var != NULL);
  167. assert(var[0] != '\0');
  168. assert(value != NULL);
  169. assert(value[0] != '\0');
  170. if (strcmp(var, "size") == 0) {
  171. // value has format like "\"1024x768\""
  172. unsigned int w = DEFAULT_WIDTH, h = DEFAULT_HEIGHT;
  173. if (sscanf(value, "\"%5dx%5d\"", &w, &h) != 2) {
  174. getConsole().print("set-size-Error: Invalid value (%s)", value);
  175. return -2;
  176. }
  177. getWindow().setSize(w, h);
  178. } else if (strcmp(var, "fullscreen") == 0) {
  179. bool fullscreen = false;
  180. if (readBool(value, &fullscreen) != 0) {
  181. getConsole().print("set-fullscreen-Error: Invalid value (%s)", value);
  182. return -3;
  183. }
  184. getWindow().setFullscreen(fullscreen);
  185. } else if (strcmp(var, "gldriver") == 0) {
  186. getWindow().setDriver(value);
  187. } else if (strcmp(var, "audio") == 0) {
  188. bool audio = false;
  189. if (readBool(value, &audio) != 0) {
  190. getConsole().print("set-audio-Error: Invalid value (%s)", value);
  191. return -4;
  192. }
  193. getSound().setEnabled(audio);
  194. } else if (strcmp(var, "volume") == 0) {
  195. float vol = 1.0f;
  196. if (sscanf(value, "%5f", &vol) != 1) {
  197. getConsole().print("set-volume-Error: Invalid value (%s)", value);
  198. return -5;
  199. }
  200. getSound().setVolume(vol);
  201. } else if (strcmp(var, "mouse_x") == 0) {
  202. float sense = 1.0f;
  203. if (sscanf(value, "%5f", &sense) != 1) {
  204. getConsole().print("set-mouse_x-Error: Invalid value (%s)", value);
  205. return -6;
  206. }
  207. getCamera().setSensitivityX(OR_DEG_TO_RAD(sense));
  208. } else if (strcmp(var, "mouse_y") == 0) {
  209. float sense = 1.0f;
  210. if (sscanf(value, "%5f", &sense) != 1) {
  211. getConsole().print("set-mouse_y-Error: Invalid value (%s)", value);
  212. return -7;
  213. }
  214. getCamera().setSensitivityY(OR_DEG_TO_RAD(sense));
  215. } else if (strcmp(var, "fps") == 0) {
  216. bool fps = false;
  217. if (readBool(value, &fps) != 0) {
  218. getConsole().print("set-fps-Error: Invalid value (%s)", value);
  219. return -8;
  220. }
  221. mFPS = fps;
  222. } else if (strcmp(var, "basedir") == 0) {
  223. CHANGE_DIR_WITH_EXPANSION(mBaseDir);
  224. } else if (strcmp(var, "pakdir") == 0) {
  225. CHANGE_DIR_WITH_EXPANSION(mPakDir);
  226. } else if (strcmp(var, "audiodir") == 0) {
  227. CHANGE_DIR_WITH_EXPANSION(mAudioDir);
  228. } else if (strcmp(var, "datadir") == 0) {
  229. CHANGE_DIR_WITH_EXPANSION(mDataDir);
  230. } else if (strcmp(var, "font") == 0) {
  231. char *quotes = stringReplace(value, "\"", "");
  232. char *tmp = expandDirectoryNames(quotes);
  233. if (tmp == NULL) {
  234. getWindow().setFont(quotes);
  235. } else {
  236. getWindow().setFont(tmp);
  237. delete [] tmp;
  238. }
  239. delete [] quotes;
  240. } else {
  241. getConsole().print("set-Error: Unknown variable (%s = %s)", var, value);
  242. return -1;
  243. }
  244. return 0;
  245. }
  246. int OpenRaider::bind(const char *action, const char *key) {
  247. assert(action != NULL);
  248. assert(action[0] != '\0');
  249. assert(key != NULL);
  250. assert(key[0] != '\0');
  251. const char *tmp = action;
  252. if (action[0] == '+')
  253. tmp++;
  254. if (strcmp(tmp, "menu") == 0) {
  255. return bind(menuAction, key);
  256. } else if (strcmp(tmp, "console") == 0) {
  257. return bind(consoleAction, key);
  258. } else if (strcmp(tmp, "forward") == 0) {
  259. return bind(forwardAction, key);
  260. } else if (strcmp(tmp, "backward") == 0) {
  261. return bind(backwardAction, key);
  262. } else if (strcmp(tmp, "left") == 0) {
  263. return bind(leftAction, key);
  264. } else if (strcmp(tmp, "right") == 0) {
  265. return bind(rightAction, key);
  266. } else if (strcmp(tmp, "jump") == 0) {
  267. return bind(jumpAction, key);
  268. } else if (strcmp(tmp, "crouch") == 0) {
  269. return bind(crouchAction, key);
  270. } else if (strcmp(tmp, "use") == 0) {
  271. return bind(useAction, key);
  272. } else if (strcmp(tmp, "holster") == 0) {
  273. return bind(holsterAction, 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. }
  422. void OpenRaider::frame() {
  423. assert(mRunning == true);
  424. static clock_t fpsSum = 0, fpsCount = 0;
  425. static int fps = 0;
  426. clock_t startTime = systemTimerGet();
  427. // Get keyboard and mouse input
  428. getWindow().eventHandling();
  429. // Draw game scene
  430. getRender().display();
  431. // Draw 2D overlays (console and menu)
  432. getWindow().glEnter2D();
  433. getConsole().display();
  434. getMenu().display();
  435. // Draw FPS counter
  436. if (mFPS)
  437. getWindow().drawText(10, getWindow().mHeight - 20, 0.5f, OR_BLUE, "%dFPS", fps);
  438. #ifdef DEBUG
  439. // Draw debug infos
  440. if (getGame().isLoaded()) {
  441. for (int i = 0; i < 3; i++) {
  442. getWindow().drawText(10, getWindow().mHeight - ((4 - i) * 20), 0.5f, OR_BLUE, "%.2f (%.2f)",
  443. getGame().mLara->pos[i] / 256.0f, getGame().mLara->angles[i]);
  444. }
  445. }
  446. #endif
  447. getWindow().glExit2D();
  448. // Put new frame on screen
  449. getWindow().swapBuffersGL();
  450. // Calculate FPS display value
  451. fpsCount++;
  452. fpsSum += (systemTimerGet() - startTime);
  453. if (fpsSum >= 500) {
  454. // Update every 500ms
  455. fps = (int)((float)fpsCount * (1000.0f / (float)fpsSum));
  456. fpsCount = fpsSum = 0;
  457. }
  458. }
  459. void OpenRaider::handleKeyboard(KeyboardButton key, bool pressed) {
  460. assert(key < unknownKey);
  461. assert(mRunning == true);
  462. if ((keyBindings[menuAction] == key) && pressed) {
  463. getMenu().setVisible(!getMenu().isVisible());
  464. } else if (!getMenu().isVisible()) {
  465. if ((keyBindings[consoleAction] == key) && pressed) {
  466. getConsole().setVisible(!getConsole().isVisible());
  467. } else if (!getConsole().isVisible()) {
  468. for (int i = forwardAction; i < ActionEventCount; i++) {
  469. if (keyBindings[i] == key) {
  470. getGame().handleAction((ActionEvents)i, pressed);
  471. }
  472. }
  473. } else {
  474. getConsole().handleKeyboard(key, pressed);
  475. }
  476. } else {
  477. getMenu().handleKeyboard(key, pressed);
  478. }
  479. getWindow().setMousegrab(!(getMenu().isVisible() || getConsole().isVisible()));
  480. }
  481. void OpenRaider::handleText(char *text, bool notFinished) {
  482. assert(text != NULL);
  483. assert(text[0] != '\0');
  484. assert(mRunning == true);
  485. if ((getConsole().isVisible()) && (!getMenu().isVisible())) {
  486. getConsole().handleText(text, notFinished);
  487. }
  488. }
  489. void OpenRaider::handleMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) {
  490. assert(button < unknownKey);
  491. assert(mRunning == true);
  492. if (getMenu().isVisible()) {
  493. getMenu().handleMouseClick(x, y, button, released);
  494. } else if (!getConsole().isVisible()) {
  495. for (int i = forwardAction; i < ActionEventCount; i++) {
  496. if (keyBindings[i] == button) {
  497. getGame().handleAction((ActionEvents)i, !released);
  498. }
  499. }
  500. }
  501. }
  502. void OpenRaider::handleMouseMotion(int xrel, int yrel) {
  503. assert((xrel != 0) || (yrel != 0));
  504. assert(mRunning == true);
  505. if ((!getConsole().isVisible()) && (!getMenu().isVisible())) {
  506. getGame().handleMouseMotion(xrel, yrel);
  507. }
  508. }
  509. void OpenRaider::handleMouseScroll(int xrel, int yrel) {
  510. assert((xrel != 0) || (yrel != 0));
  511. assert(mRunning == true);
  512. if ((getConsole().isVisible()) && (!getMenu().isVisible())) {
  513. getConsole().handleMouseScroll(xrel, yrel);
  514. }
  515. }