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 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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 <dirent.h>
  11. #include "WindowSDL.h"
  12. #include "config.h"
  13. #include "utils/strings.h"
  14. #include "utils/time.h"
  15. #include "OpenRaider.h"
  16. #define MAX_MS_PER_FRAME (1000 / MAXIMUM_FPS)
  17. OpenRaider::OpenRaider() {
  18. mInit = false;
  19. mRunning = false;
  20. mBaseDir = NULL;
  21. mPakDir = NULL;
  22. mAudioDir = NULL;
  23. mDataDir = NULL;
  24. mMapListFilled = false;
  25. mMenu = new Menu();
  26. mSound = new Sound();
  27. mWindow = new WindowSDL();
  28. for (int i = 0; i < ActionEventCount; i++)
  29. keyBindings[i] = unknown;
  30. }
  31. OpenRaider::~OpenRaider() {
  32. if (mMenu)
  33. delete mMenu;
  34. if (mSound)
  35. delete mSound;
  36. if (mWindow)
  37. delete mWindow;
  38. if (mBaseDir)
  39. delete mBaseDir;
  40. if (mPakDir)
  41. delete mPakDir;
  42. if (mAudioDir)
  43. delete mAudioDir;
  44. if (mDataDir)
  45. delete mDataDir;
  46. while (mMapList.size() > 0) {
  47. delete [] mMapList.back();
  48. mMapList.pop_back();
  49. }
  50. }
  51. int OpenRaider::loadConfig(const char *config) {
  52. assert(config != NULL);
  53. assert(config[0] != '\0');
  54. char *configFile = fullPath(config, 0);
  55. printf("Loading config from \"%s\"...\n", configFile);
  56. FILE *f = fopen(configFile, "r");
  57. if (f == NULL) {
  58. printf("Could not open file!\n");
  59. return -1;
  60. }
  61. char buffer[256];
  62. while (fgets(buffer, 256, f) != NULL) {
  63. command(buffer);
  64. }
  65. fclose(f);
  66. return 0;
  67. }
  68. int OpenRaider::command(const char *command) {
  69. assert(command != NULL);
  70. assert(command[0] != '\0');
  71. int returnValue = 0;
  72. char *cmd = bufferString("%s", command);
  73. size_t length = strlen(cmd);
  74. // Command ends at '\n' or # when a comment begins
  75. for (size_t i = 0; i < length; i++) {
  76. if (cmd[i] == '\n' || cmd[i] == '#') {
  77. cmd[i] = '\0';
  78. break;
  79. }
  80. }
  81. char *token = strtok(cmd, " \t");
  82. if (token != NULL) {
  83. // token is the command to execute
  84. // get arguments
  85. std::vector<char *> args;
  86. char *next;
  87. while ((next = strtok(NULL, " \t")) != NULL) {
  88. args.push_back(next);
  89. }
  90. // Execute
  91. returnValue = this->command(token, &args);
  92. }
  93. free(cmd);
  94. return returnValue;
  95. }
  96. int OpenRaider::command(const char *command, std::vector<char *> *args) {
  97. assert(command != NULL);
  98. assert(command[0] != '\0');
  99. assert(args != NULL);
  100. if (strcmp(command, "set") == 0) {
  101. if (args->size() != 2) {
  102. printf("Invalid use of set-command ");
  103. printStringVector(args);
  104. printf("\n");
  105. return -2;
  106. } else {
  107. return set(args->at(0), args->at(1));
  108. }
  109. } else if (strcmp(command, "bind") == 0) {
  110. if (args->size() != 2) {
  111. printf("Invalid use of bind-command ");
  112. printStringVector(args);
  113. printf("\n");
  114. return -3;
  115. } else {
  116. return bind(args->at(0), args->at(1));
  117. }
  118. } else {
  119. printf("Unknown command: %s ", command);
  120. printStringVector(args);
  121. printf("\n");
  122. return -1;
  123. }
  124. }
  125. char *OpenRaider::expandDirectoryNames(const char *s) {
  126. const char *base = "$(basedir)";
  127. const char *pak = "$(pakdir)";
  128. const char *audio = "$(audiodir)";
  129. const char *data = "$(datadir)";
  130. if (mBaseDir != NULL) {
  131. if (strstr(s, base) != NULL) {
  132. return stringReplace(s, base, mBaseDir);
  133. }
  134. }
  135. if (mPakDir != NULL) {
  136. if (strstr(s, pak) != NULL) {
  137. return stringReplace(s, pak, mPakDir);
  138. }
  139. }
  140. if (mAudioDir != NULL) {
  141. if (strstr(s, audio) != NULL) {
  142. return stringReplace(s, audio, mAudioDir);
  143. }
  144. }
  145. if (mDataDir != NULL) {
  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. if (strcmp(var, "size") == 0) {
  165. // value has format like "\"1024x768\""
  166. unsigned int w = DEFAULT_WIDTH, h = DEFAULT_HEIGHT;
  167. if (sscanf(value, "\"%dx%d\"", &w, &h) != 2) {
  168. printf("set-size-Error: Invalid value (%s)\n", value);
  169. return -2;
  170. }
  171. mWindow->setSize(w, h);
  172. } else if (strcmp(var, "fullscreen") == 0) {
  173. bool fullscreen = false;
  174. if (readBool(value, &fullscreen) != 0) {
  175. printf("set-fullscreen-Error: Invalid value (%s)\n", value);
  176. return -3;
  177. }
  178. mWindow->setFullscreen(fullscreen);
  179. } else if (strcmp(var, "gldriver") == 0) {
  180. mWindow->setDriver(value);
  181. } else if (strcmp(var, "audio") == 0) {
  182. bool audio = false;
  183. if (readBool(value, &audio) != 0) {
  184. printf("set-audio-Error: Invalid value (%s)\n", value);
  185. return -4;
  186. }
  187. mSound->setEnabled(audio);
  188. } else if (strcmp(var, "volume") == 0) {
  189. float vol = 1.0f;
  190. if (sscanf(value, "%f", &vol) != 1) {
  191. printf("set-volume-Error: Invalid value (%s)\n", value);
  192. return -5;
  193. }
  194. mSound->setVolume(vol);
  195. } else if (strcmp(var, "mouse_x") == 0) {
  196. float sense = 1.0f;
  197. if (sscanf(value, "%f", &sense) != 1) {
  198. printf("set-mouse_x-Error: Invalid value (%s)\n", value);
  199. return -6;
  200. }
  201. //! \todo mouse support
  202. } else if (strcmp(var, "mouse_y") == 0) {
  203. float sense = 1.0f;
  204. if (sscanf(value, "%f", &sense) != 1) {
  205. printf("set-mouse_y-Error: Invalid value (%s)\n", value);
  206. return -7;
  207. }
  208. //! \todo mouse support
  209. } else if (strcmp(var, "basedir") == 0) {
  210. CHANGE_DIR_WITH_EXPANSION(mBaseDir);
  211. } else if (strcmp(var, "pakdir") == 0) {
  212. CHANGE_DIR_WITH_EXPANSION(mPakDir);
  213. } else if (strcmp(var, "audiodir") == 0) {
  214. CHANGE_DIR_WITH_EXPANSION(mAudioDir);
  215. } else if (strcmp(var, "datadir") == 0) {
  216. CHANGE_DIR_WITH_EXPANSION(mDataDir);
  217. } else if (strcmp(var, "font") == 0) {
  218. char *quotes = stringReplace(value, "\"", "");
  219. char *tmp = expandDirectoryNames(quotes);
  220. if (tmp == NULL) {
  221. mWindow->setFont(quotes);
  222. } else {
  223. mWindow->setFont(tmp);
  224. delete [] tmp;
  225. }
  226. delete [] quotes;
  227. } else {
  228. printf("set-Error: Unknown variable (%s = %s)\n", var, value);
  229. return -1;
  230. }
  231. return 0;
  232. }
  233. int OpenRaider::bind(const char *action, const char *key) {
  234. const char *tmp = action;
  235. if (action[0] == '+')
  236. tmp++;
  237. if (strcmp(tmp, "menu") == 0) {
  238. return bind(menu, key);
  239. } else if (strcmp(tmp, "console") == 0) {
  240. return bind(console, key);
  241. } else if (strcmp(tmp, "forward") == 0) {
  242. return bind(forward, key);
  243. } else if (strcmp(tmp, "backward") == 0) {
  244. return bind(backward, key);
  245. } else if (strcmp(tmp, "left") == 0) {
  246. return bind(left, key);
  247. } else if (strcmp(tmp, "right") == 0) {
  248. return bind(right, key);
  249. } else if (strcmp(tmp, "jump") == 0) {
  250. return bind(jump, key);
  251. } else if (strcmp(tmp, "crouch") == 0) {
  252. return bind(crouch, key);
  253. } else if (strcmp(tmp, "use") == 0) {
  254. return bind(use, key);
  255. } else if (strcmp(tmp, "holster") == 0) {
  256. return bind(holster, key);
  257. } else {
  258. printf("bind-Error: Unknown action (%s --> %s)\n", key, action);
  259. return -1;
  260. }
  261. }
  262. int OpenRaider::bind(ActionEvents action, const char *key) {
  263. assert(action != ActionEventCount);
  264. assert(key != NULL);
  265. assert(key[0] != '\0');
  266. size_t length = strlen(key);
  267. if ((key[0] == '\'') && (key[length - 1] == '\'') && (length == 3)) {
  268. // Literal character like w, a, s, d, 0, 1...
  269. char c = key[1];
  270. if (((c >= '0') && (c <= '9'))
  271. || ((c >= 'a') && (c <= 'z'))) {
  272. keyBindings[action] = (KeyboardButton)c;
  273. } else {
  274. printf("bind-\'\'-Error: Unknown key (%s)\n", key);
  275. return -1;
  276. }
  277. } else if ((key[0] == '\"') && (key[length - 1] == '\"')) {
  278. // Special characters like tilde, esc, quote...
  279. char *tmp = stringRemoveQuotes(key);
  280. if (strcmp(tmp, "quote") == 0) {
  281. keyBindings[action] = quote;
  282. } else if (strcmp(tmp, "backslash") == 0) {
  283. keyBindings[action] = quote;
  284. } else if (strcmp(tmp, "backspace") == 0) {
  285. keyBindings[action] = backspace;
  286. } else if (strcmp(tmp, "capslock") == 0) {
  287. keyBindings[action] = capslock;
  288. } else if (strcmp(tmp, "comma") == 0) {
  289. keyBindings[action] = comma;
  290. } else if (strcmp(tmp, "del") == 0) {
  291. keyBindings[action] = del;
  292. } else if (strcmp(tmp, "up") == 0) {
  293. keyBindings[action] = up;
  294. } else if (strcmp(tmp, "down") == 0) {
  295. keyBindings[action] = down;
  296. } else if (strcmp(tmp, "left") == 0) {
  297. keyBindings[action] = KeyboardButton::left;
  298. } else if (strcmp(tmp, "right") == 0) {
  299. keyBindings[action] = KeyboardButton::right;
  300. } else if (strcmp(tmp, "end") == 0) {
  301. keyBindings[action] = end;
  302. } else if (strcmp(tmp, "equals") == 0) {
  303. keyBindings[action] = equals;
  304. } else if (strcmp(tmp, "escape") == 0) {
  305. keyBindings[action] = escape;
  306. } else if (strcmp(tmp, "f1") == 0) {
  307. keyBindings[action] = f1;
  308. } else if (strcmp(tmp, "f2") == 0) {
  309. keyBindings[action] = f2;
  310. } else if (strcmp(tmp, "f3") == 0) {
  311. keyBindings[action] = f3;
  312. } else if (strcmp(tmp, "f4") == 0) {
  313. keyBindings[action] = f4;
  314. } else if (strcmp(tmp, "f5") == 0) {
  315. keyBindings[action] = f5;
  316. } else if (strcmp(tmp, "f6") == 0) {
  317. keyBindings[action] = f6;
  318. } else if (strcmp(tmp, "f7") == 0) {
  319. keyBindings[action] = f7;
  320. } else if (strcmp(tmp, "f8") == 0) {
  321. keyBindings[action] = f8;
  322. } else if (strcmp(tmp, "f9") == 0) {
  323. keyBindings[action] = f9;
  324. } else if (strcmp(tmp, "f10") == 0) {
  325. keyBindings[action] = f10;
  326. } else if (strcmp(tmp, "f11") == 0) {
  327. keyBindings[action] = f11;
  328. } else if (strcmp(tmp, "f12") == 0) {
  329. keyBindings[action] = f12;
  330. } else if (strcmp(tmp, "backquote") == 0) {
  331. keyBindings[action] = backquote;
  332. } else if (strcmp(tmp, "home") == 0) {
  333. keyBindings[action] = home;
  334. } else if (strcmp(tmp, "insert") == 0) {
  335. keyBindings[action] = insert;
  336. } else if (strcmp(tmp, "leftalt") == 0) {
  337. keyBindings[action] = leftalt;
  338. } else if (strcmp(tmp, "leftctrl") == 0) {
  339. keyBindings[action] = leftctrl;
  340. } else if (strcmp(tmp, "leftbracket") == 0) {
  341. keyBindings[action] = leftbracket;
  342. } else if (strcmp(tmp, "leftgui") == 0) {
  343. keyBindings[action] = leftgui;
  344. } else if (strcmp(tmp, "leftshift") == 0) {
  345. keyBindings[action] = leftshift;
  346. } else if (strcmp(tmp, "minus") == 0) {
  347. keyBindings[action] = minus;
  348. } else if (strcmp(tmp, "numlock") == 0) {
  349. keyBindings[action] = numlock;
  350. } else if (strcmp(tmp, "pagedown") == 0) {
  351. keyBindings[action] = pagedown;
  352. } else if (strcmp(tmp, "pageup") == 0) {
  353. keyBindings[action] = pageup;
  354. } else if (strcmp(tmp, "pause") == 0) {
  355. keyBindings[action] = pause;
  356. } else if (strcmp(tmp, "dot") == 0) {
  357. keyBindings[action] = dot;
  358. } else if (strcmp(tmp, "rightalt") == 0) {
  359. keyBindings[action] = rightalt;
  360. } else if (strcmp(tmp, "rightctrl") == 0) {
  361. keyBindings[action] = rightctrl;
  362. } else if (strcmp(tmp, "enter") == 0) {
  363. keyBindings[action] = enter;
  364. } else if (strcmp(tmp, "rightgui") == 0) {
  365. keyBindings[action] = rightgui;
  366. } else if (strcmp(tmp, "rightbracket") == 0) {
  367. keyBindings[action] = rightbracket;
  368. } else if (strcmp(tmp, "rightshift") == 0) {
  369. keyBindings[action] = rightshift;
  370. } else if (strcmp(tmp, "scrolllock") == 0) {
  371. keyBindings[action] = scrolllock;
  372. } else if (strcmp(tmp, "semicolon") == 0) {
  373. keyBindings[action] = semicolon;
  374. } else if (strcmp(tmp, "slash") == 0) {
  375. keyBindings[action] = slash;
  376. } else if (strcmp(tmp, "space") == 0) {
  377. keyBindings[action] = space;
  378. } else if (strcmp(tmp, "tab") == 0) {
  379. keyBindings[action] = tab;
  380. } else {
  381. printf("bind-\"\"-Error: Unknown key (%s)\n", key);
  382. delete [] tmp;
  383. return -2;
  384. }
  385. delete [] tmp;
  386. } else {
  387. printf("bind-Error: Unknown key (%s)\n", key);
  388. return -3;
  389. }
  390. return 0;
  391. }
  392. void OpenRaider::loadPakFolderRecursive(const char *dir) {
  393. struct dirent *ep;
  394. DIR *pakDir;
  395. pakDir = opendir(dir);
  396. if (pakDir != NULL) {
  397. while ((ep = readdir(pakDir)) != NULL) {
  398. if (ep->d_type == DT_DIR) {
  399. if ((strcmp(".", ep->d_name) != 0)
  400. && (strcmp("..", ep->d_name) != 0)) {
  401. char *tmp = bufferString("%s%s", dir, ep->d_name);
  402. char *next = fullPath(tmp, '/');
  403. loadPakFolderRecursive(next);
  404. delete next;
  405. delete tmp;
  406. }
  407. } else {
  408. char *fullPathMap = bufferString("%s%s", dir, ep->d_name);
  409. char *lowerPath = bufferString("%s", fullPathMap);
  410. for (char *p = lowerPath; *p; ++p) *p = (char)tolower(*p);
  411. // Check for valid extension
  412. if (stringEndsWith(lowerPath, ".phd")
  413. || stringEndsWith(lowerPath, ".tr2")
  414. || stringEndsWith(lowerPath, ".tr4")
  415. || stringEndsWith(lowerPath, ".trc")) {
  416. //if (m_tombraider.checkMime(fullPathMap) == 0) {
  417. // printf("Validated pak: '%s'\n", fullPathMap);
  418. // Just load relative filename
  419. mMapList.push_back(bufferString("%s", (fullPathMap + strlen(mPakDir))));
  420. //} else {
  421. // printf("ERROR: pak file '%s' not found or invalid\n", fullPathMap);
  422. //}
  423. }
  424. delete [] lowerPath;
  425. delete [] fullPathMap;
  426. }
  427. }
  428. closedir(pakDir);
  429. } else {
  430. printf("Could not open PAK dir %s!\n", dir);
  431. }
  432. }
  433. void OpenRaider::fillMapList() {
  434. char *tmp = fullPath(mPakDir, '/');
  435. loadPakFolderRecursive(tmp);
  436. delete [] tmp;
  437. mMapListFilled = true;
  438. }
  439. int OpenRaider::initialize() {
  440. assert(mInit == false);
  441. assert(mRunning == false);
  442. // Initialize Windowing
  443. if (mWindow->initialize() != 0)
  444. return -1;
  445. // Initialize OpenGL
  446. if (mWindow->initializeGL() != 0)
  447. return -2;
  448. // Initialize window font
  449. if (mWindow->initializeFont() != 0)
  450. return -3;
  451. // Initialize sound
  452. if (mSound->initialize() != 0)
  453. return -4;
  454. mMenu->setVisible(true);
  455. mInit = true;
  456. return 0;
  457. }
  458. void OpenRaider::run() {
  459. assert(mInit == true);
  460. assert(mRunning == false);
  461. mRunning = true;
  462. while (mRunning) {
  463. clock_t startTime = systemTimerGet();
  464. mWindow->eventHandling();
  465. // Temp Debug
  466. glClearColor(0.25f, 0.75f, 0.25f, 1.0f);
  467. glClear(GL_COLOR_BUFFER_BIT);
  468. mWindow->glEnter2D();
  469. mMenu->display();
  470. mWindow->glExit2D();
  471. mWindow->swapBuffersGL();
  472. // Fill map list after first render pass,
  473. // so menu *loading screen* is visible
  474. if (!mMapListFilled)
  475. fillMapList();
  476. clock_t stopTime = systemTimerGet();
  477. if (MAX_MS_PER_FRAME > (stopTime - startTime))
  478. mWindow->delay(MAX_MS_PER_FRAME - (stopTime - startTime));
  479. }
  480. }
  481. void OpenRaider::handleKeyboard(KeyboardButton key, bool pressed) {
  482. if ((keyBindings[menu] == key) && pressed) {
  483. mMenu->setVisible(!mMenu->isVisible());
  484. } else if (!mMenu->isVisible()) {
  485. if (keyBindings[console] == key) {
  486. } else if (keyBindings[forward] == key) {
  487. } else if (keyBindings[backward] == key) {
  488. } else if (keyBindings[left] == key) {
  489. } else if (keyBindings[right] == key) {
  490. } else if (keyBindings[jump] == key) {
  491. } else if (keyBindings[crouch] == key) {
  492. } else if (keyBindings[use] == key) {
  493. } else if (keyBindings[holster] == key) {
  494. }
  495. } else {
  496. mMenu->handleKeyboard(key, pressed);
  497. }
  498. }
  499. void OpenRaider::handleText(char *text, bool notFinished) {
  500. }
  501. void OpenRaider::handleMouseClick(unsigned int x, unsigned int y, MouseButton button, bool released) {
  502. if (mMenu->isVisible()) {
  503. mMenu->handleMouseClick(x, y, button, released);
  504. }
  505. }