Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UI.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*!
  2. * \file src/UI.cpp
  3. * \brief UI interface manager
  4. *
  5. * \author xythobuz
  6. */
  7. #include <algorithm>
  8. #include "global.h"
  9. #include "Console.h"
  10. #include "Menu.h"
  11. #include "OpenRaider.h"
  12. #include "TextureManager.h"
  13. #include "Window.h"
  14. #define STB_IMAGE_IMPLEMENTATION
  15. #include "imgui/stb_image.h"
  16. std::vector<UI*> UI::windows;
  17. std::list<std::tuple<KeyboardButton, bool>> UI::keyboardEvents;
  18. std::list<std::tuple<char *, bool>> UI::textEvents;
  19. std::list<std::tuple<unsigned int, unsigned int, KeyboardButton, bool>> UI::clickEvents;
  20. std::list<std::tuple<int, int>> UI::motionEvents;
  21. std::list<std::tuple<int, int>> UI::scrollEvents;
  22. static GLuint fontTex;
  23. UI::~UI() {
  24. }
  25. void UI::display() { }
  26. void UI::handleKeyboard(KeyboardButton key, bool pressed) { }
  27. void UI::handleText(char *text, bool notFinished) { }
  28. void UI::handleAction(ActionEvents action, bool isFinished) { }
  29. void UI::handleMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) { }
  30. void UI::handleMouseMotion(int xrel, int yrel) { }
  31. void UI::handleMouseScroll(int xrel, int yrel) { }
  32. int UI::initialize() {
  33. ImGuiIO& io = ImGui::GetIO();
  34. io.DisplaySize = ImVec2((float)getWindow().getWidth(), (float)getWindow().getHeight());
  35. io.DeltaTime = 1.0f/60.0f;
  36. io.PixelCenterOffset = 0.0f;
  37. io.KeyMap[ImGuiKey_Tab] = tabKey;
  38. io.KeyMap[ImGuiKey_LeftArrow] = leftKey;
  39. io.KeyMap[ImGuiKey_RightArrow] = rightKey;
  40. io.KeyMap[ImGuiKey_UpArrow] = upKey;
  41. io.KeyMap[ImGuiKey_DownArrow] = downKey;
  42. io.KeyMap[ImGuiKey_Home] = homeKey;
  43. io.KeyMap[ImGuiKey_End] = endKey;
  44. io.KeyMap[ImGuiKey_Delete] = delKey;
  45. io.KeyMap[ImGuiKey_Backspace] = backspaceKey;
  46. io.KeyMap[ImGuiKey_Enter] = enterKey;
  47. io.KeyMap[ImGuiKey_Escape] = escapeKey;
  48. io.KeyMap[ImGuiKey_A] = aKey;
  49. io.KeyMap[ImGuiKey_C] = cKey;
  50. io.KeyMap[ImGuiKey_V] = vKey;
  51. io.KeyMap[ImGuiKey_X] = xKey;
  52. io.KeyMap[ImGuiKey_Y] = yKey;
  53. io.KeyMap[ImGuiKey_Z] = zKey;
  54. io.RenderDrawListsFn = UI::renderImGui;
  55. // Load font texture
  56. //glGenTextures(1, &fontTex);
  57. //glBindTexture(GL_TEXTURE_2D, fontTex);
  58. //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  59. //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  60. const void* png_data;
  61. unsigned int png_size;
  62. ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
  63. int tex_x, tex_y, tex_comp;
  64. void* tex_data = stbi_load_from_memory((const unsigned char*)png_data, (int)png_size, &tex_x, &tex_y, &tex_comp, 0);
  65. //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_x, tex_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_data);
  66. fontTex = getTextureManager().loadBufferSlot((unsigned char *)tex_data, tex_x, tex_y, RGBA, 32, 0);
  67. stbi_image_free(tex_data);
  68. return 0;
  69. }
  70. void UI::eventsFinished() {
  71. ImGui::NewFrame();
  72. ImGuiIO& io = ImGui::GetIO();
  73. if (!io.WantCaptureKeyboard) {
  74. while (keyboardEvents.size() > 0) {
  75. sendKeyboard(std::get<0>(keyboardEvents.front()), std::get<1>(keyboardEvents.front()));
  76. keyboardEvents.pop_front();
  77. }
  78. while (textEvents.size() > 0) {
  79. sendText(std::get<0>(textEvents.front()), std::get<1>(textEvents.front()));
  80. textEvents.pop_front();
  81. }
  82. }
  83. if (!io.WantCaptureMouse) {
  84. while (clickEvents.size() > 0) {
  85. sendMouseClick(std::get<0>(clickEvents.front()), std::get<1>(clickEvents.front()),
  86. std::get<2>(clickEvents.front()), std::get<3>(clickEvents.front()));
  87. clickEvents.pop_front();
  88. }
  89. while (motionEvents.size() > 0) {
  90. sendMouseMotion(std::get<0>(motionEvents.front()), std::get<1>(motionEvents.front()));
  91. motionEvents.pop_front();
  92. }
  93. while (scrollEvents.size() > 0) {
  94. sendMouseScroll(std::get<0>(scrollEvents.front()), std::get<1>(scrollEvents.front()));
  95. scrollEvents.pop_front();
  96. }
  97. }
  98. keyboardEvents.clear();
  99. textEvents.clear();
  100. clickEvents.clear();
  101. motionEvents.clear();
  102. scrollEvents.clear();
  103. ImGui::SetNewWindowDefaultPos(ImVec2(50, 50));
  104. bool show_test_window = true;
  105. ImGui::ShowTestWindow(&show_test_window);
  106. }
  107. void UI::renderImGui(ImDrawList** const cmd_lists, int cmd_lists_count) {
  108. if (cmd_lists_count == 0)
  109. return;
  110. glDisable(GL_CULL_FACE);
  111. glDisable(GL_DEPTH_TEST);
  112. glEnable(GL_SCISSOR_TEST);
  113. //glEnableClientState(GL_VERTEX_ARRAY);
  114. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  115. glEnableClientState(GL_COLOR_ARRAY);
  116. // Setup texture
  117. //glBindTexture(GL_TEXTURE_2D, fontTex);
  118. //glEnable(GL_TEXTURE_2D);
  119. getTextureManager().bindTextureId(fontTex);
  120. const float width = ImGui::GetIO().DisplaySize.x;
  121. const float height = ImGui::GetIO().DisplaySize.y;
  122. /*
  123. // Setup orthographic projection matrix
  124. glMatrixMode(GL_PROJECTION);
  125. glLoadIdentity();
  126. glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f);
  127. glMatrixMode(GL_MODELVIEW);
  128. glLoadIdentity();
  129. */
  130. // Render command lists
  131. for (int n = 0; n < cmd_lists_count; n++) {
  132. const ImDrawList* cmd_list = cmd_lists[n];
  133. const unsigned char* vtx_buffer = (const unsigned char*)cmd_list->vtx_buffer.begin();
  134. glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer));
  135. glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer+8));
  136. glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer+16));
  137. int vtx_offset = 0;
  138. const ImDrawCmd* pcmd_end = cmd_list->commands.end();
  139. for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++) {
  140. glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w),
  141. (int)(pcmd->clip_rect.z - pcmd->clip_rect.x),
  142. (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
  143. glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
  144. vtx_offset += pcmd->vtx_count;
  145. }
  146. }
  147. glEnable(GL_CULL_FACE);
  148. glEnable(GL_DEPTH_TEST);
  149. glDisable(GL_SCISSOR_TEST);
  150. glDisableClientState(GL_COLOR_ARRAY);
  151. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  152. //glDisableClientState(GL_VERTEX_ARRAY);
  153. }
  154. void UI::passKeyboard(KeyboardButton key, bool pressed) {
  155. keyboardEvents.push_back(std::make_tuple(key, pressed));
  156. ImGuiIO& io = ImGui::GetIO();
  157. io.KeysDown[key] = pressed;
  158. io.KeyCtrl = io.KeysDown[leftctrlKey] | io.KeysDown[rightctrlKey];
  159. io.KeyShift = io.KeysDown[leftshiftKey] | io.KeysDown[rightshiftKey];
  160. }
  161. void UI::passText(char *text, bool notFinished) {
  162. textEvents.push_back(std::make_tuple(text, notFinished));
  163. // TODO
  164. }
  165. void UI::passMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) {
  166. clickEvents.push_back(std::make_tuple(x, y, button, released));
  167. // TODO
  168. }
  169. void UI::passMouseMotion(int xrel, int yrel) {
  170. motionEvents.push_back(std::make_tuple(xrel, yrel));
  171. // TODO
  172. }
  173. void UI::passMouseScroll(int xrel, int yrel) {
  174. scrollEvents.push_back(std::make_tuple(xrel, yrel));
  175. ImGuiIO& io = ImGui::GetIO();
  176. io.MouseWheel = (yrel != 0) ? yrel > 0 ? 1 : -1 : 0;
  177. }
  178. void UI::addWindow(UI* window) {
  179. windows.push_back(window);
  180. }
  181. void UI::removeWindow(UI *window) {
  182. findInList(window, [](unsigned long i){
  183. windows.erase(windows.begin() + i);
  184. });
  185. }
  186. bool UI::compareUIs(UI* a, UI* b) {
  187. return a->zPos < b->zPos;
  188. }
  189. bool UI::isOnTop(unsigned long windowID) {
  190. assert(windowID < windows.size());
  191. auto maxIterator = std::max_element(windows.begin(), windows.end(), compareUIs);
  192. unsigned long maxPos = (unsigned long)(maxIterator - windows.begin());
  193. return (maxPos == windowID);
  194. }
  195. void UI::moveToTop(unsigned long windowID) {
  196. assert(windowID < windows.size());
  197. auto maxIterator = std::max_element(windows.begin(), windows.end(), compareUIs);
  198. long max = (*maxIterator)->zPos;
  199. unsigned long maxPos = (unsigned long)(maxIterator - windows.begin());
  200. if (maxPos != windowID) {
  201. windows.at(windowID)->zPos = max + 1;
  202. }
  203. }
  204. void UI::makeInvisible(unsigned long windowID) {
  205. assert(windowID < windows.size());
  206. windows.at(windowID)->zPos = -1;
  207. }
  208. void UI::findInList(UI *w, std::function<void (unsigned long i)> func) {
  209. for (unsigned long i = 0; i < windows.size(); i++) {
  210. auto UIptr = &(*windows.at(i));
  211. if (w == UIptr) {
  212. func(i);
  213. return;
  214. }
  215. }
  216. assert(false); // called UI was not registered
  217. }
  218. bool UI::isOnTop() {
  219. bool top = false;
  220. findInList(this, [&](unsigned long i) {
  221. top = UI::isOnTop(i);
  222. });
  223. return top;
  224. }
  225. void UI::moveToTop() {
  226. findInList(this, [](unsigned long i) {
  227. UI::moveToTop(i);
  228. });
  229. }
  230. void UI::makeInvisible() {
  231. findInList(this, [](unsigned long i) {
  232. UI::makeInvisible(i);
  233. });
  234. }
  235. void UI::displayInOrder() {
  236. std::sort(windows.begin(), windows.end(), compareUIs);
  237. for (auto &x : windows) {
  238. if (x->zPos >= 0) {
  239. x->display();
  240. }
  241. }
  242. ImGui::Render();
  243. }
  244. void UI::sendKeyboard(KeyboardButton key, bool pressed) {
  245. if (pressed) {
  246. if (getOpenRaider().keyBindings[menuAction] == key) {
  247. if (getMenu().isOnTop()) {
  248. getMenu().makeInvisible();
  249. } else {
  250. getMenu().moveToTop();
  251. }
  252. } else if (getOpenRaider().keyBindings[consoleAction] == key) {
  253. if (getConsole().isOnTop()) {
  254. getConsole().makeInvisible();
  255. } else {
  256. getConsole().moveToTop();
  257. }
  258. }
  259. }
  260. auto maxIterator = std::max_element(windows.begin(), windows.end(), compareUIs);
  261. (*maxIterator)->handleKeyboard(key, pressed);
  262. for (int i = forwardAction; i < ActionEventCount; i++) {
  263. if (getOpenRaider().keyBindings[i] == key) {
  264. (*maxIterator)->handleAction((ActionEvents)i, !pressed);
  265. }
  266. }
  267. bool mousegrab = (*maxIterator)->zPos == 0;
  268. if (mousegrab != getWindow().getMousegrab())
  269. getWindow().setMousegrab(mousegrab);
  270. }
  271. void UI::sendText(char *text, bool notFinished) {
  272. auto maxIterator = std::max_element(windows.begin(), windows.end(), compareUIs);
  273. (*maxIterator)->handleText(text, notFinished);
  274. }
  275. void UI::sendMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) {
  276. auto maxIterator = std::max_element(windows.begin(), windows.end(), compareUIs);
  277. (*maxIterator)->handleMouseClick(x, y, button, released);
  278. for (int i = forwardAction; i < ActionEventCount; i++) {
  279. if (getOpenRaider().keyBindings[i] == button) {
  280. (*maxIterator)->handleAction((ActionEvents)i, released);
  281. }
  282. }
  283. }
  284. void UI::sendMouseMotion(int xrel, int yrel) {
  285. auto maxIterator = std::max_element(windows.begin(), windows.end(), compareUIs);
  286. (*maxIterator)->handleMouseMotion(xrel, yrel);
  287. }
  288. void UI::sendMouseScroll(int xrel, int yrel) {
  289. auto maxIterator = std::max_element(windows.begin(), windows.end(), compareUIs);
  290. (*maxIterator)->handleMouseScroll(xrel, yrel);
  291. }