WIP: measure text in Font.
This commit is contained in:
@@ -34,6 +34,8 @@ public class Font : Resource, IDisposable
|
||||
internal nint FacePtr;
|
||||
internal nint LibraryPtr;
|
||||
|
||||
internal List<int> Codepoints => _glyphs.Keys.ToList();
|
||||
|
||||
public Font(string path, byte[] buffer) : base(path)
|
||||
{
|
||||
Buffer = buffer;
|
||||
@@ -62,12 +64,38 @@ public class Font : Resource, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public void Measure(string text)
|
||||
/// <summary>
|
||||
/// Measures a given string using the font metrics.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to measure.</param>
|
||||
/// <returns>A <see cref="Rect"/> with the sizes of a given text using this font.</returns>
|
||||
public Rect Measure(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return Rect.Zero;
|
||||
|
||||
float totalWidth = 0;
|
||||
float maxAscent = 0;
|
||||
float maxDescent = 0;
|
||||
|
||||
foreach (char c in text)
|
||||
{
|
||||
var glyph = GetGlyph(c);
|
||||
|
||||
totalWidth += glyph.Advance;
|
||||
|
||||
float ascent = glyph.Bearing.Y;
|
||||
float descent = glyph.Height - glyph.Bearing.Y;
|
||||
|
||||
if (ascent > maxAscent)
|
||||
maxAscent = ascent;
|
||||
|
||||
if (descent > maxDescent)
|
||||
maxDescent = descent;
|
||||
}
|
||||
|
||||
float totalHeight = maxAscent + maxDescent;
|
||||
return new Rect(totalWidth, totalHeight);
|
||||
}
|
||||
|
||||
public Glyph GetGlyph(char character)
|
||||
@@ -80,31 +108,29 @@ public class Font : Resource, IDisposable
|
||||
return loaded;
|
||||
}
|
||||
|
||||
internal void GetGlyphBoundingBox(Glyph glyph)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private unsafe Glyph LoadGlyph(char character)
|
||||
{
|
||||
var face = (FT_FaceRec_*)FacePtr;
|
||||
|
||||
// TODO: for now, we're loading glyphs for metrics, but when implementing WebGPU rendering, we want to somehow render them to SDF or bitmap.
|
||||
FT_Error error = FT_Load_Char(face, character, FT_LOAD_NO_BITMAP);
|
||||
FT_Error error = FT_Set_Pixel_Sizes(face, 0, (uint)Size);
|
||||
error = FT_Load_Char(face, character, FT_LOAD_NO_BITMAP);
|
||||
|
||||
if (error != 0)
|
||||
throw new Exception($"Failed to load glyph for '{character}'");
|
||||
|
||||
var glyph = face->glyph;
|
||||
var bitmap = glyph->bitmap;
|
||||
var metrics = glyph->metrics;
|
||||
|
||||
return new Glyph
|
||||
{
|
||||
Width = bitmap.width,
|
||||
Height = bitmap.rows,
|
||||
Bearing = new Vector2(glyph->bitmap_left, glyph->bitmap_top),
|
||||
Width = metrics.width >> 6,
|
||||
Height = metrics.height >> 6,
|
||||
Bearing = new Vector2(metrics.horiBearingX >> 6, metrics.horiBearingY >> 6),
|
||||
Advance = (int)glyph->advance.x >> 6,
|
||||
};
|
||||
}
|
||||
|
||||
private Dictionary<char, Glyph> _glyphs = new();
|
||||
private Dictionary<int, Glyph> _glyphs = new();
|
||||
}
|
||||
@@ -65,7 +65,12 @@ namespace Voile.Resources
|
||||
var resource = ResourceManager.LoadedResources[resourceGuid];
|
||||
|
||||
ResourceManager.RemoveResource(resourceGuid);
|
||||
resource.Dispose();
|
||||
|
||||
if (resource is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6,24 +6,29 @@ namespace Voile.UI.Widgets;
|
||||
|
||||
public class Label : Widget
|
||||
{
|
||||
public override Rect MinimumSize => throw new NotImplementedException();
|
||||
public override Rect MinimumSize => _textSize;
|
||||
|
||||
public string Text { get; set; } = "Hello World!";
|
||||
|
||||
public Label(string text)
|
||||
public string Text
|
||||
{
|
||||
Text = text;
|
||||
get => _text; set
|
||||
{
|
||||
_text = value;
|
||||
MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public Label(string text, ResourceRef<Font> fontOverride)
|
||||
{
|
||||
Text = text;
|
||||
_text = text;
|
||||
_fontOverride = fontOverride;
|
||||
|
||||
MarkDirty();
|
||||
Update();
|
||||
}
|
||||
|
||||
protected override void OnInput(UIInputContext action)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
}
|
||||
|
||||
public override void Render(RenderSystem renderer, Style style)
|
||||
@@ -31,13 +36,19 @@ public class Label : Widget
|
||||
// TODO: use style here.
|
||||
if (!_fontOverride.HasValue) return;
|
||||
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
||||
renderer.DrawText(_fontOverride, Text, Color.White);
|
||||
renderer.DrawText(_fontOverride, _text, Color.White);
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var font = _fontOverride.Value;
|
||||
_textSize = font.Measure(_text);
|
||||
|
||||
Size = _textSize;
|
||||
}
|
||||
|
||||
private ResourceRef<Font> _fontOverride = ResourceRef<Font>.Empty();
|
||||
|
||||
private string _text = "Hello, World!";
|
||||
private Rect _textSize = Rect.Zero;
|
||||
}
|
||||
Reference in New Issue
Block a user