diff --git a/Dashboard.Drawing.OpenGL/GLEngine.cs b/Dashboard.Drawing.OpenGL/GLEngine.cs index 7f84aff..30e92d1 100644 --- a/Dashboard.Drawing.OpenGL/GLEngine.cs +++ b/Dashboard.Drawing.OpenGL/GLEngine.cs @@ -1,3 +1,4 @@ +using Dashboard.Drawing.OpenGL.Text; using OpenTK; using OpenTK.Graphics; @@ -18,6 +19,8 @@ namespace Dashboard.Drawing.OpenGL if (bindingsContext != null) GLLoader.LoadBindings(bindingsContext); + + Typesetter.Backend = BlurgEngine.Global; } public ContextExecutor GetExecutor(IGLContext glContext) diff --git a/Dashboard.Drawing.OpenGL/Text/BlurgEngine.cs b/Dashboard.Drawing.OpenGL/Text/BlurgEngine.cs index 783261c..6f2d091 100644 --- a/Dashboard.Drawing.OpenGL/Text/BlurgEngine.cs +++ b/Dashboard.Drawing.OpenGL/Text/BlurgEngine.cs @@ -1,10 +1,13 @@ +using System.Diagnostics; +using System.Drawing; +using System.Numerics; using BlurgText; using OpenTK.Graphics.OpenGL; using OPENGL = OpenTK.Graphics.OpenGL; namespace Dashboard.Drawing.OpenGL.Text { - public class BlurgEngine : IResourceManager, IGLDisposable + public class BlurgEngine : IResourceManager, IGLDisposable, ITypeSetter { public string Name { get; } = "BlurgEngine"; public Blurg Blurg { get; } @@ -12,9 +15,16 @@ namespace Dashboard.Drawing.OpenGL.Text private readonly List _textures = new List(); - public BlurgEngine() + public BlurgEngine() : this(false) { - Blurg = new Blurg(AllocateTexture, UpdateTexture); + } + + private BlurgEngine(bool global) + { + if (global) + Blurg = new Blurg(AllocateTextureGlobal, UpdateTextureGlobal); + else + Blurg = new Blurg(AllocateTexture, UpdateTexture); SystemFontsEnabled = Blurg.EnableSystemFonts(); } @@ -24,13 +34,18 @@ namespace Dashboard.Drawing.OpenGL.Text Dispose(false, true); } - public DbBlurgFont AddFont(string path) + public SizeF MeasureString(IFont font, string value) { - BlurgFont? font = Blurg.AddFontFile(path) ?? throw new Exception("Failed to load the font file."); - return new DbBlurgFont(font, 12f); + return MeasureStringInternal(InternFont(font), value); } - public DbBlurgFont AddFont(Stream stream) + private SizeF MeasureStringInternal(DbBlurgFont font, string value) + { + Vector2 v = Blurg.MeasureString(font.Font, font.Size, value); + return new SizeF(v.X, v.Y); + } + + public IFont LoadFont(Stream stream) { string path; Stream dest; @@ -55,20 +70,50 @@ namespace Dashboard.Drawing.OpenGL.Text stream.CopyTo(dest); dest.Dispose(); - DbBlurgFont? font = AddFont(path); + DbBlurgFont font = (DbBlurgFont)LoadFont(path); File.Delete(path); return font; } - public DbBlurgFont? QueryFont(string family, FontWeight weight, FontSlant slant, FontStretch stretch) + public IFont LoadFont(string path) + { + BlurgFont? font = Blurg.AddFontFile(path) ?? throw new Exception("Failed to load the font file."); + return new DbBlurgFont(Blurg, font, 12f); + } + + public IFont LoadFont(NamedFont font) { // Ignore the stretch argument. - bool italic = slant != FontSlant.Normal; - BlurgFont? font = Blurg.QueryFont(family, new BlurgText.FontWeight((int)weight), italic); + bool italic = font.Slant != FontSlant.Normal; + BlurgFont? loaded = Blurg.QueryFont(font.Family, new BlurgText.FontWeight((int)font.Weight), italic); - if (font != null) - return new DbBlurgFont(font, 12f); - return null; + if (loaded != null) + return new DbBlurgFont(Blurg, loaded, 12f); + else + throw new Exception("Font not found."); + } + + private DbBlurgFont InternFont(IFont font) + { + if (font is NamedFont named) + { + return (DbBlurgFont)LoadFont(named); + } + else if (font is DbBlurgFont dblurg) + { + if (dblurg.Owner != Blurg) + { + throw new Exception(); + } + else + { + return dblurg; + } + } + else + { + throw new Exception("Unsupported font resource."); + } } private void UpdateTexture(IntPtr texture, IntPtr buffer, int x, int y, int width, int height) @@ -122,5 +167,22 @@ namespace Dashboard.Drawing.OpenGL.Text public void Dispose() => Dispose(true, true); public void Dispose(bool safeExit) => Dispose(true, safeExit); + + /// + /// The global Blurg engine implements the needed methods for command queues to work. + /// + public static BlurgEngine Global { get; } = new BlurgEngine(true); + + private static void UpdateTextureGlobal(IntPtr userdata, IntPtr buffer, int x, int y, int width, int height) + { + // Report the user error. + Debug.WriteLine("Attempt to create or update a texture from the global BlurgEngine.", "Dashboard/BlurgEngine"); + } + + private static IntPtr AllocateTextureGlobal(int width, int height) + { + Debug.WriteLine("Attempt to create or update a texture from the global BlurgEngine.", "Dashboard/BlurgEngine"); + return IntPtr.Zero; + } } } diff --git a/Dashboard.Drawing.OpenGL/Text/DbBlurgFont.cs b/Dashboard.Drawing.OpenGL/Text/DbBlurgFont.cs index c0a5696..f6fd7b0 100644 --- a/Dashboard.Drawing.OpenGL/Text/DbBlurgFont.cs +++ b/Dashboard.Drawing.OpenGL/Text/DbBlurgFont.cs @@ -5,6 +5,7 @@ namespace Dashboard.Drawing.OpenGL.Text public class DbBlurgFont : IFont { public IDrawExtension Kind { get; } = BlurgFontExtension.Instance; + public Blurg Owner { get; } public BlurgFont Font { get; } public float Size { get; } public string Family => Font.FamilyName; @@ -12,15 +13,16 @@ namespace Dashboard.Drawing.OpenGL.Text public FontSlant Slant => Font.Italic ? FontSlant.Italic : FontSlant.Normal; public FontStretch Stretch => FontStretch.Normal; - public DbBlurgFont(BlurgFont font, float size) + public DbBlurgFont(Blurg owner, BlurgFont font, float size) { + Owner = owner; Font = font; Size = size; } public DbBlurgFont WithSize(float size) { - return new DbBlurgFont(Font, size); + return new DbBlurgFont(Owner, Font, size); } } } diff --git a/Dashboard.Drawing/DrawExtension.cs b/Dashboard.Drawing/DrawExtension.cs index 55a2d3e..6a6a77a 100644 --- a/Dashboard.Drawing/DrawExtension.cs +++ b/Dashboard.Drawing/DrawExtension.cs @@ -119,7 +119,8 @@ namespace Dashboard.Drawing Anchor anchor = Anchor.Left) { IDrawController controller = queue.GetController(DbBaseCommands.Instance); - controller.EnsureBounds(new Box2d(position.X, position.Y, position.X, position.Y), position.Z); + SizeF size = Typesetter.MeasureString(font, text); + controller.EnsureBounds(new Box2d(position.X, position.Y, position.X + size.Width, position.Y + size.Height), position.Z); controller.Write(TextExtension.Instance.TextCommand, new TextCommandArgs(font, brush, anchor, position, text)); } @@ -127,7 +128,8 @@ namespace Dashboard.Drawing float borderRadius, string text, IFont font, Anchor anchor = Anchor.Left, BorderKind borderKind = BorderKind.Outset) { IDrawController controller = queue.GetController(DbBaseCommands.Instance); - controller.EnsureBounds(new Box2d(position.X, position.Y, position.X, position.Y), position.Z); + SizeF size = Typesetter.MeasureString(font, text); + controller.EnsureBounds(new Box2d(position.X, position.Y, position.X + size.Width, position.Y + size.Height), position.Z); controller.Write(TextExtension.Instance.TextCommand, new TextCommandArgs(font, textBrush, anchor, position, text) { BorderBrush = borderBrush, diff --git a/Dashboard.Drawing/Font.cs b/Dashboard.Drawing/Font.cs index 5e58641..8739581 100644 --- a/Dashboard.Drawing/Font.cs +++ b/Dashboard.Drawing/Font.cs @@ -19,4 +19,34 @@ namespace Dashboard.Drawing public FontSlant Slant { get; } public FontStretch Stretch { get; } } + + public struct NamedFont : IFont + { + public IDrawExtension Kind { get; } = Instance; + + public string Family { get; } + public float Size { get; } + public FontWeight Weight { get; } + public FontSlant Slant { get; } + public FontStretch Stretch { get; } + + public NamedFont(string family, float size, FontWeight weight = FontWeight.Normal, + FontSlant slant = FontSlant.Normal, FontStretch stretch = FontStretch.Normal) + { + Family = family; + Size = size; + Weight = weight; + Slant = slant; + Stretch = Stretch; + } + + private static readonly IDrawExtension Instance = new Extension(); + + private class Extension : DrawExtension + { + public Extension() : base("DB_Font_Named", [FontExtension.Instance]) + { + } + } + } } diff --git a/Dashboard.Drawing/Typesetter.cs b/Dashboard.Drawing/Typesetter.cs new file mode 100644 index 0000000..4bcefa1 --- /dev/null +++ b/Dashboard.Drawing/Typesetter.cs @@ -0,0 +1,104 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Drawing; +using System.IO; +using System.Reflection.PortableExecutable; + +namespace Dashboard.Drawing +{ + /// + /// Interface for registered typesetters. + /// + public interface ITypeSetter + { + /// + /// Name of the typesetter. + /// + string Name { get; } + + SizeF MeasureString(IFont font, string value); + + IFont LoadFont(Stream stream); + IFont LoadFont(string path); + IFont LoadFont(NamedFont font); + } + + /// + /// Class for typesetting related functions. + /// + public static class Typesetter + { + /// + /// The typesetting backend for this instance. + /// + public static ITypeSetter Backend { get; set; } = new UndefinedTypeSetter(); + + public static string Name => Backend.Name; + + public static SizeF MeasureString(IFont font, string value) + { + return Backend.MeasureString(font, value); + } + + public static IFont LoadFont(Stream stream) + { + return Backend.LoadFont(stream); + } + + public static IFont LoadFont(string path) + { + return Backend.LoadFont(path); + } + + public static IFont LoadFont(FileInfo file) + { + return Backend.LoadFont(file.FullName); + } + + public static IFont LoadFont(NamedFont font) + { + return Backend.LoadFont(font); + } + + public static IFont LoadFont(string family, float size, FontWeight weight = FontWeight.Normal, + FontSlant slant = FontSlant.Normal, FontStretch stretch = FontStretch.Normal) + { + return LoadFont(new NamedFont(family, size, weight, slant, stretch)); + } + + private class UndefinedTypeSetter : ITypeSetter + { + public string Name { get; } = "Undefined"; + + [DoesNotReturn] + private void Except() + { + throw new InvalidOperationException("No typesetting backend is loaded."); + } + + public SizeF MeasureString(IFont font, string value) + { + Except(); + return default; + } + + public IFont LoadFont(Stream stream) + { + Except(); + return default; + } + + public IFont LoadFont(string path) + { + Except(); + return default; + } + + public IFont LoadFont(NamedFont font) + { + Except(); + return default; + } + } + } +} diff --git a/tests/Dashboard.TestApplication/Program.cs b/tests/Dashboard.TestApplication/Program.cs index 2567345..a27af4f 100644 --- a/tests/Dashboard.TestApplication/Program.cs +++ b/tests/Dashboard.TestApplication/Program.cs @@ -98,9 +98,7 @@ TK.Window.SetMode(wnd, WindowMode.Normal); List points = new List(); -IFont font = executor.ResourcePool.GetResourceManager() - .QueryFont("Nimbus Mono", FontWeight._500, FontSlant.Normal, FontStretch.Normal)! - .WithSize(12f); +IFont font = Typesetter.LoadFont("Nimbus Mono", 12f); queue.Text(new sys.Vector3(96, 96, 0), bg, "Hello World!", font); queue.Text(new sys.Vector3(128, 12, 0), bg, "japenis too! uwa ~~~ アホ", font);