Fonts: reinstated ImFontAtlasBuildSetupFontCreateEllipsisFromDot() compatible with baked system, lazily baked.

This commit is contained in:
ocornut
2025-02-07 15:58:16 +01:00
parent 76b252f80a
commit d59f10d7f5
2 changed files with 50 additions and 23 deletions
+1
View File
@@ -3697,6 +3697,7 @@ struct ImFont
ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?')
float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints.
bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph needs to be generated.
short LockSingleSrcConfigIdx; short LockSingleSrcConfigIdx;
// Methods // Methods
+49 -23
View File
@@ -2497,7 +2497,8 @@ void ImTextureData::DestroyPixels()
// - ImFontAtlasBuildUpdateBasicTexData() // - ImFontAtlasBuildUpdateBasicTexData()
// - ImFontAtlasBuildUpdateLinesTexData() // - ImFontAtlasBuildUpdateLinesTexData()
// - ImFontAtlasBuildAddFont() // - ImFontAtlasBuildAddFont()
// - ImFontAtlasBuildSetupFontCreateEllipsisFromDot() // - ImFontAtlasBuildSetupFontBakedEllipsis()
// - ImFontAtlasBuildSetupFontBakedBlanks()
// - ImFontAtlasBuildSetupFontSpecialGlyphs() // - ImFontAtlasBuildSetupFontSpecialGlyphs()
// - ImFontAtlasBuildDiscardBakes() // - ImFontAtlasBuildDiscardBakes()
// - ImFontAtlasBuildDiscardFontBakedGlyph() // - ImFontAtlasBuildDiscardFontBakedGlyph()
@@ -3528,37 +3529,50 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src)
return true; return true;
} }
// Rasterize our own ellipsis character from a dot. // Create a compact, baked "..." if it doesn't exist, by using the ".".
// 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 FontLoaderGlyph() handlers and suggest that we should add further helpers.
// FIXME-BAKED: prebaked ellipsis static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, ImFontBaked* baked)
/*static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFont* font, const ImFontGlyph* dot_glyph)
{ {
ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId); ImFont* font = baked->ContainerFont;
IM_ASSERT(font->EllipsisChar != 0);
const ImFontGlyph* dot_glyph = baked->FindGlyphNoFallback((ImWchar)'.');
if (dot_glyph == NULL)
dot_glyph = baked->FindGlyphNoFallback((ImWchar)0xFF0E);
if (dot_glyph == NULL)
return NULL;
ImFontAtlasRectId dot_r_id = dot_glyph->PackId; // Deep copy to avoid invalidation of glyphs and rect pointers
ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id);
const int dot_spacing = 1; const int dot_spacing = 1;
const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing; const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing;
ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h); ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h);
ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
ImFontGlyph glyph; ImFontGlyph glyph_in = {};
glyph.Codepoint = (ImWchar)0x0085; // FIXME: Using arbitrary codepoint. ImFontGlyph* glyph = &glyph_in;
glyph.AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - dot_spacing); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. glyph->Codepoint = font->EllipsisChar;
glyph.X0 = dot_glyph->X0; glyph->AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - dot_spacing); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents.
glyph.Y0 = dot_glyph->Y0; glyph->X0 = dot_glyph->X0;
glyph.X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing; glyph->Y0 = dot_glyph->Y0;
glyph.Y1 = dot_glyph->Y1; glyph->X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing;
glyph.Visible = true; glyph->Y1 = dot_glyph->Y1;
glyph.PackId = pack_id; glyph->Visible = true;
ImFontAtlasBuildAddFontGlyph(atlas, font, NULL, &glyph); glyph->PackId = pack_id;
font->EllipsisChar = (ImWchar)glyph.Codepoint; glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, glyph);
dot_glyph = NULL; // Invalidated
// Copy to texture, post-process and queue update for backend // Copy to texture, post-process and queue update for backend
// FIXME-NEWATLAS-V2: Dot glyph is already post-processed as this point, so this would damage it. // FIXME-NEWATLAS-V2: Dot glyph is already post-processed as this point, so this would damage it.
dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id);
ImTextureData* tex = atlas->TexData; ImTextureData* tex = atlas->TexData;
for (int n = 0; n < 3; n++) for (int n = 0; n < 3; n++)
ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, dot_r->h); ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, dot_r->h);
ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
}*/
return glyph;
}
static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked)
{ {
@@ -3582,6 +3596,14 @@ static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFo
} }
baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code
baked->FallbackAdvanceX = fallback_glyph->AdvanceX; baked->FallbackAdvanceX = fallback_glyph->AdvanceX;
}
static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas* atlas, ImFontBaked* baked)
{
// Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews)
ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' ');
if (space_glyph != NULL)
space_glyph->Visible = false;
// Setup Tab character. // Setup Tab character.
// FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
@@ -3628,11 +3650,8 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im
} }
if (font->EllipsisChar == 0) if (font->EllipsisChar == 0)
{ {
/*const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; font->EllipsisChar = 0x0085;
if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars))) font->EllipsisAutoBake = true;
ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, font, dot_glyph);
else*/
font->EllipsisChar = (ImWchar)' ';
} }
font->LockSingleSrcConfigIdx = -1; font->LockSingleSrcConfigIdx = -1;
} }
@@ -4162,6 +4181,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon
} }
} }
// Important: don'return pointer valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers.
ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
{ {
IM_ASSERT(id >= 0); IM_ASSERT(id >= 0);
@@ -4182,6 +4202,12 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint)
//char utf8_buf[5]; //char utf8_buf[5];
//IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint));
// Special hook
// FIXME-NEWATLAS: it would be nicer if this used a more standardized way of hooking
if (codepoint == font->EllipsisChar && font->EllipsisAutoBake)
if (ImFontGlyph* glyph = ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked))
return glyph;
// Load from single source or all sources? // Load from single source or all sources?
int srcs_count = (font->LockSingleSrcConfigIdx != -1) ? 1 : font->SourcesCount; int srcs_count = (font->LockSingleSrcConfigIdx != -1) ? 1 : font->SourcesCount;
ImFontConfig* srcs = (font->LockSingleSrcConfigIdx != -1) ? &font->Sources[font->LockSingleSrcConfigIdx] : font->Sources; ImFontConfig* srcs = (font->LockSingleSrcConfigIdx != -1) ? &font->Sources[font->LockSingleSrcConfigIdx] : font->Sources;