Created
September 13, 2018 19:14
-
-
Save chuwilliamson/e9f2e7f1a624544342ab8bf11e25b5c7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ImGui GLFW binding with OpenGL3 + shaders | |
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. | |
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). | |
// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. | |
// https://github.com/ocornut/imgui | |
#include <imgui.h> | |
#include "imgui_impl_glfw_gl3.h" | |
// GL_CORE/GLFW | |
#include "gl_core_4_4.h" | |
#include <GLFW\glfw3.h> | |
#ifdef _WIN32 | |
#undef APIENTRY | |
#define GLFW_EXPOSE_NATIVE_WIN32 | |
#define GLFW_EXPOSE_NATIVE_WGL | |
#include <GLFW\glfw3native.h> | |
#endif | |
// Data | |
namespace imgui_impl { | |
static GLFWwindow* g_Window = nullptr; | |
static double g_Time = 0.0f; | |
static bool g_MousePressed[3] = { false, false, false }; | |
static float g_MouseWheel = 0.0f; | |
static GLuint g_FontTexture = 0; | |
static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; | |
static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; | |
static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0; | |
static unsigned int g_VboHandle = 0, g_VaoHandle = 0, g_ElementsHandle = 0; | |
} | |
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) | |
// If text or lines are blurry when integrating ImGui in your engine: | |
// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) | |
void ImGui_ImplGlfwGL3_RenderDrawLists(ImDrawData* draw_data) | |
{ | |
// Backup GL state | |
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); | |
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | |
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); | |
GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer); | |
GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); | |
GLint last_blend_src; glGetIntegerv(GL_BLEND_SRC, &last_blend_src); | |
GLint last_blend_dst; glGetIntegerv(GL_BLEND_DST, &last_blend_dst); | |
GLint last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, &last_blend_equation_rgb); | |
GLint last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &last_blend_equation_alpha); | |
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); | |
GLboolean last_enable_blend = glIsEnabled(GL_BLEND); | |
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); | |
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); | |
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); | |
// 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); | |
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) | |
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 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(imgui_impl::g_ShaderHandle); | |
glUniform1i(imgui_impl::g_AttribLocationTex, 0); | |
glUniformMatrix4fv(imgui_impl::g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); | |
glBindVertexArray(imgui_impl::g_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, imgui_impl::g_VboHandle); | |
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.size() * sizeof(ImDrawVert), (GLvoid*)&cmd_list->VtxBuffer.front(), GL_STREAM_DRAW); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, imgui_impl::g_ElementsHandle); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.size() * sizeof(ImDrawIdx), (GLvoid*)&cmd_list->IdxBuffer.front(), GL_STREAM_DRAW); | |
for (const ImDrawCmd* pcmd = cmd_list->CmdBuffer.begin(); pcmd != cmd_list->CmdBuffer.end(); pcmd++) | |
{ | |
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; | |
} | |
} | |
// Restore modified GL state | |
glUseProgram(last_program); | |
glBindTexture(GL_TEXTURE_2D, last_texture); | |
glBindVertexArray(last_vertex_array); | |
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer); | |
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); | |
glBlendFunc(last_blend_src, last_blend_dst); | |
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); | |
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); | |
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); | |
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); | |
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); | |
} | |
static const char* ImGui_ImplGlfwGL3_GetClipboardText() | |
{ | |
return glfwGetClipboardString(imgui_impl::g_Window); | |
} | |
static void ImGui_ImplGlfwGL3_SetClipboardText(const char* text) | |
{ | |
glfwSetClipboardString(imgui_impl::g_Window, text); | |
} | |
void ImGui_ImplGlfwGL3_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/) | |
{ | |
if (action == GLFW_PRESS && button >= 0 && button < 3) | |
imgui_impl::g_MousePressed[button] = true; | |
} | |
void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffset) | |
{ | |
imgui_impl::g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines. | |
} | |
void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow*, int key, int, int action, int mods) | |
{ | |
ImGuiIO& io = ImGui::GetIO(); | |
if (action == GLFW_PRESS) | |
io.KeysDown[key] = true; | |
if (action == GLFW_RELEASE) | |
io.KeysDown[key] = false; | |
(void)mods; // Modifiers are not reliable across systems | |
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; | |
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; | |
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; | |
} | |
void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow*, unsigned int c) | |
{ | |
ImGuiIO& io = ImGui::GetIO(); | |
if (c > 0 && c < 0x10000) | |
io.AddInputCharacter((unsigned short)c); | |
} | |
bool ImGui_ImplGlfwGL3_CreateFontsTexture() | |
{ | |
// Build texture atlas | |
ImGuiIO& io = ImGui::GetIO(); | |
unsigned char* pixels; | |
int width, height; | |
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits for OpenGL3 demo because it is more likely to be compatible with user's existing shader. | |
// Upload texture to graphics system | |
GLint last_texture; | |
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | |
glGenTextures(1, &imgui_impl::g_FontTexture); | |
glBindTexture(GL_TEXTURE_2D, imgui_impl::g_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)imgui_impl::g_FontTexture; | |
// Restore state | |
glBindTexture(GL_TEXTURE_2D, last_texture); | |
return true; | |
} | |
bool ImGui_ImplGlfwGL3_CreateDeviceObjects() | |
{ | |
// Backup GL state | |
GLint last_texture, last_array_buffer, last_vertex_array; | |
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); | |
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); | |
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); | |
const GLchar *vertex_shader = | |
"#version 330\n" | |
"uniform mat4 ProjMtx;\n" | |
"in vec2 Position;\n" | |
"in vec2 UV;\n" | |
"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"; | |
imgui_impl::g_ShaderHandle = glCreateProgram(); | |
imgui_impl::g_VertHandle = glCreateShader(GL_VERTEX_SHADER); | |
imgui_impl::g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); | |
glShaderSource(imgui_impl::g_VertHandle, 1, &vertex_shader, 0); | |
glShaderSource(imgui_impl::g_FragHandle, 1, &fragment_shader, 0); | |
glCompileShader(imgui_impl::g_VertHandle); | |
glCompileShader(imgui_impl::g_FragHandle); | |
glAttachShader(imgui_impl::g_ShaderHandle, imgui_impl::g_VertHandle); | |
glAttachShader(imgui_impl::g_ShaderHandle, imgui_impl::g_FragHandle); | |
glLinkProgram(imgui_impl::g_ShaderHandle); | |
imgui_impl::g_AttribLocationTex = glGetUniformLocation(imgui_impl::g_ShaderHandle, "Texture"); | |
imgui_impl::g_AttribLocationProjMtx = glGetUniformLocation(imgui_impl::g_ShaderHandle, "ProjMtx"); | |
imgui_impl::g_AttribLocationPosition = glGetAttribLocation(imgui_impl::g_ShaderHandle, "Position"); | |
imgui_impl::g_AttribLocationUV = glGetAttribLocation(imgui_impl::g_ShaderHandle, "UV"); | |
imgui_impl::g_AttribLocationColor = glGetAttribLocation(imgui_impl::g_ShaderHandle, "Color"); | |
glGenBuffers(1, &imgui_impl::g_VboHandle); | |
glGenBuffers(1, &imgui_impl::g_ElementsHandle); | |
glGenVertexArrays(1, &imgui_impl::g_VaoHandle); | |
glBindVertexArray(imgui_impl::g_VaoHandle); | |
glBindBuffer(GL_ARRAY_BUFFER, imgui_impl::g_VboHandle); | |
glEnableVertexAttribArray(imgui_impl::g_AttribLocationPosition); | |
glEnableVertexAttribArray(imgui_impl::g_AttribLocationUV); | |
glEnableVertexAttribArray(imgui_impl::g_AttribLocationColor); | |
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) | |
glVertexAttribPointer(imgui_impl::g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos)); | |
glVertexAttribPointer(imgui_impl::g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv)); | |
glVertexAttribPointer(imgui_impl::g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); | |
#undef OFFSETOF | |
ImGui_ImplGlfwGL3_CreateFontsTexture(); | |
// Restore modified GL state | |
glBindTexture(GL_TEXTURE_2D, last_texture); | |
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); | |
glBindVertexArray(last_vertex_array); | |
return true; | |
} | |
void ImGui_ImplGlfwGL3_InvalidateDeviceObjects() | |
{ | |
if (imgui_impl::g_VaoHandle) glDeleteVertexArrays(1, &imgui_impl::g_VaoHandle); | |
if (imgui_impl::g_VboHandle) glDeleteBuffers(1, &imgui_impl::g_VboHandle); | |
if (imgui_impl::g_ElementsHandle) glDeleteBuffers(1, &imgui_impl::g_ElementsHandle); | |
imgui_impl::g_VaoHandle = imgui_impl::g_VboHandle = imgui_impl::g_ElementsHandle = 0; | |
glDetachShader(imgui_impl::g_ShaderHandle, imgui_impl::g_VertHandle); | |
glDeleteShader(imgui_impl::g_VertHandle); | |
imgui_impl::g_VertHandle = 0; | |
glDetachShader(imgui_impl::g_ShaderHandle, imgui_impl::g_FragHandle); | |
glDeleteShader(imgui_impl::g_FragHandle); | |
imgui_impl::g_FragHandle = 0; | |
glDeleteProgram(imgui_impl::g_ShaderHandle); | |
imgui_impl::g_ShaderHandle = 0; | |
if (imgui_impl::g_FontTexture) | |
{ | |
glDeleteTextures(1, &imgui_impl::g_FontTexture); | |
ImGui::GetIO().Fonts->TexID = 0; | |
imgui_impl::g_FontTexture = 0; | |
} | |
} | |
bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) | |
{ | |
imgui_impl::g_Window = window; | |
ImGuiIO& io = ImGui::GetIO(); | |
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. | |
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; | |
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; | |
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; | |
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; | |
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; | |
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; | |
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; | |
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; | |
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; | |
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; | |
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; | |
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; | |
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; | |
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; | |
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; | |
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; | |
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; | |
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; | |
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; | |
io.RenderDrawListsFn = ImGui_ImplGlfwGL3_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. | |
io.SetClipboardTextFn = ImGui_ImplGlfwGL3_SetClipboardText; | |
io.GetClipboardTextFn = ImGui_ImplGlfwGL3_GetClipboardText; | |
#ifdef _WIN32 | |
io.ImeWindowHandle = glfwGetWin32Window(imgui_impl::g_Window); | |
#endif | |
if (install_callbacks) | |
{ | |
glfwSetMouseButtonCallback(window, ImGui_ImplGlfwGL3_MouseButtonCallback); | |
glfwSetScrollCallback(window, ImGui_ImplGlfwGL3_ScrollCallback); | |
glfwSetKeyCallback(window, ImGui_ImplGlfwGL3_KeyCallback); | |
glfwSetCharCallback(window, ImGui_ImplGlfwGL3_CharCallback); | |
} | |
return true; | |
} | |
void ImGui_ImplGlfwGL3_Shutdown() | |
{ | |
ImGui_ImplGlfwGL3_InvalidateDeviceObjects(); | |
ImGui::Shutdown(); | |
} | |
void ImGui_ImplGlfwGL3_NewFrame() | |
{ | |
if (!imgui_impl::g_FontTexture) | |
ImGui_ImplGlfwGL3_CreateDeviceObjects(); | |
ImGuiIO& io = ImGui::GetIO(); | |
// Setup display size (every frame to accommodate for window resizing) | |
int w, h; | |
int display_w, display_h; | |
glfwGetWindowSize(imgui_impl::g_Window, &w, &h); | |
glfwGetFramebufferSize(imgui_impl::g_Window, &display_w, &display_h); | |
io.DisplaySize = ImVec2((float)w, (float)h); | |
io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); | |
// Setup time step | |
double current_time = glfwGetTime(); | |
io.DeltaTime = imgui_impl::g_Time > 0.0 ? (float)(current_time - imgui_impl::g_Time) : (float)(1.0f/60.0f); | |
imgui_impl::g_Time = current_time; | |
// Setup inputs | |
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) | |
if (glfwGetWindowAttrib(imgui_impl::g_Window, GLFW_FOCUSED)) | |
{ | |
double mouse_x, mouse_y; | |
glfwGetCursorPos(imgui_impl::g_Window, &mouse_x, &mouse_y); | |
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.) | |
} | |
else | |
{ | |
io.MousePos = ImVec2(-1,-1); | |
} | |
for (int i = 0; i < 3; i++) | |
{ | |
io.MouseDown[i] = imgui_impl::g_MousePressed[i] || glfwGetMouseButton(imgui_impl::g_Window, i) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. | |
imgui_impl::g_MousePressed[i] = false; | |
} | |
io.MouseWheel = imgui_impl::g_MouseWheel; | |
imgui_impl::g_MouseWheel = 0.0f; | |
// Hide OS mouse cursor if ImGui is drawing it | |
glfwSetInputMode(imgui_impl::g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); | |
// Start the frame | |
ImGui::NewFrame(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment