diff --git a/Voile/Source/Resources/Font.cs b/Voile/Source/Resources/Font.cs
index 9e6a998..70421bf 100644
--- a/Voile/Source/Resources/Font.cs
+++ b/Voile/Source/Resources/Font.cs
@@ -1,5 +1,9 @@
using System.Numerics;
+using FreeTypeSharp;
+using static FreeTypeSharp.FT;
+using static FreeTypeSharp.FT_LOAD;
+
namespace Voile;
public struct Glyph
@@ -16,7 +20,7 @@ public struct Glyph
///
/// Represents font data.
///
-public class Font : Resource
+public class Font : Resource, IDisposable
{
///
/// Internal handle for the font. If it got successfully loaded into the GPU, the value will be other than -1.
@@ -27,11 +31,37 @@ public class Font : Resource
public byte[]? Buffer { get; private set; }
public long BufferSize { get; set; }
+ internal nint FacePtr;
+ internal nint LibraryPtr;
+
public Font(string path, byte[] buffer) : base(path)
{
Buffer = buffer;
}
+ public void Dispose()
+ {
+ unsafe
+ {
+ if (FacePtr != IntPtr.Zero)
+ FT_Done_Face((FT_FaceRec_*)FacePtr);
+
+ if (LibraryPtr != IntPtr.Zero)
+ FT_Done_FreeType((FT_LibraryRec_*)LibraryPtr);
+ }
+ }
+
+ ///
+ /// Loads a basic ASCII charset for this font.
+ ///
+ public void LoadAsciiData()
+ {
+ for (char c = ' '; c < 127; c++)
+ {
+ GetGlyph(c);
+ }
+ }
+
public void Measure(string text)
{
foreach (char c in text)
@@ -40,9 +70,14 @@ public class Font : Resource
}
}
- internal void AddGlyph(char c, Glyph glyph)
+ public Glyph GetGlyph(char character)
{
- _glyphs.Add(c, glyph);
+ if (_glyphs.TryGetValue(character, out var glyph))
+ return glyph;
+
+ var loaded = LoadGlyph(character);
+ _glyphs[character] = loaded;
+ return loaded;
}
internal void GetGlyphBoundingBox(Glyph glyph)
@@ -50,5 +85,26 @@ public class Font : Resource
}
+ 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);
+ if (error != 0)
+ throw new Exception($"Failed to load glyph for '{character}'");
+
+ var glyph = face->glyph;
+ var bitmap = glyph->bitmap;
+
+ return new Glyph
+ {
+ Width = bitmap.width,
+ Height = bitmap.rows,
+ Bearing = new Vector2(glyph->bitmap_left, glyph->bitmap_top),
+ Advance = (int)glyph->advance.x >> 6,
+ };
+ }
+
private Dictionary _glyphs = new();
}
\ No newline at end of file
diff --git a/Voile/Source/Resources/Loaders/FontLoader.cs b/Voile/Source/Resources/Loaders/FontLoader.cs
index 67b5eca..6e3fb28 100644
--- a/Voile/Source/Resources/Loaders/FontLoader.cs
+++ b/Voile/Source/Resources/Loaders/FontLoader.cs
@@ -1,12 +1,10 @@
using System.Numerics;
-using System.Runtime.InteropServices;
using FreeTypeSharp;
using Voile.VFS;
using static FreeTypeSharp.FT;
using static FreeTypeSharp.FT_LOAD;
-using static FreeTypeSharp.FT_Render_Mode_;
namespace Voile.Resources;
@@ -28,67 +26,28 @@ public class FontLoader : ResourceLoader
result.BufferSize = bytesRead;
LoadFaceData(result);
+ result.LoadAsciiData();
return result;
}
private unsafe void LoadFaceData(Font font)
{
- LoadFreeType();
+ FT_LibraryRec_* lib;
+ FT_Error error = FT_Init_FreeType(&lib);
+ if (error != 0)
+ throw new Exception("Failed to init FreeType");
- fixed (FT_LibraryRec_** lib = &_lib)
+ font.LibraryPtr = (nint)lib;
+
+ fixed (byte* data = font.Buffer)
{
- fixed (FT_FaceRec_* face = &_face)
- {
- FT_Error error;
+ FT_FaceRec_* face;
+ error = FT_New_Memory_Face(lib, data, (nint)font.BufferSize, 0, &face);
+ if (error != 0)
+ throw new Exception("Failed to load font face");
- var buffer = new Memory(font.Buffer);
- var handle = buffer.Pin();
-
- error = FT_New_Memory_Face(*lib, (byte*)handle.Pointer, (nint)font.BufferSize, 0, &face);
- error = FT_Set_Pixel_Sizes(face, 0, (uint)font.Size);
-
- error = FT_Select_Charmap(face, FT_Encoding_.FT_ENCODING_UNICODE);
-
- uint gid;
- var charcode = FT_Get_First_Char(face, &gid);
-
- while (gid != 0)
- {
- Console.WriteLine($"Codepoint: {(char)charcode}, gid {gid}");
- charcode = FT_Get_Next_Char(face, charcode, &gid);
- }
-
- error = FT_Load_Char(face, 'F', FT_LOAD_NO_BITMAP);
-
- var metrics = face->glyph->metrics;
-
- font.AddGlyph('F', new Glyph()
- {
- Width = metrics.width >> 6,
- Height = metrics.height >> 6,
- Bearing = new Vector2(metrics.horiBearingX >> 6, metrics.horiBearingY >> 6),
- Advance = (int)metrics.horiAdvance >> 6,
- });
-
- FT_Done_Face(face);
- FT_Done_FreeType(*lib);
- }
+ font.FacePtr = (nint)face;
}
}
-
- private unsafe void LoadFreeType()
- {
- fixed (FT_LibraryRec_** lib = &_lib)
- {
- FT_Error error;
- if (_lib == null)
- {
- error = FT_Init_FreeType(lib);
- }
- }
- }
-
- private unsafe FT_LibraryRec_* _lib;
- private unsafe FT_FaceRec_ _face;
}
\ No newline at end of file
diff --git a/Voile/Source/Resources/Resource.cs b/Voile/Source/Resources/Resource.cs
index 7ef4a76..6ab34b9 100644
--- a/Voile/Source/Resources/Resource.cs
+++ b/Voile/Source/Resources/Resource.cs
@@ -57,7 +57,7 @@ namespace Voile
///
/// Represents data usable by Voile.
///
- public abstract class Resource : IDisposable
+ public abstract class Resource
{
///
/// Path to this resource.
@@ -68,9 +68,5 @@ namespace Voile
{
Path = path;
}
-
- public void Dispose()
- {
- }
}
}
\ No newline at end of file