2024-04-14 21:35:30 +02:00
|
|
|
using Quik.Media;
|
2023-05-13 15:17:23 +02:00
|
|
|
using System;
|
2024-04-08 22:50:05 +02:00
|
|
|
using System.Collections;
|
2023-05-13 15:17:23 +02:00
|
|
|
using System.Collections.Generic;
|
2024-04-08 22:50:05 +02:00
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2024-04-11 18:33:42 +02:00
|
|
|
using System.Runtime.CompilerServices;
|
2023-05-13 15:17:23 +02:00
|
|
|
|
2023-05-20 18:37:51 +02:00
|
|
|
namespace Quik.CommandMachine
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
2024-04-08 22:50:05 +02:00
|
|
|
public class CommandList : IEnumerable<Frame>
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
2024-04-08 22:50:05 +02:00
|
|
|
private readonly List<Frame> _frames = new List<Frame>();
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
{
|
|
|
|
_frames.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void Enqueue(in Frame frame)
|
|
|
|
{
|
|
|
|
_frames.Add(frame);
|
|
|
|
}
|
|
|
|
|
2023-05-13 15:17:23 +02:00
|
|
|
public void Invoke(QuikCommandHandler handler)
|
|
|
|
{
|
|
|
|
Enqueue(Command.Invoke);
|
|
|
|
Enqueue(new Frame(handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ConditionalBegin(bool value)
|
|
|
|
{
|
|
|
|
Enqueue(Command.ConditionalBegin);
|
|
|
|
Enqueue((Frame)(value ? 1 : 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ConditionalBegin(Func<bool> condition)
|
|
|
|
{
|
|
|
|
Enqueue(Command.ConditionalBegin);
|
|
|
|
Enqueue(new Frame(condition));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ConditionalEnd()
|
|
|
|
{
|
|
|
|
Enqueue(Command.ConditionalEnd);
|
|
|
|
}
|
|
|
|
|
2023-05-14 22:32:32 +02:00
|
|
|
public void PushViewport()
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.PushViewport);
|
2023-05-14 22:32:32 +02:00
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void IntersectViewport(in QRectangle viewport)
|
2023-05-14 22:32:32 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.IntersectViewport);
|
2023-05-13 15:17:23 +02:00
|
|
|
Enqueue(viewport);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void StoreViewport(in QRectangle viewport)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.StoreViewport);
|
|
|
|
Enqueue(viewport);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void PopViewport()
|
|
|
|
{
|
|
|
|
Enqueue(Command.PopViewport);
|
|
|
|
}
|
|
|
|
|
2023-05-14 22:32:32 +02:00
|
|
|
public void PushZ()
|
|
|
|
{
|
|
|
|
Enqueue(Command.PushZ);
|
|
|
|
}
|
|
|
|
|
2023-05-13 15:17:23 +02:00
|
|
|
public void IncrementZ()
|
|
|
|
{
|
|
|
|
Enqueue(Command.IncrementZ);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void AddZ(int value)
|
|
|
|
{
|
|
|
|
if (value == 1)
|
|
|
|
{
|
|
|
|
IncrementZ();
|
|
|
|
}
|
|
|
|
else if (value == -1)
|
|
|
|
{
|
|
|
|
DecrementZ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Enqueue(Command.AddZ);
|
|
|
|
Enqueue((Frame)value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void StoreZ(int value)
|
|
|
|
{
|
|
|
|
Enqueue(Command.StoreZ);
|
|
|
|
Enqueue((Frame)value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void DecrementZ()
|
|
|
|
{
|
|
|
|
Enqueue(Command.DecrementZ);
|
|
|
|
}
|
|
|
|
|
2023-05-14 22:32:32 +02:00
|
|
|
public void PopZ()
|
|
|
|
{
|
|
|
|
Enqueue(Command.PopZ);
|
|
|
|
}
|
|
|
|
|
2024-05-16 21:57:38 +02:00
|
|
|
public void PushStyle(Style style)
|
|
|
|
{
|
|
|
|
Enqueue(Command.PushStyle);
|
|
|
|
Enqueue(new Frame(style));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void StoreStyle(Style style)
|
|
|
|
{
|
|
|
|
Enqueue(Command.StoreStyle);
|
|
|
|
Enqueue(new Frame(style));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void PopStyle()
|
|
|
|
{
|
|
|
|
Enqueue(Command.PopStyle);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Line(in QLine line)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Line);
|
|
|
|
Enqueue(line);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Line(params QLine[] lines)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Line);
|
|
|
|
Enqueue((Frame)lines.Length);
|
2023-06-29 09:42:02 +02:00
|
|
|
foreach (QLine line in lines)
|
2023-05-13 15:17:23 +02:00
|
|
|
Enqueue(line);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Bezier(in QBezier bezier)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Frame a, b;
|
|
|
|
Frame.Create(bezier, out a, out b);
|
|
|
|
|
|
|
|
Enqueue(Command.Bezier);
|
|
|
|
Enqueue(a);
|
|
|
|
Enqueue(b);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Bezier(params QBezier[] beziers)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Frame a, b;
|
|
|
|
|
|
|
|
Enqueue(Command.Bezier);
|
|
|
|
Enqueue((Frame)beziers.Length);
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
foreach (QBezier bezier in beziers)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Frame.Create(bezier, out a, out b);
|
|
|
|
Enqueue(a);
|
|
|
|
Enqueue(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Rectangle(in QRectangle rectangle)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Rectangle);
|
|
|
|
Enqueue(rectangle);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Rectangle(QRectangle[] rectangles)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Rectangle);
|
|
|
|
Enqueue((Frame)rectangles.Length);
|
2023-06-29 09:42:02 +02:00
|
|
|
foreach (QRectangle rectangle in rectangles)
|
2023-05-13 15:17:23 +02:00
|
|
|
Enqueue(rectangle);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Ellipse(in QEllipse ellipse)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Frame a, b;
|
|
|
|
Frame.Create(ellipse, out a, out b);
|
|
|
|
|
|
|
|
Enqueue(Command.Ellipse);
|
|
|
|
Enqueue(a);
|
|
|
|
Enqueue(b);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Ellipse(params QEllipse[] ellipses)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Frame a, b;
|
|
|
|
Enqueue(Command.Ellipse);
|
|
|
|
Enqueue((Frame)ellipses.Length);
|
2023-06-29 09:42:02 +02:00
|
|
|
foreach (QEllipse ellipse in ellipses)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Frame.Create(ellipse, out a, out b);
|
|
|
|
Enqueue(a);
|
|
|
|
Enqueue(b);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Triangle(in QTriangle triangle)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Triangle);
|
|
|
|
Enqueue(triangle.A);
|
|
|
|
Enqueue(triangle.B);
|
|
|
|
Enqueue(triangle.C);
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Triangle(params QTriangle[] triangles)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Triangle);
|
|
|
|
Enqueue((Frame)triangles.Length);
|
2023-06-29 09:42:02 +02:00
|
|
|
foreach (QTriangle triangle in triangles)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(triangle.A);
|
|
|
|
Enqueue(triangle.B);
|
|
|
|
Enqueue(triangle.C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
public void Polygon(params QVec2[] polygon)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Polygon);
|
|
|
|
Enqueue((Frame)polygon.Length);
|
2023-06-29 09:42:02 +02:00
|
|
|
foreach (QVec2 vertex in polygon)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(vertex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-14 21:35:30 +02:00
|
|
|
public void Image(QImage texture, in QRectangle rectangle)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Image);
|
|
|
|
Enqueue((Frame)(int)ImageCommandFlags.Single);
|
|
|
|
Enqueue(new Frame(texture));
|
|
|
|
Enqueue(rectangle);
|
|
|
|
}
|
|
|
|
|
2024-04-14 21:35:30 +02:00
|
|
|
public void Image(QImage texture, in QRectangle rectangle, in QRectangle uv)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Image);
|
|
|
|
Enqueue((Frame)(int)(ImageCommandFlags.Single | ImageCommandFlags.UVs));
|
|
|
|
Enqueue(new Frame(texture));
|
|
|
|
Enqueue(rectangle);
|
|
|
|
Enqueue(uv);
|
|
|
|
}
|
|
|
|
|
2024-04-14 21:35:30 +02:00
|
|
|
public void Image(QImage texture, ReadOnlySpan<QRectangle> rectangles, bool interleavedUV = false)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
2024-04-11 18:06:58 +02:00
|
|
|
int count = rectangles.Length;
|
|
|
|
ImageCommandFlags flags = ImageCommandFlags.None;
|
|
|
|
|
|
|
|
if (interleavedUV)
|
|
|
|
{
|
|
|
|
count /= 2;
|
|
|
|
flags |= ImageCommandFlags.UVs;
|
|
|
|
}
|
2023-05-13 15:17:23 +02:00
|
|
|
|
|
|
|
Enqueue(Command.Image);
|
2024-04-14 22:21:31 +02:00
|
|
|
Enqueue(new Frame((int)flags, count));
|
2023-05-13 15:17:23 +02:00
|
|
|
Enqueue(new Frame(texture));
|
|
|
|
|
2023-06-29 09:42:02 +02:00
|
|
|
foreach (QRectangle rectangle in rectangles)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
Enqueue(rectangle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-14 21:35:30 +02:00
|
|
|
public void Image(QImage texture, ReadOnlySpan<QRectangle> rectangles, ReadOnlySpan<QRectangle> uvs)
|
2023-05-13 15:17:23 +02:00
|
|
|
{
|
|
|
|
int count = Math.Min(rectangles.Length, uvs.Length);
|
|
|
|
Enqueue(Command.Image);
|
|
|
|
Enqueue(new Frame((int)ImageCommandFlags.UVs, count));
|
|
|
|
Enqueue(new Frame(texture));
|
|
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
Enqueue(rectangles[i]);
|
|
|
|
Enqueue(uvs[i]);
|
|
|
|
}
|
|
|
|
}
|
2024-04-08 22:50:05 +02:00
|
|
|
|
2024-04-14 21:35:30 +02:00
|
|
|
public void Image3D(QImage texture, in Image3DCall call)
|
2024-04-11 18:33:42 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Image);
|
|
|
|
Enqueue(new Frame(ImageCommandFlags.Image3d | ImageCommandFlags.Single));
|
|
|
|
Enqueue(new Frame(texture));
|
|
|
|
Enqueue(call.Rectangle);
|
|
|
|
Enqueue(call.UVs);
|
|
|
|
Enqueue(new Frame(call.Layer));
|
|
|
|
}
|
|
|
|
|
2024-04-14 21:35:30 +02:00
|
|
|
public void Image3D(QImage texture, ReadOnlySpan<Image3DCall> calls)
|
2024-04-11 18:33:42 +02:00
|
|
|
{
|
|
|
|
Enqueue(Command.Image);
|
|
|
|
Enqueue(new Frame((int)ImageCommandFlags.Image3d, calls.Length));
|
|
|
|
Enqueue(new Frame(texture));
|
|
|
|
|
|
|
|
foreach (Image3DCall call in calls)
|
|
|
|
{
|
|
|
|
Enqueue(call.Rectangle);
|
|
|
|
Enqueue(call.UVs);
|
|
|
|
Enqueue(new Frame(call.Layer));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-11 18:06:58 +02:00
|
|
|
public void Splice(CommandList list)
|
2024-04-08 22:50:05 +02:00
|
|
|
{
|
2024-04-11 18:06:58 +02:00
|
|
|
foreach (Frame frame in list)
|
2024-04-08 22:50:05 +02:00
|
|
|
{
|
|
|
|
Enqueue(frame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-11 18:06:58 +02:00
|
|
|
public CommandQueue GetEnumerator() => new CommandQueue(_frames);
|
2024-04-08 22:50:05 +02:00
|
|
|
IEnumerator<Frame> IEnumerable<Frame>.GetEnumerator() => GetEnumerator();
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
|
|
}
|
|
|
|
|
2024-04-11 18:06:58 +02:00
|
|
|
public class CommandQueue : IEnumerator<Frame>
|
2024-04-08 22:50:05 +02:00
|
|
|
{
|
|
|
|
private readonly IReadOnlyList<Frame> _frames;
|
|
|
|
private int _current;
|
|
|
|
|
|
|
|
public Frame Current => _frames[_current];
|
|
|
|
|
|
|
|
object IEnumerator.Current => Current;
|
|
|
|
|
2024-04-11 18:06:58 +02:00
|
|
|
public CommandQueue(IReadOnlyList<Frame> frames)
|
2024-04-08 22:50:05 +02:00
|
|
|
{
|
|
|
|
_current = -1;
|
|
|
|
_frames = frames;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool TryDequeue([NotNullWhen(true)] out Frame frame)
|
|
|
|
{
|
|
|
|
if (MoveNext())
|
|
|
|
{
|
|
|
|
frame = Current;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
frame = default;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Frame Dequeue() => TryDequeue(out Frame frame) ? frame : throw new Exception("No more frames left.");
|
|
|
|
|
|
|
|
public bool TryPeek([NotNullWhen(true)] out Frame frame)
|
|
|
|
{
|
|
|
|
if (_current + 1 < _frames.Count)
|
|
|
|
{
|
|
|
|
frame = _frames[_current + 1];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
frame = default;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Frame Peek() => TryPeek(out Frame frame) ? frame : throw new Exception("No more frames left.");
|
|
|
|
|
|
|
|
public bool MoveNext()
|
|
|
|
{
|
|
|
|
if (_current + 1 < _frames.Count)
|
|
|
|
{
|
|
|
|
_current++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Reset()
|
|
|
|
{
|
|
|
|
_current = -1;
|
|
|
|
}
|
2023-05-13 15:17:23 +02:00
|
|
|
}
|
|
|
|
}
|