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

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