690 lines
34 KiB
Plaintext
690 lines
34 KiB
Plaintext
// 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**)
|
|
|
|
// 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 will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
|
|
// [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-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.
|
|
|
|
// SDL
|
|
// Let Jai's SDL3 module handle this
|
|
//#include <SDL3/SDL.h>
|
|
|
|
#if OS == .MACOS {
|
|
//#include <TargetConditionals.h>
|
|
//#assert false "Please include the platform header TargetConditionals.h somehow.";
|
|
}
|
|
#if OS == .WINDOWS {
|
|
// Let Jai's Windows module handle this
|
|
|
|
// #if !exists(WIN32_LEAN_AND_MEAN) {
|
|
// //WIN32_LEAN_AND_MEAN :: 1;
|
|
// }
|
|
// //#include <windows.h>
|
|
// // you should have included this in your main file
|
|
}
|
|
|
|
#if !#exists(__EMSCRIPTEN__) && !#exists(__ANDROID__) && !(#exists(__APPLE__) && #exists(TARGET_OS_IOS)) &&
|
|
!#exists(__amigaos4__) {
|
|
SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE :: true;
|
|
} else {
|
|
SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE :: false;
|
|
}
|
|
|
|
ImGui_ImplSDL3_GamepadMode :: enum {
|
|
AutoFirst;
|
|
AutoAll;
|
|
Manual;
|
|
}
|
|
|
|
// SDL Data
|
|
ImGui_ImplSDL3_Data :: struct {
|
|
Window : *SDL_Window;
|
|
Renderer : *SDL_Renderer;
|
|
Time : Uint64;
|
|
ClipboardTextData : *u8;
|
|
|
|
// IME handling
|
|
ImeWindow : *SDL_Window;
|
|
|
|
// Mouse handling
|
|
MouseWindowID : Uint32;
|
|
MouseButtonsDown : s32;
|
|
MouseCursors : [ImGui.MouseCursor.ImGuiMouseCursor_COUNT]*SDL_Cursor;
|
|
MouseLastCursor : *SDL_Cursor;
|
|
MousePendingLeaveFrame : s32;
|
|
MouseCanUseGlobalState : bool;
|
|
|
|
// Gamepad handling
|
|
Gamepads : [..]*SDL_Gamepad;
|
|
GamepadMode : ImGui_ImplSDL3_GamepadMode;
|
|
WantUpdateGamepadsList : bool;
|
|
}
|
|
|
|
// 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.
|
|
ImGui_ImplSDL3_GetBackendData :: () -> *ImGui_ImplSDL3_Data #c_call {
|
|
return ifx ImGui.GetCurrentContext() then cast(*ImGui_ImplSDL3_Data) ImGui.GetIO().BackendPlatformUserData else null;
|
|
}
|
|
|
|
// Functions
|
|
ImGui_ImplSDL3_GetClipboardText :: (user_data: *void) -> *u8 #c_call {
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
if bd.ClipboardTextData
|
|
SDL_free(bd.ClipboardTextData);
|
|
sdl_clipboard_text : *u8 = SDL_GetClipboardText();
|
|
bd.ClipboardTextData = ifx sdl_clipboard_text then SDL_strdup(sdl_clipboard_text) else null;
|
|
return bd.ClipboardTextData;
|
|
}
|
|
|
|
ImGui_ImplSDL3_SetClipboardText :: (user_data: *void, text: *u8) #c_call {
|
|
SDL_SetClipboardText(text);
|
|
}
|
|
|
|
ImGui_ImplSDL3_PlatformSetImeData :: (ctx: *ImGui.ImGuiContext, viewport: *ImGui.Viewport, data: *ImGui.PlatformImeData) #c_call {
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
window : *SDL_Window = cast(*SDL_Window) viewport.PlatformHandle;
|
|
if ((data.WantVisible == false || bd.ImeWindow != window) && bd.ImeWindow != null) {
|
|
SDL_StopTextInput(bd.ImeWindow);
|
|
bd.ImeWindow = null;
|
|
}
|
|
|
|
if (data.WantVisible) {
|
|
r : SDL_Rect;
|
|
r.x = cast(s32) data.InputPos.x;
|
|
r.y = cast(s32) data.InputPos.y;
|
|
r.w = 1;
|
|
r.h = cast(s32) data.InputLineHeight;
|
|
SDL_SetTextInputArea(window, *r, 0);
|
|
SDL_StartTextInput(window);
|
|
bd.ImeWindow = window;
|
|
}
|
|
}
|
|
|
|
ImGui_ImplSDL3_KeyEventToImGuiKey :: (keycode: SDL_Keycode, scancode: SDL_Scancode) -> ImGui.Key {
|
|
// Keypad doesn't have individual key values in SDL3
|
|
if scancode == {
|
|
case SDL_Scancode.SDL_SCANCODE_KP_0; return ImGui.Key.Keypad0;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_1; return ImGui.Key.Keypad1;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_2; return ImGui.Key.Keypad2;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_3; return ImGui.Key.Keypad3;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_4; return ImGui.Key.Keypad4;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_5; return ImGui.Key.Keypad5;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_6; return ImGui.Key.Keypad6;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_7; return ImGui.Key.Keypad7;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_8; return ImGui.Key.Keypad8;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_9; return ImGui.Key.Keypad9;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_PERIOD; return ImGui.Key.KeypadDecimal;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_DIVIDE; return ImGui.Key.KeypadDivide;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_MULTIPLY; return ImGui.Key.KeypadMultiply;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_MINUS; return ImGui.Key.KeypadSubtract;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_PLUS; return ImGui.Key.KeypadAdd;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_ENTER; return ImGui.Key.KeypadEnter;
|
|
case SDL_Scancode.SDL_SCANCODE_KP_EQUALS; return ImGui.Key.KeypadEqual;
|
|
}
|
|
|
|
if keycode == {
|
|
case SDLK_TAB; return ImGui.Key.Tab;
|
|
case SDLK_LEFT; return ImGui.Key.LeftArrow;
|
|
case SDLK_RIGHT; return ImGui.Key.RightArrow;
|
|
case SDLK_UP; return ImGui.Key.UpArrow;
|
|
case SDLK_DOWN; return ImGui.Key.DownArrow;
|
|
case SDLK_PAGEUP; return ImGui.Key.PageUp;
|
|
case SDLK_PAGEDOWN; return ImGui.Key.PageDown;
|
|
case SDLK_HOME; return ImGui.Key.Home;
|
|
case SDLK_END; return ImGui.Key.End;
|
|
case SDLK_INSERT; return ImGui.Key.Insert;
|
|
case SDLK_DELETE; return ImGui.Key.Delete;
|
|
case SDLK_BACKSPACE; return ImGui.Key.Backspace;
|
|
case SDLK_SPACE; return ImGui.Key.Space;
|
|
case SDLK_RETURN; return ImGui.Key.Enter;
|
|
case SDLK_ESCAPE; return ImGui.Key.Escape;
|
|
case SDLK_APOSTROPHE; return ImGui.Key.Apostrophe;
|
|
case SDLK_COMMA; return ImGui.Key.Comma;
|
|
case SDLK_MINUS; return ImGui.Key.Minus;
|
|
case SDLK_PERIOD; return ImGui.Key.Period;
|
|
case SDLK_SLASH; return ImGui.Key.Slash;
|
|
case SDLK_SEMICOLON; return ImGui.Key.Semicolon;
|
|
case SDLK_EQUALS; return ImGui.Key.Equal;
|
|
case SDLK_LEFTBRACKET; return ImGui.Key.LeftBracket;
|
|
case SDLK_BACKSLASH; return ImGui.Key.Backslash;
|
|
case SDLK_RIGHTBRACKET; return ImGui.Key.RightBracket;
|
|
case SDLK_GRAVE; return ImGui.Key.GraveAccent;
|
|
case SDLK_CAPSLOCK; return ImGui.Key.CapsLock;
|
|
case SDLK_SCROLLLOCK; return ImGui.Key.ScrollLock;
|
|
case SDLK_NUMLOCKCLEAR; return ImGui.Key.NumLock;
|
|
case SDLK_PRINTSCREEN; return ImGui.Key.PrintScreen;
|
|
case SDLK_PAUSE; return ImGui.Key.Pause;
|
|
case SDLK_LCTRL; return ImGui.Key.LeftCtrl;
|
|
case SDLK_LSHIFT; return ImGui.Key.LeftShift;
|
|
case SDLK_LALT; return ImGui.Key.LeftAlt;
|
|
case SDLK_LGUI; return ImGui.Key.LeftSuper;
|
|
case SDLK_RCTRL; return ImGui.Key.RightCtrl;
|
|
case SDLK_RSHIFT; return ImGui.Key.RightShift;
|
|
case SDLK_RALT; return ImGui.Key.RightAlt;
|
|
case SDLK_RGUI; return ImGui.Key.RightSuper;
|
|
case SDLK_APPLICATION; return ImGui.Key.Menu;
|
|
case SDLK_0; return ImGui.Key._0;
|
|
case SDLK_1; return ImGui.Key._1;
|
|
case SDLK_2; return ImGui.Key._2;
|
|
case SDLK_3; return ImGui.Key._3;
|
|
case SDLK_4; return ImGui.Key._4;
|
|
case SDLK_5; return ImGui.Key._5;
|
|
case SDLK_6; return ImGui.Key._6;
|
|
case SDLK_7; return ImGui.Key._7;
|
|
case SDLK_8; return ImGui.Key._8;
|
|
case SDLK_9; return ImGui.Key._9;
|
|
case SDLK_A; return ImGui.Key.A;
|
|
case SDLK_B; return ImGui.Key.B;
|
|
case SDLK_C; return ImGui.Key.C;
|
|
case SDLK_D; return ImGui.Key.D;
|
|
case SDLK_E; return ImGui.Key.E;
|
|
case SDLK_F; return ImGui.Key.F;
|
|
case SDLK_G; return ImGui.Key.G;
|
|
case SDLK_H; return ImGui.Key.H;
|
|
case SDLK_I; return ImGui.Key.I;
|
|
case SDLK_J; return ImGui.Key.J;
|
|
case SDLK_K; return ImGui.Key.K;
|
|
case SDLK_L; return ImGui.Key.L;
|
|
case SDLK_M; return ImGui.Key.M;
|
|
case SDLK_N; return ImGui.Key.N;
|
|
case SDLK_O; return ImGui.Key.O;
|
|
case SDLK_P; return ImGui.Key.P;
|
|
case SDLK_Q; return ImGui.Key.Q;
|
|
case SDLK_R; return ImGui.Key.R;
|
|
case SDLK_S; return ImGui.Key.S;
|
|
case SDLK_T; return ImGui.Key.T;
|
|
case SDLK_U; return ImGui.Key.U;
|
|
case SDLK_V; return ImGui.Key.V;
|
|
case SDLK_W; return ImGui.Key.W;
|
|
case SDLK_X; return ImGui.Key.X;
|
|
case SDLK_Y; return ImGui.Key.Y;
|
|
case SDLK_Z; return ImGui.Key.Z;
|
|
case SDLK_F1; return ImGui.Key.F1;
|
|
case SDLK_F2; return ImGui.Key.F2;
|
|
case SDLK_F3; return ImGui.Key.F3;
|
|
case SDLK_F4; return ImGui.Key.F4;
|
|
case SDLK_F5; return ImGui.Key.F5;
|
|
case SDLK_F6; return ImGui.Key.F6;
|
|
case SDLK_F7; return ImGui.Key.F7;
|
|
case SDLK_F8; return ImGui.Key.F8;
|
|
case SDLK_F9; return ImGui.Key.F9;
|
|
case SDLK_F10; return ImGui.Key.F10;
|
|
case SDLK_F11; return ImGui.Key.F11;
|
|
case SDLK_F12; return ImGui.Key.F12;
|
|
case SDLK_F13; return ImGui.Key.F13;
|
|
case SDLK_F14; return ImGui.Key.F14;
|
|
case SDLK_F15; return ImGui.Key.F15;
|
|
case SDLK_F16; return ImGui.Key.F16;
|
|
case SDLK_F17; return ImGui.Key.F17;
|
|
case SDLK_F18; return ImGui.Key.F18;
|
|
case SDLK_F19; return ImGui.Key.F19;
|
|
case SDLK_F20; return ImGui.Key.F20;
|
|
case SDLK_F21; return ImGui.Key.F21;
|
|
case SDLK_F22; return ImGui.Key.F22;
|
|
case SDLK_F23; return ImGui.Key.F23;
|
|
case SDLK_F24; return ImGui.Key.F24;
|
|
case SDLK_AC_BACK; return ImGui.Key.AppBack;
|
|
case SDLK_AC_FORWARD; return ImGui.Key.AppForward;
|
|
}
|
|
return ImGui.Key.None;
|
|
}
|
|
|
|
ImGui_ImplSDL3_UpdateKeyModifiers :: (sdl_key_mods: SDL_Keymod) {
|
|
io : *ImGui.IO = ImGui.GetIO();
|
|
io.AddKeyEvent(io, ImGui.Key.Mod_Ctrl, (sdl_key_mods & SDL_KMOD_CTRL) != 0);
|
|
io.AddKeyEvent(io, ImGui.Key.Mod_Shift, (sdl_key_mods & SDL_KMOD_SHIFT) != 0);
|
|
io.AddKeyEvent(io, ImGui.Key.Mod_Alt, (sdl_key_mods & SDL_KMOD_ALT) != 0);
|
|
io.AddKeyEvent(io, ImGui.Key.Mod_Super, (sdl_key_mods & SDL_KMOD_GUI) != 0);
|
|
}
|
|
|
|
// 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.
|
|
ImGui_ImplSDL3_ProcessEvent :: (event: *SDL_Event) -> bool {
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
assert(bd != null && "Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()?");
|
|
io : *ImGui.IO = ImGui.GetIO();
|
|
|
|
if event.type == {
|
|
case xx SDL_EVENT_MOUSE_MOTION;
|
|
mouse_pos : ImGui.ImVec2 = .{cast(float) event.motion.x, cast(float) event.motion.y};
|
|
io.AddMouseSourceEvent(io, ifx event.motion.which == SDL_TOUCH_MOUSEID then ImGui.MouseSource.TouchScreen else ImGui.MouseSource.Mouse);
|
|
io.AddMousePosEvent(io, mouse_pos.x, mouse_pos.y);
|
|
return true;
|
|
|
|
case xx SDL_EVENT_MOUSE_WHEEL;
|
|
//IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event.wheel.x, (float)event.wheel.y, event.wheel.preciseX, event.wheel.preciseY);
|
|
wheel_x : float = -event.wheel.x;
|
|
wheel_y : float = event.wheel.y;
|
|
#if #exists (__EMSCRIPTEN__) {
|
|
wheel_x /= 100.0;
|
|
}
|
|
io.AddMouseSourceEvent(io, ifx event.wheel.which == SDL_TOUCH_MOUSEID then ImGui.MouseSource.TouchScreen else ImGui.MouseSource.Mouse);
|
|
io.AddMouseWheelEvent(io, wheel_x, wheel_y);
|
|
return true;
|
|
|
|
case xx SDL_EVENT_MOUSE_BUTTON_DOWN;
|
|
#through;
|
|
|
|
case xx SDL_EVENT_MOUSE_BUTTON_UP;
|
|
mouse_button : s32 = -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; }
|
|
io.AddMouseSourceEvent(io, ifx event.button.which == SDL_TOUCH_MOUSEID then ImGui.MouseSource.TouchScreen else ImGui.MouseSource.Mouse);
|
|
io.AddMouseButtonEvent(io, mouse_button, (event.type == xx SDL_EVENT_MOUSE_BUTTON_DOWN));
|
|
bd.MouseButtonsDown = xx ifx (event.type == xx SDL_EVENT_MOUSE_BUTTON_DOWN) then (bd.MouseButtonsDown | (1 << mouse_button)) else (bd.MouseButtonsDown & ~(1 << mouse_button));
|
|
return true;
|
|
|
|
case xx SDL_EVENT_TEXT_INPUT;
|
|
io.AddInputCharactersUTF8(io, event.text.text);
|
|
return true;
|
|
|
|
case xx SDL_EVENT_KEY_DOWN;
|
|
#through;
|
|
|
|
case xx SDL_EVENT_KEY_UP;
|
|
//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(cast(SDL_Keymod) event.key.mod);
|
|
key : ImGui.Key = ImGui_ImplSDL3_KeyEventToImGuiKey(event.key.key, event.key.scancode);
|
|
io.AddKeyEvent(io, key, (event.type == xx SDL_EVENT_KEY_DOWN));
|
|
io.SetKeyEventNativeData(io, key, xx event.key.key, xx event.key.scancode, xx event.key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
|
|
return true;
|
|
|
|
case xx SDL_EVENT_WINDOW_MOUSE_ENTER;
|
|
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 xx SDL_EVENT_WINDOW_MOUSE_LEAVE;
|
|
bd.MousePendingLeaveFrame = ImGui.GetFrameCount() + 1;
|
|
return true;
|
|
|
|
case xx SDL_EVENT_WINDOW_FOCUS_GAINED;
|
|
io.AddFocusEvent(io, true);
|
|
return true;
|
|
|
|
case xx SDL_EVENT_WINDOW_FOCUS_LOST;
|
|
io.AddFocusEvent(io, false);
|
|
return true;
|
|
|
|
case xx SDL_EVENT_GAMEPAD_ADDED;
|
|
#through;
|
|
|
|
case xx SDL_EVENT_GAMEPAD_REMOVED;
|
|
bd.WantUpdateGamepadsList = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ImGui_ImplSDL3_SetupPlatformHandles :: (viewport: *ImGui.Viewport, window: *SDL_Window) {
|
|
viewport.PlatformHandle = window;
|
|
viewport.PlatformHandleRaw = null;
|
|
#if #exists(_WIN32) && !#exists(__WINRT__) {
|
|
viewport.PlatformHandleRaw = cast(HWND) SDL_GetPointerProperty(SDL_GetWindowProperties(window),
|
|
SDL_PROP_WINDOW_WIN32_HWND_POINTER, null);
|
|
} else #if #exists (__APPLE__) && #exists (SDL_VIDEO_DRIVER_COCOA) {
|
|
viewport.PlatformHandleRaw = SDL_GetPointerProperty(SDL_GetWindowProperties(window),
|
|
SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, null);
|
|
}
|
|
}
|
|
|
|
ImGui_ImplSDL3_Init :: (window: *SDL_Window, renderer: *SDL_Renderer, sdl_gl_context: *void) -> bool {
|
|
io : *ImGui.IO = ImGui.GetIO();
|
|
ImGui.IMGUI_CHECKVERSION();
|
|
assert(io.BackendPlatformUserData == null && "Already initialized a platform backend!");
|
|
|
|
// 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)
|
|
mouse_can_use_global_state : bool = false;
|
|
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE {
|
|
//sdl_backend : *u8 = SDL_GetCurrentVideoDriver();
|
|
//global_mouse_whitelist : []*u8 = .[ "windows", "cocoa", "x11", "DIVE", "VMAN" ];
|
|
//for n : 0..global_mouse_whitelist.count {
|
|
// //if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
|
|
// // mouse_can_use_global_state = true;
|
|
//}
|
|
}
|
|
|
|
// Setup backend capabilities flags
|
|
bd : *ImGui_ImplSDL3_Data = New(ImGui_ImplSDL3_Data);
|
|
io.BackendPlatformUserData = cast(*void) bd;
|
|
io.BackendPlatformName = "imgui_impl_sdl3";
|
|
io.BackendFlags_ |= ImGui.BackendFlags.HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
|
io.BackendFlags_ |= ImGui.BackendFlags.HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
|
|
|
bd.Window = window;
|
|
bd.Renderer = renderer;
|
|
bd.MouseCanUseGlobalState = mouse_can_use_global_state;
|
|
|
|
io.SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText;
|
|
io.GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText;
|
|
io.ClipboardUserData = null;
|
|
io.PlatformSetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData;
|
|
|
|
// Gamepad handling
|
|
bd.GamepadMode = ImGui_ImplSDL3_GamepadMode.AutoFirst;
|
|
bd.WantUpdateGamepadsList = true;
|
|
|
|
// Load mouse cursors
|
|
bd.MouseCursors[ImGui.MouseCursor.Arrow] = SDL_CreateSystemCursor(.SDL_SYSTEM_CURSOR_DEFAULT);
|
|
bd.MouseCursors[ImGui.MouseCursor.TextInput] = SDL_CreateSystemCursor(.SDL_SYSTEM_CURSOR_TEXT);
|
|
bd.MouseCursors[ImGui.MouseCursor.ResizeAll] = SDL_CreateSystemCursor(.SDL_SYSTEM_CURSOR_MOVE);
|
|
bd.MouseCursors[ImGui.MouseCursor.ResizeNS] = SDL_CreateSystemCursor(.SDL_SYSTEM_CURSOR_NS_RESIZE);
|
|
bd.MouseCursors[ImGui.MouseCursor.ResizeEW] = SDL_CreateSystemCursor(.SDL_SYSTEM_CURSOR_EW_RESIZE);
|
|
bd.MouseCursors[ImGui.MouseCursor.ResizeNESW] = SDL_CreateSystemCursor(.SDL_SYSTEM_CURSOR_NESW_RESIZE);
|
|
bd.MouseCursors[ImGui.MouseCursor.ResizeNWSE] = SDL_CreateSystemCursor(.SDL_SYSTEM_CURSOR_NWSE_RESIZE);
|
|
bd.MouseCursors[ImGui.MouseCursor.Hand] = SDL_CreateSystemCursor(.SDL_SYSTEM_CURSOR_POINTER);
|
|
bd.MouseCursors[ImGui.MouseCursor.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
|
|
main_viewport : *ImGui.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)
|
|
#if SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH {
|
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
|
}
|
|
|
|
// From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
|
|
#if SDL_HINT_MOUSE_AUTO_CAPTURE {
|
|
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ImGui_ImplSDL3_InitForOpenGL :: (window: *SDL_Window, sdl_gl_context: *void) -> bool {
|
|
return ImGui_ImplSDL3_Init(window, null, sdl_gl_context);
|
|
}
|
|
|
|
ImGui_ImplSDL3_InitForVulkan :: (window: *SDL_Window) -> bool {
|
|
return ImGui_ImplSDL3_Init(window, null, null);
|
|
}
|
|
|
|
ImGui_ImplSDL3_InitForD3D :: (window: *SDL_Window) -> bool {
|
|
#if #exists (_WIN32) {
|
|
assert(0 && "Unsupported");
|
|
}
|
|
return ImGui_ImplSDL3_Init(window, null, null);
|
|
}
|
|
|
|
ImGui_ImplSDL3_InitForMetal :: (window: *SDL_Window) -> bool {
|
|
return ImGui_ImplSDL3_Init(window, null, null);
|
|
}
|
|
|
|
ImGui_ImplSDL3_InitForSDLRenderer :: (window: *SDL_Window, renderer: *SDL_Renderer) -> bool {
|
|
return ImGui_ImplSDL3_Init(window, renderer, null);
|
|
}
|
|
|
|
ImGui_ImplSDL3_InitForOther :: (window: *SDL_Window) -> bool {
|
|
return ImGui_ImplSDL3_Init(window, null, null);
|
|
}
|
|
|
|
ImGui_ImplSDL3_Shutdown :: () {
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
assert(bd != null && "No platform backend to shutdown, or already shutdown?");
|
|
io : *ImGui.IO = ImGui.GetIO();
|
|
|
|
if (bd.ClipboardTextData)
|
|
SDL_free(bd.ClipboardTextData);
|
|
for cursor_n : 0..ImGui.MouseCursor.ImGuiMouseCursor_COUNT - 1
|
|
SDL_DestroyCursor(bd.MouseCursors[cursor_n]);
|
|
ImGui_ImplSDL3_CloseGamepads();
|
|
|
|
io.BackendPlatformName = null;
|
|
io.BackendPlatformUserData = null;
|
|
io.BackendFlags_ &= ~(ImGui.BackendFlags.HasMouseCursors | ImGui.BackendFlags.HasSetMousePos | ImGui.BackendFlags.HasGamepad);
|
|
free(bd);
|
|
}
|
|
|
|
ImGui_ImplSDL3_UpdateMouseData :: () {
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
io : *ImGui.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(xx ifx (bd.MouseButtonsDown != 0) then SDL_TRUE else SDL_FALSE);
|
|
focused_window : *SDL_Window = SDL_GetKeyboardFocus();
|
|
is_app_focused : bool = (bd.Window == focused_window);
|
|
} else {
|
|
focused_window : *SDL_Window = bd.Window;
|
|
is_app_focused : bool = (SDL_GetWindowFlags(bd.Window) & SDL_WINDOW_INPUT_FOCUS) != 0;
|
|
// SDL 2.0.3 and non-windowed systems: single-viewport only
|
|
}
|
|
if (is_app_focused)
|
|
{
|
|
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos 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)
|
|
mouse_x_global, mouse_y_global : float;
|
|
window_x, window_y : s32;
|
|
SDL_GetGlobalMouseState(*mouse_x_global, *mouse_y_global);
|
|
SDL_GetWindowPosition(focused_window, *window_x, *window_y);
|
|
io.AddMousePosEvent(io, mouse_x_global - window_x, mouse_y_global - window_y);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui_ImplSDL3_UpdateMouseCursor :: () {
|
|
io : *ImGui.IO = ImGui.GetIO();
|
|
if (io.ConfigFlags_ & ImGui.ConfigFlags.NoMouseCursorChange)
|
|
return;
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
|
|
imgui_cursor : ImGui.MouseCursor = ImGui.GetMouseCursor();
|
|
if (io.MouseDrawCursor || imgui_cursor == ImGui.MouseCursor.None)
|
|
{
|
|
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
|
SDL_HideCursor();
|
|
}
|
|
else
|
|
{
|
|
// Show OS mouse cursor
|
|
expected_cursor : *SDL_Cursor = ifx bd.MouseCursors[imgui_cursor] then bd.MouseCursors[imgui_cursor] else bd.MouseCursors[ImGui.MouseCursor.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();
|
|
}
|
|
}
|
|
|
|
ImGui_ImplSDL3_CloseGamepads :: () {
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
if (bd.GamepadMode != ImGui_ImplSDL3_GamepadMode.Manual)
|
|
for gamepad : bd.Gamepads
|
|
SDL_CloseGamepad(gamepad);
|
|
array_reset(*bd.Gamepads);
|
|
}
|
|
|
|
ImGui_ImplSDL3_SetGamepadMode :: (mode: ImGui_ImplSDL3_GamepadMode, manual_gamepads_array: **SDL_Gamepad, manual_gamepads_count: s32) {
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
ImGui_ImplSDL3_CloseGamepads();
|
|
if (mode == ImGui_ImplSDL3_GamepadMode.Manual) {
|
|
assert(manual_gamepads_array != null && manual_gamepads_count > 0);
|
|
for n : 0..manual_gamepads_count - 1
|
|
array_add(*bd.Gamepads, manual_gamepads_array[n]);
|
|
} else {
|
|
assert(manual_gamepads_array == null && manual_gamepads_count <= 0);
|
|
bd.WantUpdateGamepadsList = true;
|
|
}
|
|
bd.GamepadMode = mode;
|
|
}
|
|
|
|
ImGui_ImplSDL3_UpdateGamepadButton :: (bd : *ImGui_ImplSDL3_Data, io : *ImGui.IO, key:ImGui.Key, button_no: SDL_GamepadButton) {
|
|
merged_value : bool = false;
|
|
for gamepad : bd.Gamepads
|
|
merged_value |= SDL_GetGamepadButton(gamepad, button_no) != 0;
|
|
io.AddKeyEvent(io, key, merged_value);
|
|
}
|
|
|
|
Saturate :: (v: float) -> float {
|
|
return ifx v < 0.0 then 0.0 else ifx v > 1.0 then 1.0 else v;
|
|
}
|
|
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog :: (bd : *ImGui_ImplSDL3_Data, io : *ImGui.IO, key: ImGui.Key, axis_no: SDL_GamepadAxis, v0: float, v1: float) {
|
|
merged_value : float = 0.0;
|
|
for gamepad : bd.Gamepads{
|
|
vn : float = Saturate(cast(float) (SDL_GetGamepadAxis(gamepad, axis_no) - v0) / cast(float)(v1 - v0));
|
|
if (merged_value < vn)
|
|
merged_value = vn;
|
|
}
|
|
io.AddKeyAnalogEvent(io, key, merged_value > 0.1, merged_value);
|
|
}
|
|
|
|
ImGui_ImplSDL3_UpdateGamepads :: () {
|
|
io : *ImGui.IO = ImGui.GetIO();
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
|
|
// Update list of gamepads to use
|
|
if (bd.WantUpdateGamepadsList && bd.GamepadMode != ImGui_ImplSDL3_GamepadMode.Manual) {
|
|
ImGui_ImplSDL3_CloseGamepads();
|
|
sdl_gamepads_count : s32 = 0;
|
|
sdl_gamepads : *SDL_JoystickID = SDL_GetGamepads(*sdl_gamepads_count);
|
|
for n : 0..sdl_gamepads_count - 1 {
|
|
gamepad : *SDL_Gamepad = SDL_OpenGamepad(sdl_gamepads[n]);
|
|
if gamepad {
|
|
array_add(*bd.Gamepads, gamepad);
|
|
if (bd.GamepadMode == ImGui_ImplSDL3_GamepadMode.AutoFirst)
|
|
break;
|
|
}
|
|
}
|
|
bd.WantUpdateGamepadsList = false;
|
|
}
|
|
|
|
// FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
|
|
if ((io.ConfigFlags_ & ImGui.ConfigFlags.NavEnableGamepad) == 0)
|
|
return;
|
|
io.BackendFlags_ &= ~ImGui.BackendFlags.HasGamepad;
|
|
if (bd.Gamepads.count == 0)
|
|
return;
|
|
io.BackendFlags_ |= ImGui.BackendFlags.HasGamepad;
|
|
|
|
// Update gamepad inputs
|
|
thumb_dead_zone : s32 = 8000; // SDL_gamepad.h suggests using this value.
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadStart, SDL_GAMEPAD_BUTTON_START);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadBack, SDL_GAMEPAD_BUTTON_BACK);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadFaceLeft, SDL_GAMEPAD_BUTTON_WEST); // Xbox X, PS Square
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadFaceRight, SDL_GAMEPAD_BUTTON_EAST); // Xbox B, PS Circle
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadFaceUp, SDL_GAMEPAD_BUTTON_NORTH); // Xbox Y, PS Triangle
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadFaceDown, SDL_GAMEPAD_BUTTON_SOUTH); // Xbox A, PS Cross
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadDpadLeft, SDL_GAMEPAD_BUTTON_DPAD_LEFT);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadDpadRight, SDL_GAMEPAD_BUTTON_DPAD_RIGHT);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadDpadUp, SDL_GAMEPAD_BUTTON_DPAD_UP);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadDpadDown, SDL_GAMEPAD_BUTTON_DPAD_DOWN);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadL1, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadR1, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadL2, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0.0, 32767);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadR2, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0.0, 32767);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadL3, SDL_GAMEPAD_BUTTON_LEFT_STICK);
|
|
ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGui.Key.GamepadR3, SDL_GAMEPAD_BUTTON_RIGHT_STICK);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadLStickLeft, SDL_GAMEPAD_AXIS_LEFTX, xx -thumb_dead_zone, -32768);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadLStickRight, SDL_GAMEPAD_AXIS_LEFTX, xx +thumb_dead_zone, +32767);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadLStickUp, SDL_GAMEPAD_AXIS_LEFTY, xx -thumb_dead_zone, -32768);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadLStickDown, SDL_GAMEPAD_AXIS_LEFTY, xx +thumb_dead_zone, +32767);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadRStickLeft, SDL_GAMEPAD_AXIS_RIGHTX, xx -thumb_dead_zone, -32768);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadRStickRight, SDL_GAMEPAD_AXIS_RIGHTX, xx +thumb_dead_zone, +32767);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadRStickUp, SDL_GAMEPAD_AXIS_RIGHTY, xx -thumb_dead_zone, -32768);
|
|
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGui.Key.GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, xx +thumb_dead_zone, +32767);
|
|
}
|
|
|
|
ImGui_ImplSDL3_NewFrame :: () {
|
|
bd : *ImGui_ImplSDL3_Data = ImGui_ImplSDL3_GetBackendData();
|
|
assert(bd != null && "Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()?");
|
|
io : *ImGui.IO = ImGui.GetIO();
|
|
|
|
// Setup display size (every frame to accommodate for window resizing)
|
|
w, h : s32;
|
|
display_w, display_h : s32;
|
|
SDL_GetWindowSize(bd.Window, *w, *h);
|
|
if (SDL_GetWindowFlags(bd.Window) & SDL_WINDOW_MINIMIZED) {
|
|
w = 0;
|
|
h = 0;
|
|
}
|
|
SDL_GetWindowSizeInPixels(bd.Window, *display_w, *display_h);
|
|
io.DisplaySize = ImGui.ImVec2.{cast(float)w, cast(float)h};
|
|
if (w > 0 && h > 0)
|
|
io.DisplayFramebufferScale = ImGui.ImVec2.{cast(float) display_w / w, cast(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)
|
|
frequency : Uint64 = SDL_GetPerformanceFrequency();
|
|
current_time : Uint64 = SDL_GetPerformanceCounter();
|
|
if (current_time <= bd.Time)
|
|
current_time = bd.Time + 1;
|
|
io.DeltaTime = ifx bd.Time > 0 then cast(float)(cast(float64)(current_time - bd.Time) / frequency) else cast(float)(1.0 / 60.0);
|
|
bd.Time = current_time;
|
|
|
|
if (bd.MousePendingLeaveFrame && bd.MousePendingLeaveFrame >= ImGui.GetFrameCount() && bd.MouseButtonsDown == 0) {
|
|
bd.MouseWindowID = 0;
|
|
bd.MousePendingLeaveFrame = 0;
|
|
io.AddMousePosEvent(io, FLOAT32_MIN, FLOAT32_MAX);
|
|
}
|
|
|
|
ImGui_ImplSDL3_UpdateMouseData();
|
|
ImGui_ImplSDL3_UpdateMouseCursor();
|
|
|
|
// Update game controllers (if enabled and available)
|
|
ImGui_ImplSDL3_UpdateGamepads();
|
|
}
|