Font fallbacks.
This commit is contained in:
3
TestGame/Resources/fonts/default.fontset.toml
Normal file
3
TestGame/Resources/fonts/default.fontset.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[FontSet]
|
||||||
|
|
||||||
|
fonts = ["Inter-Regular.ttf", "NotoSansJP-Regular.ttf"]
|
||||||
@@ -54,6 +54,8 @@ public class TestGame : Game
|
|||||||
{
|
{
|
||||||
throw new Exception("Failed to load emitter settings!");
|
throw new Exception("Failed to load emitter settings!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_defaultFontSet = new([_font, _jpFont]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Ready()
|
protected override void Ready()
|
||||||
@@ -78,7 +80,7 @@ public class TestGame : Game
|
|||||||
|
|
||||||
if (Input.IsActionPressed("accept"))
|
if (Input.IsActionPressed("accept"))
|
||||||
{
|
{
|
||||||
_container.AddChild(new Label("こんにちは世界!", _jpFont));
|
_container.AddChild(new Label("こんにちは世界!", _defaultFontSet));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Input.IsActionPressed("cancel") && _container.Children.Count != 0)
|
if (Input.IsActionPressed("cancel") && _container.Children.Count != 0)
|
||||||
@@ -126,6 +128,9 @@ public class TestGame : Game
|
|||||||
private ResourceRef<ParticleEmitterSettingsResource> _fireEffect;
|
private ResourceRef<ParticleEmitterSettingsResource> _fireEffect;
|
||||||
private ResourceRef<Font> _font;
|
private ResourceRef<Font> _font;
|
||||||
private ResourceRef<Font> _jpFont;
|
private ResourceRef<Font> _jpFont;
|
||||||
|
|
||||||
|
private FontSet _defaultFontSet;
|
||||||
|
|
||||||
private ResourceRef<Sound> _sound;
|
private ResourceRef<Sound> _sound;
|
||||||
private ResourceRef<Texture2d> _icon;
|
private ResourceRef<Texture2d> _icon;
|
||||||
|
|
||||||
|
|||||||
45
Voile/Source/Resources/FontSet.cs
Normal file
45
Voile/Source/Resources/FontSet.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Voile.Resources;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains a set of multiple fonts. Used to fetch fonts based on availability of glyphs.
|
||||||
|
/// </summary>
|
||||||
|
public class FontSet
|
||||||
|
{
|
||||||
|
public FontSet() { }
|
||||||
|
|
||||||
|
public FontSet(IEnumerable<ResourceRef<Font>> fonts)
|
||||||
|
{
|
||||||
|
_fonts = fonts.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddFont(ResourceRef<Font> font) => _fonts.Add(font);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to get a suitable font that has a given character.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="c">Character to get a suitable font for.</param>
|
||||||
|
/// <param name="result">Font that contains this character.</param>
|
||||||
|
/// <returns><c>true</c> if a font that contains this character exists, <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetFontFor(char c, [NotNullWhen(true)] out ResourceRef<Font>? result)
|
||||||
|
{
|
||||||
|
result = ResourceRef<Font>.Empty();
|
||||||
|
foreach (var fontRef in _fonts)
|
||||||
|
{
|
||||||
|
if (!fontRef.TryGetValue(out var font))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.HasGlyph(c))
|
||||||
|
{
|
||||||
|
result = fontRef;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ResourceRef<Font>> _fonts = new();
|
||||||
|
}
|
||||||
@@ -52,6 +52,28 @@ namespace Voile
|
|||||||
{
|
{
|
||||||
Guid = guid;
|
Guid = guid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is ResourceRef<T> other && Guid.Equals(other.Guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Guid.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(ResourceRef<T>? left, ResourceRef<T>? right)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(left, right)) return true;
|
||||||
|
if (left is null || right is null) return false;
|
||||||
|
return left.Guid == right.Guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(ResourceRef<T>? left, ResourceRef<T>? right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ namespace Voile.Resources
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">Path to the resource.</param>
|
/// <param name="path">Path to the resource.</param>
|
||||||
/// <returns>True if a resource at the specified path is loaded, otherwise false.</returns>
|
/// <returns>True if a resource at the specified path is loaded, otherwise false.</returns>
|
||||||
public bool IsResourceLoaded(string path) => _resourcePathMap.ContainsKey(path);
|
public static bool IsResourceLoaded(string path) => _resourcePathMap.ContainsKey(path);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a resource loader associated with a resource type.
|
/// Adds a resource loader associated with a resource type.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Voile.Input;
|
using Voile.Input;
|
||||||
using Voile.Rendering;
|
using Voile.Rendering;
|
||||||
|
using Voile.Resources;
|
||||||
|
|
||||||
namespace Voile.UI.Widgets;
|
namespace Voile.UI.Widgets;
|
||||||
|
|
||||||
@@ -17,10 +18,26 @@ public class Label : Widget
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="FontSet"/> to use with this label.
|
||||||
|
/// </summary>
|
||||||
|
public FontSet FontSet { get; set; } = new();
|
||||||
|
|
||||||
public Label(string text, ResourceRef<Font> fontOverride)
|
public Label(string text, ResourceRef<Font> fontOverride)
|
||||||
{
|
{
|
||||||
_text = text;
|
_text = text;
|
||||||
_fontOverride = fontOverride;
|
|
||||||
|
FontSet.AddFont(fontOverride);
|
||||||
|
|
||||||
|
MarkDirty();
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Label(string text, FontSet fontSet)
|
||||||
|
{
|
||||||
|
_text = text;
|
||||||
|
|
||||||
|
FontSet = fontSet;
|
||||||
|
|
||||||
MarkDirty();
|
MarkDirty();
|
||||||
Update();
|
Update();
|
||||||
@@ -34,20 +51,34 @@ public class Label : Widget
|
|||||||
public override void Render(RenderSystem renderer, Style style)
|
public override void Render(RenderSystem renderer, Style style)
|
||||||
{
|
{
|
||||||
// TODO: use style here.
|
// TODO: use style here.
|
||||||
if (!_fontOverride.HasValue) return;
|
|
||||||
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
||||||
renderer.DrawText(_fontOverride, _text, Color.White);
|
renderer.DrawText(_suitableFont, _text, Color.White);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
var font = _fontOverride.Value;
|
ResourceRef<Font> fontRef = ResourceRef<Font>.Empty();
|
||||||
|
foreach (var c in _text)
|
||||||
|
{
|
||||||
|
if (FontSet.TryGetFontFor(c, out var fallbackFont))
|
||||||
|
{
|
||||||
|
if (fallbackFont != fontRef)
|
||||||
|
{
|
||||||
|
fontRef = fallbackFont;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_suitableFont = fontRef;
|
||||||
|
|
||||||
|
var font = _suitableFont.Value;
|
||||||
_textSize = font.Measure(_text);
|
_textSize = font.Measure(_text);
|
||||||
|
|
||||||
Size = _textSize;
|
Size = _textSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceRef<Font> _fontOverride = ResourceRef<Font>.Empty();
|
private ResourceRef<Font> _suitableFont = ResourceRef<Font>.Empty();
|
||||||
|
|
||||||
private string _text = "Hello, World!";
|
private string _text = "Hello, World!";
|
||||||
private Rect _textSize = Rect.Zero;
|
private Rect _textSize = Rect.Zero;
|
||||||
|
|||||||
Reference in New Issue
Block a user