Browse Source

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

# Conflicts:
#	imgui.cpp
ocornut 7 months ago
parent
commit
4ff1631b31
4 changed files with 75 additions and 23 deletions
  1. 2 3
      imgui.cpp
  2. 2 5
      imgui.h
  3. 70 15
      imgui_draw.cpp
  4. 1 0
      imgui_internal.h

+ 2 - 3
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
     {

+ 2 - 5
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)

+ 70 - 15
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;
 }

+ 1 - 0
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);