diff --git a/GlitchyEngine/src/Math/MathDefs.bf b/GlitchyEngine/src/Math/MathDefs.bf index 604ccc4..40531a0 100644 --- a/GlitchyEngine/src/Math/MathDefs.bf +++ b/GlitchyEngine/src/Math/MathDefs.bf @@ -1,13 +1,11 @@ +using System; + namespace GlitchyEngine.Math { typealias Color = DirectX.Color; typealias ColorRGB = DirectX.ColorRGB; typealias ColorRGBA = DirectX.ColorRGBA; - typealias Vector2 = DirectX.Math.Vector2; - typealias Vector3 = DirectX.Math.Vector3; - typealias Vector4 = DirectX.Math.Vector4; - typealias Matrix3x3 = DirectX.Math.Matrix3x3; typealias Matrix4x3 = DirectX.Math.Matrix4x3; typealias Matrix = DirectX.Math.Matrix; diff --git a/GlitchyEngine/src/Math/SwizzleVectorAttribute.bf b/GlitchyEngine/src/Math/SwizzleVectorAttribute.bf new file mode 100644 index 0000000..34523a1 --- /dev/null +++ b/GlitchyEngine/src/Math/SwizzleVectorAttribute.bf @@ -0,0 +1,88 @@ +using System; + +namespace GlitchyEngine.Math +{ + /** + * Generates component swizzle operators for a vector. + */ + [AttributeUsage(.Struct | .Class)] + struct SwizzleVectorAttribute : Attribute, IComptimeTypeApply + { + private int _vectorSize; + + public int VectorSize => _vectorSize; + + this(int vectorSize) + { + _vectorSize = vectorSize; + } + + /** + * Determines whether or not a swizzle operator can have a valid setter (e.g. no component assigned twice) + */ + static bool invalidSetter(int[4] cmp, int vecSize) + { + return cmp[0] == cmp[1] || (vecSize >= 3 && cmp[0] == cmp[2]) || (vecSize == 4 && cmp[0] == cmp[3]) || + (vecSize >= 3 && cmp[1] == cmp[2]) || (vecSize == 4 && cmp[1] == cmp[3]) || + (vecSize == 4 && cmp[2] == cmp[3]); + } + + [Comptime] + public void ApplyToType(Type type) + { + // TODO: report bug... sized array not working + String[] componentNames = scope String[]("X", "Y", "Z", "W"); + + for(int swizzleCount = 2; swizzleCount <= 4; swizzleCount++) + { + int[4] cmp = .(); + + int cmp2max = swizzleCount > 2 ? _vectorSize : 1; + int cmp3max = swizzleCount > 3 ? _vectorSize : 1; + + for(cmp[0] = 0; cmp[0] < _vectorSize; cmp[0]++) + for(cmp[1] = 0; cmp[1] < _vectorSize; cmp[1]++) + for(cmp[2] = 0; cmp[2] < cmp2max; cmp[2]++) + for(cmp[3] = 0; cmp[3] < cmp3max; cmp[3]++) + { + String swizzleName = scope String(swizzleCount); + String swizzleConstructor = scope String(swizzleCount * 3); + String setter = scope String(128); + + bool setterInvalid = invalidSetter(cmp, swizzleCount); + + for(int c = 0; c < swizzleCount; c++) + { + swizzleName.Append(componentNames[cmp[c]]); + + if(c != 0) + { + swizzleConstructor.Append(", "); + } + swizzleConstructor.Append(componentNames[cmp[c]]); + + if(!setterInvalid && c < _vectorSize) // + { + setter.AppendF($"\n\t\t{componentNames[cmp[c]]} = value.{componentNames[c]};"); + } + } + + //{(setterInvalid ? "[Error(\"Cannot assign multiple values to same component.\")]" : String.Empty)} + + String swizzleString = scope $""" + public Vector{swizzleCount} {swizzleName} + {{ + get => .({swizzleConstructor}); + set mut + {{{setter} + }} + }} + + """; + + Compiler.EmitTypeBody(type, swizzleString); + } + } + } + } +} diff --git a/GlitchyEngine/src/Math/Vector2.bf b/GlitchyEngine/src/Math/Vector2.bf new file mode 100644 index 0000000..f0a574e --- /dev/null +++ b/GlitchyEngine/src/Math/Vector2.bf @@ -0,0 +1,227 @@ +using System; + +namespace GlitchyEngine.Math +{ + [SwizzleVector(2)] + public struct Vector2 + { + public const Vector2 Zero = .(0f, 0f); + public const Vector2 UnitX = .(1f, 0f); + public const Vector2 UnitY = .(0f, 1f); + public const Vector2 One = .(1f, 1f); + + public const int Length = 2; + + public float X, Y; + + public this() => this = default; + + public this(float value) + { + X = value; + Y = value; + } + + public this(float x, float y) + { + X = x; + Y = y; + } + + public ref float this[int index] + { + [Checked] + get + { + if(index < 0 || index >= Length) + Internal.ThrowIndexOutOfRange(1); + +#unwarn + return ref (&X)[index]; + } + + [Inline] +#unwarn + get => ref (&X)[index]; + } + + /** + * Calculates the magnitude (length) of this vector. + * @remarks MagnitudeSquared might be used if only the relative length is relevant. + */ + public float Magnitude() + { + return Math.Sqrt(X * X + Y * Y); + } + + /** + * Calculates the squared magnitude (length) of this vector. + */ + public float MagnitudeSquared() + { + return X * X + Y * Y; + } + + //TODO: Normalization interface is bad + [Checked] + public void Normalize() mut + { + if(this == .Zero) + return; + + this /= Magnitude(); + } + + public void Normalize() mut + { + this /= Magnitude(); + } + + public static Vector2 Normalize(Vector2 v) + { + return v / v.Magnitude(); + } + + public static float Dot(Vector2 l, Vector2 r) + { + return l.X * r.X + l.Y * r.Y; + } + + /** + * Calculates the projection of a onto b + */ + public Vector2 Project(Vector2 a, Vector2 b) + { + return (b * (Dot(a, b) / Dot(b, b))); + } + + /** + * Calculates the rejection of a from b + */ + public Vector2 Reject(Vector2 a, Vector2 b) + { + return (a - b * (Dot(a, b) / Dot(b, b))); + } + + + // + // Assignment operators + // + + // Addition + + public void operator +=(Vector2 value) mut + { + X += value.X; + Y += value.Y; + } + + public void operator +=(float scalar) mut + { + X += scalar; + Y += scalar; + } + + // Subtraction + + public void operator -=(Vector2 value) mut + { + X -= value.X; + Y -= value.Y; + } + + public void operator -=(float scalar) mut + { + X -= scalar; + Y -= scalar; + } + + // Multiplication + + public void operator *=(Vector2 value) mut + { + X *= value.X; + Y *= value.Y; + } + + public void operator *=(float scalar) mut + { + X *= scalar; + Y *= scalar; + } + + // Division + + public void operator /=(float scalar) mut + { + float f = 1.0f / scalar; + X *= f; + Y *= f; + } + + public void operator /=(Vector2 value) mut + { + X /= value.X; + Y /= value.Y; + } + + // + // operators + // + + // Addition + + public static Vector2 operator +(Vector2 left, Vector2 right) => Vector2(left.X + right.X, left.Y + right.Y); + + public static Vector2 operator +(Vector2 value, float scalar) => Vector2(value.X + scalar, value.Y + scalar); + + public static Vector2 operator +(float scalar, Vector2 value) => Vector2(scalar + value.X, scalar + value.Y); + + public static Vector2 operator +(Vector2 value) => value; + + // Subtraction + + public static Vector2 operator -(Vector2 left, Vector2 right) => Vector2(left.X - right.X, left.Y - right.Y); + + public static Vector2 operator -(Vector2 value, float scalar) => Vector2(value.X - scalar, value.Y - scalar); + + public static Vector2 operator -(float scalar, Vector2 value) => Vector2(scalar - value.X, scalar - value.Y); + + public static Vector2 operator -(Vector2 value) => Vector2(-value.X, -value.Y); + + // Multiplication + + public static Vector2 operator *(Vector2 left, Vector2 right) => Vector2(left.X * right.X, left.Y * right.Y); + + public static Vector2 operator *(Vector2 value, float scalar) => Vector2(value.X * scalar, value.Y * scalar); + + public static Vector2 operator *(float scalar, Vector2 value) => Vector2(scalar * value.X, scalar * value.Y); + + // Division + + public static Vector2 operator /(Vector2 left, Vector2 right) => Vector2(left.X / right.X, left.Y / right.Y); + + public static Vector2 operator /(Vector2 value, float scalar) + { + float inv = 1.0f / scalar; + return Vector2(value.X * inv, value.Y * inv); + } + + public static Vector2 operator /(float scalar, Vector2 value) => Vector2(scalar / value.X, scalar / value.Y); + + // Equality + + public static bool operator ==(Vector2 left, Vector2 right) => left.X == right.X && left.Y == right.Y; + + public static bool operator !=(Vector2 left, Vector2 right) => left.X != right.X || left.Y != right.Y; + + public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1}", X, Y); + + // Todo: move to extension + [Inline] + public static implicit operator DirectX.Math.Vector2(in Self value) => *(DirectX.Math.Vector2*)&value; + + [Inline] + public static implicit operator Self(in DirectX.Math.Vector2 value) => *(Self*)&value; + } +} diff --git a/GlitchyEngine/src/Math/Vector3.bf b/GlitchyEngine/src/Math/Vector3.bf new file mode 100644 index 0000000..4480455 --- /dev/null +++ b/GlitchyEngine/src/Math/Vector3.bf @@ -0,0 +1,258 @@ +using System; + +namespace GlitchyEngine.Math +{ + [SwizzleVector(3)] + public struct Vector3 + { + public const Vector3 Zero = .(0f, 0f, 0f); + public const Vector3 UnitX = .(1f, 0f, 0f); + public const Vector3 UnitY = .(0f, 1f, 0f); + public const Vector3 UnitZ = .(0f, 0f, 1f); + public const Vector3 One = .(1f, 1f, 1f); + + public const Vector3 Forward = .(0f, 0f, 1f); + public const Vector3 Backward = .(0f, 0f, -1f); + public const Vector3 Left = .(-1f, 0f, 0f); + public const Vector3 Right = .(1f, 0f, 0f); + public const Vector3 Up = .(0f, 1f, 0f); + public const Vector3 Down = .(0f, -1f, 0f); + + public float X, Y, Z; + + public this() => this = default; + + public this(float value) + { + X = value; + Y = value; + Z = value; + } + + public this(Vector2 value, float z) + { + X = value.X; + Y = value.Y; + Z = z; + } + + public this(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + + public ref float this[int index] + { + [Checked] + get + { + if(index < 0 || index > 2) + Internal.ThrowIndexOutOfRange(); + +#unwarn + return ref (&X)[index]; + } + + [Inline] +#unwarn + get => ref (&X)[index]; + } + + /** + * Calculates the magnitude (length) of this vector. + * @remarks MagnitudeSquared might be used if only the relative length is relevant. + */ + public float Magnitude() + { + return Math.Sqrt(X * X + Y * Y + Z * Z); + } + + /** + * Calculates the squared magnitude (length) of this vector. + */ + public float MagnitudeSquared() + { + return X * X + Y * Y + Z * Z; + } + + [Checked] + public void Normalize() mut + { + if(this == .Zero) + return; + + this /= Magnitude(); + } + + public void Normalize() mut + { + this /= Magnitude(); + } + + public static Vector3 Normalize(Vector3 v) + { + return v / v.Magnitude(); + } + + public static float Dot(Vector3 l, Vector3 r) + { + return l.X * r.X + l.Y * r.Y + l.Z * r.Z; + } + + public static Vector3 Cross(Vector3 l, Vector3 r) + { + return .(l.Y * r.Z - l.Z * r.Y, + l.Z * r.X - l.X * r.Z, + l.X * r.Y - l.Y * r.X); + } + + /** + * Calculates the projection of a onto b + */ + public static Vector3 Project(Vector3 a, Vector3 b) + { + return (b * (Dot(a, b) / Dot(b, b))); + } + + + /** + * Calculates the rejection of a from b + */ + public static Vector3 Reject(Vector3 a, Vector3 b) + { + return (a - b * (Dot(a, b) / Dot(b, b))); + } + + // + // Assignment operators + // + + // Addition + + public void operator +=(Vector3 value) mut + { + X += value.X; + Y += value.Y; + Z += value.Z; + } + + public void operator +=(float scalar) mut + { + X += scalar; + Y += scalar; + Z += scalar; + } + + // Subtraction + + + public void operator -=(Vector3 value) mut + { + X -= value.X; + Y -= value.Y; + Z -= value.Z; + } + + public void operator -=(float scalar) mut + { + X -= scalar; + Y -= scalar; + Z -= scalar; + } + + // Multiplication + + public void operator *=(Vector3 value) mut + { + X *= value.X; + Y *= value.Y; + Z *= value.Z; + } + + public void operator *=(float scalar) mut + { + X *= scalar; + Y *= scalar; + Z *= scalar; + } + + // Division + + public void operator /=(Vector3 value) mut + { + X /= value.X; + Y /= value.Y; + Z /= value.Z; + } + + public void operator /=(float scalar) mut + { + float inv = 1.0f / scalar; + X *= inv; + Y *= inv; + Z *= inv; + } + + // + // operators + // + + // Addition + + public static Vector3 operator +(Vector3 left, Vector3 right) => Vector3(left.X + right.X, left.Y + right.Y, left.Z + right.Z); + + public static Vector3 operator +(Vector3 value, float scalar) => Vector3(value.X + scalar, value.Y + scalar, value.Z + scalar); + + public static Vector3 operator +(float scalar, Vector3 value) => Vector3(scalar + value.X, scalar + value.Y, scalar + value.Z); + + public static Vector3 operator +(Vector3 value) => value; + + // Subtraction + + public static Vector3 operator -(Vector3 left, Vector3 right) => Vector3(left.X - right.X, left.Y - right.Y, left.Z - right.Z); + + public static Vector3 operator -(Vector3 value, float scalar) => Vector3(value.X - scalar, value.Y - scalar, value.Z - scalar); + + public static Vector3 operator -(float scalar, Vector3 value) => Vector3(scalar - value.X, scalar - value.Y, scalar - value.Z); + + public static Vector3 operator -(Vector3 value) => Vector3(-value.X, -value.Y, -value.Z); + + // Multiplication + + public static Vector3 operator *(Vector3 left, Vector3 right) => Vector3(left.X * right.X, left.Y * right.Y, left.Z * right.Z); + + public static Vector3 operator *(Vector3 value, float scalar) => Vector3(value.X * scalar, value.Y * scalar, value.Z * scalar); + + public static Vector3 operator *(float scalar, Vector3 value) => Vector3(scalar * value.X, scalar * value.Y, scalar * value.Z); + + // Division + + public static Vector3 operator /(Vector3 left, Vector3 right) => Vector3(left.X / right.X, left.Y / right.Y, left.Z / right.Z); + + public static Vector3 operator /(Vector3 value, float scalar) + { + float inv = 1.0f / scalar; + return Vector3(value.X * inv, value.Y * inv, value.Z * inv); + } + + public static Vector3 operator /(float scalar, Vector3 value) => Vector3(scalar / value.X, scalar / value.Y, scalar / value.Z); + + // Equality + + public static bool operator ==(Vector3 left, Vector3 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z; + + public static bool operator !=(Vector3 left, Vector3 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z; + + public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1} Z:{2}", X, Y, Z); + + // Todo: move to extension + + [Inline] + public static implicit operator DirectX.Math.Vector3(in Self value) => *(DirectX.Math.Vector3*)&value; + + [Inline] + public static implicit operator Self(in DirectX.Math.Vector3 value) => *(Self*)&value; + } +} diff --git a/GlitchyEngine/src/Math/Vector4.bf b/GlitchyEngine/src/Math/Vector4.bf new file mode 100644 index 0000000..5a9bef9 --- /dev/null +++ b/GlitchyEngine/src/Math/Vector4.bf @@ -0,0 +1,278 @@ +using System; + +namespace GlitchyEngine.Math +{ + [SwizzleVector(4)] + public struct Vector4 + { + public const Vector4 Zero = .(0f, 0f, 0f, 0f); + public const Vector4 UnitX = .(1f, 0f, 0f, 0f); + public const Vector4 UnitY = .(0f, 1f, 0f, 0f); + public const Vector4 UnitZ = .(0f, 0f, 1f, 0f); + public const Vector4 UnitW = .(0f, 0f, 0f, 1f); + public const Vector4 One = .(1f, 1f, 1f, 1f); + + public float X, Y, Z, W; + + public this() => this = default; + + public this(float value) + { + X = value; + Y = value; + Z = value; + W = value; + } + + public this(Vector2 value, float z, float w) + { + X = value.X; + Y = value.Y; + Z = z; + W = w; + } + + public this(Vector2 value1, Vector2 value2) + { + X = value1.X; + Y = value1.Y; + Z = value2.X; + W = value2.Y; + } + + public this(Vector3 value, float w) + { + X = value.X; + Y = value.Y; + Z = value.Z; + W = w; + } + + public this(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public ref float this[int index] + { + [Checked] + get + { + if(index < 0 || index > 3) + Internal.ThrowIndexOutOfRange(); +#unwarn + return ref (&X)[index]; + } + + [Inline] +#unwarn + get => ref (&X)[index]; + } + + /** + * Calculates the magnitude (length) of this vector. + * @remarks MagnitudeSquared might be used if only the relative length is relevant. + */ + public float Magnitude() + { + return Math.Sqrt(X * X + Y * Y + Z * Z + W * W); + } + + /** + * Calculates the squared magnitude (length) of this vector. + */ + public float MagnitudeSquared() + { + return X * X + Y * Y + Z * Z + W * W; + } + + [Checked] + public void Normalize() mut + { + if(this == .Zero) + return; + + this /= Magnitude(); + } + + public void Normalize() mut + { + this /= Magnitude(); + } + + public static Vector4 Normalize(Vector4 v) + { + if(v == .Zero) + return .Zero; + + return v / v.Magnitude(); + } + + [Unchecked] + public static Vector4 Normalize(Vector4 v) + { + return v / v.Magnitude(); + } + + public static float Dot(Vector4 l, Vector4 r) + { + return l.X * r.X + l.Y * r.Y + l.Z * r.Z + l.W * r.W; + } + + /** + * Calculates the projection of a onto b + */ + public static Vector4 Project(Vector4 a, Vector4 b) + { + return (b * (Dot(a, b) / Dot(b, b))); + } + + /** + * Calculates the rejection of a from b + */ + public static Vector4 Reject(Vector4 a, Vector4 b) + { + return (a - b * (Dot(a, b) / Dot(b, b))); + } + + // + // Assignment operators + // + + // Addition + + public void operator +=(Vector4 value) mut + { + X += value.X; + Y += value.Y; + Z += value.Z; + W += value.W; + } + + public void operator +=(float scalar) mut + { + X += scalar; + Y += scalar; + Z += scalar; + W += scalar; + } + + // Subtraction + + public void operator -=(Vector4 value) mut + { + X -= value.X; + Y -= value.Y; + Z -= value.Z; + W -= value.W; + } + + public void operator -=(float scalar) mut + { + X -= scalar; + Y -= scalar; + Z -= scalar; + W -= scalar; + } + + // Multiplication + + public void operator *=(Vector4 value) mut + { + X *= value.X; + Y *= value.Y; + Z *= value.Z; + W *= value.W; + } + + public void operator *=(float scalar) mut + { + X *= scalar; + Y *= scalar; + Z *= scalar; + W *= scalar; + } + + // Division + + public void operator /=(float scalar) mut + { + float f = 1.0f / scalar; + X *= f; + Y *= f; + Z *= f; + W *= f; + } + + public void operator /=(Vector4 value) mut + { + X /= value.X; + Y /= value.Y; + Z /= value.Z; + W /= value.W; + } + + // + // operators + // + + // Addition + + public static Vector4 operator +(Vector4 left, Vector4 right) => Vector4(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W); + + public static Vector4 operator +(Vector4 value, float scalar) => Vector4(value.X + scalar, value.Y + scalar, value.Z + scalar, value.W + scalar); + + public static Vector4 operator +(float scalar, Vector4 value) => Vector4(scalar + value.X, scalar + value.Y, scalar + value.Z, scalar + value.W); + + public static Vector4 operator +(Vector4 value) => value; + + // Subtraction + + public static Vector4 operator -(Vector4 left, Vector4 right) => Vector4(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W); + + public static Vector4 operator -(Vector4 value, float scalar) => Vector4(value.X - scalar, value.Y - scalar, value.Z - scalar, value.W - scalar); + + public static Vector4 operator -(float scalar, Vector4 value) => Vector4(scalar - value.X, scalar - value.Y, scalar - value.Z, scalar - value.W); + + public static Vector4 operator -(Vector4 value) => Vector4(-value.X, -value.Y, -value.Z, -value.W); + + // Multiplication + + public static Vector4 operator *(Vector4 left, Vector4 right) => Vector4(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W); + + public static Vector4 operator *(Vector4 value, float scalar) => Vector4(value.X * scalar, value.Y * scalar, value.Z * scalar, value.W * scalar); + + public static Vector4 operator *(float scalar, Vector4 value) => Vector4(scalar * value.X, scalar * value.Y, scalar * value.Z, scalar * value.W); + + // Division + + public static Vector4 operator /(Vector4 left, Vector4 right) => Vector4(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W); + + public static Vector4 operator /(Vector4 value, float scalar) + { + float inv = 1.0f / scalar; + return Vector4(value.X * inv, value.Y * inv, value.Z * inv, value.W * inv); + } + + public static Vector4 operator /(float scalar, Vector4 value) => Vector4(scalar / value.X, scalar / value.Y, scalar / value.Z, scalar / value.W); + + // Equality + + public static bool operator ==(Vector4 left, Vector4 right) => left.X == right.X && left.Y == right.Y && left.Z == right.Z && left.W == right.W; + + public static bool operator !=(Vector4 left, Vector4 right) => left.X != right.X || left.Y != right.Y || left.Z != right.Z || left.W != right.W; + + public override void ToString(String strBuffer) => strBuffer.AppendF("X:{0} Y:{1} Z:{2} W:{3}", X, Y, Z, W); + + // Todo: move to extension + + [Inline] + public static implicit operator DirectX.Math.Vector4(in Self value) => *(DirectX.Math.Vector4*)&value; + + [Inline] + public static implicit operator Self(in DirectX.Math.Vector4 value) => *(Self*)&value; + } +} diff --git a/GlitchyEngine/src/Platform/DX11/Math/Vector.bf b/GlitchyEngine/src/Platform/DX11/Math/Vector.bf new file mode 100644 index 0000000..8f6096f --- /dev/null +++ b/GlitchyEngine/src/Platform/DX11/Math/Vector.bf @@ -0,0 +1,34 @@ +#pragma warning disable 4204 +using System; + +namespace GlitchyEngine.Math +{ + /* + extension Vector2 + { + [Inline] + public static implicit operator DirectX.Math.Vector2(in Self value) => *(DirectX.Math.Vector2*)&value; + + [Inline] + public static implicit operator Self(in DirectX.Math.Vector2 value) => *(Self*)&value; + } + + extension Vector3 + { + [Inline] + public static implicit operator DirectX.Math.Vector3(in Self value) => *(DirectX.Math.Vector3*)&value; + + [Inline] + public static implicit operator Self(in DirectX.Math.Vector3 value) => *(Self*)&value; + } + + extension Vector4 + { + [Inline] + public static implicit operator DirectX.Math.Vector4(in Self value) => *(DirectX.Math.Vector4*)&value; + + [Inline] + public static implicit operator Self(in DirectX.Math.Vector4 value) => *(Self*)&value; + } + */ +}