diff --git a/TestGame/Resources/fonts/NotoSansJP-Regular.ttf b/TestGame/Resources/fonts/NotoSansJP-Regular.ttf new file mode 100644 index 0000000..7c15c59 Binary files /dev/null and b/TestGame/Resources/fonts/NotoSansJP-Regular.ttf differ diff --git a/TestGame/TestGame.cs b/TestGame/TestGame.cs index 2b24d34..c8a9e62 100644 --- a/TestGame/TestGame.cs +++ b/TestGame/TestGame.cs @@ -42,6 +42,11 @@ public class TestGame : Game } + if (!ResourceManager.TryLoad("fonts/NotoSansJP-Regular.ttf", out _jpFont)) + { + + } + ResourceManager.TryLoad("icon.png", out _icon); ResourceManager.TryLoad("sounds/test_sound_mono.ogg", out _sound); @@ -73,7 +78,7 @@ public class TestGame : Game if (Input.IsActionPressed("accept")) { - _container.AddChild(new Label("Hello, World!", _font)); + _container.AddChild(new Label("こんにちは世界!", _jpFont)); } if (Input.IsActionPressed("cancel") && _container.Children.Count != 0) @@ -120,6 +125,7 @@ public class TestGame : Game private int _emitterId; private ResourceRef _fireEffect; private ResourceRef _font; + private ResourceRef _jpFont; private ResourceRef _sound; private ResourceRef _icon; diff --git a/Voile/Source/Rendering/RaylibRenderSystem.cs b/Voile/Source/Rendering/RaylibRenderSystem.cs index 82ca3b6..fb8f189 100644 --- a/Voile/Source/Rendering/RaylibRenderSystem.cs +++ b/Voile/Source/Rendering/RaylibRenderSystem.cs @@ -244,6 +244,12 @@ namespace Voile.Rendering LoadFont(font); } + if (font.Dirty && font.Handle != -1) + { + UnloadFont(font); + LoadFont(font); + } + var rayFont = _fontPool[font.Handle]; Raylib.DrawTextPro(rayFont, text, transformPosition, transformPivot, transformRotation, font.Size, 0.0f, VoileColorToRaylibColor(color)); @@ -268,10 +274,10 @@ namespace Voile.Rendering { Raylib_cs.Font fontRay; - string ext = ".ttf"; // TODO: don't use a hardcoded extension. - int fontChars = 250; // TODO: control this dynamically to not load the entire font. + string ext = ".ttf"; + int fontChars = font.Codepoints.Count; - fontRay = Raylib.LoadFontFromMemory(ext, font.Buffer, font.Size, null, fontChars); + fontRay = Raylib.LoadFontFromMemory(ext, font.Buffer, font.Size, font.Codepoints.ToArray(), fontChars); Raylib.GenTextureMipmaps(ref fontRay.Texture); Raylib.SetTextureFilter(fontRay.Texture, TextureFilter.Bilinear); @@ -281,6 +287,14 @@ namespace Voile.Rendering font.Handle = _fontPool.Count - 1; } + private void UnloadFont(Font font) + { + var fontRay = _fontPool[font.Handle]; + Raylib.UnloadFont(fontRay); + + _fontPool.RemoveAt(font.Handle); + } + private void LoadTexture(Texture2d texture) { Image image = new(); diff --git a/Voile/Source/Resources/Font.cs b/Voile/Source/Resources/Font.cs index f9bece5..7793df6 100644 --- a/Voile/Source/Resources/Font.cs +++ b/Voile/Source/Resources/Font.cs @@ -20,7 +20,7 @@ public struct Glyph /// /// Represents font data. /// -public class Font : Resource, IDisposable +public class Font : Resource, IUpdatableResource, IDisposable { /// /// Internal handle for the font. If it got successfully loaded into the GPU, the value will be other than -1. @@ -31,6 +31,8 @@ public class Font : Resource, IDisposable public byte[]? Buffer { get; private set; } public long BufferSize { get; set; } + public bool Dirty => _dirty; + internal float UnitsPerEm; internal nint FacePtr; @@ -131,14 +133,31 @@ public class Font : Resource, IDisposable public Glyph GetGlyph(char character) { + if (!HasGlyph(character)) + { + _glyphs.TryGetValue('?', out var defGlyph); + return defGlyph; + } if (_glyphs.TryGetValue(character, out var glyph)) return glyph; var loaded = LoadGlyph(character); _glyphs[character] = loaded; + + _dirty = true; + return loaded; } + public bool HasGlyph(char character) + { + unsafe + { + var face = (FT_FaceRec_*)FacePtr; + return FT_Get_Char_Index(face, character) != 0; + } + } + private unsafe Glyph LoadGlyph(char character) { var face = (FT_FaceRec_*)FacePtr; @@ -163,5 +182,11 @@ public class Font : Resource, IDisposable }; } + public void MarkUpdated() + { + _dirty = false; + } + + private bool _dirty; private Dictionary _glyphs = new(); } \ No newline at end of file diff --git a/Voile/Source/Resources/Resource.cs b/Voile/Source/Resources/Resource.cs index 6ab34b9..272615b 100644 --- a/Voile/Source/Resources/Resource.cs +++ b/Voile/Source/Resources/Resource.cs @@ -69,4 +69,20 @@ namespace Voile Path = path; } } + + /// + /// Represents a Resource that requires systems to react to its changes. + /// + public interface IUpdatableResource + { + /// + /// Gets a value indicating whether this resource's state has changed and needs to be reloaded. + /// + bool Dirty { get; } + + /// + /// Marks this resource as updated. + /// + void MarkUpdated(); + } } \ No newline at end of file