using System; using System.Runtime.InteropServices; namespace Quik.CommandMachine { [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(24)] 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.Vec1 || _type == FrameType.Vec2 || _type == FrameType.Vec3 || _type == FrameType.Vec4; 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 FrameType Type => _type; public int I1 => _i1; public int I2 => _i2; public int I3 => _i3; public int I4 => _i4; public float F1 => _f1; public float F2 => _f2; public float F3 => _f3; public float F4 => _f4; public static Frame None { get; } = new Frame() { _type = FrameType.None }; #region Constructors public Frame(Command command) : this() { _type = FrameType.Command; _i1 = (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; } #endregion public T As() { return (T)_object; } public float GetF(int i) { switch (i) { case 0: return _f1; case 1: return _f2; case 2: return _f3; case 3: return _f4; default: throw new ArgumentOutOfRangeException(); } } public int GetI(int i) { switch (i) { case 0: return _i1; case 1: return _i2; case 2: return _i3; case 3: return _i4; default: throw new ArgumentOutOfRangeException(); } } #region Frame->T Conversion public static explicit operator int(in Frame frame) { switch (frame.Type) { default: throw new InvalidCastException(); case FrameType.Command: case FrameType.IVec1: case FrameType.IVec2: case FrameType.IVec3: case FrameType.IVec4: return frame._i1; case FrameType.Vec1: case FrameType.Vec2: case FrameType.Vec3: case FrameType.Vec4: return (int)frame._f1; } } public static explicit operator float(in Frame frame) { switch (frame.Type) { default: throw new InvalidCastException(); case FrameType.IVec1: case FrameType.IVec2: case FrameType.IVec3: case FrameType.IVec4: return frame._i1; case FrameType.Vec1: case FrameType.Vec2: case FrameType.Vec3: case FrameType.Vec4: return frame._f1; } } public static explicit operator Command(in Frame frame) { if (frame.Type != FrameType.Command) { throw new InvalidCastException("Not a command frame."); } return (Command)frame._i1; } public static explicit operator QVec2(in Frame frame) { switch (frame.Type) { default: throw new InvalidCastException(); case FrameType.IVec2: case FrameType.IVec3: case FrameType.IVec4: return new QVec2(frame._i1, frame._i2); case FrameType.Vec2: case FrameType.Vec3: case FrameType.Vec4: return new QVec2(frame._f1, frame._f2); } } public static explicit operator QColor(in Frame frame) { if (frame.Type != FrameType.IVec4) throw new InvalidCastException(); return new QColor((byte)frame._i1, (byte)frame._i2, (byte)frame._i3, (byte)frame._i4); } public static explicit operator QRectangle(in Frame frame) { switch (frame.Type) { default: throw new InvalidCastException(); case FrameType.IVec4: return new QRectangle(frame._i1, frame._i2, frame._i3, frame._i4); case FrameType.Vec4: return new QRectangle(frame._f1, frame._f2, frame._f3, frame._f4); } } public static explicit operator QLine(in Frame frame) { switch (frame.Type) { default: throw new InvalidCastException(); case FrameType.IVec4: return new QLine(frame._i1, frame._i2, frame._i3, frame._i4); case FrameType.Vec4: return new QLine(frame._f1, frame._f2, frame._f3, frame._f4); } } #endregion 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 QVec2 vector) => new Frame(vector.X, vector.Y); public static implicit operator Frame(in QColor color) => new Frame(color.R, color.G, color.B, color.A); public static implicit operator Frame(in QRectangle rect) => new Frame(rect.Max.X, rect.Max.Y, rect.Min.X, rect.Min.Y); public static implicit operator Frame(in QLine line) => new Frame(line.Start.X, line.Start.Y, line.End.X, line.Start.Y); public static void Create(in QBezier 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 QEllipse 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); } } }