1
0
Fork 0
mirror of https://github.com/ocornut/imgui.git synced 2026-01-11 00:04:24 +00:00

Fonts: Basic heuristic to repack instead of growing. Moved rects count/surface to internals.

This commit is contained in:
ocornut 2025-01-13 17:56:36 +01:00
parent 2137b3448b
commit 8ed4e2dde7
4 changed files with 27 additions and 15 deletions

View file

@ -15594,7 +15594,7 @@ static void MetricsHelpMarker(const char* desc)
} }
#ifdef IMGUI_ENABLE_FREETYPE #ifdef IMGUI_ENABLE_FREETYPE
namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetBackendIOForFreeType(); } namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); }
#endif #endif
// [DEBUG] List fonts in a font atlas and display its texture // [DEBUG] List fonts in a font atlas and display its texture
@ -15628,7 +15628,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
#endif #endif
SameLine(); SameLine();
#ifdef IMGUI_ENABLE_FREETYPE #ifdef IMGUI_ENABLE_FREETYPE
const ImFontLoader* loader_freetype = ImGuiFreeType::GetBackendIOForFreeType(); const ImFontLoader* loader_freetype = ImGuiFreeType::GetFontLoader();
if (RadioButton("FreeType", loader_current == loader_freetype)) if (RadioButton("FreeType", loader_current == loader_freetype))
ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype); ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype);
#else #else

View file

@ -3626,8 +3626,6 @@ struct ImFontAtlas
void* FontLoaderData; // Font backend opaque storage void* FontLoaderData; // Font backend opaque storage
unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig. unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig.
int RefCount; // Number of contexts using this atlas int RefCount; // Number of contexts using this atlas
int _PackedSurface; // Number of packed pixels. Used when compacting to heuristically find the ideal texture size.
int _PackedRects; // Number of packed rectangles.
// [Obsolete] // [Obsolete]
//int TexDesiredWidth; // OBSOLETED in 1.91.5 (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) //int TexDesiredWidth; // OBSOLETED in 1.91.5 (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height)

View file

@ -2504,6 +2504,7 @@ void ImTextureData::DestroyPixels()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// - ImFontAtlasBuildSetTexture() // - ImFontAtlasBuildSetTexture()
// - ImFontAtlasBuildAddTexture() // - ImFontAtlasBuildAddTexture()
// - ImFontAtlasBuildMakeSpace()
// - ImFontAtlasBuildRepackTexture() // - ImFontAtlasBuildRepackTexture()
// - ImFontAtlasBuildGrowTexture() // - ImFontAtlasBuildGrowTexture()
// - ImFontAtlasBuildCompactTexture() // - ImFontAtlasBuildCompactTexture()
@ -3521,7 +3522,7 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src)
// Rasterize our own ellipsis character from a dot. // Rasterize our own ellipsis character from a dot.
// This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used.
// FIXME-NEWATLAS: This borrows too much from FontBackend_FontAddGlyph() and suggest that we should add further helpers. // FIXME-NEWATLAS: This borrows too much from FontLoader's FontAddGlyph() and suggest that we should add further helpers.
static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFontConfig* src, const ImFontGlyph* dot_glyph) static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFontConfig* src, const ImFontGlyph* dot_glyph)
{ {
ImFont* font = src->DstFont; ImFont* font = src->DstFont;
@ -3823,7 +3824,7 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_
IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight)); IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight));
// Grow texture so it follows roughly a square. // Grow texture so it follows roughly a square.
// FIXME-NEWATLAS-V1: Take account of RectsDiscardedSurface: may not need to grow. // Caller should be taking account of RectsDiscardedSurface and may not need to grow.
int new_tex_w = (old_tex_h < old_tex_w) ? old_tex_w : old_tex_w * 2; int new_tex_w = (old_tex_h < old_tex_w) ? old_tex_w : old_tex_w * 2;
int new_tex_h = (old_tex_h < old_tex_w) ? old_tex_h * 2 : old_tex_h; int new_tex_h = (old_tex_h < old_tex_w) ? old_tex_h * 2 : old_tex_h;
@ -3839,6 +3840,16 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_
ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h);
} }
void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas)
{
// Currently using a heuristic for repack without growing.
ImFontAtlasBuilder* builder = atlas->Builder;
if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f)
ImFontAtlasBuildGrowTexture(atlas);
else
ImFontAtlasBuildRepackTexture(atlas, atlas->TexData->Width, atlas->TexData->Height);
}
ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas)
{ {
int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth); int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth);
@ -3849,7 +3860,7 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas)
ImFontAtlasBuilder* builder = atlas->Builder; ImFontAtlasBuilder* builder = atlas->Builder;
min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w); min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w);
min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h); min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h);
const int surface_approx = atlas->_PackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack const int surface_approx = builder->RectsPackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack
const int surface_sqrt = (int)sqrtf((float)surface_approx); const int surface_sqrt = (int)sqrtf((float)surface_approx);
int new_tex_w; int new_tex_w;
@ -3893,10 +3904,10 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas)
ImFontAtlasBuilder* builder = atlas->Builder; ImFontAtlasBuilder* builder = atlas->Builder;
// Select Backend // Select Backend
// - Note that we do not reassign to atlas->FontBackendIO, since it is likely to point to static data which // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which
// may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are
// using a hot-reloading scheme that messes up static data, store your own instance of ImFontBackendIO somewhere // using a hot-reloading scheme that messes up static data, store your own instance of FontLoader somewhere
// and point to it instead of pointing directly to return value of the GetBackendIOXXX functions. // and point to it instead of pointing directly to return value of the GetFontLoaderXXX functions.
if (atlas->FontLoader == NULL) if (atlas->FontLoader == NULL)
{ {
#ifdef IMGUI_ENABLE_FREETYPE #ifdef IMGUI_ENABLE_FREETYPE
@ -3958,7 +3969,7 @@ void ImFontAtlasPackInit(ImFontAtlas * atlas)
builder->PackNodes.resize(pack_node_count); builder->PackNodes.resize(pack_node_count);
IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque)); IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque));
stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size); stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size);
atlas->_PackedSurface = atlas->_PackedRects = 0; builder->RectsPackedSurface = builder->RectsPackedCount = 0;
builder->MaxRectSize = ImVec2i(0, 0); builder->MaxRectSize = ImVec2i(0, 0);
builder->MaxRectBounds = ImVec2i(0, 0); builder->MaxRectBounds = ImVec2i(0, 0);
} }
@ -4041,14 +4052,14 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon
return -1; return -1;
} }
// Resize atlas! (this should be a rare event) // Resize or repack atlas! (this should be a rare event)
ImFontAtlasBuildGrowTexture(atlas); ImFontAtlasBuildMakeSpace(atlas);
} }
builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w + pack_padding); builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w + pack_padding);
builder->MaxRectBounds.y = ImMax(builder->MaxRectBounds.y, r.y + r.h + pack_padding); builder->MaxRectBounds.y = ImMax(builder->MaxRectBounds.y, r.y + r.h + pack_padding);
atlas->_PackedSurface += (w + pack_padding) * (h + pack_padding); builder->RectsPackedCount++;
atlas->_PackedRects++; builder->RectsPackedSurface += (w + pack_padding) * (h + pack_padding);
builder->Rects.push_back(r); builder->Rects.push_back(r);
if (overwrite_entry != NULL) if (overwrite_entry != NULL)

View file

@ -3685,6 +3685,8 @@ struct ImFontAtlasBuilder
ImVector<ImFontAtlasRectEntry> RectsIndex; // ImFontAtlasRectId -> index into Rects[] ImVector<ImFontAtlasRectEntry> RectsIndex; // ImFontAtlasRectId -> index into Rects[]
ImVector<unsigned char> TempBuffer; // Misc scratch buffer ImVector<unsigned char> TempBuffer; // Misc scratch buffer
int RectsIndexFreeListStart;// First unused entry int RectsIndexFreeListStart;// First unused entry
int RectsPackedCount; // Number of packed rectangles.
int RectsPackedSurface; // Number of packed pixels. Used when compacting to heuristically find the ideal texture size.
int RectsDiscardedCount; int RectsDiscardedCount;
int RectsDiscardedSurface; int RectsDiscardedSurface;
ImVec2i MaxRectSize; // Largest rectangle to pack (de-facto used as a "minimum texture size") ImVec2i MaxRectSize; // Largest rectangle to pack (de-facto used as a "minimum texture size")
@ -3709,6 +3711,7 @@ IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildDestroy(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildDestroy(ImFontAtlas* atlas);
IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h); IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h);
IMGUI_API void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h); IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h);
IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_w = -1, int old_h = -1); IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_w = -1, int old_h = -1);
IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas);