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.
 
 
 

462 lines
16 KiB

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