From 98b1c1a277e4254e5c5309d7ee350e2bff6208c4 Mon Sep 17 00:00:00 2001 From: "H. Utku Maden" Date: Sat, 13 May 2023 16:17:23 +0300 Subject: [PATCH] New in development queue system. --- Quik/CommandQueue/Command.cs | 59 +++++++ Quik/CommandQueue/CommandHandler.cs | 8 + Quik/CommandQueue/CommandQueue.cs | 232 +++++++++++++++++++++++++ Quik/CommandQueue/Frame.cs | 212 ++++++++++++++++++++++ Quik/CommandQueue/FrameType.cs | 17 ++ Quik/CommandQueue/ImageCommandFlags.cs | 10 ++ Quik/IQuikTexture.cs | 6 +- Quik/QuikGeometry.cs | 13 ++ Quik/QuikImageFormat.cs | 4 +- 9 files changed, 558 insertions(+), 3 deletions(-) create mode 100644 Quik/CommandQueue/Command.cs create mode 100644 Quik/CommandQueue/CommandHandler.cs create mode 100644 Quik/CommandQueue/CommandQueue.cs create mode 100644 Quik/CommandQueue/Frame.cs create mode 100644 Quik/CommandQueue/FrameType.cs create mode 100644 Quik/CommandQueue/ImageCommandFlags.cs diff --git a/Quik/CommandQueue/Command.cs b/Quik/CommandQueue/Command.cs new file mode 100644 index 0000000..f85b200 --- /dev/null +++ b/Quik/CommandQueue/Command.cs @@ -0,0 +1,59 @@ +namespace Quik.CommandQueue +{ + /// + /// Enumeration of built-in Quik commands. + /// + public enum Command + { + #region Control Commands + /// + /// Invoke a function directly. + /// + Invoke, + + /// + /// Begin conditional rendering segment. + /// + ConditionalBegin, + + /// + /// End conditional rendering segment. + /// + ConditionalEnd, + + PushViewport, + StoreViewport, + PopViewport, + + IncrementZ, + AddZ, + StoreZ, + DecrementZ, + + PushMatrix, + StoreIdentityMatrix, + StoreMatrix, + PopMatrix, + + PushStyle, + StoreStyle, + PopStyle, + #endregion + + #region Draw Commands + Line, + Bezier, + Rectangle, + Ellipse, + Triangle, + Polygon, + Image, + #endregion + + + /// + /// Start index for custom commands. + /// + CustomCommandBase = 1024, + } +} \ No newline at end of file diff --git a/Quik/CommandQueue/CommandHandler.cs b/Quik/CommandQueue/CommandHandler.cs new file mode 100644 index 0000000..01e2b67 --- /dev/null +++ b/Quik/CommandQueue/CommandHandler.cs @@ -0,0 +1,8 @@ +namespace Quik.CommandQueue +{ + /// + /// A delegate for a QUIK command. + /// + /// The current stack. + public delegate void QuikCommandHandler(object state); +} \ No newline at end of file diff --git a/Quik/CommandQueue/CommandQueue.cs b/Quik/CommandQueue/CommandQueue.cs new file mode 100644 index 0000000..862bd9c --- /dev/null +++ b/Quik/CommandQueue/CommandQueue.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; + +namespace Quik.CommandQueue +{ + public class CommandQueue : Queue + { + 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(in QuikRectangle viewport) + { + Enqueue(Command.PushViewport); + Enqueue(viewport); + } + + public void StoreViewport(in QuikRectangle viewport) + { + Enqueue(Command.StoreViewport); + Enqueue(viewport); + } + + public void PopViewport() + { + Enqueue(Command.PopViewport); + } + + 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 Line(in QuikLine line) + { + Enqueue(Command.Line); + Enqueue(line); + } + + public void Line(params QuikLine[] lines) + { + Enqueue(Command.Line); + Enqueue((Frame)lines.Length); + foreach (QuikLine line in lines) + Enqueue(line); + } + + public void Bezier(in QuikBezier bezier) + { + Frame a, b; + Frame.Create(bezier, out a, out b); + + Enqueue(Command.Bezier); + Enqueue(a); + Enqueue(b); + } + + public void Bezier(params QuikBezier[] beziers) + { + Frame a, b; + + Enqueue(Command.Bezier); + Enqueue((Frame)beziers.Length); + + foreach (QuikBezier bezier in beziers) + { + Frame.Create(bezier, out a, out b); + Enqueue(a); + Enqueue(b); + } + } + + public void Rectangle(in QuikRectangle rectangle) + { + Enqueue(Command.Rectangle); + Enqueue(rectangle); + } + + public void Rectangle(QuikRectangle[] rectangles) + { + Enqueue(Command.Rectangle); + Enqueue((Frame)rectangles.Length); + foreach (QuikRectangle rectangle in rectangles) + Enqueue(rectangle); + } + + public void Ellipse(in QuikEllipse ellipse) + { + Frame a, b; + Frame.Create(ellipse, out a, out b); + + Enqueue(Command.Ellipse); + Enqueue(a); + Enqueue(b); + } + + public void Ellipse(params QuikEllipse[] ellipses) + { + Frame a, b; + Enqueue(Command.Ellipse); + Enqueue((Frame)ellipses.Length); + foreach (QuikEllipse ellipse in ellipses) + { + Frame.Create(ellipse, out a, out b); + Enqueue(a); + Enqueue(b); + } + } + + public void Triangle(in QuikTriangle triangle) + { + Enqueue(Command.Triangle); + Enqueue(triangle.A); + Enqueue(triangle.B); + Enqueue(triangle.C); + } + + public void Triangle(params QuikTriangle[] triangles) + { + Enqueue(Command.Triangle); + Enqueue((Frame)triangles.Length); + foreach (QuikTriangle triangle in triangles) + { + Enqueue(triangle.A); + Enqueue(triangle.B); + Enqueue(triangle.C); + } + } + + public void Polygon(params QuikVec2[] polygon) + { + Enqueue(Command.Polygon); + Enqueue((Frame)polygon.Length); + foreach (QuikVec2 vertex in polygon) + { + Enqueue(vertex); + } + } + + public void Image(IQuikTexture texture, in QuikRectangle rectangle) + { + Enqueue(Command.Image); + Enqueue((Frame)(int)ImageCommandFlags.Single); + Enqueue(new Frame(texture)); + Enqueue(rectangle); + } + + public void Image(IQuikTexture texture, in QuikRectangle rectangle, in QuikRectangle uv) + { + Enqueue(Command.Image); + Enqueue((Frame)(int)(ImageCommandFlags.Single | ImageCommandFlags.UVs)); + Enqueue(new Frame(texture)); + Enqueue(rectangle); + Enqueue(uv); + } + + public void Image(IQuikTexture texture, QuikRectangle[] 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 (QuikRectangle rectangle in rectangles) + { + Enqueue(rectangle); + } + } + + public void Image(IQuikTexture texture, QuikRectangle[] rectangles, QuikRectangle[] 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]); + } + } + } +} \ No newline at end of file diff --git a/Quik/CommandQueue/Frame.cs b/Quik/CommandQueue/Frame.cs new file mode 100644 index 0000000..f6fbd3b --- /dev/null +++ b/Quik/CommandQueue/Frame.cs @@ -0,0 +1,212 @@ +using System.Runtime.InteropServices; + +namespace Quik.CommandQueue +{ + [StructLayout(LayoutKind.Explicit)] + public struct Frame + { + [FieldOffset(0)] + private FrameType _type; + + [FieldOffset(sizeof(FrameType) + 0*sizeof(int))] + private int _i1; + [FieldOffset(sizeof(FrameType) + 1*sizeof(int))] + private int _i2; + [FieldOffset(sizeof(FrameType) + 2*sizeof(int))] + private int _i3; + [FieldOffset(sizeof(FrameType) + 3*sizeof(int))] + private int _i4; + + [FieldOffset(sizeof(FrameType) + 0*sizeof(float))] + private float _f1; + [FieldOffset(sizeof(FrameType) + 1*sizeof(float))] + private float _f2; + [FieldOffset(sizeof(FrameType) + 2*sizeof(float))] + private float _f3; + [FieldOffset(sizeof(FrameType) + 3*sizeof(float))] + private float _f4; + + [FieldOffset(sizeof(FrameType))] + private object _object; + + public bool IsCommand => _type == FrameType.Command; + public bool IsInteger => + _type == FrameType.IVec1 || + _type == FrameType.IVec2 || + _type == FrameType.IVec3 || + _type == FrameType.IVec4; + public bool IsFloat => + _type == FrameType.IVec1 || + _type == FrameType.IVec2 || + _type == FrameType.IVec3 || + _type == FrameType.IVec4; + + public int VectorSize + { + get + { + switch (_type) + { + case FrameType.None: + return 0; + default: + return 1; + case FrameType.Vec2: case FrameType.IVec2: + return 2; + case FrameType.Vec3: case FrameType.IVec3: + return 3; + case FrameType.Vec4: case FrameType.IVec4: + return 4; + } + } + } + + public static Frame None { get; } = new Frame() { + _type = FrameType.None + }; + + public Frame(Command command) : this((int)command) + { + } + + public Frame(object o) + { + _type = FrameType.Object; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _object = o; + } + + public Frame(int i1) + { + _type = FrameType.IVec1; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _i1 = i1; + } + + public Frame(int i1, int i2) + { + _type = FrameType.IVec2; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _i1 = i1; + _i2 = i2; + } + + public Frame(int i1, int i2, int i3) + { + _type = FrameType.IVec3; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _i1 = i1; + _i2 = i2; + _i3 = i3; + } + + public Frame(int i1, int i2, int i3, int i4) + { + _type = FrameType.IVec4; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _i1 = i1; + _i2 = i2; + _i3 = i3; + _i4 = i4; + } + + public Frame(float f1) + { + _type = FrameType.Vec1; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _f1 = f1; + } + + public Frame(float f1, float f2) + { + _type = FrameType.Vec2; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _f1 = f1; + _f2 = f2; + } + + public Frame(float f1, float f2, float f3) + { + _type = FrameType.Vec3; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _f1 = f1; + _f2 = f2; + _f3 = f3; + } + + public Frame(float f1, float f2, float f3, float f4) + { + _type = FrameType.Vec4; + + _i1 = _i2 = _i3 = _i4 = default; + _f1 = _f2 = _f3 = _f4 = default; + _object = null; + + _f1 = f1; + _f2 = f2; + _f3 = f3; + _f4 = f4; + } + + public T As() where T : class + { + return (T)_object; + } + + public static implicit operator int(in Frame frame) => frame._i1; + public static implicit operator float(in Frame frame) => frame._f1; + public static implicit operator Command(in Frame frame) => (Command)frame._i1; + + public static explicit operator Frame(int i) => new Frame(i); + public static explicit operator Frame(float f) => new Frame(f); + public static implicit operator Frame(Command cmd) => new Frame(cmd); + public static implicit operator Frame(in QuikVec2 vector) => new Frame(vector.X, vector.Y); + public static implicit operator Frame(in QuikColor color) => new Frame(color.R, color.G, color.B, color.A); + public static implicit operator Frame(in QuikRectangle rect) => new Frame(rect.Min.X, rect.Min.Y, rect.Max.X, rect.Max.Y); + public static implicit operator Frame(in QuikLine line) => new Frame(line.Start.X, line.Start.Y, line.End.X, line.Start.Y); + + public static void Create(in QuikBezier bezier, out Frame a, out Frame b) + { + a = new Frame(bezier.Start.X, bezier.Start.Y, bezier.End.X, bezier.End.Y); + b = new Frame(bezier.ControlA.X, bezier.ControlA.Y, bezier.ControlB.X, bezier.ControlB.Y); + } + + public static void Create(in QuikEllipse ellipse, out Frame a, out Frame b) + { + a = new Frame(ellipse.Center.X, ellipse.Center.Y); + b = new Frame(ellipse.AxisA.X, ellipse.AxisA.Y, ellipse.AxisB.X, ellipse.AxisB.Y); + } + } +} \ No newline at end of file diff --git a/Quik/CommandQueue/FrameType.cs b/Quik/CommandQueue/FrameType.cs new file mode 100644 index 0000000..6bc6344 --- /dev/null +++ b/Quik/CommandQueue/FrameType.cs @@ -0,0 +1,17 @@ +namespace Quik.CommandQueue +{ + public enum FrameType + { + None, + Command, + IVec1, + IVec2, + IVec3, + IVec4, + Vec1, + Vec2, + Vec3, + Vec4, + Object, + } +} \ No newline at end of file diff --git a/Quik/CommandQueue/ImageCommandFlags.cs b/Quik/CommandQueue/ImageCommandFlags.cs new file mode 100644 index 0000000..1374183 --- /dev/null +++ b/Quik/CommandQueue/ImageCommandFlags.cs @@ -0,0 +1,10 @@ +namespace Quik.CommandQueue +{ + public enum ImageCommandFlags + { + None = 0, + + Single = 1 << 0, + UVs = 1 << 1 + } +} \ No newline at end of file diff --git a/Quik/IQuikTexture.cs b/Quik/IQuikTexture.cs index 172976a..98bb9ec 100644 --- a/Quik/IQuikTexture.cs +++ b/Quik/IQuikTexture.cs @@ -29,7 +29,8 @@ namespace Quik /// Color format of the data. /// Size of the texture data. /// Mip level. - void Image(IntPtr data, QuikImageFormat format, QuikVec2 size, int level); + /// Pixel alignment. Expected to be 1, 2, 4, or 8. + void Image(IntPtr data, QuikImageFormat format, QuikVec2 size, int level, int alignment = 4); /// /// Upload texture data. @@ -38,7 +39,8 @@ namespace Quik /// Color format for the data. /// Location of the data in the texture. /// Mip level. - void SubImage(IntPtr data, QuikImageFormat format, QuikRectangle location, int level); + /// Pixel alignment. Expected to be 1, 2, 4, or 8. + void SubImage(IntPtr data, QuikImageFormat format, QuikRectangle location, int level, int alignment = 4); /// /// Generate the mip maps for the texture. diff --git a/Quik/QuikGeometry.cs b/Quik/QuikGeometry.cs index 5d140fe..f781fec 100644 --- a/Quik/QuikGeometry.cs +++ b/Quik/QuikGeometry.cs @@ -308,6 +308,19 @@ namespace Quik Max = new QuikVec2() {X = r, Y = t}; Min = new QuikVec2() {X = l, Y = b}; } + + public bool Contains(QuikVec2 point) + { + return + point.X > Left && point.X < Right && + point.Y > Bottom && point.Y < Top; + } + + internal void Translate(in QuikVec2 offset) + { + Min += offset; + Max += offset; + } } /// diff --git a/Quik/QuikImageFormat.cs b/Quik/QuikImageFormat.cs index 986b232..63efbdd 100644 --- a/Quik/QuikImageFormat.cs +++ b/Quik/QuikImageFormat.cs @@ -7,6 +7,8 @@ namespace Quik RgbaU8, RedF, RgbF, - RgbaF + RgbaF, + AlphaU8, + AlphaF } } \ No newline at end of file