imgui icon indicating copy to clipboard operation
imgui copied to clipboard

Jittering Font Rendering when scaling with `ImGui::SetWindowFontScale`

Open corgifist opened this issue 1 year ago • 8 comments

Version/Branch of Dear ImGui:

Version 1.90.6, Branch: docking

Back-ends:

imgui_impl_opengl.cpp + imgui_impl_glfw3.cpp

Compiler, OS:

Windows 10 64-Bit + MinGW G++ 14.1.0

Full config/build information:

Dear ImGui 1.90.6 (19060)
--------------------------------

sizeof(size_t): 8, sizeof(ImDrawIdx): 4, sizeof(ImDrawVert): 20
define: __cplusplus=202002
define: _WIN32
define: _WIN64
define: __MINGW32__
define: __MINGW64__
define: __GNUC__=14
define: IMGUI_HAS_VIEWPORT
define: IMGUI_HAS_DOCK
--------------------------------

io.BackendPlatformName: imgui_impl_glfw
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00008441
 NavEnableKeyboard
 DockingEnable
 ViewportsEnable
 DpiEnableScaleFonts
io.ConfigViewportsNoDecoration
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x00001C06
 HasMouseCursors
 HasSetMousePos
 PlatformHasViewports
 HasMouseHoveredViewport
 RendererHasViewports
--------------------------------

io.Fonts: 2 fonts, Flags: 0x00000000, TexSize: 2048,4096
io.DisplaySize: 1920.00,1017.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------

style.WindowPadding: 12.00,12.00
style.WindowBorderSize: 1.00
style.FramePadding: 8.00,3.00
style.FrameRounding: 2.00
style.FrameBorderSize: 1.00
style.ItemSpacing: 4.00,6.00
style.ItemInnerSpacing: 6.00,6.00

Details:

My Issue/Question:

Hello! Currently I'm having two fonts loaded in my application:

  • One font with 16.0f with RasterizerDensity set to 1 (the default value)
  • One font with 16.0f but with RasterizerDensity set to 5 (I'm using thedmd's node editor, so I'm using this ultra-dense font as a workaround for zooming

I noticed that when using ImGui::SetWindowFontScale(1.5f); the baseline of the font becomes wrong and it results in the rendered text being jittery.

I'm loading fonts using the io.Fonts->AddFontFromMemoryCompressedTTF() with cyrillic glyph ranges included and disabled PixelSnapH

Screenshots/Video:

I made a little comparasion between different SetWindowFontScale values: (In the screensots below I was using the font with RasterizerDensity set to 5) (The test pharse is Attribute | Blending | Easing because you can clearly see the jittering with it)

  • 1.4 font scale, no jittering spotted image

  • 1.5 font scale, the peak jitteriness image

  • 1.6 font scale, for some reasons one letters seem to be narrower than others (like the seccond t in Attribute) image

  • 1.7 font scale, jittering disappears image

When using font scale bigger than 1.7 the jittering disappears completely and the text looks normal as it should look image

Minimal, Complete and Verifiable Example code:

ImGui::Begin("Text Jittering");

ImFontConfig fontCfg = {};
fontCfg.RasterizerDensity = 5;

auto someVeryDenseFont = io.Fonts->AddFontFromMemoryCompressedTTF(
                    s_someFontBytes, s_someFontSize,
                    16.0f, &fontCfg, io.Fonts->GetGlyphRangesCyrillic());


ImGui::PushFont(someVeryDenseFont);
ImGui::SetWindowFontScale(1.5f);
ImGui::Text("Blending | Attribute | Easing");
ImGui::SetWindowFontScale(1.0f);
ImGui::PopFont();

ImGui::End();

(EDIT: Fixed some typo in MCVE)

corgifist avatar Aug 27 '24 18:08 corgifist

I'm currently using FreeType rasterizer. This issue exists in stb_truetype rasterizer too

corgifist avatar Aug 27 '24 18:08 corgifist

Current workaround is just using 1.7 font scale instead of 1.5. Size difference between them is not very noticeable and this fixes the problem of jittering

corgifist avatar Aug 28 '24 07:08 corgifist

This issue also exists in master branch. The jittering occurs with almost every font that comes pre-pacakged in the misc/fonts/ folder All screenshots below are using stb_truetype rasterizer: image image image

Changing font rasterizer to FreeType doesn't fix the jittering

Very intresting that fonts like Cousine-Regular and ProggyClean are not jittering at all (or produce very little jittering) image image

Config/Build Info of this test project:

Dear ImGui 1.91.1 WIP (19104)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=201703
define: _WIN32
define: _WIN64
define: __MINGW32__
define: __MINGW64__
define: __GNUC__=14
--------------------------------
io.BackendPlatformName: imgui_impl_glfw
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00000003
 NavEnableKeyboard
 NavEnableGamepad
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x0000000E
 HasMouseCursors
 HasSetMousePos
 RendererHasVtxOffset
--------------------------------
io.Fonts: 2 fonts, Flags: 0x00000000, TexSize: 1024,1024
io.DisplaySize: 1920.00,1017.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 1.00
style.FramePadding: 4.00,3.00
style.FrameRounding: 0.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 8.00,4.00
style.ItemInnerSpacing: 4.00,4.00

corgifist avatar Aug 28 '24 11:08 corgifist

I managed to fix this glyph misalignment bug! Here's what I did:

  • In file imgui_draw.cpp in function void ImFont::RenderText() I changed these lines:
        ...
        if (glyph->Visible)
        {
            // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w
            float x1 = x + glyph->X0 * scale;
            float x2 = x + glyph->X1 * scale;
            float y1 = y + glyph->Y0 * scale;
            float y2 = y + glyph->Y1 * scale;
            if (x1 <= clip_rect.z && x2 >= clip_rect.x)
            {
            ...
 

To these lines:

        ...
        if (glyph->Visible)
        {
            // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w
            float x1 = x + glyph->X0 * scale;
            float x2 = x + glyph->X1 * scale;
            float y1 = y + IM_TRUNC(glyph->Y0 * scale);
            float y2 = y + IM_TRUNC(glyph->Y1 * scale);
            if (x1 <= clip_rect.z && x2 >= clip_rect.x)
            {
        ...

Here's the difference: image image

I'm gonna make a pull request soon :) EDIT: I just made a pull request proposing a fix for this issue #7929

corgifist avatar Aug 28 '24 16:08 corgifist

My pull request fixes the problem only partially. When using SetWindowFontScale with values like 1.75, 1.76, 1.86 the misalignment returns. I'm gonna investigate futrher. Any help will be appreciated

image

corgifist avatar Aug 28 '24 19:08 corgifist

I'm currently struggling to fully fix this issue. Really don't sure what exactly causes this issue :(

corgifist avatar Aug 30 '24 10:08 corgifist

This may just be due to how font design works. Some font letter shapes exceed their bounds slightly to compensate for perceived sizes.

The issue is that, without antialiasing, rounding or truncating sizes will bring these variances into sharp contrast at various scalings.

Not sure there may be much you can do about it. If you know the exact font you can compensate by doing truncation on the scaling value.

lailoken avatar Aug 30 '24 10:08 lailoken

Non integer height fonts are not really supported by the layout system anyway, and SetWindowFontScale() leading to that case isn't well supported as well. In theory we could make ImGuiWindow::CalcFontSize() round the value but this is going to have other side effects so I'll be working on that later.

ocornut avatar Sep 04 '24 14:09 ocornut