diff options
author | rtk0c <[email protected]> | 2021-03-27 23:01:07 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2021-03-27 23:01:07 -0700 |
commit | 442d2d75d71bbc057e667edc301a79fa1cc813be (patch) | |
tree | b5d1e5068a4d481bc6bcd72dca851ac7a85bf7e4 /3rdparty/imgui/backend/imgui_impl_glfw.cpp |
Initial setup
Diffstat (limited to '3rdparty/imgui/backend/imgui_impl_glfw.cpp')
-rw-r--r-- | 3rdparty/imgui/backend/imgui_impl_glfw.cpp | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/3rdparty/imgui/backend/imgui_impl_glfw.cpp b/3rdparty/imgui/backend/imgui_impl_glfw.cpp new file mode 100644 index 0000000..cd0f51d --- /dev/null +++ b/3rdparty/imgui/backend/imgui_impl_glfw.cpp @@ -0,0 +1,374 @@ +// dear imgui: Platform Backend for GLFW +// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..) +// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) +// (Requires: GLFW 3.1+) + +// Implemented features: +// [X] Platform: Clipboard support. +// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). +// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). + +// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. +// Read online: https://github.com/ocornut/imgui/tree/master/docs + +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors. +// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor). +// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown. +// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter. +// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter(). +// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized. +// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. +// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. +// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. +// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. +// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples. +// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()). +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. +// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set. +// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). +// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. +// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. +// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). +// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. + +#include "imgui.h" +#include "imgui_impl_glfw.h" + +// GLFW +#include <GLFW/glfw3.h> +#ifdef _WIN32 +#undef APIENTRY +#define GLFW_EXPOSE_NATIVE_WIN32 +#include <GLFW/glfw3native.h> // for glfwGetWin32Window +#endif +#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING +#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED +#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity +#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale +#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface +#ifdef GLFW_RESIZE_NESW_CURSOR // let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? +#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR +#else +#define GLFW_HAS_NEW_CURSORS (0) +#endif + +// Data +enum GlfwClientApi +{ + GlfwClientApi_Unknown, + GlfwClientApi_OpenGL, + GlfwClientApi_Vulkan +}; +static GLFWwindow* g_Window = NULL; // Main window +static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown; +static double g_Time = 0.0; +static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {}; +static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {}; +static bool g_InstalledCallbacks = false; + +// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. +static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL; +static GLFWscrollfun g_PrevUserCallbackScroll = NULL; +static GLFWkeyfun g_PrevUserCallbackKey = NULL; +static GLFWcharfun g_PrevUserCallbackChar = NULL; + +static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) +{ + return glfwGetClipboardString((GLFWwindow*)user_data); +} + +static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) +{ + glfwSetClipboardString((GLFWwindow*)user_data, text); +} + +void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +{ + if (g_PrevUserCallbackMousebutton != NULL) + g_PrevUserCallbackMousebutton(window, button, action, mods); + + if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed)) + g_MouseJustPressed[button] = true; +} + +void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) +{ + if (g_PrevUserCallbackScroll != NULL) + g_PrevUserCallbackScroll(window, xoffset, yoffset); + + ImGuiIO& io = ImGui::GetIO(); + io.MouseWheelH += (float)xoffset; + io.MouseWheel += (float)yoffset; +} + +void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + if (g_PrevUserCallbackKey != NULL) + g_PrevUserCallbackKey(window, key, scancode, action, mods); + + ImGuiIO& io = ImGui::GetIO(); + if (action == GLFW_PRESS) + io.KeysDown[key] = true; + if (action == GLFW_RELEASE) + io.KeysDown[key] = false; + + // 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]; +#ifdef _WIN32 + io.KeySuper = false; +#else + io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; +#endif +} + +void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) +{ + if (g_PrevUserCallbackChar != NULL) + g_PrevUserCallbackChar(window, c); + + ImGuiIO& io = ImGui::GetIO(); + io.AddInputCharacter(c); +} + +static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) +{ + g_Window = window; + g_Time = 0.0; + + // Setup backend capabilities flags + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = "imgui_impl_glfw"; + + // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array. + io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; + 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_Insert] = GLFW_KEY_INSERT; + io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; + io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; + io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; + io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; + io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; + io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER; + 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.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; + io.ClipboardUserData = g_Window; +#if defined(_WIN32) + io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window); +#endif + + // Create mouse cursors + // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist, + // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting. + // Missing cursors will return NULL and our _UpdateMouseCursor() function will use the Arrow cursor instead.) + GLFWerrorfun prev_error_callback = glfwSetErrorCallback(NULL); + g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); + g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); +#if GLFW_HAS_NEW_CURSORS + g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR); + g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR); +#else + g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); + g_MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); +#endif + glfwSetErrorCallback(prev_error_callback); + + // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. + g_PrevUserCallbackMousebutton = NULL; + g_PrevUserCallbackScroll = NULL; + g_PrevUserCallbackKey = NULL; + g_PrevUserCallbackChar = NULL; + if (install_callbacks) + { + g_InstalledCallbacks = true; + g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); + g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); + g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); + g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); + } + + g_ClientApi = client_api; + return true; +} + +bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL); +} + +bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); +} + +bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks) +{ + return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown); +} + +void ImGui_ImplGlfw_Shutdown() +{ + if (g_InstalledCallbacks) + { + glfwSetMouseButtonCallback(g_Window, g_PrevUserCallbackMousebutton); + glfwSetScrollCallback(g_Window, g_PrevUserCallbackScroll); + glfwSetKeyCallback(g_Window, g_PrevUserCallbackKey); + glfwSetCharCallback(g_Window, g_PrevUserCallbackChar); + g_InstalledCallbacks = false; + } + + for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) + { + glfwDestroyCursor(g_MouseCursors[cursor_n]); + g_MouseCursors[cursor_n] = NULL; + } + g_ClientApi = GlfwClientApi_Unknown; +} + +static void ImGui_ImplGlfw_UpdateMousePosAndButtons() +{ + // Update buttons + ImGuiIO& io = ImGui::GetIO(); + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + // 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[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; + g_MouseJustPressed[i] = false; + } + + // Update mouse position + const ImVec2 mouse_pos_backup = io.MousePos; + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); +#ifdef __EMSCRIPTEN__ + const bool focused = true; // Emscripten +#else + const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0; +#endif + if (focused) + { + if (io.WantSetMousePos) + { + glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y); + } + else + { + double mouse_x, mouse_y; + glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); + } + } +} + +static void ImGui_ImplGlfw_UpdateMouseCursor() +{ + ImGuiIO& io = ImGui::GetIO(); + if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) + return; + + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) + { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + } + else + { + // Show OS mouse cursor + // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. + glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } +} + +static void ImGui_ImplGlfw_UpdateGamepads() +{ + ImGuiIO& io = ImGui::GetIO(); + memset(io.NavInputs, 0, sizeof(io.NavInputs)); + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; + + // Update gamepad inputs + #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } + #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } + int axes_count = 0, buttons_count = 0; + const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); + const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); + MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A + MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B + MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X + MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y + MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left + MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right + MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up + MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down + MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB + MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB + MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB + MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB + MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f); + MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f); + MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f); + MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f); + #undef MAP_BUTTON + #undef MAP_ANALOG + if (axes_count > 0 && buttons_count > 0) + io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + else + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; +} + +void ImGui_ImplGlfw_NewFrame() +{ + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); + + // Setup display size (every frame to accommodate for window resizing) + int w, h; + int display_w, display_h; + glfwGetWindowSize(g_Window, &w, &h); + glfwGetFramebufferSize(g_Window, &display_w, &display_h); + io.DisplaySize = ImVec2((float)w, (float)h); + if (w > 0 && h > 0) + io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + + // Setup time step + double current_time = glfwGetTime(); + io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f); + g_Time = current_time; + + ImGui_ImplGlfw_UpdateMousePosAndButtons(); + ImGui_ImplGlfw_UpdateMouseCursor(); + + // Update game controllers (if enabled and available) + ImGui_ImplGlfw_UpdateGamepads(); +} |