How to Load and Use Custom Fonts with the Dear ImGui Font Atlas System
To load custom fonts in Dear ImGui, access the global ImFontAtlas via ImGui::GetIO().Fonts, configure an ImFontConfig struct, then call AddFontFromFileTTF() with your TTF path before the first frame renders.
Dear ImGui stores all glyphs in a single GPU texture called the font atlas. The ocornut/imgui repository provides a robust API through ImFontAtlas (exposed via ImGuiIO::Fonts) that allows you to load TrueType fonts, merge icon sets, and manage typographic resources efficiently. This guide covers the complete workflow from configuration to runtime usage based on the actual implementation in imgui_draw.cpp and imgui.h.
Understanding the ImFontAtlas Architecture
The font atlas is owned by the ImGuiIO structure and initialized when you call ImGui::CreateContext(). All font loading operations must occur after initializing ImGui but before the first call to ImGui::NewFrame(), as the texture needs to be uploaded to the GPU.
In imgui.h, the ImFontAtlas class (around line 3736) exposes the primary loading methods:
AddFontFromFileTTF()– Loads from disk with optional configurationAddFontFromMemoryTTF()– Loads from raw memory bufferAddFontFromMemoryCompressedTTF()– Loads pre-compressed font dataBuild()– Forces immediate atlas construction (usually automatic)
The atlas rasterizes glyphs on demand and packs them into a single texture, enabling efficient batch rendering of UI text.
Step-by-Step Guide to Loading Custom Fonts
Configure Font Settings with ImFontConfig
Before loading a font, create an ImFontConfig struct to control rasterization quality and glyph handling. This struct is defined in imgui.h (lines 3456–3505) and copied internally, so stack allocation is safe.
ImFontConfig cfg;
cfg.OversampleH = 1; // Reduce texture size (quality trade-off)
cfg.OversampleV = 1;
cfg.GlyphMinAdvanceX = 13.0f; // Force monospaced width (useful for icons)
cfg.PixelSnapH = true; // Align glyphs to pixel grid
Oversampling controls anti-aliasing quality versus texture memory usage. For standard UI text, 2 is typical; for icon fonts or memory-constrained applications, use 1.
Load Font Files from Disk or Memory
Call AddFontFromFileTTF() on the font atlas. Since Dear ImGui v1.92, the size parameter is optional (pass 0.0f for automatic selection), though explicit sizes are recommended for consistency.
ImGuiIO& io = ImGui::GetIO();
ImFont* myFont = io.Fonts->AddFontFromFileTTF(
"assets/fonts/Roboto-Medium.ttf",
16.0f, // Size in pixels
&cfg // Optional config (can be NULL)
);
The implementation in imgui_draw.cpp (lines 3241–3320) handles file reading, stb_truetype rasterization, and atlas packing. The function returns an ImFont* pointer you can store for later use.
Merge Icon Fonts into the Same Atlas
To combine an icon font (like FontAwesome) with your base font, enable merge mode in the configuration and specify the glyph ranges.
// After loading the main font
cfg.MergeMode = true; // Merge into previous font instead of creating new
cfg.GlyphMinAdvanceX = 13.0f;
// Define icon range (example for FontAwesome)
static const ImWchar icon_ranges[] = { 0xF000, 0xF2E0, 0 };
// Load icon font at same size as base font
io.Fonts->AddFontFromFileTTF(
"assets/fonts/fontawesome-webfont.ttf",
16.0f,
&cfg,
icon_ranges
);
Merge mode ensures icons occupy the same texture and ImFont object as the base text, allowing seamless mixed rendering.
Build and Upload the Texture
Modern ImGui backends build the atlas automatically during the first frame. However, if you need the texture handle immediately (for custom engine integration), force a build:
io.Fonts->Build();
The resulting texture ID is accessible via io.Fonts->TexID. Custom backends must upload this to the GPU; standard backends (GLFW, SDL, DirectX) handle this automatically.
Using Custom Fonts in Your UI
Switching Fonts at Runtime
By default, the first font added becomes the global default. To temporarily switch fonts for specific widgets, use the font stack:
ImGui::PushFont(myFont);
ImGui::Text("This uses the custom typeface");
ImGui::Button("Custom Font Button");
ImGui::PopFont(); // Restore previous font
Since v1.92, you can also push a dynamic size without creating a new font entry:
ImGui::PushFont(myFont, 24.0f); // 24px for this scope only
ImGui::Text("Large header text");
ImGui::PopFont();
Handling DPI Scaling
For high-DPI displays, avoid reloading fonts. Instead, use the built-in scaling mechanisms:
ImGuiStyle::ScaleAllSizes()– Scales layout geometrystyle.FontScaleDpi– Global font scaling (when backend supportsImGuiBackendFlags_HasTextures)
See the DPI handling section in docs/FONTS.md for platform-specific recommendations.
Working with Embedded and Compressed Font Data
For applications requiring standalone binaries, embed fonts as compressed byte arrays. The imconfig.h file allows disabling default fonts via IMGUI_DISABLE_DEFAULT_FONT to reduce binary size.
// Data typically generated by binary_to_c compression tools
extern const unsigned char Roboto_compressed_data[];
extern const int Roboto_compressed_size;
ImFontConfig cfg;
cfg.FontDataOwnedByAtlas = false; // You retain ownership
ImFont* embeddedFont = io.Fonts->AddFontFromMemoryCompressedTTF(
Roboto_compressed_data,
Roboto_compressed_size,
16.0f,
&cfg
);
Set FontDataOwnedByAtlas = false only if you manage the memory lifetime; otherwise, ImGui copies and owns the data.
Summary
- Access the font atlas through
ImGui::GetIO().Fontsimmediately afterImGui::CreateContext() - Use
ImFontConfigto control oversampling (OversampleH/V), merge mode, and glyph spacing - Load fonts via
AddFontFromFileTTF()(disk) orAddFontFromMemoryCompressedTTF()(embedded) - Merge icon fonts by setting
cfg.MergeMode = trueand definingImWcharranges - Switch fonts at runtime with
PushFont()/PopFont(); size overrides available since v1.92 - Reference
imgui_draw.cppfor rasterization internals anddocs/FONTS.mdfor advanced glyph range configurations
Frequently Asked Questions
Do I need to call Build() after adding fonts?
Usually no. Modern backends build the atlas automatically during the first ImGui::NewFrame() when they detect dirty font data. However, if you need the GPU texture handle immediately—such as when integrating with a custom renderer—call io.Fonts->Build() manually after adding all fonts.
How do I merge icon fonts like FontAwesome?
Set ImFontConfig::MergeMode = true when loading the secondary font, and specify the Unicode glyph ranges you want to import using the glyph_ranges parameter. The icon font must be loaded at the same size as the base font to align correctly. Refer to the "Using Icon Fonts" section in docs/FONTS.md for range constants like ICON_MIN_FA.
Can I load fonts from memory instead of files?
Yes. Use AddFontFromMemoryTTF() for raw TTF data or AddFontFromMemoryCompressedTTF() for stb_compress'd data. The latter is preferred for embedded resources to minimize binary size. Set FontDataOwnedByAtlas = false in the config if you will free the memory after initialization.
How do I change font size dynamically without reloading?
Since Dear ImGui v1.92, you can push a temporary size multiplier: ImGui::PushFont(myFont, 24.0f) draws at 24px for that scope. For older versions, you must add the same font file multiple times with different sizes during initialization, then select the appropriate ImFont* pointer with PushFont().
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →