diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 75c54670..d4d0b5a3 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -16,7 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 7b026365..804d20ad 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -16,7 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index cfec286b..31ee7372 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -25,7 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 0aeb43dc..2f03fa6e 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -16,7 +16,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575) // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1. @@ -330,6 +331,24 @@ void ImGui_ImplDX9_Shutdown() IM_DELETE(bd); } +static bool ImGui_ImplDX9_CheckFormatSupport(IDirect3DDevice9* pDevice, D3DFORMAT format) +{ + IDirect3D9* pd3d = nullptr; + if (pDevice->GetDirect3D(&pd3d) != D3D_OK) + return false; + D3DDEVICE_CREATION_PARAMETERS param = {}; + D3DDISPLAYMODE mode = {}; + if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK) + { + pd3d->Release(); + return false; + } + // Font texture should support linear filter, color blend and write to render-target + bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK; + pd3d->Release(); + return support; +} + static bool ImGui_ImplDX9_CreateFontsTexture() { // Build texture atlas @@ -341,18 +360,21 @@ static bool ImGui_ImplDX9_CreateFontsTexture() // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) #ifndef IMGUI_USE_BGRA_PACKED_COLOR - if (io.Fonts->TexPixelsUseColors) + const bool rgba_support = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); + if (!rgba_support && io.Fonts->TexPixelsUseColors) { ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) *dst = IMGUI_COL_TO_DX9_ARGB(*src); pixels = (unsigned char*)dst_start; } +#else + const bool rgba_support = false; #endif // Upload texture to graphics system bd->FontTexture = nullptr; - if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) + if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, rgba_support ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) return false; D3DLOCKED_RECT tex_locked_rect; if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) @@ -365,7 +387,7 @@ static bool ImGui_ImplDX9_CreateFontsTexture() io.Fonts->SetTexID((ImTextureID)bd->FontTexture); #ifndef IMGUI_USE_BGRA_PACKED_COLOR - if (io.Fonts->TexPixelsUseColors) + if (!rgba_support && io.Fonts->TexPixelsUseColors) ImGui::MemFree(pixels); #endif diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index a4beb26d..53303e93 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -24,7 +24,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2023-12-19: Emscripten: Added ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to register canvas selector and auto-resize GLFW window. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys. // 2023-07-18: Inputs: Revert ignoring mouse data on GLFW_CURSOR_DISABLED as it can be used differently. User may set ImGuiConfigFLags_NoMouse if desired. (#5625, #6609) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 20754d65..bae0468d 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -16,7 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. // 2022-07-05: Metal: Add dispatch synchronization. // 2022-06-30: Metal: Use __bridge for ARC based systems. diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index f2c82179..30cf50f5 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -23,7 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-12-08: OpenGL: Fixed mishandling of the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index eaa508e5..0be98b63 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,7 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-01-09: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" and variants, fixing regression on distros missing a symlink. // 2023-11-08: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" instead of "libGL.so.1", accommodating for NetBSD systems having only "libGL.so.3" available. (#6983) // 2023-10-05: OpenGL: Rename symbols in our internal loader so that LTO compilation with another copy of gl3w is possible. (#6875, #6668, #4445) diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 229f3459..908ee84d 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -31,7 +31,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F20 function keys. Stopped mapping F13 into PrintScreen. // 2023-04-09: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_Pen. // 2023-02-01: Fixed scroll wheel scaling for devices emitting events with hasPreciseScrollingDeltas==false (e.g. non-Apple mices). diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 65fa70f8..f101cf3e 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -24,7 +24,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-02-14: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadMode(). // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. // 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) @@ -116,19 +117,26 @@ static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; // SDL Data struct ImGui_ImplSDL2_Data { - SDL_Window* Window; - SDL_Renderer* Renderer; - Uint64 Time; - Uint32 MouseWindowID; - int MouseButtonsDown; - SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; - SDL_Cursor* LastMouseCursor; - int PendingMouseLeaveFrame; - char* ClipboardTextData; - bool MouseCanUseGlobalState; - bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. - bool UseVulkan; - bool WantUpdateMonitors; + SDL_Window* Window; + SDL_Renderer* Renderer; + Uint64 Time; + char* ClipboardTextData; + bool UseVulkan; + bool WantUpdateMonitors; + + // Mouse handling + Uint32 MouseWindowID; + int MouseButtonsDown; + SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; + SDL_Cursor* MouseLastCursor; + int MouseLastLeaveFrame; + bool MouseCanUseGlobalState; + bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. + + // Gamepad handling + ImVector Gamepads; + ImGui_ImplSDL2_GamepadMode GamepadMode; + bool WantUpdateGamepadsList; ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -405,10 +413,10 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) if (window_event == SDL_WINDOWEVENT_ENTER) { bd->MouseWindowID = event->window.windowID; - bd->PendingMouseLeaveFrame = 0; + bd->MouseLastLeaveFrame = 0; } if (window_event == SDL_WINDOWEVENT_LEAVE) - bd->PendingMouseLeaveFrame = ImGui::GetFrameCount() + 1; + bd->MouseLastLeaveFrame = ImGui::GetFrameCount() + 1; if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) io.AddFocusEvent(true); else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) @@ -426,6 +434,12 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } return true; } + case SDL_CONTROLLERDEVICEADDED: + case SDL_CONTROLLERDEVICEREMOVED: + { + bd->WantUpdateGamepadsList = true; + return true; + } } return false; } @@ -473,6 +487,10 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void io.ClipboardUserData = nullptr; io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData; + // Gamepad handling + bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; + bd->WantUpdateGamepadsList = true; + // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); @@ -569,6 +587,8 @@ bool ImGui_ImplSDL2_InitForOther(SDL_Window* window) return ImGui_ImplSDL2_Init(window, nullptr, nullptr); } +static void ImGui_ImplSDL2_CloseGamepads(); + void ImGui_ImplSDL2_Shutdown() { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); @@ -581,7 +601,7 @@ void ImGui_ImplSDL2_Shutdown() SDL_free(bd->ClipboardTextData); for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) SDL_FreeCursor(bd->MouseCursors[cursor_n]); - bd->LastMouseCursor = nullptr; + ImGui_ImplSDL2_CloseGamepads(); io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; @@ -670,59 +690,118 @@ static void ImGui_ImplSDL2_UpdateMouseCursor() { // Show OS mouse cursor SDL_Cursor* expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]; - if (bd->LastMouseCursor != expected_cursor) + if (bd->MouseLastCursor != expected_cursor) { SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113) - bd->LastMouseCursor = expected_cursor; + bd->MouseLastCursor = expected_cursor; } SDL_ShowCursor(SDL_TRUE); } } +static void ImGui_ImplSDL2_CloseGamepads() +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + if (bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual) + for (SDL_GameController* gamepad : bd->Gamepads) + SDL_GameControllerClose(gamepad); + bd->Gamepads.resize(0); +} + +void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array, int manual_gamepads_count) +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + ImGui_ImplSDL2_CloseGamepads(); + if (mode == ImGui_ImplSDL2_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_ImplSDL2_UpdateGamepadButton(ImGui_ImplSDL2_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GameControllerButton button_no) +{ + bool merged_value = false; + for (SDL_GameController* gamepad : bd->Gamepads) + merged_value |= SDL_GameControllerGetButton(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_ImplSDL2_UpdateGamepadAnalog(ImGui_ImplSDL2_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GameControllerAxis axis_no, float v0, float v1) +{ + float merged_value = 0.0f; + for (SDL_GameController* gamepad : bd->Gamepads) + { + float vn = Saturate((float)(SDL_GameControllerGetAxis(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_ImplSDL2_UpdateGamepads() { + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); ImGuiIO& io = ImGui::GetIO(); - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - return; - // Get gamepad + // Update list of controller(s) to use + if (bd->WantUpdateGamepadsList && bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual) + { + ImGui_ImplSDL2_CloseGamepads(); + int joystick_count = SDL_NumJoysticks(); + for (int n = 0; n < joystick_count; n++) + if (SDL_IsGameController(n)) + if (SDL_GameController* gamepad = SDL_GameControllerOpen(n)) + { + bd->Gamepads.push_back(gamepad); + if (bd->GamepadMode == ImGui_ImplSDL2_GamepadMode_AutoFirst) + break; + } + bd->WantUpdateGamepadsList = false; + } + + // 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; - SDL_GameController* game_controller = SDL_GameControllerOpen(0); - if (!game_controller) + if (bd->Gamepads.Size == 0) return; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; // Update gamepad inputs - #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) - #define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0); } - #define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); } - const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. - MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START); - MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK); - MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square - MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle - MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle - MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross - MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); - MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); - MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); - MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); - MAP_BUTTON(ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); - MAP_BUTTON(ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); - MAP_ANALOG(ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767); - MAP_ANALOG(ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767); - MAP_BUTTON(ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK); - MAP_BUTTON(ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK); - MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767); - #undef MAP_BUTTON - #undef MAP_ANALOG + const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767); } // FIXME: Note that doesn't update with DPI/Scaling change only as SDL2 doesn't have an event for it (SDL3 has). @@ -791,10 +870,10 @@ void ImGui_ImplSDL2_NewFrame() io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f); bd->Time = current_time; - if (bd->PendingMouseLeaveFrame && bd->PendingMouseLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) + if (bd->MouseLastLeaveFrame && bd->MouseLastLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) { bd->MouseWindowID = 0; - bd->PendingMouseLeaveFrame = 0; + bd->MouseLastLeaveFrame = 0; io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); } diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index dee37fb6..2970772e 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -27,6 +27,7 @@ struct SDL_Window; struct SDL_Renderer; +struct _SDL_GameController; typedef union SDL_Event SDL_Event; IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); @@ -39,8 +40,9 @@ IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(); IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter -#endif +// 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_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; +IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = NULL, int manual_gamepads_count = -1); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 870dded5..8eccaa89 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -24,7 +24,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 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) @@ -64,19 +65,26 @@ // SDL Data struct ImGui_ImplSDL3_Data { - SDL_Window* Window; - SDL_Renderer* Renderer; - Uint64 Time; - Uint32 MouseWindowID; - int MouseButtonsDown; - SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; - SDL_Cursor* LastMouseCursor; - int PendingMouseLeaveFrame; - char* ClipboardTextData; - bool MouseCanUseGlobalState; - bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. - bool UseVulkan; - bool WantUpdateMonitors; + SDL_Window* Window; + SDL_Renderer* Renderer; + Uint64 Time; + char* ClipboardTextData; + bool UseVulkan; + bool WantUpdateMonitors; + + // Mouse handling + Uint32 MouseWindowID; + int MouseButtonsDown; + SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; + SDL_Cursor* MouseLastCursor; + int MousePendingLeaveFrame; + bool MouseCanUseGlobalState; + bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. + + // Gamepad handling + ImVector Gamepads; + ImGui_ImplSDL3_GamepadMode GamepadMode; + bool WantUpdateGamepadsList; ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -339,7 +347,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_WINDOW_MOUSE_ENTER: { bd->MouseWindowID = event->window.windowID; - bd->PendingMouseLeaveFrame = 0; + 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, @@ -348,7 +356,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // FIXME: Unconfirmed whether this is still needed with SDL3. case SDL_EVENT_WINDOW_MOUSE_LEAVE: { - bd->PendingMouseLeaveFrame = ImGui::GetFrameCount() + 1; + bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1; return true; } case SDL_EVENT_WINDOW_FOCUS_GAINED: @@ -371,6 +379,12 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) return true; } return true; + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: + { + bd->WantUpdateGamepadsList = true; + return true; + } } return false; } @@ -430,6 +444,10 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void io.ClipboardUserData = nullptr; io.SetPlatformImeDataFn = ImGui_ImplSDL3_SetPlatformImeData; + // Gamepad handling + bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst; + bd->WantUpdateGamepadsList = true; + // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); @@ -504,6 +522,8 @@ 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(); @@ -516,7 +536,7 @@ void ImGui_ImplSDL3_Shutdown() SDL_free(bd->ClipboardTextData); for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) SDL_DestroyCursor(bd->MouseCursors[cursor_n]); - bd->LastMouseCursor = nullptr; + ImGui_ImplSDL3_CloseGamepads(); io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; @@ -605,59 +625,118 @@ static void ImGui_ImplSDL3_UpdateMouseCursor() { // Show OS mouse cursor SDL_Cursor* expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]; - if (bd->LastMouseCursor != expected_cursor) + if (bd->MouseLastCursor != expected_cursor) { SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113) - bd->LastMouseCursor = expected_cursor; + 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(); - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - return; + 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; + } - // Get gamepad + // 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; - SDL_Gamepad* gamepad = SDL_OpenGamepad(0); - if (!gamepad) + if (bd->Gamepads.Size == 0) return; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; // Update gamepad inputs - #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) - #define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GetGamepadButton(gamepad, BUTTON_NO) != 0); } - #define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GetGamepadAxis(gamepad, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); } - const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. - MAP_BUTTON(ImGuiKey_GamepadStart, SDL_GAMEPAD_BUTTON_START); - MAP_BUTTON(ImGuiKey_GamepadBack, SDL_GAMEPAD_BUTTON_BACK); - MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_GAMEPAD_BUTTON_WEST); // Xbox X, PS Square - MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_GAMEPAD_BUTTON_EAST); // Xbox B, PS Circle - MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_GAMEPAD_BUTTON_NORTH); // Xbox Y, PS Triangle - MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_GAMEPAD_BUTTON_SOUTH); // Xbox A, PS Cross - MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_GAMEPAD_BUTTON_DPAD_LEFT); - MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_GAMEPAD_BUTTON_DPAD_RIGHT); - MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_GAMEPAD_BUTTON_DPAD_UP); - MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_GAMEPAD_BUTTON_DPAD_DOWN); - MAP_BUTTON(ImGuiKey_GamepadL1, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER); - MAP_BUTTON(ImGuiKey_GamepadR1, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER); - MAP_ANALOG(ImGuiKey_GamepadL2, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0.0f, 32767); - MAP_ANALOG(ImGuiKey_GamepadR2, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0.0f, 32767); - MAP_BUTTON(ImGuiKey_GamepadL3, SDL_GAMEPAD_BUTTON_LEFT_STICK); - MAP_BUTTON(ImGuiKey_GamepadR3, SDL_GAMEPAD_BUTTON_RIGHT_STICK); - MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_GAMEPAD_AXIS_LEFTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_GAMEPAD_AXIS_LEFTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_GAMEPAD_AXIS_LEFTY, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_GAMEPAD_AXIS_LEFTY, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadRStickLeft, SDL_GAMEPAD_AXIS_RIGHTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadRStickRight, SDL_GAMEPAD_AXIS_RIGHTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadRStickUp, SDL_GAMEPAD_AXIS_RIGHTY, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767); - #undef MAP_BUTTON - #undef MAP_ANALOG + 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); } static void ImGui_ImplSDL3_UpdateMonitors() @@ -719,10 +798,10 @@ void ImGui_ImplSDL3_NewFrame() io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f); bd->Time = current_time; - if (bd->PendingMouseLeaveFrame && bd->PendingMouseLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) + if (bd->MousePendingLeaveFrame && bd->MousePendingLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) { bd->MouseWindowID = 0; - bd->PendingMouseLeaveFrame = 0; + bd->MousePendingLeaveFrame = 0; io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); } diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index 1a4b3170..18ab945a 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -28,6 +28,7 @@ struct SDL_Window; struct SDL_Renderer; +struct SDL_Gamepad; typedef union SDL_Event SDL_Event; IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); @@ -40,4 +41,9 @@ 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/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 29671be0..6675356e 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -22,6 +22,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2024-02-12: Amend to query SDL_RenderViewportSet() and restore viewport accordingly. // 2023-05-30: Initial version. #include "imgui.h" @@ -131,10 +132,12 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data) struct BackupSDLRendererState { SDL_Rect Viewport; + bool ViewportEnabled; bool ClipEnabled; SDL_Rect ClipRect; }; BackupSDLRendererState old = {}; + old.ViewportEnabled = SDL_RenderViewportSet(bd->SDLRenderer) == SDL_TRUE; old.ClipEnabled = SDL_RenderClipEnabled(bd->SDLRenderer) == SDL_TRUE; SDL_GetRenderViewport(bd->SDLRenderer, &old.Viewport); SDL_GetRenderClipRect(bd->SDLRenderer, &old.ClipRect); @@ -180,11 +183,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data) 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)); -#if SDL_VERSION_ATLEAST(2,0,19) const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+ -#else - const int* color = (const int*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18 -#endif // Bind texture, Draw SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); @@ -199,7 +198,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data) } // Restore modified SDL_Renderer state - SDL_SetRenderViewport(bd->SDLRenderer, &old.Viewport); + SDL_SetRenderViewport(bd->SDLRenderer, old.ViewportEnabled ? &old.Viewport : nullptr); SDL_SetRenderClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : nullptr); } diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index b6ca9be8..505c2a77 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -35,10 +35,12 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-02-14: *BREAKING CHANGE*: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering. +// 2024-02-12: *BREAKING CHANGE*: Dynamic rendering now require filling PipelineRenderingCreateInfo structure. // 2024-01-19: Vulkan: Fixed vkAcquireNextImageKHR() validation errors in VulkanSDK 1.3.275 by allocating one extra semaphore than in-flight frames. (#7236) // 2024-01-11: Vulkan: Fixed vkMapMemory() calls unnecessarily using full buffer size (#3957). Fixed MinAllocationSize handing (#7189). // 2024-01-03: Vulkan: Added MinAllocationSize field in ImGui_ImplVulkan_InitInfo to workaround zealous "best practice" validation layer. (#7189, #4238) -// 2024-01-03: Vulkan: Stoped creating command pools with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT as we don't reset them. +// 2024-01-03: Vulkan: Stopped creating command pools with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT as we don't reset them. // 2023-11-29: Vulkan: Fixed mismatching allocator passed to vkCreateCommandPool() vs vkDestroyCommandPool(). (#7075) // 2023-11-10: *BREAKING CHANGE*: Removed parameter from ImGui_ImplVulkan_CreateFontsTexture(): backend now creates its own command-buffer to upload fonts. // *BREAKING CHANGE*: Removed ImGui_ImplVulkan_DestroyFontUploadObjects() which is now unecessary as we create and destroy those objects in the backend. @@ -194,8 +196,7 @@ IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF) #undef IMGUI_VULKAN_FUNC_DEF #endif // VK_NO_PROTOTYPES -#if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering) -#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING static PFN_vkCmdBeginRenderingKHR ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR; static PFN_vkCmdEndRenderingKHR ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR; #endif @@ -237,13 +238,11 @@ struct ImGui_ImplVulkan_ViewportData struct ImGui_ImplVulkan_Data { ImGui_ImplVulkan_InitInfo VulkanInitInfo; - VkRenderPass RenderPass; VkDeviceSize BufferMemoryAlignment; VkPipelineCreateFlags PipelineCreateFlags; VkDescriptorSetLayout DescriptorSetLayout; VkPipelineLayout PipelineLayout; VkPipeline Pipeline; - uint32_t Subpass; VkShaderModule ShaderModuleVert; VkShaderModule ShaderModuleFrag; @@ -981,13 +980,11 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC info.subpass = subpass; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - VkPipelineRenderingCreateInfoKHR pipelineRenderingCreateInfo = {}; - pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR; - pipelineRenderingCreateInfo.colorAttachmentCount = 1; - pipelineRenderingCreateInfo.pColorAttachmentFormats = &bd->VulkanInitInfo.ColorAttachmentFormat; if (bd->VulkanInitInfo.UseDynamicRendering) { - info.pNext = &pipelineRenderingCreateInfo; + IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR"); + IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be NULL"); + info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo; info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. } #endif @@ -1052,7 +1049,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, bd->RenderPass, v->MSAASamples, &bd->Pipeline, bd->Subpass); + ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, &bd->Pipeline, v->Subpass); return true; } @@ -1102,7 +1099,7 @@ bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const ch return true; } -bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass) +bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) { IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!"); @@ -1138,11 +1135,9 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend IM_ASSERT(info->MinImageCount >= 2); IM_ASSERT(info->ImageCount >= info->MinImageCount); if (info->UseDynamicRendering == false) - IM_ASSERT(render_pass != VK_NULL_HANDLE); + IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); bd->VulkanInitInfo = *info; - bd->RenderPass = render_pass; - bd->Subpass = info->Subpass; ImGui_ImplVulkan_CreateDeviceObjects(); @@ -1538,7 +1533,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V // We do not create a pipeline by default as this is also used by examples' main.cpp, // but secondary viewport in multi-viewport mode may want to create one with: - //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, bd->Subpass); + //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, v->Subpass); } // Create The Image Views diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 98c1d7ed..e1bbb4e2 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -53,8 +53,14 @@ #else #include #endif +#if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering) +#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING +#endif // Initialization data, for ImGui_ImplVulkan_Init() +// - VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, +// and must contain a pool size large enough to hold an ImGui VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor. +// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. // [Please zero-clear before use!] struct ImGui_ImplVulkan_InitInfo { @@ -63,25 +69,31 @@ struct ImGui_ImplVulkan_InitInfo VkDevice Device; uint32_t QueueFamily; VkQueue Queue; + VkDescriptorPool DescriptorPool; // See requirements in note above + VkRenderPass RenderPass; // Ignored if using dynamic rendering + uint32_t MinImageCount; // >= 2 + uint32_t ImageCount; // >= MinImageCount + VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT + + // (Optional) VkPipelineCache PipelineCache; - VkDescriptorPool DescriptorPool; uint32_t Subpass; - uint32_t MinImageCount; // >= 2 - uint32_t ImageCount; // >= MinImageCount - VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT (0 -> default to VK_SAMPLE_COUNT_1_BIT) - // Dynamic Rendering (Optional) - bool UseDynamicRendering; // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. - VkFormat ColorAttachmentFormat; // Required for dynamic rendering + // (Optional) Dynamic Rendering + // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. + bool UseDynamicRendering; +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; +#endif - // Allocation, Debugging + // (Optional) Allocation, Debugging const VkAllocationCallbacks* Allocator; void (*CheckVkResultFn)(VkResult err); VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. }; // Called by user code -IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); +IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 924f2f1d..b14ae1ab 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -40,7 +40,7 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*); // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. // 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL). // 2023-09-07: Inputs: Added support for keyboard codepage conversion for when application is compiled in MBCS mode and using a non-Unicode window. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 350e73c2..5d25f80f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,7 +36,42 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.90.2 (Released 2024-01-09) + VERSION 1.90.3 (Released 2024-02-14) +----------------------------------------------------------------------- + +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.90.3 + +Breaking changes: + +- Backends: SDL2: Removed obsolete ImGui_ImplSDL2_NewFrame(SDL_Window*) signature which + was obsoleted in 1.84. Calling ImGui_ImplSDL2_NewFrame() is fine. +- Backends: Vulkan: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to + ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering. (#7308) [@shawnhatori] +- Backends: Vulkan: Using dynamic rendering now require filling the PipelineRenderingCreateInfo + structure in ImGui_ImplVulkan_InitInfo, allowing to configure color/depth/stencil formats. + Removed ColorAttachmentFormat field previously provided for dynamic rendering. + (#7166, #6855, #5446, #5037) [@shawnhatori] + +Other changes: + +- Menus, Popups: Fixed menus and popups with ChildWindow flag erroneously not displaying + a scrollbar when contents is over parent viewport size. (#7287, #7063) [@ZingBallyhoo] +- Backends: SDL2, SDL3: Handle gamepad disconnection + fixed increasing gamepad reference + counter continuously. Added support for multiple simultaneous gamepads. + Added ImGui_ImplSDL2_SetGamepadMode()) function to select whether to automatically pick + first available gamepad, all gamepads, or specific gamepads. + (#3884, #6559, #6890, #7180) [@ocornut, @lethal-guitar, @wn2000, @bog-dan-ro] +- BackendsL SDL3: Fixed gamepad handling. (#7180) [@bog-dan-ro] +- Backends: SDLRenderer3: query newly added SDL_RenderViewportSet() to not restore + a wrong viewport if none was initially set. +- Backends: DirectX9: Using RGBA format when allowed by the driver to avoid CPU side + conversion. (#6575) [@Demonese] +- Internals: Fixed ImFileOpen not working before context is created, preventing creation + of a font atlas before main context creation. (#7314, #7315) [@PathogenDavid, @ocornut] + + +----------------------------------------------------------------------- + VERSION 1.90.2 (Released 2024-02-09) ----------------------------------------------------------------------- Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.90.2 diff --git a/examples/example_glfw_metal/Makefile b/examples/example_glfw_metal/Makefile index 82d5ac96..32a7aeca 100644 --- a/examples/example_glfw_metal/Makefile +++ b/examples/example_glfw_metal/Makefile @@ -14,10 +14,10 @@ SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) LIBS = -framework Metal -framework MetalKit -framework Cocoa -framework IOKit -framework CoreVideo -framework QuartzCore -LIBS += -L/usr/local/lib -L/opt/homebrew/lib +LIBS += -L/usr/local/lib -L/opt/homebrew/lib -L/opt/local/lib LIBS += -lglfw -CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I/usr/local/include -I/opt/homebrew/include +CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I/usr/local/include -I/opt/homebrew/include -I/opt/local/include CXXFLAGS += -Wall -Wformat CFLAGS = $(CXXFLAGS) diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index e4ed9c45..c852e5f4 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -446,13 +446,14 @@ int main(int, char**) init_info.Queue = g_Queue; init_info.PipelineCache = g_PipelineCache; init_info.DescriptorPool = g_DescriptorPool; + init_info.RenderPass = wd->RenderPass; init_info.Subpass = 0; init_info.MinImageCount = g_MinImageCount; init_info.ImageCount = wd->ImageCount; init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; init_info.Allocator = g_Allocator; init_info.CheckVkResultFn = check_vk_result; - ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); + ImGui_ImplVulkan_Init(&init_info); // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 54ffa7dd..3fdba88b 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -446,13 +446,14 @@ int main(int, char**) init_info.Queue = g_Queue; init_info.PipelineCache = g_PipelineCache; init_info.DescriptorPool = g_DescriptorPool; + init_info.RenderPass = wd->RenderPass; init_info.Subpass = 0; init_info.MinImageCount = g_MinImageCount; init_info.ImageCount = wd->ImageCount; init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; init_info.Allocator = g_Allocator; init_info.CheckVkResultFn = check_vk_result; - ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); + ImGui_ImplVulkan_Init(&init_info); // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. diff --git a/imgui.cpp b/imgui.cpp index 5635f19a..1a02470f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 // (main code and documentation) // Help: @@ -2121,12 +2121,18 @@ ImFileHandle ImFileOpen(const char* filename, const char* mode) // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0); - ImGuiContext& g = *GImGui; - g.TempBuffer.reserve((filename_wsize + mode_wsize) * sizeof(wchar_t)); - wchar_t* buf = (wchar_t*)(void*)g.TempBuffer.Data; - ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize); - ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize); - return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]); + + // Use stack buffer if possible, otherwise heap buffer. Sizes include zero terminator. + // We don't rely on current ImGuiContext as this is implied to be a helper function which doesn't depend on it (see #7314). + wchar_t local_temp_stack[FILENAME_MAX]; + ImVector local_temp_heap; + if (filename_wsize + mode_wsize > IM_ARRAYSIZE(local_temp_stack)) + local_temp_heap.resize(filename_wsize + mode_wsize); + wchar_t* filename_wbuf = local_temp_heap.Data ? local_temp_heap.Data : local_temp_stack; + wchar_t* mode_wbuf = filename_wbuf + filename_wsize; + ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, filename_wbuf, filename_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_wbuf, mode_wsize); + return ::_wfopen(filename_wbuf, mode_wbuf); #else return fopen(filename, mode); #endif @@ -6048,7 +6054,7 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont { // Maximum window size is determined by the viewport size or monitor size ImVec2 size_min = CalcWindowMinSize(window); - ImVec2 size_max = (window->ViewportOwned || (window->Flags & ImGuiWindowFlags_ChildWindow)) ? ImVec2(FLT_MAX, FLT_MAX) : window->Viewport->WorkSize - style.DisplaySafeAreaPadding * 2.0f; + ImVec2 size_max = (window->ViewportOwned || ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup))) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f; const int monitor_idx = window->ViewportAllowPlatformMonitorExtend; if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0) size_max = g.PlatformIO.Monitors[monitor_idx].WorkSize - style.DisplaySafeAreaPadding * 2.0f; diff --git a/imgui.h b/imgui.h index 110db607..e99a84e9 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 // (headers) // Help: @@ -23,8 +23,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.90.2" -#define IMGUI_VERSION_NUM 19020 +#define IMGUI_VERSION "1.90.3" +#define IMGUI_VERSION_NUM 19030 #define IMGUI_HAS_TABLE #define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_DOCK // Docking WIP branch diff --git a/imgui_demo.cpp b/imgui_demo.cpp index fc13f673..775900be 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5840a4df..d2c2e6a4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 56ead550..61d78d11 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 5052dee1..36c4c95b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6cfeeda8..0b5dc5bc 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 // (widgets code) /* @@ -2001,7 +2001,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*old_getter)(void* // - DataTypeGetInfo() // - DataTypeFormatString() // - DataTypeApplyOp() -// - DataTypeApplyOpFromText() +// - DataTypeApplyFromText() // - DataTypeCompare() // - DataTypeClamp() // - GetMinimumStepAtDecimalPrecision