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

Fonts: Rasterizing ellipsis character from dot as one glyph + avoid preloading if it not needed.

# Conflicts:
#	imgui.cpp
This commit is contained in:
ocornut 2025-01-08 19:07:40 +01:00
parent a2bc3d81c2
commit 4ff1631b31
4 changed files with 75 additions and 23 deletions

View file

@ -3738,7 +3738,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
const float font_size = draw_list->_Data->FontSize; const float font_size = draw_list->_Data->FontSize;
const float font_scale = draw_list->_Data->FontScale; const float font_scale = draw_list->_Data->FontScale;
const char* text_end_ellipsis = NULL; const char* text_end_ellipsis = NULL;
const float ellipsis_width = font->EllipsisWidth * font_scale; const float ellipsis_width = font->GetCharAdvance(font->EllipsisChar) * font_scale;
// We can now claim the space between pos_max.x and ellipsis_max.x // We can now claim the space between pos_max.x and ellipsis_max.x
const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f); const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f);
@ -3754,8 +3754,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
ImVec4 cpu_fine_clip_rect(pos_min.x, pos_min.y, pos_max.x, pos_max.y); ImVec4 cpu_fine_clip_rect(pos_min.x, pos_min.y, pos_max.x, pos_max.y);
ImVec2 ellipsis_pos = ImTrunc(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y)); ImVec2 ellipsis_pos = ImTrunc(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y));
for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale) font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar, &cpu_fine_clip_rect);
font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar, &cpu_fine_clip_rect);
} }
else else
{ {

View file

@ -3648,13 +3648,10 @@ struct ImFont
// [Internal] Members: Cold ~32/40/60 bytes // [Internal] Members: Cold ~32/40/60 bytes
// Conceptually Sources[] is the list of font sources merged to create this font. // Conceptually Sources[] is the list of font sources merged to create this font.
short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont.
short EllipsisCharCount; // 1 // out // 1 or 3
ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...').
ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?')
ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances
ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into
float EllipsisWidth; // 4 // out // Total ellipsis Width ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...').
float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 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()
float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled)
int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)

View file

@ -2462,6 +2462,7 @@ void ImTextureData::DestroyPixels()
// - ImFontAtlasTextureBlockConvert() // - ImFontAtlasTextureBlockConvert()
// - ImFontAtlasTextureBlockPostProcess() // - ImFontAtlasTextureBlockPostProcess()
// - ImFontAtlasTextureBlockPostProcessMultiply() // - ImFontAtlasTextureBlockPostProcessMultiply()
// - ImFontAtlasTextureBlockFill()
// - ImFontAtlasTextureBlockCopy() // - ImFontAtlasTextureBlockCopy()
// - ImFontAtlasTextureBlockQueueUpload() // - ImFontAtlasTextureBlockQueueUpload()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2490,6 +2491,7 @@ void ImTextureData::DestroyPixels()
// - ImFontAtlasBuildUpdateBasicTexData() // - ImFontAtlasBuildUpdateBasicTexData()
// - ImFontAtlasBuildUpdateLinesTexData() // - ImFontAtlasBuildUpdateLinesTexData()
// - ImFontAtlasBuildAddFont() // - ImFontAtlasBuildAddFont()
// - ImFontAtlasBuildSetupFontCreateEllipsisFromDot()
// - ImFontAtlasBuildSetupFontSpecialGlyphs() // - ImFontAtlasBuildSetupFontSpecialGlyphs()
// - ImFontAtlasBuildReloadFont() // - ImFontAtlasBuildReloadFont()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2820,10 +2822,29 @@ void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data
} }
} }
// Convert block from one texture to another // Fill with single color. We don't use this directly but it is convenient for anyone working on uploading custom rects.
void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h, ImU32 col)
{
if (dst_tex->Format == ImTextureFormat_Alpha8)
{
ImU8 col_a = (col >> IM_COL32_A_SHIFT) & 0xFF;
for (int y = 0; y < h; y++)
memset((ImU8*)dst_tex->GetPixelsAt(dst_x, dst_y + y), col_a, w);
}
else
{
for (int y = 0; y < h; y++)
{
ImU32* p = (ImU32*)(void*)dst_tex->GetPixelsAt(dst_x, dst_y + y);
for (int x = w; x > 0; x--, p++)
*p = col;
}
}
}
// Copy block from one texture to another
void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h) void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h)
{ {
IM_ASSERT(src_tex != dst_tex);
IM_ASSERT(src_tex->Pixels != NULL && dst_tex->Pixels != NULL); IM_ASSERT(src_tex->Pixels != NULL && dst_tex->Pixels != NULL);
IM_ASSERT(src_tex->Format == dst_tex->Format); IM_ASSERT(src_tex->Format == dst_tex->Format);
IM_ASSERT(src_x >= 0 && src_x + w <= src_tex->Width); IM_ASSERT(src_x >= 0 && src_x + w <= src_tex->Width);
@ -3483,6 +3504,44 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src)
return true; return true;
} }
// 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.
// FIXME-NEWATLAS: This borrows too much from FontBackend_FontAddGlyph() and suggest that we should add further helpers.
static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFontConfig* cfg, const ImFontGlyph* dot_glyph)
{
ImFont* font = cfg->DstFont;
ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId);
const int dot_spacing = 1;
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);
ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
font->MetricsTotalSurface += r->w * r->h;
ImFontGlyph glyph;
glyph.Codepoint = (ImWchar)0x0085; // FIXME: Using arbitrary codepoint.
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.X0 = dot_glyph->X0;
glyph.Y0 = dot_glyph->Y0;
glyph.X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing;
glyph.Y1 = dot_glyph->Y1;
glyph.U0 = (r->x) * atlas->TexUvScale.x;
glyph.V0 = (r->y) * atlas->TexUvScale.y;
glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x;
glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y;
glyph.Visible = true;
glyph.PackId = pack_id;
font->BuildRegisterGlyph(cfg, &glyph);
font->EllipsisChar = (ImWchar)glyph.Codepoint;
// 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.
ImTextureData* tex = atlas->TexData;
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);
ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
}
// Load/identify special glyphs // Load/identify special glyphs
// (note that this is called again for fonts with MergeMode) // (note that this is called again for fonts with MergeMode)
void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src) void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src)
@ -3526,23 +3585,19 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr
// FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots.
const ImWchar ellipsis_chars[] = { src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; const ImWchar ellipsis_chars[] = { src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 };
if (font->EllipsisChar == 0) if (font->EllipsisChar == 0)
if (const ImFontGlyph* glyph = LoadFirstExistingGlyph(font, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars))) for (ImWchar candidate_char : ellipsis_chars)
{ if (candidate_char != 0 && font->IsGlyphInFont(candidate_char))
font->EllipsisChar = (ImWchar)glyph->Codepoint; {
font->EllipsisCharCount = 1; font->EllipsisChar = candidate_char;
font->EllipsisWidth = font->EllipsisCharStep = glyph->X1; break;
} }
if (font->EllipsisChar == 0) if (font->EllipsisChar == 0)
{ {
// FIXME-NEWATLAS-V2: We can now rasterize this into a regular character and register it!
const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars))) if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars)))
{ ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, src, dot_glyph);
font->EllipsisChar = (ImWchar)dot_glyph->Codepoint; else
font->EllipsisCharCount = 3; font->EllipsisChar = (ImWchar)' ';
font->EllipsisCharStep = (float)(int)(dot_glyph->X1 - dot_glyph->X0) + 1.0f;
font->EllipsisWidth = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + font->EllipsisCharStep * 3.0f - 1.0f); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents.
}
} }
font->LockSingleSrcConfigIdx = -1; font->LockSingleSrcConfigIdx = -1;
} }

View file

@ -3736,6 +3736,7 @@ IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h); IMGUI_API void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h);
IMGUI_API void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data); IMGUI_API void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data);
IMGUI_API void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor); IMGUI_API void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor);
IMGUI_API void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h, ImU32 col);
IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h); IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h);
IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h); IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h);