From fb5c53708075709a4f859d8b5721893aad89a244 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 3 Apr 2025 19:10:16 +0200 Subject: [PATCH] Fonts: changing loader/backend or loader flags may be done without losing custom rects. Sharing more code. --- imgui.cpp | 27 ++++++++++++----- imgui_draw.cpp | 79 ++++++++++++++++++++++++------------------------ imgui_internal.h | 4 +-- 3 files changed, 61 insertions(+), 49 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 00bb950fc..a713390c3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15695,9 +15695,16 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype); if (loader_current == loader_freetype) { - Text("Shared FreeType Loader Flags:"); - if (ImGuiFreeType::DebugEditFontBuilderFlags(&atlas->FontBuilderFlags)) - ImFontAtlasBuildReloadAll(atlas); + unsigned int loader_flags = atlas->FontBuilderFlags; + Text("Shared FreeType Loader Flags: 0x%08", loader_flags); + if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) + { + for (ImFont* font : atlas->Fonts) + ImFontAtlasBuildDestroyFontOutput(atlas, font); + atlas->FontBuilderFlags = loader_flags; + for (ImFont* font : atlas->Fonts) + ImFontAtlasBuildInitFontOutput(atlas, font); + } } #else BeginDisabled(); @@ -15724,8 +15731,9 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) if (Button("Grow")) ImFontAtlasBuildGrowTexture(atlas); SameLine(); - if (Button("Clear Output")) + if (Button("Clear All")) ImFontAtlasBuildClear(atlas); + SetItemTooltip("Destroy cache and custom rectangles."); for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { @@ -16613,9 +16621,14 @@ void ImGui::DebugNodeFont(ImFont* font) #ifdef IMGUI_ENABLE_FREETYPE if (loader->Name != NULL && strcmp(loader->Name, "FreeType") == 0) { - Text("FreeType Loader Flags: 0x%08X", src->FontBuilderFlags); - if (ImGuiFreeType::DebugEditFontBuilderFlags(&src->FontBuilderFlags)) - ImFontAtlasBuildReloadFont(atlas, src); + unsigned int loader_flags = src->FontBuilderFlags; + Text("FreeType Loader Flags: 0x%08X", loader_flags); + if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) + { + ImFontAtlasBuildDestroyFontOutput(atlas, font); + src->FontBuilderFlags = loader_flags; + ImFontAtlasBuildInitFontOutput(atlas, font); + } } #endif TreePop(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f3a79b4e7..b1683e204 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2649,14 +2649,11 @@ void ImFontAtlas::CompactCache() void ImFontAtlas::ClearInputData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - for (ImFontConfig& font_cfg : Sources) - { - const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : FontLoader; - if (loader && loader->FontSrcDestroy != NULL) - loader->FontSrcDestroy(this, &font_cfg); - ImFontAtlasBuildDestroyFontSourceData(this, &font_cfg); - } + for (ImFont* font : Fonts) + ImFontAtlasBuildDestroyFontOutput(this, font); + for (ImFontConfig& font_cfg : Sources) + ImFontAtlasBuildDestroyFontSourceData(this, &font_cfg); for (ImFont* font : Fonts) { // When clearing this we lose access to the font name and other information used to build the font. @@ -3197,15 +3194,9 @@ void ImFontAtlas::RemoveFont(ImFont* font) IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); font->ClearOutputData(); + ImFontAtlasBuildDestroyFontOutput(this, font); for (int src_n = 0; src_n < font->SourcesCount; src_n++) - { - ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n]; - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : FontLoader; - if (loader && loader->FontSrcDestroy != NULL) - loader->FontSrcDestroy(this, src); - if (src->FontData != NULL && src->FontDataOwnedByAtlas) - IM_FREE(src->FontData); - } + ImFontAtlasBuildDestroyFontSourceData(this, &font->Sources[src_n]); bool removed = Fonts.find_erase(font); IM_ASSERT(removed); @@ -3376,15 +3367,19 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon return; IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); - // Note that texture size estimate is likely incorrect in this situation, as FreeType backend doesn't use oversampling. - ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); - ImFontAtlasBuildDestroy(atlas); + for (ImFont* font : atlas->Fonts) + ImFontAtlasBuildDestroyFontOutput(atlas, font); + if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) + atlas->FontLoader->LoaderShutdown(atlas); atlas->FontLoader = font_loader; atlas->FontLoaderName = font_loader ? font_loader->Name : "NULL"; + IM_ASSERT(atlas->FontLoaderData == NULL); - ImFontAtlasBuildAddTexture(atlas, new_tex_size.x, new_tex_size.y); - ImFontAtlasBuildInit(atlas); + if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderInit) + atlas->FontLoader->LoaderInit(atlas); + for (ImFont* font : atlas->Fonts) + ImFontAtlasBuildInitFontOutput(atlas, font); } // Preload all glyph ranges for legacy backends. @@ -3562,18 +3557,31 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ //----------------------------------------------------------------------------------------------------------------------------- -void ImFontAtlasBuildReloadAll(ImFontAtlas* atlas) +bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, ImFont* font) { - const ImFontLoader* main_loader = atlas->FontLoader; - ImFontAtlasBuildSetupFontLoader(atlas, NULL); - ImFontAtlasBuildSetupFontLoader(atlas, main_loader); + bool ret = true; + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader && loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) + ret = false; + } + IM_ASSERT(ret); // Unclear how to react to this meaningfully. Assume that result will be same as initial AddFont() call. + return ret; } -void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFontConfig* src) +// Keep source/input FontData +void ImFontAtlasBuildDestroyFontOutput(ImFontAtlas* atlas, ImFont* font) { - // FIXME-NEWATLAS: rebuild single font not supported yet. - IM_UNUSED(src); - ImFontAtlasBuildReloadAll(atlas); + font->ClearOutputData(); + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader && loader->FontSrcDestroy != NULL) + loader->FontSrcDestroy(atlas, src); + } } //----------------------------------------------------------------------------------------------------------------------------- @@ -4148,13 +4156,8 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) #else IM_ASSERT(0); // Invalid Build function #endif - return; // ImFontAtlasBuildSetupFontLoader() automatically call ImFontAtlasBuildInit() } - IM_ASSERT(atlas->FontLoaderData == NULL); - if (atlas->FontLoader->LoaderInit) - atlas->FontLoader->LoaderInit(atlas); - // Create initial texture size if (atlas->TexData == NULL || atlas->TexData->Pixels == NULL) ImFontAtlasBuildAddTexture(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight)); @@ -4165,6 +4168,8 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) { IM_ASSERT(atlas->Builder == NULL); builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); + if (atlas->FontLoader->LoaderInit) + atlas->FontLoader->LoaderInit(atlas); } ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); @@ -4193,13 +4198,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) { for (ImFont* font : atlas->Fonts) - font->ClearOutputData(); - for (ImFontConfig& font_cfg : atlas->Sources) - { - const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : atlas->FontLoader; - if (loader && loader->FontSrcDestroy != NULL) - loader->FontSrcDestroy(atlas, &font_cfg); - } + ImFontAtlasBuildDestroyFontOutput(atlas, font); if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) { atlas->FontLoader->LoaderShutdown(atlas); diff --git a/imgui_internal.h b/imgui_internal.h index 41b99b438..009f6f9c9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3774,9 +3774,9 @@ IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontCo IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); +IMGUI_API bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, ImFont* font); // Using DestroyFontOutput/InitFontOutput sequence useful notably if font loader params have changed +IMGUI_API void ImFontAtlasBuildDestroyFontOutput(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildDestroyFontSourceData(ImFontAtlas* atlas, ImFontConfig* src); -IMGUI_API void ImFontAtlasBuildReloadAll(ImFontAtlas* atlas); // Reinit/rebuild, notably if font loader params have changed. -IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFontConfig* src); // Reinit/rebuild, notably if font loader params have changed. IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); IMGUI_API ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size);