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.

UI.cpp 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. /*!
  2. * \file src/UI.cpp
  3. * \brief UI interface manager
  4. *
  5. * \author xythobuz
  6. */
  7. #include <algorithm>
  8. #include <cstring>
  9. #include "imgui/imgui.h"
  10. #include "stb/stb_image.h"
  11. #include "global.h"
  12. #include "Camera.h"
  13. #include "Console.h"
  14. #include "Game.h"
  15. #include "Log.h"
  16. #include "Menu.h"
  17. #include "Render.h"
  18. #include "RunTime.h"
  19. #include "SoundManager.h"
  20. #include "TextureManager.h"
  21. #include "World.h"
  22. #include "commands/Command.h"
  23. #include "system/Sound.h"
  24. #include "system/Window.h"
  25. #include "utils/time.h"
  26. #include "UI.h"
  27. Shader UI::imguiShader;
  28. bool UI::visible = false;
  29. unsigned int UI::fontTex;
  30. std::string UI::iniFilename;
  31. std::string UI::logFilename;
  32. bool UI::metaKeyIsActive = false;
  33. std::list<std::tuple<KeyboardButton, bool>> UI::keyboardEvents;
  34. std::list<std::tuple<unsigned int, unsigned int, KeyboardButton, bool>> UI::clickEvents;
  35. std::list<std::tuple<int, int, int, int>> UI::motionEvents;
  36. std::list<std::tuple<int, int>> UI::scrollEvents;
  37. void UI::setSize(glm::i32vec2 s) {
  38. ImGuiIO& io = ImGui::GetIO();
  39. io.DisplaySize = ImVec2(s.x, s.y);
  40. }
  41. int UI::initialize() {
  42. if (imguiShader.compile(imguiShaderVertex, imguiShaderFragment) < 0)
  43. return -1;
  44. if (imguiShader.addUniform("screen") < 0)
  45. return -2;
  46. if (imguiShader.addUniform("textureSampler") < 0)
  47. return -3;
  48. iniFilename = RunTime::getBaseDir() + "/imgui.ini";
  49. logFilename = RunTime::getBaseDir() + "/imgui_log.txt";
  50. ImGuiIO& io = ImGui::GetIO();
  51. io.DisplaySize = ImVec2(Window::getSize().x, Window::getSize().y);
  52. io.DeltaTime = 1.0f / 60.0f;
  53. io.IniFilename = iniFilename.c_str();
  54. io.LogFilename = logFilename.c_str();
  55. io.KeyMap[ImGuiKey_Tab] = tabKey;
  56. io.KeyMap[ImGuiKey_LeftArrow] = leftKey;
  57. io.KeyMap[ImGuiKey_RightArrow] = rightKey;
  58. io.KeyMap[ImGuiKey_UpArrow] = upKey;
  59. io.KeyMap[ImGuiKey_DownArrow] = downKey;
  60. io.KeyMap[ImGuiKey_Home] = homeKey;
  61. io.KeyMap[ImGuiKey_End] = endKey;
  62. io.KeyMap[ImGuiKey_Delete] = delKey;
  63. io.KeyMap[ImGuiKey_Backspace] = backspaceKey;
  64. io.KeyMap[ImGuiKey_Enter] = enterKey;
  65. io.KeyMap[ImGuiKey_Escape] = escapeKey;
  66. io.KeyMap[ImGuiKey_A] = aKey;
  67. io.KeyMap[ImGuiKey_C] = cKey;
  68. io.KeyMap[ImGuiKey_V] = vKey;
  69. io.KeyMap[ImGuiKey_X] = xKey;
  70. io.KeyMap[ImGuiKey_Y] = yKey;
  71. io.KeyMap[ImGuiKey_Z] = zKey;
  72. io.RenderDrawListsFn = UI::renderImGui;
  73. // Load font texture
  74. //! \todo Use our own font subsystem instead of this?
  75. const void* png_data;
  76. unsigned int png_size;
  77. ImGui::GetDefaultFontData(nullptr, nullptr, &png_data, &png_size);
  78. int tex_x, tex_y, tex_comp;
  79. void* tex_data = stbi_load_from_memory((const unsigned char*)png_data,
  80. (int)png_size, &tex_x, &tex_y, &tex_comp, 0);
  81. fontTex = TextureManager::loadBufferSlot((unsigned char*)tex_data,
  82. tex_x, tex_y, ColorMode::RGBA, 32,
  83. TextureStorage::SYSTEM, -1, false);
  84. stbi_image_free(tex_data);
  85. return 0;
  86. }
  87. void UI::eventsFinished() {
  88. ImGuiIO& io = ImGui::GetIO();
  89. io.DisplaySize = ImVec2(Window::getSize().x, Window::getSize().y);
  90. static unsigned long lastTime = 0;
  91. io.DeltaTime = ((float)(systemTimerGet() - lastTime)) / 1000.0f;
  92. lastTime = systemTimerGet();
  93. if (io.DeltaTime <= 0.0f)
  94. io.DeltaTime = 1.0f / 60.0f;
  95. ImGui::NewFrame();
  96. if (!(visible || Console::isVisible())) {
  97. while (!clickEvents.empty()) {
  98. auto i = clickEvents.front();
  99. if (getMenu().isVisible()) {
  100. getMenu().handleMouseClick(std::get<0>(i), std::get<1>(i),
  101. std::get<2>(i), std::get<3>(i));
  102. }
  103. clickEvents.pop_front();
  104. }
  105. while (!motionEvents.empty()) {
  106. auto i = motionEvents.front();
  107. if (!getMenu().isVisible()) {
  108. getGame().handleMouseMotion(std::get<0>(i), std::get<1>(i),
  109. std::get<2>(i), std::get<3>(i));
  110. }
  111. motionEvents.pop_front();
  112. }
  113. while (!scrollEvents.empty()) {
  114. auto i = scrollEvents.front();
  115. if (getMenu().isVisible()) {
  116. getMenu().handleMouseScroll(std::get<0>(i), std::get<1>(i));
  117. }
  118. scrollEvents.pop_front();
  119. }
  120. }
  121. while (!keyboardEvents.empty()) {
  122. auto i = keyboardEvents.front();
  123. if (!(visible || Console::isVisible())) {
  124. if (getMenu().isVisible()) {
  125. getMenu().handleKeyboard(std::get<0>(i), std::get<1>(i));
  126. } else {
  127. for (int n = forwardAction; n < ActionEventCount; n++) {
  128. if (RunTime::getKeyBinding((ActionEvents)n) == std::get<0>(i))
  129. getGame().handleAction((ActionEvents)n, !std::get<1>(i));
  130. }
  131. }
  132. }
  133. if (std::get<1>(i)) {
  134. if (!(visible || Console::isVisible())) {
  135. if (RunTime::getKeyBinding(menuAction) == std::get<0>(i)) {
  136. getMenu().setVisible(!getMenu().isVisible());
  137. }
  138. }
  139. if ((!io.WantCaptureKeyboard) || (!(visible || Console::isVisible()))) {
  140. if (!metaKeyIsActive) {
  141. if (RunTime::getKeyBinding(debugAction) == std::get<0>(i)) {
  142. visible = !visible;
  143. }
  144. if (RunTime::getKeyBinding(consoleAction) == std::get<0>(i)) {
  145. Console::setVisible(!Console::isVisible());
  146. }
  147. }
  148. }
  149. }
  150. keyboardEvents.pop_front();
  151. }
  152. bool clicked = !clickEvents.empty();
  153. clickEvents.clear();
  154. motionEvents.clear();
  155. scrollEvents.clear();
  156. if ((visible || Console::isVisible()) && (
  157. ((!io.WantCaptureKeyboard) && io.KeysDown[escapeKey])
  158. || ((!io.WantCaptureMouse) && clicked)
  159. )) {
  160. visible = false;
  161. Console::setVisible(false);
  162. }
  163. if (Window::getTextInput() != (visible || Console::isVisible()))
  164. Window::setTextInput(visible || Console::isVisible());
  165. bool input = !(visible || Console::isVisible() || getMenu().isVisible());
  166. if (Window::getMousegrab() != input)
  167. Window::setMousegrab(input);
  168. io.MouseWheel = 0;
  169. }
  170. void UI::display() {
  171. Console::display();
  172. if (!visible) {
  173. ImGui::Render();
  174. return;
  175. }
  176. static bool showTestWindow = false;
  177. if (ImGui::Begin("Engine", &visible, ImVec2(400, 400))) {
  178. Render::displayUI();
  179. RunTime::display();
  180. SoundManager::display();
  181. /*
  182. static bool visibleTex = false;
  183. static bool visibleTile = false;
  184. static bool visibleAnim = false;
  185. static bool visibleSprite = false;
  186. if (ImGui::CollapsingHeader("Texture Viewer")) {
  187. static bool game = getGame().isLoaded();
  188. static int index = 0;
  189. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  190. ImGui::SliderInt("##texslide", &index, 0, TextureManager::.numTextures(
  191. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1);
  192. ImGui::PopItemWidth();
  193. ImGui::SameLine();
  194. if (ImGui::Button("+##texplus", ImVec2(0, 0), true)) {
  195. if (index < (TextureManager::numTextures(
  196. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1))
  197. index++;
  198. else
  199. index = 0;
  200. }
  201. ImGui::SameLine();
  202. if (ImGui::Button("-##texminus", ImVec2(0, 0), true)) {
  203. if (index > 0)
  204. index--;
  205. else
  206. index = TextureManager::numTextures(
  207. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1;
  208. }
  209. ImGui::SameLine();
  210. if ((TextureManager::numTextures() > 0)) {
  211. ImGui::Checkbox("Game##texgame", &game);
  212. } else {
  213. game = false;
  214. }
  215. ImGui::SameLine();
  216. if (ImGui::Button("Show##texshow")) {
  217. visibleTex = true;
  218. visibleTile = false;
  219. visibleAnim = false;
  220. visibleSprite = false;
  221. }
  222. ImGui::SameLine();
  223. if (ImGui::Button("Clear##texclear")) {
  224. getRender().debugDisplayTexture();
  225. visibleTex = false;
  226. }
  227. if (visibleTex) {
  228. getRender().debugDisplayTexture(index,
  229. game ? TextureStorage::GAME : TextureStorage::SYSTEM,
  230. ImGui::GetWindowPos().x - ImGui::GetWindowWidth(),
  231. ImGui::GetWindowPos().y,
  232. ImGui::GetWindowWidth(), ImGui::GetWindowWidth());
  233. }
  234. }
  235. if (ImGui::CollapsingHeader("Textile Viewer")) {
  236. if (TextureManager::numTiles() > 0) {
  237. static int index = 0;
  238. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  239. ImGui::SliderInt("##tileslide", &index, 0, TextureManager::numTiles() - 1);
  240. ImGui::PopItemWidth();
  241. ImGui::SameLine();
  242. if (ImGui::Button("+##tileplus", ImVec2(0, 0), true)) {
  243. if (index < (TextureManager::numTiles() - 1))
  244. index++;
  245. else
  246. index = 0;
  247. }
  248. ImGui::SameLine();
  249. if (ImGui::Button("-##tileminus", ImVec2(0, 0), true)) {
  250. if (index > 0)
  251. index--;
  252. else
  253. index = TextureManager::numTiles() - 1;
  254. }
  255. ImGui::SameLine();
  256. if (ImGui::Button("Show##tileshow")) {
  257. visibleTile = true;
  258. visibleTex = false;
  259. visibleAnim = false;
  260. visibleSprite = false;
  261. }
  262. ImGui::SameLine();
  263. if (ImGui::Button("Clear##tileclear")) {
  264. getRender().debugDisplayTextile();
  265. visibleTile = false;
  266. }
  267. if (visibleTile && (index < TextureManager::numTiles())) {
  268. ImGui::Text(TextureManager::.getTile(index).isTriangle() ? "Triangle" : "Rectangle");
  269. }
  270. if (visibleTile) {
  271. getRender().debugDisplayTextile(index,
  272. ImGui::GetWindowPos().x - (ImGui::GetWindowWidth() / 2),
  273. ImGui::GetWindowPos().y,
  274. (ImGui::GetWindowWidth() / 2), (ImGui::GetWindowWidth() / 2));
  275. }
  276. } else {
  277. ImGui::Text("Please load a level using the new loader!");
  278. }
  279. }
  280. if (ImGui::CollapsingHeader("Animated Textile Viewer")) {
  281. if (TextureManager::.numAnimatedTiles() > 0) {
  282. static int index = 0;
  283. static int tile = TextureManager::.getFirstTileAnimation(index);
  284. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  285. if (ImGui::SliderInt("##animslide", &index, 0, TextureManager::.numAnimatedTiles() - 1)) {
  286. tile = TextureManager::.getFirstTileAnimation(index);
  287. }
  288. ImGui::PopItemWidth();
  289. ImGui::SameLine();
  290. if (ImGui::Button("+##animplus", ImVec2(0, 0), true)) {
  291. if (index < (TextureManager::.numAnimatedTiles() - 1))
  292. index++;
  293. else
  294. index = 0;
  295. tile = TextureManager::.getFirstTileAnimation(index);
  296. }
  297. ImGui::SameLine();
  298. if (ImGui::Button("-##animminus", ImVec2(0, 0), true)) {
  299. if (index > 0)
  300. index--;
  301. else
  302. index = TextureManager::.numAnimatedTiles() - 1;
  303. tile = TextureManager::.getFirstTileAnimation(index);
  304. }
  305. ImGui::SameLine();
  306. if (ImGui::Button("Show##animshow")) {
  307. visibleAnim = true;
  308. visibleTex = false;
  309. visibleTile = false;
  310. visibleSprite = false;
  311. }
  312. ImGui::SameLine();
  313. if (ImGui::Button("Clear##animclear")) {
  314. getRender().debugDisplayTextile();
  315. visibleAnim = false;
  316. }
  317. if (visibleAnim) {
  318. static int fr = 0;
  319. if (fr > 0) {
  320. fr--;
  321. } else {
  322. getRender().debugDisplayTextile(tile,
  323. ImGui::GetWindowPos().x - (ImGui::GetWindowWidth() / 2),
  324. ImGui::GetWindowPos().y,
  325. (ImGui::GetWindowWidth() / 2), (ImGui::GetWindowWidth() / 2));
  326. fr = RunTime::getFPS() / 2;
  327. tile = TextureManager::.getNextTileAnimation(tile);
  328. }
  329. ImGui::Text("Current Tile: %d", tile);
  330. }
  331. } else {
  332. ImGui::Text("Please load a level with animated textures!");
  333. }
  334. }
  335. if (ImGui::CollapsingHeader("Sprite Sequence Viewer")) {
  336. if (getWorld().sizeSprite() <= 0) {
  337. ImGui::Text("Please load a level containing sprites!");
  338. } else {
  339. static int index = 0;
  340. static int sprite = 0;
  341. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  342. if (ImGui::SliderInt("##spriteslide", &index, 0, getWorld().sizeSprite() - 1))
  343. sprite = 0;
  344. ImGui::PopItemWidth();
  345. ImGui::SameLine();
  346. if (ImGui::Button("+##spriteplus", ImVec2(0, 0), true)) {
  347. if (index < (getWorld().sizeSprite() - 1))
  348. index++;
  349. else
  350. index = 0;
  351. sprite = 0;
  352. }
  353. ImGui::SameLine();
  354. if (ImGui::Button("-##spriteminus", ImVec2(0, 0), true)) {
  355. if (index > 0)
  356. index--;
  357. else
  358. index = getWorld().sizeSprite() - 1;
  359. sprite = 0;
  360. }
  361. ImGui::SameLine();
  362. if (ImGui::Button("Show##spriteshow")) {
  363. visibleSprite = true;
  364. visibleTex = false;
  365. visibleTile = false;
  366. visibleAnim = false;
  367. sprite = 0;
  368. }
  369. ImGui::SameLine();
  370. if (ImGui::Button("Clear##spriteclear")) {
  371. getRender().debugDisplaySprite();
  372. visibleSprite = false;
  373. }
  374. if (visibleSprite) {
  375. static int fr = 0;
  376. if (fr > 0) {
  377. fr--;
  378. } else {
  379. getRender().debugDisplaySprite(index, sprite,
  380. ImGui::GetWindowPos().x - (ImGui::GetWindowWidth() / 2),
  381. ImGui::GetWindowPos().y,
  382. (ImGui::GetWindowWidth() / 2), (ImGui::GetWindowWidth() / 2));
  383. fr = RunTime::getFPS() / 10;
  384. if (sprite < (getWorld().getSprite(index).size() - 1))
  385. sprite++;
  386. else
  387. sprite = 0;
  388. }
  389. ImGui::Text("Sprite %d/%d", sprite + 1, getWorld().getSprite(index).size());
  390. }
  391. }
  392. }
  393. */
  394. if (ImGui::CollapsingHeader("ImGui/Debug UI Help")) {
  395. //ImGui::TextWrapped("DebugViewer Textures/Textiles/Sprites will be drawn on"
  396. // " the left side and scale with the size of this window!");
  397. //ImGui::Separator();
  398. ImGui::ShowUserGuide();
  399. ImGui::Separator();
  400. if (ImGui::Button("Show/Hide Test Window")) {
  401. showTestWindow = !showTestWindow;
  402. }
  403. }
  404. }
  405. ImGui::End();
  406. if (showTestWindow)
  407. ImGui::ShowTestWindow();
  408. ImGui::Render();
  409. }
  410. void UI::shutdown() {
  411. ImGui::Shutdown();
  412. }
  413. void UI::handleKeyboard(KeyboardButton key, bool pressed) {
  414. ImGuiIO& io = ImGui::GetIO();
  415. io.KeysDown[key] = pressed;
  416. io.KeyCtrl = io.KeysDown[leftctrlKey] | io.KeysDown[rightctrlKey];
  417. io.KeyShift = io.KeysDown[leftshiftKey] | io.KeysDown[rightshiftKey];
  418. keyboardEvents.push_back(std::make_tuple(key, pressed));
  419. if ((key == leftguiKey) || (key == rightguiKey))
  420. metaKeyIsActive = pressed;
  421. }
  422. void UI::handleText(char* text, bool notFinished) {
  423. if (notFinished)
  424. return;
  425. ImGuiIO& io = ImGui::GetIO();
  426. while (*text != '\0') {
  427. io.AddInputCharacter(*text);
  428. text++;
  429. }
  430. }
  431. void UI::handleMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) {
  432. ImGuiIO& io = ImGui::GetIO();
  433. io.MousePos = ImVec2((float)x, (float)y);
  434. if (button == leftmouseKey) {
  435. io.MouseDown[0] = !released;
  436. } else if (button == rightmouseKey) {
  437. io.MouseDown[1] = !released;
  438. } else if (button == middlemouseKey) {
  439. io.MouseDown[2] = !released;
  440. } else if (button == fourthmouseKey) {
  441. io.MouseDown[3] = !released;
  442. } else if (button == fifthmouseKey) {
  443. io.MouseDown[4] = !released;
  444. }
  445. clickEvents.push_back(std::make_tuple(x, y, button, released));
  446. }
  447. void UI::handleMouseMotion(int xrel, int yrel, int xabs, int yabs) {
  448. ImGuiIO& io = ImGui::GetIO();
  449. io.MousePos = ImVec2((float)xabs, (float)yabs);
  450. motionEvents.push_back(std::make_tuple(xrel, yrel, xabs, yabs));
  451. }
  452. void UI::handleMouseScroll(int xrel, int yrel) {
  453. ImGuiIO& io = ImGui::GetIO();
  454. io.MouseWheel += yrel;
  455. scrollEvents.push_back(std::make_tuple(xrel, yrel));
  456. }
  457. void UI::handleControllerAxis(float value, KeyboardButton axis) {
  458. getGame().handleControllerAxis(value, axis);
  459. }
  460. void UI::handleControllerButton(KeyboardButton button, bool released) {
  461. getGame().handleControllerButton(button, released);
  462. }
  463. void UI::renderImGui(ImDrawList** const cmd_lists, int cmd_lists_count) {
  464. if (cmd_lists_count == 0)
  465. return;
  466. static ShaderBuffer vert, uv, col;
  467. glEnable(GL_SCISSOR_TEST);
  468. glDisable(GL_DEPTH_TEST);
  469. imguiShader.use();
  470. imguiShader.loadUniform(0, Window::getSize());
  471. imguiShader.loadUniform(1, fontTex, TextureStorage::SYSTEM);
  472. vert.bindBuffer(0, 2);
  473. uv.bindBuffer(1, 2);
  474. col.bindBuffer(2, 4);
  475. /*! \fixme Don't copy data
  476. * The GL calls and the shaders can probably be slightly altered
  477. * to avoid copying all the vertices, uvs and colors again here.
  478. */
  479. for (int i = 0; i < cmd_lists_count; i++) {
  480. auto& commands = cmd_lists[i]->commands;
  481. auto& buffer = cmd_lists[i]->vtx_buffer;
  482. int offset = 0;
  483. for (int n = 0; n < commands.size(); n++) {
  484. std::vector<glm::vec2> vertices;
  485. std::vector<glm::vec2> uvs;
  486. std::vector<glm::vec4> colors;
  487. for (int v = 0; v < commands[n].vtx_count; v++) {
  488. vertices.push_back(glm::vec2(buffer[offset + v].pos.x, buffer[offset + v].pos.y));
  489. uvs.push_back(glm::vec2(buffer[offset + v].uv.x, buffer[offset + v].uv.y));
  490. float r, g, b, a;
  491. a = ((buffer[offset + v].col & 0xFF000000) >> 24) / 255.0f;
  492. b = ((buffer[offset + v].col & 0x00FF0000) >> 16) / 255.0f;
  493. g = ((buffer[offset + v].col & 0x0000FF00) >> 8) / 255.0f;
  494. r = (buffer[offset + v].col & 0x000000FF) / 255.0f;
  495. colors.push_back(glm::vec4(r, g, b, a));
  496. }
  497. offset += commands[n].vtx_count;
  498. vert.bufferData(vertices);
  499. uv.bufferData(uvs);
  500. col.bufferData(colors);
  501. glScissor(commands[n].clip_rect.x,
  502. Window::getSize().y - commands[n].clip_rect.w,
  503. commands[n].clip_rect.z - commands[n].clip_rect.x,
  504. commands[n].clip_rect.w - commands[n].clip_rect.y);
  505. glDrawArrays(GL_TRIANGLES, 0, vertices.size());
  506. }
  507. }
  508. vert.unbind(0);
  509. uv.unbind(1);
  510. col.unbind(2);
  511. glEnable(GL_DEPTH_TEST);
  512. glDisable(GL_SCISSOR_TEST);
  513. }
  514. // --------------------------------------
  515. // *INDENT-OFF*
  516. const char* UI::imguiShaderVertex = R"!?!(
  517. #version 330 core
  518. layout(location = 0) in vec2 vertexPosition_screen;
  519. layout(location = 1) in vec2 vertexUV;
  520. layout(location = 2) in vec4 vertexColor;
  521. out vec2 UV;
  522. out vec4 FragColor;
  523. uniform vec2 screen;
  524. void main() {
  525. vec2 halfScreen = screen / 2;
  526. vec2 vertexPosition_homogenous = (vertexPosition_screen - halfScreen) / halfScreen;
  527. gl_Position = vec4(vertexPosition_homogenous.x, -vertexPosition_homogenous.y, 0, 1);
  528. UV = vertexUV;
  529. FragColor = vertexColor;
  530. }
  531. )!?!";
  532. const char* UI::imguiShaderFragment = R"!?!(
  533. #version 330 core
  534. in vec2 UV;
  535. in vec4 FragColor;
  536. out vec4 color;
  537. uniform sampler2D textureSampler;
  538. void main() {
  539. color = texture(textureSampler, UV) * FragColor;
  540. }
  541. )!?!";
  542. // --------------------------------------
  543. // *INDENT-ON*