diff --git a/imgui.cpp b/imgui.cpp index 0cf8bce21..7ac49382e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -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_scale = draw_list->_Data->FontScale; 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 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)); 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)); - 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 { diff --git a/imgui.h b/imgui.h index 2fb54a511..d5136e2a6 100644 --- a/imgui.h +++ b/imgui.h @@ -3648,13 +3648,10 @@ struct ImFont // [Internal] Members: Cold ~32/40/60 bytes // 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 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 ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into - float EllipsisWidth; // 4 // out // Total ellipsis Width - float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 + 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, '?') 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) 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) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b6280afb6..83212712f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2462,6 +2462,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasTextureBlockConvert() // - ImFontAtlasTextureBlockPostProcess() // - ImFontAtlasTextureBlockPostProcessMultiply() +// - ImFontAtlasTextureBlockFill() // - ImFontAtlasTextureBlockCopy() // - ImFontAtlasTextureBlockQueueUpload() //----------------------------------------------------------------------------- @@ -2490,6 +2491,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildUpdateBasicTexData() // - ImFontAtlasBuildUpdateLinesTexData() // - ImFontAtlasBuildAddFont() +// - ImFontAtlasBuildSetupFontCreateEllipsisFromDot() // - ImFontAtlasBuildSetupFontSpecialGlyphs() // - 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) { - IM_ASSERT(src_tex != dst_tex); IM_ASSERT(src_tex->Pixels != NULL && dst_tex->Pixels != NULL); IM_ASSERT(src_tex->Format == dst_tex->Format); IM_ASSERT(src_x >= 0 && src_x + w <= src_tex->Width); @@ -3483,6 +3504,44 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) 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 // (note that this is called again for fonts with MergeMode) 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. const ImWchar ellipsis_chars[] = { src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; if (font->EllipsisChar == 0) - if (const ImFontGlyph* glyph = LoadFirstExistingGlyph(font, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars))) - { - font->EllipsisChar = (ImWchar)glyph->Codepoint; - font->EllipsisCharCount = 1; - font->EllipsisWidth = font->EllipsisCharStep = glyph->X1; - } + for (ImWchar candidate_char : ellipsis_chars) + if (candidate_char != 0 && font->IsGlyphInFont(candidate_char)) + { + font->EllipsisChar = candidate_char; + break; + } 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 }; if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars))) - { - font->EllipsisChar = (ImWchar)dot_glyph->Codepoint; - font->EllipsisCharCount = 3; - 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. - } + ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, src, dot_glyph); + else + font->EllipsisChar = (ImWchar)' '; } font->LockSingleSrcConfigIdx = -1; } diff --git a/imgui_internal.h b/imgui_internal.h index 830ca9c6e..bc98e83d2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -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 ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data); 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 ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h);