WIP: use kerning for text measuring.

This commit is contained in:
2025-06-29 15:53:29 +02:00
parent 0ec4e45c38
commit 9bc9810c8f
3 changed files with 37 additions and 5 deletions

View File

@@ -73,7 +73,7 @@ public class TestGame : Game
if (Input.IsActionPressed("accept")) if (Input.IsActionPressed("accept"))
{ {
_container.AddChild(new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", _font)); _container.AddChild(new Label("Hello, World!", _font));
} }
if (Input.IsActionPressed("cancel") && _container.Children.Count != 0) if (Input.IsActionPressed("cancel") && _container.Children.Count != 0)

View File

@@ -31,6 +31,8 @@ public class Font : Resource, IDisposable
public byte[]? Buffer { get; private set; } public byte[]? Buffer { get; private set; }
public long BufferSize { get; set; } public long BufferSize { get; set; }
internal float UnitsPerEm;
internal nint FacePtr; internal nint FacePtr;
internal nint LibraryPtr; internal nint LibraryPtr;
@@ -78,9 +80,10 @@ public class Font : Resource, IDisposable
float maxAscent = 0; float maxAscent = 0;
float maxDescent = 0; float maxDescent = 0;
foreach (char c in text) for (int i = 0; i < text.Length; i++)
{ {
var glyph = GetGlyph(c); char c = text[i];
Glyph glyph = GetGlyph(c);
totalWidth += glyph.Advance; totalWidth += glyph.Advance;
@@ -89,15 +92,43 @@ public class Font : Resource, IDisposable
if (ascent > maxAscent) if (ascent > maxAscent)
maxAscent = ascent; maxAscent = ascent;
if (descent > maxDescent) if (descent > maxDescent)
maxDescent = descent; maxDescent = descent;
if (i > 0)
{
char prevChar = text[i - 1];
totalWidth += GetKerning(prevChar, c);
}
} }
float totalHeight = maxAscent + maxDescent; float totalHeight = maxAscent + maxDescent;
return new Rect(totalWidth, totalHeight); return new Rect(totalWidth, totalHeight);
} }
public int GetKerning(char left, char right)
{
unsafe
{
if (FacePtr == IntPtr.Zero)
return 0;
FT_FaceRec_* face = (FT_FaceRec_*)FacePtr;
uint leftIndex = FT_Get_Char_Index(face, left);
uint rightIndex = FT_Get_Char_Index(face, right);
if (leftIndex == 0 || rightIndex == 0)
return 0;
FT_Vector_ kerning;
if (FT_Get_Kerning(face, leftIndex, rightIndex, FT_Kerning_Mode_.FT_KERNING_DEFAULT, &kerning) != 0)
return 0;
return (int)kerning.x;
}
}
public Glyph GetGlyph(char character) public Glyph GetGlyph(char character)
{ {
if (_glyphs.TryGetValue(character, out var glyph)) if (_glyphs.TryGetValue(character, out var glyph))
@@ -128,7 +159,7 @@ public class Font : Resource, IDisposable
Width = metrics.width >> 6, Width = metrics.width >> 6,
Height = metrics.height >> 6, Height = metrics.height >> 6,
Bearing = new Vector2(metrics.horiBearingX >> 6, metrics.horiBearingY >> 6), Bearing = new Vector2(metrics.horiBearingX >> 6, metrics.horiBearingY >> 6),
Advance = (int)glyph->advance.x >> 6, Advance = (int)metrics.horiAdvance >> 6,
}; };
} }

View File

@@ -47,6 +47,7 @@ public class FontLoader : ResourceLoader<Font>
if (error != 0) if (error != 0)
throw new Exception("Failed to load font face"); throw new Exception("Failed to load font face");
font.UnitsPerEm = face->units_per_EM;
font.FacePtr = (nint)face; font.FacePtr = (nint)face;
} }
} }