diff --git a/CMakeLists.txt b/CMakeLists.txt index d9f5838..4963698 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ file(GLOB LIB_HEAD_LIST src/*.h) #set compilation option set(IS_LIBRARY True) +set(USE_IMGUI True) set(USE_OPENGL True) add_definitions(-Wno-comment) diff --git a/src/deferredpipeline.cpp b/src/deferredpipeline.cpp index fe6fb93..def2e82 100644 --- a/src/deferredpipeline.cpp +++ b/src/deferredpipeline.cpp @@ -8,6 +8,7 @@ #include "shadersource.h" #include "phongmaterial.h" #include "camera.h" +#include "guimesh.h" #include #include @@ -94,6 +95,8 @@ DeferredPipeline::DeferredPipeline() : std::string vertSource = shaderMap["shaders/posteffects.vert.glsl"]; std::string fragSource = shaderMap["shaders/posteffects.frag.glsl"]; m_postEffectsShader = new Shader(vertSource, fragSource); + m_guiMesh = new GuiMesh(); + m_guiMesh->initGL(); } bool depthCompare(const GeometryNode* firstElem, const GeometryNode* secondElem) { @@ -214,6 +217,9 @@ void DeferredPipeline::renderGL(Scene *scene) // draw geometry node->mesh->draw(shader); } + + // IMGUI PASS + gui.drawGL(); } void DeferredPipeline::resizeGL(int w, int h) @@ -231,6 +237,7 @@ void DeferredPipeline::resizeGL(int w, int h) m_gBuffer = new GBuffer(w, h); m_lightingBuffer = new LightingBuffer(w, h); m_orthoMatrix = glm::ortho(0.f, float(m_width), float(m_height), 0.f); + m_guiMesh->resizeGL(w, h); } void DeferredPipeline::setSources(ShaderSource *gBufferSource, ShaderSource *lightingSource, ShaderSource *guiSource, Shader *postEffectsShader) diff --git a/src/deferredpipeline.h b/src/deferredpipeline.h index c252412..e2fb307 100644 --- a/src/deferredpipeline.h +++ b/src/deferredpipeline.h @@ -8,6 +8,7 @@ class Shader; class Camera; +class GuiMesh; class GBuffer : public FrameBuffer { @@ -45,7 +46,9 @@ class DeferredPipeline : public Pipeline ShaderSource *m_lightingSource; ShaderSource *m_mesh2DSource; Shader *m_postEffectsShader; // TODELETE - + + GuiMesh * m_guiMesh; + // framebuffers GBuffer *m_gBuffer; LightingBuffer *m_lightingBuffer; diff --git a/src/guimesh.cpp b/src/guimesh.cpp new file mode 100644 index 0000000..d865bd9 --- /dev/null +++ b/src/guimesh.cpp @@ -0,0 +1,184 @@ +#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: alpha-blending enabled, no face culling, no depth testing, scissor enabled + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + 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_BLEND); + glEnable(GL_DEPTH_TEST); + 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; + } +} diff --git a/src/guimesh.h b/src/guimesh.h new file mode 100644 index 0000000..19ec408 --- /dev/null +++ b/src/guimesh.h @@ -0,0 +1,26 @@ +#ifndef GUIMESH_H +#define GUIMESH_H + +class GuiMesh +{ + int ShaderHandle = 0; + int VertHandle = 0; + int FragHandle = 0; + int AttribLocationTex = 0; + int AttribLocationProjMtx = 0; + unsigned int VboHandle = 0; + unsigned int VaoHandle = 0; + unsigned int ElementsHandle = 0; + unsigned int FontTexture = 0; + + unsigned int width; + unsigned int height; + +public: + void initGL(); + void drawGL(); + void resizeGL(int w, int h); + void destroyGL(); +}; + +#endif // GUIMESH_H