Problem
When ImGuiFreeTypeLoaderFlags_LoadColor is set, color fonts (COLR / COLRv1, sbix, CBDT) do not render through the FreeType builder: the glyph bakes as an empty bitmap and AddText draws nothing. Color emoji (e.g. a Twemoji Mozilla COLRv0 font at U+1F600) is the most visible victim.
Root cause
ImGui_ImplFreeType_FontSrcData::InitFont adds FT_LOAD_COLOR to the FreeType LoadFlags but not FT_LOAD_RENDER, so FT_Load_Glyph leaves the glyph unrendered. ImGui_ImplFreeType_FontBakedLoadGlyph then unconditionally calls:
FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);FT_RENDER_MODE_NORMAL renders the outline only. For pure-COLR glyphs (no traditional outline, only color layers) the result is an empty bitmap (w == 0 && h == 0), is_visible is false, no atlas rect is packed, and the glyph never rasterizes. Even for COLR glyphs that do have a base outline, the color layers are discarded, so the emoji renders monochrome instead of color.
Fix
Two small changes in misc/freetype/imgui_freetype.cpp:
- In
InitFont, whenLoadColoris set, also addFT_LOAD_RENDERtoLoadFlags. FreeType then auto-renders duringFT_Load_Glyph: color glyphs come back as aFT_PIXEL_MODE_BGRAbitmap withslot->format == FT_GLYPH_FORMAT_BITMAP. - In
FontBakedLoadGlyph, only callFT_Render_Glyphwhen the glyph is not already a bitmap (slot->format != FT_GLYPH_FORMAT_BITMAP). This avoids re-rendering an already-rendered color bitmap withFT_RENDER_MODE_NORMAL, which would discard the BGRA pixels.
Monochrome fonts unaffected
Fonts without color layers (the common case) ignore FT_LOAD_COLOR; slot->format stays FT_GLYPH_FORMAT_OUTLINE after FT_Load_Glyph, so the existing FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL) path runs exactly as before. No behavior change for ASCII / CJK / etc.
MCVE (minimal, pastable into an example app)
Build any example with IMGUI_ENABLE_FREETYPE defined (so the FreeType builder is used). Drop this in the example's main.cpp right after the ImGui context is created (point COLOR_FONT_PATH at a COLR/sbix color font, e.g. Twemoji Mozilla COLRv0, or Apple Color Emoji):
#define IMGUI_ENABLE_FREETYPE // in your build, alongside linking FreeType
#include "imgui.h"
// ...
{
// After ImGui::CreateContext():
ImFontConfig cfg;
cfg.FontLoaderFlags = ImGuiFreeTypeLoaderFlags_LoadColor; // ImGuiFreeTypeBuilderFlags_LoadColor on older branches
static const ImWchar32 ranges[] = { 0x1F600, 0x1F64F, 0x2764, 0x2764, 0 }; // 😀..🙂 + ❤
io.Fonts->AddFontFromFileTTF(COLOR_FONT_PATH, 32.0f, &cfg, ranges);
}then in your UI:
ImGui::Text("\xF0\x9F\x98\x80 \xE2\x9D\xA4"); // "😀 ❤" -- UTF-8 literals for portability- before this PR: the emoji render blank (empty bitmap baked, AddText draws nothing);
- after this PR: they render as colored bitmaps (BGRA atlas texture).
You can confirm the bake with a quick check after the first frame:
ImFontBaked* baked = io.Fonts->GetFont(0)->GetFontBaked(io.Fonts->GetFont(0)->LegacySize);
if (const ImFontGlyph* g = baked ? baked->FindGlyph((ImWchar)0x1F600) : nullptr)
ImGui::Text("😀 Colored=%d Visible=%d %dx%d", g->Colored, g->Visible, (int)(g->X1 - g->X0), (int)(g->Y1 - g->Y0));Validation
Built cimgui with IMGUI_ENABLE_FREETYPE + IMGUI_USE_WCHAR32 against FreeType 2.13.4 and loaded a Twemoji Mozilla COLRv0 font with LoadColor:
- before:
FT_Load_Glyph(U+2764, FT_LOAD_COLOR|FT_LOAD_RENDER)→0x0bitmap via the old code path → ❤️/😀 render blank; - after: BGRA bitmap (
pixel_mode == FT_PIXEL_MODE_BGRA),out_glyph->Colored = true, AddText renders the color glyph.
The patch compiles cleanly against master (clang, -DIMGUI_ENABLE_FREETYPE, FreeType 2.13.4 headers).
A downstream TUI cell-grid renderer (ManyUI / ManyUICImGui, ImGui 1.92 docking via cimgui-pack) renders ❤️ ☝️ 😀 in color with this change where it previously rendered the □ placeholder.
AI-assisted.