409 lines
14 KiB

  1. //
  2. // imGui integration in lolengine
  3. //
  4. // Copyright © 2009-2015 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
  5. //
  6. // This program is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #include <lol/engine-internal.h>
  13. #include "imgui.cpp"
  14. #include <cstdio>
  15. using namespace lol;
  16. //-----------------------------------------------------------------------------
  17. LolImGui::LolImGui()
  18. {
  19. m_gamegroup = GAMEGROUP_IMGUI;
  20. m_drawgroup = DRAWGROUP_IMGUI;
  21. //Build shader code -------------------------------------------------------
  22. ShaderVar out_vertex = ShaderVar::GetShaderOut(ShaderProgram::Vertex);
  23. ShaderVar out_pixel = ShaderVar::GetShaderOut(ShaderProgram::Pixel);
  24. ShaderVar pass_texcoord = ShaderVar(ShaderVariable::Varying, ShaderVariableType::Vec2, "texcoord");
  25. ShaderVar pass_color = ShaderVar(ShaderVariable::Varying, ShaderVariableType::Vec4, "color");
  26. ShaderVar in_position = ShaderVar(ShaderVariable::Attribute, ShaderVariableType::Vec2, "position");
  27. ShaderVar in_texcoord = ShaderVar(ShaderVariable::Attribute, ShaderVariableType::Vec2, "texcoord");
  28. ShaderVar in_color = ShaderVar(ShaderVariable::Attribute, ShaderVariableType::Vec4, "color");
  29. m_ortho.m_var = ShaderVar(ShaderVariable::Uniform, ShaderVariableType::Mat4, "ortho");
  30. m_texture.m_var = ShaderVar(ShaderVariable::Uniform, ShaderVariableType::sampler2D, "texture");
  31. ShaderBlock imgui_vertex("imgui_vertex");
  32. imgui_vertex
  33. << out_vertex << m_ortho << in_position
  34. << pass_texcoord << in_texcoord
  35. << pass_color << in_color;
  36. imgui_vertex.SetMainCode(String() +
  37. Line(out_vertex + " = .5 *" + m_ortho + " * vec4(" + in_position + ", -1.0, 1.0);")
  38. + Line(pass_texcoord + " = " + in_texcoord + ";")
  39. + Line(pass_color + " = " + in_color + ";")
  40. );
  41. ShaderBlock imgui_pixel("imgui_pixel");
  42. imgui_pixel << m_texture << pass_texcoord << pass_color << out_pixel;
  43. imgui_pixel.SetMainCode(String() +
  44. Line(String()
  45. + "vec4 col = " + pass_color + " * texture2D(" + m_texture + ", " + pass_texcoord + ");")
  46. + Line("if (col.a == 0.0) discard; ")
  47. + Line(out_pixel + " = col;")
  48. );
  49. m_builder
  50. << ShaderProgram::Vertex << imgui_vertex
  51. << ShaderProgram::Pixel << imgui_pixel;
  52. //Input Setup -------------------------------------------------------------
  53. InputProfile& ip = m_profile;
  54. ip.AddBindings<LolImGuiKey, LolImGuiKey::KEY_START, LolImGuiKey::KEY_END>(InputProfileType::Keyboard);
  55. //for (int i = LolImGuiKey::KEY_START; i < LolImGuiKey::KEY_END; ++i)
  56. // m_profile << InputProfile::Keyboard(i, LolImGuiKey(i).ToString());
  57. for (int i = LolImGuiKey::MOUSE_KEY_START; i < LolImGuiKey::MOUSE_KEY_END; ++i)
  58. m_profile << InputProfile::MouseKey(i, LolImGuiKey(i).ToString());
  59. for (int i = LolImGuiAxis::MOUSE_AXIS_START; i < LolImGuiAxis::MOUSE_AXIS_END; ++i)
  60. m_profile << InputProfile::MouseAxis(i, LolImGuiAxis(i).ToString());
  61. Ticker::Ref(m_controller = new Controller("ImGui_Controller"));
  62. m_controller->Init(m_profile);
  63. //InputDevice::CaptureMouse(true);
  64. m_mouse = InputDevice::GetMouse();
  65. m_keyboard = InputDevice::GetKeyboard();
  66. //m_controller->Get
  67. //# define KB InputProfile::Keyboard
  68. // m_profile
  69. // << InputProfile::Keyboard(idx, g_name_key_Left);
  70. //# undef KB
  71. }
  72. LolImGui::~LolImGui()
  73. {
  74. ImGui::GetIO().Fonts->TexID = nullptr;
  75. Ticker::Unref(m_font);
  76. m_font = nullptr;
  77. Shader::Destroy(m_shader);
  78. delete m_vdecl;
  79. }
  80. //-----------------------------------------------------------------------------
  81. LolImGui* g_lolimgui = nullptr;
  82. void LolImGui::Init()
  83. {
  84. Ticker::Ref(g_lolimgui = new LolImGui());
  85. ImGuiIO& io = ImGui::GetIO();
  86. //ImFont* font0 = io.Fonts->AddFontDefault();
  87. // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
  88. io.KeyMap[ImGuiKey_Tab] = LolImGuiKey::Tab;
  89. io.KeyMap[ImGuiKey_LeftArrow] = LolImGuiKey::LeftArrow;
  90. io.KeyMap[ImGuiKey_RightArrow] = LolImGuiKey::RightArrow;
  91. io.KeyMap[ImGuiKey_UpArrow] = LolImGuiKey::UpArrow;
  92. io.KeyMap[ImGuiKey_DownArrow] = LolImGuiKey::DownArrow;
  93. io.KeyMap[ImGuiKey_Home] = LolImGuiKey::Home;
  94. io.KeyMap[ImGuiKey_End] = LolImGuiKey::End;
  95. io.KeyMap[ImGuiKey_Delete] = LolImGuiKey::Delete;
  96. io.KeyMap[ImGuiKey_Backspace] = LolImGuiKey::Backspace;
  97. io.KeyMap[ImGuiKey_Enter] = LolImGuiKey::Enter;
  98. io.KeyMap[ImGuiKey_Escape] = LolImGuiKey::Escape;
  99. io.KeyMap[ImGuiKey_A] = LolImGuiKey::A;
  100. io.KeyMap[ImGuiKey_C] = LolImGuiKey::C;
  101. io.KeyMap[ImGuiKey_V] = LolImGuiKey::V;
  102. io.KeyMap[ImGuiKey_X] = LolImGuiKey::X;
  103. io.KeyMap[ImGuiKey_Y] = LolImGuiKey::Y;
  104. io.KeyMap[ImGuiKey_Z] = LolImGuiKey::Z;
  105. //Func pointer
  106. io.RenderDrawListsFn = LolImGui::RenderDrawLists;
  107. io.SetClipboardTextFn = LolImGui::SetClipboard;
  108. io.GetClipboardTextFn = LolImGui::GetClipboard;
  109. }
  110. /* CALLBACKS
  111. void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
  112. {
  113. ImGuiIO& io = ImGui::GetIO();
  114. if (c > 0 && c < 0x10000)
  115. io.AddInputCharacter((unsigned short)c);
  116. }
  117. */
  118. void LolImGui::Shutdown()
  119. {
  120. Ticker::Unref(g_lolimgui);
  121. ImGui::Shutdown();
  122. }
  123. //-----------------------------------------------------------------------------
  124. static String g_clipboard;
  125. void LolImGui::SetClipboard(const char* text)
  126. {
  127. g_clipboard = text;
  128. }
  129. const char* LolImGui::GetClipboard()
  130. {
  131. return g_clipboard.C();
  132. }
  133. //-----------------------------------------------------------------------------
  134. void LolImGui::TickGame(float seconds)
  135. {
  136. super::TickGame(seconds);
  137. ImGuiIO& io = ImGui::GetIO();
  138. //Init Texture
  139. if (!m_font)
  140. {
  141. // Build texture
  142. unsigned char* pixels;
  143. ivec2 size;
  144. io.Fonts->GetTexDataAsRGBA32(&pixels, &size.x, &size.y);
  145. Image* image = new Image();
  146. image->Copy(pixels, size, PixelFormat::RGBA_8);
  147. Ticker::Ref(m_font = new TextureImage("", image));
  148. }
  149. //Texture has been created
  150. if (m_font && m_font->GetTexture())
  151. {
  152. io.Fonts->TexID = (void *)(intptr_t)m_font;
  153. }
  154. // Setup display size (every frame to accommodate for window resizing)
  155. vec2 video_size = vec2(0);
  156. video_size = vec2(Video::GetSize());
  157. io.DisplaySize = ImVec2(video_size.x, video_size.y);
  158. //Setup time step
  159. io.DeltaTime = seconds;
  160. io.MouseDrawCursor = true;
  161. //Update Keyboard
  162. io.KeyCtrl = false;
  163. io.KeyShift = false;
  164. for (int i = LolImGuiKey::KEY_START; i < LolImGuiKey::KEY_END; ++i)
  165. {
  166. switch (i)
  167. {
  168. default:
  169. io.KeysDown[i] = m_controller->IsKeyPressed(i);
  170. break;
  171. case LolImGuiKey::LShift:
  172. case LolImGuiKey::RShift:
  173. io.KeyShift = (io.KeyShift || m_controller->IsKeyPressed(i));
  174. break;
  175. case LolImGuiKey::LCtrl:
  176. case LolImGuiKey::RCtrl:
  177. io.KeyCtrl = (io.KeyCtrl || m_controller->IsKeyPressed(i));
  178. break;
  179. }
  180. }
  181. //Update text input
  182. String text = m_keyboard->GetText();
  183. //text.case_change(io.KeyShift);
  184. for (int i = 0; i < text.count(); ++i)
  185. io.AddInputCharacter(text[i]);
  186. //Update mouse
  187. if (m_mouse)
  188. {
  189. vec2 cursor = m_mouse->GetCursor(0);
  190. cursor.y = 1.f - cursor.y;
  191. cursor *= video_size;
  192. io.MousePos = ImVec2(cursor.x, cursor.y);
  193. Log::Debug(Line("%.2f/%.2f"), io.MousePos.x, io.MousePos.y);
  194. io.MouseWheel = m_controller->GetAxisValue(LolImGuiAxis::Scroll);
  195. for (int i = LolImGuiKey::MOUSE_KEY_START; i < LolImGuiKey::MOUSE_KEY_END; ++i)
  196. {
  197. switch (i)
  198. {
  199. default:
  200. io.MouseDown[i - LolImGuiKey::MOUSE_KEY_START] = m_controller->IsKeyPressed(i);
  201. break;
  202. case LolImGuiKey::Focus:
  203. if (m_controller->IsKeyReleased(i))
  204. {
  205. Log::Debug(Line("Not focused ....."));
  206. io.MousePos = ImVec2(-1.f, -1.f);
  207. }
  208. else
  209. Log::Debug(Line("Focused !!"));
  210. break;
  211. }
  212. }
  213. }
  214. // Start the frame
  215. ImGui::NewFrame();
  216. }
  217. //-----------------------------------------------------------------------------
  218. void LolImGui::TickDraw(float seconds, Scene &scene)
  219. {
  220. super::TickDraw(seconds, scene);
  221. scene.AddPrimitive(new PrimitiveLolImGui());
  222. }
  223. void PrimitiveLolImGui::Render() const
  224. {
  225. g_renderer->Clear(ClearMask::Depth);
  226. ImGuiIO& io = ImGui::GetIO();
  227. if (io.Fonts->TexID)
  228. ImGui::Render();
  229. }
  230. //// Data
  231. //static GLFWwindow* g_Window = NULL;
  232. //static double g_Time = 0.0f;
  233. //static bool g_MousePressed[3] = { false, false, false };
  234. //static float g_MouseWheel = 0.0f;
  235. //static GLuint g_FontTexture = 0;
  236. //-------------------------------------------------------------------------
  237. // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
  238. // If text or lines are blurry when integrating ImGui in your engine:
  239. // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
  240. //-------------------------------------------------------------------------
  241. void LolImGui::RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
  242. {
  243. g_lolimgui->RenderDrawListsMethod(cmd_lists, cmd_lists_count);
  244. }
  245. void LolImGui::RenderDrawListsMethod(ImDrawList** const cmd_lists, int cmd_lists_count)
  246. {
  247. if (cmd_lists_count == 0)
  248. return;
  249. vec2 size = vec2(Video::GetSize());
  250. float alpha = 1.f;
  251. mat4 ortho = mat4::ortho(size.x * alpha, size.y * alpha, -1000.f, 1000.f)
  252. * mat4::lookat(vec3::axis_z, vec3::zero, vec3::axis_y)
  253. * mat4::scale(vec3::axis_x - vec3::axis_y - vec3::axis_z)
  254. * mat4::translate(-size.x * .5f * alpha, -size.y * .5f * alpha, 0.f);
  255. //Create shader
  256. if (!m_shader)
  257. {
  258. String code;
  259. m_builder.Build(code);
  260. m_shader = Shader::Create(m_builder.GetName(), code);
  261. ASSERT(m_shader);
  262. m_ortho.m_uniform = m_shader->GetUniformLocation(m_ortho.m_var);
  263. m_texture.m_uniform = m_shader->GetUniformLocation(m_texture.m_var);
  264. m_attribs
  265. << m_shader->GetAttribLocation(VertexUsage::Position, 0)
  266. << m_shader->GetAttribLocation(VertexUsage::TexCoord, 0)
  267. << m_shader->GetAttribLocation(VertexUsage::Color, 0);
  268. m_vdecl = new VertexDeclaration(
  269. VertexStream<vec2, vec2, u8vec4>(
  270. VertexUsage::Position,
  271. VertexUsage::TexCoord,
  272. VertexUsage::Color));
  273. }
  274. //Do not render without shader
  275. if (!m_shader)
  276. return;
  277. RenderContext rc;
  278. rc.SetCullMode(CullMode::Disabled);
  279. rc.SetDepthFunc(DepthFunc::Disabled);
  280. m_shader->Bind();
  281. for (int n = 0; n < cmd_lists_count; n++)
  282. {
  283. const ImDrawList* cmd_list = cmd_lists[n];
  284. const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->vtx_buffer.front();
  285. //Register uniforms
  286. m_shader->SetUniform(m_ortho, ortho);
  287. m_shader->SetUniform(m_texture, m_font->GetTexture()->GetTextureUniform(), 0);
  288. int vtx_offset = 0;
  289. for (size_t cmd_i = 0; cmd_i < cmd_list->commands.size(); cmd_i++)
  290. {
  291. const ImDrawCmd* pcmd = &cmd_list->commands[cmd_i];
  292. struct Vertex
  293. {
  294. vec2 pos, tex;
  295. u8vec4 color;
  296. };
  297. VertexBuffer* vbo = new VertexBuffer(pcmd->vtx_count * sizeof(Vertex));
  298. Vertex *vert = (Vertex *)vbo->Lock(0, 0);
  299. #ifdef SHOW_IMGUI_DEBUG
  300. //-----------------------------------------------------------------
  301. //<Debug render> --------------------------------------------------
  302. //-----------------------------------------------------------------
  303. float mod = -200.f;
  304. vec3 off = vec3(vec2(-size.x, -size.y), 0.f);
  305. vec3 pos[4] = {
  306. (1.f / mod) * (off + vec3(0.f)),
  307. (1.f / mod) * (off + size.x * vec3::axis_x),
  308. (1.f / mod) * (off + size.x * vec3::axis_x + size.y * vec3::axis_y),
  309. (1.f / mod) * (off + size.y * vec3::axis_y)
  310. };
  311. for (int i = 0; i < 4; ++i)
  312. Debug::DrawLine(pos[i], pos[(i + 1) % 4], Color::white);
  313. ImDrawVert* buf = (ImDrawVert*)(vtx_buffer + vtx_offset);
  314. for (uint16_t i = 0; i < pcmd->vtx_count; i += 3)
  315. {
  316. vec2 pos[3];
  317. pos[0] = vec2(buf[i + 0].pos.x, buf[i + 0].pos.y);
  318. pos[1] = vec2(buf[i + 1].pos.x, buf[i + 1].pos.y);
  319. pos[2] = vec2(buf[i + 2].pos.x, buf[i + 2].pos.y);
  320. vec4 col[3];
  321. col[0] = vec4(Color::FromRGBA32(buf[i + 0].col).arg, 1.f);
  322. col[1] = vec4(Color::FromRGBA32(buf[i + 1].col).arg, 1.f);
  323. col[2] = vec4(Color::FromRGBA32(buf[i + 2].col).arg, 1.f);
  324. Debug::DrawLine((off + vec3(pos[0], 0.f)) / mod, (off + vec3(pos[1], 0.f)) / mod, col[0]);
  325. Debug::DrawLine((off + vec3(pos[1], 0.f)) / mod, (off + vec3(pos[2], 0.f)) / mod, col[1]);
  326. Debug::DrawLine((off + vec3(pos[2], 0.f)) / mod, (off + vec3(pos[0], 0.f)) / mod, col[2]);
  327. }
  328. //-----------------------------------------------------------------
  329. //<\Debug render> -------------------------------------------------
  330. //-----------------------------------------------------------------
  331. #endif //SHOW_IMGUI_DEBUG
  332. memcpy(vert, vtx_buffer + vtx_offset, pcmd->vtx_count * sizeof(Vertex));
  333. vbo->Unlock();
  334. m_font->Bind();
  335. m_vdecl->Bind();
  336. m_vdecl->SetStream(vbo, m_attribs[0], m_attribs[1], m_attribs[2]);
  337. m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, pcmd->vtx_count);
  338. m_vdecl->Unbind();
  339. m_font->Unbind();
  340. vtx_offset += pcmd->vtx_count * sizeof(Vertex);
  341. delete vbo;
  342. }
  343. }
  344. m_shader->Unbind();
  345. }