Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(WIP) Dynamic glyph rasterization and unlimited number of font textures #3471

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8942a8d
Added dynamic glyph rasterization and unlimited number of font textures.
georgegerdin Sep 14, 2020
af65082
Some small fixes
georgegerdin Sep 14, 2020
6076638
Fixing some warnings from unused debug code.
georgegerdin Sep 14, 2020
2e247f7
Update README.md
georgegerdin Sep 14, 2020
97f197f
Added FIXME-DYNAMICFONT comments in places where things needs to be f…
georgegerdin Sep 18, 2020
9f0cdc5
Added support for CustomRects and software mouse cursor.
georgegerdin Sep 18, 2020
634745d
Added textured lines and FindGlyphNoFallback.
georgegerdin Sep 19, 2020
b8b5c71
Added support for SDL backend.
georgegerdin Sep 25, 2020
58b51b1
Added support for freetype (link with freetype libraries and add a gl…
georgegerdin Sep 25, 2020
fe1fbb9
Some minor fixes...
georgegerdin Sep 25, 2020
986738c
Fixed flicker issues. FindGlyph can now provide a backup glyph if the…
georgegerdin Sep 27, 2020
4133a5e
In this update only one font texture is used for the majority of the
georgegerdin Jul 14, 2021
a049652
Merge remote-tracking branch 'upstream/master'
georgegerdin Jul 18, 2021
9a38be3
Merge branch 'master' of https://github.com/ocornut/imgui
georgegerdin Jul 20, 2021
ba975a2
Added DirectX9 support.
georgegerdin Jul 20, 2021
068df22
Added support for DirectX 10.
georgegerdin Jul 20, 2021
76b8d85
Added DirectX11 support.
georgegerdin Jul 21, 2021
2bf352f
Small changes and bug fixes.
georgegerdin Jul 23, 2021
a844ce9
Merge branch 'master' of https://github.com/ocornut/imgui into ocornu…
georgegerdin Jul 27, 2021
728979f
Merge branch 'master' of https://github.com/ocornut/imgui into ocorn…
georgegerdin Dec 17, 2021
d4d67ea
Merge branch 'master' of https://github.com/georgegerdin/imgui
georgegerdin Dec 17, 2021
137ec70
Merge branch 'master' of git://github.com/ocornut/imgui into ocornut-…
georgegerdin Dec 17, 2021
fa0b88f
Merge branch 'ocornut-master'
georgegerdin Dec 17, 2021
2d4d3e5
Merge v1.90.6
georgegerdin May 18, 2024
a6ebfef
Fix a bug that caused the columns to be generated erroneously.
georgegerdin May 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion imgui.h
Expand Up @@ -2250,6 +2250,7 @@ struct ImFontGlyph
int NextGlyph;
short GlyphSize;
ImFontTexture* FontTexture;
int FrameCountCreation; //Frame count when this glyph was rendered
};

struct ImFontQuad
Expand Down Expand Up @@ -2424,7 +2425,7 @@ struct ImFont
// Methods
IMGUI_API ImFont();
IMGUI_API ~ImFont();
IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c, float size);
IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c, float size, ImFontGlyph** backup_glyph = NULL);
// FIXME-DYNAMICFONT: Add support for findglyphnofallback
IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c, float size) const;
float GetCharAdvance(ImWchar c, float size);
Expand Down
97 changes: 82 additions & 15 deletions imgui_draw.cpp
Expand Up @@ -1739,6 +1739,17 @@ ImFontAtlas::ImFontAtlas(int tex_width, int tex_height)
//Create data for an empty font texture. This will be used every time a new texture is spawned.
EmptyFontTexturePixelData.resize(TexWidth*TexHeight * 4, 0);

//This turns the font texture green for debugging purposes
/*for(auto x = 0; x < TexWidth; ++x) {
for(auto y = 0; y < TexHeight; ++y) {
auto* pixel = &EmptyFontTexturePixelData[((y*TexWidth) + x) * 4];
pixel[0] = 0;
pixel[1] = 255;
pixel[2] = 0;
pixel[3] = 255;
}
}*/

//Create first font texture
FontTextures.push_back(IM_NEW(ImFontTexture(TexWidth, TexHeight, EmptyFontTexturePixelData.Data)));

Expand Down Expand Up @@ -2466,7 +2477,7 @@ void ImFontAtlas::FindTextureAndRow(ImFontTexture** resulting_texture, ImFontTex
*resulting_texture = (*texture);
}

const ImFontGlyph* ImFont::FindGlyph(ImWchar codepoint, float size)
const ImFontGlyph* ImFont::FindGlyph(ImWchar codepoint, float size, ImFontGlyph** backup_glyph)
{

int i, g, advance, lsb, x0, y0, x1, y1;
Expand All @@ -2475,13 +2486,34 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar codepoint, float size)
// Find code point and size using lookup table.
unsigned int h = hashint(codepoint) & (IM_HASH_LUT_SIZE - 1);
i = this->lut[h];
ImFontGlyph* result = NULL;
if(backup_glyph) *backup_glyph = NULL;
while (i != -1)
{
if (this->Glyphs[i].Codepoint == codepoint && this->Glyphs[i].GlyphSize == (short) size)
return &this->Glyphs[i];
if (this->Glyphs[i].Codepoint == codepoint) {
if(this->Glyphs[i].GlyphSize == (short) size && !result) {
result = &this->Glyphs[i]; // Save the result
if(!backup_glyph) break; //Caller didn't want a backup glyph
if((this->Glyphs[i].FontTexture && this->Glyphs[i].FontTexture->TexID != NULL) && this->Glyphs[i].FrameCountCreation != ImGui::GetFrameCount()) {
*backup_glyph = NULL; // This glyph has already been rendered and uploeaded to the graphics card. No backup glyph needed.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*backup_glyph = NULL; // This glyph has already been rendered and uploeaded to the graphics card. No backup glyph needed.
*backup_glyph = NULL; // This glyph has already been rendered and uploaded to the graphics card. No backup glyph needed.

break;
}
if(*backup_glyph)
break; //We have already found a backup glyph
//We have found the glyph but we still need a backup glyph
}
else if(backup_glyph && *backup_glyph == NULL) {
if(this->Glyphs[i].FontTexture && this->Glyphs[i].FontTexture->TexID && this->Glyphs[i].FrameCountCreation != ImGui::GetFrameCount()) { //Make sure the backup glyph has been rendered and uploaded
*backup_glyph = &this->Glyphs[i]; // Save this as a backup
if(result) break; //Both primary glyph and backup has been found
}
}
}
i = this->Glyphs[i].NextGlyph;
}

if(result) return result;

// Create this glyph.
float scale = FONT_ScaleForPixelHeight(this->PrivData, size);

Expand Down Expand Up @@ -2516,6 +2548,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar codepoint, float size)
glyph.Xoff = (float)x0;
glyph.Yoff = (float)y0;
glyph.NextGlyph = this->lut[h];
glyph.FrameCountCreation = ImGui::GetFrameCount();

// Advance row location.
br->x += gw + 1;
Expand Down Expand Up @@ -2791,31 +2824,45 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
{
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
return;
if (const ImFontGlyph* glyph = FindGlyph((unsigned int)c, size))
ImFontGlyph* backup_glyph = NULL;
if (const ImFontGlyph* glyph = FindGlyph((unsigned int)c, size, &backup_glyph))
{
float ascender = IM_FLOOR(Ascent * size);
pos.x = IM_FLOOR(pos.x + DisplayOffset.x);
pos.y = IM_FLOOR(pos.y + DisplayOffset.y);
int texture_width = glyph->FontTexture->TexWidth;
int texture_height = glyph->FontTexture->TexHeight;

ImFontTexture* glyph_texture = glyph->FontTexture;

ImFontQuad q = GetQuad(*glyph, pos.x, pos.y);

float x1 = q.x0;
float x2 = q.x1;
float y1 = ascender + q.y0;
float y2 = ascender + q.y1;

//If this glyph has not yet been rendered and uploaded to the video card
//render a stretched backup glyph instead
if(backup_glyph && (glyph_texture->TexID == NULL || glyph->FrameCountCreation == ImGui::GetFrameCount())) { // It takes a frame for the glyph to be uploaded
glyph_texture = backup_glyph->FontTexture;
q = GetQuad(*backup_glyph, pos.x, pos.y);
}

float u1 = q.u0;
float v1 = q.v0;
float u2 = q.u1;
float v2 = q.v1;

int texture_width = glyph_texture->TexWidth;
int texture_height = glyph_texture->TexHeight;

u1 /= texture_width;
u2 /= texture_width;
v1 /= texture_height;
v2 /= texture_height;

// FIXME-DYNAMICFONT: Shouldn't use AddImageQuad
draw_list->AddImageQuad(
glyph->FontTexture->TexID,
glyph_texture->TexID,
ImVec2(x1, y1),
ImVec2(x2, y1),
ImVec2(x2, y2),
Expand Down Expand Up @@ -2959,18 +3006,29 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col

float char_width = 0.0f;
float ascender = ImFloor(Ascent * size);
if (const ImFontGlyph* glyph = FindGlyph((ImWchar)c, size))
ImFontGlyph* backup_glyph = NULL; //If the correct glyph has not yet been rendered
if (const ImFontGlyph* glyph = FindGlyph((ImWchar)c, size, &backup_glyph))
{
int texture_width = glyph->FontTexture->TexWidth;
int texture_height = glyph->FontTexture->TexHeight;
ImFontTexture* glyph_texture = glyph->FontTexture;

//If this glyph has not yet been rendered and uploaded to the video card
//render a stretched backup glyph instead
bool using_backup_glyph = false;
if(backup_glyph && (glyph_texture->TexID == NULL || glyph->FrameCountCreation == ImGui::GetFrameCount())) { // It takes a frame for the glyph to be uploaded
glyph_texture = backup_glyph->FontTexture;
using_backup_glyph = true;
}

int texture_width = glyph_texture->TexWidth;
int texture_height = glyph_texture->TexHeight;

char_width = IM_ROUND(glyph->AdvanceX);/* scale*/

// Arbitrarily assume that both space and tabs are empty glyphs as an optimization
if (c != ' ' && c != '\t' && glyph->FontTexture->TexID)
if (c != ' ' && c != '\t' && glyph_texture->TexID)
{
if (!texture_selected) { //When rendering the first char we select our default texture
selected_texture = glyph->FontTexture->TexID;
selected_texture = glyph_texture->TexID;
if (draw_list->_CmdHeader.TextureId != selected_texture) {
draw_list->PushTextureID(selected_texture);
pushed_texture = true; // We need to pop later
Expand All @@ -2986,13 +3044,13 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
texture_selected = true;
}

if (glyph->FontTexture->TexID != selected_texture) {//Save the glyph for later rendering
if (glyph_texture->TexID != selected_texture) {//Save the glyph for later rendering
FontRenderList* render_list = NULL;

// Find the render list for this texture
for (FontRenderList** rlist = font_render_list.begin(); rlist != font_render_list.end(); rlist++) {
FontRenderList* rlist_ref = *rlist;
if (rlist_ref->TexID == glyph->FontTexture->TexID) {
if (rlist_ref->TexID == glyph_texture->TexID) {
render_list = rlist_ref;
break;
}
Expand All @@ -3001,7 +3059,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
if (!render_list) { // Render list for this texture not found
//Create render list for this texture
render_list = IM_NEW(FontRenderList);
render_list->TexID = glyph->FontTexture->TexID;
render_list->TexID = glyph_texture->TexID;
render_list->VtxBuffer.resize(vtx_count_max);
render_list->IdxBuffer.resize(idx_count_max);
render_list->vtx_write = render_list->VtxBuffer.Data;
Expand All @@ -3019,6 +3077,10 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
float y2 = ascender + q.y1 /* scale*/;
if (x1 <= clip_rect.z && x2 >= clip_rect.x)
{
//If using a backup glyph we need to change the texture UV's
if(using_backup_glyph) {
q = GetQuad(*backup_glyph, x, y);
}
// Render a character
float u1 = q.u0;
float v1 = q.v0;
Expand Down Expand Up @@ -3107,6 +3169,11 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
float y2 = ascender + q.y1 /* scale*/;
if (x1 <= clip_rect.z && x2 >= clip_rect.x)
{
//If using a backup glyph we need to change the texture UV's
if(using_backup_glyph) {
q = GetQuad(*backup_glyph, x, y);
}

// Render a character
float u1 = q.u0;
float v1 = q.v0;
Expand Down
2 changes: 1 addition & 1 deletion imgui_widgets.cpp
Expand Up @@ -3944,7 +3944,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// Password pushes a temporary font with only a fallback glyph
if (is_password && !is_displaying_hint)
{
const ImFontGlyph* glyph = g.Font->FindGlyph('*', g.FontSize);
const ImFontGlyph* glyph = g.Font->FindGlyph('*', g.FontSize);
ImFont* password_font = &g.InputTextPasswordFont;
//password_font->FontSize = g.Font->FontSize;
password_font->Scale = g.Font->Scale;
Expand Down