using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Dashboard.Drawing { public class TextExtension : DrawExtension { public TextCommand TextCommand { get; } private TextExtension() : base("DB_Text", new [] { FontExtension.Instance, BrushExtension.Instance }) { TextCommand = new TextCommand(this); } public static readonly TextExtension Instance = new TextExtension(); } public class TextCommand : IDrawCommand { public string Name { get; } = "Text"; public IDrawExtension Extension { get; } public int Length { get; } = -1; public TextCommand(TextExtension ext) { Extension = ext; } public int WriteParams(DrawQueue queue, TextCommandArgs obj, Span param) { int size = Unsafe.SizeOf
() + obj.Text.Length * sizeof(char) + 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; } }