Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions docs/FONTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config);
// Load a first font
ImFont* font = io.Fonts->AddFontDefault();
ImFontConfig config;
config.MergeMode = true;
config.MergeTarget = font;
io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 0.0f, &config); // Merge into first font to add e.g. Asian characters
io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 0.0f, &config); // Merge into first font to add Icons
io.Fonts->Build();
Expand All @@ -162,7 +162,7 @@ ImFont* font = io.Fonts->AddFontDefault();
// so ensure it is available at the time of building or calling GetTexDataAsRGBA32().
static const ImWchar icons_ranges[] = { 0xf000, 0xf3ff, 0 }; // Will not be copied by AddFont* so keep in scope.
ImFontConfig config;
config.MergeMode = true;
config.MergeTarget = font;
io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 18.0f, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge into first font
io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 18.0f, &config, icons_ranges); // Merge into first font
io.Fonts->Build();
Expand Down Expand Up @@ -269,9 +269,9 @@ Example Setup:
// Merge icons into default tool font
#include "IconsFontAwesome.h"
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontDefault();
ImFont *font = io.Fonts->AddFontDefault();
ImFontConfig config;
config.MergeMode = true;
config.MergeTarget = font;
config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced
io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config);
```
Expand All @@ -280,10 +280,10 @@ io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config);
// Merge icons into default tool font
#include "IconsFontAwesome.h"
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontDefault();
ImFont *font = io.Fonts->AddFontDefault();

ImFontConfig config;
config.MergeMode = true;
config.MergeTarget = font;
config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced
static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config, icon_ranges);
Expand Down Expand Up @@ -322,11 +322,11 @@ Here's an application using icons ("Avoyd", https://www.avoyd.com):
static ImWchar exclude_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFontConfig cfg1;
cfg1.GlyphExcludeRanges = exclude_ranges;
io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1);
ImFont *font1 = io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1);

// Add Font Source 2, which expects to use the range above
ImFontConfig cfg2;
cfg2.MergeMode = true;
cfg2.MergeTarget = font1;
io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2);
```
Another (silly) example:
Expand All @@ -335,11 +335,11 @@ Another (silly) example:
static ImWchar exclude_ranges[] = { 'A', 'Z', 0 };
ImFontConfig cfg1;
cfg1.GlyphExcludeRanges = exclude_ranges;
io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1);
ImFont *font1 = io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1);

// Load another font to fill the gaps
ImFontConfig cfg2;
cfg2.MergeMode = true;
cfg2.MergeTarget = font1;
io.Fonts->AddFontFromFileTTF("Roboto-Medium.ttf", 0.0f, &cfg2);
```
![image](https://github.com/user-attachments/assets/f3d751d3-1aee-4698-bd9b-f511902f56bb)
Expand Down Expand Up @@ -373,10 +373,10 @@ You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool`
![colored glyphs](https://user-images.githubusercontent.com/8225057/106171241-9dc4ba80-6191-11eb-8a69-ca1467b206d1.png)

```cpp
io.Fonts->AddFontFromFileTTF("../../../imgui_dev/data/fonts/NotoSans-Regular.ttf", 16.0f);
ImFont *font = io.Fonts->AddFontFromFileTTF("../../../imgui_dev/data/fonts/NotoSans-Regular.ttf", 16.0f);
static ImWchar ranges[] = { 0x1, 0x1FFFF, 0 };
static ImFontConfig cfg;
cfg.MergeMode = true;
cfg.MergeTarget = font;
cfg.FontLoaderFlags |= ImGuiFreeTypeLoaderFlags_LoadColor;
io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\seguiemj.ttf", 16.0f, &cfg);
```
Expand Down
3 changes: 2 additions & 1 deletion imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -3474,7 +3474,7 @@ struct ImFontConfig
bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself).

// Options
bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
ImFont* MergeTarget; // NULL // Merge into specified ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1.
bool PixelSnapV; // true // Align Scaled GlyphOffset.y to pixel boundaries.
ImS8 OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.
Expand All @@ -3499,6 +3499,7 @@ struct ImFontConfig
ImFont* DstFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font)
const ImFontLoader* FontLoader; // Custom font backend for this source (default source is the one stored in ImFontAtlas)
void* FontLoaderData; // Font loader opaque storage (per font config)
void* UserData;

IMGUI_API ImFontConfig();
};
Expand Down
76 changes: 62 additions & 14 deletions imgui_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3012,7 +3012,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in)

// Create new font
ImFont* font;
if (!font_cfg_in->MergeMode)
if (!font_cfg_in->MergeTarget)
{
font = IM_NEW(ImFont)();
font->FontId = FontNextUniqueID++;
Expand All @@ -3023,8 +3023,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in)
}
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.
font = Fonts.back();
IM_ASSERT(font_cfg_in->MergeTarget->ContainerAtlas == this);
font = font_cfg_in->MergeTarget;
}

// Add to list
Expand Down Expand Up @@ -3064,7 +3064,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in)
ImFontAtlasFontDestroySourceData(this, font_cfg);
Sources.pop_back();
font->Sources.pop_back();
if (!font_cfg->MergeMode)
if (!font_cfg->MergeTarget)
{
IM_DELETE(font);
Fonts.pop_back();
Expand Down Expand Up @@ -3610,7 +3610,7 @@ bool ImFontAtlasFontSourceInit(ImFontAtlas* atlas, ImFontConfig* src)

void ImFontAtlasFontSourceAddToFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src)
{
if (src->MergeMode == false)
if (!src->MergeTarget)
{
font->ClearOutputData();
//font->FontSize = src->SizePixels;
Expand Down Expand Up @@ -3718,7 +3718,7 @@ static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas* atlas, ImFontBaked
}

// Load/identify special glyphs
// (note that this is called again for fonts with MergeMode)
// (note that this is called again for fonts with MergeTarget)
void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src)
{
IM_UNUSED(atlas);
Expand Down Expand Up @@ -4436,11 +4436,14 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep
return glyph;

// Call backend
char* loader_user_data_p = (char*)baked->FontLoaderDatas;
int src_n = 0;
for (ImFontConfig* src : font->Sources)
bool no_fallback = false;
size_t loader_user_data_n = 0;
auto loadGlyph = [=, &no_fallback, &loader_user_data_n](int src_n) -> ImFontGlyph*
{
ImFontConfig* src = font->Sources[src_n];
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
void *loader_user_data_p = (char*)baked->FontLoaderDatas + loader_user_data_n;
loader_user_data_n += loader->FontBakedSrcLoaderDataSize;
if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint))
{
if (only_load_advance_x == NULL)
Expand All @@ -4460,12 +4463,57 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep
if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, NULL, only_load_advance_x))
{
ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, *only_load_advance_x);
no_fallback = true;
return NULL;
}
}
}
loader_user_data_p += loader->FontBakedSrcLoaderDataSize;
src_n++;

return NULL;
};

int src_n = 0;
for (; src_n < font->Sources.Size; ++src_n)
{
ImFontGlyph* glyph = loadGlyph(src_n);
if (glyph || no_fallback)
return glyph;
}

if (atlas->FontLoader->FontAddFallbackSrc)
{
atlas->FontLoader->FontAddFallbackSrc(atlas, font, codepoint);

for (; src_n < font->Sources.Size; ++src_n)
{
ImFontConfig* src = font->Sources[src_n];
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;

for (int baked_n = 0; baked_n < atlas->Builder->BakedPool.Size; baked_n++)
{
ImFontBaked* baked_sibling = &atlas->Builder->BakedPool[baked_n];
if (baked_sibling->ContainerFont != font || baked_sibling->WantDestroy)
continue;

if (loader->FontBakedSrcLoaderDataSize > 0)
{
void *new_data = IM_ALLOC(loader_user_data_n + loader->FontBakedSrcLoaderDataSize);
memcpy(new_data, baked_sibling->FontLoaderDatas, loader_user_data_n);
IM_FREE(baked_sibling->FontLoaderDatas);
baked_sibling->FontLoaderDatas = new_data;
}

if (loader->FontBakedInit)
{
void *loader_user_data_p = (char*)baked_sibling->FontLoaderDatas + loader_user_data_n;
loader->FontBakedInit(atlas, src, baked_sibling, loader_user_data_p);
}
}

ImFontGlyph* glyph = loadGlyph(src_n);
if (glyph || no_fallback)
return glyph;
}
}

// Lazily load fallback glyph
Expand Down Expand Up @@ -4572,14 +4620,14 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig*
}
src->FontLoaderData = bd_font_data;

if (src->MergeMode && src->SizePixels == 0.0f)
if (src->MergeTarget && src->SizePixels == 0.0f)
src->SizePixels = src->DstFont->Sources[0]->SizePixels;

if (src->SizePixels >= 0.0f)
bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f);
else
bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f);
if (src->MergeMode && src->SizePixels != 0.0f)
if (src->MergeTarget && src->SizePixels != 0.0f)
bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0]->SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit

return true;
Expand Down Expand Up @@ -4609,7 +4657,7 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig
IM_UNUSED(atlas);

ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData;
if (src->MergeMode == false)
if (!src->MergeTarget)
{
// FIXME-NEWFONTS: reevaluate how to use sizing metrics
// FIXME-NEWFONTS: make use of line gap value
Expand Down
1 change: 1 addition & 0 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -3700,6 +3700,7 @@ struct ImFontLoader
bool (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src);
void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src);
bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x);
void (*FontAddFallbackSrc)(ImFontAtlas* atlas, ImFont* parent, ImWchar codepoint); // merges zero or more new font sources into the parent ImFont which should contain a glyph for the codepoint

// Size of backend data, Per Baked * Per Source. Buffers are managed by core to avoid excessive allocations.
// FIXME: At this point the two other types of buffers may be managed by core to be consistent?
Expand Down
4 changes: 2 additions & 2 deletions misc/freetype/imgui_freetype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF
{
IM_UNUSED(atlas);
float size = baked->Size;
if (src->MergeMode && src->SizePixels != 0.0f)
if (src->MergeTarget && src->SizePixels != 0.0f)
size *= (src->SizePixels / baked->ContainerFont->Sources[0]->SizePixels);

ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData;
Expand Down Expand Up @@ -450,7 +450,7 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF
FT_Request_Size(bd_font_data->FtFace, &req);

// Output
if (src->MergeMode == false)
if (!src->MergeTarget)
{
// Read metrics
FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics;
Expand Down