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

Font.FindGlyph and font.Glyphs return wrong data #206

Open
babooncodes opened this issue Oct 21, 2020 · 6 comments · May be fixed by #245
Open

Font.FindGlyph and font.Glyphs return wrong data #206

babooncodes opened this issue Oct 21, 2020 · 6 comments · May be fixed by #245

Comments

@babooncodes
Copy link

Font ProggySmall.ttf everything renders and works correctly.
However if you print the contents of each glyph from ImGui.GetFont() you get uvs that dont make sense, AdvanceX that doesnt make sense etc. I tried to find the issue to the best of my knowledge, set structs to sequential in hopes that there is some layout mismatch, converted chars to utf8, the result is always the same - wrong data is provided.
I am not sure what is going on there.

here is the case where i found out the problem

static bool test = false;

    /// Draws vertical text. The position is the bottom left of the text rect.
    public static unsafe void AddTextVertical(string text, Color text_color, Vector2? position = null)
    {
        if (string.IsNullOrEmpty(text))
        {
            text = "Null";
        }

        Vector2 pos = position.HasValue ? position.Value + ImGui.GetWindowPos() : ImGui.GetCursorPos() + ImGui.GetWindowPos();
        ImDrawListPtr DrawList = ImGui.GetWindowDrawList();
        pos.x = Mathf.Round(pos.x);
        pos.y = Mathf.Round(pos.y);
        ImFontPtr font = ImGui.GetFont();

        if (!test)
        {
            var glyphs = font.Glyphs;
            for (int i = 0; i < glyphs.Size; i++)
            {
                var g = glyphs[i];
                Debug.Log("g: " + g.Codepoint + " a:" + g.AdvanceX + " v0:" + g.V0 + " v1:" + g.V1);
            }
            test = true;
        }

        byte[] bytes = Encoding.Default.GetBytes(text);
        text = Encoding.UTF8.GetString(bytes);

        ImFontGlyphPtr glyph;
        char c;
        //ImGuiContext g = *GImGui;
        Vector2 text_size = ImGui.CalcTextSize(text);

        float textX = text_size.x / text.Length;
        for (int i = 0; i < text.Length; i++)
        {
            c = text[i];

            glyph = font.FindGlyph(c);

            if (glyph.NativePtr == null) continue;

            DrawList.PrimReserve(6, 4);
            DrawList.PrimQuadUV(
                    pos + new Vector2(glyph.Y0, -glyph.X0),
                    pos + new Vector2(glyph.Y0, -glyph.X1),
                    pos + new Vector2(glyph.Y1, -glyph.X1),
                    pos + new Vector2(glyph.Y1, -glyph.X0),

                    new Vector2(glyph.U0, glyph.V0),
                    new Vector2(glyph.U1, glyph.V0),
                    new Vector2(glyph.U1, glyph.V1),
                    new Vector2(glyph.U0, glyph.V1),
                    text_color.ToUint());
            
            pos.y -= textX ;
        }

        ImGui.SetCursorPosX(text_size.y);
    }
@mellinoe
Copy link
Collaborator

mellinoe commented Nov 8, 2020

Without really knowing too much about how these low-level font details work, it's hard to say if this is expected. Are you able to get the same or similar code working with the native library directly?

@ncatlin
Copy link

ncatlin commented Jan 26, 2021

If you just want to sanity check the results from FindGlyph you could just have a test case like
Debug.Assert(fontptr.FindGlyph('B').AdvanceX == fontptr.GetCharAdvance('B'))

@ncatlin
Copy link

ncatlin commented Jan 27, 2021

This is a problem with the sizes of the first two entries in ImFontGlyph. https://github.com/ocornut/imgui/blob/3867c6c5f0eace22ce2c59ac299bae285bb84ec4/imgui.h Lists 'codepoint' and 'visible' as unsigned ints, but the compiled library seems to have 2 byte ints (?) so we need to have unsigned shorts here.

Changing in ImFontGlyph.gen.cs (or structs_and_enums.json I guess)

    public unsafe partial struct ImFontGlyph
    {
        public ushort Codepoint;  // <---
        public ushort Visible;       //  <---
        public float AdvanceX;
        public float X0;
        ---snip---
    }

makes the problem go away

@sonoro1234
Copy link

sonoro1234 commented Jan 27, 2021

struct ImFontGlyph
{
    unsigned int Codepoint : 31;
    unsigned int Visible : 1;
    float AdvanceX;
    float X0, Y0, X1, Y1;
    float U0, V0, U1, V1;
};

Codepoint and Visible are bitfields, both are in the same 32bit int, Codepoint fills the first 31 bits and Visible the last 1 bit.
So AdvanceX offset is corrected with two ushort declarations but Codepoint and Visible wont be correctly accesible.

How C# manages bitfields?
A quick and dirty solution would be to declare one field only CodepointVisible of size u32 and use the relevant bits for Codepoint or Visible.

@ncatlin
Copy link

ncatlin commented Jan 27, 2021

Ahhh, that makes sense now - I didn't recognise the bitfield syntax.

@mellinoe
Copy link
Collaborator

Yeah, bitfields are not handled at all right now. C# has no concept of a bitfield, so this will require a lot of custom handling to make these parts work. Luckily, they are very few and far between (although it seems the Tables API has added a few new instances).

@Helco Helco linked a pull request Mar 28, 2021 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants