From 4d745bc602d40b242504c15f03fb0322dedb74b3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Jul 2025 18:41:05 +0200 Subject: [PATCH 01/18] Version 1.92.2 WIP --- docs/CHANGELOG.txt | 17 +++++++++++++---- 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, 22 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7f12f6a5b..f19d5f246 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,15 @@ 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.92.2 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking Changes: + +Other Changes: + + ----------------------------------------------------------------------- VERSION 1.92.1 (Released 2025-07-09) ----------------------------------------------------------------------- @@ -64,13 +73,13 @@ Changes: - Debug Tools: added IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS to detect id conflicts _before_ hovering. This is very slow and should only be used temporarily. (#8651, #7961, #7669) -- Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses GLFW port +- Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses GLFW port 'contrib.glfw3' which offers better HiDPI support. (#8742) [@pthom] -- Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and - ImGui_ImplSDL2_GetContentScaleXXXX() helpers return 1.0f on Emscripten +- Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and + ImGui_ImplSDL2_GetContentScaleXXXX() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) [@pthom] - Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. - (fixes e.g.: an issue on iOS where the keyboard animation will popup every + (fixes e.g.: an issue on iOS where the keyboard animation will popup every time the user types a key + probably other things) (#8727) [@morrazzzz] - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. (#8739) [@cfillion] diff --git a/imgui.cpp b/imgui.cpp index 99819ffe4..94d94ff85 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index a2b2a1fae..f474876f1 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.1" -#define IMGUI_VERSION_NUM 19210 +#define IMGUI_VERSION "1.92.2 WIP" +#define IMGUI_VERSION_NUM 19211 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 991676f78..6bc8968a4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 401282678..93fa8c344 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index ccb979b8c..c5a664010 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 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 119fe7bcc..f2fa47d78 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index a0c4f14f5..63dd9dc21 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (widgets code) /* From c680f54e6c56952885c8f3aebc7eb09d2934e212 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Jul 2025 18:42:39 +0200 Subject: [PATCH 02/18] FIxed IsWindowFocused() using wrong flag types (harmless as values were identical). (#8786) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 94d94ff85..0ba16fb31 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12501,10 +12501,10 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) IM_ASSERT(cur_window); // Not inside a Begin()/End() const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; - if (flags & ImGuiHoveredFlags_RootWindow) + if (flags & ImGuiFocusedFlags_RootWindow) cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); - if (flags & ImGuiHoveredFlags_ChildWindows) + if (flags & ImGuiFocusedFlags_ChildWindows) return IsWindowChildOf(ref_window, cur_window, popup_hierarchy); else return (ref_window == cur_window); From 0e6e876f237921b7d73bd201f0fc63953fed95d6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Jul 2025 19:04:43 +0200 Subject: [PATCH 03/18] Docs: update docs/comments about ImTextureRef, ImTextureID. (#8783) --- docs/FAQ.md | 38 ++++++++++++++++++++++++++++++-------- imgui.h | 5 +++-- imgui_internal.h | 1 - 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 10fb60350..286127cb9 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -389,8 +389,8 @@ node open/closed state differently. See what makes more sense in your situation! ### Q: What are ImTextureID/ImTextureRef? **Short explanation:** -- Refer to [Image Loading and Displaying Examples](https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples) on the [Wiki](https://github.com/ocornut/imgui/wiki). - You may use functions such as `ImGui::Image()`, `ImGui::ImageButton()` or lower-level `ImDrawList::AddImage()` to emit draw calls that will use your own textures. +- To load and display your own textures, refer to [Image Loading and Displaying Examples](https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples) on the [Wiki](https://github.com/ocornut/imgui/wiki). - Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as an opaque ImTextureID value. - By default ImTextureID can store up to 64-bits. You may `#define` it to a custom type/structure if you need. - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason), but the examples linked above may be useful references. @@ -398,12 +398,20 @@ node open/closed state differently. See what makes more sense in your situation! **Details:** 1.92 introduced `ImTextureRef` in June 2025. -- Most drawing functions using ImTextureID were changed to use ImTextureRef. -- We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. +- All drawing functions using `ImTextureID` were changed to use `ImTextureRef`. +- You can trivially create a `ImTextureRef` from a `ImTextureID`. +- **If you use Image functions with textures that you have loaded/created yourself, you will mostly likely only ever store/manipulate `ImTextureID` and then pass them as `ImTextureRef`.** +- You only NEED to manipulate `ImTextureRef` when dealing with textures managed by the backend itself, aka mainly the atlas texture for now. +- We intentionally do not provide an implicit `ImTextureRef` -> `ImTextureID` cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. **ImTextureID = backend specific, low-level identifier for a texture uploaded in GPU/graphics system.** +```cpp +#ifndef ImTextureID +typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that. +#endif +``` - When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint`; Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.). -- User may submit their own textures to e.g. ImGui::Image() function by passing the same type. +- User may submit their own textures to e.g. `ImGui::Image()` function by passing this value. - During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside a ImTextureRef, which is stored inside ImDrawCmd. - Compile-time type configuration: - To use something other than a 64-bit value: add '#define ImTextureID MyTextureType*' in your imconfig.h file. @@ -411,13 +419,27 @@ node open/closed state differently. See what makes more sense in your situation! - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various constructors if you like. You will need to implement ==/!= operators. **ImTextureRef = higher-level identifier for a texture.** +```cpp +// Store a ImTextureID _or_ a ImTextureData*. +struct ImTextureRef +{ + ImTextureRef() { _TexData = NULL; _TexID = ImTextureID_Invalid; } + ImTextureRef(ImTextureID tex_id) { _TexData = NULL; _TexID = tex_id; } + inline ImTextureID GetTexID() const { return _TexData ? _TexData->TexID : _TexID; } + + // Members (either are set, never both!) + ImTextureData* _TexData; // A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded. + ImTextureID _TexID; // _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. Generally provided to e.g. ImGui::Image() calls. +}; +``` - The identifier is valid even before the texture has been uploaded to the GPU/graphics system. - This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`. - This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering. - - When a texture is created by user code (e.g. custom images), we directly stores the low-level `ImTextureID`. - - When a texture is created by the backend, we stores a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened. - - There is no constructor to create a `ImTextureID` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code. - - If you want to bind the current atlas when using custom rectangle, you can use `io.Fonts->TexRef`. + - When a texture is created by user code (e.g. custom images), we directly store the low-level `ImTextureID`. + - Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. + - When a texture is created by the backend, we store a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened. + - There is no constructor to create a `ImTextureRef` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code. + - If you want to bind the current atlas when using custom rectangles, you can use `io.Fonts->TexRef`. - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }` **Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.** diff --git a/imgui.h b/imgui.h index f474876f1..cef7d7b87 100644 --- a/imgui.h +++ b/imgui.h @@ -317,7 +317,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // - When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value. // (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint`; // Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.). -// - User may submit their own textures to e.g. ImGui::Image() function by passing the same type. +// - User may submit their own textures to e.g. ImGui::Image() function by passing this value. // - During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside a // ImTextureRef, which is stored inside a ImDrawCmd. // - Compile-time type configuration: @@ -337,11 +337,12 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or #define ImTextureID_Invalid ((ImTextureID)0) #endif -// ImTextureRef = higher-level identifier for a texture. +// ImTextureRef = higher-level identifier for a texture. Store a ImTextureID _or_ a ImTextureData*. // The identifier is valid even before the texture has been uploaded to the GPU/graphics system. // This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`. // This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering. // - When a texture is created by user code (e.g. custom images), we directly stores the low-level ImTextureID. +// Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. // - When a texture is created by the backend, we stores a ImTextureData* which becomes an indirection // to extract the ImTextureID value during rendering, after texture upload has happened. // - There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this diff --git a/imgui_internal.h b/imgui_internal.h index c5a664010..bf744d4b1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3671,7 +3671,6 @@ namespace ImGui //inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 //inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } // Removed in 1.87: Mapping from named key is always identity! - // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister(): // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister(): // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool tab_focused = FocusableItemRegister(...)' // (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool tab_focused = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0' From a0d3e405a343677cd326ed704b1b27c000c05d17 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Jul 2025 16:40:35 +0200 Subject: [PATCH 04/18] Textures: ImTextureData::Create() sets status. RegisterUserTexture() increases RefCount. Added comments about ImTextureData::GetTexRef(). (#8789) --- docs/FAQ.md | 2 ++ imgui.cpp | 5 ++++- imgui.h | 9 +++++---- imgui_draw.cpp | 3 ++- imgui_internal.h | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 286127cb9..fb693c7e3 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -438,6 +438,8 @@ struct ImTextureRef - When a texture is created by user code (e.g. custom images), we directly store the low-level `ImTextureID`. - Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. - When a texture is created by the backend, we store a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened. + - To create a `ImTextureRef` from a `ImTextureData*` you can use `ImTextureData::GetTexRef()`. + We intentionally do not provide an `ImTextureRef` constructor for this: we don't expect this to be frequently useful to the end-user, and it would be erroneously called by many legacy code. - There is no constructor to create a `ImTextureRef` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code. - If you want to bind the current atlas when using custom rectangles, you can use `io.Fonts->TexRef`. - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }` diff --git a/imgui.cpp b/imgui.cpp index 0ba16fb31..31a95716b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8732,16 +8732,19 @@ ImFont* ImGui::GetDefaultFont() return g.IO.FontDefault ? g.IO.FontDefault : atlas->Fonts[0]; } +// EXPERIMENTAL: DO NOT USE YET. void ImGui::RegisterUserTexture(ImTextureData* tex) { ImGuiContext& g = *GImGui; - IM_ASSERT(tex->RefCount > 0); + tex->RefCount++; g.UserTextures.push_back(tex); } void ImGui::UnregisterUserTexture(ImTextureData* tex) { ImGuiContext& g = *GImGui; + IM_ASSERT(tex->RefCount > 0); + tex->RefCount--; g.UserTextures.find_erase(tex); } diff --git a/imgui.h b/imgui.h index cef7d7b87..ee4e976ae 100644 --- a/imgui.h +++ b/imgui.h @@ -345,8 +345,9 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or // Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. // - When a texture is created by the backend, we stores a ImTextureData* which becomes an indirection // to extract the ImTextureID value during rendering, after texture upload has happened. -// - There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this -// to be useful to the end-user, and it would be erroneously called by many legacy code. +// - To create a ImTextureRef from a ImTextureData you can use ImTextureData::GetTexRef(). +// We intentionally do not provide an ImTextureRef constructor for this: we don't expect this +// to be frequently useful to the end-user, and it would be erroneously called by many legacy code. // - If you want to bind the current atlas when using custom rectangle, you can use io.Fonts->TexRef. // - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. // inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; } @@ -3425,7 +3426,7 @@ struct ImTextureRect struct ImTextureData { //------------------------------------------ core / backend --------------------------------------- - int UniqueID; // w - // Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas. + int UniqueID; // w - // [DEBUG] Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas. ImTextureStatus Status; // rw rw // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! void* BackendUserData; // - rw // Convenience storage for backend. Some backends may have enough with TexID. ImTextureID TexID; // r w // Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function. @@ -3443,7 +3444,7 @@ struct ImTextureData bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. // Functions - ImTextureData() { memset(this, 0, sizeof(*this)); TexID = ImTextureID_Invalid; } + ImTextureData() { memset(this, 0, sizeof(*this)); Status = ImTextureStatus_Destroyed; TexID = ImTextureID_Invalid; } ~ImTextureData() { DestroyPixels(); } IMGUI_API void Create(ImTextureFormat format, int w, int h); IMGUI_API void DestroyPixels(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 93fa8c344..d12b8b55d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2457,8 +2457,10 @@ const char* ImTextureDataGetFormatName(ImTextureFormat format) void ImTextureData::Create(ImTextureFormat format, int w, int h) { + IM_ASSERT(Status == ImTextureStatus_Destroyed); DestroyPixels(); Format = format; + Status = ImTextureStatus_WantCreate; Width = w; Height = h; BytesPerPixel = ImTextureDataGetFormatBytesPerPixel(format); @@ -3971,7 +3973,6 @@ ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h) } new_tex->Create(atlas->TexDesiredFormat, w, h); - new_tex->Status = ImTextureStatus_WantCreate; atlas->TexIsBuilt = false; ImFontAtlasBuildSetTexture(atlas, new_tex); diff --git a/imgui_internal.h b/imgui_internal.h index bf744d4b1..f5f324c6e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3124,7 +3124,7 @@ namespace ImGui IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags); // Fonts, drawing - IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture + IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture. EXPERIMENTAL: DO NOT USE YET. IMGUI_API void UnregisterUserTexture(ImTextureData* tex); IMGUI_API void RegisterFontAtlas(ImFontAtlas* atlas); IMGUI_API void UnregisterFontAtlas(ImFontAtlas* atlas); From 79d88e2d0b1c915a9ea3d1a4215cf2a4dded3fab Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Jul 2025 16:57:43 +0200 Subject: [PATCH 05/18] Error Handling, Tables: TableGetSortSpecs() silently return NULL when no table (matching most other table getters). TableSetBgColor() uses IM_ASSERT_USER_ERROR. --- docs/CHANGELOG.txt | 3 +++ imgui_tables.cpp | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f19d5f246..70d3c37a3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking Changes: Other Changes: +- Error Handling: minor improvements to error handling for TableGetSortSpecs() + and TableSetBgColor() calls. (#1651, #8499) + ----------------------------------------------------------------------- VERSION 1.92.1 (Released 2025-07-09) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index f2fa47d78..a1504853b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1825,6 +1825,11 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; IM_ASSERT(target != ImGuiTableBgTarget_None); + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); + return; + } if (color == IM_COL32_DISABLE) color = 0; @@ -2876,9 +2881,7 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL); - - if (!(table->Flags & ImGuiTableFlags_Sortable)) + if (table == NULL || !(table->Flags & ImGuiTableFlags_Sortable)) return NULL; // Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths. From 336d9212fc25055a52107c70441c11acd12e8bb9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Jul 2025 17:41:52 +0200 Subject: [PATCH 06/18] Backends: using range-for to iterate draw_data->CmdLists[]. --- backends/imgui_impl_allegro5.cpp | 4 +--- backends/imgui_impl_dx10.cpp | 6 ++---- backends/imgui_impl_dx11.cpp | 6 ++---- backends/imgui_impl_dx12.cpp | 6 ++---- backends/imgui_impl_dx9.cpp | 6 ++---- backends/imgui_impl_metal.mm | 6 ++---- backends/imgui_impl_opengl2.cpp | 3 +-- backends/imgui_impl_opengl3.cpp | 4 +--- backends/imgui_impl_sdlgpu3.cpp | 6 ++---- backends/imgui_impl_sdlrenderer2.cpp | 3 +-- backends/imgui_impl_sdlrenderer3.cpp | 3 +-- backends/imgui_impl_vulkan.cpp | 6 ++---- backends/imgui_impl_wgpu.cpp | 8 +++----- docs/BACKENDS.md | 3 +-- imgui.h | 2 +- imgui_draw.cpp | 17 ++++++++--------- 16 files changed, 32 insertions(+), 57 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 5cbb89365..40417fc63 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -160,10 +160,8 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) ImGui_ImplAllegro5_SetupRenderState(draw_data); // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - ImVector& vertices = bd->BufVertices; #if ALLEGRO_HAS_DRAW_INDEXED_PRIM vertices.resize(draw_list->VtxBuffer.Size); diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 6bc52156f..3781a0974 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -200,9 +200,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) ImDrawIdx* idx_dst = nullptr; bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst); bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst); - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -268,9 +267,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; ImVec2 clip_scale = draw_data->FramebufferScale; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 1b28745a3..08bf7998f 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -208,9 +208,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) return; ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -282,9 +281,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) int global_vtx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; ImVec2 clip_scale = draw_data->FramebufferScale; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 557850979..2932855ed 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -262,9 +262,8 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL return; ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource; ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -295,9 +294,8 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; ImVec2 clip_scale = draw_data->FramebufferScale; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index b0159bf37..94411fabe 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -228,9 +228,8 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) // FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and // 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR // 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; } - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_src = draw_list->VtxBuffer.Data; for (int i = 0; i < draw_list->VtxBuffer.Size; i++) { @@ -260,9 +259,8 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) int global_vtx_offset = 0; int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index b1decb2bb..a1adc6c9a 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -223,7 +223,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0) + if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. @@ -259,10 +259,8 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id // Render command lists size_t vertexBufferOffset = 0; size_t indexBufferOffset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, draw_list->VtxBuffer.Data, (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, draw_list->IdxBuffer.Data, (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index afcafe826..7f760cca5 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -208,9 +208,8 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, pos))); diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 40b3be68b..7e8853017 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -584,10 +584,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - // Upload vertex/index buffers // - OpenGL drivers are in a very sorry state nowadays.... // During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 927e511cb..f58324a89 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -180,9 +180,8 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->Device, fd->VertexTransferBuffer, true); ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->Device, fd->IndexTransferBuffer, true); - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -238,9 +237,8 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe // (Because we merged all buffers into a single one, we maintain our own offset into them) int global_vtx_offset = 0; int global_idx_offset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index a39360f5c..3a47f80bf 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -169,9 +169,8 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* ImVec2 clip_scale = render_scale; // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index f62949150..42c173888 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -189,9 +189,8 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* ImVec2 clip_scale = render_scale; // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index a5dd75c8e..1120b4b5e 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -550,9 +550,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm check_vk_result(err); err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)&idx_dst); check_vk_result(err); - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -590,9 +589,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // (Because we merged all buffers into a single one, we maintain our own offset into them) int global_vtx_offset = 0; int global_idx_offset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index c0ec2e3f9..d20028d55 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -367,7 +367,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Avoid rendering when minimized int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0) + if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. @@ -442,9 +442,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Upload vertex/index data into a single contiguous GPU buffer ImDrawVert* vtx_dst = (ImDrawVert*)fr->VertexBufferHost; ImDrawIdx* idx_dst = (ImDrawIdx*)fr->IndexBufferHost; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -471,9 +470,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder int global_idx_offset = 0; ImVec2 clip_scale = draw_data->FramebufferScale; ImVec2 clip_off = draw_data->DisplayPos; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index fa05d55ea..629f8d83f 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -245,9 +245,8 @@ void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) // Render command lists ImVec2 clip_off = draw_data->DisplayPos; ImVec2 clip_scale = draw_data->FramebufferScale; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) diff --git a/imgui.h b/imgui.h index ee4e976ae..5d947b23d 100644 --- a/imgui.h +++ b/imgui.h @@ -3361,7 +3361,7 @@ struct ImDrawList struct ImDrawData { bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. - int CmdListsCount; // Number of ImDrawList* to render. (== CmdLists.Size). Exists for legacy reason. + int CmdListsCount; // == CmdLists.Size. (OBSOLETE: exists for legacy reasons). Number of ImDrawList* to render. int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size ImVector CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d12b8b55d..f42f96639 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2312,17 +2312,16 @@ void ImDrawData::DeIndexAllBuffers() { ImVector new_vtx_buffer; TotalVtxCount = TotalIdxCount = 0; - for (int i = 0; i < CmdListsCount; i++) + for (ImDrawList* draw_list : CmdLists) { - ImDrawList* cmd_list = CmdLists[i]; - if (cmd_list->IdxBuffer.empty()) + if (draw_list->IdxBuffer.empty()) continue; - new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); - for (int j = 0; j < cmd_list->IdxBuffer.Size; j++) - new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]]; - cmd_list->VtxBuffer.swap(new_vtx_buffer); - cmd_list->IdxBuffer.resize(0); - TotalVtxCount += cmd_list->VtxBuffer.Size; + new_vtx_buffer.resize(draw_list->IdxBuffer.Size); + for (int j = 0; j < draw_list->IdxBuffer.Size; j++) + new_vtx_buffer[j] = draw_list->VtxBuffer[draw_list->IdxBuffer[j]]; + draw_list->VtxBuffer.swap(new_vtx_buffer); + draw_list->IdxBuffer.resize(0); + TotalVtxCount += draw_list->VtxBuffer.Size; } } From 8744d10235e58536c5237a2ead3af53b700f40c4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Jul 2025 14:30:50 +0200 Subject: [PATCH 07/18] Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) --- backends/imgui_impl_opengl2.cpp | 3 +++ backends/imgui_impl_opengl3.cpp | 15 ++++++++++++--- backends/imgui_impl_opengl3_loader.h | 1 + docs/CHANGELOG.txt | 2 ++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 7f760cca5..477e3a043 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -25,6 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture(). // 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748) @@ -285,6 +286,7 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); // Store identifiers @@ -304,6 +306,7 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id)); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width)); + GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); for (ImTextureRect& r : tex->Updates) GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y))); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 7e8853017..e9660295e 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,6 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). // 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) // 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) @@ -709,6 +710,17 @@ static void ImGui_ImplOpenGL3_DestroyTexture(ImTextureData* tex) void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) { + // FIXME: Consider backing up and restoring + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) + { +#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); +#endif +#ifdef GL_UNPACK_ALIGNMENT + GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); +#endif + } + if (tex->Status == ImTextureStatus_WantCreate) { // Create and upload new texture to graphics system @@ -728,9 +740,6 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); -#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES - GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); -#endif GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); // Store identifiers diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h index 4ca053603..aa8fdc27e 100644 --- a/backends/imgui_impl_opengl3_loader.h +++ b/backends/imgui_impl_opengl3_loader.h @@ -166,6 +166,7 @@ typedef khronos_uint8_t GLubyte; #define GL_SCISSOR_BOX 0x0C10 #define GL_SCISSOR_TEST 0x0C11 #define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_TEXTURE_2D 0x0DE1 diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 70d3c37a3..17cf659ba 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other Changes: - Error Handling: minor improvements to error handling for TableGetSortSpecs() and TableSetBgColor() calls. (#1651, #8499) +- Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating + textures. (#8802) [@Daandelange] ----------------------------------------------------------------------- From 643f0e3abf6f84c210ea717f62c02bf411fc2e8c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Jul 2025 14:34:04 +0200 Subject: [PATCH 08/18] Backends: OpenGL3: restore update path on non-WebGL non-ES targets that doesn't require a CPU copy. (#8802, #8465) Amend/fix dbb91a5 --- backends/imgui_impl_opengl3.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index e9660295e..00d1d94c3 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) -// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) +// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures (#8802) + restore non-WebGL/ES update path that doesn't require a CPU-side copy. // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). // 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) // 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) @@ -758,7 +758,7 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id)); -#if 0// GL_UNPACK_ROW_LENGTH // Not on WebGL/ES +#if GL_UNPACK_ROW_LENGTH // Not on WebGL/ES GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width)); for (ImTextureRect& r : tex->Updates) GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y))); From 57a816ae609b09c384be938d4a1036483fe71f83 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Jul 2025 15:27:17 +0900 Subject: [PATCH 09/18] Texutres: minor comments, tweaks. --- imgui_draw.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f42f96639..5cb0ef8b5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2740,10 +2740,9 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere if (atlas->Builder == NULL) // This will only happen if fonts were not already loaded. ImFontAtlasBuildMain(atlas); } - else // Legacy backend - { + // Legacy backend + if (!atlas->RendererHasTextures) IM_ASSERT_USER_ERROR(atlas->TexIsBuilt, "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()."); - } if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build()."); @@ -2798,8 +2797,9 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere } else if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_WantDestroy) { - // Request destroy. Keep bool as it allows us to keep track of things. - // We don't destroy pixels right away, as backend may have an in-flight copy from RAM. + // Request destroy. + // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend. + // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM. IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates); tex->Status = ImTextureStatus_WantDestroy; } @@ -2955,7 +2955,7 @@ void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, tex->UsedRect.h = (unsigned short)(ImMax(tex->UsedRect.y + tex->UsedRect.h, req.y + req.h) - tex->UsedRect.y); atlas->TexIsBuilt = false; - // No need to queue if status is _WantCreate + // No need to queue if status is == ImTextureStatus_WantCreate if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates) { tex->Status = ImTextureStatus_WantUpdates; From c9e0208de4512ba2c9d93da76d8a71ed5de092d5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Jul 2025 15:35:53 +0900 Subject: [PATCH 10/18] Textures: moved UpdateTexturesNewFrame(), UpdateTexturesEndFrame() to a more suitable location in the file. --- imgui.cpp | 86 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 31a95716b..02080d14b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -78,7 +78,7 @@ CODE // [SECTION] RENDER HELPERS // [SECTION] INITIALIZATION, SHUTDOWN // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) -// [SECTION] FONTS +// [SECTION] FONTS, TEXTURES // [SECTION] ID STACK // [SECTION] INPUTS // [SECTION] ERROR CHECKING, STATE RECOVERY @@ -5261,46 +5261,6 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos) io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; } -static void ImGui::UpdateTexturesNewFrame() -{ - // Cannot update every atlases based on atlas's FrameCount < g.FrameCount, because an atlas may be shared by multiple contexts with different frame count. - ImGuiContext& g = *GImGui; - const bool has_textures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; - for (ImFontAtlas* atlas : g.FontAtlases) - { - if (atlas->OwnerContext == &g) - { - ImFontAtlasUpdateNewFrame(atlas, g.FrameCount, has_textures); - } - else - { - // (1) If you manage font atlases yourself, e.g. create a ImFontAtlas yourself you need to call ImFontAtlasUpdateNewFrame() on it. - // Otherwise, calling ImGui::CreateContext() without parameter will create an atlas owned by the context. - // (2) If you have multiple font atlases, make sure the 'atlas->RendererHasTextures' as specified in the ImFontAtlasUpdateNewFrame() call matches for that. - // (3) If you have multiple imgui contexts, they also need to have a matching value for ImGuiBackendFlags_RendererHasTextures. - IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1); - IM_ASSERT(atlas->RendererHasTextures == has_textures); - } - } -} - -// Build a single texture list -static void ImGui::UpdateTexturesEndFrame() -{ - ImGuiContext& g = *GImGui; - g.PlatformIO.Textures.resize(0); - for (ImFontAtlas* atlas : g.FontAtlases) - for (ImTextureData* tex : atlas->TexList) - { - // We provide this information so backends can decide whether to destroy textures. - // This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized. - tex->RefCount = (unsigned short)atlas->RefCount; - g.PlatformIO.Textures.push_back(tex); - } - for (ImTextureData* tex : g.UserTextures) - g.PlatformIO.Textures.push_back(tex); -} - // Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. // FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal! static void SetupDrawListSharedData() @@ -8671,11 +8631,13 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) } //----------------------------------------------------------------------------- -// [SECTION] FONTS +// [SECTION] FONTS, TEXTURES //----------------------------------------------------------------------------- // Most of the relevant font logic is in imgui_draw.cpp. // Those are high-level support functions. //----------------------------------------------------------------------------- +// - UpdateTexturesNewFrame() [Internal] +// - UpdateTexturesEndFrame() [Internal] // - UpdateFontsNewFrame() [Internal] // - UpdateFontsEndFrame() [Internal] // - GetDefaultFont() [Internal] @@ -8690,6 +8652,46 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) // - PopFont() //----------------------------------------------------------------------------- +static void ImGui::UpdateTexturesNewFrame() +{ + // Cannot update every atlases based on atlas's FrameCount < g.FrameCount, because an atlas may be shared by multiple contexts with different frame count. + ImGuiContext& g = *GImGui; + const bool has_textures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; + for (ImFontAtlas* atlas : g.FontAtlases) + { + if (atlas->OwnerContext == &g) + { + ImFontAtlasUpdateNewFrame(atlas, g.FrameCount, has_textures); + } + else + { + // (1) If you manage font atlases yourself, e.g. create a ImFontAtlas yourself you need to call ImFontAtlasUpdateNewFrame() on it. + // Otherwise, calling ImGui::CreateContext() without parameter will create an atlas owned by the context. + // (2) If you have multiple font atlases, make sure the 'atlas->RendererHasTextures' as specified in the ImFontAtlasUpdateNewFrame() call matches for that. + // (3) If you have multiple imgui contexts, they also need to have a matching value for ImGuiBackendFlags_RendererHasTextures. + IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1); + IM_ASSERT(atlas->RendererHasTextures == has_textures); + } + } +} + +// Build a single texture list +static void ImGui::UpdateTexturesEndFrame() +{ + ImGuiContext& g = *GImGui; + g.PlatformIO.Textures.resize(0); + for (ImFontAtlas* atlas : g.FontAtlases) + for (ImTextureData* tex : atlas->TexList) + { + // We provide this information so backends can decide whether to destroy textures. + // This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized. + tex->RefCount = (unsigned short)atlas->RefCount; + g.PlatformIO.Textures.push_back(tex); + } + for (ImTextureData* tex : g.UserTextures) + g.PlatformIO.Textures.push_back(tex); +} + void ImGui::UpdateFontsNewFrame() { ImGuiContext& g = *GImGui; From 3401dbde92cab3691fa04ea3d773f051d9fa7307 Mon Sep 17 00:00:00 2001 From: Rhys Pounder <60443928+Rhys-Pounder@users.noreply.github.com> Date: Mon, 21 Jul 2025 07:42:16 +0100 Subject: [PATCH 11/18] Docs: Fixed typo. (#8817) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 7c62950d8..0cd64fa82 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,7 +16,7 @@ Businesses: support continued development and maintenance via invoiced sponsorin | [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Releases & Changelogs](#releases--changelogs) - [Demo](#demo) - [Getting Started & Integration](#getting-started--integration) | :----------------------------------------------------------: | | [Gallery](#gallery) - [Support, FAQ](#support-frequently-asked-questions-faq) - [How to help](#how-to-help) - **[Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding)** - [Credits](#credits) - [License](#license) | -| [Wiki](https://github.com/ocornut/imgui/wiki) - [Extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions) - [Languages bindings & frameworks backends](https://github.com/ocornut/imgui/wiki/Bindings) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) - [User quotes](https://github.com/ocornut/imgui/wiki/Quotes) | +| [Wiki](https://github.com/ocornut/imgui/wiki) - [Extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions) - [Language bindings & framework backends](https://github.com/ocornut/imgui/wiki/Bindings) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) - [User quotes](https://github.com/ocornut/imgui/wiki/Quotes) | ### The Pitch From ed5bd1f9ef951628491b7d2355410a703fa2046f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Jul 2025 14:06:44 +0900 Subject: [PATCH 12/18] Changed ImTextCharToUtf8() to return bytes count rather than original pointer. (#8820) Amend c2bf4abfa12 --- imgui.cpp | 15 ++++++++++----- imgui.h | 2 +- imgui_internal.h | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 02080d14b..dc29cdb32 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2582,11 +2582,11 @@ static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int return 0; } -const char* ImTextCharToUtf8(char out_buf[5], unsigned int c) +int ImTextCharToUtf8(char out_buf[5], unsigned int c) { int count = ImTextCharToUtf8_inline(out_buf, 5, c); out_buf[count] = 0; - return out_buf; + return count; } // Not optimal but we very rarely use this function. @@ -16922,8 +16922,10 @@ void ImGui::DebugNodeFont(ImFont* font) #endif char c_str[5]; - Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar); - Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar); + ImTextCharToUtf8(c_str, font->FallbackChar); + Text("Fallback character: '%s' (U+%04X)", c_str, font->FallbackChar); + ImTextCharToUtf8(c_str, font->EllipsisChar); + Text("Ellipsis character: '%s' (U+%04X)", c_str, font->EllipsisChar); for (int src_n = 0; src_n < font->Sources.Size; src_n++) { @@ -16965,7 +16967,10 @@ void ImGui::DebugNodeFont(ImFont* font) { char utf8_buf[5]; for (unsigned int n = c; n < c_end; n++) - BulletText("Codepoint U+%04X (%s)", n, ImTextCharToUtf8(utf8_buf, n)); + { + ImTextCharToUtf8(utf8_buf, n); + BulletText("Codepoint U+%04X (%s)", n, utf8_buf); + } TreePop(); } TableNextColumn(); diff --git a/imgui.h b/imgui.h index 5d947b23d..4caa4e134 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.2 WIP" -#define IMGUI_VERSION_NUM 19211 +#define IMGUI_VERSION_NUM 19212 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 diff --git a/imgui_internal.h b/imgui_internal.h index f5f324c6e..f0e6b4175 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -417,7 +417,7 @@ IMGUI_API const char* ImParseFormatSanitizeForScanning(const char* fmt_in, cha IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); // Helpers: UTF-8 <> wchar conversions -IMGUI_API const char* ImTextCharToUtf8(char out_buf[5], unsigned int c); // return out_buf +IMGUI_API int ImTextCharToUtf8(char out_buf[5], unsigned int c); // return output UTF-8 bytes count IMGUI_API int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count IMGUI_API int ImTextStrFromUtf8(ImWchar* out_buf, int out_buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count From ea613e181c95de2765e92e7b52ba1a849070df8a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Jul 2025 16:22:53 +0900 Subject: [PATCH 13/18] Windows: fixed an issue where resizable child windows would emit border logic when hidden/non-visible. (#8815) This makes more sense in docking branch but may be merged in master right away. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 17cf659ba..f58f01a50 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking Changes: Other Changes: +- Windows: fixed an issue where resizable child windows would emit border + logic when hidden/non-visible (e.g. when in a docked window that is not + selected), impacting code not checking for BeginChild() return value. (#8815) - Error Handling: minor improvements to error handling for TableGetSortSpecs() and TableSetBgColor() calls. (#1651, #8499) - Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating diff --git a/imgui.cpp b/imgui.cpp index dc29cdb32..769fd44df 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7578,12 +7578,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) } #endif + // Decide if we are going to handle borders and resize grips + // 'window->SkipItems' is not updated yet so for child windows we rely on ParentWindow to avoid submitting decorations. (#8815) + // Whenever we add support for full decorated child windows we will likely make this logic more general. + bool handle_borders_and_resize_grips = true; + if ((flags & ImGuiWindowFlags_ChildWindow) && window->ParentWindow->SkipItems) + handle_borders_and_resize_grips = false; + // Handle manual resize: Resize Grips, Borders, Gamepad int border_hovered = -1, border_held = -1; ImU32 resize_grip_col[4] = {}; const int resize_grip_count = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) ? 0 : g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); - if (!window->Collapsed) + if (handle_borders_and_resize_grips && !window->Collapsed) if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) { if (auto_fit_mask & (1 << ImGuiAxis_X)) @@ -7720,7 +7727,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Handle title bar, scrollbar, resize grips and resize borders const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); - const bool handle_borders_and_resize_grips = true; // This exists to facilitate merge with 'docking' branch. RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size); if (render_decorations_in_parent) From 9c392896b750c056e952bc84e6036c0d6bc1acaa Mon Sep 17 00:00:00 2001 From: gomkyung2 Date: Thu, 17 Jul 2025 18:56:12 +0900 Subject: [PATCH 14/18] Misc: removed more redundant inline static linkage from imgui_internal.h. (#8813, #8682, #8358) --- docs/CHANGELOG.txt | 2 + imgui_internal.h | 114 ++++++++++++++++++++++----------------------- 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f58f01a50..da2162b9f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,8 @@ Other Changes: selected), impacting code not checking for BeginChild() return value. (#8815) - Error Handling: minor improvements to error handling for TableGetSortSpecs() and TableSetBgColor() calls. (#1651, #8499) +- Misc: removed more redundant inline static linkage from imgui_internal.h to + facilitate using in C++ modules. (#8813, #8682, #8358) [@stripe2933] - Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) [@Daandelange] diff --git a/imgui_internal.h b/imgui_internal.h index f0e6b4175..e92ab7b5c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -369,17 +369,17 @@ IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImGuiI // Helpers: Sorting #ifndef ImQsort -static inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); } +inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); } #endif // Helpers: Color Blending IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); // Helpers: Bit manipulation -static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } -static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; } -static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } -static inline unsigned int ImCountSetBits(unsigned int v) { unsigned int count = 0; while (v > 0) { v = v & (v - 1); count++; } return count; } +inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } +inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; } +inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } +inline unsigned int ImCountSetBits(unsigned int v) { unsigned int count = 0; while (v > 0) { v = v & (v - 1); count++; } return count; } // Helpers: String #define ImStrlen strlen @@ -398,10 +398,10 @@ IMGUI_API const char* ImStrSkipBlank(const char* str); IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string) IMGUI_API const char* ImStrbol(const char* buf_mid_line, const char* buf_begin); // Find beginning-of-line IM_MSVC_RUNTIME_CHECKS_OFF -static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } -static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } -static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } -static inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); } +inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } +inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } +inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); } IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Formatting @@ -431,11 +431,11 @@ IMGUI_API int ImTextCountLines(const char* in_text, const char* in_tex #ifdef IMGUI_DISABLE_FILE_FUNCTIONS #define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS typedef void* ImFileHandle; -static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; } -static inline bool ImFileClose(ImFileHandle) { return false; } -static inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; } -static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; } -static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; } +inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; } +inline bool ImFileClose(ImFileHandle) { return false; } +inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; } +inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; } +inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; } #endif #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS typedef FILE* ImFileHandle; @@ -462,56 +462,56 @@ IM_MSVC_RUNTIME_CHECKS_OFF #define ImAtan2(Y, X) atan2f((Y), (X)) #define ImAtof(STR) atof(STR) #define ImCeil(X) ceilf(X) -static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision -static inline double ImPow(double x, double y) { return pow(x, y); } -static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision -static inline double ImLog(double x) { return log(x); } -static inline int ImAbs(int x) { return x < 0 ? -x : x; } -static inline float ImAbs(float x) { return fabsf(x); } -static inline double ImAbs(double x) { return fabs(x); } -static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument -static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; } +inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision +inline double ImPow(double x, double y) { return pow(x, y); } +inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision +inline double ImLog(double x) { return log(x); } +inline int ImAbs(int x) { return x < 0 ? -x : x; } +inline float ImAbs(float x) { return fabsf(x); } +inline double ImAbs(double x) { return fabs(x); } +inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument +inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; } #ifdef IMGUI_ENABLE_SSE -static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } +inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } #else -static inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); } +inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); } #endif -static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } +inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } #endif // - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double // (Exceptionally using templates here but we could also redefine them for those types) -template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } -template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } -template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } -template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } -template static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } -template static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } -template static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } +template T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } +template T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } +template T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } +template T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } +template void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } +template T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } +template T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } // - Misc maths helpers -static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } -static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } -static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2&mn, const ImVec2&mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); } -static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } -static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } -static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } -static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } -static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); } -static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); } -static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; } -static inline float ImTrunc(float f) { return (float)(int)(f); } -static inline ImVec2 ImTrunc(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } -static inline float ImFloor(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() -static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); } -static inline float ImTrunc64(float f) { return (float)(ImS64)(f); } -static inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } -static inline int ImModPositive(int a, int b) { return (a + b) % b; } -static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } -static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } -static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } -static inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; } -static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } -static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } -static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; } +inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } +inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } +inline ImVec2 ImClamp(const ImVec2& v, const ImVec2&mn, const ImVec2&mx){ return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); } +inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } +inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } +inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } +inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } +inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); } +inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); } +inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; } +inline float ImTrunc(float f) { return (float)(int)(f); } +inline ImVec2 ImTrunc(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } +inline float ImFloor(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() +inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); } +inline float ImTrunc64(float f) { return (float)(ImS64)(f); } +inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } +inline int ImModPositive(int a, int b) { return (a + b) % b; } +inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } +inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } +inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } +inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; } +inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } +inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / n; avg += sample / n; return avg; } IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Geometry From 4a51295c9e72b7339657c7e3baa40a66bc359caa Mon Sep 17 00:00:00 2001 From: Tim-Rex Date: Sat, 12 Jul 2025 16:47:45 +1000 Subject: [PATCH 15/18] Backends: OpenGL3: add and call embedded loader shutdown in ImGui_ImplOpenGL3_Shutdown(). (#8792) Include update of imgui_impl_opengl3_loader.h as submitted to gl3w_stripped repository, which adds imgl3wShutdown(). --- backends/imgui_impl_opengl3.cpp | 5 +++++ backends/imgui_impl_opengl3_loader.h | 14 ++++++++++---- docs/CHANGELOG.txt | 2 ++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 00d1d94c3..607d24371 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,6 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-22: OpenGL: Add and call embedded loader shutdown during ImGui_ImplOpenGL3_Shutdown() to facilitate multiple init/shutdown cycles in same process. (#8792) // 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures (#8802) + restore non-WebGL/ES update path that doesn't require a CPU-side copy. // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). // 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) @@ -422,6 +423,10 @@ void ImGui_ImplOpenGL3_Shutdown() io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); + +#ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W + imgl3wShutdown(); +#endif } void ImGui_ImplOpenGL3_NewFrame() diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h index aa8fdc27e..c3f5a93f5 100644 --- a/backends/imgui_impl_opengl3_loader.h +++ b/backends/imgui_impl_opengl3_loader.h @@ -477,6 +477,7 @@ typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc); /* gl3w api */ GL3W_API int imgl3wInit(void); GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc); +GL3W_API void imgl3wShutdown(void); GL3W_API int imgl3wIsSupported(int major, int minor); GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc); @@ -632,7 +633,7 @@ extern "C" { #endif #include -static HMODULE libgl; +static HMODULE libgl = NULL; typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR); static GL3WglGetProcAddr wgl_get_proc_address; @@ -645,7 +646,7 @@ static int open_libgl(void) return GL3W_OK; } -static void close_libgl(void) { FreeLibrary(libgl); } +static void close_libgl(void) { FreeLibrary(libgl); libgl = NULL; } static GL3WglProc get_proc(const char *proc) { GL3WglProc res; @@ -657,7 +658,7 @@ static GL3WglProc get_proc(const char *proc) #elif defined(__APPLE__) #include -static void *libgl; +static void *libgl = NULL; static int open_libgl(void) { libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL); @@ -666,7 +667,7 @@ static int open_libgl(void) return GL3W_OK; } -static void close_libgl(void) { dlclose(libgl); } +static void close_libgl(void) { dlclose(libgl); libgl = NULL; } static GL3WglProc get_proc(const char *proc) { @@ -834,6 +835,11 @@ int imgl3wInit2(GL3WGetProcAddressProc proc) return parse_version(); } +void imgl3wShutdown(void) +{ + close_libgl(); +} + int imgl3wIsSupported(int major, int minor) { if (major < 2) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index da2162b9f..edc43247a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,8 @@ Other Changes: and TableSetBgColor() calls. (#1651, #8499) - Misc: removed more redundant inline static linkage from imgui_internal.h to facilitate using in C++ modules. (#8813, #8682, #8358) [@stripe2933] +- Backends: OpenGL3: add and call embedded loader shutdown in ImGui_ImplOpenGL3_Shutdown() + to facilitate multiple init/shutdown cycles in same process. (#8792) [@tim-rex] - Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) [@Daandelange] From c96e9c82739944ac38e2efbc056697d24c18e2e2 Mon Sep 17 00:00:00 2001 From: scribam Date: Sun, 20 Jul 2025 18:04:57 +0200 Subject: [PATCH 16/18] CI: Update Windows CI to use a more recent SDL2. (#8819, #8778) --- .github/workflows/build.yml | 6 +++--- docs/CHANGELOG.txt | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 95bcf3e76..13cc0b88b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,9 +27,9 @@ jobs: - name: Install Dependencies shell: powershell run: | - Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL2-devel-2.26.3-VC.zip" -OutFile "SDL2-devel-2.26.3-VC.zip" - Expand-Archive -Path SDL2-devel-2.26.3-VC.zip - echo "SDL2_DIR=$(pwd)\SDL2-devel-2.26.3-VC\SDL2-2.26.3\" >>${env:GITHUB_ENV} + Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL2-devel-2.32.8-VC.zip" -OutFile "SDL2-devel-2.32.8-VC.zip" + Expand-Archive -Path SDL2-devel-2.32.8-VC.zip + echo "SDL2_DIR=$(pwd)\SDL2-devel-2.32.8-VC\SDL2-2.32.8\" >>${env:GITHUB_ENV} Invoke-WebRequest -Uri "https://github.com/ocornut/imgui/files/3789205/vulkan-sdk-1.1.121.2.zip" -OutFile vulkan-sdk-1.1.121.2.zip Expand-Archive -Path vulkan-sdk-1.1.121.2.zip diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index edc43247a..a2b749e72 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,7 @@ Other Changes: and TableSetBgColor() calls. (#1651, #8499) - Misc: removed more redundant inline static linkage from imgui_internal.h to facilitate using in C++ modules. (#8813, #8682, #8358) [@stripe2933] +- CI: Update Windows CI to use a more recent SDL2. (#8819, #8778) [@scribam] - Backends: OpenGL3: add and call embedded loader shutdown in ImGui_ImplOpenGL3_Shutdown() to facilitate multiple init/shutdown cycles in same process. (#8792) [@tim-rex] - Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating From 7babc24ad4ef7091b76fa94ef91277bc5154d3a6 Mon Sep 17 00:00:00 2001 From: scribam Date: Sun, 20 Jul 2025 18:08:11 +0200 Subject: [PATCH 17/18] CI: Add SDL3 builds to MacOS and Windows. (#8819, #8778) --- .github/workflows/build.yml | 48 ++++++++++++++++++++++++++++++++++++- docs/CHANGELOG.txt | 3 ++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 13cc0b88b..0eb409247 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,6 +30,10 @@ jobs: Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL2-devel-2.32.8-VC.zip" -OutFile "SDL2-devel-2.32.8-VC.zip" Expand-Archive -Path SDL2-devel-2.32.8-VC.zip echo "SDL2_DIR=$(pwd)\SDL2-devel-2.32.8-VC\SDL2-2.32.8\" >>${env:GITHUB_ENV} + + Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL3-devel-3.2.18-VC.zip" -OutFile "SDL3-devel-3.2.18-VC.zip" + Expand-Archive -Path SDL3-devel-3.2.18-VC.zip + echo "SDL3_DIR=$(pwd)\SDL3-devel-3.2.18-VC\SDL3-3.2.18\" >>${env:GITHUB_ENV} Invoke-WebRequest -Uri "https://github.com/ocornut/imgui/files/3789205/vulkan-sdk-1.1.121.2.zip" -OutFile vulkan-sdk-1.1.121.2.zip Expand-Archive -Path vulkan-sdk-1.1.121.2.zip @@ -140,6 +144,25 @@ jobs: run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release' if: github.event_name == 'workflow_run' + - name: Build Win32 example_sdl3_opengl3 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release' + + - name: Build Win32 example_sdl3_sdlgpu3 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj /p:Platform=Win32 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + + - name: Build Win32 example_sdl3_sdlrenderer3 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj /p:Platform=Win32 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + + - name: Build Win32 example_sdl3_vulkan + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + - name: Build Win32 example_win32_directx9 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=Win32 /p:Configuration=Release' @@ -190,6 +213,26 @@ jobs: shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release' + - name: Build x64 example_sdl3_opengl3 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + + - name: Build x64 example_sdl3_sdlgpu3 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj /p:Platform=x64 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + + - name: Build x64 example_sdl3_sdlrenderer3 + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj /p:Platform=x64 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + + - name: Build x64 example_sdl3_vulkan + shell: cmd + run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release' + if: github.event_name == 'workflow_run' + - name: Build x64 example_win32_directx9 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=x64 /p:Configuration=Release' @@ -433,7 +476,7 @@ jobs: - name: Install Dependencies run: | - brew install glfw3 sdl2 + brew install glfw3 sdl2 sdl3 - name: Build example_null (extra warnings, clang 64-bit) run: make -C examples/example_null WITH_EXTRA_WARNINGS=1 @@ -491,6 +534,9 @@ jobs: - name: Build example_sdl2_opengl3 run: make -C examples/example_sdl2_opengl3 + - name: Build example_sdl3_opengl3 + run: make -C examples/example_sdl3_opengl3 + - name: Build example_apple_metal run: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_macos diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a2b749e72..5626bb3e5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,7 +50,8 @@ Other Changes: and TableSetBgColor() calls. (#1651, #8499) - Misc: removed more redundant inline static linkage from imgui_internal.h to facilitate using in C++ modules. (#8813, #8682, #8358) [@stripe2933] -- CI: Update Windows CI to use a more recent SDL2. (#8819, #8778) [@scribam] +- CI: Added SDL3 builds to MacOS and Windows. (#8819, #8778) [@scribam] +- CI: Updated Windows CI to use a more recent SDL2. (#8819, #8778) [@scribam] - Backends: OpenGL3: add and call embedded loader shutdown in ImGui_ImplOpenGL3_Shutdown() to facilitate multiple init/shutdown cycles in same process. (#8792) [@tim-rex] - Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating From 06ab541e2fc182c35b59cd4b011f2afdc7924b7f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Jul 2025 17:01:26 +0900 Subject: [PATCH 18/18] CI: Adjust policies to more frequently build Win64 SDL3+SDL_Renderer, SDL3+SDL_GPU, and tweak others. --- .github/workflows/build.yml | 41 ++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0eb409247..bb2e502a2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -106,9 +106,12 @@ jobs: cl.exe /D_USRDLL /D_WINDLL /I. example_single_file.cpp /LD /FeImGui.dll /link cl.exe /DIMGUI_API=__declspec(dllimport) /I. ImGui.lib /Feexample_null.exe examples/example_null/main.cpp + # Win64 examples are more frequently compilted than the Win32 examples. + # More of the Win32 examples requires 'workflow_run' to reduce waste. - name: Build Win32 example_glfw_opengl2 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj /p:Platform=Win32 /p:Configuration=Release' + if: github.event_name == 'workflow_run' - name: Build Win32 example_glfw_opengl3 shell: cmd @@ -166,89 +169,89 @@ jobs: - name: Build Win32 example_win32_directx9 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=Win32 /p:Configuration=Release' + if: github.event_name == 'workflow_run' - name: Build Win32 example_win32_directx10 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx10/example_win32_directx10.vcxproj /p:Platform=Win32 /p:Configuration=Release' + if: github.event_name == 'workflow_run' - name: Build Win32 example_win32_directx11 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_glfw_opengl2 + # Windows 64-bits + - name: Build Win64 example_glfw_opengl2 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_glfw_opengl3 + - name: Build Win64 example_glfw_opengl3 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release' - - name: Build x64 example_glfw_vulkan + - name: Build Win64 example_glfw_vulkan shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release' - - name: Build x64 example_sdl2_sdlrenderer2 + - name: Build Win64 example_sdl2_sdlrenderer2 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_sdl2_vulkan + - name: Build Win64 example_sdl2_vulkan shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_sdl2_opengl2 + - name: Build Win64 example_sdl2_opengl2 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_sdl2_opengl3 + - name: Build Win64 example_sdl2_opengl3 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_sdl2_directx11 + - name: Build Win64 example_sdl2_directx11 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release' - - name: Build x64 example_sdl3_opengl3 + - name: Build Win64 example_sdl3_opengl3 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_sdl3_sdlgpu3 + - name: Build Win64 example_sdl3_sdlgpu3 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj /p:Platform=x64 /p:Configuration=Release' - if: github.event_name == 'workflow_run' - - name: Build x64 example_sdl3_sdlrenderer3 + - name: Build Win64 example_sdl3_sdlrenderer3 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj /p:Platform=x64 /p:Configuration=Release' - if: github.event_name == 'workflow_run' - - name: Build x64 example_sdl3_vulkan + - name: Build Win64 example_sdl3_vulkan shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_win32_directx9 + - name: Build Win64 example_win32_directx9 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_win32_directx10 + - name: Build Win64 example_win32_directx10 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx10/example_win32_directx10.vcxproj /p:Platform=x64 /p:Configuration=Release' if: github.event_name == 'workflow_run' - - name: Build x64 example_win32_directx11 + - name: Build Win64 example_win32_directx11 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release' - if: github.event_name == 'workflow_run' - - name: Build x64 example_win32_directx12 + - name: Build Win64 example_win32_directx12 shell: cmd run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx12/example_win32_directx12.vcxproj /p:Platform=x64 /p:Configuration=Release'