-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Previous SDL implementation didn't work with my OpenGL 3.3 project, s…
…pliced the GLFW OpenGL examples on top of the SDL example to create an option that works for me. Could be useful for others.
- Loading branch information
Zach Toogood
committed
Sep 30, 2015
1 parent
a76b75c
commit e130b09
Showing
4 changed files
with
509 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
|
||
# How to Build | ||
|
||
Link | ||
=== | ||
OpenGL | ||
SDL2 | ||
GLEW |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,379 @@ | ||
// ImGui SDL2 binding with OpenGL3 | ||
// https://github.com/ocornut/imgui | ||
|
||
#include <SDL.h> | ||
#include <SDL_syswm.h> | ||
#include <GL/glew.h> | ||
#include "imgui.h" | ||
#include "imgui_impl_sdlogl3.h" | ||
|
||
// Data | ||
static SDL_Window* g_Window = NULL; | ||
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_ImplSdlOgl3_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); | ||
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(); | ||
float fb_height = io.DisplaySize.y * io.DisplayFramebufferScale.y; | ||
draw_data->ScaleClipRects(io.DisplayFramebufferScale); | ||
|
||
// Setup orthographic projection matrix | ||
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(g_ShaderHandle); | ||
glUniform1i(g_AttribLocationTex, 0); | ||
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); | ||
glBindVertexArray(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, 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, 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, GL_UNSIGNED_SHORT, idx_buffer_offset); | ||
} | ||
idx_buffer_offset += pcmd->ElemCount; | ||
} | ||
} | ||
|
||
// Restore modified GL state | ||
glUseProgram(last_program); | ||
glBindTexture(GL_TEXTURE_2D, last_texture); | ||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); | ||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer); | ||
glBindVertexArray(last_vertex_array); | ||
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); | ||
} | ||
|
||
static const char* ImGui_ImplSdlOgl3_GetClipboardText() | ||
{ | ||
return SDL_GetClipboardText(); | ||
} | ||
|
||
static void ImGui_ImplSdlOgl3_SetClipboardText(const char* text) | ||
{ | ||
SDL_SetClipboardText(text); | ||
} | ||
|
||
bool ImGui_ImplSdlOgl3_ProcessEvent(SDL_Event* event) | ||
{ | ||
ImGuiIO& io = ImGui::GetIO(); | ||
switch (event->type) | ||
{ | ||
case SDL_MOUSEWHEEL: | ||
{ | ||
if (event->wheel.y > 0) | ||
g_MouseWheel = 1; | ||
if (event->wheel.y < 0) | ||
g_MouseWheel = -1; | ||
return true; | ||
} | ||
case SDL_MOUSEBUTTONDOWN: | ||
{ | ||
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true; | ||
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true; | ||
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true; | ||
return true; | ||
} | ||
case SDL_TEXTINPUT: | ||
{ | ||
ImGuiIO& io = ImGui::GetIO(); | ||
io.AddInputCharactersUTF8(event->text.text); | ||
return true; | ||
} | ||
case SDL_KEYDOWN: | ||
case SDL_KEYUP: | ||
{ | ||
int key = event->key.keysym.sym & ~SDLK_SCANCODE_MASK; | ||
io.KeysDown[key] = (event->type == SDL_KEYDOWN); | ||
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); | ||
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); | ||
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
void ImGui_ImplSdlOgl3_CreateFontsTexture() | ||
{ | ||
ImGuiIO& io = ImGui::GetIO(); | ||
|
||
// Build texture atlas | ||
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. | ||
|
||
// Create OpenGL texture | ||
glGenTextures(1, &g_FontTexture); | ||
glBindTexture(GL_TEXTURE_2D, 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)g_FontTexture; | ||
|
||
// Cleanup (don't clear the input data if you want to append new fonts later) | ||
io.Fonts->ClearInputData(); | ||
io.Fonts->ClearTexData(); | ||
} | ||
|
||
bool ImGui_ImplSdlOgl3_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"; | ||
|
||
g_ShaderHandle = glCreateProgram(); | ||
g_VertHandle = glCreateShader(GL_VERTEX_SHADER); | ||
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); | ||
glShaderSource(g_VertHandle, 1, &vertex_shader, 0); | ||
glShaderSource(g_FragHandle, 1, &fragment_shader, 0); | ||
glCompileShader(g_VertHandle); | ||
glCompileShader(g_FragHandle); | ||
glAttachShader(g_ShaderHandle, g_VertHandle); | ||
glAttachShader(g_ShaderHandle, g_FragHandle); | ||
glLinkProgram(g_ShaderHandle); | ||
|
||
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); | ||
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); | ||
g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position"); | ||
g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV"); | ||
g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color"); | ||
|
||
glGenBuffers(1, &g_VboHandle); | ||
glGenBuffers(1, &g_ElementsHandle); | ||
|
||
glGenVertexArrays(1, &g_VaoHandle); | ||
glBindVertexArray(g_VaoHandle); | ||
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); | ||
glEnableVertexAttribArray(g_AttribLocationPosition); | ||
glEnableVertexAttribArray(g_AttribLocationUV); | ||
glEnableVertexAttribArray(g_AttribLocationColor); | ||
|
||
#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) | ||
glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, pos)); | ||
glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, uv)); | ||
glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)OFFSETOF(ImDrawVert, col)); | ||
#undef OFFSETOF | ||
|
||
ImGui_ImplSdlOgl3_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_ImplSdlOgl3_InvalidateDeviceObjects() | ||
{ | ||
if (g_FontTexture) | ||
{ | ||
glDeleteTextures(1, &g_FontTexture); | ||
ImGui::GetIO().Fonts->TexID = 0; | ||
g_FontTexture = 0; | ||
} | ||
} | ||
|
||
bool ImGui_ImplSdlOgl3_Init(SDL_Window *window) | ||
{ | ||
g_Window = window; | ||
|
||
ImGuiIO& io = ImGui::GetIO(); | ||
io.KeyMap[ImGuiKey_Tab] = SDLK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array. | ||
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; | ||
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; | ||
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP; | ||
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN; | ||
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP; | ||
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN; | ||
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME; | ||
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END; | ||
io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE; | ||
io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE; | ||
io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN; | ||
io.KeyMap[ImGuiKey_Escape] = SDLK_ESCAPE; | ||
io.KeyMap[ImGuiKey_A] = SDLK_a; | ||
io.KeyMap[ImGuiKey_C] = SDLK_c; | ||
io.KeyMap[ImGuiKey_V] = SDLK_v; | ||
io.KeyMap[ImGuiKey_X] = SDLK_x; | ||
io.KeyMap[ImGuiKey_Y] = SDLK_y; | ||
io.KeyMap[ImGuiKey_Z] = SDLK_z; | ||
|
||
io.RenderDrawListsFn = ImGui_ImplSdlOgl3_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. | ||
io.SetClipboardTextFn = ImGui_ImplSdlOgl3_SetClipboardText; | ||
io.GetClipboardTextFn = ImGui_ImplSdlOgl3_GetClipboardText; | ||
|
||
#ifdef _WIN32 | ||
SDL_SysWMinfo wmInfo; | ||
SDL_VERSION(&wmInfo.version); | ||
SDL_GetWindowWMInfo(window, &wmInfo); | ||
io.ImeWindowHandle = wmInfo.info.win.window; | ||
#endif | ||
|
||
return true; | ||
} | ||
|
||
void ImGui_ImplSdlOgl3_Shutdown() | ||
{ | ||
if (g_VaoHandle) glDeleteVertexArrays(1, &g_VaoHandle); | ||
if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle); | ||
if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); | ||
g_VaoHandle = g_VboHandle = g_ElementsHandle = 0; | ||
|
||
glDetachShader(g_ShaderHandle, g_VertHandle); | ||
glDeleteShader(g_VertHandle); | ||
g_VertHandle = 0; | ||
|
||
glDetachShader(g_ShaderHandle, g_FragHandle); | ||
glDeleteShader(g_FragHandle); | ||
g_FragHandle = 0; | ||
|
||
glDeleteProgram(g_ShaderHandle); | ||
g_ShaderHandle = 0; | ||
|
||
if (g_FontTexture) | ||
{ | ||
glDeleteTextures(1, &g_FontTexture); | ||
ImGui::GetIO().Fonts->TexID = 0; | ||
g_FontTexture = 0; | ||
} | ||
ImGui::Shutdown(); | ||
} | ||
|
||
void ImGui_ImplSdlOgl3_NewFrame(SDL_Window *window) | ||
{ | ||
if (!g_FontTexture) | ||
ImGui_ImplSdlOgl3_CreateDeviceObjects(); | ||
|
||
ImGuiIO& io = ImGui::GetIO(); | ||
|
||
// Setup display size (every frame to accommodate for window resizing) | ||
int w, h; | ||
int display_w, display_h; | ||
SDL_GetWindowSize(window, &w, &h); | ||
SDL_GetWindowSize(window, &display_w, &display_h); | ||
io.DisplaySize = ImVec2((float)w, (float)h); | ||
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); | ||
|
||
// Setup time step | ||
Uint32 time = SDL_GetTicks(); | ||
double current_time = time / 1000.0; | ||
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f); | ||
g_Time = current_time; | ||
|
||
// Setup inputs | ||
// (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) | ||
int mx, my; | ||
Uint32 mouseMask = SDL_GetMouseState(&mx, &my); | ||
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_FOCUS) | ||
io.MousePos = ImVec2((float)mx, (float)my); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) | ||
else | ||
io.MousePos = ImVec2(-1, -1); | ||
|
||
io.MouseDown[0] = g_MousePressed[0] || (mouseMask & SDL_BUTTON(SDL_BUTTON_LEFT)) != 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. | ||
io.MouseDown[1] = g_MousePressed[1] || (mouseMask & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; | ||
io.MouseDown[2] = g_MousePressed[2] || (mouseMask & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; | ||
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; | ||
|
||
io.MouseWheel = g_MouseWheel; | ||
g_MouseWheel = 0.0f; | ||
|
||
// Hide OS mouse cursor if ImGui is drawing it | ||
SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1); | ||
|
||
// Start the frame | ||
ImGui::NewFrame(); | ||
} |
Oops, something went wrong.