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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. /*!
  2. * \file src/UI.cpp
  3. * \brief UI interface manager
  4. *
  5. * \author xythobuz
  6. */
  7. #include <algorithm>
  8. #include <cstring>
  9. #include "global.h"
  10. #include "Console.h"
  11. #include "Game.h"
  12. #include "Log.h"
  13. #include "Menu.h"
  14. #include "Render.h"
  15. #include "RunTime.h"
  16. #include "Sound.h"
  17. #include "TextureManager.h"
  18. #include "Window.h"
  19. #include "commands/Command.h"
  20. #include "utils/time.h"
  21. #include "UI.h"
  22. #define STB_IMAGE_IMPLEMENTATION
  23. #include "imgui/stb_image.h"
  24. bool UI::visible = false;
  25. unsigned int UI::fontTex;
  26. std::string UI::iniFilename;
  27. std::string UI::logFilename;
  28. bool UI::metaKeyIsActive = false;
  29. std::list<std::tuple<KeyboardButton, bool>> UI::keyboardEvents;
  30. std::list<std::tuple<unsigned int, unsigned int, KeyboardButton, bool>> UI::clickEvents;
  31. std::list<std::tuple<int, int, int, int>> UI::motionEvents;
  32. std::list<std::tuple<int, int>> UI::scrollEvents;
  33. int UI::initialize() {
  34. iniFilename = getRunTime().getBaseDir() + "/imgui.ini";
  35. logFilename = getRunTime().getBaseDir() + "/imgui_log.txt";
  36. ImGuiIO& io = ImGui::GetIO();
  37. io.DisplaySize = ImVec2((float)getWindow().getWidth(), (float)getWindow().getHeight());
  38. io.DeltaTime = 1.0f / 60.0f;
  39. io.IniFilename = iniFilename.c_str();
  40. io.LogFilename = logFilename.c_str();
  41. io.KeyMap[ImGuiKey_Tab] = tabKey;
  42. io.KeyMap[ImGuiKey_LeftArrow] = leftKey;
  43. io.KeyMap[ImGuiKey_RightArrow] = rightKey;
  44. io.KeyMap[ImGuiKey_UpArrow] = upKey;
  45. io.KeyMap[ImGuiKey_DownArrow] = downKey;
  46. io.KeyMap[ImGuiKey_Home] = homeKey;
  47. io.KeyMap[ImGuiKey_End] = endKey;
  48. io.KeyMap[ImGuiKey_Delete] = delKey;
  49. io.KeyMap[ImGuiKey_Backspace] = backspaceKey;
  50. io.KeyMap[ImGuiKey_Enter] = enterKey;
  51. io.KeyMap[ImGuiKey_Escape] = escapeKey;
  52. io.KeyMap[ImGuiKey_A] = aKey;
  53. io.KeyMap[ImGuiKey_C] = cKey;
  54. io.KeyMap[ImGuiKey_V] = vKey;
  55. io.KeyMap[ImGuiKey_X] = xKey;
  56. io.KeyMap[ImGuiKey_Y] = yKey;
  57. io.KeyMap[ImGuiKey_Z] = zKey;
  58. io.RenderDrawListsFn = UI::renderImGui;
  59. // Load font texture
  60. //! \todo Use our own font subsystem instead of this?
  61. const void* png_data;
  62. unsigned int png_size;
  63. ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
  64. int tex_x, tex_y, tex_comp;
  65. void* tex_data = stbi_load_from_memory((const unsigned char*)png_data,
  66. (int)png_size, &tex_x, &tex_y, &tex_comp, 0);
  67. //! \fixme TODO use proper texture slot
  68. fontTex = getTextureManager().loadBufferSlot((unsigned char*)tex_data,
  69. tex_x, tex_y, RGBA, 32, TextureManager::TextureStorage::SYSTEM, -1, false);
  70. stbi_image_free(tex_data);
  71. return 0;
  72. }
  73. void UI::eventsFinished() {
  74. ImGuiIO& io = ImGui::GetIO();
  75. io.DisplaySize = ImVec2((float)getWindow().getWidth(), (float)getWindow().getHeight());
  76. static unsigned long lastTime = 0;
  77. io.DeltaTime = ((float)(systemTimerGet() - lastTime)) / 1000.0f;
  78. lastTime = systemTimerGet();
  79. if (io.DeltaTime <= 0.0f)
  80. io.DeltaTime = 1.0f / 60.0f;
  81. ImGui::NewFrame();
  82. if (!visible) {
  83. while (!clickEvents.empty()) {
  84. auto i = clickEvents.front();
  85. if (getMenu().isVisible()) {
  86. getMenu().handleMouseClick(std::get<0>(i), std::get<1>(i),
  87. std::get<2>(i), std::get<3>(i));
  88. }
  89. clickEvents.pop_front();
  90. }
  91. while (!motionEvents.empty()) {
  92. auto i = motionEvents.front();
  93. if (!getMenu().isVisible()) {
  94. getGame().handleMouseMotion(std::get<0>(i), std::get<1>(i),
  95. std::get<2>(i), std::get<3>(i));
  96. }
  97. motionEvents.pop_front();
  98. }
  99. while (!scrollEvents.empty()) {
  100. auto i = scrollEvents.front();
  101. if (getMenu().isVisible()) {
  102. getMenu().handleMouseScroll(std::get<0>(i), std::get<1>(i));
  103. }
  104. scrollEvents.pop_front();
  105. }
  106. }
  107. while (!keyboardEvents.empty()) {
  108. auto i = keyboardEvents.front();
  109. if (!visible) {
  110. if (getMenu().isVisible()) {
  111. getMenu().handleKeyboard(std::get<0>(i), std::get<1>(i));
  112. } else {
  113. for (int n = forwardAction; n < ActionEventCount; n++) {
  114. if (getRunTime().getKeyBinding((ActionEvents)n) == std::get<0>(i))
  115. getGame().handleAction((ActionEvents)n, !std::get<1>(i));
  116. }
  117. }
  118. }
  119. if (std::get<1>(i)) {
  120. if (!visible) {
  121. if (getRunTime().getKeyBinding(menuAction) == std::get<0>(i)) {
  122. getMenu().setVisible(!getMenu().isVisible());
  123. }
  124. }
  125. if ((!io.WantCaptureKeyboard) || (!visible)) {
  126. if (getRunTime().getKeyBinding(debugAction) == std::get<0>(i)) {
  127. if (!metaKeyIsActive)
  128. visible = !visible;
  129. }
  130. }
  131. }
  132. keyboardEvents.pop_front();
  133. }
  134. bool clicked = !clickEvents.empty();
  135. // Only already empty when !visible
  136. if (visible) {
  137. clickEvents.clear();
  138. motionEvents.clear();
  139. scrollEvents.clear();
  140. }
  141. if (visible && (
  142. ((!io.WantCaptureKeyboard) && io.KeysDown[escapeKey])
  143. || ((!io.WantCaptureMouse) && clicked)
  144. )) {
  145. visible = false;
  146. }
  147. if (getWindow().getTextInput() != visible)
  148. getWindow().setTextInput(visible);
  149. bool input = !(visible || getMenu().isVisible());
  150. if (getWindow().getMousegrab() != input)
  151. getWindow().setMousegrab(input);
  152. }
  153. void UI::display() {
  154. if (!visible)
  155. return;
  156. Console::display();
  157. if (ImGui::Begin("Engine")) {
  158. if (ImGui::CollapsingHeader("Engine Info")) {
  159. ImGui::Text("Uptime: %lums", systemTimerGet());
  160. ImGui::Text("Frames per Second: %luFPS", getRunTime().getFPS());
  161. if (getRunTime().getHistoryFPS().size() > 1) {
  162. static bool scroll = true;
  163. if (scroll) {
  164. int offset = getRunTime().getHistoryFPS().size() - 1;
  165. if (offset > 10)
  166. offset = 10;
  167. ImGui::PlotLines("FPS", &getRunTime().getHistoryFPS()[1],
  168. getRunTime().getHistoryFPS().size() - 1,
  169. getRunTime().getHistoryFPS().size() - offset - 1);
  170. } else {
  171. ImGui::PlotLines("FPS", &getRunTime().getHistoryFPS()[1],
  172. getRunTime().getHistoryFPS().size() - 1);
  173. }
  174. ImGui::SameLine();
  175. ImGui::Checkbox("Scroll##fpsscroll", &scroll);
  176. }
  177. }
  178. if (ImGui::CollapsingHeader("RunTime Settings")) {
  179. bool showFPS = getRunTime().getShowFPS();
  180. if (ImGui::Checkbox("Show FPS##runtime", &showFPS)) {
  181. getRunTime().setShowFPS(showFPS);
  182. }
  183. ImGui::SameLine();
  184. bool running = getRunTime().isRunning();
  185. if (ImGui::Checkbox("Running (!)##runtime", &running)) {
  186. getRunTime().setRunning(running);
  187. }
  188. ImGui::SameLine();
  189. bool sound = getSound().getEnabled();
  190. if (ImGui::Checkbox("Sound##runtime", &sound)) {
  191. getSound().setEnabled(sound);
  192. }
  193. ImGui::SameLine();
  194. bool fullscreen = getWindow().getFullscreen();
  195. if (ImGui::Checkbox("Fullscreen##runtime", &fullscreen)) {
  196. getWindow().setFullscreen(fullscreen);
  197. }
  198. float vol = getSound().getVolume();
  199. if (ImGui::InputFloat("Volume##runtime", &vol, 0.0f, 0.0f, 3,
  200. ImGuiInputTextFlags_EnterReturnsTrue)) {
  201. if (vol < 0.0f)
  202. vol = 0.0f;
  203. if (vol > 1.0f)
  204. vol = 1.0f;
  205. getSound().setVolume(vol);
  206. }
  207. int w = getWindow().getWidth();
  208. if (ImGui::InputInt("Width##runtime", &w, 10, 100, ImGuiInputTextFlags_EnterReturnsTrue)) {
  209. if (w < 1)
  210. w = 1;
  211. getWindow().setSize(w, getWindow().getHeight());
  212. }
  213. int h = getWindow().getHeight();
  214. if (ImGui::InputInt("Height##runtime", &h, 10, 100, ImGuiInputTextFlags_EnterReturnsTrue)) {
  215. if (h < 1)
  216. h = 1;
  217. getWindow().setSize(getWindow().getWidth(), h);
  218. }
  219. static int fr = 0;
  220. char buff[1024];
  221. strncpy(buff, getRunTime().getBaseDir().c_str(), 1024);
  222. if (ImGui::InputText("BaseDir##runtime", buff, 1024, ImGuiInputTextFlags_EnterReturnsTrue)) {
  223. getRunTime().setBaseDir(buff);
  224. fr = getRunTime().getFPS();
  225. }
  226. if (fr > 0) {
  227. ImGui::SameLine();
  228. ImGui::Text("Done!##runtime1");
  229. fr--;
  230. }
  231. static int fr2 = 0;
  232. char buff2[1024];
  233. strncpy(buff2, getRunTime().getPakDir().c_str(), 1024);
  234. if (ImGui::InputText("PakDir##runtime", buff2, 1024, ImGuiInputTextFlags_EnterReturnsTrue)) {
  235. getRunTime().setPakDir(buff2);
  236. fr2 = getRunTime().getFPS();
  237. }
  238. if (fr2 > 0) {
  239. ImGui::SameLine();
  240. ImGui::Text("Done!##runtime2");
  241. fr2--;
  242. }
  243. static int fr3 = 0;
  244. char buff3[1024];
  245. strncpy(buff3, getRunTime().getAudioDir().c_str(), 1024);
  246. if (ImGui::InputText("AudioDir##runtime", buff3, 1024, ImGuiInputTextFlags_EnterReturnsTrue)) {
  247. getRunTime().setAudioDir(buff3);
  248. fr3 = getRunTime().getFPS();
  249. }
  250. if (fr3 > 0) {
  251. ImGui::SameLine();
  252. ImGui::Text("Done!##runtime3");
  253. fr3--;
  254. }
  255. static int fr4 = 0;
  256. char buff4[1024];
  257. strncpy(buff4, getRunTime().getDataDir().c_str(), 1024);
  258. if (ImGui::InputText("DataDir##runtime", buff4, 1024, ImGuiInputTextFlags_EnterReturnsTrue)) {
  259. getRunTime().setDataDir(buff4);
  260. fr4 = getRunTime().getFPS();
  261. }
  262. if (fr4 > 0) {
  263. ImGui::SameLine();
  264. ImGui::Text("Done!##runtime4");
  265. fr4--;
  266. }
  267. }
  268. static bool visibleTex = false;
  269. static bool visibleTile = false;
  270. static bool visibleAnim = false;
  271. if (ImGui::CollapsingHeader("Texture Viewer")) {
  272. static bool game = getGame().isLoaded();
  273. static int index = 0;
  274. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  275. ImGui::SliderInt("##texslide", &index, 0, getTextureManager().numTextures(
  276. game ? TextureManager::TextureStorage::GAME
  277. : TextureManager::TextureStorage::SYSTEM) - 1);
  278. ImGui::PopItemWidth();
  279. ImGui::SameLine();
  280. if (ImGui::Button("+##texplus", ImVec2(0, 0), true)) {
  281. if (index < (getTextureManager().numTextures(
  282. game ? TextureManager::TextureStorage::GAME
  283. : TextureManager::TextureStorage::SYSTEM) - 1))
  284. index++;
  285. else
  286. index = 0;
  287. }
  288. ImGui::SameLine();
  289. if (ImGui::Button("-##texminus", ImVec2(0, 0), true)) {
  290. if (index > 0)
  291. index--;
  292. else
  293. index = getTextureManager().numTextures(
  294. game ? TextureManager::TextureStorage::GAME
  295. : TextureManager::TextureStorage::SYSTEM) - 1;
  296. }
  297. ImGui::SameLine();
  298. if ((getTextureManager().numTextures() > 0)) {
  299. ImGui::Checkbox("Game##texgame", &game);
  300. } else {
  301. game = false;
  302. }
  303. ImGui::SameLine();
  304. if (ImGui::Button("Show##texshow")) {
  305. visibleTex = true;
  306. visibleTile = false;
  307. visibleAnim = false;
  308. }
  309. ImGui::SameLine();
  310. if (ImGui::Button("Clear##texclear")) {
  311. getRender().debugDisplayTexture();
  312. visibleTex = false;
  313. }
  314. if (visibleTex) {
  315. getRender().debugDisplayTexture(index,
  316. game ? TextureManager::TextureStorage::GAME
  317. : TextureManager::TextureStorage::SYSTEM,
  318. ImGui::GetWindowPos().x - ImGui::GetWindowWidth(),
  319. ImGui::GetWindowPos().y,
  320. ImGui::GetWindowWidth(), ImGui::GetWindowWidth());
  321. }
  322. }
  323. if (ImGui::CollapsingHeader("Textile Viewer")) {
  324. if (getTextureManager().numTiles() > 0) {
  325. static int index = 0;
  326. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  327. ImGui::SliderInt("##tileslide", &index, 0, getTextureManager().numTiles() - 1);
  328. ImGui::PopItemWidth();
  329. ImGui::SameLine();
  330. if (ImGui::Button("+##tileplus", ImVec2(0, 0), true)) {
  331. if (index < (getTextureManager().numTiles() - 1))
  332. index++;
  333. else
  334. index = 0;
  335. }
  336. ImGui::SameLine();
  337. if (ImGui::Button("-##tileminus", ImVec2(0, 0), true)) {
  338. if (index > 0)
  339. index--;
  340. else
  341. index = getTextureManager().numTiles() - 1;
  342. }
  343. ImGui::SameLine();
  344. if (ImGui::Button("Show##tileshow")) {
  345. visibleTile = true;
  346. visibleTex = false;
  347. visibleAnim = false;
  348. }
  349. ImGui::SameLine();
  350. if (ImGui::Button("Clear##tileclear")) {
  351. getRender().debugDisplayTextile();
  352. visibleTile = false;
  353. }
  354. if (visibleTile && (index < getTextureManager().numTiles())) {
  355. ImGui::Text(getTextureManager().getTile(index).isTriangle() ? "Triangle" : "Rectangle");
  356. }
  357. if (visibleTile) {
  358. getRender().debugDisplayTextile(index,
  359. ImGui::GetWindowPos().x - (ImGui::GetWindowWidth() / 2),
  360. ImGui::GetWindowPos().y,
  361. (ImGui::GetWindowWidth() / 2), (ImGui::GetWindowWidth() / 2));
  362. }
  363. } else {
  364. ImGui::Text("Please load a level using the new loader!");
  365. }
  366. }
  367. if (ImGui::CollapsingHeader("Animated Textile Viewer")) {
  368. if (getTextureManager().numAnimatedTiles() > 0) {
  369. static int index = 0;
  370. static int tile = getTextureManager().getFirstTileAnimation(index);
  371. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  372. if (ImGui::SliderInt("##animslide", &index, 0, getTextureManager().numAnimatedTiles() - 1)) {
  373. tile = getTextureManager().getFirstTileAnimation(index);
  374. }
  375. ImGui::PopItemWidth();
  376. ImGui::SameLine();
  377. if (ImGui::Button("+##animplus", ImVec2(0, 0), true)) {
  378. if (index < (getTextureManager().numAnimatedTiles() - 1))
  379. index++;
  380. else
  381. index = 0;
  382. tile = getTextureManager().getFirstTileAnimation(index);
  383. }
  384. ImGui::SameLine();
  385. if (ImGui::Button("-##animminus", ImVec2(0, 0), true)) {
  386. if (index > 0)
  387. index--;
  388. else
  389. index = getTextureManager().numAnimatedTiles() - 1;
  390. tile = getTextureManager().getFirstTileAnimation(index);
  391. }
  392. ImGui::SameLine();
  393. static int fr = 0;
  394. if (ImGui::Button("Show##animshow")) {
  395. visibleAnim = true;
  396. visibleTex = false;
  397. visibleTile = false;
  398. }
  399. ImGui::SameLine();
  400. if (ImGui::Button("Clear##animclear")) {
  401. getRender().debugDisplayTextile();
  402. visibleAnim = false;
  403. }
  404. if (visibleAnim) {
  405. if (fr > 0) {
  406. fr--;
  407. } else {
  408. getRender().debugDisplayTextile(tile,
  409. ImGui::GetWindowPos().x - (ImGui::GetWindowWidth() / 2),
  410. ImGui::GetWindowPos().y,
  411. (ImGui::GetWindowWidth() / 2), (ImGui::GetWindowWidth() / 2));
  412. fr = getRunTime().getFPS() / 2;
  413. tile = getTextureManager().getNextTileAnimation(tile);
  414. }
  415. ImGui::Text("Current Tile: %d", tile);
  416. }
  417. } else {
  418. ImGui::Text("Please load a level with animated textures!");
  419. }
  420. }
  421. if (ImGui::CollapsingHeader("SoundSample Player")) {
  422. if (!getSound().getEnabled()) {
  423. ImGui::Text("Please enable Sound before loading a level!");
  424. if (ImGui::Button("Enable Sound!")) {
  425. getSound().setEnabled(true);
  426. }
  427. } else if (getSound().registeredSources() == 0) {
  428. ImGui::Text("Please load a level!");
  429. } else {
  430. static int index = 0;
  431. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  432. ImGui::SliderInt("##soundslide", &index, 0, getSound().registeredSources() - 1);
  433. ImGui::PopItemWidth();
  434. ImGui::SameLine();
  435. if (ImGui::Button("+##soundplus", ImVec2(0, 0), true)) {
  436. if (index < (getSound().registeredSources() - 1))
  437. index++;
  438. else
  439. index = 0;
  440. }
  441. ImGui::SameLine();
  442. if (ImGui::Button("-##soundminus", ImVec2(0, 0), true)) {
  443. if (index > 0)
  444. index--;
  445. else
  446. index = getSound().registeredSources() - 1;
  447. }
  448. ImGui::SameLine();
  449. if (ImGui::Button("Play##soundplay")) {
  450. getSound().play(index);
  451. }
  452. }
  453. }
  454. if (ImGui::CollapsingHeader("ImGui UI Help")) {
  455. ImGui::ShowUserGuide();
  456. }
  457. }
  458. ImGui::End();
  459. ImGui::Render();
  460. }
  461. void UI::shutdown() {
  462. ImGui::Shutdown();
  463. }
  464. void UI::handleKeyboard(KeyboardButton key, bool pressed) {
  465. ImGuiIO& io = ImGui::GetIO();
  466. io.KeysDown[key] = pressed;
  467. io.KeyCtrl = io.KeysDown[leftctrlKey] | io.KeysDown[rightctrlKey];
  468. io.KeyShift = io.KeysDown[leftshiftKey] | io.KeysDown[rightshiftKey];
  469. keyboardEvents.push_back(std::make_tuple(key, pressed));
  470. if ((key == leftguiKey) || (key == rightguiKey))
  471. metaKeyIsActive = pressed;
  472. }
  473. void UI::handleText(char* text, bool notFinished) {
  474. if (notFinished)
  475. return;
  476. ImGuiIO& io = ImGui::GetIO();
  477. while (*text != '\0') {
  478. io.AddInputCharacter(*text);
  479. text++;
  480. }
  481. }
  482. void UI::handleMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) {
  483. ImGuiIO& io = ImGui::GetIO();
  484. io.MousePos = ImVec2((float)x, (float)y);
  485. if (button == leftmouseKey) {
  486. io.MouseDown[0] = !released;
  487. } else if (button == rightmouseKey) {
  488. io.MouseDown[1] = !released;
  489. } else if (button == middlemouseKey) {
  490. io.MouseDown[2] = !released;
  491. } else if (button == fourthmouseKey) {
  492. io.MouseDown[3] = !released;
  493. } else if (button == fifthmouseKey) {
  494. io.MouseDown[4] = !released;
  495. }
  496. clickEvents.push_back(std::make_tuple(x, y, button, released));
  497. }
  498. void UI::handleMouseMotion(int xrel, int yrel, int xabs, int yabs) {
  499. ImGuiIO& io = ImGui::GetIO();
  500. io.MousePos = ImVec2((float)xabs, (float)yabs);
  501. motionEvents.push_back(std::make_tuple(xrel, yrel, xabs, yabs));
  502. }
  503. void UI::handleMouseScroll(int xrel, int yrel) {
  504. ImGuiIO& io = ImGui::GetIO();
  505. io.MouseWheel = (yrel != 0) ? yrel > 0 ? 1 : -1 : 0;
  506. scrollEvents.push_back(std::make_tuple(xrel, yrel));
  507. }
  508. void UI::setVisible(bool v) {
  509. visible = v;
  510. }
  511. bool UI::isVisible() {
  512. return visible;
  513. }
  514. void UI::renderImGui(ImDrawList** const cmd_lists, int cmd_lists_count) {
  515. if (cmd_lists_count == 0)
  516. return;
  517. getWindow().glEnter2D();
  518. glDisable(GL_DEPTH_TEST);
  519. glEnable(GL_SCISSOR_TEST);
  520. glEnableClientState(GL_VERTEX_ARRAY);
  521. glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  522. glEnableClientState(GL_COLOR_ARRAY);
  523. // Setup texture
  524. getTextureManager().bindTextureId(fontTex, TextureManager::TextureStorage::SYSTEM);
  525. // Render command lists
  526. for (int n = 0; n < cmd_lists_count; n++) {
  527. const ImDrawList* cmd_list = cmd_lists[n];
  528. const unsigned char* vtx_buffer = (const unsigned char*)cmd_list->vtx_buffer.begin();
  529. glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer));
  530. glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + 8));
  531. glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + 16));
  532. int vtx_offset = 0;
  533. const ImDrawCmd* pcmd_end = cmd_list->commands.end();
  534. for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++) {
  535. glScissor((int)pcmd->clip_rect.x, (int)(ImGui::GetIO().DisplaySize.y - pcmd->clip_rect.w),
  536. (int)(pcmd->clip_rect.z - pcmd->clip_rect.x),
  537. (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
  538. glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
  539. vtx_offset += pcmd->vtx_count;
  540. }
  541. }
  542. glEnable(GL_DEPTH_TEST);
  543. glDisable(GL_SCISSOR_TEST);
  544. glDisableClientState(GL_VERTEX_ARRAY);
  545. glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  546. glDisableClientState(GL_COLOR_ARRAY);
  547. getWindow().glExit2D();
  548. }