using System; using System.ComponentModel.DataAnnotations; using System.Diagnostics; namespace Quik { /// /// A 2 dimensional Vector. /// [DebuggerDisplay("({X}, {Y})")] public struct QuikVec2 { public float X; public float Y; public float Magnitude => MathF.Sqrt(X * X + Y * Y); public QuikVec2(float x, float y) { X = x; Y = y; } public QuikVec2 Normalize() => this * (1.0f / Magnitude); public float Atan2() => MathF.Atan2(Y, X); public static QuikVec2 operator +(QuikVec2 a, QuikVec2 b) { return new QuikVec2() { X = a.X + b.X, Y = a.Y + b.Y }; } public static QuikVec2 operator -(QuikVec2 a) { return new QuikVec2() { X = -a.X, Y = -a.Y }; } public static QuikVec2 operator -(QuikVec2 a, QuikVec2 b) { return new QuikVec2() { X = a.X - b.X, Y = a.Y - b.Y }; } public static QuikVec2 operator *(float a, QuikVec2 b) { return new QuikVec2() { X = a * b.X, Y = a * b.Y }; } public static QuikVec2 operator *(QuikVec2 a, float b) => b * a; public static bool operator ==(QuikVec2 a, QuikVec2 b) => a.X == b.X && a.Y == b.Y; public static bool operator !=(QuikVec2 a, QuikVec2 b) => a.X != b.X || a.Y != b.Y; public override bool Equals(object obj) { if (obj is QuikVec2) { return (QuikVec2) obj == this; } else { return false; } } public override int GetHashCode() { return 63671 * X.GetHashCode() ^ 81083 * Y.GetHashCode(); } public static float Dot(QuikVec2 a, QuikVec2 b) { return a.X * b.X + a.Y * b.Y; } } /// /// A RGBA color value. /// [DebuggerDisplay("({R}, {G}, {B}, {A})")] public struct QuikColor { /// /// Red channel. /// public byte R; /// /// Green channel. /// public byte G; /// /// Blue channel. /// public byte B; /// /// Alpha channel. /// public byte A; public QuikColor(byte r, byte g, byte b, byte a) { R = r; G = g; B = b; A = a; } public QuikColor(byte r, byte g, byte b) : this(r, g, b, 1) { } public QuikColor(uint hexCode) { R = (byte)((hexCode >> 24) & 0xFF); G = (byte)((hexCode >> 16) & 0xFF); B = (byte)((hexCode >> 8 ) & 0xFF); A = (byte)((hexCode >> 0 ) & 0xFF); } public QuikColor(int hexCode) : this((uint)hexCode) { } } /// /// A bezier curve segment. /// [DebuggerDisplay("{Start} -- {ControlA} -- {ControlB} -- {End}")] public struct QuikBezier { /// /// Segment start point. /// public QuikVec2 Start; /// /// Start point control point. /// public QuikVec2 ControlA; /// /// End point control point. /// public QuikVec2 ControlB; /// /// Segment end point. /// public QuikVec2 End; /// /// An approximation of the arc length of the bezier curve, for calculating rasterization resolution. /// public float RasterizationArc => 0.5f * (End - Start).Magnitude + 0.5f * ((ControlA - Start).Magnitude + (ControlB - ControlA).Magnitude + (End - ControlB).Magnitude); public QuikBezier(QuikVec2 start, QuikVec2 controlA, QuikVec2 controlB, QuikVec2 end) { Start = start; ControlA = controlA; ControlB = controlB; End = end; } public QuikBezier( float startX, float startY, float controlAx, float controlAy, float controlBx, float controlBy, float endX, float endY) : this( new QuikVec2(startX, startY), new QuikVec2(controlAx, controlAy), new QuikVec2(controlBx, controlBy), new QuikVec2(endX, endY)) { } /// /// Get a point in the curve segment. /// /// Control parameter (between 0 and 1) /// The point on the curve. public QuikVec2 GetBezierPoint(float t) { float T = 1 - t; return T * T * T * Start + 3 * T * T * t * ControlA + 3 * T * t * t * ControlB + t * t * t * End; } /// /// Get the tangent on the curve. /// /// Control parameter (between 0 and 1) /// The tangent curve. public QuikVec2 GetBezierTangent(float t) { float T = 1 - t; return 3 * T * T * (ControlA - Start) + 6 * T * t * (ControlB - ControlA) + 3 * t * t * (End - ControlB); } } /// /// A line segment. /// [DebuggerDisplay("{Start} -- {End}")] public struct QuikLine { /// /// Start point. /// public QuikVec2 Start; /// /// End point. /// public QuikVec2 End; public QuikLine(QuikVec2 start, QuikVec2 end) { Start = start; End = end; } public QuikLine(float startX, float startY, float endX, float endY) { Start.X = startX; Start.Y = startY; End.X = endX; End.Y = endY; } } /// /// A rectangle. /// [DebuggerDisplay("({Right}, {Top}, {Left}, {Bottom})")] public struct QuikRectangle { /// /// Rectangle maximum point. /// public QuikVec2 Max; /// /// Rectangle minimum point. /// public QuikVec2 Min; public float Left { get => Min.X; set => Min.X = value; } public float Right { get => Max.X; set => Max.X = value; } public float Top { get => Max.Y; set => Max.Y = value; } public float Bottom { get => Min.Y; set => Min.Y = value; } public QuikVec2 Size { get => Max - Min; set => Max = Min + value; } public QuikRectangle(QuikVec2 max, QuikVec2 min) { Max = max; Min = min; } public QuikRectangle(float r, float t, float l, float b) { Max = new QuikVec2() {X = r, Y = t}; Min = new QuikVec2() {X = l, Y = b}; } } /// /// An ellipse. /// /// It is undefined to have an ellipse with non-orthogonal axes. [DebuggerDisplay("{Center} ellipse {AxisA}; {AxisB}")] public struct QuikEllipse { /// /// Ellipse center point. /// public QuikVec2 Center; /// /// First ellipse axis. /// public QuikVec2 AxisA; /// /// Second ellipse axis. /// public QuikVec2 AxisB; } /// /// A triangle. /// [DebuggerDisplay("{A} -- {B} -- {C}")] public struct QuikTriangle { /// /// First vertex. /// public QuikVec2 A; /// /// Second vertex. /// public QuikVec2 B; /// /// Third vertex. /// public QuikVec2 C; } }