cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

imgui_impl_sdl.cpp (17843B)


      1// dear imgui: Platform Binding for SDL2
      2// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
      3// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
      4// (Requires: SDL 2.0. Prefer SDL 2.0.4+ for full feature support.)
      5
      6// Implemented features:
      7//  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
      8//  [X] Platform: Clipboard support.
      9//  [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
     10//  [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
     11// Missing features:
     12//  [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
     13
     14// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
     15// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
     16// https://github.com/ocornut/imgui
     17
     18// CHANGELOG
     19// (minor and older changes stripped away, please see git history for details)
     20//  2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
     21//  2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
     22//  2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
     23//  2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
     24//  2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
     25//  2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
     26//  2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
     27//  2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
     28//  2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
     29//  2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
     30//  2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
     31//  2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
     32//  2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
     33//  2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
     34//  2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
     35//  2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
     36//  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
     37//  2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
     38//  2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
     39//  2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
     40//  2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
     41//  2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
     42//  2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
     43//  2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
     44//  2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
     45
     46#include "imgui.h"
     47#include "imgui_impl_sdl.h"
     48
     49// SDL
     50#include <SDL.h>
     51#include <SDL_syswm.h>
     52#if defined(__APPLE__)
     53#include "TargetConditionals.h"
     54#endif
     55
     56#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE    SDL_VERSION_ATLEAST(2,0,4)
     57#define SDL_HAS_VULKAN                      SDL_VERSION_ATLEAST(2,0,6)
     58
     59// Data
     60static SDL_Window*  g_Window = NULL;
     61static Uint64       g_Time = 0;
     62static bool         g_MousePressed[3] = { false, false, false };
     63static SDL_Cursor*  g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
     64static char*        g_ClipboardTextData = NULL;
     65static bool         g_MouseCanUseGlobalState = true;
     66
     67static const char* ImGui_ImplSDL2_GetClipboardText(void*)
     68{
     69    if (g_ClipboardTextData)
     70        SDL_free(g_ClipboardTextData);
     71    g_ClipboardTextData = SDL_GetClipboardText();
     72    return g_ClipboardTextData;
     73}
     74
     75static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
     76{
     77    SDL_SetClipboardText(text);
     78}
     79
     80// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
     81// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
     82// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
     83// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
     84// 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.
     85bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
     86{
     87    ImGuiIO& io = ImGui::GetIO();
     88    switch (event->type)
     89    {
     90    case SDL_MOUSEWHEEL:
     91        {
     92            if (event->wheel.x > 0) io.MouseWheelH += 1;
     93            if (event->wheel.x < 0) io.MouseWheelH -= 1;
     94            if (event->wheel.y > 0) io.MouseWheel += 1;
     95            if (event->wheel.y < 0) io.MouseWheel -= 1;
     96            return true;
     97        }
     98    case SDL_MOUSEBUTTONDOWN:
     99        {
    100            if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
    101            if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
    102            if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
    103            return true;
    104        }
    105    case SDL_TEXTINPUT:
    106        {
    107            io.AddInputCharactersUTF8(event->text.text);
    108            return true;
    109        }
    110    case SDL_KEYDOWN:
    111    case SDL_KEYUP:
    112        {
    113            int key = event->key.keysym.scancode;
    114            IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
    115            io.KeysDown[key] = (event->type == SDL_KEYDOWN);
    116            io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
    117            io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
    118            io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
    119#ifdef _WIN32
    120            io.KeySuper = false;
    121#else
    122            io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
    123#endif
    124            return true;
    125        }
    126    }
    127    return false;
    128}
    129
    130static bool ImGui_ImplSDL2_Init(SDL_Window* window)
    131{
    132    g_Window = window;
    133
    134    // Setup back-end capabilities flags
    135    ImGuiIO& io = ImGui::GetIO();
    136    io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;       // We can honor GetMouseCursor() values (optional)
    137    io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;        // We can honor io.WantSetMousePos requests (optional, rarely used)
    138    io.BackendPlatformName = "imgui_impl_sdl";
    139
    140    // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
    141    io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
    142    io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
    143    io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
    144    io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
    145    io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
    146    io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
    147    io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
    148    io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
    149    io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
    150    io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
    151    io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
    152    io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
    153    io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
    154    io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
    155    io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
    156    io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_KP_ENTER;
    157    io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
    158    io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
    159    io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
    160    io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
    161    io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
    162    io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
    163
    164    io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
    165    io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
    166    io.ClipboardUserData = NULL;
    167
    168    // Load mouse cursors
    169    g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
    170    g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
    171    g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
    172    g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
    173    g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
    174    g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
    175    g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
    176    g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
    177    g_MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
    178
    179    // Check and store if we are on Wayland
    180    g_MouseCanUseGlobalState = strncmp(SDL_GetCurrentVideoDriver(), "wayland", 7) != 0;
    181
    182#ifdef _WIN32
    183    SDL_SysWMinfo wmInfo;
    184    SDL_VERSION(&wmInfo.version);
    185    SDL_GetWindowWMInfo(window, &wmInfo);
    186    io.ImeWindowHandle = wmInfo.info.win.window;
    187#else
    188    (void)window;
    189#endif
    190
    191    return true;
    192}
    193
    194bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
    195{
    196    (void)sdl_gl_context; // Viewport branch will need this.
    197    return ImGui_ImplSDL2_Init(window);
    198}
    199
    200bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
    201{
    202#if !SDL_HAS_VULKAN
    203    IM_ASSERT(0 && "Unsupported");
    204#endif
    205    return ImGui_ImplSDL2_Init(window);
    206}
    207
    208bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
    209{
    210#if !defined(_WIN32)
    211    IM_ASSERT(0 && "Unsupported");
    212#endif
    213    return ImGui_ImplSDL2_Init(window);
    214}
    215
    216bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
    217{
    218    return ImGui_ImplSDL2_Init(window);
    219}
    220
    221void ImGui_ImplSDL2_Shutdown()
    222{
    223    g_Window = NULL;
    224
    225    // Destroy last known clipboard data
    226    if (g_ClipboardTextData)
    227        SDL_free(g_ClipboardTextData);
    228    g_ClipboardTextData = NULL;
    229
    230    // Destroy SDL mouse cursors
    231    for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
    232        SDL_FreeCursor(g_MouseCursors[cursor_n]);
    233    memset(g_MouseCursors, 0, sizeof(g_MouseCursors));
    234}
    235
    236static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
    237{
    238    ImGuiIO& io = ImGui::GetIO();
    239
    240    // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
    241    if (io.WantSetMousePos)
    242        SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
    243    else
    244        io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
    245
    246    int mx, my;
    247    Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my);
    248    io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;  // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
    249    io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
    250    io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
    251    g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
    252
    253#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
    254    SDL_Window* focused_window = SDL_GetKeyboardFocus();
    255    if (g_Window == focused_window)
    256    {
    257        if (g_MouseCanUseGlobalState)
    258        {
    259            // SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
    260            // The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
    261            // Won't use this workaround when on Wayland, as there is no global mouse position.
    262            int wx, wy;
    263            SDL_GetWindowPosition(focused_window, &wx, &wy);
    264            SDL_GetGlobalMouseState(&mx, &my);
    265            mx -= wx;
    266            my -= wy;
    267        }
    268        io.MousePos = ImVec2((float)mx, (float)my);
    269    }
    270
    271    // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
    272    // The function is only supported from SDL 2.0.4 (released Jan 2016)
    273    bool any_mouse_button_down = ImGui::IsAnyMouseDown();
    274    SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE);
    275#else
    276    if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
    277        io.MousePos = ImVec2((float)mx, (float)my);
    278#endif
    279}
    280
    281static void ImGui_ImplSDL2_UpdateMouseCursor()
    282{
    283    ImGuiIO& io = ImGui::GetIO();
    284    if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
    285        return;
    286
    287    ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
    288    if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
    289    {
    290        // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
    291        SDL_ShowCursor(SDL_FALSE);
    292    }
    293    else
    294    {
    295        // Show OS mouse cursor
    296        SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
    297        SDL_ShowCursor(SDL_TRUE);
    298    }
    299}
    300
    301static void ImGui_ImplSDL2_UpdateGamepads()
    302{
    303    ImGuiIO& io = ImGui::GetIO();
    304    memset(io.NavInputs, 0, sizeof(io.NavInputs));
    305    if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
    306        return;
    307
    308    // Get gamepad
    309    SDL_GameController* game_controller = SDL_GameControllerOpen(0);
    310    if (!game_controller)
    311    {
    312        io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
    313        return;
    314    }
    315
    316    // Update gamepad inputs
    317    #define MAP_BUTTON(NAV_NO, BUTTON_NO)       { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; }
    318    #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
    319    const int thumb_dead_zone = 8000;           // SDL_gamecontroller.h suggests using this value.
    320    MAP_BUTTON(ImGuiNavInput_Activate,      SDL_CONTROLLER_BUTTON_A);               // Cross / A
    321    MAP_BUTTON(ImGuiNavInput_Cancel,        SDL_CONTROLLER_BUTTON_B);               // Circle / B
    322    MAP_BUTTON(ImGuiNavInput_Menu,          SDL_CONTROLLER_BUTTON_X);               // Square / X
    323    MAP_BUTTON(ImGuiNavInput_Input,         SDL_CONTROLLER_BUTTON_Y);               // Triangle / Y
    324    MAP_BUTTON(ImGuiNavInput_DpadLeft,      SDL_CONTROLLER_BUTTON_DPAD_LEFT);       // D-Pad Left
    325    MAP_BUTTON(ImGuiNavInput_DpadRight,     SDL_CONTROLLER_BUTTON_DPAD_RIGHT);      // D-Pad Right
    326    MAP_BUTTON(ImGuiNavInput_DpadUp,        SDL_CONTROLLER_BUTTON_DPAD_UP);         // D-Pad Up
    327    MAP_BUTTON(ImGuiNavInput_DpadDown,      SDL_CONTROLLER_BUTTON_DPAD_DOWN);       // D-Pad Down
    328    MAP_BUTTON(ImGuiNavInput_FocusPrev,     SDL_CONTROLLER_BUTTON_LEFTSHOULDER);    // L1 / LB
    329    MAP_BUTTON(ImGuiNavInput_FocusNext,     SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);   // R1 / RB
    330    MAP_BUTTON(ImGuiNavInput_TweakSlow,     SDL_CONTROLLER_BUTTON_LEFTSHOULDER);    // L1 / LB
    331    MAP_BUTTON(ImGuiNavInput_TweakFast,     SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);   // R1 / RB
    332    MAP_ANALOG(ImGuiNavInput_LStickLeft,    SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
    333    MAP_ANALOG(ImGuiNavInput_LStickRight,   SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
    334    MAP_ANALOG(ImGuiNavInput_LStickUp,      SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767);
    335    MAP_ANALOG(ImGuiNavInput_LStickDown,    SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
    336
    337    io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
    338    #undef MAP_BUTTON
    339    #undef MAP_ANALOG
    340}
    341
    342void ImGui_ImplSDL2_NewFrame(SDL_Window* window)
    343{
    344    ImGuiIO& io = ImGui::GetIO();
    345    IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
    346
    347    // Setup display size (every frame to accommodate for window resizing)
    348    int w, h;
    349    int display_w, display_h;
    350    SDL_GetWindowSize(window, &w, &h);
    351    SDL_GL_GetDrawableSize(window, &display_w, &display_h);
    352    io.DisplaySize = ImVec2((float)w, (float)h);
    353    if (w > 0 && h > 0)
    354        io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
    355
    356    // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
    357    static Uint64 frequency = SDL_GetPerformanceFrequency();
    358    Uint64 current_time = SDL_GetPerformanceCounter();
    359    io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
    360    g_Time = current_time;
    361
    362    ImGui_ImplSDL2_UpdateMousePosAndButtons();
    363    ImGui_ImplSDL2_UpdateMouseCursor();
    364
    365    // Update game controllers (if enabled and available)
    366    ImGui_ImplSDL2_UpdateGamepads();
    367}