From 165801800ed8e05058cf7102c0873047f972aaee Mon Sep 17 00:00:00 2001 From: "H. Utku Maden" Date: Tue, 24 Dec 2024 23:20:43 +0300 Subject: [PATCH] Add basic text support. --- Dashboard.Common/Anchor.cs | 14 +++ Dashboard.Common/FontProperties.cs | 40 +++++++++ Dashboard.Drawing/DbBaseCommands.cs | 24 ++--- Dashboard.Drawing/DrawExtension.cs | 25 +++++- Dashboard.Drawing/Font.cs | 22 +++++ Dashboard.Drawing/TextExtension.cs | 134 ++++++++++++++++++++++++++++ 6 files changed, 245 insertions(+), 14 deletions(-) create mode 100644 Dashboard.Common/Anchor.cs create mode 100644 Dashboard.Common/FontProperties.cs create mode 100644 Dashboard.Drawing/Font.cs create mode 100644 Dashboard.Drawing/TextExtension.cs diff --git a/Dashboard.Common/Anchor.cs b/Dashboard.Common/Anchor.cs new file mode 100644 index 0000000..0505972 --- /dev/null +++ b/Dashboard.Common/Anchor.cs @@ -0,0 +1,14 @@ +namespace Dashboard +{ + public enum Anchor + { + Auto = 0, + Right = (1 << 0), + Left = (1 << 1), + HCenter = Left | Right, + Top = (1 << 2), + Bottom = (1 << 3), + VCenter = Top | Bottom, + Middle = HCenter | VCenter, + } +} diff --git a/Dashboard.Common/FontProperties.cs b/Dashboard.Common/FontProperties.cs new file mode 100644 index 0000000..fac7d37 --- /dev/null +++ b/Dashboard.Common/FontProperties.cs @@ -0,0 +1,40 @@ +namespace Dashboard +{ + public enum FontWeight + { + _100 = 100, + _200 = 200, + _300 = 300, + _400 = 400, + _500 = 500, + _600 = 600, + _800 = 800, + _900 = 900, + + Thin = _100, + Normal = _400, + Bold = _600, + Heavy = _900, + } + + public enum FontSlant + { + Normal, + Italic, + Oblique, + } + + public enum FontStretch + { + UltraCondensed = 500, + ExtraCondensed = 625, + Condensed = 750, + SemiCondensed = 875, + Normal = 1000, + SemiExpanded = 1125, + Expanded = 1250, + ExtraExpanded = 1500, + UltraExpanded = 2000, + } + +} diff --git a/Dashboard.Drawing/DbBaseCommands.cs b/Dashboard.Drawing/DbBaseCommands.cs index cfd9a57..689616b 100644 --- a/Dashboard.Drawing/DbBaseCommands.cs +++ b/Dashboard.Drawing/DbBaseCommands.cs @@ -123,7 +123,7 @@ namespace Dashboard.Drawing public static readonly int CommandSize = Unsafe.SizeOf(); } - public enum StrikeKind + public enum BorderKind { Inset = -1, Center = 0, @@ -179,12 +179,12 @@ namespace Dashboard.Drawing break; case Mode.Strike: ref readonly RectS s = ref MemoryMarshal.AsRef(param); - args = new RectCommandArgs(s.Start, s.End, (IBrush)queue.Resources[s.StrikeBrushIndex], s.StrikeSize, s.StrikeKind); + args = new RectCommandArgs(s.Start, s.End, (IBrush)queue.Resources[s.StrikeBrushIndex], s.StrikeSize, s.BorderKind); break; default: ref readonly RectFS fs = ref MemoryMarshal.AsRef(param); args = new RectCommandArgs(fs.Start, fs.End, (IBrush)queue.Resources[fs.FillBrushIndex], - (IBrush)queue.Resources[fs.StrikeBrushIndex], fs.StrikeSize, fs.StrikeKind); + (IBrush)queue.Resources[fs.StrikeBrushIndex], fs.StrikeSize, fs.BorderKind); break; } @@ -215,7 +215,7 @@ namespace Dashboard.Drawing s.End = obj.End; s.StrikeBrushIndex = queue.RequireResource(obj.StrikeBrush!); s.StrikeSize = obj.StrikeSize; - s.StrikeKind = obj.StrikeKind; + s.BorderKind = obj.BorderKind; break; default: ref RectFS fs = ref MemoryMarshal.AsRef(param); @@ -224,7 +224,7 @@ namespace Dashboard.Drawing fs.FillBrushIndex = queue.RequireResource(obj.FillBrush!); fs.StrikeBrushIndex = queue.RequireResource(obj.StrikeBrush!); fs.StrikeSize = obj.StrikeSize; - fs.StrikeKind = obj.StrikeKind; + fs.BorderKind = obj.BorderKind; break; } @@ -240,15 +240,15 @@ namespace Dashboard.Drawing } private record struct RectF(Vector3 Start, Vector3 End, int FillBrushIndex); - private record struct RectS(Vector3 Start, Vector3 End, int StrikeBrushIndex, float StrikeSize, StrikeKind StrikeKind); - private record struct RectFS(Vector3 Start, Vector3 End, int FillBrushIndex, int StrikeBrushIndex, float StrikeSize, StrikeKind StrikeKind); + private record struct RectS(Vector3 Start, Vector3 End, int StrikeBrushIndex, float StrikeSize, BorderKind BorderKind); + private record struct RectFS(Vector3 Start, Vector3 End, int FillBrushIndex, int StrikeBrushIndex, float StrikeSize, BorderKind BorderKind); } public struct RectCommandArgs { public Vector3 Start { get; private set; } public Vector3 End { get; private set; } - public StrikeKind StrikeKind { get; private set; } = StrikeKind.Center; + public BorderKind BorderKind { get; private set; } = BorderKind.Center; public float StrikeSize { get; private set; } = 0f; public IBrush? FillBrush { get; private set; } = null; public IBrush? StrikeBrush { get; private set; } = null; @@ -261,24 +261,24 @@ namespace Dashboard.Drawing FillBrush = fillBrush; } - public RectCommandArgs(Vector3 start, Vector3 end, IBrush strikeBrush, float strikeSize, StrikeKind strikeKind) + public RectCommandArgs(Vector3 start, Vector3 end, IBrush strikeBrush, float strikeSize, BorderKind borderKind) { Start = start; End = end; StrikeBrush = strikeBrush; StrikeSize = strikeSize; - StrikeKind = strikeKind; + BorderKind = borderKind; } public RectCommandArgs(Vector3 start, Vector3 end, IBrush fillBrush, IBrush strikeBrush, float strikeSize, - StrikeKind strikeKind) + BorderKind borderKind) { Start = start; End = end; FillBrush = fillBrush; StrikeBrush = strikeBrush; StrikeSize = strikeSize; - StrikeKind = strikeKind; + BorderKind = borderKind; } } } diff --git a/Dashboard.Drawing/DrawExtension.cs b/Dashboard.Drawing/DrawExtension.cs index 36342f9..12e1da4 100644 --- a/Dashboard.Drawing/DrawExtension.cs +++ b/Dashboard.Drawing/DrawExtension.cs @@ -94,7 +94,7 @@ namespace Dashboard.Drawing } public static void Rect(this DrawQueue queue, Vector3 start, Vector3 end, IBrush strikeBrush, float strikeSize, - StrikeKind kind = StrikeKind.Center) + BorderKind kind = BorderKind.Center) { IDrawController controller = queue.GetController(DbBaseCommands.Instance); Vector3 min = Vector3.Min(start, end); @@ -104,7 +104,7 @@ namespace Dashboard.Drawing } public static void Rect(this DrawQueue queue, Vector3 start, Vector3 end, IBrush fillBrush, IBrush strikeBrush, - float strikeSize, StrikeKind kind = StrikeKind.Center) + float strikeSize, BorderKind kind = BorderKind.Center) { IDrawController controller = queue.GetController(DbBaseCommands.Instance); Vector3 min = Vector3.Min(start, end); @@ -112,5 +112,26 @@ namespace Dashboard.Drawing controller.EnsureBounds(new Box3d(min, max)); controller.Write(DbBaseCommands.Instance.DrawRectF, new RectCommandArgs(start, end, fillBrush, strikeBrush, strikeSize, kind)); } + + public static void Text(this DrawQueue queue, Vector3 position, IBrush brush, string text, IFont font, + Anchor anchor = Anchor.Left) + { + IDrawController controller = queue.GetController(DbBaseCommands.Instance); + controller.EnsureBounds(new Box3d(position, position)); + controller.Write(TextExtension.Instance.TextCommand, new TextCommandArgs(font, brush, anchor, position, text)); + } + + public static void Text(this DrawQueue queue, Vector3 position, IBrush textBrush, IBrush borderBrush, + float borderRadius, string text, IFont font, Anchor anchor = Anchor.Left, BorderKind borderKind = BorderKind.Outset) + { + IDrawController controller = queue.GetController(DbBaseCommands.Instance); + controller.EnsureBounds(new Box3d(position, position)); + controller.Write(TextExtension.Instance.TextCommand, new TextCommandArgs(font, textBrush, anchor, position, text) + { + BorderBrush = borderBrush, + BorderRadius = borderRadius, + BorderKind = borderKind, + }); + } } } diff --git a/Dashboard.Drawing/Font.cs b/Dashboard.Drawing/Font.cs new file mode 100644 index 0000000..5e58641 --- /dev/null +++ b/Dashboard.Drawing/Font.cs @@ -0,0 +1,22 @@ +using System.Linq; + +namespace Dashboard.Drawing +{ + public class FontExtension : DrawExtension + { + private FontExtension() : base("DB_Font", Enumerable.Empty()) + { + } + + public static readonly IDrawExtension Instance = new FontExtension(); + } + + public interface IFont : IDrawResource + { + public string Family { get; } + public float Size { get; } + public FontWeight Weight { get; } + public FontSlant Slant { get; } + public FontStretch Stretch { get; } + } +} diff --git a/Dashboard.Drawing/TextExtension.cs b/Dashboard.Drawing/TextExtension.cs new file mode 100644 index 0000000..253b8f0 --- /dev/null +++ b/Dashboard.Drawing/TextExtension.cs @@ -0,0 +1,134 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Dashboard.Drawing +{ + public class TextExtension : DrawExtension + { + public TextCommand TextCommand { get; } = new TextCommand(); + + private TextExtension() : base("DB_Text", new [] { FontExtension.Instance, BrushExtension.Instance }) + { + } + + public static readonly TextExtension Instance = new TextExtension(); + } + + public class TextCommand : IDrawCommand + { + public string Name { get; } = "Text"; + public IDrawExtension Extension { get; } = TextExtension.Instance; + public int Length { get; } = -1; + + public int WriteParams(DrawQueue queue, TextCommandArgs obj, Span param) + { + int size = Unsafe.SizeOf
() + obj.Text.Length + sizeof(char); + + if (param.Length < size) + return size; + + ref Header header = ref MemoryMarshal.Cast(param[0..Unsafe.SizeOf
()])[0]; + Span text = MemoryMarshal.Cast(param[Unsafe.SizeOf
()..]); + + header = new Header() + { + Font = queue.RequireResource(obj.Font), + TextBrush = queue.RequireResource(obj.TextBrush), + BorderBrush = (obj.BorderBrush != null) ? queue.RequireResource(obj.BorderBrush) : -1, + BorderRadius = (obj.BorderBrush != null) ? obj.BorderRadius : 0f, + Anchor = obj.Anchor, + Position = obj.Position, + BorderKind = obj.BorderKind, + }; + obj.Text.CopyTo(text); + + return size; + } + + public TextCommandArgs GetParams(DrawQueue queue, ReadOnlySpan param) + { + Header header = MemoryMarshal.Cast(param[0..Unsafe.SizeOf
()])[0]; + ReadOnlySpan text = MemoryMarshal.Cast(param[Unsafe.SizeOf
()..]); + + if (header.BorderBrush == -1 || header.BorderRadius == 0) + { + return new TextCommandArgs( + (IFont)queue.Resources[header.Font], + (IBrush)queue.Resources[header.TextBrush], + header.Anchor, + header.Position, + text.ToString()) + { + BorderBrush = (IBrush)queue.Resources[header.BorderBrush], + BorderRadius = header.BorderRadius, + BorderKind = header.BorderKind, + }; + } + else + { + return new TextCommandArgs( + (IFont)queue.Resources[header.Font], + (IBrush)queue.Resources[header.TextBrush], + header.Anchor, + header.Position, + text.ToString()); + } + } + + int IDrawCommand.WriteParams(DrawQueue queue, object? obj, Span param) + { + return WriteParams(queue, (TextCommandArgs)obj!, param); + } + + object? IDrawCommand.GetParams(DrawQueue queue, ReadOnlySpan param) + { + return GetParams(queue, param); + } + + private struct Header + { + private int _flags; + public int Font; + public int TextBrush; + public int BorderBrush; + public Vector3 Position; + public float BorderRadius; + + public Anchor Anchor + { + get => (Anchor)(_flags & 0xF); + set => _flags = (_flags & ~0xF) | (int)value; + } + + public BorderKind BorderKind + { + get => (_flags & INSET) switch + { + OUTSET => BorderKind.Outset, + INSET => BorderKind.Inset, + _ => BorderKind.Center, + }; + set => _flags = value switch + { + BorderKind.Outset => (_flags & ~INSET) | OUTSET, + BorderKind.Inset => (_flags & ~INSET) | INSET, + _ => (_flags & ~INSET) | CENTER, + }; + } + + private const int INSET = 0x30; + private const int CENTER = 0x00; + private const int OUTSET = 0x10; + } + } + + public record struct TextCommandArgs(IFont Font, IBrush TextBrush, Anchor Anchor, Vector3 Position, string Text) + { + public IBrush? BorderBrush { get; init; } = null; + public float BorderRadius { get; init; } = 0; + + public BorderKind BorderKind { get; init; } = BorderKind.Center; + } +}