Browse Source

Fonts: Baked system, with auto-bind, v10.

# Conflicts:
#	imgui_internal.h
ocornut 6 months ago
parent
commit
093d01269a
7 changed files with 542 additions and 293 deletions
  1. 60 34
      imgui.cpp
  2. 44 18
      imgui.h
  3. 309 165
      imgui_draw.cpp
  4. 26 13
      imgui_internal.h
  5. 1 1
      imgui_tables.cpp
  6. 18 15
      imgui_widgets.cpp
  7. 84 47
      misc/freetype/imgui_freetype.cpp

+ 60 - 34
imgui.cpp

@@ -3738,7 +3738,8 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
         const float font_size = draw_list->_Data->FontSize;
         const float font_size = draw_list->_Data->FontSize;
         const float font_scale = draw_list->_Data->FontScale;
         const float font_scale = draw_list->_Data->FontScale;
         const char* text_end_ellipsis = NULL;
         const char* text_end_ellipsis = NULL;
-        const float ellipsis_width = font->GetCharAdvance(font->EllipsisChar) * font_scale;
+        ImFontBaked* baked = font->GetFontBaked(font_size);
+        const float ellipsis_width = baked->GetCharAdvance(font->EllipsisChar) * font_scale;
 
 
         // We can now claim the space between pos_max.x and ellipsis_max.x
         // 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);
         const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f);
@@ -3939,7 +3940,8 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
     Initialized = false;
     Initialized = false;
     FontAtlasOwnedByContext = shared_font_atlas ? false : true;
     FontAtlasOwnedByContext = shared_font_atlas ? false : true;
     Font = NULL;
     Font = NULL;
-    FontSize = FontBaseSize = FontScale = CurrentDpiScale = 0.0f;
+    FontBaked = NULL;
+    FontSize = /*FontBaseSize = */FontScale = CurrentDpiScale = 0.0f;
     IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
     IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
     IO.Fonts->RefCount++;
     IO.Fonts->RefCount++;
     Time = 0.0f;
     Time = 0.0f;
@@ -4275,6 +4277,7 @@ void ImGui::Shutdown()
     g.MenusIdSubmittedThisFrame.clear();
     g.MenusIdSubmittedThisFrame.clear();
     g.InputTextState.ClearFreeMemory();
     g.InputTextState.ClearFreeMemory();
     g.InputTextDeactivatedState.ClearFreeMemory();
     g.InputTextDeactivatedState.ClearFreeMemory();
+    g.InputTextPasswordFont.ContainerAtlas = NULL;
 
 
     g.SettingsWindows.clear();
     g.SettingsWindows.clear();
     g.SettingsHandlers.clear();
     g.SettingsHandlers.clear();
@@ -4371,8 +4374,9 @@ static void SetCurrentWindow(ImGuiWindow* window)
     g.CurrentDpiScale = 1.0f; // FIXME-DPI: WIP this is modified in docking
     g.CurrentDpiScale = 1.0f; // FIXME-DPI: WIP this is modified in docking
     if (window)
     if (window)
     {
     {
-        g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
-        g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize;
+        // FIXME-BAKED
+        //g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
+        //g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize;
         ImGui::NavUpdateCurrentWindowIsScrollPushableX();
         ImGui::NavUpdateCurrentWindowIsScrollPushableX();
     }
     }
 }
 }
@@ -5186,7 +5190,7 @@ static void ImGui::UpdateTexturesNewFrame()
     if (g.FontAtlasOwnedByContext)
     if (g.FontAtlasOwnedByContext)
     {
     {
         atlas->RendererHasTextures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
         atlas->RendererHasTextures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
-        ImFontAtlasUpdateNewFrame(atlas);
+        ImFontAtlasUpdateNewFrame(atlas, g.FrameCount);
     }
     }
 }
 }
 
 
@@ -8399,11 +8403,14 @@ ImVec2 ImGui::GetFontTexUvWhitePixel()
 void ImGui::SetWindowFontScale(float scale)
 void ImGui::SetWindowFontScale(float scale)
 {
 {
     IM_ASSERT(scale > 0.0f);
     IM_ASSERT(scale > 0.0f);
+    // FIXME-BAKED
+    /*
     ImGuiContext& g = *GImGui;
     ImGuiContext& g = *GImGui;
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
     window->FontWindowScale = scale;
     window->FontWindowScale = scale;
     g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
     g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
     g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize;
     g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize;
+    */
 }
 }
 
 
 void ImGui::PushFocusScope(ImGuiID id)
 void ImGui::PushFocusScope(ImGuiID id)
@@ -8570,20 +8577,21 @@ void ImGui::UpdateFontsNewFrame()
     ImGuiContext& g = *GImGui;
     ImGuiContext& g = *GImGui;
     if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0)
     if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0)
         g.IO.Fonts->Locked = true;
         g.IO.Fonts->Locked = true;
-    SetCurrentFont(GetDefaultFont());
+    SetCurrentFont(GetDefaultFont(), GetDefaultFont()->Sources[0].SizePixels);
     IM_ASSERT(g.Font->IsLoaded());
     IM_ASSERT(g.Font->IsLoaded());
 }
 }
 
 
 // Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only.
 // Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only.
-void ImGui::SetCurrentFont(ImFont* font)
+void ImGui::SetCurrentFont(ImFont* font, float font_size)
 {
 {
     ImGuiContext& g = *GImGui;
     ImGuiContext& g = *GImGui;
     IM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
     IM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
     IM_ASSERT(font->Scale > 0.0f);
     IM_ASSERT(font->Scale > 0.0f);
     g.Font = font;
     g.Font = font;
-    g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
-    g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
-    g.FontScale = g.FontSize / g.Font->FontSize;
+    //g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.FontBaked->Size * g.Font->Scale);
+    g.FontSize = font_size;// g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
+    g.FontBaked = g.Font->GetFontBaked(g.FontSize);
+    g.FontScale = g.FontSize / g.FontBaked->Size;
     g.DrawListSharedData.Font = g.Font;
     g.DrawListSharedData.Font = g.Font;
     g.DrawListSharedData.FontSize = g.FontSize;
     g.DrawListSharedData.FontSize = g.FontSize;
     g.DrawListSharedData.FontScale = g.FontScale;
     g.DrawListSharedData.FontScale = g.FontScale;
@@ -8606,7 +8614,7 @@ void ImGui::PushFont(ImFont* font)
     if (font == NULL)
     if (font == NULL)
         font = GetDefaultFont();
         font = GetDefaultFont();
     g.FontStack.push_back(font);
     g.FontStack.push_back(font);
-    SetCurrentFont(font);
+    SetCurrentFont(font, g.FontSize);
 }
 }
 
 
 void  ImGui::PopFont()
 void  ImGui::PopFont()
@@ -8619,7 +8627,14 @@ void  ImGui::PopFont()
     }
     }
     g.FontStack.pop_back();
     g.FontStack.pop_back();
     ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back();
     ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back();
-    SetCurrentFont(font);
+    SetCurrentFont(font, g.FontSize); // FIXME-BAKED: size in stack
+}
+
+void    ImGui::SetFontSize(float size)
+{
+    // FIXME-BAKED
+    ImGuiContext& g = *GImGui;
+    SetCurrentFont(g.Font, size);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -15512,7 +15527,7 @@ void ImGui::DebugTextEncoding(const char* str)
         }
         }
         TableNextColumn();
         TableNextColumn();
         TextUnformatted(p, p + c_utf8_len);
         TextUnformatted(p, p + c_utf8_len);
-        if (GetFont()->FindGlyphNoFallback((ImWchar)c) == NULL)
+        if (!GetFont()->IsGlyphInFont((ImWchar)c))
         {
         {
             SameLine();
             SameLine();
             TextUnformatted("[missing]");
             TextUnformatted("[missing]");
@@ -16478,8 +16493,8 @@ void ImGui::DebugNodeFont(ImFont* font)
 {
 {
     ImGuiContext& g = *GImGui;
     ImGuiContext& g = *GImGui;
     ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
     ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
-    bool opened = TreeNode(font, "Font: \"%s\": %.2f px, %d glyphs, %d sources(s)",
-        font->Sources ? font->Sources[0].Name : "", font->FontSize, font->Glyphs.Size, font->SourcesCount);
+    ImFontAtlas* atlas = font->ContainerAtlas;
+    bool opened = TreeNode(font, "Font: \"%s\": %d sources(s)", font->Sources ? font->Sources[0].Name : "", font->SourcesCount);
 
 
     // Display preview text
     // Display preview text
     if (!opened)
     if (!opened)
@@ -16499,11 +16514,11 @@ void ImGui::DebugNodeFont(ImFont* font)
     }
     }
     if (SmallButton("Set as default"))
     if (SmallButton("Set as default"))
         GetIO().FontDefault = font;
         GetIO().FontDefault = font;
-    if (font->ContainerAtlas->Fonts.Size > 1 && !font->ContainerAtlas->Locked)
+    if (atlas->Fonts.Size > 1 && !atlas->Locked)
     {
     {
         SameLine();
         SameLine();
         if (SmallButton("Remove"))
         if (SmallButton("Remove"))
-            font->ContainerAtlas->RemoveFont(font);
+            atlas->RemoveFont(font);
     }
     }
 
 
     // Display details
     // Display details
@@ -16515,33 +16530,43 @@ void ImGui::DebugNodeFont(ImFont* font)
         "You may oversample them to get some flexibility with scaling. "
         "You may oversample them to get some flexibility with scaling. "
         "You can also render at multiple sizes and select which one to use at runtime.\n\n"
         "You can also render at multiple sizes and select which one to use at runtime.\n\n"
         "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");
         "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");
-    Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
+
     char c_str[5];
     char c_str[5];
     Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar);
     Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar);
     Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar);
     Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar);
-    const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface);
-    Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt);
-    for (int config_i = 0; config_i < font->SourcesCount; config_i++)
-        if (font->Sources)
-        {
-            ImFontConfig* src = &font->Sources[config_i];
-            int oversample_h, oversample_v;
-            ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v);
-            BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
-                config_i, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y);
-        }
+    for (int src_n = 0; src_n < font->SourcesCount; src_n++)
+        if (ImFontConfig* src = &font->Sources[src_n])
+            BulletText("Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)",
+                src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y);
 
 
     // Display all glyphs of the fonts in separate pages of 256 characters
     // Display all glyphs of the fonts in separate pages of 256 characters
+    for (int baked_n = 0; baked_n < atlas->Builder->BakedPool.Size; baked_n++)
     {
     {
-        if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
+        ImFontBaked* baked = &atlas->Builder->BakedPool[baked_n];
+        if (baked->ContainerFont != font)
+            continue;
+        PushID(baked_n);
+        if (TreeNode("Glyphs", "Baked at %.2fpx: %d glyphs%s", baked->Size, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : ""))
         {
         {
             if (SmallButton("Load all"))
             if (SmallButton("Load all"))
                 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base++)
                 for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base++)
-                    font->FindGlyph((ImWchar)base);
+                    baked->FindGlyph((ImWchar)base);
+
+            const int surface_sqrt = (int)ImSqrt((float)baked->MetricsTotalSurface);
+            Text("Ascent: %f, Descent: %f, Ascent-Descent: %f", baked->Ascent, baked->Descent, baked->Ascent - baked->Descent);
+            Text("Texture Area: about %d px ~%dx%d px", baked->MetricsTotalSurface, surface_sqrt, surface_sqrt);
+            for (int src_n = 0; src_n < font->SourcesCount; src_n++)
+            {
+                ImFontConfig* src = &font->Sources[src_n];
+                int oversample_h, oversample_v;
+                ImFontAtlasBuildGetOversampleFactors(src, baked->Size, &oversample_h, &oversample_v);
+                BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
+                    src_n, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y);
+            }
 
 
             ImDrawList* draw_list = GetWindowDrawList();
             ImDrawList* draw_list = GetWindowDrawList();
             const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
             const ImU32 glyph_col = GetColorU32(ImGuiCol_Text);
-            const float cell_size = font->FontSize * 1;
+            const float cell_size = baked->Size * 1;
             const float cell_spacing = GetStyle().ItemSpacing.y;
             const float cell_spacing = GetStyle().ItemSpacing.y;
             for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
             for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
             {
             {
@@ -16556,7 +16581,7 @@ void ImGui::DebugNodeFont(ImFont* font)
 
 
                 int count = 0;
                 int count = 0;
                 for (unsigned int n = 0; n < 256; n++)
                 for (unsigned int n = 0; n < 256; n++)
-                    if (font->IsGlyphLoaded((ImWchar)(base + n)))
+                    if (baked->IsGlyphLoaded((ImWchar)(base + n)))
                         count++;
                         count++;
                 if (count <= 0)
                 if (count <= 0)
                     continue;
                     continue;
@@ -16571,7 +16596,7 @@ void ImGui::DebugNodeFont(ImFont* font)
                     // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
                     // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
                     ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
                     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);
                     ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
-                    const ImFontGlyph* glyph = font->IsGlyphLoaded((ImWchar)(base + n)) ? font->FindGlyph((ImWchar)(base + n)) : NULL;
+                    const ImFontGlyph* glyph = baked->IsGlyphLoaded((ImWchar)(base + n)) ? baked->FindGlyph((ImWchar)(base + n)) : NULL;
                     draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
                     draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
                     if (!glyph)
                     if (!glyph)
                         continue;
                         continue;
@@ -16587,6 +16612,7 @@ void ImGui::DebugNodeFont(ImFont* font)
             }
             }
             TreePop();
             TreePop();
         }
         }
+        PopID();
     }
     }
     TreePop();
     TreePop();
     Unindent();
     Unindent();

+ 44 - 18
imgui.h

@@ -50,7 +50,7 @@ Index of this file:
 // [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage)
 // [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage)
 // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData)
 // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData)
 // [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData)
 // [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData)
-// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
+// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFontBaked, ImFont)
 // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport)
 // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport)
 // [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData)
 // [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData)
 // [SECTION] Obsolete functions and types
 // [SECTION] Obsolete functions and types
@@ -172,6 +172,7 @@ struct ImDrawVert;                  // A single vertex (pos + uv + col = 20 byte
 struct ImFont;                      // Runtime data for a single font within a parent ImFontAtlas
 struct ImFont;                      // Runtime data for a single font within a parent ImFontAtlas
 struct ImFontAtlas;                 // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader
 struct ImFontAtlas;                 // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader
 struct ImFontAtlasBuilder;          // Opaque storage for building a ImFontAtlas
 struct ImFontAtlasBuilder;          // Opaque storage for building a ImFontAtlas
+struct ImFontBaked;                 // Baked data for a ImFont at a given size.
 struct ImFontConfig;                // Configuration data when adding a font or merging fonts
 struct ImFontConfig;                // Configuration data when adding a font or merging fonts
 struct ImFontGlyph;                 // A single font glyph (code point + coordinates within in ImFontAtlas + offset)
 struct ImFontGlyph;                 // A single font glyph (code point + coordinates within in ImFontAtlas + offset)
 struct ImFontGlyphRangesBuilder;    // Helper to build glyph ranges from text/string data
 struct ImFontGlyphRangesBuilder;    // Helper to build glyph ranges from text/string data
@@ -471,6 +472,8 @@ namespace ImGui
     // Parameters stacks (shared)
     // Parameters stacks (shared)
     IMGUI_API void          PushFont(ImFont* font);                                         // use NULL as a shortcut to push default font
     IMGUI_API void          PushFont(ImFont* font);                                         // use NULL as a shortcut to push default font
     IMGUI_API void          PopFont();
     IMGUI_API void          PopFont();
+    IMGUI_API void          SetFontSize(float size);
+    //IMGUI_API void          PopFontSize();
     IMGUI_API void          PushStyleColor(ImGuiCol idx, ImU32 col);                        // modify a style color. always use this if you modify the style after NewFrame().
     IMGUI_API void          PushStyleColor(ImGuiCol idx, ImU32 col);                        // modify a style color. always use this if you modify the style after NewFrame().
     IMGUI_API void          PushStyleColor(ImGuiCol idx, const ImVec4& col);
     IMGUI_API void          PushStyleColor(ImGuiCol idx, const ImVec4& col);
     IMGUI_API void          PopStyleColor(int count = 1);
     IMGUI_API void          PopStyleColor(int count = 1);
@@ -3419,10 +3422,10 @@ struct ImFontConfig
     int             OversampleV;            // 0 (1)    // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis.
     int             OversampleV;            // 0 (1)    // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis.
     float           SizePixels;             //          // Size in pixels for rasterizer (more or less maps to the resulting font height).
     float           SizePixels;             //          // Size in pixels for rasterizer (more or less maps to the resulting font height).
     //ImVec2        GlyphExtraSpacing;      // 0, 0     // (REMOVED IN 1.91.9: use GlyphExtraAdvanceX)
     //ImVec2        GlyphExtraSpacing;      // 0, 0     // (REMOVED IN 1.91.9: use GlyphExtraAdvanceX)
-    ImVec2          GlyphOffset;            // 0, 0     // Offset all glyphs from this font input.
+    ImVec2          GlyphOffset;            // 0, 0     // [FIXME-BAKED] Offset all glyphs from this font input.
     const ImWchar*  GlyphRanges;            // NULL     // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list).
     const ImWchar*  GlyphRanges;            // NULL     // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list).
-    float           GlyphMinAdvanceX;       // 0        // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font
-    float           GlyphMaxAdvanceX;       // FLT_MAX  // Maximum AdvanceX for glyphs
+    float           GlyphMinAdvanceX;       // 0        // [FIXME-BAKED] Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font
+    float           GlyphMaxAdvanceX;       // FLT_MAX  // [FIXME-BAKED] Maximum AdvanceX for glyphs
     float           GlyphExtraAdvanceX;     // 0        // Extra spacing (in pixels) between glyphs. Please contact us if you are using this.
     float           GlyphExtraAdvanceX;     // 0        // Extra spacing (in pixels) between glyphs. Please contact us if you are using this.
     unsigned int    FontBuilderFlags;       // 0        // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure.
     unsigned int    FontBuilderFlags;       // 0        // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure.
     float           RasterizerMultiply;     // 1.0f     // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future.
     float           RasterizerMultiply;     // 1.0f     // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future.
@@ -3599,6 +3602,7 @@ struct ImFontAtlas
     ImVector<ImFontConfig>      Sources;            // Source/configuration data
     ImVector<ImFontConfig>      Sources;            // Source/configuration data
     ImVec4                      TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1];  // UVs for baked anti-aliased lines
     ImVec4                      TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1];  // UVs for baked anti-aliased lines
     int                         TexNextUniqueID;    // Next value to be stored in TexData->UniqueID
     int                         TexNextUniqueID;    // Next value to be stored in TexData->UniqueID
+    int                         FontNextUniqueID;   // Next value to be stored in ImFont->SourceID
     ImVector<ImDrawListSharedData*> DrawListSharedDatas;
     ImVector<ImDrawListSharedData*> DrawListSharedDatas;
 
 
     // [Internal] Font builder
     // [Internal] Font builder
@@ -3616,30 +3620,57 @@ struct ImFontAtlas
     //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder;      // OBSOLETED in 1.67+
     //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder;      // OBSOLETED in 1.67+
 };
 };
 
 
-// Font runtime data and rendering
-// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32().
-struct ImFont
+// Font runtime data for a given size
+// Important: pointers to ImFontBaked are only valid for the current frame.
+struct ImFontBaked
 {
 {
     // [Internal] Members: Hot ~20/24 bytes (for CalcTextSize)
     // [Internal] Members: Hot ~20/24 bytes (for CalcTextSize)
     ImVector<float>             IndexAdvanceX;      // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI).
     ImVector<float>             IndexAdvanceX;      // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI).
     float                       FallbackAdvanceX;   // 4     // out // FindGlyph(FallbackChar)->AdvanceX
     float                       FallbackAdvanceX;   // 4     // out // FindGlyph(FallbackChar)->AdvanceX
-    float                       FontSize;           // 4     // in  // Height of characters/line, set during loading (don't change after loading)
+    float                       Size;               // 4     // in  // Height of characters/line, set during loading (doesn't change after loading)
 
 
     // [Internal] Members: Hot ~28/36 bytes (for RenderText loop)
     // [Internal] Members: Hot ~28/36 bytes (for RenderText loop)
     ImVector<ImU16>             IndexLookup;        // 12-16 // out // Sparse. Index glyphs by Unicode code-point.
     ImVector<ImU16>             IndexLookup;        // 12-16 // out // Sparse. Index glyphs by Unicode code-point.
     ImVector<ImFontGlyph>       Glyphs;             // 12-16 // out // All glyphs.
     ImVector<ImFontGlyph>       Glyphs;             // 12-16 // out // All glyphs.
     int                         FallbackGlyphIndex; // 4     // out // Index of FontFallbackChar
     int                         FallbackGlyphIndex; // 4     // out // Index of FontFallbackChar
 
 
-    // [Internal] Members: Cold ~32/40/60 bytes
+    // [Internal] Members: Cold
+    float                       Ascent, Descent;    // 4+4   // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled)
+    unsigned int                MetricsTotalSurface:26;// 3  // 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)
+    unsigned int                WantDestroy:1;      // 1     //     // Queued for destroy
+    int                         LastUsedFrame;      // 4     //     // Record of that time this was bounds
+    ImGuiID                     BakedId;            // 4     //
+    ImFont*                     ContainerFont;      // 4-8   // in  // Parent font
+    void*                       FontBackendData;    // 4-8   //     // Font backend opaque storage (per baked font)
+
+    // Functions
+    IMGUI_API ImFontBaked();
+    IMGUI_API void              ClearOutputData();
+    IMGUI_API ImFontGlyph*      FindGlyph(ImWchar c);               // Return U+FFFD glyph if requested glyph doesn't exists.
+    IMGUI_API ImFontGlyph*      FindGlyphNoFallback(ImWchar c);     // Return NULL if glyph doesn't exist
+    IMGUI_API float             GetCharAdvance(ImWchar c);
+    IMGUI_API bool              IsGlyphLoaded(ImWchar c);
+    IMGUI_API ImFontGlyph*      BuildLoadGlyph(ImWchar c);
+    IMGUI_API void              BuildGrowIndex(int new_size);
+};
+
+// Font runtime data and rendering
+// - ImFontAtlas automatically loads a default embedded font for you if you didn't load one manually.
+// - Since 1.92.X a font may be rendered as any size! Therefore a font doesn't have one specific size.
+// - Use 'font->GetBakedForSize(size)' to retrieve the ImFontBaked* corresponding to a given size.
+// - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as g.FontBaked == g.Font->GetBakedForSize(g.FontSize).
+struct ImFont
+{
+    // [Internal] Members: Cold ~32/40/80 bytes
     // Conceptually Sources[] is the list of font sources merged to create this font.
     // Conceptually Sources[] is the list of font sources merged to create this font.
+    ImFontBaked*                LastBaked;          // Cache last bound baked. DO NOT USE. Use GetFontBaked().
+    ImGuiID                     FontId;             // Unique identifier for the 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                       SourcesCount;       // 2     // in  // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont.
     ImFontConfig*               Sources;            // 4-8   // in  // Pointer within ContainerAtlas->Sources[], to SourcesCount instances
     ImFontConfig*               Sources;            // 4-8   // in  // Pointer within ContainerAtlas->Sources[], to SourcesCount instances
     ImFontAtlas*                ContainerAtlas;     // 4-8   // out // What we has been loaded into
     ImFontAtlas*                ContainerAtlas;     // 4-8   // out // What we has been loaded into
     ImWchar                     EllipsisChar;       // 2-4   // out // Character used for ellipsis rendering ('...').
     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, '?')
     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                       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)
     ImU8                        Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 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 across all used codepoints.
     ImU8                        Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 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 across all used codepoints.
     bool                        LockDisableLoading;
     bool                        LockDisableLoading;
     short                       LockSingleSrcConfigIdx;
     short                       LockSingleSrcConfigIdx;
@@ -3647,10 +3678,7 @@ struct ImFont
     // Methods
     // Methods
     IMGUI_API ImFont();
     IMGUI_API ImFont();
     IMGUI_API ~ImFont();
     IMGUI_API ~ImFont();
-    IMGUI_API ImFontGlyph*      FindGlyph(ImWchar c);           // Return fallback glyph if requested glyph doesn't exists.
-    IMGUI_API ImFontGlyph*      FindGlyphNoFallback(ImWchar c); // Return NULL if glyph doesn't exist
-    IMGUI_API float             GetCharAdvance(ImWchar c);
-    IMGUI_API bool              IsGlyphLoaded(ImWchar c);
+    IMGUI_API ImFontBaked*      GetFontBaked(float font_size);  // Get or create baked data for given size
     IMGUI_API bool              IsGlyphInFont(ImWchar c);
     IMGUI_API bool              IsGlyphInFont(ImWchar c);
     bool                        IsLoaded() const                { return ContainerAtlas != NULL; }
     bool                        IsLoaded() const                { return ContainerAtlas != NULL; }
     const char*                 GetDebugName() const            { return Sources ? Sources->Name : "<unknown>"; }
     const char*                 GetDebugName() const            { return Sources ? Sources->Name : "<unknown>"; }
@@ -3664,15 +3692,13 @@ struct ImFont
     IMGUI_API void              RenderText(ImDrawList* draw_list, float size, const 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);
     IMGUI_API void              RenderText(ImDrawList* draw_list, float size, const 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);
 
 
 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
-    inline const char*          CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(FontSize * scale, text, text_end, wrap_width); }
+    inline const char*          CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(Sources[0].SizePixels * scale, text, text_end, wrap_width); }
 #endif
 #endif
 
 
     // [Internal] Don't use!
     // [Internal] Don't use!
     IMGUI_API void              ClearOutputData();
     IMGUI_API void              ClearOutputData();
     IMGUI_API void              AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst);// , 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              AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst);// , 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 bool              IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
     IMGUI_API bool              IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
-    IMGUI_API ImFontGlyph*      BuildLoadGlyph(ImWchar c);
-    IMGUI_API void              BuildGrowIndex(int new_size);
 };
 };
 
 
 // Added indirection to avoid patching ImDrawCmd after texture updates.
 // Added indirection to avoid patching ImDrawCmd after texture updates.

+ 309 - 165
imgui_draw.cpp

@@ -2394,6 +2394,7 @@ void ImGui::ShadeVertsTransformPos(ImDrawList* draw_list, int vert_start_idx, in
 // [SECTION] ImFontConfig
 // [SECTION] ImFontConfig
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
+// FIXME-NEWATLAS: Oversample specification could be more dynamic. For now, favoring automatic selection.
 ImFontConfig::ImFontConfig()
 ImFontConfig::ImFontConfig()
 {
 {
     memset(this, 0, sizeof(*this));
     memset(this, 0, sizeof(*this));
@@ -2495,9 +2496,9 @@ void ImTextureData::DestroyPixels()
 // - ImFontAtlasBuildAddFont()
 // - ImFontAtlasBuildAddFont()
 // - ImFontAtlasBuildSetupFontCreateEllipsisFromDot()
 // - ImFontAtlasBuildSetupFontCreateEllipsisFromDot()
 // - ImFontAtlasBuildSetupFontSpecialGlyphs()
 // - ImFontAtlasBuildSetupFontSpecialGlyphs()
-// - ImFontAtlasBuildDiscardFontGlyph()
-// - ImFontAtlasBuildDiscardFontGlyphs()
-// - ImFontAtlasBuildReloadFont()
+// - ImFontAtlasBuildDiscardUnusedBakes()
+// - ImFontAtlasBuildDiscardFontBaked()
+// - ImFontAtlasBuildDiscardFontBakedGlyph()
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // - ImFontAtlasAddDrawListSharedData()
 // - ImFontAtlasAddDrawListSharedData()
 // - ImFontAtlasRemoveDrawListSharedData()
 // - ImFontAtlasRemoveDrawListSharedData()
@@ -2594,6 +2595,7 @@ ImFontAtlas::ImFontAtlas()
     RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update.
     RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update.
     TexRef._TexData = NULL;// this;
     TexRef._TexData = NULL;// this;
     TexNextUniqueID = 1;
     TexNextUniqueID = 1;
+    FontNextUniqueID = 1;
     Builder = NULL;
     Builder = NULL;
 }
 }
 
 
@@ -2685,7 +2687,8 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at
 
 
 // Called by NewFrame(). When multiple context own the atlas, only the first one calls this.
 // Called by NewFrame(). When multiple context own the atlas, only the first one calls this.
 // If you are calling this yourself, ensure atlas->RendererHasTexUpdates is et.
 // If you are calling this yourself, ensure atlas->RendererHasTexUpdates is et.
-void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas)
+// 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age.
+void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count)
 {
 {
     // Check that font atlas was built or backend support texture reload in which case we can build now
     // Check that font atlas was built or backend support texture reload in which case we can build now
     if (atlas->RendererHasTextures)
     if (atlas->RendererHasTextures)
@@ -2701,6 +2704,33 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas)
     if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges)
     if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges)
         IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build().");
         IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build().");
 
 
+    // Clear BakedCurrent cache, this is important because it ensure the uncached path gets taken once.
+    // We also rely on ImFontBaked* pointers never crossing frames.
+    ImFontAtlasBuilder* builder = atlas->Builder;
+    builder->FrameCount = frame_count;
+    for (ImFont* font : atlas->Fonts)
+        font->LastBaked = NULL;
+
+    // Garbage collect BakedPool
+    if (builder->BakedDiscardedCount > 0)
+    {
+        int dst_n = 0, src_n = 0;
+        for (; src_n < builder->BakedPool.Size; src_n++)
+        {
+            ImFontBaked* p_src = &builder->BakedPool[src_n];
+            if (p_src->WantDestroy)
+                continue;
+            ImFontBaked* p_dst = &builder->BakedPool[dst_n++];
+            if (p_dst == p_src)
+                continue;
+            memcpy(p_dst, p_src, sizeof(ImFontBaked));
+            builder->BakedMap.SetVoidPtr(p_dst->BakedId, p_dst);
+        }
+        IM_ASSERT(dst_n + builder->BakedDiscardedCount == src_n);
+        builder->BakedPool.Size -= builder->BakedDiscardedCount;
+        builder->BakedDiscardedCount = 0;
+    }
+
     // Update texture status
     // Update texture status
     for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
     for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
     {
     {
@@ -2928,15 +2958,23 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
         ImFontAtlasBuildInit(this);
         ImFontAtlasBuildInit(this);
 
 
     // Create new font
     // Create new font
+    ImFont* font;
     if (!font_cfg->MergeMode)
     if (!font_cfg->MergeMode)
-        Fonts.push_back(IM_NEW(ImFont));
+    {
+        font = IM_NEW(ImFont)();
+        font->FontId = FontNextUniqueID++;
+        Fonts.push_back(font);
+    }
     else
     else
+    {
         IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
         IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
+        font = Fonts.back();
+    }
 
 
     Sources.push_back(*font_cfg);
     Sources.push_back(*font_cfg);
     ImFontConfig& new_font_cfg = Sources.back();
     ImFontConfig& new_font_cfg = Sources.back();
     if (new_font_cfg.DstFont == NULL)
     if (new_font_cfg.DstFont == NULL)
-        new_font_cfg.DstFont = Fonts.back();
+        new_font_cfg.DstFont = font;
     if (!new_font_cfg.FontDataOwnedByAtlas)
     if (!new_font_cfg.FontDataOwnedByAtlas)
     {
     {
         new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
         new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
@@ -2960,7 +2998,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
         Sources.pop_back();
         Sources.pop_back();
         if (!font_cfg->MergeMode)
         if (!font_cfg->MergeMode)
         {
         {
-            IM_DELETE(Fonts.back());
+            IM_DELETE(font);
             Fonts.pop_back();
             Fonts.pop_back();
         }
         }
         return NULL;
         return NULL;
@@ -3091,7 +3129,7 @@ static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font,
                 bool need_bind_ctx = ctx != curr_ctx;
                 bool need_bind_ctx = ctx != curr_ctx;
                 if (need_bind_ctx)
                 if (need_bind_ctx)
                     ImGui::SetCurrentContext(ctx);
                     ImGui::SetCurrentContext(ctx);
-                ImGui::SetCurrentFont(new_font);
+                ImGui::SetCurrentFont(new_font, ctx->FontSize);
                 if (need_bind_ctx)
                 if (need_bind_ctx)
                     ImGui::SetCurrentContext(curr_ctx);
                     ImGui::SetCurrentContext(curr_ctx);
             }
             }
@@ -3102,7 +3140,7 @@ static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font,
 void ImFontAtlas::RemoveFont(ImFont* font)
 void ImFontAtlas::RemoveFont(ImFont* font)
 {
 {
     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
     IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!");
-    ImFontAtlasBuildDiscardFontGlyphs(this, font);
+    font->ClearOutputData();
 
 
     for (int src_n = 0; src_n < font->SourcesCount; src_n++)
     for (int src_n = 0; src_n < font->SourcesCount; src_n++)
     {
     {
@@ -3151,7 +3189,7 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int wid
     IM_ASSERT(font != NULL);
     IM_ASSERT(font != NULL);
     IM_ASSERT(width > 0 && width <= 0xFFFF);
     IM_ASSERT(width > 0 && width <= 0xFFFF);
     IM_ASSERT(height > 0 && height <= 0xFFFF);
     IM_ASSERT(height > 0 && height <= 0xFFFF);
-
+#if 0
     ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height);
     ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height);
     if (r_id < 0)
     if (r_id < 0)
         return -1;
         return -1;
@@ -3174,6 +3212,12 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int wid
     glyph.PackId = r_id;
     glyph.PackId = r_id;
     ImFontAtlasBuildAddFontGlyph(this, font, &font->Sources[0], &glyph);
     ImFontAtlasBuildAddFontGlyph(this, font, &font->Sources[0], &glyph);
     return r_id;
     return r_id;
+#endif
+    // FIXME-BAKED: Need a design for AddCustomRectFontGlyph()
+    IM_UNUSED(codepoint);
+    IM_UNUSED(offset);
+    IM_UNUSED(advance_x);
+    return -1;
 }
 }
 
 
 ImTextureRect* ImFontAtlas::GetCustomRectByIndex(int idx)
 ImTextureRect* ImFontAtlas::GetCustomRectByIndex(int idx)
@@ -3237,10 +3281,10 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas)
     atlas->TexIsBuilt = true;
     atlas->TexIsBuilt = true;
 }
 }
 
 
-void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v)
+void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v)
 {
 {
     // Automatically disable horizontal oversampling over size 36
     // Automatically disable horizontal oversampling over size 36
-    *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (src->SizePixels * src->RasterizerDensity > 36.0f || src->PixelSnapH) ? 1 : 2;
+    *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : ((size * src->RasterizerDensity > 36.0f) || src->PixelSnapH) ? 1 : 2;
     *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1;
     *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1;
 }
 }
 
 
@@ -3277,11 +3321,12 @@ void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas)
         for (int src_n = 0; src_n < font->SourcesCount; src_n++)
         for (int src_n = 0; src_n < font->SourcesCount; src_n++)
         {
         {
             ImFontConfig* src = &font->Sources[src_n];
             ImFontConfig* src = &font->Sources[src_n];
+            ImFontBaked* baked = font->GetFontBaked(src->SizePixels);
             const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault();
             const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault();
             IM_ASSERT(ranges != NULL);
             IM_ASSERT(ranges != NULL);
             for (; ranges[0]; ranges += 2)
             for (; ranges[0]; ranges += 2)
                 for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
                 for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
-                    font->FindGlyphNoFallback((ImWchar)c);
+                    baked->FindGlyphNoFallback((ImWchar)c);
         }
         }
 }
 }
 
 
@@ -3436,22 +3481,23 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_
 
 
 //-----------------------------------------------------------------------------------------------------------------------------
 //-----------------------------------------------------------------------------------------------------------------------------
 
 
-static const ImFontGlyph* LoadFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count)
+ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size)
 {
 {
-    for (int n = 0; n < candidate_chars_count; n++)
-        if (candidate_chars[n] != 0)
-            if (const ImFontGlyph* glyph = font->FindGlyphNoFallback(candidate_chars[n]))
-                return glyph;
-    return NULL;
+    struct { ImGuiID FontId; float BakedSize; } hashed_data;
+    hashed_data.FontId = font_id;
+    hashed_data.BakedSize = baked_size;
+    return ImHashData(&hashed_data, sizeof(hashed_data));
 }
 }
 
 
+//-----------------------------------------------------------------------------------------------------------------------------
+
 bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src)
 bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src)
 {
 {
     ImFont* font = src->DstFont;
     ImFont* font = src->DstFont;
     if (src->MergeMode == false)
     if (src->MergeMode == false)
     {
     {
         font->ClearOutputData();
         font->ClearOutputData();
-        font->FontSize = src->SizePixels;
+        //font->FontSize = src->SizePixels;
         font->ContainerAtlas = atlas;
         font->ContainerAtlas = atlas;
         IM_ASSERT(font->Sources == src);
         IM_ASSERT(font->Sources == src);
     }
     }
@@ -3466,15 +3512,15 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src)
 
 
 // Rasterize our own ellipsis character from a dot.
 // 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.
 // 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 FontLoader's FontAddGlyph() and suggest that we should add further helpers.
-static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFont* font, const ImFontGlyph* dot_glyph)
+// FIXME-NEWATLAS: This borrows too much from FontBackend_FontAddGlyph() and suggest that we should add further helpers.
+// FIXME-BAKED: prebaked ellipsis
+/*static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFont* font, const ImFontGlyph* dot_glyph)
 {
 {
     ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId);
     ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId);
     const int dot_spacing = 1;
     const int dot_spacing = 1;
     const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing;
     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);
     ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h);
     ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
     ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
-    font->MetricsTotalSurface += r->w * r->h;
 
 
     ImFontGlyph glyph;
     ImFontGlyph glyph;
     glyph.Codepoint = (ImWchar)0x0085; // FIXME: Using arbitrary codepoint.
     glyph.Codepoint = (ImWchar)0x0085; // FIXME: Using arbitrary codepoint.
@@ -3494,44 +3540,55 @@ static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, I
     for (int n = 0; n < 3; n++)
     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);
         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);
     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, ImFont* font, ImFontConfig* src)
+static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked)
 {
 {
-    const int src_idx_in_font = (int)(src - font->Sources);
-    IM_ASSERT(src_idx_in_font >= 0 && src_idx_in_font < font->SourcesCount);
-    IM_UNUSED(atlas);
-
-    // While manipulating glyphs during init we want to restrict all searches for one source font.
-    font->LockSingleSrcConfigIdx = (short)src_idx_in_font;
-
-    // Setup Fallback character
     // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded?
     // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded?
-    const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
-    if (font->FallbackGlyphIndex == -1)
-        if (const ImFontGlyph* glyph = LoadFirstExistingGlyph(font, fallback_chars, IM_ARRAYSIZE(fallback_chars)))
+    IM_ASSERT(baked->FallbackGlyphIndex == -1);
+    if (font->FallbackChar != 0)
+        if (const ImFontGlyph* glyph = baked->FindGlyphNoFallback(font->FallbackChar))
         {
         {
-            font->FallbackChar = (ImWchar)glyph->Codepoint;
-            font->FallbackGlyphIndex = font->Glyphs.index_from_ptr(glyph); // Storing index avoid need to update pointer on growth.
-            font->FallbackAdvanceX = glyph->AdvanceX;
+            baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(glyph); // Storing index avoid need to update pointer on growth.
+            baked->FallbackAdvanceX = glyph->AdvanceX;
         }
         }
 
 
     // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews)
     // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews)
-    ImFontGlyph* space_glyph = (ImFontGlyph*)(void*)font->FindGlyph((ImWchar)' ');
+    ImFontGlyph* space_glyph = (ImFontGlyph*)(void*)baked->FindGlyphNoFallback((ImWchar)' ');
     if (space_glyph != NULL)
     if (space_glyph != NULL)
         space_glyph->Visible = false;
         space_glyph->Visible = false;
 
 
     // Setup Tab character.
     // Setup Tab character.
     // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
     // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
-    if (font->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL)
+    if (baked->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL)
     {
     {
         ImFontGlyph tab_glyph;
         ImFontGlyph tab_glyph;
         tab_glyph.Codepoint = '\t';
         tab_glyph.Codepoint = '\t';
         tab_glyph.AdvanceX = space_glyph->AdvanceX * IM_TABSIZE;
         tab_glyph.AdvanceX = space_glyph->AdvanceX * IM_TABSIZE;
-        ImFontAtlasBuildAddFontGlyph(atlas, font, src, &tab_glyph);
+        ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, &tab_glyph);
     }
     }
+}
+
+// Load/identify special glyphs
+// (note that this is called again for fonts with MergeMode)
+void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src)
+{
+    const int src_idx_in_font = (int)(src - font->Sources);
+    IM_ASSERT(src_idx_in_font >= 0 && src_idx_in_font < font->SourcesCount);
+    IM_UNUSED(atlas);
+
+    // While manipulating glyphs during init we want to restrict all searches for one source font.
+    font->LockSingleSrcConfigIdx = (short)src_idx_in_font;
+
+    // Find Fallback character. Actual glyph loaded in GetFontBaked().
+    const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' };
+    if (font->FallbackChar == 0)
+        for (ImWchar candidate_char : fallback_chars)
+            if (candidate_char != 0 && font->IsGlyphInFont(candidate_char)) // FIXME: does not respect LockSingleSrcConfigIdx()
+            {
+                font->FallbackChar = (ImWchar)candidate_char;
+                break;
+            }
 
 
     // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
     // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
     // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
     // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
@@ -3546,16 +3603,16 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im
             }
             }
     if (font->EllipsisChar == 0)
     if (font->EllipsisChar == 0)
     {
     {
-        const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
+        /*const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E };
         if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars)))
         if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars)))
             ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, font, dot_glyph);
             ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, font, dot_glyph);
-        else
+        else*/
             font->EllipsisChar = (ImWchar)' ';
             font->EllipsisChar = (ImWchar)' ';
     }
     }
     font->LockSingleSrcConfigIdx = -1;
     font->LockSingleSrcConfigIdx = -1;
 }
 }
 
 
-void ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGlyph* glyph)
+void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph)
 {
 {
     if (glyph->PackId >= 0)
     if (glyph->PackId >= 0)
     {
     {
@@ -3564,41 +3621,45 @@ void ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGl
     }
     }
     ImWchar c = glyph->Codepoint;
     ImWchar c = glyph->Codepoint;
     IM_ASSERT(font->FallbackChar != c && font->EllipsisChar != c); // Unsupported for simplicity
     IM_ASSERT(font->FallbackChar != c && font->EllipsisChar != c); // Unsupported for simplicity
-    IM_ASSERT(glyph >= font->Glyphs.Data && glyph < font->Glyphs.Data + font->Glyphs.Size);
-    font->IndexLookup[c] = (ImWchar)IM_FONTGLYPH_INDEX_UNUSED;
-    font->IndexAdvanceX[c] = font->FallbackAdvanceX;
+    IM_ASSERT(glyph >= baked->Glyphs.Data && glyph < baked->Glyphs.Data + baked->Glyphs.Size);
+    baked->IndexLookup[c] = IM_FONTGLYPH_INDEX_UNUSED;
+    baked->IndexAdvanceX[c] = baked->FallbackAdvanceX;
 }
 }
 
 
-void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font)
+void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFontBaked* baked)
 {
 {
-    for (ImFontGlyph& glyph : font->Glyphs)
+    ImGuiContext& g = *GImGui;
+    IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT()
+
+    ImFontAtlasBuilder* builder = atlas->Builder;
+    ImFont* font = baked->ContainerFont;
+    IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName());
+
+    for (ImFontGlyph& glyph : baked->Glyphs)
         if (glyph.PackId >= 0)
         if (glyph.PackId >= 0)
             ImFontAtlasPackDiscardRect(atlas, glyph.PackId);
             ImFontAtlasPackDiscardRect(atlas, glyph.PackId);
-    font->ClearOutputData();
-    font->FallbackChar = font->EllipsisChar = 0;
+
+    if (atlas->FontLoader->FontBakedDestroy)
+        atlas->FontLoader->FontBakedDestroy(atlas, baked);
+
+    builder->BakedMap.SetVoidPtr(baked->BakedId, NULL);
+    builder->BakedDiscardedCount++;
+    baked->ClearOutputData();
+    baked->WantDestroy = true;
+    font->LastBaked = NULL;
 }
 }
 
 
-// Discard old glyphs and reload font. Use if changing font size.
-void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font)
+void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, ImFont* font_filter)
 {
 {
-    ImFontAtlasBuildDiscardFontGlyphs(atlas, font);
-    for (int src_n = 0; src_n < font->SourcesCount; src_n++)
+    ImFontAtlasBuilder* builder = atlas->Builder;
+    const int GC_FRAMES = 2;
+    for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
     {
     {
-        ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n];
-        IM_ASSERT(src->SizePixels > 0.0f);
-
-        // Reload font in backend
-        if (atlas->FontLoader && atlas->FontLoader->FontSrcDestroy != NULL)
-            atlas->FontLoader->FontSrcDestroy(atlas, src);
-        if (atlas->FontLoader && atlas->FontLoader->FontSrcInit != NULL)
-            atlas->FontLoader->FontSrcInit(atlas, src);
-
-        ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything.
-        atlas->TexIsBuilt = false;
+        ImFontBaked* baked = &builder->BakedPool[baked_n];
+        if (font_filter == NULL || baked->ContainerFont == font_filter)
+            if (baked->LastUsedFrame + GC_FRAMES < atlas->Builder->FrameCount && !baked->WantDestroy)
+                ImFontAtlasBuildDiscardFontBaked(atlas, baked);
     }
     }
-
-    // Notify external systems
-    ImFontAtlasBuildNotifySetFont(atlas, font, font);
 }
 }
 
 
 // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData*
 // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData*
@@ -3747,8 +3808,8 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h)
     builder->RectsDiscardedSurface = 0;
     builder->RectsDiscardedSurface = 0;
 
 
     // Patch glyphs UV
     // Patch glyphs UV
-    for (ImFont* font : atlas->Fonts)
-        for (ImFontGlyph& glyph : font->Glyphs)
+    for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
+        for (ImFontGlyph& glyph : builder->BakedPool[baked_n].Glyphs)
             if (glyph.PackId != -1)
             if (glyph.PackId != -1)
             {
             {
                 ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId);
                 ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId);
@@ -3798,8 +3859,11 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_
 
 
 void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas)
 void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas)
 {
 {
-    // Currently using a heuristic for repack without growing.
+    // Can some baked contents be ditched?
     ImFontAtlasBuilder* builder = atlas->Builder;
     ImFontAtlasBuilder* builder = atlas->Builder;
+    ImFontAtlasBuildDiscardUnusedBakes(atlas, NULL);
+
+    // Currently using a heuristic for repack without growing.
     if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f)
     if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f)
         ImFontAtlasBuildGrowTexture(atlas);
         ImFontAtlasBuildGrowTexture(atlas);
     else
     else
@@ -3845,6 +3909,8 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas)
 void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas)
 void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas)
 {
 {
     ImFontAtlasBuilder* builder = atlas->Builder;
     ImFontAtlasBuilder* builder = atlas->Builder;
+    ImFontAtlasBuildDiscardUnusedBakes(atlas, NULL);
+
     ImTextureData* old_tex = atlas->TexData;
     ImTextureData* old_tex = atlas->TexData;
     ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height);
     ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height);
     ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas);
     ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas);
@@ -3927,7 +3993,7 @@ void ImFontAtlasPackInit(ImFontAtlas * atlas)
     ImFontAtlasBuilder* builder = atlas->Builder;
     ImFontAtlasBuilder* builder = atlas->Builder;
 
 
     // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but it doesn't seem worth it.
     // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but it doesn't seem worth it.
-    int pack_node_count = tex->Width;
+    const int pack_node_count = tex->Width;
     builder->PackNodes.resize(pack_node_count);
     builder->PackNodes.resize(pack_node_count);
     IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque));
     IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque));
     stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size);
     stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size);
@@ -4046,38 +4112,40 @@ ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id
     return &builder->Rects[index_entry->TargetIndex];
     return &builder->Rects[index_entry->TargetIndex];
 }
 }
 
 
-ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint)
+ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint)
 {
 {
-    ImFontAtlas* atlas = ContainerAtlas;
-    if (LockDisableLoading || atlas->Locked)
+    ImFont* font = ContainerFont;
+    ImFontBaked* baked = this;
+    ImFontAtlas* atlas = font->ContainerAtlas;
+    if (font->LockDisableLoading || atlas->Locked)
         return NULL;
         return NULL;
 
 
     //char utf8_buf[5];
     //char utf8_buf[5];
     //IMGUI_DEBUG_LOG("[font] BuildAddGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint));
     //IMGUI_DEBUG_LOG("[font] BuildAddGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint));
 
 
     // Load from single source or all sources?
     // Load from single source or all sources?
-    int srcs_count = (LockSingleSrcConfigIdx != -1) ? 1 : SourcesCount;
-    ImFontConfig* srcs = (LockSingleSrcConfigIdx != -1) ? &Sources[LockSingleSrcConfigIdx] : Sources;
+    int srcs_count = (font->LockSingleSrcConfigIdx != -1) ? 1 : font->SourcesCount;
+    ImFontConfig* srcs = (font->LockSingleSrcConfigIdx != -1) ? &font->Sources[font->LockSingleSrcConfigIdx] : font->Sources;
 
 
     // Call backend
     // Call backend
     const ImFontLoader* font_loader = atlas->FontLoader;
     const ImFontLoader* font_loader = atlas->FontLoader;
-    if (!font_loader->FontAddGlyph(atlas, this, srcs, srcs_count, codepoint))
+    if (!font_loader->FontBakedAddGlyph(atlas, baked, srcs, srcs_count, codepoint))
     {
     {
         // Mark index as not found, so we don't attempt the search twice
         // Mark index as not found, so we don't attempt the search twice
-        BuildGrowIndex(codepoint + 1);
-        IndexAdvanceX[codepoint] = FallbackAdvanceX;
-        IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND;
+        baked->BuildGrowIndex(codepoint + 1);
+        baked->IndexAdvanceX[codepoint] = baked->FallbackAdvanceX;
+        baked->IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND;
         return NULL;
         return NULL;
     }
     }
 
 
     // FIXME: Add hooks for e.g. #7962
     // FIXME: Add hooks for e.g. #7962
-    ImFontGlyph* glyph = &Glyphs.back();
+    ImFontGlyph* glyph = &baked->Glyphs.back();
     return glyph;
     return glyph;
 }
 }
 
 
 // The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b
 // The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b
 IM_MSVC_RUNTIME_CHECKS_OFF
 IM_MSVC_RUNTIME_CHECKS_OFF
-static float BuildLoadGlyphGetAdvanceOrFallback(ImFont* font, unsigned int codepoint)
+static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* font, unsigned int codepoint)
 {
 {
     ImFontGlyph* glyph = font->BuildLoadGlyph((ImWchar)codepoint);
     ImFontGlyph* glyph = font->BuildLoadGlyph((ImWchar)codepoint);
     return glyph ? glyph->AdvanceX : font->FallbackAdvanceX;
     return glyph ? glyph->AdvanceX : font->FallbackAdvanceX;
@@ -4124,9 +4192,7 @@ void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas)
 struct ImGui_ImplStbTrueType_FontSrcData
 struct ImGui_ImplStbTrueType_FontSrcData
 {
 {
     stbtt_fontinfo  FontInfo;
     stbtt_fontinfo  FontInfo;
-    float           ScaleForRasterX;        // Factor in RasterizationDensity * OversampleH
-    float           ScaleForRasterY;        // Factor in RasterizationDensity * OversampleV
-    float           ScaleForLayout;
+    float           ScaleFactor;
 };
 };
 
 
 static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src)
 static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src)
@@ -4152,28 +4218,10 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig*
     }
     }
     src->FontLoaderData = bd_font_data;
     src->FontLoaderData = bd_font_data;
 
 
-    // FIXME-NEWFONTS: reevaluate sizing metrics
-    int oversample_h, oversample_v;
-    ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v);
-    float scale;
     if (src->SizePixels > 0.0f)
     if (src->SizePixels > 0.0f)
-        scale = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f);
+        bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f);
     else
     else
-        scale = -stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f);
-    bd_font_data->ScaleForRasterX = scale * src->SizePixels * src->RasterizerDensity * oversample_h;
-    bd_font_data->ScaleForRasterY = scale * src->SizePixels * src->RasterizerDensity * oversample_v;
-    bd_font_data->ScaleForLayout = scale * src->SizePixels;
-
-    // FIXME-NEWFONTS: make use of line gap value
-    int unscaled_ascent, unscaled_descent, unscaled_line_gap;
-    stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
-
-    if (src->MergeMode == false)
-    {
-        ImFont* font = src->DstFont;
-        font->Ascent = ImCeil(unscaled_ascent * bd_font_data->ScaleForLayout);
-        font->Descent = ImFloor(unscaled_descent * bd_font_data->ScaleForLayout);
-    }
+        bd_font_data->ScaleFactor = -stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f);
 
 
     return true;
     return true;
 }
 }
@@ -4197,7 +4245,27 @@ static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFon
     return glyph_index != 0;
     return glyph_index != 0;
 }
 }
 
 
-static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint)
+static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* baked)
+{
+    IM_UNUSED(atlas);
+    ImFont* font = baked->ContainerFont;
+
+    for (int src_n = 0; src_n < font->SourcesCount; src_n++)
+    {
+        ImFontConfig* src = &font->Sources[src_n];
+        ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
+
+        // FIXME-NEWFONTS: reevaluate how to use sizing metrics
+        // FIXME-NEWFONTS: make use of line gap value
+        float scale_for_layout = bd_font_data->ScaleFactor * baked->Size;
+        int unscaled_ascent, unscaled_descent, unscaled_line_gap;
+        stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
+        baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout);
+        baked->Descent = ImFloor(unscaled_descent * scale_for_layout);
+    }
+}
+
+static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint)
 {
 {
     // Search for first font which has the glyph
     // Search for first font which has the glyph
     ImGui_ImplStbTrueType_FontSrcData* bd_font_data = NULL;
     ImGui_ImplStbTrueType_FontSrcData* bd_font_data = NULL;
@@ -4215,9 +4283,12 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font,
     if (glyph_index == 0)
     if (glyph_index == 0)
         return false; // Not found
         return false; // Not found
 
 
-    const float scale_for_layout = bd_font_data->ScaleForLayout;    // ~ (font units to pixels)
-    const float scale_for_raster_x = bd_font_data->ScaleForRasterX; // ~ (font units to pixels) * RasterizationDensity * OversampleH
-    const float scale_for_raster_y = bd_font_data->ScaleForRasterY; // ~ (font units to pixels) * RasterizationDensity * OversampleV
+    // Fonts unit to pixels
+    int oversample_h, oversample_v;
+    ImFontAtlasBuildGetOversampleFactors(src, baked->Size, &oversample_h, &oversample_v);
+    const float scale_for_layout = bd_font_data->ScaleFactor * baked->Size;
+    const float scale_for_raster_x = bd_font_data->ScaleFactor * baked->Size * src->RasterizerDensity * oversample_h;
+    const float scale_for_raster_y = bd_font_data->ScaleFactor * baked->Size * src->RasterizerDensity * oversample_v;
 
 
     // Obtain size and advance
     // Obtain size and advance
     int x0, y0, x1, y1;
     int x0, y0, x1, y1;
@@ -4235,8 +4306,6 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font,
     // (generally based on stbtt_PackFontRangesRenderIntoRects)
     // (generally based on stbtt_PackFontRangesRenderIntoRects)
     if (is_visible)
     if (is_visible)
     {
     {
-        int oversample_h, oversample_v;
-        ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v);
         const int w = (x1 - x0 + oversample_h - 1);
         const int w = (x1 - x0 + oversample_h - 1);
         const int h = (y1 - y0 + oversample_v - 1);
         const int h = (y1 - y0 + oversample_v - 1);
         ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
         ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
@@ -4246,9 +4315,7 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font,
             IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory.");
             IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory.");
             return false;
             return false;
         }
         }
-
         ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
         ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
-        font->MetricsTotalSurface += w * h;
 
 
         // Render
         // Render
         stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, &x1, &y1);
         stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, &x1, &y1);
@@ -4267,7 +4334,7 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font,
             stbtt__v_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_v);
             stbtt__v_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_v);
 
 
         float font_off_x = src->GlyphOffset.x + stbtt__oversample_shift(oversample_h);
         float font_off_x = src->GlyphOffset.x + stbtt__oversample_shift(oversample_h);
-        float font_off_y = src->GlyphOffset.y + stbtt__oversample_shift(oversample_v) + IM_ROUND(font->Ascent);
+        float font_off_y = src->GlyphOffset.y + stbtt__oversample_shift(oversample_v) + IM_ROUND(baked->Ascent);
         float recip_h = 1.0f / (oversample_h * src->RasterizerDensity);
         float recip_h = 1.0f / (oversample_h * src->RasterizerDensity);
         float recip_v = 1.0f / (oversample_v * src->RasterizerDensity);
         float recip_v = 1.0f / (oversample_v * src->RasterizerDensity);
 
 
@@ -4280,19 +4347,19 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font,
         glyph.Y1 = (y0 + (int)r->h) * recip_v + font_off_y;
         glyph.Y1 = (y0 + (int)r->h) * recip_v + font_off_y;
         glyph.Visible = true;
         glyph.Visible = true;
         glyph.PackId = pack_id;
         glyph.PackId = pack_id;
-        ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph);
+        ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph);
 
 
         // Copy to texture, post-process and queue update for backend
         // Copy to texture, post-process and queue update for backend
         ImTextureData* tex = atlas->TexData;
         ImTextureData* tex = atlas->TexData;
         IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height);
         IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height);
         ImFontAtlasTextureBlockConvert(bitmap_pixels, ImTextureFormat_Alpha8, w, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h);
         ImFontAtlasTextureBlockConvert(bitmap_pixels, ImTextureFormat_Alpha8, w, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h);
-        ImFontAtlasPostProcessData pp_data = { atlas, font, src, &font->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h };
+        ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, &baked->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h };
         ImFontAtlasTextureBlockPostProcess(&pp_data);
         ImFontAtlasTextureBlockPostProcess(&pp_data);
         ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
         ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
     }
     }
     else
     else
     {
     {
-        ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph);
+        ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph);
     }
     }
 
 
     return true;
     return true;
@@ -4305,7 +4372,9 @@ const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype()
     loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit;
     loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit;
     loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy;
     loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy;
     loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph;
     loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph;
-    loader.FontAddGlyph = ImGui_ImplStbTrueType_FontAddGlyph;
+    loader.FontBakedInit = ImGui_ImplStbTrueType_FontBakedInit;
+    loader.FontBakedDestroy = NULL;
+    loader.FontBakedAddGlyph = ImGui_ImplStbTrueType_FontBakedAddGlyph;
     return &loader;
     return &loader;
 }
 }
 
 
@@ -4628,6 +4697,34 @@ void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
 // [SECTION] ImFont
 // [SECTION] ImFont
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
+ImFontBaked::ImFontBaked()
+{
+    memset(this, 0, sizeof(*this));
+    FallbackGlyphIndex = -1;
+}
+
+void ImFontBaked::ClearOutputData()
+{
+    FallbackAdvanceX = 0.0f;
+    Glyphs.clear();
+    IndexAdvanceX.clear();
+    IndexLookup.clear();
+    FallbackGlyphIndex = -1;
+    Ascent = Descent = 0.0f;
+    MetricsTotalSurface = 0;
+}
+
+void ImFontBaked::BuildGrowIndex(int new_size)
+{
+    IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
+    if (new_size <= IndexLookup.Size)
+        return;
+    //ImGuiContext& g = *GImGui;
+    //IMGUI_DEBUG_LOG_FONT("[font] BuildGrowIndex(%d)\n", new_size);
+    IndexAdvanceX.resize(new_size, -1.0f);
+    IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED);
+}
+
 ImFont::ImFont()
 ImFont::ImFont()
 {
 {
     memset(this, 0, sizeof(*this));
     memset(this, 0, sizeof(*this));
@@ -4642,14 +4739,17 @@ ImFont::~ImFont()
 
 
 void ImFont::ClearOutputData()
 void ImFont::ClearOutputData()
 {
 {
-    FallbackAdvanceX = 0.0f;
-    Glyphs.clear();
-    IndexAdvanceX.clear();
-    IndexLookup.clear();
-    FallbackGlyphIndex = -1;
-    Ascent = Descent = 0.0f;
-    MetricsTotalSurface = 0;
+    if (ImFontAtlas* atlas = ContainerAtlas)
+        if (ImFontAtlasBuilder* builder = atlas->Builder)
+            for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++)
+            {
+                ImFontBaked* baked = &builder->BakedPool[baked_n];
+                if (baked->ContainerFont == this)
+                    ImFontAtlasBuildDiscardFontBaked(atlas, baked);
+            }
+    FallbackChar = EllipsisChar = 0;
     memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
     memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap));
+    LastBaked = NULL;
 }
 }
 
 
 // API is designed this way to avoid exposing the 8K page size
 // API is designed this way to avoid exposing the 8K page size
@@ -4665,24 +4765,15 @@ bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
     return true;
     return true;
 }
 }
 
 
-void ImFont::BuildGrowIndex(int new_size)
-{
-    IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
-    if (new_size <= IndexLookup.Size)
-        return;
-    IndexAdvanceX.resize(new_size, -1.0f);
-    IndexLookup.resize(new_size, (ImU16)-1);
-}
-
 // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
 // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
 // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis).
 // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis).
 // 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font.
 // 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font.
-ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, const ImFontGlyph* in_glyph)
+ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph)
 {
 {
-    int glyph_idx = font->Glyphs.Size;
-    font->Glyphs.push_back(*in_glyph);
-    ImFontGlyph& glyph = font->Glyphs[glyph_idx];
-    IM_ASSERT(font->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved.
+    int glyph_idx = baked->Glyphs.Size;
+    baked->Glyphs.push_back(*in_glyph);
+    ImFontGlyph& glyph = baked->Glyphs[glyph_idx];
+    IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved.
 
 
     // Set UV from packed rectangle
     // Set UV from packed rectangle
     if (in_glyph->PackId >= 0)
     if (in_glyph->PackId >= 0)
@@ -4693,6 +4784,7 @@ ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFo
         glyph.V0 = (r->y) * atlas->TexUvScale.y;
         glyph.V0 = (r->y) * atlas->TexUvScale.y;
         glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x;
         glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x;
         glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y;
         glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y;
+        baked->MetricsTotalSurface += r->w * r->h;
     }
     }
 
 
     if (src != NULL)
     if (src != NULL)
@@ -4718,17 +4810,22 @@ ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFo
 
 
     // Update lookup tables
     // Update lookup tables
     int codepoint = glyph.Codepoint;
     int codepoint = glyph.Codepoint;
-    font->BuildGrowIndex(codepoint + 1);
-    font->IndexAdvanceX[codepoint] = glyph.AdvanceX;
-    font->IndexLookup[codepoint] = (ImU16)glyph_idx;
+    baked->BuildGrowIndex(codepoint + 1);
+    baked->IndexAdvanceX[codepoint] = glyph.AdvanceX;
+    baked->IndexLookup[codepoint] = (ImU16)glyph_idx;
     const int page_n = codepoint / 8192;
     const int page_n = codepoint / 8192;
-    font->Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
+    baked->ContainerFont->Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
 
 
     return &glyph;
     return &glyph;
 }
 }
 
 
 void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst)
 void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst)
 {
 {
+    // FIXME-BAKED: Implement AddRemapChar()
+    IM_UNUSED(from_codepoint);
+    IM_UNUSED(to_codepoint);
+    IM_UNUSED(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.
     IM_ASSERT(IndexLookup.Size > 0);    // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
     unsigned int index_size = (unsigned int)IndexLookup.Size;
     unsigned int index_size = (unsigned int)IndexLookup.Size;
 
 
@@ -4740,10 +4837,11 @@ void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool ove
     BuildGrowIndex(from_codepoint + 1);
     BuildGrowIndex(from_codepoint + 1);
     IndexLookup[from_codepoint] = (to_codepoint < index_size) ? IndexLookup.Data[to_codepoint] : (ImU16)-1;
     IndexLookup[from_codepoint] = (to_codepoint < index_size) ? IndexLookup.Data[to_codepoint] : (ImU16)-1;
     IndexAdvanceX[from_codepoint] = (to_codepoint < index_size) ? IndexAdvanceX.Data[to_codepoint] : 1.0f;
     IndexAdvanceX[from_codepoint] = (to_codepoint < index_size) ? IndexAdvanceX.Data[to_codepoint] : 1.0f;
+    */
 }
 }
 
 
 // Find glyph, load if necessary, return fallback if missing
 // Find glyph, load if necessary, return fallback if missing
-ImFontGlyph* ImFont::FindGlyph(ImWchar c)
+ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c)
 {
 {
     if (c < (size_t)IndexLookup.Size) IM_LIKELY
     if (c < (size_t)IndexLookup.Size) IM_LIKELY
     {
     {
@@ -4758,7 +4856,7 @@ ImFontGlyph* ImFont::FindGlyph(ImWchar c)
 }
 }
 
 
 // Attempt to load but when missing, return NULL instead of FallbackGlyph
 // Attempt to load but when missing, return NULL instead of FallbackGlyph
-ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c)
+ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c)
 {
 {
     if (c < (size_t)IndexLookup.Size) IM_LIKELY
     if (c < (size_t)IndexLookup.Size) IM_LIKELY
     {
     {
@@ -4768,11 +4866,10 @@ ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c)
         if (i != IM_FONTGLYPH_INDEX_UNUSED)
         if (i != IM_FONTGLYPH_INDEX_UNUSED)
             return &Glyphs.Data[i];
             return &Glyphs.Data[i];
     }
     }
-    ImFontGlyph* glyph = BuildLoadGlyph(c);
-    return glyph;
+    return BuildLoadGlyph(c);
 }
 }
 
 
-bool ImFont::IsGlyphLoaded(ImWchar c)
+bool ImFontBaked::IsGlyphLoaded(ImWchar c)
 {
 {
     if (c < (size_t)IndexLookup.Size) IM_LIKELY
     if (c < (size_t)IndexLookup.Size) IM_LIKELY
     {
     {
@@ -4797,7 +4894,7 @@ bool ImFont::IsGlyphInFont(ImWchar c)
 
 
 // This is manually inlined in CalcTextSizeA() and CalcWordWrapPosition(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback().
 // This is manually inlined in CalcTextSizeA() and CalcWordWrapPosition(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback().
 IM_MSVC_RUNTIME_CHECKS_OFF
 IM_MSVC_RUNTIME_CHECKS_OFF
-float ImFont::GetCharAdvance(ImWchar c)
+float ImFontBaked::GetCharAdvance(ImWchar c)
 {
 {
     if ((int)c < IndexAdvanceX.Size)
     if ((int)c < IndexAdvanceX.Size)
     {
     {
@@ -4813,6 +4910,46 @@ float ImFont::GetCharAdvance(ImWchar c)
 }
 }
 IM_MSVC_RUNTIME_CHECKS_RESTORE
 IM_MSVC_RUNTIME_CHECKS_RESTORE
 
 
+// ImFontBaked pointers are valid for the entire frame but shall never be kept between frames.
+ImFontBaked* ImFont::GetFontBaked(float size)
+{
+    ImFontBaked* baked = LastBaked;
+    if (baked && baked->Size == size)
+        return baked;
+
+    ImFontAtlas* atlas = ContainerAtlas;
+    ImFontAtlasBuilder* builder = atlas->Builder;
+
+    ImGuiID baked_id = ImFontAtlasBakedGetId(FontId, size);
+    ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id);
+    baked = *p_baked_in_map;
+    if (baked != NULL)
+    {
+        // FIXME-BAKED: Design for picking a nearest size?
+        IM_ASSERT(baked->Size == size && baked->ContainerFont == this && baked->BakedId == baked_id);
+        baked->LastUsedFrame = builder->FrameCount;
+        LastBaked = baked;
+        return baked;
+    }
+
+    // Create new
+    ImGuiContext& g = *GImGui;
+    IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT()
+    IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", size);
+    baked = builder->BakedPool.push_back(ImFontBaked());
+    baked->Size = size;
+    baked->BakedId = baked_id;
+    baked->ContainerFont = this;
+    baked->LastUsedFrame = ContainerAtlas->Builder->FrameCount;
+    LastBaked = baked;
+    *p_baked_in_map = baked; // To avoid 'builder->BakedMap.SetVoidPtr(baked_id, baked);' while we can.
+    if (atlas->FontLoader->FontBakedInit)
+        atlas->FontLoader->FontBakedInit(atlas, baked);
+    ImFontAtlasBuildSetupFontBakedSpecialGlyphs(atlas, baked->ContainerFont, baked);
+
+    return baked;
+}
+
 // Trim trailing space and find beginning of next line
 // Trim trailing space and find beginning of next line
 static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end)
 static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end)
 {
 {
@@ -4839,10 +4976,13 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha
 
 
     // Cut words that cannot possibly fit within one line.
     // Cut words that cannot possibly fit within one line.
     // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
     // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
+
+    ImFontBaked* baked = GetFontBaked(size);
+    const float scale = size / baked->Size;
+
     float line_width = 0.0f;
     float line_width = 0.0f;
     float word_width = 0.0f;
     float word_width = 0.0f;
     float blank_width = 0.0f;
     float blank_width = 0.0f;
-    const float scale = size / FontSize;
     wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
     wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
 
 
     const char* word_end = text;
     const char* word_end = text;
@@ -4877,9 +5017,9 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha
         }
         }
 
 
         // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);'
         // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);'
-        float char_width = (c < (unsigned int)IndexAdvanceX.Size) ? IndexAdvanceX.Data[c] : -1.0f;
+        float char_width = (c < (unsigned int)baked->IndexAdvanceX.Size) ? baked->IndexAdvanceX.Data[c] : -1.0f;
         if (char_width < 0.0f)
         if (char_width < 0.0f)
-            char_width = BuildLoadGlyphGetAdvanceOrFallback(this, c);
+            char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c);
 
 
         if (ImCharIsBlankW(c))
         if (ImCharIsBlankW(c))
         {
         {
@@ -4935,7 +5075,8 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
         text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this.
         text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this.
 
 
     const float line_height = size;
     const float line_height = size;
-    const float scale = size / FontSize;
+    ImFontBaked* baked = GetFontBaked(size);
+    const float scale = size / baked->Size;
 
 
     ImVec2 text_size = ImVec2(0, 0);
     ImVec2 text_size = ImVec2(0, 0);
     float line_width = 0.0f;
     float line_width = 0.0f;
@@ -4986,9 +5127,9 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
         }
         }
 
 
         // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);'
         // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);'
-        float char_width = (c < (unsigned int)IndexAdvanceX.Size) ? IndexAdvanceX.Data[c] : -1.0f;
+        float char_width = (c < (unsigned int)baked->IndexAdvanceX.Size) ? baked->IndexAdvanceX.Data[c] : -1.0f;
         if (char_width < 0.0f)
         if (char_width < 0.0f)
-            char_width = BuildLoadGlyphGetAdvanceOrFallback(this, c);
+            char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c);
         char_width *= scale;
         char_width *= scale;
 
 
         if (line_width + char_width >= max_width)
         if (line_width + char_width >= max_width)
@@ -5015,12 +5156,13 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
 // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
 // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound.
 void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip)
 void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip)
 {
 {
-    const ImFontGlyph* glyph = FindGlyph(c);
+    ImFontBaked* baked = GetFontBaked(size);
+    const ImFontGlyph* glyph = baked->FindGlyph(c);
     if (!glyph || !glyph->Visible)
     if (!glyph || !glyph->Visible)
         return;
         return;
     if (glyph->Colored)
     if (glyph->Colored)
         col |= ~IM_COL32_A_MASK;
         col |= ~IM_COL32_A_MASK;
-    float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
+    float scale = (size >= 0.0f) ? (size / baked->Size) : 1.0f;
     float x = IM_TRUNC(pos.x);
     float x = IM_TRUNC(pos.x);
     float y = IM_TRUNC(pos.y);
     float y = IM_TRUNC(pos.y);
 
 
@@ -5062,8 +5204,10 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
     if (!text_end)
     if (!text_end)
         text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
         text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
 
 
-    const float scale = size / FontSize;
-    const float line_height = FontSize * scale;
+    const float line_height = size;
+    ImFontBaked* baked = GetFontBaked(size);
+
+    const float scale = size / baked->Size;
     const float origin_x = x;
     const float origin_x = x;
     const bool word_wrap_enabled = (wrap_width > 0.0f);
     const bool word_wrap_enabled = (wrap_width > 0.0f);
 
 
@@ -5158,7 +5302,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
                 continue;
                 continue;
         }
         }
 
 
-        const ImFontGlyph* glyph = FindGlyph((ImWchar)c);
+        const ImFontGlyph* glyph = baked->FindGlyph((ImWchar)c);
         if (glyph == NULL)
         if (glyph == NULL)
             continue;
             continue;
 
 

+ 26 - 13
imgui_internal.h

@@ -2130,11 +2130,12 @@ struct ImGuiContext
     ImGuiIO                 IO;
     ImGuiIO                 IO;
     ImGuiPlatformIO         PlatformIO;
     ImGuiPlatformIO         PlatformIO;
     ImGuiStyle              Style;
     ImGuiStyle              Style;
-    ImFont*                 Font;                               // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()
-    float                   FontSize;                           // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
-    float                   FontBaseSize;                       // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
-    float                   FontScale;                          // == FontSize / Font->FontSize
-    float                   CurrentDpiScale;                    // Current window/viewport DpiScale
+    ImFont*                 Font;                               // == FontStack.back().Font
+    ImFontBaked*            FontBaked;                          // == Font->GetFontBaked(FontSize)
+    float                   FontSize;                           // == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
+    //float                 FontBaseSize;                       // == io.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
+    float                   FontScale;                          // == FontBaked->Size / Font->FontSize. Scale factor over baked size.
+    float                   CurrentDpiScale;                    // Current window/viewport DpiScale == CurrentViewport->DpiScale
     ImDrawListSharedData    DrawListSharedData;
     ImDrawListSharedData    DrawListSharedData;
     ImVector<ImTextureData*>Textures;
     ImVector<ImTextureData*>Textures;
     double                  Time;
     double                  Time;
@@ -2673,7 +2674,7 @@ public:
 
 
     // We don't use g.FontSize because the window may be != g.CurrentWindow.
     // We don't use g.FontSize because the window may be != g.CurrentWindow.
     ImRect      Rect() const            { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
     ImRect      Rect() const            { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
-    float       CalcFontSize() const    { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; }
+    //float     CalcFontSize() const    { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; }
     ImRect      TitleBarRect() const    { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight)); }
     ImRect      TitleBarRect() const    { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight)); }
     ImRect      MenuBarRect() const     { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); }
     ImRect      MenuBarRect() const     { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); }
 };
 };
@@ -3098,7 +3099,7 @@ namespace ImGui
     IMGUI_API void          SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags);
     IMGUI_API void          SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags);
 
 
     // Fonts, drawing
     // Fonts, drawing
-    IMGUI_API void          SetCurrentFont(ImFont* font);
+    IMGUI_API void          SetCurrentFont(ImFont* font, float font_size);
     inline ImFont*          GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
     inline ImFont*          GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
     IMGUI_API void          PushPasswordFont();
     IMGUI_API void          PushPasswordFont();
     inline ImDrawList*      GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches.
     inline ImDrawList*      GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches.
@@ -3661,7 +3662,9 @@ struct ImFontLoader
     bool            (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src);
     bool            (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src);
     void            (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src);
     void            (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src);
     bool            (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint);
     bool            (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint);
-    bool            (*FontAddGlyph)(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint);
+    void            (*FontBakedInit)(ImFontAtlas* atlas, ImFontBaked* baked);
+    void            (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontBaked* baked);
+    bool            (*FontBakedAddGlyph)(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint);
 
 
     ImFontLoader()  { memset(this, 0, sizeof(*this)); }
     ImFontLoader()  { memset(this, 0, sizeof(*this)); }
 };
 };
@@ -3698,6 +3701,7 @@ struct ImFontAtlasPostProcessData
     ImFontAtlas*        FontAtlas;
     ImFontAtlas*        FontAtlas;
     ImFont*             Font;
     ImFont*             Font;
     ImFontConfig*       FontSrc;
     ImFontConfig*       FontSrc;
+    ImFontBaked*        FontBaked;
     ImFontGlyph*        Glyph;
     ImFontGlyph*        Glyph;
 
 
     // Pixel data
     // Pixel data
@@ -3723,11 +3727,17 @@ struct ImFontAtlasBuilder
     int                         RectsPackedSurface;     // Number of packed pixels. Used when compacting to heuristically find the ideal texture size.
     int                         RectsPackedSurface;     // Number of packed pixels. Used when compacting to heuristically find the ideal texture size.
     int                         RectsDiscardedCount;
     int                         RectsDiscardedCount;
     int                         RectsDiscardedSurface;
     int                         RectsDiscardedSurface;
+    int                         FrameCount;             // Current frame count
     ImVec2i                     MaxRectSize;            // Largest rectangle to pack (de-facto used as a "minimum texture size")
     ImVec2i                     MaxRectSize;            // Largest rectangle to pack (de-facto used as a "minimum texture size")
     ImVec2i                     MaxRectBounds;          // Bottom-right most used pixels
     ImVec2i                     MaxRectBounds;          // Bottom-right most used pixels
     bool                        LockDisableResize;      // Disable resizing texture
     bool                        LockDisableResize;      // Disable resizing texture
     bool                        PreloadedAllGlyphsRanges; // Set when missing ImGuiBackendFlags_RendererHasTextures features forces atlas to preload everything.
     bool                        PreloadedAllGlyphsRanges; // Set when missing ImGuiBackendFlags_RendererHasTextures features forces atlas to preload everything.
 
 
+    // Cache of all ImFontBaked
+    ImStableVector<ImFontBaked,32> BakedPool;
+    ImGuiStorage                BakedMap;
+    int                         BakedDiscardedCount;
+
     // Custom rectangle identifiers
     // Custom rectangle identifiers
     ImFontAtlasRectId           PackIdMouseCursors;     // White pixel + mouse cursors. Also happen to be fallback in case of packing failure.
     ImFontAtlasRectId           PackIdMouseCursors;     // White pixel + mouse cursors. Also happen to be fallback in case of packing failure.
     ImFontAtlasRectId           PackIdLinesTexData;
     ImFontAtlasRectId           PackIdLinesTexData;
@@ -3750,20 +3760,23 @@ IMGUI_API void              ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas);
 IMGUI_API ImVec2i           ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas);
 IMGUI_API ImVec2i           ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas);
 
 
 IMGUI_API bool              ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src);
 IMGUI_API bool              ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src);
-IMGUI_API ImFontGlyph*      ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, const ImFontGlyph* in_glyph);
 IMGUI_API void              ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src);
 IMGUI_API void              ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src);
-IMGUI_API void              ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGlyph* glyph);
-IMGUI_API void              ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font);
+IMGUI_API void              ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, ImFont* font_filter);
+IMGUI_API void              ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked);
+IMGUI_API void              ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph);
 IMGUI_API void              ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); // <--- Your future new best friend!
 IMGUI_API void              ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); // <--- Your future new best friend!
 IMGUI_API void              ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy
 IMGUI_API void              ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy
-IMGUI_API void              ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v);
+IMGUI_API void              ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v);
+
+IMGUI_API ImFontGlyph*      ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph);
+IMGUI_API ImGuiID           ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size);
 
 
 IMGUI_API void              ImFontAtlasPackInit(ImFontAtlas* atlas);
 IMGUI_API void              ImFontAtlasPackInit(ImFontAtlas* atlas);
 IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL);
 IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL);
 IMGUI_API ImFontAtlasRect*  ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id);
 IMGUI_API ImFontAtlasRect*  ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id);
 IMGUI_API void              ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id);
 IMGUI_API void              ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id);
 
 
-IMGUI_API void              ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas);
+IMGUI_API void              ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count);
 IMGUI_API void              ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data);
 IMGUI_API void              ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data);
 IMGUI_API void              ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data);
 IMGUI_API void              ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data);
 IMGUI_API void              ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex);
 IMGUI_API void              ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex);

+ 1 - 1
imgui_tables.cpp

@@ -3375,7 +3375,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label
     ButtonBehavior(row_r, row_id, NULL, NULL);
     ButtonBehavior(row_r, row_id, NULL, NULL);
     KeepAliveID(row_id);
     KeepAliveID(row_id);
 
 
-    const float ascent_scaled = g.Font->Ascent * g.FontScale; // FIXME: Standardize those scaling factors better
+    const float ascent_scaled = g.FontBaked->Ascent * g.FontScale; // FIXME: Standardize those scaling factors better
     const float line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5f, 0.0f) / -sin_a) * (flip_label ? -1.0f : 1.0f);
     const float line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5f, 0.0f) / -sin_a) * (flip_label ? -1.0f : 1.0f);
     const ImVec2 padding = g.Style.CellPadding; // We will always use swapped component
     const ImVec2 padding = g.Style.CellPadding; // We will always use swapped component
     const ImVec2 align = g.Style.TableAngledHeadersTextAlign;
     const ImVec2 align = g.Style.TableAngledHeadersTextAlign;

+ 18 - 15
imgui_widgets.cpp

@@ -1518,7 +1518,7 @@ bool ImGui::TextLink(const char* label)
         ColorConvertHSVtoRGB(h, s, v, line_colf.x, line_colf.y, line_colf.z);
         ColorConvertHSVtoRGB(h, s, v, line_colf.x, line_colf.y, line_colf.z);
     }
     }
 
 
-    float line_y = bb.Max.y + ImFloor(g.Font->Descent * g.FontScale * 0.20f);
+    float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontScale * 0.20f);
     window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI
     window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI
 
 
     PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf));
     PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf));
@@ -3956,9 +3956,10 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char**
 static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining, ImVec2* out_offset, bool stop_on_new_line)
 static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining, ImVec2* out_offset, bool stop_on_new_line)
 {
 {
     ImGuiContext& g = *ctx;
     ImGuiContext& g = *ctx;
-    ImFont* font = g.Font;
+    //ImFont* font = g.Font;
+    ImFontBaked* baked = g.FontBaked;
     const float line_height = g.FontSize;
     const float line_height = g.FontSize;
-    const float scale = line_height / font->FontSize;
+    const float scale = line_height / baked->Size;
 
 
     ImVec2 text_size = ImVec2(0, 0);
     ImVec2 text_size = ImVec2(0, 0);
     float line_width = 0.0f;
     float line_width = 0.0f;
@@ -3984,7 +3985,7 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c
         if (c == '\r')
         if (c == '\r')
             continue;
             continue;
 
 
-        line_width += font->GetCharAdvance((ImWchar)c) * scale;
+        line_width += baked->GetCharAdvance((ImWchar)c) * scale;
     }
     }
 
 
     if (text_size.x < line_width)
     if (text_size.x < line_width)
@@ -4011,7 +4012,7 @@ namespace ImStb
 {
 {
 static int     STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj)                             { return obj->TextLen; }
 static int     STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj)                             { return obj->TextLen; }
 static char    STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx)                      { IM_ASSERT(idx <= obj->TextLen); return obj->TextSrc[idx]; }
 static char    STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx)                      { IM_ASSERT(idx <= obj->TextLen); return obj->TextSrc[idx]; }
-static float   STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx)  { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; }
+static float   STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx)  { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.FontBaked->GetCharAdvance((ImWchar)c) * g.FontScale; }
 static char    STB_TEXTEDIT_NEWLINE = '\n';
 static char    STB_TEXTEDIT_NEWLINE = '\n';
 static void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx)
 static void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx)
 {
 {
@@ -4314,19 +4315,21 @@ void ImGui::PushPasswordFont()
 {
 {
     ImGuiContext& g = *GImGui;
     ImGuiContext& g = *GImGui;
     ImFont* in_font = g.Font;
     ImFont* in_font = g.Font;
+    ImFontBaked* in_baked = g.FontBaked;
+    ImFontGlyph glyph = *in_baked->FindGlyph('*');
+    glyph.PackId = -1;
     ImFont* out_font = &g.InputTextPasswordFont;
     ImFont* out_font = &g.InputTextPasswordFont;
-    ImFontGlyph* glyph = in_font->FindGlyph('*');
-    out_font->FontSize = in_font->FontSize;
     out_font->Scale = in_font->Scale;
     out_font->Scale = in_font->Scale;
-    out_font->Ascent = in_font->Ascent;
-    out_font->Descent = in_font->Descent;
     out_font->ContainerAtlas = in_font->ContainerAtlas;
     out_font->ContainerAtlas = in_font->ContainerAtlas;
-    out_font->Glyphs.resize(0);
-    out_font->Glyphs.push_back(*glyph);
-    out_font->FallbackGlyphIndex = 0;
-    out_font->FallbackAdvanceX = glyph->AdvanceX;
     out_font->LockDisableLoading = true;
     out_font->LockDisableLoading = true;
-    IM_ASSERT(out_font->Glyphs.Size == 1 && out_font->IndexAdvanceX.Size == 0 && out_font->IndexLookup.Size == 0);
+    ImFontBaked* out_baked = out_font->GetFontBaked(in_baked->Size);
+    IM_ASSERT(out_baked->Glyphs.Size <= 1 && out_baked->IndexAdvanceX.Size == 0 && out_baked->IndexLookup.Size == 0);
+    out_baked->Ascent = in_baked->Ascent;
+    out_baked->Descent = in_baked->Descent;
+    out_baked->Glyphs.resize(0);
+    out_baked->Glyphs.push_back(glyph);
+    out_baked->FallbackGlyphIndex = 0;
+    out_baked->FallbackAdvanceX = glyph.AdvanceX;
     PushFont(out_font);
     PushFont(out_font);
 }
 }
 
 
@@ -5354,7 +5357,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
                 else
                 else
                 {
                 {
                     ImVec2 rect_size = InputTextCalcTextSize(&g, p, text_selected_end, &p, NULL, true);
                     ImVec2 rect_size = InputTextCalcTextSize(&g, p, text_selected_end, &p, NULL, true);
-                    if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
+                    if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(g.FontBaked->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
                     ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn));
                     ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn));
                     rect.ClipWith(clip_rect);
                     rect.ClipWith(clip_rect);
                     if (rect.Overlaps(clip_rect))
                     if (rect.Overlaps(clip_rect))

+ 84 - 47
misc/freetype/imgui_freetype.cpp

@@ -46,6 +46,7 @@
 #include FT_FREETYPE_H          // <freetype/freetype.h>
 #include FT_FREETYPE_H          // <freetype/freetype.h>
 #include FT_MODULE_H            // <freetype/ftmodapi.h>
 #include FT_MODULE_H            // <freetype/ftmodapi.h>
 #include FT_GLYPH_H             // <freetype/ftglyph.h>
 #include FT_GLYPH_H             // <freetype/ftglyph.h>
+#include FT_SIZES_H             // <freetype/ftsizes.h>
 #include FT_SYNTHESIS_H         // <freetype/ftsynth.h>
 #include FT_SYNTHESIS_H         // <freetype/ftsynth.h>
 
 
 // Handle LunaSVG and PlutoSVG
 // Handle LunaSVG and PlutoSVG
@@ -150,15 +151,19 @@ namespace
         ImGui_ImplFreeType_Data()       { memset((void*)this, 0, sizeof(*this)); }
         ImGui_ImplFreeType_Data()       { memset((void*)this, 0, sizeof(*this)); }
     };
     };
 
 
-    // Font parameters and metrics.
-    struct ImGui_ImplFreeType_FontInfo
+    // Stored in ImFontBaked::FontBackendData: pointer to SourcesCount instances of this.
+    struct ImGui_ImplFreeType_FontSrcBakedData
     {
     {
-        float       PixelHeight;        // Size this font was generated with.
+        FT_Size     FtSize;             // This represent a FT_Face with a given size.
+
+        // Metrics
         float       Ascender;           // The pixel extents above the baseline in pixels (typically positive).
         float       Ascender;           // The pixel extents above the baseline in pixels (typically positive).
         float       Descender;          // The extents below the baseline in pixels (typically negative).
         float       Descender;          // The extents below the baseline in pixels (typically negative).
         float       LineSpacing;        // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate.
         float       LineSpacing;        // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate.
         float       LineGap;            // The spacing in pixels between one row's descent and the next row's ascent.
         float       LineGap;            // The spacing in pixels between one row's descent and the next row's ascent.
         float       MaxAdvanceWidth;    // This field gives the maximum horizontal cursor advance for all glyphs in the font.
         float       MaxAdvanceWidth;    // This field gives the maximum horizontal cursor advance for all glyphs in the font.
+
+        ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); }
     };
     };
 
 
     // Stored in ImFontConfig::FontLoaderData
     // Stored in ImFontConfig::FontLoaderData
@@ -166,20 +171,19 @@ namespace
     {
     {
         bool                            InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
         bool                            InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
         void                            CloseFont();
         void                            CloseFont();
-        void                            SetPixelHeight(float pixel_height); // Change font pixel size.
         const FT_Glyph_Metrics*         LoadGlyph(uint32_t in_codepoint);
         const FT_Glyph_Metrics*         LoadGlyph(uint32_t in_codepoint);
         void                            BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch);
         void                            BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch);
         ImGui_ImplFreeType_FontSrcData()   { memset((void*)this, 0, sizeof(*this)); }
         ImGui_ImplFreeType_FontSrcData()   { memset((void*)this, 0, sizeof(*this)); }
         ~ImGui_ImplFreeType_FontSrcData()  { CloseFont(); }
         ~ImGui_ImplFreeType_FontSrcData()  { CloseFont(); }
 
 
         // Members
         // Members
-        ImGui_ImplFreeType_FontInfo     Info;               // Font descriptor of the current font.
         FT_Face                         FtFace;
         FT_Face                         FtFace;
         unsigned int                    UserFlags;          // = ImFontConfig::RasterizerFlags
         unsigned int                    UserFlags;          // = ImFontConfig::RasterizerFlags
         FT_Int32                        LoadFlags;
         FT_Int32                        LoadFlags;
         FT_Render_Mode                  RenderMode;
         FT_Render_Mode                  RenderMode;
         float                           RasterizationDensity;
         float                           RasterizationDensity;
         float                           InvRasterizationDensity;
         float                           InvRasterizationDensity;
+        ImFontBaked*                    BakedLastActivated;
     };
     };
 
 
     bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_font_builder_flags)
     bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_font_builder_flags)
@@ -222,9 +226,6 @@ namespace
         RasterizationDensity = src->RasterizerDensity;
         RasterizationDensity = src->RasterizerDensity;
         InvRasterizationDensity = 1.0f / RasterizationDensity;
         InvRasterizationDensity = 1.0f / RasterizationDensity;
 
 
-        memset(&Info, 0, sizeof(Info));
-        SetPixelHeight(src->SizePixels);
-
         return true;
         return true;
     }
     }
 
 
@@ -237,31 +238,6 @@ namespace
         }
         }
     }
     }
 
 
-    void ImGui_ImplFreeType_FontSrcData::SetPixelHeight(float pixel_height)
-    {
-        // Vuhdo (2017): "I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
-        // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
-        // FT_Set_Pixel_Sizes() doesn't seem to get us the same result."
-        // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL)
-        FT_Size_RequestRec req;
-        req.type = (UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM;
-        req.width = 0;
-        req.height = (uint32_t)(pixel_height * 64 * RasterizationDensity);
-        req.horiResolution = 0;
-        req.vertResolution = 0;
-        FT_Request_Size(FtFace, &req);
-        // Note: To handle multiple sizes later, we may need to use FT_New_Size(), FT_Activate_Size()
-
-        // Update font info
-        FT_Size_Metrics metrics = FtFace->size->metrics;
-        Info.PixelHeight = pixel_height * InvRasterizationDensity;
-        Info.Ascender = (float)FT_CEIL(metrics.ascender) * InvRasterizationDensity;
-        Info.Descender = (float)FT_CEIL(metrics.descender) * InvRasterizationDensity;
-        Info.LineSpacing = (float)FT_CEIL(metrics.height) * InvRasterizationDensity;
-        Info.LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * InvRasterizationDensity;
-        Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * InvRasterizationDensity;
-    }
-
     const FT_Glyph_Metrics* ImGui_ImplFreeType_FontSrcData::LoadGlyph(uint32_t codepoint)
     const FT_Glyph_Metrics* ImGui_ImplFreeType_FontSrcData::LoadGlyph(uint32_t codepoint)
     {
     {
         uint32_t glyph_index = FT_Get_Char_Index(FtFace, codepoint);
         uint32_t glyph_index = FT_Get_Char_Index(FtFace, codepoint);
@@ -447,12 +423,6 @@ bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src)
     if (!bd_font_data->InitFont(bd->Library, src, atlas->FontBuilderFlags))
     if (!bd_font_data->InitFont(bd->Library, src, atlas->FontBuilderFlags))
         return false;
         return false;
 
 
-    if (src->MergeMode == false)
-    {
-        ImFont* font = src->DstFont;
-        font->Ascent = bd_font_data->Info.Ascender;
-        font->Descent = bd_font_data->Info.Descender;
-    }
     return true;
     return true;
 }
 }
 
 
@@ -464,7 +434,65 @@ void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src)
     src->FontLoaderData = NULL;
     src->FontLoaderData = NULL;
 }
 }
 
 
-bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint)
+void ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* baked)
+{
+    IM_UNUSED(atlas);
+    ImFont* font = baked->ContainerFont;
+    const float size = baked->Size;
+
+    IM_ASSERT(baked->FontBackendData == NULL);
+    ImGui_ImplFreeType_FontSrcBakedData* bd_baked_datas = (ImGui_ImplFreeType_FontSrcBakedData*)IM_ALLOC(sizeof(ImGui_ImplFreeType_FontSrcBakedData) * font->SourcesCount);
+    baked->FontBackendData = bd_baked_datas;
+
+    for (int src_n = 0; src_n < font->SourcesCount; src_n++)
+    {
+        ImFontConfig* src = &font->Sources[src_n];
+        ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontBackendData;
+        bd_font_data->BakedLastActivated = baked;
+
+        // We need one FT_Size per source, so create one ImGui_ImplFreeType_FontBakedData for each source.
+        ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = &bd_baked_datas[src_n];
+        FT_New_Size(bd_font_data->FtFace, &bd_baked_data->FtSize);
+        FT_Activate_Size(bd_baked_data->FtSize);
+
+        // Vuhdo 2017: "I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height'
+        // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me.
+        // FT_Set_Pixel_Sizes() doesn't seem to get us the same result."
+        // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL)
+        FT_Size_RequestRec req;
+        req.type = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM;
+        req.width = 0;
+        req.height = (uint32_t)(size * 64 * bd_font_data->RasterizationDensity);
+        req.horiResolution = 0;
+        req.vertResolution = 0;
+        FT_Request_Size(bd_font_data->FtFace, &req);
+
+        // Read metrics
+        FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics;
+        bd_baked_data->Ascender = (float)FT_CEIL(metrics.ascender) * bd_font_data->InvRasterizationDensity;
+        bd_baked_data->Descender = (float)FT_CEIL(metrics.descender) * bd_font_data->InvRasterizationDensity;
+        bd_baked_data->LineSpacing = (float)FT_CEIL(metrics.height) * bd_font_data->InvRasterizationDensity;
+        bd_baked_data->LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * bd_font_data->InvRasterizationDensity;
+        bd_baked_data->MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * bd_font_data->InvRasterizationDensity;
+
+        // Output
+        baked->Ascent = bd_baked_data->Ascender;
+        baked->Descent = bd_baked_data->Descender;
+    }
+}
+
+void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontBaked* baked)
+{
+    IM_UNUSED(atlas);
+    ImFont* font = baked->ContainerFont;
+    ImGui_ImplFreeType_FontSrcBakedData* bd_baked_datas = (ImGui_ImplFreeType_FontSrcBakedData*)baked->FontBackendData;
+    for (int src_n = 0; src_n < font->SourcesCount; src_n++)
+        FT_Done_Size(bd_baked_datas[src_n].FtSize);
+    IM_FREE(bd_baked_datas);
+    baked->FontBackendData = NULL;
+}
+
+bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint)
 {
 {
     // Search for first font which has the glyph
     // Search for first font which has the glyph
     ImGui_ImplFreeType_FontSrcData* bd_font_data = NULL;
     ImGui_ImplFreeType_FontSrcData* bd_font_data = NULL;
@@ -481,6 +509,15 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon
     if (glyph_index == 0)
     if (glyph_index == 0)
         return false; // Not found
         return false; // Not found
 
 
+    if (bd_font_data->BakedLastActivated != baked)
+    {
+        // Activate current size
+        int src_n = (int)(font_cfg - srcs);
+        ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = &((ImGui_ImplFreeType_FontSrcBakedData*)baked->FontBackendData)[src_n];
+        FT_Activate_Size(bd_baked_data->FtSize);
+        bd_font_data->BakedLastActivated = baked;
+    }
+
     const FT_Glyph_Metrics* metrics = bd_font_data->LoadGlyph(codepoint);
     const FT_Glyph_Metrics* metrics = bd_font_data->LoadGlyph(codepoint);
     if (metrics == NULL)
     if (metrics == NULL)
         return false;
         return false;
@@ -515,9 +552,7 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon
             IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory.");
             IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory.");
             return false;
             return false;
         }
         }
-
         ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
         ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
-        font->MetricsTotalSurface += w * h;
 
 
         // Render pixels to our temporary buffer
         // Render pixels to our temporary buffer
         atlas->Builder->TempBuffer.resize(w * h * 4);
         atlas->Builder->TempBuffer.resize(w * h * 4);
@@ -525,7 +560,7 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon
         bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w);
         bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w);
 
 
         float font_off_x = src->GlyphOffset.x;
         float font_off_x = src->GlyphOffset.x;
-        float font_off_y = src->GlyphOffset.y + IM_ROUND(font->Ascent);
+        float font_off_y = src->GlyphOffset.y + IM_ROUND(baked->Ascent);
         float recip_h = 1.0f / src->RasterizerDensity;
         float recip_h = 1.0f / src->RasterizerDensity;
         float recip_v = 1.0f / src->RasterizerDensity;
         float recip_v = 1.0f / src->RasterizerDensity;
 
 
@@ -539,19 +574,19 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon
         glyph.Visible = true;
         glyph.Visible = true;
         glyph.Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);
         glyph.Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);
         glyph.PackId = pack_id;
         glyph.PackId = pack_id;
-        ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph);
+        ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph);
 
 
         // Copy to texture, post-process and queue update for backend
         // Copy to texture, post-process and queue update for backend
         ImTextureData* tex = atlas->TexData;
         ImTextureData* tex = atlas->TexData;
         IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height);
         IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height);
         ImFontAtlasTextureBlockConvert(temp_buffer, ImTextureFormat_RGBA32, w * 4, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h);
         ImFontAtlasTextureBlockConvert(temp_buffer, ImTextureFormat_RGBA32, w * 4, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h);
-        ImFontAtlasPostProcessData pp_data = { atlas, font, src, &font->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h };
+        ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, &baked->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h };
         ImFontAtlasTextureBlockPostProcess(&pp_data);
         ImFontAtlasTextureBlockPostProcess(&pp_data);
         ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
         ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h);
     }
     }
     else
     else
     {
     {
-        ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph);
+        ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph);
     }
     }
     return true;
     return true;
 }
 }
@@ -573,7 +608,9 @@ const ImFontLoader* ImGuiFreeType::GetFontLoader()
     loader.FontSrcInit = ImGui_ImplFreeType_FontSrcInit;
     loader.FontSrcInit = ImGui_ImplFreeType_FontSrcInit;
     loader.FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy;
     loader.FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy;
     loader.FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph;
     loader.FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph;
-    loader.FontAddGlyph = ImGui_ImplFreeType_FontAddGlyph;
+    loader.FontBakedInit = ImGui_ImplFreeType_FontBakedInit;
+    loader.FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy;
+    loader.FontBakedAddGlyph = ImGui_ImplFreeType_FontBakedAddGlyph;
     return &loader;
     return &loader;
 }
 }