Skip to content

Commit

Permalink
ImFont: Demo, Store Used4kPagesMap[] map in ImFont to facilitate iter…
Browse files Browse the repository at this point in the history
…ation on all codepoints with a large value of IM_UNICODE_CODEPOINT_MAX. (ocornut#2815)

Demo uses IsGlyphRangeUnused()
  • Loading branch information
ocornut authored and sergeyn committed Mar 30, 2020
1 parent 48acd70 commit 0e3cb8c
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 0 deletions.
2 changes: 2 additions & 0 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -2257,6 +2257,7 @@ struct ImFont
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_CODEPOINT_MAX+1)/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.

// Methods
IMGUI_API ImFont();
Expand All @@ -2282,6 +2283,7 @@ struct ImFont
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 SetGlyphVisible(ImWchar c, bool visible);
IMGUI_API void SetFallbackChar(ImWchar c);
IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
};

#if defined(__clang__)
Expand Down
9 changes: 9 additions & 0 deletions imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3443,6 +3443,15 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
// Display all glyphs of the fonts in separate pages of 256 characters
for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; 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 ImWchar==ImWchar32 we will do at least about 272 queries here)
if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
{
base += 4096 - 256;
continue;
}

int count = 0;
for (unsigned int n = 0; n < 256; n++)
count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0;
Expand Down
19 changes: 19 additions & 0 deletions imgui_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2594,6 +2594,7 @@ ImFont::ImFont()
Scale = 1.0f;
Ascent = Descent = 0.0f;
MetricsTotalSurface = 0;
memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
}

ImFont::~ImFont()
Expand Down Expand Up @@ -2626,12 +2627,17 @@ void ImFont::BuildLookupTable()
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
Expand Down Expand Up @@ -2660,6 +2666,19 @@ void ImFont::BuildLookupTable()
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::SetGlyphVisible(ImWchar c, bool visible)
{
if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c))
Expand Down

0 comments on commit 0e3cb8c

Please sign in to comment.