From 73dd0e869dff793bca8813832c8dd8b65b4ae661 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 23 Dec 2025 14:30:16 +0100 Subject: [PATCH] (Breaking) Fonts: remove ImFontConfig::PixelSnapV. Post-rescale GlyphOffset is always rounded. Amend 99f6b305c, 99bca397d8. --- docs/CHANGELOG.txt | 28 ++++++++++++++++------------ imgui.cpp | 8 ++++---- imgui.h | 6 ++++-- imgui_draw.cpp | 12 ++++-------- misc/freetype/imgui_freetype.cpp | 8 ++------ 5 files changed, 30 insertions(+), 32 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 114abfbdb..679a61768 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,17 +50,21 @@ Breaking Changes: - This will invalidate hashes (stored in .ini data) for Tables and Windows that are using the "###" operators. (#713, #1698) - Renamed helper macro IM_ARRAYSIZE() -> IM_COUNTOF(). Kept redirection/legacy name. -- Fonts: Fixed handling of `ImFontConfig::FontDataOwnedByAtlas = false` which - did erroneously make a copy of the font data, essentially defeating the purpose - of this flag and wasting memory (undetected since July 2015 and now spotted - by @TellowKrinkle, this is perhaps the oldest bug in Dear ImGui history, - albeit for a rarely used feature!) (#9086, #8465) - HOWEVER, fixing this bug is likely to surface bugs in user/app code: - - Prior to 1.92, font data only needs to be available during the atlas->AddFontXXX() call. - - Since 1.92, font data needs to available until atlas->RemoveFont(), or more typically - until a shutdown of the owning context or font atlas. - - The fact that handling of `FontDataOwnedByAtlas = false` was broken - bypassed the issue altogether. +- Fonts: + - Fixed handling of `ImFontConfig::FontDataOwnedByAtlas = false` which + did erroneously make a copy of the font data, essentially defeating the purpose + of this flag and wasting memory (undetected since July 2015 and now spotted + by @TellowKrinkle, this is perhaps the oldest bug in Dear ImGui history, + albeit for a rarely used feature!) (#9086, #8465) + HOWEVER, fixing this bug is likely to surface bugs in user/app code: + - Prior to 1.92, font data only needs to be available during the atlas->AddFontXXX() call. + Since 1.92, font data needs to available until atlas->RemoveFont(), or more typically + until a shutdown of the owning context or font atlas. + - The fact that handling of `FontDataOwnedByAtlas = false` was broken bypassed + the issue altogether. + - Removed ImFontConfig::PixelSnapV added in 1.92 which turns out is unnecessary + (and misdocumented). Post-rescale GlyphOffset is always rounded. + Other Changes: @@ -70,7 +74,7 @@ Other Changes: - imgui_freetype: fixed overwriting ImFontConfig::PixelSnapH when hinting is enabled, creating side-effects when later disabling hinting or dynamically switching to stb_truetype rasterizer. - which would prevent + - Post rescale GlyphOffset is always rounded. - Textures: - Fixed a building issue when ImTextureID is defined as a struct. - Fixed displaying texture # in Metrics/Debugger window. diff --git a/imgui.cpp b/imgui.cpp index 18dbbce3f..14dc8afca 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -394,13 +394,13 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/12/23 (1.92.6) - Fonts: removed ImFontConfig::PixelSnapV added in 1.92 which turns out is unnecessary (and misdocumented). Post-rescale GlyphOffset is always rounded. - 2025/12/17 (1.92.6) - Renamed helper macro IM_ARRAYSIZE() -> IM_COUNTOF(). Kept redirection/legacy name for now. - 2025/12/11 (1.92.6) - Hashing: handling of "###" operator to reset to seed within a string identifier doesn't include the "###" characters in the output hash anymore. - Before: GetID("Hello###World") == GetID("###World") != GetID("World"); - Now: GetID("Hello###World") == GetID("###World") == GetID("World"); - This has the property of facilitating concatenating and manipulating identifiers using "###", and will allow fixing other dangling issues. - - This will invalidate hashes (stored in .ini data) for Tables and Windows! - that are using the "###" operators. (#713, #1698) + - This will invalidate hashes (stored in .ini data) for Tables and Windows that are using the "###" operators. (#713, #1698) - 2025/11/24 (1.92.6) - Fonts: Fixed handling of `ImFontConfig::FontDataOwnedByAtlas = false` which did erroneously make a copy of the font data, essentially defeating the purpose of this flag and wasting memory. (trivia: undetected since July 2015, this is perhaps the oldest bug in Dear ImGui history, albeit for a rarely used feature, see #9086) HOWEVER, fixing this bug is likely to surface bugs in user code using `FontDataOwnedByAtlas = false`. @@ -1265,7 +1265,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: #define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window // Default font size if unspecified in both style.FontSizeBase and AddFontXXX() calls. -static const float FONT_DEFAULT_SIZE = 20.0f; +static const float FONT_DEFAULT_SIZE_BASE = 20.0f; // When using Ctrl+Tab (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in @@ -8903,7 +8903,7 @@ void ImGui::UpdateFontsNewFrame() // Apply default font size the first time ImFont* font = ImGui::GetDefaultFont(); if (g.Style.FontSizeBase <= 0.0f) - g.Style.FontSizeBase = (font->LegacySize > 0.0f ? font->LegacySize : FONT_DEFAULT_SIZE); + g.Style.FontSizeBase = (font->LegacySize > 0.0f ? font->LegacySize : FONT_DEFAULT_SIZE_BASE); // Set initial font g.Font = font; diff --git a/imgui.h b/imgui.h index 36f914911..199af5d3c 100644 --- a/imgui.h +++ b/imgui.h @@ -30,7 +30,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.6 WIP" -#define IMGUI_VERSION_NUM 19257 +#define IMGUI_VERSION_NUM 19258 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 @@ -3528,7 +3528,6 @@ struct ImFontConfig // Options bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Prevents fractional font size from working correctly! Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. - bool PixelSnapV; // false // Align Scaled GlyphOffset.y to pixel boundaries. Prevents fractional font size from working correctly!. ImS8 OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. ImS8 OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. @@ -3553,6 +3552,9 @@ struct ImFontConfig const ImFontLoader* FontLoader; // Custom font backend for this source (default source is the one stored in ImFontAtlas) void* FontLoaderData; // Font loader opaque storage (per font config) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + bool PixelSnapV; // true // [Obsoleted in 1.91.6] Align Scaled GlyphOffset.y to pixel boundaries. +#endif IMGUI_API ImFontConfig(); }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index db8994282..f437abc9f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3121,11 +3121,11 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) font_cfg.PixelSnapH = true; } if (font_cfg.SizePixels <= 0.0f) - font_cfg.SizePixels = 13.0f * 1.0f; + font_cfg.SizePixels = 13.0f; // This only serves (1) as a reference for GlyphOffset.y setting and (2) as a default for pre-1.92 backend. if (font_cfg.Name[0] == '\0') ImFormatString(font_cfg.Name, IM_COUNTOF(font_cfg.Name), "ProggyClean.ttf"); font_cfg.EllipsisChar = (ImWchar)0x0085; - font_cfg.GlyphOffset.y += 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units + font_cfg.GlyphOffset.y += 1.0f * (font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units int ttf_compressed_size = 0; const char* ttf_compressed = GetDefaultCompressedFontDataTTF(&ttf_compressed_size); @@ -4721,12 +4721,8 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC const float ref_size = baked->OwnerFont->Sources[0]->SizePixels; const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f; - float font_off_x = (src->GlyphOffset.x * offsets_scale); - float font_off_y = (src->GlyphOffset.y * offsets_scale); - if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. - font_off_x = IM_ROUND(font_off_x); - if (src->PixelSnapV) - font_off_y = IM_ROUND(font_off_y); + float font_off_x = ImFloor(src->GlyphOffset.x * offsets_scale + 0.5f); // Snap scaled offset. + float font_off_y = ImFloor(src->GlyphOffset.y * offsets_scale + 0.5f); font_off_x += sub_x; font_off_y += sub_y + IM_ROUND(baked->Ascent); float recip_h = 1.0f / (oversample_h * rasterizer_density); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 70c794159..c358d89db 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -538,12 +538,8 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf const float ref_size = baked->OwnerFont->Sources[0]->SizePixels; const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f; - float font_off_x = (src->GlyphOffset.x * offsets_scale); - float font_off_y = (src->GlyphOffset.y * offsets_scale) + baked->Ascent; - if (src->PixelSnapH || (bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_NoHinting) == 0) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. - font_off_x = IM_ROUND(font_off_x); - if (src->PixelSnapV) - font_off_y = IM_ROUND(font_off_y); + float font_off_x = ImFloor(src->GlyphOffset.x * offsets_scale + 0.5f); // Snap scaled offset. + float font_off_y = ImFloor(src->GlyphOffset.y * offsets_scale + 0.5f) + baked->Ascent; float recip_h = 1.0f / rasterizer_density; float recip_v = 1.0f / rasterizer_density;