From 529ca279a47bcc829e5ba9f14fa6bfb4a10d706a Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 26 Sep 2017 18:41:21 +0200 Subject: [PATCH 1/7] ImFont: Split some building code into a AddGlyph() helper (that custom rect code and imgui_freetype can use) --- imgui.h | 5 +++-- imgui_draw.cpp | 40 +++++++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/imgui.h b/imgui.h index 081cf8e49..f655a1667 100644 --- a/imgui.h +++ b/imgui.h @@ -1387,7 +1387,7 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters - // Helpers to build glyph ranges from text data. Feed all your application strings/characters to it then call BuildRanges(). + // Helpers to build glyph ranges from text data. Feed your application strings/characters to it then call BuildRanges(). struct GlyphRangesBuilder { ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) @@ -1477,8 +1477,9 @@ struct ImFont IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const; IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; - // Private + // [Private] IMGUI_API void GrowIndex(int new_size); + IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float x_advance); 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. }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a28063975..3291c31ae 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1535,23 +1535,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) stbtt_aligned_quad q; float dummy_x = 0.0f, dummy_y = 0.0f; stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0); - - dst_font->Glyphs.resize(dst_font->Glyphs.Size + 1); - ImFont::Glyph& glyph = dst_font->Glyphs.back(); - glyph.Codepoint = (ImWchar)codepoint; - glyph.X0 = q.x0 + off_x; - glyph.Y0 = q.y0 + off_y; - glyph.X1 = q.x1 + off_x; - glyph.Y1 = q.y1 + off_y; - glyph.U0 = q.s0; - glyph.V0 = q.t0; - glyph.U1 = q.s1; - glyph.V1 = q.t1; - glyph.XAdvance = (pc.xadvance + cfg.GlyphExtraSpacing.x); // Bake spacing into XAdvance - - if (cfg.PixelSnapH) - glyph.XAdvance = (float)(int)(glyph.XAdvance + 0.5f); - dst_font->MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * atlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * atlas->TexHeight + 1.99f); // +1 to account for average padding, +0.99 to round + dst_font->AddGlyph((ImWchar)codepoint, q.x0 + off_x, q.y0 + off_y, q.x1 + off_x, q.y1 + off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance); } } cfg.DstFont->BuildLookupTable(); @@ -1923,6 +1907,28 @@ void ImFont::GrowIndex(int new_size) IndexLookup.resize(new_size, (unsigned short)-1); } +void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float x_advance) +{ + Glyphs.resize(Glyphs.Size + 1); + ImFont::Glyph& glyph = Glyphs.back(); + glyph.Codepoint = (ImWchar)codepoint; + glyph.X0 = x0; + glyph.Y0 = y0; + glyph.X1 = x1; + glyph.Y1 = y1; + glyph.U0 = u0; + glyph.V0 = v0; + glyph.U1 = u1; + glyph.V1 = v1; + glyph.XAdvance = (x_advance + ConfigData->GlyphExtraSpacing.x); // Bake spacing into XAdvance + + if (ConfigData->PixelSnapH) + glyph.XAdvance = (float)(int)(glyph.XAdvance + 0.5f); + + // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) + MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f); +} + void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) { IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. From 2170b0b2789a71b3f45d87b8940830f50312f60d Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 26 Sep 2017 19:10:29 +0200 Subject: [PATCH 2/7] ImFontAtlas: Comments and minor reorganization of declaration in header file. --- imgui.h | 46 ++++++++++++++++++++++++++++------------------ imgui_draw.cpp | 5 +++-- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/imgui.h b/imgui.h index f655a1667..1a221c0d0 100644 --- a/imgui.h +++ b/imgui.h @@ -1369,21 +1369,25 @@ struct ImFontAtlas IMGUI_API void ClearFonts(); // Clear the ImGui-side font data (glyphs storage, UV coordinates) IMGUI_API void Clear(); // Clear all - // Retrieve texture data - // User is in charge of copying the pixels into graphics memory, then call SetTextureUserID() - // After loading the texture into your graphic system, store your texture handle in 'TexID' (ignore if you aren't using multiple fonts nor images) + // Build atlas, retrieve pixel data. + // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). // RGBA32 format is provided for convenience and high compatibility, but note that all RGB pixels are white, so 75% of the memory is wasted. // Pitch = Width * BytesPerPixels + IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel void SetTexID(ImTextureID id) { TexID = id; } + //------------------------------------------- + // Glyph Ranges + //------------------------------------------- + // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details. IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs - IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs + IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Default + Japanese + full set of about 21000 CJK Unified Ideographs IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters @@ -1400,17 +1404,9 @@ struct ImFontAtlas IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges }; - // Members - // (Access texture data via GetTexData*() calls which will setup a default font for you.) - ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. - unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight - unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 - int TexWidth; // Texture width calculated during Build(). - int TexHeight; // Texture height calculated during Build(). - int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. - int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. - ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel - ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. + //------------------------------------------- + // Custom Rectangles + //------------------------------------------- // [Private] User rectangle for packing custom texture data into the atlas. struct CustomRect @@ -1422,10 +1418,24 @@ struct ImFontAtlas bool IsPacked() const { return X != 0xFFFF; } }; - // [Private] Members + //------------------------------------------- + // Members + //------------------------------------------- + + ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. + int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. + int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. + + // [Private] + // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight + unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 + int TexWidth; // Texture width calculated during Build(). + int TexHeight; // Texture height calculated during Build(). + ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel + ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. ImVector ConfigData; // Internal data - IMGUI_API bool Build(); // Build pixels data. This is automatically for you by the GetTexData*** functions. IMGUI_API int CustomRectRegister(unsigned int id, int width, int height); IMGUI_API void CustomRectCalcUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max); }; @@ -1438,7 +1448,7 @@ struct ImFont { ImWchar Codepoint; float XAdvance; - float X0, Y0, X1, Y1; + float X0, Y0, X1, Y1; // Glyph corners float U0, V0, U1, V1; // Texture coordinates }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3291c31ae..f08259b11 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1101,10 +1101,11 @@ const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF ImFontAtlas::ImFontAtlas() { TexID = NULL; + TexDesiredWidth = 0; + TexGlyphPadding = 1; TexPixelsAlpha8 = NULL; TexPixelsRGBA32 = NULL; - TexWidth = TexHeight = TexDesiredWidth = 0; - TexGlyphPadding = 1; + TexWidth = TexHeight = 0; TexUvWhitePixel = ImVec2(0, 0); } From 072d6d8cb5a8bb66318ae5db7d23b3be74bf5ffe Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 26 Sep 2017 19:26:16 +0200 Subject: [PATCH 3/7] ImFontAtlas: Refactored internals API to 1) avoid building lookup table multiple times for merged fonts + 2) allow the mapping of custom icons inside fonts (wip, uncommited) --- imgui_draw.cpp | 16 ++++++++++++---- imgui_internal.h | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f08259b11..10627bfc8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1539,7 +1539,6 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) dst_font->AddGlyph((ImWchar)codepoint, q.x0 + off_x, q.y0 + off_y, q.x1 + off_x, q.y1 + off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance); } } - cfg.DstFont->BuildLookupTable(); } // Cleanup temporaries @@ -1547,8 +1546,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) ImGui::MemFree(buf_ranges); ImGui::MemFree(tmp_array); - // Render into our custom data block - ImFontAtlasBuildRenderDefaultTexData(atlas); + ImFontAtlasBuildFinish(atlas); return true; } @@ -1600,7 +1598,7 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaq } } -void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) +static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) { ImFontAtlas::CustomRect& r = atlas->CustomRects[0]; IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); @@ -1650,6 +1648,16 @@ void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) } } +void ImFontAtlasBuildFinish(ImFontAtlas* atlas) +{ + // Render into our custom data block + ImFontAtlasBuildRenderDefaultTexData(atlas); + + // Build all fonts lookup tables + for (int i = 0; i < atlas->Fonts.Size; i++) + atlas->Fonts[i]->BuildLookupTable(); +} + // Retrieve list of range (2 int per range, values are inclusive) const ImWchar* ImFontAtlas::GetGlyphRangesDefault() { diff --git a/imgui_internal.h b/imgui_internal.h index 0e779a2a8..99b0f3afa 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -849,7 +849,7 @@ IMGUI_API bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc); -IMGUI_API void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); From 10bb9524eb99ede4b86a3a0da72fc1fb92ebaaf0 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 26 Sep 2017 19:54:30 +0200 Subject: [PATCH 4/7] ImFont: Renamed ImFont::Glyph to ImFontGlyph (for consistency and so ImFontAtlas types can use it without ordering half of the file). Left a redirection type. --- imgui.cpp | 2 +- imgui.h | 28 ++++++++++++++++------------ imgui_demo.cpp | 4 ++-- imgui_draw.cpp | 10 +++++----- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4aafd8845..2409b9140 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7847,7 +7847,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 // Password pushes a temporary font with only a fallback glyph if (is_password) { - const ImFont::Glyph* glyph = g.Font->FindGlyph('*'); + const ImFontGlyph* glyph = g.Font->FindGlyph('*'); ImFont* password_font = &g.InputTextPasswordFont; password_font->FontSize = g.Font->FontSize; password_font->Scale = g.Font->Scale; diff --git a/imgui.h b/imgui.h index 1a221c0d0..dd1d6b9f8 100644 --- a/imgui.h +++ b/imgui.h @@ -1332,7 +1332,7 @@ struct ImFontConfig float SizePixels; // // Size in pixels for rasterizer. int OversampleH, OversampleV; // 3, 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. - ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. + ImVec2 GlyphExtraSpacing; // 1, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. const ImWchar* GlyphRanges; // NULL // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. @@ -1346,6 +1346,14 @@ struct ImFontConfig IMGUI_API ImFontConfig(); }; +struct ImFontGlyph +{ + ImWchar Codepoint; // 0x0000..0xFFFF + float XAdvance; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) + float X0, Y0, X1, Y1; // Glyph corners + float U0, V0, U1, V1; // Texture coordinates +}; + // Load and rasterize multiple TTF/OTF fonts into a same texture. // Sharing a texture for multiple fonts allows us to reduce the number of draw calls during rendering. // We also add custom graphic data into the texture that serves for ImGui. @@ -1444,22 +1452,14 @@ struct ImFontAtlas // ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). struct ImFont { - struct Glyph - { - ImWchar Codepoint; - float XAdvance; - float X0, Y0, X1, Y1; // Glyph corners - float U0, V0, U1, V1; // Texture coordinates - }; - // Members: Hot ~62/78 bytes float FontSize; // // Height of characters, set during loading (don't change after loading) float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() ImVec2 DisplayOffset; // = (0.f,1.f) // Offset font rendering by xx pixels - ImVector Glyphs; // // All glyphs. + ImVector Glyphs; // // All glyphs. ImVector IndexXAdvance; // // Sparse. Glyphs->XAdvance in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). ImVector IndexLookup; // // Sparse. Index glyphs by Unicode code-point. - const Glyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) + const ImFontGlyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) float FallbackXAdvance; // == FallbackGlyph->XAdvance ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() @@ -1475,7 +1475,7 @@ struct ImFont IMGUI_API ~ImFont(); IMGUI_API void Clear(); IMGUI_API void BuildLookupTable(); - IMGUI_API const Glyph* FindGlyph(ImWchar c) const; + IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; IMGUI_API void SetFallbackChar(ImWchar c); float GetCharAdvance(ImWchar c) const { return ((int)c < IndexXAdvance.Size) ? IndexXAdvance[(int)c] : FallbackXAdvance; } bool IsLoaded() const { return ContainerAtlas != NULL; } @@ -1491,6 +1491,10 @@ struct ImFont IMGUI_API void GrowIndex(int new_size); IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float x_advance); 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. + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + typedef ImFontGlyph Glyph; // OBSOLETE 1.52+ +#endif }; #if defined(__clang__) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6773840f8..f52dcbfdc 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1926,7 +1926,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) { // Display all glyphs of the fonts in separate pages of 256 characters - const ImFont::Glyph* glyph_fallback = font->FallbackGlyph; // Forcefully/dodgily make FindGlyph() return NULL on fallback, which isn't the default behavior. + const ImFontGlyph* glyph_fallback = font->FallbackGlyph; // Forcefully/dodgily make FindGlyph() return NULL on fallback, which isn't the default behavior. font->FallbackGlyph = NULL; for (int base = 0; base < 0x10000; base += 256) { @@ -1943,7 +1943,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size.x + cell_spacing), base_pos.y + (n / 16) * (cell_size.y + cell_spacing)); ImVec2 cell_p2(cell_p1.x + cell_size.x, cell_p1.y + cell_size.y); - const ImFont::Glyph* glyph = font->FindGlyph((ImWchar)(base+n));; + const ImFontGlyph* glyph = font->FindGlyph((ImWchar)(base+n));; draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255,255,255,100) : IM_COL32(255,255,255,50)); font->RenderChar(draw_list, cell_size.x, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base+n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string. if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2)) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 10627bfc8..f02e56262 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1885,7 +1885,7 @@ void ImFont::BuildLookupTable() { if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times Glyphs.resize(Glyphs.Size + 1); - ImFont::Glyph& tab_glyph = Glyphs.back(); + ImFontGlyph& tab_glyph = Glyphs.back(); tab_glyph = *FindGlyph((unsigned short)' '); tab_glyph.Codepoint = '\t'; tab_glyph.XAdvance *= 4; @@ -1919,7 +1919,7 @@ void ImFont::GrowIndex(int new_size) void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float x_advance) { Glyphs.resize(Glyphs.Size + 1); - ImFont::Glyph& glyph = Glyphs.back(); + ImFontGlyph& glyph = Glyphs.back(); glyph.Codepoint = (ImWchar)codepoint; glyph.X0 = x0; glyph.Y0 = y0; @@ -1953,7 +1953,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) IndexXAdvance[dst] = (src < index_size) ? IndexXAdvance.Data[src] : 1.0f; } -const ImFont::Glyph* ImFont::FindGlyph(unsigned short c) const +const ImFontGlyph* ImFont::FindGlyph(unsigned short c) const { if (c < IndexLookup.Size) { @@ -2161,7 +2161,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col { if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded. return; - if (const Glyph* glyph = FindGlyph(c)) + if (const ImFontGlyph* glyph = FindGlyph(c)) { float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; pos.x = (float)(int)pos.x + DisplayOffset.x; @@ -2265,7 +2265,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col } float char_width = 0.0f; - if (const Glyph* glyph = FindGlyph((unsigned short)c)) + if (const ImFontGlyph* glyph = FindGlyph((unsigned short)c)) { char_width = glyph->XAdvance * scale; From 9e1ad7295f34a749e1337e2ffff0a2f60dada591 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 26 Sep 2017 20:05:16 +0200 Subject: [PATCH 5/7] ImFont: Renamed (supposedly internal) fields (e.g. XAdvance to AdvanceX). Custom text renderers might be affected if they didn't use the GetCharAdvance() helper function. --- imgui.cpp | 6 +++--- imgui.h | 10 +++++----- imgui_demo.cpp | 2 +- imgui_draw.cpp | 36 ++++++++++++++++++------------------ 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2409b9140..5faff4f56 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3065,7 +3065,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex return ImVec2(0.0f, font_size); ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); - // Cancel out character spacing for the last character of a line (it is baked into glyph->XAdvance field) + // Cancel out character spacing for the last character of a line (it is baked into glyph->AdvanceX field) const float font_scale = font_size / font->FontSize; const float character_spacing_x = 1.0f * font_scale; if (text_size.x > 0.0f) @@ -7856,8 +7856,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 password_font->Descent = g.Font->Descent; password_font->ContainerAtlas = g.Font->ContainerAtlas; password_font->FallbackGlyph = glyph; - password_font->FallbackXAdvance = glyph->XAdvance; - IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexXAdvance.empty() && password_font->IndexLookup.empty()); + password_font->FallbackAdvanceX = glyph->AdvanceX; + IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty()); PushFont(password_font); } diff --git a/imgui.h b/imgui.h index dd1d6b9f8..a4b0273eb 100644 --- a/imgui.h +++ b/imgui.h @@ -1349,7 +1349,7 @@ struct ImFontConfig struct ImFontGlyph { ImWchar Codepoint; // 0x0000..0xFFFF - float XAdvance; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) + float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) float X0, Y0, X1, Y1; // Glyph corners float U0, V0, U1, V1; // Texture coordinates }; @@ -1457,10 +1457,10 @@ struct ImFont float Scale; // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale() ImVec2 DisplayOffset; // = (0.f,1.f) // Offset font rendering by xx pixels ImVector Glyphs; // // All glyphs. - ImVector IndexXAdvance; // // Sparse. Glyphs->XAdvance in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). + ImVector IndexAdvanceX; // // Sparse. Glyphs->AdvanceX in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI). ImVector IndexLookup; // // Sparse. Index glyphs by Unicode code-point. const ImFontGlyph* FallbackGlyph; // == FindGlyph(FontFallbackChar) - float FallbackXAdvance; // == FallbackGlyph->XAdvance + float FallbackAdvanceX; // == FallbackGlyph->AdvanceX ImWchar FallbackChar; // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() // Members: Cold ~18/26 bytes @@ -1477,7 +1477,7 @@ struct ImFont IMGUI_API void BuildLookupTable(); IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; IMGUI_API void SetFallbackChar(ImWchar c); - float GetCharAdvance(ImWchar c) const { return ((int)c < IndexXAdvance.Size) ? IndexXAdvance[(int)c] : FallbackXAdvance; } + float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } bool IsLoaded() const { return ContainerAtlas != NULL; } // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. @@ -1489,7 +1489,7 @@ struct ImFont // [Private] IMGUI_API void GrowIndex(int new_size); - IMGUI_API void AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float x_advance); + 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. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f52dcbfdc..81e89db50 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1951,7 +1951,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::BeginTooltip(); ImGui::Text("Codepoint: U+%04X", base+n); ImGui::Separator(); - ImGui::Text("XAdvance+1: %.1f", glyph->XAdvance); + ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX); ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); ImGui::EndTooltip(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f02e56262..f2e1a2b81 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1851,10 +1851,10 @@ void ImFont::Clear() FontSize = 0.0f; DisplayOffset = ImVec2(0.0f, 1.0f); Glyphs.clear(); - IndexXAdvance.clear(); + IndexAdvanceX.clear(); IndexLookup.clear(); FallbackGlyph = NULL; - FallbackXAdvance = 0.0f; + FallbackAdvanceX = 0.0f; ConfigDataCount = 0; ConfigData = NULL; ContainerAtlas = NULL; @@ -1869,13 +1869,13 @@ void ImFont::BuildLookupTable() max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved - IndexXAdvance.clear(); + IndexAdvanceX.clear(); IndexLookup.clear(); GrowIndex(max_codepoint + 1); for (int i = 0; i < Glyphs.Size; i++) { int codepoint = (int)Glyphs[i].Codepoint; - IndexXAdvance[codepoint] = Glyphs[i].XAdvance; + IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; IndexLookup[codepoint] = (unsigned short)i; } @@ -1888,17 +1888,17 @@ void ImFont::BuildLookupTable() ImFontGlyph& tab_glyph = Glyphs.back(); tab_glyph = *FindGlyph((unsigned short)' '); tab_glyph.Codepoint = '\t'; - tab_glyph.XAdvance *= 4; - IndexXAdvance[(int)tab_glyph.Codepoint] = (float)tab_glyph.XAdvance; + tab_glyph.AdvanceX *= 4; + IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size-1); } FallbackGlyph = NULL; FallbackGlyph = FindGlyph(FallbackChar); - FallbackXAdvance = FallbackGlyph ? FallbackGlyph->XAdvance : 0.0f; + FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f; for (int i = 0; i < max_codepoint + 1; i++) - if (IndexXAdvance[i] < 0.0f) - IndexXAdvance[i] = FallbackXAdvance; + if (IndexAdvanceX[i] < 0.0f) + IndexAdvanceX[i] = FallbackAdvanceX; } void ImFont::SetFallbackChar(ImWchar c) @@ -1909,14 +1909,14 @@ void ImFont::SetFallbackChar(ImWchar c) void ImFont::GrowIndex(int new_size) { - IM_ASSERT(IndexXAdvance.Size == IndexLookup.Size); + IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); if (new_size <= IndexLookup.Size) return; - IndexXAdvance.resize(new_size, -1.0f); + IndexAdvanceX.resize(new_size, -1.0f); IndexLookup.resize(new_size, (unsigned short)-1); } -void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float x_advance) +void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) { Glyphs.resize(Glyphs.Size + 1); ImFontGlyph& glyph = Glyphs.back(); @@ -1929,10 +1929,10 @@ void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, glyph.V0 = v0; glyph.U1 = u1; glyph.V1 = v1; - glyph.XAdvance = (x_advance + ConfigData->GlyphExtraSpacing.x); // Bake spacing into XAdvance + glyph.AdvanceX = (advance_x + ConfigData->GlyphExtraSpacing.x); // Bake spacing into AdvanceX if (ConfigData->PixelSnapH) - glyph.XAdvance = (float)(int)(glyph.XAdvance + 0.5f); + glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f); // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f); @@ -1950,7 +1950,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) GrowIndex(dst + 1); IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1; - IndexXAdvance[dst] = (src < index_size) ? IndexXAdvance.Data[src] : 1.0f; + IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; } const ImFontGlyph* ImFont::FindGlyph(unsigned short c) const @@ -2018,7 +2018,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } } - const float char_width = ((int)c < IndexXAdvance.Size ? IndexXAdvance[(int)c] : FallbackXAdvance); + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX); if (ImCharIsSpace(c)) { if (inside_word) @@ -2135,7 +2135,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons continue; } - const float char_width = ((int)c < IndexXAdvance.Size ? IndexXAdvance[(int)c] : FallbackXAdvance) * scale; + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale; if (line_width + char_width >= max_width) { s = prev_s; @@ -2267,7 +2267,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col float char_width = 0.0f; if (const ImFontGlyph* glyph = FindGlyph((unsigned short)c)) { - char_width = glyph->XAdvance * scale; + char_width = glyph->AdvanceX * scale; // Arbitrarily assume that both space and tabs are empty glyphs as an optimization if (c != ' ' && c != '\t') From 501e73feedf603b22e3e4ea428f745d6992930eb Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 26 Sep 2017 20:18:14 +0200 Subject: [PATCH 6/7] Minor comments --- imgui.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.h b/imgui.h index a4b0273eb..8d5b13ebc 100644 --- a/imgui.h +++ b/imgui.h @@ -864,7 +864,7 @@ struct ImGuiIO ImVec2 MouseDelta; // Mouse delta. Note that this is zero if either current or previous position are negative, so a disappearing/reappearing mouse won't have a huge delta for one frame. //------------------------------------------------------------------ - // [Private] ImGui will maintain those fields. Forward compatibility not guaranteed! + // [Internal] ImGui will maintain those fields. Forward compatibility not guaranteed! //------------------------------------------------------------------ ImVec2 MousePosPrev; // Previous mouse position temporary storage (nb: not for public use, set to MousePos in NewFrame()) @@ -1379,12 +1379,12 @@ struct ImFontAtlas // Build atlas, retrieve pixel data. // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). - // RGBA32 format is provided for convenience and high compatibility, but note that all RGB pixels are white, so 75% of the memory is wasted. + // RGBA32 format is provided for convenience and compatibility, but note that unless you use CustomRect to draw color data, the RGB pixels emitted from Fonts will all be white (~75% of waste). // Pitch = Width * BytesPerPixels IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel - void SetTexID(ImTextureID id) { TexID = id; } + void SetTexID(ImTextureID id) { TexID = id; } //------------------------------------------- // Glyph Ranges @@ -1434,7 +1434,7 @@ struct ImFontAtlas int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. - // [Private] + // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 @@ -1487,7 +1487,7 @@ struct ImFont IMGUI_API void RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const; IMGUI_API void RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; - // [Private] + // [Internal] IMGUI_API void GrowIndex(int new_size); 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. From 3fe2ecfd4cd34367b505fba38941217a3cc89f1d Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 26 Sep 2017 20:24:27 +0200 Subject: [PATCH 7/7] ImFontAtlas: Added support for CustomRect API to submit custom rectangles to be packed into the atlas / and map them as font glyphs --- imgui.h | 21 +++++++++++++++------ imgui_draw.cpp | 50 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/imgui.h b/imgui.h index 8d5b13ebc..185a31355 100644 --- a/imgui.h +++ b/imgui.h @@ -1413,19 +1413,29 @@ struct ImFontAtlas }; //------------------------------------------- - // Custom Rectangles + // Custom Rectangles/Glyphs API //------------------------------------------- - // [Private] User rectangle for packing custom texture data into the atlas. + // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. After calling Build(), you can query the rectangle position and render your pixels. + // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs. struct CustomRect { - unsigned int ID; // Input // User ID. <0x10000 for font mapped data (WIP/UNSUPPORTED), >=0x10000 for other texture data + unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data. unsigned short Width, Height; // Input // Desired rectangle dimension unsigned short X, Y; // Output // Packed position in Atlas - CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; } + float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance + ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset + ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font + CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; } bool IsPacked() const { return X != 0xFFFF; } }; + IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font. + IMGUI_API void ClearCustomRects(); + IMGUI_API void CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max); + const CustomRect* GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; } + //------------------------------------------- // Members //------------------------------------------- @@ -1444,8 +1454,7 @@ struct ImFontAtlas ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. ImVector ConfigData; // Internal data - IMGUI_API int CustomRectRegister(unsigned int id, int width, int height); - IMGUI_API void CustomRectCalcUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max); + int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList }; // Font runtime data and rendering diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f2e1a2b81..aee9374d5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1066,7 +1066,7 @@ ImFontConfig::ImFontConfig() // The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes. const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 90; const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; -const int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0xF0000; +const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000; const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = { "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" @@ -1107,6 +1107,8 @@ ImFontAtlas::ImFontAtlas() TexPixelsRGBA32 = NULL; TexWidth = TexHeight = 0; TexUvWhitePixel = ImVec2(0, 0); + for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++) + CustomRectIds[n] = -1; } ImFontAtlas::~ImFontAtlas() @@ -1123,7 +1125,7 @@ void ImFontAtlas::ClearInputData() ConfigData[i].FontData = NULL; } - // When clearing this we lose access to the font name and other information used to build the font. + // When clearing this we lose access to the font name and other information used to build the font. for (int i = 0; i < Fonts.Size; i++) if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size) { @@ -1319,8 +1321,9 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed return font; } -int ImFontAtlas::CustomRectRegister(unsigned int id, int width, int height) +int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height) { + IM_ASSERT(id >= 0x10000); IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); CustomRect r; @@ -1331,7 +1334,23 @@ int ImFontAtlas::CustomRectRegister(unsigned int id, int width, int height) return CustomRects.Size - 1; // Return index } -void ImFontAtlas::CustomRectCalcUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) +int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) +{ + IM_ASSERT(font != NULL); + IM_ASSERT(width > 0 && width <= 0xFFFF); + IM_ASSERT(height > 0 && height <= 0xFFFF); + CustomRect r; + r.ID = id; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + r.GlyphAdvanceX = advance_x; + r.GlyphOffset = offset; + r.Font = font; + CustomRects.push_back(r); + return CustomRects.Size - 1; // Return index +} + +void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) { IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed @@ -1553,9 +1572,8 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas) { - // FIXME-WIP: We should register in the constructor (but cannot because our static instances may not have allocator ready by the time they initialize). This needs to be fixed because we can expose CustomRects. - if (atlas->CustomRects.empty()) - atlas->CustomRectRegister(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H); + if (atlas->CustomRectIds[0] < 0) + atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1, FONT_ATLAS_DEFAULT_TEX_DATA_H); } void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) @@ -1600,7 +1618,8 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaq static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) { - ImFontAtlas::CustomRect& r = atlas->CustomRects[0]; + IM_ASSERT(atlas->CustomRectIds[0] >= 0); + ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]]; IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID); IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF*2+1); IM_ASSERT(r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); @@ -1653,6 +1672,19 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) // Render into our custom data block ImFontAtlasBuildRenderDefaultTexData(atlas); + // Register custom rectangle glyphs + for (int i = 0; i < atlas->CustomRects.Size; i++) + { + const ImFontAtlas::CustomRect& r = atlas->CustomRects[i]; + if (r.Font == NULL || r.ID > 0x10000) + continue; + + IM_ASSERT(r.Font->ContainerAtlas == atlas); + ImVec2 uv0, uv1; + atlas->CalcCustomRectUV(&r, &uv0, &uv1); + r.Font->AddGlyph((ImWchar)r.ID, r.GlyphOffset.x, r.GlyphOffset.y, r.GlyphOffset.x + r.Width, r.GlyphOffset.y + r.Height, uv0.x, uv0.y, uv1.x, uv1.y, r.GlyphAdvanceX); + } + // Build all fonts lookup tables for (int i = 0; i < atlas->Fonts.Size; i++) atlas->Fonts[i]->BuildLookupTable(); @@ -1929,7 +1961,7 @@ void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, glyph.V0 = v0; glyph.U1 = u1; glyph.V1 = v1; - glyph.AdvanceX = (advance_x + ConfigData->GlyphExtraSpacing.x); // Bake spacing into AdvanceX + glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x; // Bake spacing into AdvanceX if (ConfigData->PixelSnapH) glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f);