How to Load Custom Fonts in Dear ImGui: A Complete Guide to ImFontAtlas

Dear ImGui loads custom fonts through the ImFontAtlas class, which aggregates one or more fonts into a single rasterized texture using methods like AddFontFromFileTTF and AddFontFromMemoryTTF, requiring a Build() call before the first frame is rendered.

Dear ImGui (ocornut/imgui) renders all user interface text using a centralized texture atlas generated from TrueType or OpenType font files. The ImFontAtlas class manages the entire pipeline, from parsing font data to packing glyphs into a GPU-ready texture. Properly configuring this system is essential for supporting international character sets, icon fonts, and high-quality text rendering.

Understanding the ImFontAtlas Architecture

The font system revolves around a single ImFontAtlas instance owned by the global ImGuiIO context. Access it via ImGui::GetIO().Fonts. This atlas holds the raw rasterized glyphs, a texture reference (TexRef), and optional custom rectangles for user-defined graphics like icons.

The atlas operates in two distinct phases: configuration and build. During configuration, you add fonts, set glyph ranges, and reserve custom rectangles. The build phase packs everything into a single texture buffer that your rendering backend uploads to the GPU.

Loading Fonts from Files and Memory

Dear ImGui provides two primary methods for ingesting font data: loading directly from disk or importing from memory buffers.

Loading from TTF/OTF Files

The most common approach uses AddFontFromFileTTF, declared in imgui.h around line 3713. This method parses the font file, rasterizes it at the specified pixel size, and returns an ImFont* pointer.

ImGuiIO& io = ImGui::GetIO();
ImFont* myFont = io.Fonts->AddFontFromFileTTF("assets/fonts/Roboto-Regular.ttf", 18.0f);

If you need to customize the font, pass an ImFontConfig pointer as the third argument and an optional glyph range specifier as the fourth.

Loading from Memory Buffers

For embedded resources or runtime-generated fonts, use AddFontFromMemoryTTF. This function takes ownership of the supplied buffer by default, copying the data into the atlas unless configured otherwise.

unsigned char* ttfData = /* load file into memory */;
int ttfSize = /* size of buffer */;
ImFont* font = io.Fonts->AddFontFromMemoryTTF(ttfData, ttfSize, 16.0f);

Critical: Set ImFontConfig::FontDataOwnedByAtlas = false (as documented in imgui.h near line 3714) if you want to retain ownership of the memory and free it yourself. If true, Dear ImGui allocates and owns the copy.

Configuring Font Rendering with ImFontConfig

The ImFontConfig struct (defined in imgui.h around line 3600) controls rasterization quality, glyph subsets, and memory ownership.

Custom Glyph Ranges and Unicode Blocks

By default, Dear ImGui loads a basic Latin range. To support Cyrillic, Chinese, Japanese, or custom Unicode blocks, specify GlyphRanges using built-in helpers or custom arrays.

ImFontConfig cfg;
cfg.GlyphRanges = io.Fonts->GetGlyphRangesCyrillic(); // Or GetGlyphRangesChineseFull()
ImFont* font = io.Fonts->AddFontFromFileTTF("arial.ttf", 16.0f, &cfg);

Warning: As noted in imgui.h at line 3699, GlyphRanges is stored as a raw pointer. The underlying array must remain valid until you call Build() on the atlas.

Oversampling and Quality Settings

For higher quality text on high-DPI displays, increase horizontal and vertical oversampling:

ImFontConfig cfg;
cfg.OversampleH = 3;
cfg.OversampleV = 3;
cfg.PixelSnapH = true;
ImFont* hqFont = io.Fonts->AddFontFromFileTTF("font.ttf", 20.0f, &cfg);

Adding Custom Rectangles for Icons

The atlas supports custom rectangular regions for images or colored icons. This API (located in imgui.h lines 3889-3892) reserves space in the texture before the build step.

ImFontAtlasRect iconRect;
ImFontAtlasRectId iconId = io.Fonts->AddCustomRect(64, 64, &iconRect);
// After building, fill the texture data at rect locations

Call io.Fonts->GetCustomRect(iconId, &iconRect) after Build() to retrieve the final UV coordinates for use in ImDrawList calls.

Building and Uploading the Texture

Before rendering any text, you must finalize the atlas:

io.Fonts->Build();

This packs all fonts and custom rectangles into a single pixel buffer. Retrieve the texture data using GetTexDataAsRGBA32() or GetTexDataAsAlpha8(), upload it to your GPU, and store the texture identifier via SetTexID.

Important: Any subsequent call that modifies the atlas—adding a new font, changing glyph ranges, or resizing—invalidates the existing texture and requires a rebuild. Always fetch custom rectangle UVs after each build operation.

Optional FreeType Integration

For superior hinting and subpixel rendering, enable the optional FreeType loader. Define IMGUI_ENABLE_FREETYPE before including imgui.h, include misc/freetype/imgui_freetype.cpp in your build, and set the custom loader:

io.Fonts->SetFontLoader(ImGui::GetFreeTypeFontLoader());
// Now AddFontFromFileTTF uses FreeType rasterization

The FreeType implementation resides in misc/freetype/imgui_freetype.cpp and provides advanced hinting controls compared to the default stb_truetype backend.

Summary

  • Access the global atlas via ImGui::GetIO().Fonts before any rendering occurs.
  • Use AddFontFromFileTTF for disk files or AddFontFromMemoryTTF for embedded data.
  • Configure glyph ranges via ImFontConfig to support international characters, ensuring the range array outlives the build process.
  • Call Build() once after all fonts are added to generate the texture atlas.
  • Reserve custom rectangles before building to embed icons alongside text.
  • Enable the FreeType backend (in misc/freetype/imgui_freetype.cpp) for production-quality rasterization.

Frequently Asked Questions

Why do some characters display as question marks or boxes?

This typically occurs when the glyph range specified in ImFontConfig does not include the Unicode codepoints you are attempting to render. Verify that you are using the correct range helper (e.g., GetGlyphRangesChineseFull()) or a custom array that includes the specific characters. As implemented in imgui.h, missing glyphs fall back to the default font if available, or render as the "missing character" box if not.

Can I load multiple fonts at different sizes simultaneously?

Yes. Call AddFontFromFileTTF or AddFontFromMemoryTTF multiple times with different size parameters and optional ImFontConfig structures. Each call returns a distinct ImFont* pointer. Switch between active fonts using ImGui::PushFont(fontPtr) and ImGui::PopFont() during your UI rendering code.

When exactly should I call Build() on the font atlas?

You must call Build() (or implicitly trigger it via GetTexDataAsRGBA32) after all font addition and configuration is complete, but before the first frame is rendered. Modifying the atlas after building—for example, calling AddFontFromFileTTF later—invalidates the existing texture and requires another build cycle as implemented in imgui.cpp.

How do I prevent Dear ImGui from copying my embedded font memory?

Set ImFontConfig::FontDataOwnedByAtlas = false before calling AddFontFromMemoryTTF. According to the source in imgui.h near line 3714, this flag tells the atlas to reference your existing buffer rather than allocating its own copy. You remain responsible for keeping that memory valid for the duration of the atlas's lifetime and freeing it after Dear ImGui shuts down.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →