WIP: measure text in Font.
This commit is contained in:
@@ -56,10 +56,10 @@ public class TestGame : Game
|
||||
Input.AddInputMapping("reload", new IInputAction[] { new KeyInputAction(KeyboardKey.R) });
|
||||
_emitterId = _particleSystem.CreateEmitter(Renderer.WindowSize / 2, _fireEffect);
|
||||
|
||||
_fillContainer.AddChild(_marginContainer);
|
||||
_marginContainer.AddChild(_container);
|
||||
// _fillContainer.AddChild(_container);
|
||||
// _marginContainer.AddChild(_container);
|
||||
|
||||
_uiSystem.AddElement(_fillContainer);
|
||||
_uiSystem.AddElement(_container);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TestGame : Game
|
||||
|
||||
if (Input.IsActionPressed("accept"))
|
||||
{
|
||||
_container.AddChild(new RectangleWidget(new Rect(32.0f, 32.0f), MathUtils.RandomColor()));
|
||||
_container.AddChild(new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", _font));
|
||||
}
|
||||
|
||||
if (Input.IsActionPressed("cancel") && _container.Children.Count != 0)
|
||||
@@ -123,7 +123,7 @@ public class TestGame : Game
|
||||
private ResourceRef<Sound> _sound;
|
||||
private ResourceRef<Texture2d> _icon;
|
||||
|
||||
private FlexContainer _container = new(minimumSize: new Rect(64.0f, 64.0f), new())
|
||||
private FlexContainer _container = new(minimumSize: new Rect(256.0f, 256.0f), new())
|
||||
{
|
||||
Anchor = Anchor.Center,
|
||||
Direction = FlexDirection.Column,
|
||||
@@ -133,6 +133,8 @@ public class TestGame : Game
|
||||
Gap = 8.0f
|
||||
};
|
||||
|
||||
[NotNull] private Label _label;
|
||||
|
||||
private FillContainer _fillContainer = new();
|
||||
private MarginContainer _marginContainer = new(new Margin(32.0f))
|
||||
{
|
||||
|
||||
@@ -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