Compare commits
7 Commits
8bc2685206
...
1067d3e188
Author | SHA1 | Date | |
---|---|---|---|
1067d3e188 | |||
1b6bf09f95 | |||
509bad221f | |||
9ab2edffee | |||
1a1e761326 | |||
34720970ff | |||
c706e16db1 |
31
Dashboard.Common/Box3d.cs
Normal file
31
Dashboard.Common/Box3d.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Dashboard
|
||||
{
|
||||
public readonly record struct Box3d(Vector3 Min, Vector3 Max)
|
||||
{
|
||||
public float Left => Min.X;
|
||||
public float Right => Max.X;
|
||||
public float Top => Min.Y;
|
||||
public float Bottom => Max.Y;
|
||||
public float Far => Min.Z;
|
||||
public float Near => Max.Z;
|
||||
|
||||
public Vector3 Size => Max - Min;
|
||||
public Vector3 Center => Min + Size / 2f;
|
||||
|
||||
public static Box3d Union(Box3d left, Box3d right)
|
||||
{
|
||||
Vector3 min = Vector3.Min(left.Min, right.Min);
|
||||
Vector3 max = Vector3.Max(left.Max, right.Max);
|
||||
return new Box3d(min, max);
|
||||
}
|
||||
|
||||
public static Box3d Intersect(Box3d left, Box3d right)
|
||||
{
|
||||
Vector3 min = Vector3.Max(left.Min, right.Min);
|
||||
Vector3 max = Vector3.Min(left.Max, right.Max);
|
||||
return new Box3d(min, max);
|
||||
}
|
||||
}
|
||||
}
|
9
Dashboard.Common/Dashboard.Common.csproj
Normal file
9
Dashboard.Common/Dashboard.Common.csproj
Normal file
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
38
Dashboard.Common/HashList.cs
Normal file
38
Dashboard.Common/HashList.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Dashboard.Drawing
|
||||
{
|
||||
public class HashList<T> : IReadOnlyList<T>
|
||||
where T : notnull
|
||||
{
|
||||
private readonly List<T> _list = new List<T>();
|
||||
private readonly Dictionary<T, int> _map = new Dictionary<T, int>();
|
||||
|
||||
public T this[int index] => _list[index];
|
||||
|
||||
public int Count => _list.Count;
|
||||
|
||||
public int Intern(T value)
|
||||
{
|
||||
if (_map.TryGetValue(value, out int index))
|
||||
return index;
|
||||
|
||||
index = Count;
|
||||
|
||||
_list.Add(value);
|
||||
_map.Add(value, index);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_list.Clear();
|
||||
_map.Clear();
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
|
||||
}
|
||||
}
|
@ -6,4 +6,8 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dashboard.Common\Dashboard.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
@ -9,6 +10,10 @@ namespace Dashboard.Drawing
|
||||
public class DbBaseCommands : DrawExtension
|
||||
{
|
||||
public DrawCommand<PointCommandArgs> DrawPoint { get; }
|
||||
public DrawCommand<LineCommandArgs> DrawLine { get; }
|
||||
public RectCommand DrawRectF { get; }
|
||||
public RectCommand DrawRectS { get; }
|
||||
public RectCommand DrawRectFS { get; }
|
||||
|
||||
private DbBaseCommands() : base("DB_base",
|
||||
new[]
|
||||
@ -17,6 +22,10 @@ namespace Dashboard.Drawing
|
||||
})
|
||||
{
|
||||
AddCommand(DrawPoint = new DrawCommand<PointCommandArgs>("Point", this, PointCommandArgs.CommandSize));
|
||||
AddCommand(DrawLine = new DrawCommand<LineCommandArgs>("Line", this, LineCommandArgs.CommandSize));
|
||||
AddCommand(DrawRectF = new RectCommand(RectCommand.Mode.Fill));
|
||||
AddCommand(DrawRectS = new RectCommand(RectCommand.Mode.Strike));
|
||||
AddCommand(DrawRectFS = new RectCommand(RectCommand.Mode.FillStrike));
|
||||
}
|
||||
|
||||
public static readonly DbBaseCommands Instance = new DbBaseCommands();
|
||||
@ -66,4 +75,210 @@ namespace Dashboard.Drawing
|
||||
|
||||
public static readonly int CommandSize = Unsafe.SizeOf<Value>();
|
||||
}
|
||||
|
||||
public struct LineCommandArgs : IParameterSerializer<LineCommandArgs>
|
||||
{
|
||||
public Vector3 Start { get; private set; }
|
||||
public Vector3 End { get; private set; }
|
||||
public float Size { get; private set; }
|
||||
public IBrush? Brush { get; private set; }
|
||||
|
||||
public LineCommandArgs(Vector3 start, Vector3 end, float size, IBrush brush)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
Brush = brush;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
public int Serialize(DrawQueue queue, Span<byte> bytes)
|
||||
{
|
||||
if (bytes.Length < CommandSize)
|
||||
return CommandSize;
|
||||
|
||||
Span<Value> value = stackalloc Value[]
|
||||
{
|
||||
new Value(Start, End, Size, queue.RequireResource(Brush!))
|
||||
};
|
||||
|
||||
MemoryMarshal.AsBytes(value).CopyTo(bytes);
|
||||
return CommandSize;
|
||||
}
|
||||
|
||||
public void Deserialize(DrawQueue queue, ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if (bytes.Length < CommandSize)
|
||||
throw new Exception("Not enough bytes");
|
||||
|
||||
Value value = MemoryMarshal.AsRef<Value>(bytes);
|
||||
|
||||
Start = value.Start;
|
||||
End = value.End;
|
||||
Size = value.Size;
|
||||
Brush = (IBrush)queue.Resources[value.BrushIndex];
|
||||
}
|
||||
|
||||
private record struct Value(Vector3 Start, Vector3 End, float Size, int BrushIndex);
|
||||
|
||||
public static readonly int CommandSize = Unsafe.SizeOf<Value>();
|
||||
}
|
||||
|
||||
public enum StrikeKind
|
||||
{
|
||||
Inset = -1,
|
||||
Center = 0,
|
||||
Outset = 1,
|
||||
}
|
||||
|
||||
public class RectCommand : IDrawCommand<RectCommandArgs>
|
||||
{
|
||||
private readonly Mode _mode;
|
||||
public string Name { get; }
|
||||
public IDrawExtension Extension { get; }
|
||||
public int Length { get; }
|
||||
|
||||
public RectCommand(Mode mode)
|
||||
{
|
||||
Extension = DbBaseCommands.Instance;
|
||||
_mode = mode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case Mode.Fill:
|
||||
Name = "RectF";
|
||||
Length = Unsafe.SizeOf<RectF>();
|
||||
break;
|
||||
case Mode.Strike:
|
||||
Name = "RectS";
|
||||
Length = Unsafe.SizeOf<RectS>();
|
||||
break;
|
||||
default:
|
||||
Name = "RectFS";
|
||||
Length = Unsafe.SizeOf<RectFS>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
object? IDrawCommand.GetParams(DrawQueue queue, ReadOnlySpan<byte> param)
|
||||
{
|
||||
return GetParams(queue, param);
|
||||
}
|
||||
|
||||
public RectCommandArgs GetParams(DrawQueue queue, ReadOnlySpan<byte> param)
|
||||
{
|
||||
if (param.Length < Length)
|
||||
throw new Exception("Not enough bytes");
|
||||
|
||||
RectCommandArgs args;
|
||||
|
||||
switch (_mode)
|
||||
{
|
||||
case Mode.Fill:
|
||||
ref readonly RectF f = ref MemoryMarshal.AsRef<RectF>(param);
|
||||
args = new RectCommandArgs(f.Start, f.End, (IBrush)queue.Resources[f.FillBrushIndex]);
|
||||
break;
|
||||
case Mode.Strike:
|
||||
ref readonly RectS s = ref MemoryMarshal.AsRef<RectS>(param);
|
||||
args = new RectCommandArgs(s.Start, s.End, (IBrush)queue.Resources[s.StrikeBrushIndex], s.StrikeSize, s.StrikeKind);
|
||||
break;
|
||||
default:
|
||||
ref readonly RectFS fs = ref MemoryMarshal.AsRef<RectFS>(param);
|
||||
args = new RectCommandArgs(fs.Start, fs.End, (IBrush)queue.Resources[fs.FillBrushIndex],
|
||||
(IBrush)queue.Resources[fs.StrikeBrushIndex], fs.StrikeSize, fs.StrikeKind);
|
||||
break;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
public int WriteParams(DrawQueue queue, object? obj, Span<byte> param)
|
||||
{
|
||||
return WriteParams(queue, (RectCommandArgs)obj, param);
|
||||
}
|
||||
|
||||
public int WriteParams(DrawQueue queue, RectCommandArgs obj, Span<byte> param)
|
||||
{
|
||||
if (param.Length < Length)
|
||||
return Length;
|
||||
|
||||
switch (_mode)
|
||||
{
|
||||
case Mode.Fill:
|
||||
ref RectF f = ref MemoryMarshal.AsRef<RectF>(param);
|
||||
f.Start = obj.Start;
|
||||
f.End = obj.End;
|
||||
f.FillBrushIndex = queue.RequireResource(obj.FillBrush!);
|
||||
break;
|
||||
case Mode.Strike:
|
||||
ref RectS s = ref MemoryMarshal.AsRef<RectS>(param);
|
||||
s.Start = obj.Start;
|
||||
s.End = obj.End;
|
||||
s.StrikeBrushIndex = queue.RequireResource(obj.StrikeBrush!);
|
||||
s.StrikeSize = obj.StrikeSize;
|
||||
s.StrikeKind = obj.StrikeKind;
|
||||
break;
|
||||
default:
|
||||
ref RectFS fs = ref MemoryMarshal.AsRef<RectFS>(param);
|
||||
fs.Start = obj.Start;
|
||||
fs.End = obj.End;
|
||||
fs.FillBrushIndex = queue.RequireResource(obj.FillBrush!);
|
||||
fs.StrikeBrushIndex = queue.RequireResource(obj.StrikeBrush!);
|
||||
fs.StrikeSize = obj.StrikeSize;
|
||||
fs.StrikeKind = obj.StrikeKind;
|
||||
break;
|
||||
}
|
||||
|
||||
return Length;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum Mode
|
||||
{
|
||||
Fill = 1,
|
||||
Strike = 2,
|
||||
FillStrike = Fill | Strike,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public struct RectCommandArgs
|
||||
{
|
||||
public Vector3 Start { get; private set; }
|
||||
public Vector3 End { get; private set; }
|
||||
public StrikeKind StrikeKind { get; private set; } = StrikeKind.Center;
|
||||
public float StrikeSize { get; private set; } = 0f;
|
||||
public IBrush? FillBrush { get; private set; } = null;
|
||||
public IBrush? StrikeBrush { get; private set; } = null;
|
||||
public bool IsStruck => StrikeSize != 0;
|
||||
|
||||
public RectCommandArgs(Vector3 start, Vector3 end, IBrush fillBrush)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
FillBrush = fillBrush;
|
||||
}
|
||||
|
||||
public RectCommandArgs(Vector3 start, Vector3 end, IBrush strikeBrush, float strikeSize, StrikeKind strikeKind)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
StrikeBrush = strikeBrush;
|
||||
StrikeSize = strikeSize;
|
||||
StrikeKind = strikeKind;
|
||||
}
|
||||
|
||||
public RectCommandArgs(Vector3 start, Vector3 end, IBrush fillBrush, IBrush strikeBrush, float strikeSize,
|
||||
StrikeKind strikeKind)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
FillBrush = fillBrush;
|
||||
StrikeBrush = strikeBrush;
|
||||
StrikeSize = strikeSize;
|
||||
StrikeKind = strikeKind;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ namespace Dashboard.Drawing
|
||||
/// <param name="param">The parameter array.</param>
|
||||
/// <returns>The parameters object.</returns>
|
||||
object? GetParams(DrawQueue queue, ReadOnlySpan<byte> param);
|
||||
|
||||
int WriteParams(DrawQueue queue, object? obj, Span<byte> param);
|
||||
}
|
||||
|
||||
public interface IDrawCommand<T> : IDrawCommand
|
||||
@ -39,6 +41,8 @@ namespace Dashboard.Drawing
|
||||
/// <param name="param">The parameter array.</param>
|
||||
/// <returns>The parameters object.</returns>
|
||||
new T? GetParams(DrawQueue queue, ReadOnlySpan<byte> param);
|
||||
|
||||
new int WriteParams(DrawQueue queue, T? obj, Span<byte> param);
|
||||
}
|
||||
|
||||
public sealed class DrawCommand : IDrawCommand
|
||||
@ -57,6 +61,11 @@ namespace Dashboard.Drawing
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public int WriteParams(DrawQueue queue, object? obj, Span<byte> param)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DrawCommand<T> : IDrawCommand<T>
|
||||
@ -80,6 +89,16 @@ namespace Dashboard.Drawing
|
||||
return t;
|
||||
}
|
||||
|
||||
public int WriteParams(DrawQueue queue, T? obj, Span<byte> param)
|
||||
{
|
||||
return obj!.Serialize(queue, param);
|
||||
}
|
||||
|
||||
int IDrawCommand.WriteParams(DrawQueue queue, object? obj, Span<byte> param)
|
||||
{
|
||||
return WriteParams(queue, (T?)obj, param);
|
||||
}
|
||||
|
||||
object? IDrawCommand.GetParams(DrawQueue queue, ReadOnlySpan<byte> param)
|
||||
{
|
||||
return GetParams(queue, param);
|
||||
|
@ -64,9 +64,53 @@ namespace Dashboard.Drawing
|
||||
|
||||
public static void Point(this DrawQueue queue, Vector3 position, float size, IBrush brush)
|
||||
{
|
||||
var controller = queue.GetController(DbBaseCommands.Instance);
|
||||
controller.EnsureSize(position);
|
||||
Vector3 radius = new Vector3(size / 2f);
|
||||
Box3d bounds = new Box3d(position - radius, position + radius);
|
||||
|
||||
IDrawController controller = queue.GetController(DbBaseCommands.Instance);
|
||||
controller.EnsureBounds(bounds);
|
||||
controller.Write(DbBaseCommands.Instance.DrawPoint, new PointCommandArgs(position, size, brush));
|
||||
}
|
||||
|
||||
public static void Line(this DrawQueue queue, Vector3 start, Vector3 end, float size, IBrush brush)
|
||||
{
|
||||
Vector3 radius = new Vector3(size / 2f);
|
||||
Vector3 min = Vector3.Min(start, end) - radius;
|
||||
Vector3 max = Vector3.Max(start, end) + radius;
|
||||
Box3d bounds = new Box3d(min, max);
|
||||
|
||||
IDrawController controller = queue.GetController(DbBaseCommands.Instance);
|
||||
controller.EnsureBounds(bounds);
|
||||
controller.Write(DbBaseCommands.Instance.DrawLine, new LineCommandArgs(start, end, size, brush));
|
||||
}
|
||||
|
||||
public static void Rect(this DrawQueue queue, Vector3 start, Vector3 end, IBrush fillBrush)
|
||||
{
|
||||
IDrawController controller = queue.GetController(DbBaseCommands.Instance);
|
||||
Vector3 min = Vector3.Min(start, end);
|
||||
Vector3 max = Vector3.Max(start, end);
|
||||
controller.EnsureBounds(new Box3d(min, max));
|
||||
controller.Write(DbBaseCommands.Instance.DrawRectF, new RectCommandArgs(start, end, fillBrush));
|
||||
}
|
||||
|
||||
public static void Rect(this DrawQueue queue, Vector3 start, Vector3 end, IBrush strikeBrush, float strikeSize,
|
||||
StrikeKind kind = StrikeKind.Center)
|
||||
{
|
||||
IDrawController controller = queue.GetController(DbBaseCommands.Instance);
|
||||
Vector3 min = Vector3.Min(start, end);
|
||||
Vector3 max = Vector3.Max(start, end);
|
||||
controller.EnsureBounds(new Box3d(min, max));
|
||||
controller.Write(DbBaseCommands.Instance.DrawRectF, new RectCommandArgs(start, end, strikeBrush, strikeSize, kind));
|
||||
}
|
||||
|
||||
public static void Rect(this DrawQueue queue, Vector3 start, Vector3 end, IBrush fillBrush, IBrush strikeBrush,
|
||||
float strikeSize, StrikeKind kind = StrikeKind.Center)
|
||||
{
|
||||
IDrawController controller = queue.GetController(DbBaseCommands.Instance);
|
||||
Vector3 min = Vector3.Min(start, end);
|
||||
Vector3 max = Vector3.Max(start, end);
|
||||
controller.EnsureBounds(new Box3d(min, max));
|
||||
controller.Write(DbBaseCommands.Instance.DrawRectF, new RectCommandArgs(start, end, fillBrush, strikeBrush, strikeSize, kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Dashboard.Drawing
|
||||
{
|
||||
public class DrawQueue : IDisposable
|
||||
public class DrawQueue : IEnumerable<ICommandFrame>, IDisposable
|
||||
{
|
||||
private readonly HashList<IDrawExtension> _extensions = new HashList<IDrawExtension>();
|
||||
private readonly HashList<IDrawCommand> _commands = new HashList<IDrawCommand>();
|
||||
@ -15,9 +17,9 @@ namespace Dashboard.Drawing
|
||||
private readonly MemoryStream _commandStream = new MemoryStream();
|
||||
|
||||
/// <summary>
|
||||
/// Size of the image in points.
|
||||
/// The absolute boundary of all graphics objects.
|
||||
/// </summary>
|
||||
public Vector3 Size { get; private set; } = Vector3.Zero;
|
||||
public Box3d Bounds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The extensions required to draw the image.
|
||||
@ -119,6 +121,10 @@ namespace Dashboard.Drawing
|
||||
}
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator() => new Enumerator(this);
|
||||
IEnumerator<ICommandFrame> IEnumerable<ICommandFrame>.GetEnumerator() => GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
private static int ToVlq(int value, Span<byte> bytes)
|
||||
{
|
||||
if (value < 0)
|
||||
@ -126,8 +132,13 @@ namespace Dashboard.Drawing
|
||||
else if (bytes.Length < 5)
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes), "Must at least be five bytes long.");
|
||||
|
||||
int i;
|
||||
if (value == 0)
|
||||
{
|
||||
bytes[0] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 5 && value != 0; i++, value >>= 7)
|
||||
{
|
||||
if (i > 0)
|
||||
@ -139,21 +150,25 @@ namespace Dashboard.Drawing
|
||||
return i;
|
||||
}
|
||||
|
||||
private static int FromVlq(ReadOnlySpan<byte> bytes)
|
||||
private static int FromVlq(ReadOnlySpan<byte> bytes, out int value)
|
||||
{
|
||||
int value = 0;
|
||||
value = 0;
|
||||
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
int i;
|
||||
for (i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
byte b = bytes[i];
|
||||
|
||||
value = (value << 7) | b;
|
||||
|
||||
if ((b & (1 << 7)) == 0)
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
return i;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@ -163,19 +178,9 @@ namespace Dashboard.Drawing
|
||||
|
||||
private class DrawController(DrawQueue Queue) : IDrawController
|
||||
{
|
||||
public void EnsureSize(Vector3 size)
|
||||
public void EnsureBounds(Box3d bounds)
|
||||
{
|
||||
Queue.Size = Vector3.Max(Queue.Size, size);
|
||||
}
|
||||
|
||||
public int Require(IDrawExtension extension)
|
||||
{
|
||||
return Queue.RequireExtension(extension);
|
||||
}
|
||||
|
||||
public int GetResourceIndex(IDrawResource resource)
|
||||
{
|
||||
return Queue._resources.Intern(resource);
|
||||
Queue.Bounds = Box3d.Union(Queue.Bounds, bounds);
|
||||
}
|
||||
|
||||
public void Write(IDrawCommand command)
|
||||
@ -196,49 +201,142 @@ namespace Dashboard.Drawing
|
||||
param.Serialize(Queue, bytes);
|
||||
Write(command, bytes);
|
||||
}
|
||||
|
||||
public void Write<T1, T2>(T2 command, T1 param) where T2 : IDrawCommand<T1>
|
||||
{
|
||||
int length = command.WriteParams(Queue, param, Span<byte>.Empty);
|
||||
Span<byte> bytes = stackalloc byte[length];
|
||||
|
||||
command.WriteParams(Queue, param, bytes);
|
||||
Write(command, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
private class HashList<T> : IReadOnlyList<T>
|
||||
where T : notnull
|
||||
public class Enumerator : ICommandFrame, IEnumerator<ICommandFrame>
|
||||
{
|
||||
private readonly List<T> _list = new List<T>();
|
||||
private readonly Dictionary<T, int> _map = new Dictionary<T, int>();
|
||||
private readonly DrawQueue _queue;
|
||||
private readonly byte[] _stream;
|
||||
private int _length;
|
||||
private int _index = -1;
|
||||
private int _paramsIndex = -1;
|
||||
private int _paramLength = 0;
|
||||
private IDrawCommand? _current = null;
|
||||
|
||||
public T this[int index] => _list[index];
|
||||
public ICommandFrame Current => this;
|
||||
|
||||
public int Count => _list.Count;
|
||||
object? IEnumerator.Current => Current;
|
||||
|
||||
public int Intern(T value)
|
||||
public IDrawCommand Command => _current ?? throw new InvalidOperationException();
|
||||
|
||||
public bool HasParameters { get; private set; }
|
||||
|
||||
public Enumerator(DrawQueue queue)
|
||||
{
|
||||
if (_map.TryGetValue(value, out int index))
|
||||
return index;
|
||||
|
||||
index = Count;
|
||||
|
||||
_list.Add(value);
|
||||
_map.Add(value, index);
|
||||
|
||||
return index;
|
||||
_queue = queue;
|
||||
_stream = queue._commandStream.GetBuffer();
|
||||
_length = (int)queue._commandStream.Length;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
public bool MoveNext()
|
||||
{
|
||||
_list.Clear();
|
||||
_map.Clear();
|
||||
if (_index >= _length)
|
||||
return false;
|
||||
|
||||
if (_index == -1)
|
||||
_index = 0;
|
||||
|
||||
_index += FromVlq(_stream[_index .. (_index + 5)], out int command);
|
||||
_current = _queue.Command[command];
|
||||
|
||||
HasParameters = _current.Length != 0;
|
||||
|
||||
if (!HasParameters)
|
||||
{
|
||||
_paramsIndex = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
int length;
|
||||
if (_current.Length < 0)
|
||||
{
|
||||
_index += FromVlq(_stream[_index .. (_index + 5)], out length);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = _current.Length;
|
||||
}
|
||||
|
||||
_paramsIndex = _index;
|
||||
_paramLength = length;
|
||||
_index += length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_current = null;
|
||||
}
|
||||
|
||||
public object? GetParameter()
|
||||
{
|
||||
return _current?.GetParams(_queue, _stream.AsSpan(_paramsIndex, _paramLength));
|
||||
}
|
||||
|
||||
public T GetParameter<T>()
|
||||
{
|
||||
if (_current is IDrawCommand<T> command)
|
||||
{
|
||||
return command.GetParams(_queue, _stream.AsSpan(_paramsIndex, _paramLength))!;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetParameter<T>([NotNullWhen(true)] out T? parameter)
|
||||
{
|
||||
if (_current is IDrawCommand<T> command)
|
||||
{
|
||||
parameter = command.GetParams(_queue, _stream.AsSpan(_paramsIndex, _paramLength))!;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameter = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICommandFrame
|
||||
{
|
||||
public IDrawCommand Command { get; }
|
||||
|
||||
public bool HasParameters { get; }
|
||||
|
||||
public object? GetParameter();
|
||||
|
||||
public T GetParameter<T>();
|
||||
|
||||
public bool TryGetParameter<T>([NotNullWhen(true)] out T? parameter);
|
||||
}
|
||||
|
||||
|
||||
public interface IDrawController
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures that the canvas is at least a certain size.
|
||||
/// </summary>
|
||||
/// <param name="size">The minimum size.</param>
|
||||
void EnsureSize(Vector3 size);
|
||||
/// <param name="bounds">The bounding box.</param>
|
||||
void EnsureBounds(Box3d bounds);
|
||||
|
||||
/// <summary>
|
||||
/// Write into the command stream.
|
||||
@ -259,5 +357,12 @@ namespace Dashboard.Drawing
|
||||
/// <param name="command">The command to write.</param>
|
||||
/// <param name="param">Any data associated with the command.</param>
|
||||
void Write<T>(IDrawCommand command, T param) where T : IParameterSerializer<T>;
|
||||
|
||||
/// <summary>
|
||||
/// Write into the command stream.
|
||||
/// </summary>
|
||||
/// <param name="command">The command to write.</param>
|
||||
/// <param name="param">Any data associated with the command.</param>
|
||||
void Write<T1, T2>(T2 command, T1 param) where T2 : IDrawCommand<T1>;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Dashboard.Drawing
|
||||
{
|
||||
@ -22,6 +23,11 @@ namespace Dashboard.Drawing
|
||||
{
|
||||
Color = color;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Kind, Color);
|
||||
}
|
||||
}
|
||||
|
||||
public class SolidBrushExtension : DrawExtension
|
||||
|
@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dashboard.TestApplication",
|
||||
{49A62F46-AC1C-4240-8615-020D4FBBF964} = {49A62F46-AC1C-4240-8615-020D4FBBF964}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard.Common", "Dashboard.Common\Dashboard.Common.csproj", "{C77CDD2B-2482-45F9-B330-47A52F5F13C0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -33,6 +35,10 @@ Global
|
||||
{7C90B90B-DF31-439B-9080-CD805383B014}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C90B90B-DF31-439B-9080-CD805383B014}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C90B90B-DF31-439B-9080-CD805383B014}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C77CDD2B-2482-45F9-B330-47A52F5F13C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C77CDD2B-2482-45F9-B330-47A52F5F13C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C77CDD2B-2482-45F9-B330-47A52F5F13C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C77CDD2B-2482-45F9-B330-47A52F5F13C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1,6 +0,0 @@
|
||||
namespace Dashboard;
|
||||
|
||||
public class Class1
|
||||
{
|
||||
|
||||
}
|
@ -5,6 +5,19 @@ using System.Numerics;
|
||||
|
||||
DrawQueue queue = new DrawQueue();
|
||||
|
||||
queue.Point(Vector3.Zero, 2, new SolidBrush(Color.White));
|
||||
SolidBrush fg = new SolidBrush(Color.Black);
|
||||
SolidBrush bg = new SolidBrush(Color.White);
|
||||
|
||||
queue.Point(Vector3.Zero, 2f, fg);
|
||||
queue.Line(Vector3.Zero, Vector3.One * 2, 2f, bg);
|
||||
queue.Rect(Vector3.UnitX, 2 * Vector3.UnitX + Vector3.UnitY, fg, bg, 2f);
|
||||
|
||||
foreach (ICommandFrame frame in queue)
|
||||
{
|
||||
Console.WriteLine("{0}", frame.Command.Name);
|
||||
|
||||
if (frame.HasParameters)
|
||||
Console.WriteLine("Param: {0}", frame.GetParameter());
|
||||
}
|
||||
|
||||
Debugger.Break();
|
||||
|
Loading…
Reference in New Issue
Block a user