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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  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) {
  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) {
  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) {
  135. if (RunTime::getKeyBinding(menuAction) == std::get<0>(i)) {
  136. getMenu().setVisible(!getMenu().isVisible());
  137. }
  138. }
  139. if ((!io.WantCaptureKeyboard) || (!visible)) {
  140. if (RunTime::getKeyBinding(debugAction) == std::get<0>(i)) {
  141. if (!metaKeyIsActive)
  142. visible = !visible;
  143. }
  144. }
  145. }
  146. keyboardEvents.pop_front();
  147. }
  148. bool clicked = !clickEvents.empty();
  149. // Only already empty when !visible
  150. if (visible) {
  151. clickEvents.clear();
  152. motionEvents.clear();
  153. scrollEvents.clear();
  154. }
  155. if (visible && (
  156. ((!io.WantCaptureKeyboard) && io.KeysDown[escapeKey])
  157. || ((!io.WantCaptureMouse) && clicked)
  158. )) {
  159. visible = false;
  160. }
  161. if (Window::getTextInput() != visible)
  162. Window::setTextInput(visible);
  163. bool input = !(visible || getMenu().isVisible());
  164. if (Window::getMousegrab() != input)
  165. Window::setMousegrab(input);
  166. io.MouseWheel = 0;
  167. }
  168. void UI::display() {
  169. if (!visible)
  170. return;
  171. Console::display();
  172. static bool showTestWindow = false;
  173. if (ImGui::Begin("Engine", nullptr, ImVec2(400, 400))) {
  174. Render::displayUI();
  175. RunTime::display();
  176. SoundManager::display();
  177. /*
  178. static bool visibleTex = false;
  179. static bool visibleTile = false;
  180. static bool visibleAnim = false;
  181. static bool visibleSprite = false;
  182. if (ImGui::CollapsingHeader("Texture Viewer")) {
  183. static bool game = getGame().isLoaded();
  184. static int index = 0;
  185. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  186. ImGui::SliderInt("##texslide", &index, 0, TextureManager::.numTextures(
  187. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1);
  188. ImGui::PopItemWidth();
  189. ImGui::SameLine();
  190. if (ImGui::Button("+##texplus", ImVec2(0, 0), true)) {
  191. if (index < (TextureManager::numTextures(
  192. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1))
  193. index++;
  194. else
  195. index = 0;
  196. }
  197. ImGui::SameLine();
  198. if (ImGui::Button("-##texminus", ImVec2(0, 0), true)) {
  199. if (index > 0)
  200. index--;
  201. else
  202. index = TextureManager::numTextures(
  203. game ? TextureStorage::GAME : TextureStorage::SYSTEM) - 1;
  204. }
  205. ImGui::SameLine();
  206. if ((TextureManager::numTextures() > 0)) {
  207. ImGui::Checkbox("Game##texgame", &game);
  208. } else {
  209. game = false;
  210. }
  211. ImGui::SameLine();
  212. if (ImGui::Button("Show##texshow")) {
  213. visibleTex = true;
  214. visibleTile = false;
  215. visibleAnim = false;
  216. visibleSprite = false;
  217. }
  218. ImGui::SameLine();
  219. if (ImGui::Button("Clear##texclear")) {
  220. getRender().debugDisplayTexture();
  221. visibleTex = false;
  222. }
  223. if (visibleTex) {
  224. getRender().debugDisplayTexture(index,
  225. game ? TextureStorage::GAME : TextureStorage::SYSTEM,
  226. ImGui::GetWindowPos().x - ImGui::GetWindowWidth(),
  227. ImGui::GetWindowPos().y,
  228. ImGui::GetWindowWidth(), ImGui::GetWindowWidth());
  229. }
  230. }
  231. if (ImGui::CollapsingHeader("Textile Viewer")) {
  232. if (TextureManager::numTiles() > 0) {
  233. static int index = 0;
  234. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  235. ImGui::SliderInt("##tileslide", &index, 0, TextureManager::numTiles() - 1);
  236. ImGui::PopItemWidth();
  237. ImGui::SameLine();
  238. if (ImGui::Button("+##tileplus", ImVec2(0, 0), true)) {
  239. if (index < (TextureManager::numTiles() - 1))
  240. index++;
  241. else
  242. index = 0;
  243. }
  244. ImGui::SameLine();
  245. if (ImGui::Button("-##tileminus", ImVec2(0, 0), true)) {
  246. if (index > 0)
  247. index--;
  248. else
  249. index = TextureManager::numTiles() - 1;
  250. }
  251. ImGui::SameLine();
  252. if (ImGui::Button("Show##tileshow")) {
  253. visibleTile = true;
  254. visibleTex = false;
  255. visibleAnim = false;
  256. visibleSprite = false;
  257. }
  258. ImGui::SameLine();
  259. if (ImGui::Button("Clear##tileclear")) {
  260. getRender().debugDisplayTextile();
  261. visibleTile = false;
  262. }
  263. if (visibleTile && (index < TextureManager::numTiles())) {
  264. ImGui::Text(TextureManager::.getTile(index).isTriangle() ? "Triangle" : "Rectangle");
  265. }
  266. if (visibleTile) {
  267. getRender().debugDisplayTextile(index,
  268. ImGui::GetWindowPos().x - (ImGui::GetWindowWidth() / 2),
  269. ImGui::GetWindowPos().y,
  270. (ImGui::GetWindowWidth() / 2), (ImGui::GetWindowWidth() / 2));
  271. }
  272. } else {
  273. ImGui::Text("Please load a level using the new loader!");
  274. }
  275. }
  276. if (ImGui::CollapsingHeader("Animated Textile Viewer")) {
  277. if (TextureManager::.numAnimatedTiles() > 0) {
  278. static int index = 0;
  279. static int tile = TextureManager::.getFirstTileAnimation(index);
  280. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  281. if (ImGui::SliderInt("##animslide", &index, 0, TextureManager::.numAnimatedTiles() - 1)) {
  282. tile = TextureManager::.getFirstTileAnimation(index);
  283. }
  284. ImGui::PopItemWidth();
  285. ImGui::SameLine();
  286. if (ImGui::Button("+##animplus", ImVec2(0, 0), true)) {
  287. if (index < (TextureManager::.numAnimatedTiles() - 1))
  288. index++;
  289. else
  290. index = 0;
  291. tile = TextureManager::.getFirstTileAnimation(index);
  292. }
  293. ImGui::SameLine();
  294. if (ImGui::Button("-##animminus", ImVec2(0, 0), true)) {
  295. if (index > 0)
  296. index--;
  297. else
  298. index = TextureManager::.numAnimatedTiles() - 1;
  299. tile = TextureManager::.getFirstTileAnimation(index);
  300. }
  301. ImGui::SameLine();
  302. if (ImGui::Button("Show##animshow")) {
  303. visibleAnim = true;
  304. visibleTex = false;
  305. visibleTile = false;
  306. visibleSprite = false;
  307. }
  308. ImGui::SameLine();
  309. if (ImGui::Button("Clear##animclear")) {
  310. getRender().debugDisplayTextile();
  311. visibleAnim = false;
  312. }
  313. if (visibleAnim) {
  314. static int fr = 0;
  315. if (fr > 0) {
  316. fr--;
  317. } else {
  318. getRender().debugDisplayTextile(tile,
  319. ImGui::GetWindowPos().x - (ImGui::GetWindowWidth() / 2),
  320. ImGui::GetWindowPos().y,
  321. (ImGui::GetWindowWidth() / 2), (ImGui::GetWindowWidth() / 2));
  322. fr = RunTime::getFPS() / 2;
  323. tile = TextureManager::.getNextTileAnimation(tile);
  324. }
  325. ImGui::Text("Current Tile: %d", tile);
  326. }
  327. } else {
  328. ImGui::Text("Please load a level with animated textures!");
  329. }
  330. }
  331. if (ImGui::CollapsingHeader("Sprite Sequence Viewer")) {
  332. if (getWorld().sizeSprite() <= 0) {
  333. ImGui::Text("Please load a level containing sprites!");
  334. } else {
  335. static int index = 0;
  336. static int sprite = 0;
  337. ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
  338. if (ImGui::SliderInt("##spriteslide", &index, 0, getWorld().sizeSprite() - 1))
  339. sprite = 0;
  340. ImGui::PopItemWidth();
  341. ImGui::SameLine();
  342. if (ImGui::Button("+##spriteplus", ImVec2(0, 0), true)) {
  343. if (index < (getWorld().sizeSprite() - 1))
  344. index++;
  345. else
  346. index = 0;
  347. sprite = 0;
  348. }
  349. ImGui::SameLine();
  350. if (ImGui::Button("-##spriteminus", ImVec2(0, 0), true)) {
  351. if (index > 0)
  352. index--;
  353. else
  354. index = getWorld().sizeSprite() - 1;
  355. sprite = 0;
  356. }
  357. ImGui::SameLine();
  358. if (ImGui::Button("Show##spriteshow")) {
  359. visibleSprite = true;
  360. visibleTex = false;
  361. visibleTile = false;
  362. visibleAnim = false;
  363. sprite = 0;
  364. }
  365. ImGui::SameLine();
  366. if (ImGui::Button("Clear##spriteclear")) {
  367. getRender().debugDisplaySprite();
  368. visibleSprite = false;
  369. }
  370. if (visibleSprite) {
  371. static int fr = 0;
  372. if (fr > 0) {
  373. fr--;
  374. } else {
  375. getRender().debugDisplaySprite(index, sprite,
  376. ImGui::GetWindowPos().x - (ImGui::GetWindowWidth() / 2),
  377. ImGui::GetWindowPos().y,
  378. (ImGui::GetWindowWidth() / 2), (ImGui::GetWindowWidth() / 2));
  379. fr = RunTime::getFPS() / 10;
  380. if (sprite < (getWorld().getSprite(index).size() - 1))
  381. sprite++;
  382. else
  383. sprite = 0;
  384. }
  385. ImGui::Text("Sprite %d/%d", sprite + 1, getWorld().getSprite(index).size());
  386. }
  387. }
  388. }
  389. */
  390. if (ImGui::CollapsingHeader("ImGui/Debug UI Help")) {
  391. //ImGui::TextWrapped("DebugViewer Textures/Textiles/Sprites will be drawn on"
  392. // " the left side and scale with the size of this window!");
  393. //ImGui::Separator();
  394. ImGui::ShowUserGuide();
  395. ImGui::Separator();
  396. if (ImGui::Button("Show/Hide Test Window")) {
  397. showTestWindow = !showTestWindow;
  398. }
  399. }
  400. }
  401. ImGui::End();
  402. if (showTestWindow)
  403. ImGui::ShowTestWindow();
  404. ImGui::Render();
  405. }
  406. void UI::shutdown() {
  407. ImGui::Shutdown();
  408. }
  409. void UI::handleKeyboard(KeyboardButton key, bool pressed) {
  410. ImGuiIO& io = ImGui::GetIO();
  411. io.KeysDown[key] = pressed;
  412. io.KeyCtrl = io.KeysDown[leftctrlKey] | io.KeysDown[rightctrlKey];
  413. io.KeyShift = io.KeysDown[leftshiftKey] | io.KeysDown[rightshiftKey];
  414. keyboardEvents.push_back(std::make_tuple(key, pressed));
  415. if ((key == leftguiKey) || (key == rightguiKey))
  416. metaKeyIsActive = pressed;
  417. }
  418. void UI::handleText(char* text, bool notFinished) {
  419. if (notFinished)
  420. return;
  421. ImGuiIO& io = ImGui::GetIO();
  422. while (*text != '\0') {
  423. io.AddInputCharacter(*text);
  424. text++;
  425. }
  426. }
  427. void UI::handleMouseClick(unsigned int x, unsigned int y, KeyboardButton button, bool released) {
  428. ImGuiIO& io = ImGui::GetIO();
  429. io.MousePos = ImVec2((float)x, (float)y);
  430. if (button == leftmouseKey) {
  431. io.MouseDown[0] = !released;
  432. } else if (button == rightmouseKey) {
  433. io.MouseDown[1] = !released;
  434. } else if (button == middlemouseKey) {
  435. io.MouseDown[2] = !released;
  436. } else if (button == fourthmouseKey) {
  437. io.MouseDown[3] = !released;
  438. } else if (button == fifthmouseKey) {
  439. io.MouseDown[4] = !released;
  440. }
  441. clickEvents.push_back(std::make_tuple(x, y, button, released));
  442. }
  443. void UI::handleMouseMotion(int xrel, int yrel, int xabs, int yabs) {
  444. ImGuiIO& io = ImGui::GetIO();
  445. io.MousePos = ImVec2((float)xabs, (float)yabs);
  446. motionEvents.push_back(std::make_tuple(xrel, yrel, xabs, yabs));
  447. }
  448. void UI::handleMouseScroll(int xrel, int yrel) {
  449. ImGuiIO& io = ImGui::GetIO();
  450. io.MouseWheel += yrel;
  451. scrollEvents.push_back(std::make_tuple(xrel, yrel));
  452. }
  453. void UI::handleControllerAxis(float value, KeyboardButton axis) {
  454. getGame().handleControllerAxis(value, axis);
  455. }
  456. void UI::handleControllerButton(KeyboardButton button, bool released) {
  457. getGame().handleControllerButton(button, released);
  458. }
  459. void UI::setVisible(bool v) {
  460. visible = v;
  461. }
  462. bool UI::isVisible() {
  463. return visible;
  464. }
  465. void UI::renderImGui(ImDrawList** const cmd_lists, int cmd_lists_count) {
  466. if (cmd_lists_count == 0)
  467. return;
  468. static ShaderBuffer vert, uv, col;
  469. glEnable(GL_SCISSOR_TEST);
  470. glDisable(GL_DEPTH_TEST);
  471. imguiShader.use();
  472. imguiShader.loadUniform(0, Window::getSize());
  473. imguiShader.loadUniform(1, fontTex, TextureStorage::SYSTEM);
  474. vert.bindBuffer(0, 2);
  475. uv.bindBuffer(1, 2);
  476. col.bindBuffer(2, 4);
  477. /*! \fixme Don't copy data
  478. * The GL calls and the shaders can probably be slightly altered
  479. * to avoid copying all the vertices, uvs and colors again here.
  480. */
  481. for (int i = 0; i < cmd_lists_count; i++) {
  482. auto& commands = cmd_lists[i]->commands;
  483. auto& buffer = cmd_lists[i]->vtx_buffer;
  484. int offset = 0;
  485. for (int n = 0; n < commands.size(); n++) {
  486. std::vector<glm::vec2> vertices;
  487. std::vector<glm::vec2> uvs;
  488. std::vector<glm::vec4> colors;
  489. for (int v = 0; v < commands[n].vtx_count; v++) {
  490. vertices.push_back(glm::vec2(buffer[offset + v].pos.x, buffer[offset + v].pos.y));
  491. uvs.push_back(glm::vec2(buffer[offset + v].uv.x, buffer[offset + v].uv.y));
  492. float r, g, b, a;
  493. a = ((buffer[offset + v].col & 0xFF000000) >> 24) / 255.0f;
  494. b = ((buffer[offset + v].col & 0x00FF0000) >> 16) / 255.0f;
  495. g = ((buffer[offset + v].col & 0x0000FF00) >> 8) / 255.0f;
  496. r = (buffer[offset + v].col & 0x000000FF) / 255.0f;
  497. colors.push_back(glm::vec4(r, g, b, a));
  498. }
  499. offset += commands[n].vtx_count;
  500. vert.bufferData(vertices);
  501. uv.bufferData(uvs);
  502. col.bufferData(colors);
  503. glScissor(commands[n].clip_rect.x,
  504. Window::getSize().y - commands[n].clip_rect.w,
  505. commands[n].clip_rect.z - commands[n].clip_rect.x,
  506. commands[n].clip_rect.w - commands[n].clip_rect.y);
  507. glDrawArrays(GL_TRIANGLES, 0, vertices.size());
  508. }
  509. }
  510. vert.unbind(0);
  511. uv.unbind(1);
  512. col.unbind(2);
  513. glEnable(GL_DEPTH_TEST);
  514. glDisable(GL_SCISSOR_TEST);
  515. }
  516. // --------------------------------------
  517. // *INDENT-OFF*
  518. const char* UI::imguiShaderVertex = R"!?!(
  519. #version 330 core
  520. layout(location = 0) in vec2 vertexPosition_screen;
  521. layout(location = 1) in vec2 vertexUV;
  522. layout(location = 2) in vec4 vertexColor;
  523. out vec2 UV;
  524. out vec4 FragColor;
  525. uniform vec2 screen;
  526. void main() {
  527. vec2 halfScreen = screen / 2;
  528. vec2 vertexPosition_homogenous = (vertexPosition_screen - halfScreen) / halfScreen;
  529. gl_Position = vec4(vertexPosition_homogenous.x, -vertexPosition_homogenous.y, 0, 1);
  530. UV = vertexUV;
  531. FragColor = vertexColor;
  532. }
  533. )!?!";
  534. const char* UI::imguiShaderFragment = R"!?!(
  535. #version 330 core
  536. in vec2 UV;
  537. in vec4 FragColor;
  538. out vec4 color;
  539. uniform sampler2D textureSampler;
  540. void main() {
  541. color = texture(textureSampler, UV) * FragColor;
  542. }
  543. )!?!";
  544. // --------------------------------------
  545. // *INDENT-ON*