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.

Menu.cpp 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*!
  2. * \file src/Menu.cpp
  3. * \brief Menu 'overlay'
  4. *
  5. * \author xythobuz
  6. */
  7. #include <assert.h>
  8. #include <dirent.h>
  9. #include <cctype>
  10. #ifdef __APPLE__
  11. #include <OpenGL/gl.h>
  12. #else
  13. #include <GL/gl.h>
  14. #endif
  15. #include "config.h"
  16. #include "global.h"
  17. #include "main.h"
  18. #include "Menu.h"
  19. #include "utils/strings.h"
  20. Menu::Menu() {
  21. mVisible = false;
  22. mCursor = 0;
  23. mMin = 0;
  24. mainText.text = bufferString(VERSION);
  25. mainText.color[0] = 0xFF;
  26. mainText.color[1] = 0xFF;
  27. mainText.color[2] = 0xFF;
  28. mainText.color[3] = 0xFF;
  29. mainText.scale = 1.2f;
  30. mainText.y = 10;
  31. mainText.w = 0;
  32. mainText.h = 0;
  33. mMapListFilled = false;
  34. mFirstPass = false;
  35. }
  36. Menu::~Menu() {
  37. delete [] mainText.text;
  38. while (mMapList.size() > 0) {
  39. delete [] mMapList.back();
  40. mMapList.pop_back();
  41. }
  42. }
  43. void Menu::setVisible(bool visible) {
  44. mVisible = visible;
  45. }
  46. bool Menu::isVisible() {
  47. return mVisible;
  48. }
  49. void Menu::loadPakFolderRecursive(const char *dir) {
  50. struct dirent entry;
  51. struct dirent *ep = NULL;
  52. DIR *pakDir;
  53. assert(dir != NULL);
  54. assert(dir[0] != '\0');
  55. pakDir = opendir(dir);
  56. if (pakDir != NULL) {
  57. readdir_r(pakDir, &entry, &ep);
  58. while (ep != NULL) {
  59. if (ep->d_type == DT_DIR) {
  60. if ((strcmp(".", ep->d_name) != 0)
  61. && (strcmp("..", ep->d_name) != 0)) {
  62. char *tmp = bufferString("%s%s", dir, ep->d_name);
  63. char *next = fullPath(tmp, '/');
  64. loadPakFolderRecursive(next);
  65. delete next;
  66. delete tmp;
  67. }
  68. } else {
  69. char *fullPathMap = bufferString("%s%s", dir, ep->d_name);
  70. char *lowerPath = bufferString("%s", fullPathMap);
  71. for (char *p = lowerPath; *p; ++p) *p = (char)tolower(*p);
  72. // Check for valid extension
  73. if (stringEndsWith(lowerPath, ".phd")
  74. || stringEndsWith(lowerPath, ".tr2")
  75. || stringEndsWith(lowerPath, ".tr4")
  76. || stringEndsWith(lowerPath, ".trc")) {
  77. int error = TombRaider::checkMime(fullPathMap);
  78. if (error == 0) {
  79. // Just load relative filename
  80. mMapList.push_back(bufferString("%s", (fullPathMap + strlen(getOpenRaider().mPakDir) + 1)));
  81. } else {
  82. getConsole().print("Error: pak file '%s' %s",
  83. fullPathMap, (error == -1) ? "not found" : "invalid");
  84. }
  85. }
  86. delete [] lowerPath;
  87. delete [] fullPathMap;
  88. }
  89. readdir_r(pakDir, &entry, &ep);
  90. }
  91. closedir(pakDir);
  92. } else {
  93. getConsole().print("Could not open PAK dir %s!", dir);
  94. }
  95. }
  96. void Menu::fillMapList() {
  97. char *tmp = fullPath(getOpenRaider().mPakDir, '/');
  98. loadPakFolderRecursive(tmp);
  99. delete [] tmp;
  100. mMapListFilled = true;
  101. }
  102. void Menu::displayMapList() {
  103. // Estimate displayable number of items
  104. int items = (getWindow().mHeight - 110) / 25;
  105. // Select which part of the list to show
  106. int min, max;
  107. if (((int)mCursor - (items / 2)) > 0)
  108. min = mCursor - (items / 2);
  109. else
  110. min = 0;
  111. if ((mCursor + (items / 2)) < mMapList.size())
  112. max = mCursor + (items / 2);
  113. else
  114. max = mMapList.size();
  115. while ((max - min) < items) {
  116. if (min > 0)
  117. min--;
  118. else if (max < ((int)mMapList.size()))
  119. max++;
  120. else
  121. break;
  122. }
  123. mMin = min;
  124. for (int i = 0; i < (max - min); i++) {
  125. char *map = mMapList[i + min];
  126. if ((i + min) == (int)mCursor)
  127. getWindow().drawText(25, 100 + (25 * i), 0.75f, RED, "%s", map);
  128. else
  129. getWindow().drawText(25, 100 + (25 * i), 0.75f, OR_BLUE, "%s", map);
  130. }
  131. }
  132. void Menu::display() {
  133. if (mVisible) {
  134. // Draw half-transparent *overlay*
  135. glColor4f(0.0f, 0.0f, 0.0f, 0.75f);
  136. glDisable(GL_TEXTURE_2D);
  137. glRecti(0, 0, getWindow().mWidth, getWindow().mHeight);
  138. glEnable(GL_TEXTURE_2D);
  139. // Draw heading text
  140. mainText.x = (getWindow().mWidth / 2) - (mainText.w / 2);
  141. getWindow().writeString(&mainText);
  142. if (!mMapListFilled) {
  143. getWindow().drawText(25, (getWindow().mHeight / 2) - 20, 0.75f, OR_BLUE, "Generating map list...");
  144. } else {
  145. if (mMapList.size() == 0) {
  146. getWindow().drawText(25, (getWindow().mHeight / 2) - 20, 0.75f, RED, "No maps found! See README.md");
  147. } else {
  148. // draw *play button* above list
  149. glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  150. glDisable(GL_TEXTURE_2D);
  151. glRecti(25, 25, 100, 75);
  152. glEnable(GL_TEXTURE_2D);
  153. getWindow().drawText(40, 35, 0.75f, BLACK, "Play");
  154. displayMapList();
  155. }
  156. }
  157. // Fill map list after first render pass,
  158. // so menu *loading screen* is visible
  159. if (mFirstPass) {
  160. if (!mMapListFilled) {
  161. fillMapList();
  162. }
  163. } else {
  164. mFirstPass = true;
  165. }
  166. }
  167. }
  168. void Menu::handleKeyboard(KeyboardButton key, bool pressed) {
  169. if (!pressed)
  170. return;
  171. if (key == upKey) {
  172. if (mCursor > 0)
  173. mCursor--;
  174. else
  175. mCursor = mMapList.size() - 1;
  176. } else if (key == downKey) {
  177. if (mCursor < (mMapList.size() - 1))
  178. mCursor++;
  179. else
  180. mCursor = 0;
  181. } else if (key == rightKey) {
  182. int i = 10;
  183. if (mCursor > (mMapList.size() - 11))
  184. i = mMapList.size() - 1 - mCursor;
  185. while (i-- > 0)
  186. handleKeyboard(downKey, true);
  187. } else if (key == leftKey) {
  188. int i = 10;
  189. if (mCursor < 10)
  190. i = mCursor;
  191. while (i-- > 0)
  192. handleKeyboard(upKey, true);
  193. } else if (key == enterKey) {
  194. char *tmp = bufferString("load %s", mMapList[mCursor]);
  195. if (getOpenRaider().command(tmp) == 0) {
  196. setVisible(false);
  197. } else {
  198. //! \todo Display something if an error occurs
  199. }
  200. delete [] tmp;
  201. }
  202. }
  203. void Menu::handleMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) {
  204. int items = (getWindow().mHeight - 110) / 25;
  205. if ((!released) || (button != leftmouseKey))
  206. return;
  207. if ((y >= 100) && (y <= (unsigned int)(100 + (25 * items)))) {
  208. y -= 100;
  209. mCursor = mMin + (y / 25);
  210. } else if ((y >= 25) && (y <= 100) && (x >= 25) && (x <= 125)) {
  211. // Play button
  212. mCursor = 0;
  213. }
  214. }