aboutsummaryrefslogtreecommitdiffstats
path: root/third_party/imgui/backends
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/imgui/backends')
-rw-r--r--third_party/imgui/backends/imgui_impl_sdl3.cpp770
-rw-r--r--third_party/imgui/backends/imgui_impl_sdl3.h47
-rw-r--r--third_party/imgui/backends/imgui_impl_sdlrenderer3.cpp294
-rw-r--r--third_party/imgui/backends/imgui_impl_sdlrenderer3.h51
4 files changed, 1162 insertions, 0 deletions
diff --git a/third_party/imgui/backends/imgui_impl_sdl3.cpp b/third_party/imgui/backends/imgui_impl_sdl3.cpp
new file mode 100644
index 0000000..3cd56a7
--- /dev/null
+++ b/third_party/imgui/backends/imgui_impl_sdl3.cpp
@@ -0,0 +1,770 @@
+// dear imgui: Platform Backend for SDL3 (*EXPERIMENTAL*)
+// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
+// (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
+
+// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**)
+
+// Implemented features:
+// [X] Platform: Clipboard support.
+// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
+// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
+// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten.
+// 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807)
+// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
+// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
+// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
+// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn
+// 2024-08-19: Storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*.
+// 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853)
+// 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807)
+// 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801)
+// 2024-07-15: Update for SDL3 api changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794)
+// 2024-07-02: Update for SDL3 api changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762).
+// 2024-07-01: Update for SDL3 api changes: SDL_SetTextInputRect() changed to SDL_SetTextInputArea().
+// 2024-06-26: Update for SDL3 api changes: SDL_StartTextInput()/SDL_StopTextInput()/SDL_SetTextInputRect() functions signatures.
+// 2024-06-24: Update for SDL3 api changes: SDL_EVENT_KEY_DOWN/SDL_EVENT_KEY_UP contents.
+// 2024-06-03; Update for SDL3 api changes: SDL_SYSTEM_CURSOR_ renames.
+// 2024-05-15: Update for SDL3 api changes: SDLK_ renames.
+// 2024-04-15: Inputs: Re-enable calling SDL_StartTextInput()/SDL_StopTextInput() as SDL3 no longer enables it by default and should play nicer with IME.
+// 2024-02-13: Inputs: Fixed gamepad support. Handle gamepad disconnection. Added ImGui_ImplSDL3_SetGamepadMode().
+// 2023-11-13: Updated for recent SDL3 API changes.
+// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
+// 2023-05-04: Fixed build on Emscripten/iOS/Android. (#6391)
+// 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306)
+// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702)
+// 2023-02-23: Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. (#6189, #6114, #3644)
+// 2023-02-07: Forked "imgui_impl_sdl2" into "imgui_impl_sdl3". Removed version checks for old feature. Refer to imgui_impl_sdl2.cpp for older changelog.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_sdl3.h"
+
+// Clang warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
+#endif
+
+// SDL
+#include <SDL3/SDL.h>
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
+#endif
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+
+#if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
+#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
+#else
+#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
+#endif
+
+// FIXME-LEGACY: remove when SDL 3.1.3 preview is released.
+#ifndef SDLK_APOSTROPHE
+#define SDLK_APOSTROPHE SDLK_QUOTE
+#endif
+#ifndef SDLK_GRAVE
+#define SDLK_GRAVE SDLK_BACKQUOTE
+#endif
+
+// SDL Data
+struct ImGui_ImplSDL3_Data
+{
+ SDL_Window* Window;
+ SDL_WindowID WindowID;
+ SDL_Renderer* Renderer;
+ Uint64 Time;
+ char* ClipboardTextData;
+
+ // IME handling
+ SDL_Window* ImeWindow;
+
+ // Mouse handling
+ Uint32 MouseWindowID;
+ int MouseButtonsDown;
+ SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
+ SDL_Cursor* MouseLastCursor;
+ int MousePendingLeaveFrame;
+ bool MouseCanUseGlobalState;
+
+ // Gamepad handling
+ ImVector<SDL_Gamepad*> Gamepads;
+ ImGui_ImplSDL3_GamepadMode GamepadMode;
+ bool WantUpdateGamepadsList;
+
+ ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
+// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
+static ImGui_ImplSDL3_Data* ImGui_ImplSDL3_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplSDL3_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
+}
+
+// Functions
+static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*)
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ if (bd->ClipboardTextData)
+ SDL_free(bd->ClipboardTextData);
+ const char* sdl_clipboard_text = SDL_GetClipboardText();
+ bd->ClipboardTextData = sdl_clipboard_text ? SDL_strdup(sdl_clipboard_text) : NULL;
+ return bd->ClipboardTextData;
+}
+
+static void ImGui_ImplSDL3_SetClipboardText(ImGuiContext*, const char* text)
+{
+ SDL_SetClipboardText(text);
+}
+
+static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data)
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle;
+ SDL_Window* window = SDL_GetWindowFromID(window_id);
+ if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != NULL)
+ {
+ SDL_StopTextInput(bd->ImeWindow);
+ bd->ImeWindow = nullptr;
+ }
+ if (data->WantVisible)
+ {
+ SDL_Rect r;
+ r.x = (int)data->InputPos.x;
+ r.y = (int)data->InputPos.y;
+ r.w = 1;
+ r.h = (int)data->InputLineHeight;
+ SDL_SetTextInputArea(window, &r, 0);
+ SDL_StartTextInput(window);
+ bd->ImeWindow = window;
+ }
+}
+
+// Not static to allow third-party code to use that if they want to (but undocumented)
+ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode);
+ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode)
+{
+ // Keypad doesn't have individual key values in SDL3
+ switch (scancode)
+ {
+ case SDL_SCANCODE_KP_0: return ImGuiKey_Keypad0;
+ case SDL_SCANCODE_KP_1: return ImGuiKey_Keypad1;
+ case SDL_SCANCODE_KP_2: return ImGuiKey_Keypad2;
+ case SDL_SCANCODE_KP_3: return ImGuiKey_Keypad3;
+ case SDL_SCANCODE_KP_4: return ImGuiKey_Keypad4;
+ case SDL_SCANCODE_KP_5: return ImGuiKey_Keypad5;
+ case SDL_SCANCODE_KP_6: return ImGuiKey_Keypad6;
+ case SDL_SCANCODE_KP_7: return ImGuiKey_Keypad7;
+ case SDL_SCANCODE_KP_8: return ImGuiKey_Keypad8;
+ case SDL_SCANCODE_KP_9: return ImGuiKey_Keypad9;
+ case SDL_SCANCODE_KP_PERIOD: return ImGuiKey_KeypadDecimal;
+ case SDL_SCANCODE_KP_DIVIDE: return ImGuiKey_KeypadDivide;
+ case SDL_SCANCODE_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
+ case SDL_SCANCODE_KP_MINUS: return ImGuiKey_KeypadSubtract;
+ case SDL_SCANCODE_KP_PLUS: return ImGuiKey_KeypadAdd;
+ case SDL_SCANCODE_KP_ENTER: return ImGuiKey_KeypadEnter;
+ case SDL_SCANCODE_KP_EQUALS: return ImGuiKey_KeypadEqual;
+ default: break;
+ }
+ switch (keycode)
+ {
+ case SDLK_TAB: return ImGuiKey_Tab;
+ case SDLK_LEFT: return ImGuiKey_LeftArrow;
+ case SDLK_RIGHT: return ImGuiKey_RightArrow;
+ case SDLK_UP: return ImGuiKey_UpArrow;
+ case SDLK_DOWN: return ImGuiKey_DownArrow;
+ case SDLK_PAGEUP: return ImGuiKey_PageUp;
+ case SDLK_PAGEDOWN: return ImGuiKey_PageDown;
+ case SDLK_HOME: return ImGuiKey_Home;
+ case SDLK_END: return ImGuiKey_End;
+ case SDLK_INSERT: return ImGuiKey_Insert;
+ case SDLK_DELETE: return ImGuiKey_Delete;
+ case SDLK_BACKSPACE: return ImGuiKey_Backspace;
+ case SDLK_SPACE: return ImGuiKey_Space;
+ case SDLK_RETURN: return ImGuiKey_Enter;
+ case SDLK_ESCAPE: return ImGuiKey_Escape;
+ case SDLK_APOSTROPHE: return ImGuiKey_Apostrophe;
+ case SDLK_COMMA: return ImGuiKey_Comma;
+ case SDLK_MINUS: return ImGuiKey_Minus;
+ case SDLK_PERIOD: return ImGuiKey_Period;
+ case SDLK_SLASH: return ImGuiKey_Slash;
+ case SDLK_SEMICOLON: return ImGuiKey_Semicolon;
+ case SDLK_EQUALS: return ImGuiKey_Equal;
+ case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket;
+ case SDLK_BACKSLASH: return ImGuiKey_Backslash;
+ case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket;
+ case SDLK_GRAVE: return ImGuiKey_GraveAccent;
+ case SDLK_CAPSLOCK: return ImGuiKey_CapsLock;
+ case SDLK_SCROLLLOCK: return ImGuiKey_ScrollLock;
+ case SDLK_NUMLOCKCLEAR: return ImGuiKey_NumLock;
+ case SDLK_PRINTSCREEN: return ImGuiKey_PrintScreen;
+ case SDLK_PAUSE: return ImGuiKey_Pause;
+ case SDLK_LCTRL: return ImGuiKey_LeftCtrl;
+ case SDLK_LSHIFT: return ImGuiKey_LeftShift;
+ case SDLK_LALT: return ImGuiKey_LeftAlt;
+ case SDLK_LGUI: return ImGuiKey_LeftSuper;
+ case SDLK_RCTRL: return ImGuiKey_RightCtrl;
+ case SDLK_RSHIFT: return ImGuiKey_RightShift;
+ case SDLK_RALT: return ImGuiKey_RightAlt;
+ case SDLK_RGUI: return ImGuiKey_RightSuper;
+ case SDLK_APPLICATION: return ImGuiKey_Menu;
+ case SDLK_0: return ImGuiKey_0;
+ case SDLK_1: return ImGuiKey_1;
+ case SDLK_2: return ImGuiKey_2;
+ case SDLK_3: return ImGuiKey_3;
+ case SDLK_4: return ImGuiKey_4;
+ case SDLK_5: return ImGuiKey_5;
+ case SDLK_6: return ImGuiKey_6;
+ case SDLK_7: return ImGuiKey_7;
+ case SDLK_8: return ImGuiKey_8;
+ case SDLK_9: return ImGuiKey_9;
+ case SDLK_A: return ImGuiKey_A;
+ case SDLK_B: return ImGuiKey_B;
+ case SDLK_C: return ImGuiKey_C;
+ case SDLK_D: return ImGuiKey_D;
+ case SDLK_E: return ImGuiKey_E;
+ case SDLK_F: return ImGuiKey_F;
+ case SDLK_G: return ImGuiKey_G;
+ case SDLK_H: return ImGuiKey_H;
+ case SDLK_I: return ImGuiKey_I;
+ case SDLK_J: return ImGuiKey_J;
+ case SDLK_K: return ImGuiKey_K;
+ case SDLK_L: return ImGuiKey_L;
+ case SDLK_M: return ImGuiKey_M;
+ case SDLK_N: return ImGuiKey_N;
+ case SDLK_O: return ImGuiKey_O;
+ case SDLK_P: return ImGuiKey_P;
+ case SDLK_Q: return ImGuiKey_Q;
+ case SDLK_R: return ImGuiKey_R;
+ case SDLK_S: return ImGuiKey_S;
+ case SDLK_T: return ImGuiKey_T;
+ case SDLK_U: return ImGuiKey_U;
+ case SDLK_V: return ImGuiKey_V;
+ case SDLK_W: return ImGuiKey_W;
+ case SDLK_X: return ImGuiKey_X;
+ case SDLK_Y: return ImGuiKey_Y;
+ case SDLK_Z: return ImGuiKey_Z;
+ case SDLK_F1: return ImGuiKey_F1;
+ case SDLK_F2: return ImGuiKey_F2;
+ case SDLK_F3: return ImGuiKey_F3;
+ case SDLK_F4: return ImGuiKey_F4;
+ case SDLK_F5: return ImGuiKey_F5;
+ case SDLK_F6: return ImGuiKey_F6;
+ case SDLK_F7: return ImGuiKey_F7;
+ case SDLK_F8: return ImGuiKey_F8;
+ case SDLK_F9: return ImGuiKey_F9;
+ case SDLK_F10: return ImGuiKey_F10;
+ case SDLK_F11: return ImGuiKey_F11;
+ case SDLK_F12: return ImGuiKey_F12;
+ case SDLK_F13: return ImGuiKey_F13;
+ case SDLK_F14: return ImGuiKey_F14;
+ case SDLK_F15: return ImGuiKey_F15;
+ case SDLK_F16: return ImGuiKey_F16;
+ case SDLK_F17: return ImGuiKey_F17;
+ case SDLK_F18: return ImGuiKey_F18;
+ case SDLK_F19: return ImGuiKey_F19;
+ case SDLK_F20: return ImGuiKey_F20;
+ case SDLK_F21: return ImGuiKey_F21;
+ case SDLK_F22: return ImGuiKey_F22;
+ case SDLK_F23: return ImGuiKey_F23;
+ case SDLK_F24: return ImGuiKey_F24;
+ case SDLK_AC_BACK: return ImGuiKey_AppBack;
+ case SDLK_AC_FORWARD: return ImGuiKey_AppForward;
+ default: break;
+ }
+ return ImGuiKey_None;
+}
+
+static void ImGui_ImplSDL3_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddKeyEvent(ImGuiMod_Ctrl, (sdl_key_mods & SDL_KMOD_CTRL) != 0);
+ io.AddKeyEvent(ImGuiMod_Shift, (sdl_key_mods & SDL_KMOD_SHIFT) != 0);
+ io.AddKeyEvent(ImGuiMod_Alt, (sdl_key_mods & SDL_KMOD_ALT) != 0);
+ io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & SDL_KMOD_GUI) != 0);
+}
+
+
+static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id)
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : NULL;
+}
+
+// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
+// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
+// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
+// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
+// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
+bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event)
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()?");
+ ImGuiIO& io = ImGui::GetIO();
+
+ switch (event->type)
+ {
+ case SDL_EVENT_MOUSE_MOTION:
+ {
+ if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == NULL)
+ return false;
+ ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
+ io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
+ io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
+ return true;
+ }
+ case SDL_EVENT_MOUSE_WHEEL:
+ {
+ if (ImGui_ImplSDL3_GetViewportForWindowID(event->wheel.windowID) == NULL)
+ return false;
+ //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY);
+ float wheel_x = -event->wheel.x;
+ float wheel_y = event->wheel.y;
+ io.AddMouseSourceEvent(event->wheel.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
+ io.AddMouseWheelEvent(wheel_x, wheel_y);
+ return true;
+ }
+ case SDL_EVENT_MOUSE_BUTTON_DOWN:
+ case SDL_EVENT_MOUSE_BUTTON_UP:
+ {
+ if (ImGui_ImplSDL3_GetViewportForWindowID(event->button.windowID) == NULL)
+ return false;
+ int mouse_button = -1;
+ if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; }
+ if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; }
+ if (event->button.button == SDL_BUTTON_MIDDLE) { mouse_button = 2; }
+ if (event->button.button == SDL_BUTTON_X1) { mouse_button = 3; }
+ if (event->button.button == SDL_BUTTON_X2) { mouse_button = 4; }
+ if (mouse_button == -1)
+ break;
+ io.AddMouseSourceEvent(event->button.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
+ io.AddMouseButtonEvent(mouse_button, (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN));
+ bd->MouseButtonsDown = (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) ? (bd->MouseButtonsDown | (1 << mouse_button)) : (bd->MouseButtonsDown & ~(1 << mouse_button));
+ return true;
+ }
+ case SDL_EVENT_TEXT_INPUT:
+ {
+ if (ImGui_ImplSDL3_GetViewportForWindowID(event->text.windowID) == NULL)
+ return false;
+ io.AddInputCharactersUTF8(event->text.text);
+ return true;
+ }
+ case SDL_EVENT_KEY_DOWN:
+ case SDL_EVENT_KEY_UP:
+ {
+ if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == NULL)
+ return false;
+ //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod);
+ ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod);
+ ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode);
+ io.AddKeyEvent(key, (event->type == SDL_EVENT_KEY_DOWN));
+ io.SetKeyEventNativeData(key, event->key.key, event->key.scancode, event->key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
+ return true;
+ }
+ case SDL_EVENT_WINDOW_MOUSE_ENTER:
+ {
+ if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL)
+ return false;
+ bd->MouseWindowID = event->window.windowID;
+ bd->MousePendingLeaveFrame = 0;
+ return true;
+ }
+ // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
+ // causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why
+ // we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details.
+ // FIXME: Unconfirmed whether this is still needed with SDL3.
+ case SDL_EVENT_WINDOW_MOUSE_LEAVE:
+ {
+ if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL)
+ return false;
+ bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1;
+ return true;
+ }
+ case SDL_EVENT_WINDOW_FOCUS_GAINED:
+ case SDL_EVENT_WINDOW_FOCUS_LOST:
+ {
+ if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL)
+ return false;
+ io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED);
+ return true;
+ }
+ case SDL_EVENT_GAMEPAD_ADDED:
+ case SDL_EVENT_GAMEPAD_REMOVED:
+ {
+ bd->WantUpdateGamepadsList = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+static void ImGui_ImplSDL3_SetupPlatformHandles(ImGuiViewport* viewport, SDL_Window* window)
+{
+ viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(window);
+ viewport->PlatformHandleRaw = nullptr;
+#if defined(_WIN32) && !defined(__WINRT__)
+ viewport->PlatformHandleRaw = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
+#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
+ viewport->PlatformHandleRaw = SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr);
+#endif
+}
+
+static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void* sdl_gl_context)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
+ IM_UNUSED(sdl_gl_context); // Unused in this branch
+
+ // Check and store if we are on a SDL backend that supports global mouse position
+ // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
+ bool mouse_can_use_global_state = false;
+#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
+ const char* sdl_backend = SDL_GetCurrentVideoDriver();
+ const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
+ for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
+ if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
+ mouse_can_use_global_state = true;
+#endif
+
+ // Setup backend capabilities flags
+ ImGui_ImplSDL3_Data* bd = IM_NEW(ImGui_ImplSDL3_Data)();
+ io.BackendPlatformUserData = (void*)bd;
+ io.BackendPlatformName = "imgui_impl_sdl3";
+ io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
+ io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
+
+ bd->Window = window;
+ bd->WindowID = SDL_GetWindowID(window);
+ bd->Renderer = renderer;
+ bd->MouseCanUseGlobalState = mouse_can_use_global_state;
+
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText;
+ platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText;
+ platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData;
+
+ // Gamepad handling
+ bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst;
+ bd->WantUpdateGamepadsList = true;
+
+ // Load mouse cursors
+ bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
+ bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_TEXT);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NS_RESIZE);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_EW_RESIZE);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NESW_RESIZE);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE);
+ bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER);
+ bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED);
+
+ // Set platform dependent data in viewport
+ // Our mouse update function expect PlatformHandle to be filled for the main viewport
+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
+ ImGui_ImplSDL3_SetupPlatformHandles(main_viewport, window);
+
+ // From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
+ // Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
+ // (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
+ // It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
+ // you can ignore SDL_EVENT_MOUSE_BUTTON_DOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
+#ifdef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
+ SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
+#endif
+
+ // From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
+#ifdef SDL_HINT_MOUSE_AUTO_CAPTURE
+ SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
+#endif
+
+ return true;
+}
+
+bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
+{
+ IM_UNUSED(sdl_gl_context); // Viewport branch will need this.
+ return ImGui_ImplSDL3_Init(window, nullptr, sdl_gl_context);
+}
+
+bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window)
+{
+ return ImGui_ImplSDL3_Init(window, nullptr, nullptr);
+}
+
+bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window)
+{
+#if !defined(_WIN32)
+ IM_ASSERT(0 && "Unsupported");
+#endif
+ return ImGui_ImplSDL3_Init(window, nullptr, nullptr);
+}
+
+bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window)
+{
+ return ImGui_ImplSDL3_Init(window, nullptr, nullptr);
+}
+
+bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer)
+{
+ return ImGui_ImplSDL3_Init(window, renderer, nullptr);
+}
+
+bool ImGui_ImplSDL3_InitForOther(SDL_Window* window)
+{
+ return ImGui_ImplSDL3_Init(window, nullptr, nullptr);
+}
+
+static void ImGui_ImplSDL3_CloseGamepads();
+
+void ImGui_ImplSDL3_Shutdown()
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
+ if (bd->ClipboardTextData)
+ SDL_free(bd->ClipboardTextData);
+ for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
+ SDL_DestroyCursor(bd->MouseCursors[cursor_n]);
+ ImGui_ImplSDL3_CloseGamepads();
+
+ io.BackendPlatformName = nullptr;
+ io.BackendPlatformUserData = nullptr;
+ io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
+ IM_DELETE(bd);
+}
+
+static void ImGui_ImplSDL3_UpdateMouseData()
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ ImGuiIO& io = ImGui::GetIO();
+
+ // We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below)
+#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
+ // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
+ SDL_CaptureMouse(bd->MouseButtonsDown != 0);
+ SDL_Window* focused_window = SDL_GetKeyboardFocus();
+ const bool is_app_focused = (bd->Window == focused_window);
+#else
+ SDL_Window* focused_window = bd->Window;
+ const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
+#endif
+ if (is_app_focused)
+ {
+ // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
+ if (io.WantSetMousePos)
+ SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y);
+
+ // (Optional) Fallback to provide mouse position when focused (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured)
+ if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0)
+ {
+ // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
+ float mouse_x_global, mouse_y_global;
+ int window_x, window_y;
+ SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
+ SDL_GetWindowPosition(focused_window, &window_x, &window_y);
+ io.AddMousePosEvent(mouse_x_global - window_x, mouse_y_global - window_y);
+ }
+ }
+}
+
+static void ImGui_ImplSDL3_UpdateMouseCursor()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
+ return;
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+
+ ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
+ if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
+ {
+ // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
+ SDL_HideCursor();
+ }
+ else
+ {
+ // Show OS mouse cursor
+ SDL_Cursor* expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow];
+ if (bd->MouseLastCursor != expected_cursor)
+ {
+ SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113)
+ bd->MouseLastCursor = expected_cursor;
+ }
+ SDL_ShowCursor();
+ }
+}
+
+static void ImGui_ImplSDL3_CloseGamepads()
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ if (bd->GamepadMode != ImGui_ImplSDL3_GamepadMode_Manual)
+ for (SDL_Gamepad* gamepad : bd->Gamepads)
+ SDL_CloseGamepad(gamepad);
+ bd->Gamepads.resize(0);
+}
+
+void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array, int manual_gamepads_count)
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ ImGui_ImplSDL3_CloseGamepads();
+ if (mode == ImGui_ImplSDL3_GamepadMode_Manual)
+ {
+ IM_ASSERT(manual_gamepads_array != nullptr && manual_gamepads_count > 0);
+ for (int n = 0; n < manual_gamepads_count; n++)
+ bd->Gamepads.push_back(manual_gamepads_array[n]);
+ }
+ else
+ {
+ IM_ASSERT(manual_gamepads_array == nullptr && manual_gamepads_count <= 0);
+ bd->WantUpdateGamepadsList = true;
+ }
+ bd->GamepadMode = mode;
+}
+
+static void ImGui_ImplSDL3_UpdateGamepadButton(ImGui_ImplSDL3_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GamepadButton button_no)
+{
+ bool merged_value = false;
+ for (SDL_Gamepad* gamepad : bd->Gamepads)
+ merged_value |= SDL_GetGamepadButton(gamepad, button_no) != 0;
+ io.AddKeyEvent(key, merged_value);
+}
+
+static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
+static void ImGui_ImplSDL3_UpdateGamepadAnalog(ImGui_ImplSDL3_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GamepadAxis axis_no, float v0, float v1)
+{
+ float merged_value = 0.0f;
+ for (SDL_Gamepad* gamepad : bd->Gamepads)
+ {
+ float vn = Saturate((float)(SDL_GetGamepadAxis(gamepad, axis_no) - v0) / (float)(v1 - v0));
+ if (merged_value < vn)
+ merged_value = vn;
+ }
+ io.AddKeyAnalogEvent(key, merged_value > 0.1f, merged_value);
+}
+
+static void ImGui_ImplSDL3_UpdateGamepads()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+
+ // Update list of gamepads to use
+ if (bd->WantUpdateGamepadsList && bd->GamepadMode != ImGui_ImplSDL3_GamepadMode_Manual)
+ {
+ ImGui_ImplSDL3_CloseGamepads();
+ int sdl_gamepads_count = 0;
+ SDL_JoystickID* sdl_gamepads = SDL_GetGamepads(&sdl_gamepads_count);
+ for (int n = 0; n < sdl_gamepads_count; n++)
+ if (SDL_Gamepad* gamepad = SDL_OpenGamepad(sdl_gamepads[n]))
+ {
+ bd->Gamepads.push_back(gamepad);
+ if (bd->GamepadMode == ImGui_ImplSDL3_GamepadMode_AutoFirst)
+ break;
+ }
+ bd->WantUpdateGamepadsList = false;
+ SDL_free(sdl_gamepads);
+ }
+
+ // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
+ if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
+ return;
+ io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
+ if (bd->Gamepads.Size == 0)
+ return;
+ io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
+
+ // Update gamepad inputs
+ const int thumb_dead_zone = 8000; // SDL_gamepad.h suggests using this value.
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadStart, SDL_GAMEPAD_BUTTON_START);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadBack, SDL_GAMEPAD_BUTTON_BACK);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceLeft, SDL_GAMEPAD_BUTTON_WEST); // Xbox X, PS Square
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceRight, SDL_GAMEPAD_BUTTON_EAST); // Xbox B, PS Circle
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceUp, SDL_GAMEPAD_BUTTON_NORTH); // Xbox Y, PS Triangle
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceDown, SDL_GAMEPAD_BUTTON_SOUTH); // Xbox A, PS Cross
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadLeft, SDL_GAMEPAD_BUTTON_DPAD_LEFT);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadRight, SDL_GAMEPAD_BUTTON_DPAD_RIGHT);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadUp, SDL_GAMEPAD_BUTTON_DPAD_UP);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadDown, SDL_GAMEPAD_BUTTON_DPAD_DOWN);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL1, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR1, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadL2, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0.0f, 32767);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadR2, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0.0f, 32767);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL3, SDL_GAMEPAD_BUTTON_LEFT_STICK);
+ ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR3, SDL_GAMEPAD_BUTTON_RIGHT_STICK);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickLeft, SDL_GAMEPAD_AXIS_LEFTX, -thumb_dead_zone, -32768);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickRight, SDL_GAMEPAD_AXIS_LEFTX, +thumb_dead_zone, +32767);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickUp, SDL_GAMEPAD_AXIS_LEFTY, -thumb_dead_zone, -32768);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickDown, SDL_GAMEPAD_AXIS_LEFTY, +thumb_dead_zone, +32767);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickLeft, SDL_GAMEPAD_AXIS_RIGHTX, -thumb_dead_zone, -32768);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickRight, SDL_GAMEPAD_AXIS_RIGHTX, +thumb_dead_zone, +32767);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickUp, SDL_GAMEPAD_AXIS_RIGHTY, -thumb_dead_zone, -32768);
+ ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767);
+}
+
+void ImGui_ImplSDL3_NewFrame()
+{
+ ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()?");
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Setup display size (every frame to accommodate for window resizing)
+ int w, h;
+ int display_w, display_h;
+ SDL_GetWindowSize(bd->Window, &w, &h);
+ if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
+ w = h = 0;
+ SDL_GetWindowSizeInPixels(bd->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 (we don't use SDL_GetTicks() because it is using millisecond resolution)
+ // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
+ static Uint64 frequency = SDL_GetPerformanceFrequency();
+ Uint64 current_time = SDL_GetPerformanceCounter();
+ if (current_time <= bd->Time)
+ current_time = bd->Time + 1;
+ io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
+ bd->Time = current_time;
+
+ if (bd->MousePendingLeaveFrame && bd->MousePendingLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0)
+ {
+ bd->MouseWindowID = 0;
+ bd->MousePendingLeaveFrame = 0;
+ io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
+ }
+
+ ImGui_ImplSDL3_UpdateMouseData();
+ ImGui_ImplSDL3_UpdateMouseCursor();
+
+ // Update game controllers (if enabled and available)
+ ImGui_ImplSDL3_UpdateGamepads();
+}
+
+//-----------------------------------------------------------------------------
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/third_party/imgui/backends/imgui_impl_sdl3.h b/third_party/imgui/backends/imgui_impl_sdl3.h
new file mode 100644
index 0000000..c4a5a12
--- /dev/null
+++ b/third_party/imgui/backends/imgui_impl_sdl3.h
@@ -0,0 +1,47 @@
+// dear imgui: Platform Backend for SDL3 (*EXPERIMENTAL*)
+// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
+// (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
+
+// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**)
+
+// Implemented features:
+// [X] Platform: Clipboard support.
+// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
+// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
+// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+struct SDL_Window;
+struct SDL_Renderer;
+struct SDL_Gamepad;
+typedef union SDL_Event SDL_Event;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
+IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window);
+IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window);
+IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window);
+IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
+IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOther(SDL_Window* window);
+IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame();
+IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event);
+
+// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this.
+// When using manual mode, caller is responsible for opening/closing gamepad.
+enum ImGui_ImplSDL3_GamepadMode { ImGui_ImplSDL3_GamepadMode_AutoFirst, ImGui_ImplSDL3_GamepadMode_AutoAll, ImGui_ImplSDL3_GamepadMode_Manual };
+IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = NULL, int manual_gamepads_count = -1);
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/third_party/imgui/backends/imgui_impl_sdlrenderer3.cpp b/third_party/imgui/backends/imgui_impl_sdlrenderer3.cpp
new file mode 100644
index 0000000..5dabea1
--- /dev/null
+++ b/third_party/imgui/backends/imgui_impl_sdlrenderer3.cpp
@@ -0,0 +1,294 @@
+// dear imgui: Renderer Backend for SDL_Renderer for SDL3
+// (Requires: SDL 3.0.0+)
+
+// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**)
+
+// Note how SDL_Renderer is an _optional_ component of SDL3.
+// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
+// If your application will want to render any non trivial amount of graphics other than UI,
+// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and
+// it might be difficult to step out of those boundaries.
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
+// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+// CHANGELOG
+// 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer3_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
+// 2024-07-01: Update for SDL3 api changes: SDL_RenderGeometryRaw() uint32 version was removed (SDL#9009).
+// 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter.
+// 2024-02-12: Amend to query SDL_RenderViewportSet() and restore viewport accordingly.
+// 2023-05-30: Initial version.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_sdlrenderer3.h"
+#include <stdint.h> // intptr_t
+
+// Clang warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#endif
+
+// SDL
+#include <SDL3/SDL.h>
+#if !SDL_VERSION_ATLEAST(3,0,0)
+#error This backend requires SDL 3.0.0+
+#endif
+
+// SDL_Renderer data
+struct ImGui_ImplSDLRenderer3_Data
+{
+ SDL_Renderer* Renderer; // Main viewport's renderer
+ SDL_Texture* FontTexture;
+ ImVector<SDL_FColor> ColorBuffer;
+
+ ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
+}
+
+// Functions
+bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
+ IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplSDLRenderer3_Data* bd = IM_NEW(ImGui_ImplSDLRenderer3_Data)();
+ io.BackendRendererUserData = (void*)bd;
+ io.BackendRendererName = "imgui_impl_sdlrenderer3";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+
+ bd->Renderer = renderer;
+
+ return true;
+}
+
+void ImGui_ImplSDLRenderer3_Shutdown()
+{
+ ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
+ IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+
+ ImGui_ImplSDLRenderer3_DestroyDeviceObjects();
+
+ io.BackendRendererName = nullptr;
+ io.BackendRendererUserData = nullptr;
+ io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
+ IM_DELETE(bd);
+}
+
+static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer)
+{
+ // Clear out any viewports and cliprect set by the user
+ // FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
+ SDL_SetRenderViewport(renderer, nullptr);
+ SDL_SetRenderClipRect(renderer, nullptr);
+}
+
+void ImGui_ImplSDLRenderer3_NewFrame()
+{
+ ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLRenderer3_Init()?");
+
+ if (!bd->FontTexture)
+ ImGui_ImplSDLRenderer3_CreateDeviceObjects();
+}
+
+// https://github.com/libsdl-org/SDL/issues/9009
+static int SDL_RenderGeometryRaw8BitColor(SDL_Renderer* renderer, ImVector<SDL_FColor>& colors_out, SDL_Texture* texture, const float* xy, int xy_stride, const SDL_Color* color, int color_stride, const float* uv, int uv_stride, int num_vertices, const void* indices, int num_indices, int size_indices)
+{
+ const Uint8* color2 = (const Uint8*)color;
+ colors_out.resize(num_vertices);
+ SDL_FColor* color3 = colors_out.Data;
+ for (int i = 0; i < num_vertices; i++)
+ {
+ color3[i].r = color->r / 255.0f;
+ color3[i].g = color->g / 255.0f;
+ color3[i].b = color->b / 255.0f;
+ color3[i].a = color->a / 255.0f;
+ color2 += color_stride;
+ color = (const SDL_Color*)color2;
+ }
+ return SDL_RenderGeometryRaw(renderer, texture, xy, xy_stride, color3, sizeof(*color3), uv, uv_stride, num_vertices, indices, num_indices, size_indices);
+}
+
+void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
+{
+ ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
+
+ // If there's a scale factor set by the user, use that instead
+ // If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
+ // to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
+ float rsx = 1.0f;
+ float rsy = 1.0f;
+ SDL_GetRenderScale(renderer, &rsx, &rsy);
+ ImVec2 render_scale;
+ render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
+ render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
+
+ // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
+ int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
+ int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
+ if (fb_width == 0 || fb_height == 0)
+ return;
+
+ // Backup SDL_Renderer state that will be modified to restore it afterwards
+ struct BackupSDLRendererState
+ {
+ SDL_Rect Viewport;
+ bool ViewportEnabled;
+ bool ClipEnabled;
+ SDL_Rect ClipRect;
+ };
+ BackupSDLRendererState old = {};
+ old.ViewportEnabled = SDL_RenderViewportSet(renderer);
+ old.ClipEnabled = SDL_RenderClipEnabled(renderer);
+ SDL_GetRenderViewport(renderer, &old.Viewport);
+ SDL_GetRenderClipRect(renderer, &old.ClipRect);
+
+ // Setup desired state
+ ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
+
+ // Setup render state structure (for callbacks and custom texture bindings)
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ ImGui_ImplSDLRenderer3_RenderState render_state;
+ render_state.Renderer = renderer;
+ platform_io.Renderer_RenderState = &render_state;
+
+ // Will project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
+ ImVec2 clip_scale = render_scale;
+
+ // Render command lists
+ for (int n = 0; n < draw_data->CmdListsCount; n++)
+ {
+ const ImDrawList* draw_list = draw_data->CmdLists[n];
+ const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data;
+ const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data;
+
+ for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
+ else
+ pcmd->UserCallback(draw_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
+ if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
+ if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
+ if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
+ if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
+ SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
+ SDL_SetRenderClipRect(renderer, &r);
+
+ const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos));
+ const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv));
+ const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+
+
+ // Bind texture, Draw
+ SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
+ SDL_RenderGeometryRaw8BitColor(renderer, bd->ColorBuffer, tex,
+ xy, (int)sizeof(ImDrawVert),
+ color, (int)sizeof(ImDrawVert),
+ uv, (int)sizeof(ImDrawVert),
+ draw_list->VtxBuffer.Size - pcmd->VtxOffset,
+ idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
+ }
+ }
+ }
+ platform_io.Renderer_RenderState = NULL;
+
+ // Restore modified SDL_Renderer state
+ SDL_SetRenderViewport(renderer, old.ViewportEnabled ? &old.Viewport : nullptr);
+ SDL_SetRenderClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
+}
+
+// Called by Init/NewFrame/Shutdown
+bool ImGui_ImplSDLRenderer3_CreateFontsTexture()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
+
+ // Build texture atlas
+ unsigned char* pixels;
+ int width, height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (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
+ // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
+ bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
+ if (bd->FontTexture == nullptr)
+ {
+ SDL_Log("error creating texture");
+ return false;
+ }
+ SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width);
+ SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
+ SDL_SetTextureScaleMode(bd->FontTexture, SDL_SCALEMODE_LINEAR);
+
+ // Store our identifier
+ io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
+
+ return true;
+}
+
+void ImGui_ImplSDLRenderer3_DestroyFontsTexture()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
+ if (bd->FontTexture)
+ {
+ io.Fonts->SetTexID(0);
+ SDL_DestroyTexture(bd->FontTexture);
+ bd->FontTexture = nullptr;
+ }
+}
+
+bool ImGui_ImplSDLRenderer3_CreateDeviceObjects()
+{
+ return ImGui_ImplSDLRenderer3_CreateFontsTexture();
+}
+
+void ImGui_ImplSDLRenderer3_DestroyDeviceObjects()
+{
+ ImGui_ImplSDLRenderer3_DestroyFontsTexture();
+}
+
+//-----------------------------------------------------------------------------
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/third_party/imgui/backends/imgui_impl_sdlrenderer3.h b/third_party/imgui/backends/imgui_impl_sdlrenderer3.h
new file mode 100644
index 0000000..7d4c609
--- /dev/null
+++ b/third_party/imgui/backends/imgui_impl_sdlrenderer3.h
@@ -0,0 +1,51 @@
+// dear imgui: Renderer Backend for SDL_Renderer for SDL3
+// (Requires: SDL 3.0.0+)
+
+// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**)
+
+// Note how SDL_Renderer is an _optional_ component of SDL3.
+// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
+// If your application will want to render any non trivial amount of graphics other than UI,
+// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and
+// it might be difficult to step out of those boundaries.
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
+// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
+// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
+
+// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+struct SDL_Renderer;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer);
+IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer);
+
+// Called by Init/NewFrame/Shutdown
+IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_CreateFontsTexture();
+IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyFontsTexture();
+IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_CreateDeviceObjects();
+IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyDeviceObjects();
+
+// [BETA] Selected render state data shared with callbacks.
+// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLRenderer3_RenderDrawData() call.
+// (Please open an issue if you feel you need access to more data)
+struct ImGui_ImplSDLRenderer3_RenderState
+{
+ SDL_Renderer* Renderer;
+};
+
+#endif // #ifndef IMGUI_DISABLE