From 915c6393ad7eeafc26cb0845e31b17e75d878a1a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 Feb 2024 14:54:48 +0100 Subject: [PATCH 01/18] Version 1.90.3 WIP --- docs/CHANGELOG.txt | 6 ++++++ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1ed921903..acf52803b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,12 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.90.3 WIP (In Progress) +----------------------------------------------------------------------- + +Other changes: + ----------------------------------------------------------------------- VERSION 1.90.2 (Released 2024-01-09) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index a3ca2bf62..b7e8d9573 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index f4c716164..f6740ca35 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 WIP // (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 WIP" +#define IMGUI_VERSION_NUM 19021 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7e48dd18a..39dfa34ca 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 90da08826..04fb78968 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 1575600d8..f9fb0e91c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 WIP // (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 5052dee1e..538877f9e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index a129d8087..52436ead4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.2 +// dear imgui, v1.90.3 WIP // (widgets code) /* From 2af01baffd1054fc62e577168ef783a4ed7fd87d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 Feb 2024 14:57:39 +0100 Subject: [PATCH 02/18] Backends: SDLRenderer3: query newly added SDL_RenderViewportSet() to not restore a wrong viewport if none was initially set. https://github.com/libsdl-org/SDL/issues/9029 --- backends/imgui_impl_sdlrenderer3.cpp | 9 ++++----- docs/CHANGELOG.txt | 4 ++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index fcef4f5df..01cd1a308 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -20,6 +20,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" @@ -129,10 +130,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); @@ -178,11 +181,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(); @@ -197,7 +196,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/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index acf52803b..ec27103af 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,10 @@ HOW TO UPDATE? Other changes: +- Backends: SDLRenderer3: query newly added SDL_RenderViewportSet() to not restore + a wrong viewport if none was initially set. + + ----------------------------------------------------------------------- VERSION 1.90.2 (Released 2024-01-09) ----------------------------------------------------------------------- From 3af739a2d176223870cedbe0704a102b07a0885e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 Feb 2024 15:21:48 +0100 Subject: [PATCH 03/18] Menus, Popups: fixed menus and popups with child window flag erroneously not displaying a scrollbar when contents is over parent viewport size. (#7287, #7063) Amend f37f6f6 --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ec27103af..092d0b73c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,8 @@ HOW TO UPDATE? Other changes: +- Menus, Popups: fixed menus and popups with child window flag erroneously not displaying + a scrollbar when contents is over parent viewport size. (#7287, #7063) [@ZingBallyhoo] - Backends: SDLRenderer3: query newly added SDL_RenderViewportSet() to not restore a wrong viewport if none was initially set. diff --git a/imgui.cpp b/imgui.cpp index b7e8d9573..70d11d3ae 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5755,7 +5755,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->Flags & ImGuiWindowFlags_ChildWindow) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f; + ImVec2 size_max = ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup)) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f; ImVec2 size_auto_fit = ImClamp(size_desired, size_min, size_max); // When the window cannot fit all contents (either because of constraints, either because screen is too small), From 1d6f0cea0e6bb59519f65e05fe394114dccc49e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=92=80=E5=A2=83=E7=9F=B3?= Date: Thu, 6 Jul 2023 01:48:35 +0800 Subject: [PATCH 04/18] Backends: DX9: use RGBA texture to avoid conversion if supported --- backends/imgui_impl_dx9.cpp | 28 +++++++++++++++++++++++++--- docs/CHANGELOG.txt | 2 ++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 48fee4bd5..ea0b26ec0 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -15,6 +15,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 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. @@ -312,6 +313,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 @@ -323,18 +342,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) @@ -347,7 +369,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/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 092d0b73c..70304200d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other changes: a scrollbar when contents is over parent viewport size. (#7287, #7063) [@ZingBallyhoo] - 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] ----------------------------------------------------------------------- From 89019319ddbb3f03c228a1cde1f8233b121fee0e Mon Sep 17 00:00:00 2001 From: Shawn Hatori Date: Sat, 23 Dec 2023 14:01:48 -0500 Subject: [PATCH 05/18] Backends: Vulkan: use PipelineRenderingCreateInfo for dynamic rendering (#7166, #6855, #5446, #5037) --- backends/imgui_impl_vulkan.cpp | 11 +++++------ backends/imgui_impl_vulkan.h | 22 ++++++++++++++-------- docs/CHANGELOG.txt | 7 +++++++ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 91bd43b68..1c7d5a6c7 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -33,10 +33,11 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 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. @@ -953,13 +954,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; + 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"); if (bd->VulkanInitInfo.UseDynamicRendering) { - info.pNext = &pipelineRenderingCreateInfo; + info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo; info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. } #endif diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 94c5b1d30..650576dd7 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -54,6 +54,9 @@ #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 { @@ -62,18 +65,21 @@ struct ImGui_ImplVulkan_InitInfo VkDevice Device; uint32_t QueueFamily; VkQueue Queue; + VkDescriptorPool DescriptorPool; // See requirements in note above + 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; + VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; - // 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. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 70304200d..15382b476 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,6 +39,13 @@ HOW TO UPDATE? VERSION 1.90.3 WIP (In Progress) ----------------------------------------------------------------------- +Breaking changes: + +- 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 child window flag erroneously not displaying From 11d73f03ee5e33f1847a4b34a6025a040ef0d17e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 Feb 2024 17:18:52 +0100 Subject: [PATCH 06/18] Backends: Vulkan: Fix/amend 8901931 --- backends/imgui_impl_vulkan.cpp | 4 ++-- imgui_widgets.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 1c7d5a6c7..64cb04fb2 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -954,10 +954,10 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC info.subpass = subpass; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - 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"); if (bd->VulkanInitInfo.UseDynamicRendering) { + 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. } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 52436ead4..a53f3e8ef 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1995,7 +1995,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*old_getter)(void* // - DataTypeGetInfo() // - DataTypeFormatString() // - DataTypeApplyOp() -// - DataTypeApplyOpFromText() +// - DataTypeApplyFromText() // - DataTypeCompare() // - DataTypeClamp() // - GetMinimumStepAtDecimalPrecision From e0ba0d0433ae2cd2b5c6ddf4a87a76259e121fd1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 Feb 2024 18:46:01 +0100 Subject: [PATCH 07/18] Backends: Vulkan: Fixes for building with pre Vulkan 1.3. Amend 8901931. (#7166) --- backends/imgui_impl_vulkan.cpp | 3 +-- backends/imgui_impl_vulkan.h | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 64cb04fb2..2aa5518d5 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -185,8 +185,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 diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 650576dd7..c2324449f 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -52,6 +52,9 @@ #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, @@ -77,7 +80,9 @@ struct ImGui_ImplVulkan_InitInfo // (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 // (Optional) Allocation, Debugging const VkAllocationCallbacks* Allocator; From fd8d6dc5d19883fda08641351d912cd9c74b374d Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Feb 2024 15:49:49 +0100 Subject: [PATCH 08/18] Backends: SDL2,SDL3: tidying up. --- backends/imgui_impl_sdl2.cpp | 36 +++++++++++++++++++----------------- backends/imgui_impl_sdl3.cpp | 36 +++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 9f950bb17..dfcfa925e 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -103,16 +103,18 @@ // 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; + SDL_Window* Window; + SDL_Renderer* Renderer; + Uint64 Time; + char* ClipboardTextData; + + // Mouse handling + Uint32 MouseWindowID; + int MouseButtonsDown; + SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; + SDL_Cursor* MouseLastCursor; + int MouseLastLeaveFrame; + bool MouseCanUseGlobalState; ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -368,10 +370,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 (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST) @@ -511,7 +513,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; + bd->MouseLastCursor = nullptr; io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; @@ -567,10 +569,10 @@ 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); } @@ -651,10 +653,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_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index d41a5e461..e06ef7959 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -61,16 +61,18 @@ // 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; + SDL_Window* Window; + SDL_Renderer* Renderer; + Uint64 Time; + char* ClipboardTextData; + + // Mouse handling + Uint32 MouseWindowID; + int MouseButtonsDown; + SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; + SDL_Cursor* MouseLastCursor; + int MousePendingLeaveFrame; + bool MouseCanUseGlobalState; ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -312,7 +314,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, @@ -321,7 +323,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: @@ -455,7 +457,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; + bd->MouseLastCursor = nullptr; io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; @@ -514,10 +516,10 @@ 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(); } @@ -595,10 +597,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); } From bf1c96d4fa24b95e8e47585fc8a2705ff982820e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Feb 2024 16:24:44 +0100 Subject: [PATCH 09/18] Backends: SDL2: Handle gamepad disconnection + fixed increasing refcount. Added ImGui_ImplSDL2_SelectGamepadAuto()/ImGui_ImplSDL2_SelectGamepadExplicit(). (#3884, #6559, #6890) --- backends/imgui_impl_sdl2.cpp | 68 +++++++++++++++++++++++++++++++++--- backends/imgui_impl_sdl2.h | 8 ++++- docs/CHANGELOG.txt | 4 +++ 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index dfcfa925e..6fe074677 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-02-13: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SelectGamepadAuto()/ImGui_ImplSDL2_SelectGamepadExplicit(). // 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,6 +117,11 @@ struct ImGui_ImplSDL2_Data int MouseLastLeaveFrame; bool MouseCanUseGlobalState; + // Gamepad handling + SDL_GameController* Gamepad; + bool GamepadSelectAuto; + bool WantRefreshGamepads; // Refresh gamepad list + ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -380,6 +386,12 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) io.AddFocusEvent(false); return true; } + case SDL_CONTROLLERDEVICEADDED: + case SDL_CONTROLLERDEVICEREMOVED: + { + bd->WantRefreshGamepads = true; + return true; + } } return false; } @@ -416,6 +428,11 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer) io.ClipboardUserData = nullptr; io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData; + // Gamepad handling + bd->Gamepad = NULL; + bd->GamepadSelectAuto = true; + bd->WantRefreshGamepads = true; + // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); @@ -521,6 +538,24 @@ void ImGui_ImplSDL2_Shutdown() IM_DELETE(bd); } +void ImGui_ImplSDL2_SelectGamepadAuto() +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + if (bd->GamepadSelectAuto == false) + bd->Gamepad = NULL; + bd->GamepadSelectAuto = true; + bd->WantRefreshGamepads = true; +} + +void ImGui_ImplSDL2_SelectGamepadExplicit(SDL_GameController* gamepad) +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + if (bd->GamepadSelectAuto == true && bd->Gamepad != NULL) + SDL_GameControllerClose(bd->Gamepad); + bd->Gamepad = gamepad; + bd->GamepadSelectAuto = false; +} + static void ImGui_ImplSDL2_UpdateMouseData() { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); @@ -580,21 +615,44 @@ static void ImGui_ImplSDL2_UpdateMouseCursor() 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. + + // Select a new controller + if (bd->WantRefreshGamepads && bd->GamepadSelectAuto) + { + SDL_GameController* old_gamepad = bd->Gamepad; + SDL_GameController* new_gamepad = NULL; + int joystick_count = SDL_NumJoysticks(); + for (int n = 0; n < joystick_count; n++) + if (SDL_IsGameController(n)) + if (SDL_GameController* gamepad = SDL_GameControllerOpen(n)) + { + new_gamepad = gamepad; + break; + } + + //IMGUI_DEBUG_LOG("ImGui_ImplSDL2_UpdateGamepads(): Gamepad change %p -> %p\n", old_gamepad, new_gamepad); + if (old_gamepad != NULL && new_gamepad != NULL) + SDL_GameControllerClose(old_gamepad); + bd->Gamepad = new_gamepad; + bd->WantRefreshGamepads = false; + } + + // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) return; // Get gamepad io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; - SDL_GameController* game_controller = SDL_GameControllerOpen(0); - if (!game_controller) + if (bd->Gamepad == NULL) 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); } + #define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GameControllerGetButton(bd->Gamepad, BUTTON_NO) != 0); } + #define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(bd->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_CONTROLLER_BUTTON_START); MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK); diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index dd5e047e7..cd477a897 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -24,6 +24,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); @@ -36,8 +37,13 @@ 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); +// Gamepad selection automatically starts in Auto mode, picking first available SDL_GameController. You may override this. +// When using Explicit selection, caller is responsible for opening/closing gamepad. +IMGUI_IMPL_API void ImGui_ImplSDL2_SelectGamepadAuto(); +IMGUI_IMPL_API void ImGui_ImplSDL2_SelectGamepadExplicit(struct _SDL_GameController* gamepad); + #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter +static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter #endif #endif // #ifndef IMGUI_DISABLE diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 15382b476..5b37b9f20 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,10 @@ Other changes: - Menus, Popups: fixed menus and popups with child window flag erroneously not displaying a scrollbar when contents is over parent viewport size. (#7287, #7063) [@ZingBallyhoo] +- Backends: SDL2: Handle gamepad disconnection + fixed increasing gamepad reference counter + continuously. Added ImGui_ImplSDL2_SelectGamepadAuto()/ImGui_ImplSDL2_SelectGamepadExplicit() + functions to respectively select automatic selection or provide a gamepad to use. + (#3884, #6559, #6890) [@ocornut, @lethal-guitar, @wn2000, @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 From f966da1f8fb569b99dd4220162f2d9bde6f3b153 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Feb 2024 16:31:33 +0100 Subject: [PATCH 10/18] Backends: SDL2: Gamepad handlng: amend bf1c96d. (#3884, #6559, #6890) --- backends/imgui_impl_sdl2.cpp | 4 +++- docs/CHANGELOG.txt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 6fe074677..001dced3e 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -530,7 +530,9 @@ 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->MouseLastCursor = nullptr; + + if (bd->Gamepad && bd->GamepadSelectAuto) + SDL_GameControllerClose(bd->Gamepad); io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5b37b9f20..94457fc86 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,7 +53,7 @@ Other changes: - Backends: SDL2: Handle gamepad disconnection + fixed increasing gamepad reference counter continuously. Added ImGui_ImplSDL2_SelectGamepadAuto()/ImGui_ImplSDL2_SelectGamepadExplicit() functions to respectively select automatic selection or provide a gamepad to use. - (#3884, #6559, #6890) [@ocornut, @lethal-guitar, @wn2000, @bog-dan-ro] + (#3884, #6559, #6890) [@lethal-guitar, @wn2000, @ocornut, @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 From d15e4100b839acdf701c92644eb804838d891e70 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 Feb 2024 18:50:21 +0100 Subject: [PATCH 11/18] Backends: SDL2: Amend new API, all support for multiple gamepads. (#3884, #6559, #6890) --- backends/imgui_impl_sdl2.cpp | 177 +++++++++++++++++++++-------------- backends/imgui_impl_sdl2.h | 7 +- docs/CHANGELOG.txt | 7 +- 3 files changed, 113 insertions(+), 78 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 001dced3e..ecd8f9426 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,7 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-02-13: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SelectGamepadAuto()/ImGui_ImplSDL2_SelectGamepadExplicit(). +// 2024-02-13: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadModeAutoFirst(), ImGui_ImplSDL2_SetGamepadModeAutoAll(), ImGui_ImplSDL2_SetGamepadModeManual(). // 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) @@ -102,6 +102,13 @@ #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) // SDL Data +enum ImGui_ImplSDL2_GamepadMode +{ + ImGui_ImplSDL2_GamepadMode_AutoFirst, // (Default) Use first available gamepad + ImGui_ImplSDL2_GamepadMode_AutoAll, // Use all available gamepad + ImGui_ImplSDL2_GamepadMode_Manual, +}; + struct ImGui_ImplSDL2_Data { SDL_Window* Window; @@ -118,9 +125,9 @@ struct ImGui_ImplSDL2_Data bool MouseCanUseGlobalState; // Gamepad handling - SDL_GameController* Gamepad; - bool GamepadSelectAuto; - bool WantRefreshGamepads; // Refresh gamepad list + ImVector Gamepads; + ImGui_ImplSDL2_GamepadMode GamepadMode; + bool WantUpdateGamepadsList; ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -389,7 +396,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_CONTROLLERDEVICEADDED: case SDL_CONTROLLERDEVICEREMOVED: { - bd->WantRefreshGamepads = true; + bd->WantUpdateGamepadsList = true; return true; } } @@ -429,9 +436,8 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer) io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData; // Gamepad handling - bd->Gamepad = NULL; - bd->GamepadSelectAuto = true; - bd->WantRefreshGamepads = true; + bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; + bd->WantUpdateGamepadsList = true; // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); @@ -520,6 +526,8 @@ bool ImGui_ImplSDL2_InitForOther(SDL_Window* window) return ImGui_ImplSDL2_Init(window, nullptr); } +static void ImGui_ImplSDL2_CloseGamepads(); + void ImGui_ImplSDL2_Shutdown() { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); @@ -530,9 +538,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]); - - if (bd->Gamepad && bd->GamepadSelectAuto) - SDL_GameControllerClose(bd->Gamepad); + ImGui_ImplSDL2_CloseGamepads(); io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; @@ -540,24 +546,6 @@ void ImGui_ImplSDL2_Shutdown() IM_DELETE(bd); } -void ImGui_ImplSDL2_SelectGamepadAuto() -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - if (bd->GamepadSelectAuto == false) - bd->Gamepad = NULL; - bd->GamepadSelectAuto = true; - bd->WantRefreshGamepads = true; -} - -void ImGui_ImplSDL2_SelectGamepadExplicit(SDL_GameController* gamepad) -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - if (bd->GamepadSelectAuto == true && bd->Gamepad != NULL) - SDL_GameControllerClose(bd->Gamepad); - bd->Gamepad = gamepad; - bd->GamepadSelectAuto = false; -} - static void ImGui_ImplSDL2_UpdateMouseData() { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); @@ -615,30 +603,80 @@ static void ImGui_ImplSDL2_UpdateMouseCursor() } } +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_SetGamepadModeAutoFirst() +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + ImGui_ImplSDL2_CloseGamepads(); + bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; + bd->WantUpdateGamepadsList = true; +} + +void ImGui_ImplSDL2_SetGamepadModeAutoAll() +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + ImGui_ImplSDL2_CloseGamepads(); + bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoAll; + bd->WantUpdateGamepadsList = true; +} + +void ImGui_ImplSDL2_SetGamepadModeManual(struct _SDL_GameController** gamepads_array, int gamepads_count) +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + ImGui_ImplSDL2_CloseGamepads(); + for (int n = 0; n < gamepads_count; n++) + bd->Gamepads.push_back(gamepads_array[n]); + bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_Manual; +} + +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 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 = (float)(SDL_GameControllerGetAxis(gamepad, axis_no) - v0) / (float)(v1 - v0); + vn = (vn < 0.0f) ? 0.0f : (vn > 1.0f) ? 1.0f : vn; + 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(); - // Select a new controller - if (bd->WantRefreshGamepads && bd->GamepadSelectAuto) + // Update list of controller(s) to use + if (bd->WantUpdateGamepadsList && bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual) { - SDL_GameController* old_gamepad = bd->Gamepad; - SDL_GameController* new_gamepad = NULL; + 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)) { - new_gamepad = gamepad; - break; + bd->Gamepads.push_back(gamepad); + if (bd->GamepadMode == ImGui_ImplSDL2_GamepadMode_AutoFirst) + break; } - - //IMGUI_DEBUG_LOG("ImGui_ImplSDL2_UpdateGamepads(): Gamepad change %p -> %p\n", old_gamepad, new_gamepad); - if (old_gamepad != NULL && new_gamepad != NULL) - SDL_GameControllerClose(old_gamepad); - bd->Gamepad = new_gamepad; - bd->WantRefreshGamepads = false; + bd->WantUpdateGamepadsList = false; } // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. @@ -647,41 +685,36 @@ static void ImGui_ImplSDL2_UpdateGamepads() // Get gamepad io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; - if (bd->Gamepad == NULL) + 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(bd->Gamepad, BUTTON_NO) != 0); } - #define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(bd->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_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); } void ImGui_ImplSDL2_NewFrame() diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index cd477a897..1d8d6e28c 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -38,9 +38,10 @@ IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(); IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); // Gamepad selection automatically starts in Auto mode, picking first available SDL_GameController. You may override this. -// When using Explicit selection, caller is responsible for opening/closing gamepad. -IMGUI_IMPL_API void ImGui_ImplSDL2_SelectGamepadAuto(); -IMGUI_IMPL_API void ImGui_ImplSDL2_SelectGamepadExplicit(struct _SDL_GameController* gamepad); +// When using manual mode, caller is responsible for opening/closing gamepad. +IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadModeAutoFirst(); // Use first available gamepad (default) +IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadModeAutoAll(); +IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadModeManual(struct _SDL_GameController** gamepads_array, int gamepads_count); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 94457fc86..fc57af2d7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,9 +51,10 @@ Other changes: - Menus, Popups: fixed menus and popups with child window flag erroneously not displaying a scrollbar when contents is over parent viewport size. (#7287, #7063) [@ZingBallyhoo] - Backends: SDL2: Handle gamepad disconnection + fixed increasing gamepad reference counter - continuously. Added ImGui_ImplSDL2_SelectGamepadAuto()/ImGui_ImplSDL2_SelectGamepadExplicit() - functions to respectively select automatic selection or provide a gamepad to use. - (#3884, #6559, #6890) [@lethal-guitar, @wn2000, @ocornut, @bog-dan-ro] + continuously. Added support for multiple simultaneous gamepads. + Added ImGui_ImplSDL2_SetGamepadModeXXX() functions to select whether to automatically pick + first available gamepad, all gamepads, or specific gamepads. + (#3884, #6559, #6890) [@ocornut, @lethal-guitar, @wn2000, @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 From 9dfa2397deb17cf4fff5302c4ea6ee7eb41917fa Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Feb 2024 11:02:24 +0100 Subject: [PATCH 12/18] Internals: Fixed ImFileOpen not working before context is created. (#7314, #7315) Amend daf49e9d8 --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index fc57af2d7..915d02d08 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,8 @@ Other changes: 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] ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 70d11d3ae..2eb615931 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2063,12 +2063,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 From 262e30e300197b499a102b450984217fb494fc4f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Feb 2024 11:30:43 +0100 Subject: [PATCH 13/18] Backends: SDL2: rework new API as ImGui_ImplSDL2_SetGamepadMode(). (#3884, #6559, #6890, #7180) Code is simpler this way. --- backends/imgui_impl_sdl2.cpp | 48 ++++++++++++------------------------ backends/imgui_impl_sdl2.h | 7 +++--- docs/CHANGELOG.txt | 2 +- 3 files changed, 20 insertions(+), 37 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index ecd8f9426..7abeb0e89 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,7 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-02-13: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadModeAutoFirst(), ImGui_ImplSDL2_SetGamepadModeAutoAll(), ImGui_ImplSDL2_SetGamepadModeManual(). +// 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) @@ -102,13 +102,6 @@ #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) // SDL Data -enum ImGui_ImplSDL2_GamepadMode -{ - ImGui_ImplSDL2_GamepadMode_AutoFirst, // (Default) Use first available gamepad - ImGui_ImplSDL2_GamepadMode_AutoAll, // Use all available gamepad - ImGui_ImplSDL2_GamepadMode_Manual, -}; - struct ImGui_ImplSDL2_Data { SDL_Window* Window; @@ -612,29 +605,22 @@ static void ImGui_ImplSDL2_CloseGamepads() bd->Gamepads.resize(0); } -void ImGui_ImplSDL2_SetGamepadModeAutoFirst() +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(); - bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; - bd->WantUpdateGamepadsList = true; -} - -void ImGui_ImplSDL2_SetGamepadModeAutoAll() -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - ImGui_ImplSDL2_CloseGamepads(); - bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoAll; - bd->WantUpdateGamepadsList = true; -} - -void ImGui_ImplSDL2_SetGamepadModeManual(struct _SDL_GameController** gamepads_array, int gamepads_count) -{ - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - ImGui_ImplSDL2_CloseGamepads(); - for (int n = 0; n < gamepads_count; n++) - bd->Gamepads.push_back(gamepads_array[n]); - bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_Manual; + 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) @@ -645,13 +631,13 @@ static void ImGui_ImplSDL2_UpdateGamepadButton(ImGui_ImplSDL2_Data* bd, ImGuiIO& 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 = (float)(SDL_GameControllerGetAxis(gamepad, axis_no) - v0) / (float)(v1 - v0); - vn = (vn < 0.0f) ? 0.0f : (vn > 1.0f) ? 1.0f : vn; + float vn = Saturate((float)(SDL_GameControllerGetAxis(gamepad, axis_no) - v0) / (float)(v1 - v0)); if (merged_value < vn) merged_value = vn; } @@ -682,8 +668,6 @@ static void ImGui_ImplSDL2_UpdateGamepads() // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) return; - - // Get gamepad io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; if (bd->Gamepads.Size == 0) return; diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index 1d8d6e28c..d330da281 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -37,11 +37,10 @@ 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); -// Gamepad selection automatically starts in Auto mode, picking first available SDL_GameController. You may override this. +// 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. -IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadModeAutoFirst(); // Use first available gamepad (default) -IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadModeAutoAll(); -IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadModeManual(struct _SDL_GameController** gamepads_array, int gamepads_count); +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); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 915d02d08..861ab7b28 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,7 +52,7 @@ Other changes: a scrollbar when contents is over parent viewport size. (#7287, #7063) [@ZingBallyhoo] - Backends: SDL2: Handle gamepad disconnection + fixed increasing gamepad reference counter continuously. Added support for multiple simultaneous gamepads. - Added ImGui_ImplSDL2_SetGamepadModeXXX() functions to select whether to automatically pick + Added ImGui_ImplSDL2_SetGamepadMode()) function to select whether to automatically pick first available gamepad, all gamepads, or specific gamepads. (#3884, #6559, #6890) [@ocornut, @lethal-guitar, @wn2000, @bog-dan-ro] - Backends: SDLRenderer3: query newly added SDL_RenderViewportSet() to not restore From 891b81fc5d77aeeeb462d17921c881e7d095ae73 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Feb 2024 11:37:18 +0100 Subject: [PATCH 14/18] Backends: SDL3: Fixed gamepad. Added support for disconnection. Added support for multiple gamepads. Added ImGui_ImplSDL3_SetGamepadMode(). (#7180, #3884, #6559, #6890) --- backends/imgui_impl_sdl3.cpp | 149 ++++++++++++++++++++++++++--------- backends/imgui_impl_sdl3.h | 6 ++ docs/CHANGELOG.txt | 3 +- 3 files changed, 121 insertions(+), 37 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index e06ef7959..2e261ef1a 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -22,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 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) @@ -74,6 +75,11 @@ struct ImGui_ImplSDL3_Data int MousePendingLeaveFrame; bool MouseCanUseGlobalState; + // Gamepad handling + ImVector Gamepads; + ImGui_ImplSDL3_GamepadMode GamepadMode; + bool WantUpdateGamepadsList; + ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -332,6 +338,12 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_WINDOW_FOCUS_LOST: io.AddFocusEvent(false); return true; + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: + { + bd->WantUpdateGamepadsList = true; + return true; + } } return false; } @@ -380,6 +392,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); @@ -447,6 +463,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(); @@ -457,7 +475,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->MouseLastCursor = nullptr; + ImGui_ImplSDL3_CloseGamepads(); io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; @@ -525,50 +543,109 @@ static void ImGui_ImplSDL3_UpdateMouseCursor() } } +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(); - // Get gamepad + // 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; + } + + // 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); } void ImGui_ImplSDL3_NewFrame() diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index 9baa7e68c..4898729d4 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -26,6 +26,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); @@ -38,4 +39,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/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 861ab7b28..f79dd8d3b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,7 +54,8 @@ Other changes: 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) [@ocornut, @lethal-guitar, @wn2000, @bog-dan-ro] + (#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 From 3cc37170ca71fae26aab14eb765325221f5fcef9 Mon Sep 17 00:00:00 2001 From: Tom Seddon Date: Tue, 13 Feb 2024 22:31:03 +0000 Subject: [PATCH 15/18] Examples: GLFW+Metal: Add -I and -L paths for MacPorts. --- examples/example_glfw_metal/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/example_glfw_metal/Makefile b/examples/example_glfw_metal/Makefile index 82d5ac962..32a7aeca2 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) From 829f45df994cc5eea5484fe2d135f5717ee40b2a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Feb 2024 12:06:21 +0100 Subject: [PATCH 16/18] Backends: SDL2: removed obsolete ImGui_ImplSDL2_NewFrame(SDL_Window*) signature which was obsoleted in 1.84.. --- backends/imgui_impl_sdl2.h | 4 ---- docs/CHANGELOG.txt | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index d330da281..7020a29e0 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -42,8 +42,4 @@ IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); 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); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter -#endif - #endif // #ifndef IMGUI_DISABLE diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f79dd8d3b..94b4dc6e4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,8 @@ HOW TO UPDATE? 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: 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. From f80e65a406885beedf68856057b278343d5c1407 Mon Sep 17 00:00:00 2001 From: Shawn Hatori Date: Mon, 12 Feb 2024 14:51:24 -0500 Subject: [PATCH 17/18] Backends:,Examples: Vulkan: moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. (#7308) --- backends/imgui_impl_vulkan.cpp | 13 +++++-------- backends/imgui_impl_vulkan.h | 3 ++- docs/CHANGELOG.txt | 2 ++ examples/example_glfw_vulkan/main.cpp | 3 ++- examples/example_sdl2_vulkan/main.cpp | 3 ++- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 2aa5518d5..a8962ecd2 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -33,6 +33,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 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). @@ -215,13 +216,11 @@ struct ImGui_ImplVulkan_WindowRenderBuffers 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; @@ -1022,7 +1021,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; } @@ -1072,7 +1071,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!"); @@ -1107,11 +1106,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(); @@ -1487,7 +1484,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 c2324449f..f77fc235b 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -69,6 +69,7 @@ struct ImGui_ImplVulkan_InitInfo 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 @@ -91,7 +92,7 @@ struct ImGui_ImplVulkan_InitInfo }; // 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/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 94b4dc6e4..f6508cd8f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ 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. diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 98e8dc270..b1c596dd3 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -434,13 +434,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 6de55701a..633f8bb8b 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -434,13 +434,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. From 5b6f03213dde8c6ca9bea4707321cca79f2265ec Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 Feb 2024 13:57:26 +0100 Subject: [PATCH 18/18] Version 1.90.3 --- docs/CHANGELOG.txt | 14 ++++++++------ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f6508cd8f..57151f2a0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,12 +36,14 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.90.3 WIP (In Progress) + 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 +- 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] @@ -52,10 +54,10 @@ Breaking changes: Other changes: -- Menus, Popups: fixed menus and popups with child window flag erroneously not displaying +- 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: Handle gamepad disconnection + fixed increasing gamepad reference counter - continuously. Added support for multiple simultaneous gamepads. +- 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] @@ -69,7 +71,7 @@ Other changes: ----------------------------------------------------------------------- - VERSION 1.90.2 (Released 2024-01-09) + 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/imgui.cpp b/imgui.cpp index 2eb615931..05f578316 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.3 WIP +// dear imgui, v1.90.3 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index f6740ca35..1346ecacd 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.90.3 WIP +// 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.3 WIP" -#define IMGUI_VERSION_NUM 19021 +#define IMGUI_VERSION "1.90.3" +#define IMGUI_VERSION_NUM 19030 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 39dfa34ca..bbed74244 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.3 WIP +// dear imgui, v1.90.3 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 04fb78968..ca1fe7d0f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.3 WIP +// dear imgui, v1.90.3 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index f9fb0e91c..3caef13b6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.90.3 WIP +// 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 538877f9e..36c4c95b7 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.3 WIP +// dear imgui, v1.90.3 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index a53f3e8ef..e2fab9cdc 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.90.3 WIP +// dear imgui, v1.90.3 // (widgets code) /*