using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection.Emit; namespace Quik.CommandMachine { public class CommandList : IEnumerable { private readonly List _frames = new List(); public void Clear() { _frames.Clear(); } protected void Enqueue(in Frame frame) { _frames.Add(frame); } 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 condition) { Enqueue(Command.ConditionalBegin); Enqueue(new Frame(condition)); } public void ConditionalEnd() { Enqueue(Command.ConditionalEnd); } public void PushViewport() { Enqueue(Command.PushViewport); } public void IntersectViewport(in QRectangle viewport) { Enqueue(Command.IntersectViewport); Enqueue(viewport); } public void StoreViewport(in QRectangle viewport) { Enqueue(Command.StoreViewport); Enqueue(viewport); } public void PopViewport() { Enqueue(Command.PopViewport); } public void PushZ() { Enqueue(Command.PushZ); } 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); } public void PopZ() { Enqueue(Command.PopZ); } public void Line(in QLine line) { Enqueue(Command.Line); Enqueue(line); } public void Line(params QLine[] lines) { Enqueue(Command.Line); Enqueue((Frame)lines.Length); foreach (QLine line in lines) Enqueue(line); } public void Bezier(in QBezier bezier) { Frame a, b; Frame.Create(bezier, out a, out b); Enqueue(Command.Bezier); Enqueue(a); Enqueue(b); } public void Bezier(params QBezier[] beziers) { Frame a, b; Enqueue(Command.Bezier); Enqueue((Frame)beziers.Length); foreach (QBezier bezier in beziers) { Frame.Create(bezier, out a, out b); Enqueue(a); Enqueue(b); } } public void Rectangle(in QRectangle rectangle) { Enqueue(Command.Rectangle); Enqueue(rectangle); } public void Rectangle(QRectangle[] rectangles) { Enqueue(Command.Rectangle); Enqueue((Frame)rectangles.Length); foreach (QRectangle rectangle in rectangles) Enqueue(rectangle); } public void Ellipse(in QEllipse ellipse) { Frame a, b; Frame.Create(ellipse, out a, out b); Enqueue(Command.Ellipse); Enqueue(a); Enqueue(b); } public void Ellipse(params QEllipse[] ellipses) { Frame a, b; Enqueue(Command.Ellipse); Enqueue((Frame)ellipses.Length); foreach (QEllipse ellipse in ellipses) { Frame.Create(ellipse, out a, out b); Enqueue(a); Enqueue(b); } } public void Triangle(in QTriangle triangle) { Enqueue(Command.Triangle); Enqueue(triangle.A); Enqueue(triangle.B); Enqueue(triangle.C); } public void Triangle(params QTriangle[] triangles) { Enqueue(Command.Triangle); Enqueue((Frame)triangles.Length); foreach (QTriangle triangle in triangles) { Enqueue(triangle.A); Enqueue(triangle.B); Enqueue(triangle.C); } } public void Polygon(params QVec2[] polygon) { Enqueue(Command.Polygon); Enqueue((Frame)polygon.Length); foreach (QVec2 vertex in polygon) { Enqueue(vertex); } } public void Image(QuikTexture texture, in QRectangle rectangle) { Enqueue(Command.Image); Enqueue((Frame)(int)ImageCommandFlags.Single); Enqueue(new Frame(texture)); Enqueue(rectangle); } public void Image(QuikTexture texture, in QRectangle rectangle, in QRectangle uv) { Enqueue(Command.Image); Enqueue((Frame)(int)(ImageCommandFlags.Single | ImageCommandFlags.UVs)); Enqueue(new Frame(texture)); Enqueue(rectangle); Enqueue(uv); } public void Image(QuikTexture texture, QRectangle[] rectangles, bool interleavedUV = false) { ImageCommandFlags flags = interleavedUV ? ImageCommandFlags.UVs : ImageCommandFlags.None; Enqueue(Command.Image); Enqueue(new Frame((int)flags, rectangles.Length / 2)); Enqueue(new Frame(texture)); foreach (QRectangle rectangle in rectangles) { Enqueue(rectangle); } } public void Image(QuikTexture texture, QRectangle[] rectangles, QRectangle[] uvs) { 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]); } } public void Splice(CommandList queue) { foreach (Frame frame in queue) { Enqueue(frame); } } public CommandEnumerator GetEnumerator() => new CommandEnumerator(_frames); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public class CommandEnumerator : IEnumerator { private readonly IReadOnlyList _frames; private int _current; public Frame Current => _frames[_current]; object IEnumerator.Current => Current; public CommandEnumerator(IReadOnlyList frames) { _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; } } }