ImFont: Demo, Store Used4kPagesMap[] map in ImFont to facilitate iteration on all codepoints with a large value of IM_UNICODE_MAX_CODEPOINT. Demo uses IsGlyphRangeUnused()
diff --git a/imgui.h b/imgui.h
index 7ab1792..9418182 100644
--- a/imgui.h
+++ b/imgui.h
@@ -2201,6 +2201,7 @@
float Scale; // 4 // in // = 1.f // Base font scale, 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]
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)
+ ImU8 Used4kPagesMap[IM_UNICODE_MAX_CODEPOINT/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 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 accross all used codepoints.
bool DirtyLookupTables; // 1 // out //
// Methods
@@ -2226,6 +2227,7 @@
IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
IMGUI_API void SetFallbackChar(ImWchar c);
+ IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
};
#if defined(__clang__)
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index 17d2927..19902ac 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -3401,10 +3401,18 @@
if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
{
// Display all glyphs of the fonts in separate pages of 256 characters
- for (int base = 0; base < IM_UNICODE_MAX_CODEPOINT; base += 256)
+ for (unsigned int base = 0; base < IM_UNICODE_MAX_CODEPOINT; base += 256)
{
+ // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
+ // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT is large.
+ if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
+ {
+ base += 4096 - 256;
+ continue;
+ }
+
int count = 0;
- for (int n = 0; n < 256; n++)
+ for (unsigned int n = 0; n < 256; n++)
count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0;
if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
{
@@ -3412,7 +3420,7 @@
float cell_spacing = style.ItemSpacing.y;
ImVec2 base_pos = ImGui::GetCursorScreenPos();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
- for (int n = 0; n < 256; n++)
+ for (unsigned int n = 0; n < 256; n++)
{
ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index ad3cf1f..078c662 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -2499,6 +2499,7 @@
Scale = 1.0f;
Ascent = Descent = 0.0f;
MetricsTotalSurface = 0;
+ memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
}
ImFont::~ImFont()
@@ -2530,12 +2531,17 @@
IndexAdvanceX.clear();
IndexLookup.clear();
DirtyLookupTables = false;
+ memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
GrowIndex(max_codepoint + 1);
for (int i = 0; i < Glyphs.Size; i++)
{
int codepoint = (int)Glyphs[i].Codepoint;
IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
IndexLookup[codepoint] = (ImWchar)i;
+
+ // Mark 4K page as used
+ const int page_n = codepoint / 4096;
+ Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
}
// Create a glyph to handle TAB
@@ -2559,6 +2565,19 @@
IndexAdvanceX[i] = FallbackAdvanceX;
}
+// API is designed this way to avoid exposing the 4K page size
+// e.g. use with IsGlyphRangeUnused(0, 255)
+bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
+{
+ unsigned int page_begin = (c_begin / 4096);
+ unsigned int page_last = (c_last / 4096);
+ for (unsigned int page_n = page_begin; page_n <= page_last; page_n++)
+ if ((page_n >> 3) < sizeof(Used4kPagesMap))
+ if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
+ return false;
+ return true;
+}
+
void ImFont::SetFallbackChar(ImWchar c)
{
FallbackChar = c;