#include "guimesh.h" #include "opengl.h" #include "imgui/imgui.h" void GuiMesh::initGL() { const GLchar *vertex_shader = "#version 330\n" "uniform mat4 ProjMtx;\n" "layout(location = 0)in vec2 Position;\n" "layout(location = 1)in vec2 UV;\n" "layout(location = 2)in vec4 Color;\n" "out vec2 Frag_UV;\n" "out vec4 Frag_Color;\n" "void main()\n" "{\n" " Frag_UV = UV;\n" " Frag_Color = Color;\n" " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" "}\n"; const GLchar* fragment_shader = "#version 330\n" "uniform sampler2D Texture;\n" "in vec2 Frag_UV;\n" "in vec4 Frag_Color;\n" "out vec4 Out_Color;\n" "void main()\n" "{\n" " Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n" "}\n"; ShaderHandle = glCreateProgram(); VertHandle = glCreateShader(GL_VERTEX_SHADER); FragHandle = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(VertHandle, 1, &vertex_shader, 0); glShaderSource(FragHandle, 1, &fragment_shader, 0); glCompileShader(VertHandle); glCompileShader(FragHandle); glAttachShader(ShaderHandle, VertHandle); glAttachShader(ShaderHandle, FragHandle); glLinkProgram(ShaderHandle); AttribLocationTex = glGetUniformLocation(ShaderHandle, "Texture"); AttribLocationProjMtx = glGetUniformLocation(ShaderHandle, "ProjMtx"); glGenBuffers(1, &VboHandle); glGenBuffers(1, &ElementsHandle); glGenVertexArrays(1, &VaoHandle); glBindVertexArray(VaoHandle); glBindBuffer(GL_ARRAY_BUFFER, VboHandle); #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos)); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv)); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); #undef OFFSETOF // Build texture atlas ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. // Upload texture to graphics system glGenTextures(1, &FontTexture); glBindTexture(GL_TEXTURE_2D, FontTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Store our identifier io.Fonts->TexID = (void *)(intptr_t)FontTexture; } void GuiMesh::drawGL() { ImGui::Render(); ImDrawData* draw_data = ImGui::GetDrawData(); ImGuiIO& io = ImGui::GetIO(); int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x); int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y); if (fb_width == 0 || fb_height == 0) return; draw_data->ScaleClipRects(io.DisplayFramebufferScale); // Setup render state: scissor enabled glEnable(GL_SCISSOR_TEST); glActiveTexture(GL_TEXTURE0); // Setup viewport, orthographic projection matrix glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); const float ortho_projection[4][4] = { { 2.0f/io.DisplaySize.x, 0.0f, 0.0f, 0.0f }, { 0.0f, 2.0f/-io.DisplaySize.y, 0.0f, 0.0f }, { 0.0f, 0.0f, -1.0f, 0.0f }, {-1.0f, 1.0f, 0.0f, 1.0f }, }; glUseProgram(ShaderHandle); glUniform1i(AttribLocationTex, 0); glUniformMatrix4fv(AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); glBindVertexArray(VaoHandle); for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawIdx* idx_buffer_offset = 0; glBindBuffer(GL_ARRAY_BUFFER, VboHandle); glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementsHandle); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); } else { glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y)); glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset); } idx_buffer_offset += pcmd->ElemCount; } } glDisable(GL_SCISSOR_TEST); } void GuiMesh::resizeGL(int w, int h) { ImGuiIO& io = ImGui::GetIO(); width = w; height = h; io.DisplaySize = ImVec2(w, h); } void GuiMesh::destroyGL() { if (VaoHandle) glDeleteVertexArrays(1, &VaoHandle); if (VboHandle) glDeleteBuffers(1, &VboHandle); if (ElementsHandle) glDeleteBuffers(1, &ElementsHandle); VaoHandle = VboHandle = ElementsHandle = 0; if (ShaderHandle && VertHandle) glDetachShader(ShaderHandle, VertHandle); if (VertHandle) glDeleteShader(VertHandle); VertHandle = 0; if (ShaderHandle && FragHandle) glDetachShader(ShaderHandle, FragHandle); if (FragHandle) glDeleteShader(FragHandle); FragHandle = 0; if (ShaderHandle) glDeleteProgram(ShaderHandle); ShaderHandle = 0; if (FontTexture) { glDeleteTextures(1, &FontTexture); ImGui::GetIO().Fonts->TexID = 0; FontTexture = 0; } }