diff --git a/sources/Maths/Maths/Legacy/Vector2D.Ops.cs b/sources/Maths/Maths/Legacy/Vector2D.Ops.cs index 3c556c26d3..df68ebed3b 100644 --- a/sources/Maths/Maths/Legacy/Vector2D.Ops.cs +++ b/sources/Maths/Maths/Legacy/Vector2D.Ops.cs @@ -213,7 +213,7 @@ public static Vector2D TransformNormal(Vector2D normal, Matrix4X4 ma /// The source vector to be rotated. /// The rotation to apply. /// The transformed vector. - public static Vector2D Transform(Vector2D value, Quaternion rotation) + public static Vector2D Transform(Vector2D value, Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { T x2 = Scalar.Add(rotation.X, rotation.X); @@ -285,4 +285,4 @@ public static Vector2D Multiply(Vector2D value1, Matrix2X2 value2) where T : unmanaged, IFormattable, IEquatable, IComparable => value1 * value2; } -} \ No newline at end of file +} diff --git a/sources/Maths/Maths/Legacy/Vector3D.Ops.cs b/sources/Maths/Maths/Legacy/Vector3D.Ops.cs index ec06f40112..618c53b805 100644 --- a/sources/Maths/Maths/Legacy/Vector3D.Ops.cs +++ b/sources/Maths/Maths/Legacy/Vector3D.Ops.cs @@ -254,7 +254,7 @@ public static Vector3D Transform(Vector3D position, Matrix4X4 matrix /// The rotation to apply. /// The transformed vector. [MethodImpl((MethodImplOptions) 768)] - public static Vector3D Transform(Vector3D value, Quaternion rotation) + public static Vector3D Transform(Vector3D value, Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { T x2 = Scalar.Add(rotation.X, rotation.X); @@ -296,4 +296,4 @@ public static Vector3D TransformNormal(Vector3D normal, Matrix4X4 ma ); } } -} \ No newline at end of file +} diff --git a/sources/Maths/Maths/Legacy/Vector4D.Ops.cs b/sources/Maths/Maths/Legacy/Vector4D.Ops.cs index 16caebd93b..b86726fc19 100644 --- a/sources/Maths/Maths/Legacy/Vector4D.Ops.cs +++ b/sources/Maths/Maths/Legacy/Vector4D.Ops.cs @@ -237,7 +237,7 @@ public static Vector4D Transform(Vector2D position, Matrix4X4 matrix /// The rotation to apply. /// The transformed vector. [MethodImpl((MethodImplOptions) 768)] - public static Vector4D Transform(Vector2D value, Quaternion rotation) + public static Vector4D Transform(Vector2D value, Silk.NET.Maths.Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { T x2 = Scalar.Add(rotation.X, rotation.X); @@ -283,7 +283,7 @@ public static Vector4D Transform(Vector3D position, Matrix4X4 matrix /// The rotation to apply. /// The transformed vector. [MethodImpl((MethodImplOptions) 768)] - public static Vector4D Transform(Vector3D value, Quaternion rotation) + public static Vector4D Transform(Vector3D value, Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { T x2 = Scalar.Add(rotation.X, rotation.X); @@ -329,7 +329,7 @@ public static Vector4D Transform(Vector4D vector, Matrix4X4 matrix) /// The rotation to apply. /// The transformed vector. [MethodImpl((MethodImplOptions) 768)] - public static Vector4D Transform(Vector4D value, Quaternion rotation) + public static Vector4D Transform(Vector4D value, Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { T x2 = Scalar.Add(rotation.X, rotation.X); @@ -354,4 +354,4 @@ public static Vector4D Transform(Vector4D value, Quaternion rotation ); } } -} \ No newline at end of file +} diff --git a/sources/Maths/Maths/Matrix2X3.Ops.cs b/sources/Maths/Maths/Matrix2X3.Ops.cs index 242912de0b..6ebb6124ca 100644 --- a/sources/Maths/Maths/Matrix2X3.Ops.cs +++ b/sources/Maths/Maths/Matrix2X3.Ops.cs @@ -104,7 +104,7 @@ public static Matrix2X3 CreateFromAxisAngle(Vector3D axis, T angle) /// Creates a rotation matrix from the given Quaternion rotation value. /// The source Quaternion. /// The rotation matrix. - public static Matrix2X3 CreateFromQuaternion(Quaternion quaternion) + public static Matrix2X3 CreateFromQuaternion(Silk.NET.Maths.Legacy.Quaternion quaternion) where T : unmanaged, IFormattable, IEquatable, IComparable { Matrix2X3 result = Matrix2X3.Identity; @@ -140,7 +140,7 @@ public static Matrix2X3 CreateFromQuaternion(Quaternion quaternion) public static Matrix2X3 CreateFromYawPitchRoll(T yaw, T pitch, T roll) where T : unmanaged, IFormattable, IEquatable, IComparable { - Quaternion q = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll); + Legacy.Quaternion q = Legacy.Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll); return CreateFromQuaternion(q); } @@ -223,7 +223,7 @@ public static unsafe Matrix2X3 Lerp(Matrix2X3 matrix1, Matrix2X3 mat /// The source matrix to transform. /// The rotation to apply. /// The transformed matrix. - public static Matrix2X3 Transform(Matrix2X3 value, Quaternion rotation) + public static Matrix2X3 Transform(Matrix2X3 value, Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { // Compute rotation matrix. @@ -260,4 +260,4 @@ public static Matrix2X3 Transform(Matrix2X3 value, Quaternion rotati return new(value.M11 * q1 + value.M12 * q2 + value.M13 * q3, value.M21 * q1 + value.M22 * q2 + value.M23 * q3); } } -} \ No newline at end of file +} diff --git a/sources/Maths/Maths/Matrix3X3.Ops.cs b/sources/Maths/Maths/Matrix3X3.Ops.cs index 2b11c28756..aa3905c23a 100644 --- a/sources/Maths/Maths/Matrix3X3.Ops.cs +++ b/sources/Maths/Maths/Matrix3X3.Ops.cs @@ -127,7 +127,7 @@ public static Matrix3X3 CreateFromAxisAngle(Vector3D axis, T angle) /// Creates a rotation matrix from the given Quaternion rotation value. /// The source Quaternion. /// The rotation matrix. - public static Matrix3X3 CreateFromQuaternion(Quaternion quaternion) + public static Matrix3X3 CreateFromQuaternion(Silk.NET.Maths.Legacy.Quaternion quaternion) where T : unmanaged, IFormattable, IEquatable, IComparable { Matrix3X3 result = Matrix3X3.Identity; @@ -167,7 +167,7 @@ public static Matrix3X3 CreateFromQuaternion(Quaternion quaternion) public static Matrix3X3 CreateFromYawPitchRoll(T yaw, T pitch, T roll) where T : unmanaged, IFormattable, IEquatable, IComparable { - Quaternion q = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll); + Legacy.Quaternion q = Legacy.Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll); return CreateFromQuaternion(q); } @@ -373,7 +373,7 @@ public static Matrix3X3 Subtract(Matrix3X3 value1, Matrix3X3 value2) /// The scaling component of the transformation matrix. /// The rotation component of the transformation matrix. /// True if the source matrix was successfully decomposed; False otherwise. - public static bool Decompose(Matrix3X3 matrix, out Vector3D scale, out Quaternion rotation) + public static bool Decompose(Matrix3X3 matrix, out Vector3D scale, out Silk.NET.Maths.Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { bool result = true; @@ -546,13 +546,13 @@ public static bool Decompose(Matrix3X3 matrix, out Vector3D scale, out if (!Scalar.GreaterThanOrEqual(Scalar.As(DecomposeEpsilon), det)) { // Non-SRT matrix encountered - rotation = Quaternion.Identity; + rotation = Legacy.Quaternion.Identity; result = false; } else { // generate the quaternion from the matrix - rotation = Quaternion.CreateFromRotationMatrix(matTemp); + rotation = Legacy.Quaternion.CreateFromRotationMatrix(matTemp); } } } @@ -579,7 +579,7 @@ public static unsafe Matrix3X3 Lerp(Matrix3X3 matrix1, Matrix3X3 mat /// The source matrix to transform. /// The rotation to apply. /// The transformed matrix. - public static Matrix3X3 Transform(Matrix3X3 value, Quaternion rotation) + public static Matrix3X3 Transform(Matrix3X3 value, Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { // Compute rotation matrix. @@ -625,4 +625,4 @@ public static unsafe Matrix3X3 Transpose(Matrix3X3 matrix) return new(matrix.Column1, matrix.Column2, matrix.Column3); } } -} \ No newline at end of file +} diff --git a/sources/Maths/Maths/Matrix4X4.Ops.cs b/sources/Maths/Maths/Matrix4X4.Ops.cs index d27a6128ae..fb74c4345a 100644 --- a/sources/Maths/Maths/Matrix4X4.Ops.cs +++ b/sources/Maths/Maths/Matrix4X4.Ops.cs @@ -197,7 +197,7 @@ public static Matrix4X4 CreateFromAxisAngle(Vector3D axis, T angle) /// Creates a rotation matrix from the given Quaternion rotation value. /// The source Quaternion. /// The rotation matrix. - public static Matrix4X4 CreateFromQuaternion(Quaternion quaternion) + public static Matrix4X4 CreateFromQuaternion(Silk.NET.Maths.Legacy.Quaternion quaternion) where T : unmanaged, IFormattable, IEquatable, IComparable { Matrix4X4 result = Matrix4X4.Identity; @@ -237,7 +237,7 @@ public static Matrix4X4 CreateFromQuaternion(Quaternion quaternion) public static Matrix4X4 CreateFromYawPitchRoll(T yaw, T pitch, T roll) where T : unmanaged, IFormattable, IEquatable, IComparable { - Quaternion q = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll); + Legacy.Quaternion q = Legacy.Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll); return CreateFromQuaternion(q); } @@ -1276,7 +1276,7 @@ private static Vector128 Permute(Vector128 value, byte control) /// The rotation component of the transformation matrix. /// The translation component of the transformation matrix /// True if the source matrix was successfully decomposed; False otherwise. - public static bool Decompose(Matrix4X4 matrix, out Vector3D scale, out Quaternion rotation, out Vector3D translation) + public static bool Decompose(Matrix4X4 matrix, out Vector3D scale, out Silk.NET.Maths.Legacy.Quaternion rotation, out Vector3D translation) where T : unmanaged, IFormattable, IEquatable, IComparable { bool result = true; @@ -1454,13 +1454,13 @@ public static bool Decompose(Matrix4X4 matrix, out Vector3D scale, out if (!Scalar.GreaterThanOrEqual(Scalar.As(DecomposeEpsilon), det)) { // Non-SRT matrix encountered - rotation = Quaternion.Identity; + rotation = Legacy.Quaternion.Identity; result = false; } else { // generate the quaternion from the matrix - rotation = Quaternion.CreateFromRotationMatrix(matTemp); + rotation = Legacy.Quaternion.CreateFromRotationMatrix(matTemp); } } } @@ -1488,7 +1488,7 @@ public static unsafe Matrix4X4 Lerp(Matrix4X4 matrix1, Matrix4X4 mat /// The source matrix to transform. /// The rotation to apply. /// The transformed matrix. - public static Matrix4X4 Transform(Matrix4X4 value, Quaternion rotation) + public static Matrix4X4 Transform(Matrix4X4 value, Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { // Compute rotation matrix. @@ -1539,4 +1539,4 @@ public static unsafe Matrix4X4 Transpose(Matrix4X4 matrix) return new(matrix.Column1, matrix.Column2, matrix.Column3, matrix.Column4); } } -} \ No newline at end of file +} diff --git a/sources/Maths/Maths/Plane.Ops.cs b/sources/Maths/Maths/Plane.Ops.cs index ec15e8de18..24879072fb 100644 --- a/sources/Maths/Maths/Plane.Ops.cs +++ b/sources/Maths/Maths/Plane.Ops.cs @@ -181,7 +181,7 @@ public static Plane Transform(Plane plane, Matrix4X4 matrix) /// The Quaternion rotation to apply to the Plane. /// A new Plane that results from applying the rotation. [MethodImpl((MethodImplOptions) 768)] - public static Plane Transform(Plane plane, Quaternion rotation) + public static Plane Transform(Plane plane, Legacy.Quaternion rotation) where T : unmanaged, IFormattable, IEquatable, IComparable { // Compute rotation matrix. @@ -220,4 +220,4 @@ public static Plane Transform(Plane plane, Quaternion rotation) plane.Distance); } } -} \ No newline at end of file +} diff --git a/sources/Maths/Maths/Vector2F.cs b/sources/Maths/Maths/Vector2F.cs index 10c855434b..843f180af2 100644 --- a/sources/Maths/Maths/Vector2F.cs +++ b/sources/Maths/Maths/Vector2F.cs @@ -14,75 +14,8 @@ namespace Silk.NET.Maths { /// A structure representing a 2D floating-point vector. - internal partial struct Vector2F : - ISpanFormattable, - ISpanParsable>, - IUtf8SpanFormattable, - IUtf8SpanParsable>, - IParsable>, - IFormattable - where T : IFloatingPointIeee754 + internal partial struct Vector2F { - /// Initializes the vector from a span of two values. - public Vector2F(ReadOnlySpan values) - { - if (values.Length != 2) - throw new ArgumentException("Input span must contain exactly 2 elements.", nameof(values)); - - X = values[0]; - Y = values[1]; - } - - /// Gets a vector whose 2 elements are equal to one. - public static Vector2F One => new(Scalar.One); - - /// Returns a vector whose 2 elements are equal to zero. - public static Vector2F Zero => default; - - /// Gets the vector (1, 0). - public static Vector2F UnitX => new(Scalar.One, Scalar.Zero); - - /// Gets the vector (0, 1). - public static Vector2F UnitY => new(Scalar.Zero, Scalar.One); - - /// Gets a vector with all bits set for each component. - public static Vector2F AllBitsSet => new(T.AllBitsSet, T.AllBitsSet); - - /// Gets the squared length of the vector (dot product with itself). - public T LengthSquared => (X * X) + (Y * Y); - - /// Gets the length of the vector. - public T Length => T.Sqrt(LengthSquared); - - /// Computes the dot product of this vector with another vector. - public T Dot(Vector2F other) => (X * other.X) + (Y * other.Y); - - /// Computes the dot product of two vectors. - public static T Dot(Vector2F left, Vector2F right) => (left.X * right.X) + (left.Y * right.Y); - - /// Computes the cross product of this vector with another vector. - public T Cross(Vector2F other) => (X * other.Y) - (Y * other.X); - - /// Computes the cross product of two vectors. - public static T Cross(Vector2F left, Vector2F right) => (left.X * right.Y) - (left.Y * right.X); - - /// Returns a span over the vector components. - public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 2); - - /// Normalizes this vector. - public Vector2F Normalize() - { - T length = Length; - return length != T.Zero ? this / length : Zero; - } - - /// Normalizes a vector. - public static Vector2F Normalize(Vector2F vector) - { - T length = vector.Length; - return length != T.Zero ? vector / length : Zero; - } - /// Returns a vector with the component-wise maximum of this and another vector. public Vector2F Max(Vector2F other) => new(T.Max(X, other.X), T.Max(Y, other.Y)); @@ -157,100 +90,6 @@ public static Vector2F LerpClamped(Vector2F a, Vector2F b, Vector2F a.Y + (b.Y - a.Y) * T.Clamp(t.Y, T.Zero, T.One) ); - /// Reflects a vector over a normal vector. - public Vector2F Reflect(Vector2F normal) - { - T dot = Dot(normal); - return this - (normal * (dot + dot)); - } - - /// Reflects a vector over a normal vector. - public static Vector2F Reflect(Vector2F vector, Vector2F normal) - { - T dot = Dot(vector, normal); - return vector - (normal * (dot + dot)); - } - - /// Formats the vector as a string using the specified format and format provider. - public string ToString(string? format, IFormatProvider? formatProvider) => $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}>"; - - /// Formats the vector as a string. - public override string ToString() => $"<{X}, {Y}>"; - - /// Formats the vector as a string using the specified format and format provider. - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) - { - Span xBuffer = stackalloc char[64]; - Span yBuffer = stackalloc char[64]; - - if (!X.TryFormat(xBuffer, out int xChars, format, provider) || - !Y.TryFormat(yBuffer, out int yChars, format, provider)) - { - charsWritten = 0; - return false; - } - - int requiredLength = 1 + xChars + 2 + yChars + 1; - - if (destination.Length < requiredLength) - { - charsWritten = 0; - return false; - } - - int pos = 0; - destination[pos++] = '<'; - - xBuffer[..xChars].CopyTo(destination[pos..]); - pos += xChars; - - destination[pos++] = ','; - destination[pos++] = ' '; - - yBuffer[..yChars].CopyTo(destination[pos..]); - pos += yChars; - - destination[pos++] = '>'; - - charsWritten = pos; - return true; - } - - /// Parses a span to a instance. - public static Vector2F Parse(ReadOnlySpan s, IFormatProvider? provider) - { - if (!TryParse(s, provider, out var result)) - throw new FormatException("Invalid format for Vector2F."); - - return result; - } - - /// Copies the components of the vector to the specified array starting at index 0. - public void CopyTo(T[] array) => CopyTo(array, 0); - - /// Copies the components of the vector to the specified array starting at the given index. - public void CopyTo(T[] array, int startIndex) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (startIndex < 0 || startIndex + 2 > array.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex)); - array[startIndex] = X; - array[startIndex + 1] = Y; - } - - /// Copies the components of the vector to the specified span starting at index 0. - public void CopyTo(Span span) => CopyTo(span, 0); - - /// Copies the components of the vector to the specified span starting at the given index. - public void CopyTo(Span span, int startIndex) - { - if (startIndex < 0 || startIndex + 2 > span.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex)); - span[startIndex] = X; - span[startIndex + 1] = Y; - } - /// Returns a vector where each component is the sign of the original vector's component. public Vector2F Sign() => new(T.CreateChecked(T.Sign(X)), T.CreateChecked(T.Sign(Y))); @@ -274,110 +113,6 @@ public Vector2F CopySign(T signScalar) => public static Vector2F CopySign(Vector2F value, T signScalar) => new(T.CopySign(value.X, signScalar), T.CopySign(value.Y, signScalar)); - /// Parses a string to a instance. - public static Vector2F Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); - - /// Tries to parse a span to a instance. - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) - { - result = default; - - s = s.Trim(); - if (s.Length < 5 || s[0] != '<' || s[^1] != '>') - return false; - - s = s[1..^1]; // Remove < and > - - int commaIndex = s.IndexOf(','); - if (commaIndex < 0) - return false; - - ReadOnlySpan xSpan = s[..commaIndex].Trim(); - ReadOnlySpan ySpan = s[(commaIndex + 1)..].Trim(); - - if (T.TryParse(xSpan, provider, out var x) && - T.TryParse(ySpan, provider, out var y)) - { - result = new Vector2F(x, y); - return true; - } - - return false; - } - - /// Tries to parse a string to a instance. - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) => - TryParse(s.AsSpan(), provider, out result); - - /// Parses a span to a instance. - static Vector2F ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => - Parse(s, provider); - - /// Parses a string to a instance. - static Vector2F IParsable>.Parse(string s, IFormatProvider? provider) => - Parse(s, provider); - - /// Tries to parse a span to a instance. - static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) => - TryParse(s, provider, out result); - - /// Tries to parse a string to a instance. - static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) => - TryParse(s, provider, out result); - - /// Formats the vector as a UTF-8 string using the specified format and format provider. - public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) - { - Span xBuffer = stackalloc char[64]; - Span yBuffer = stackalloc char[64]; - - if (!X.TryFormat(xBuffer, out int xChars, format, provider) || - !Y.TryFormat(yBuffer, out int yChars, format, provider)) - { - bytesWritten = 0; - return false; - } - - int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + - Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + - Encoding.UTF8.GetByteCount("<, >"); - - if (utf8Destination.Length < estimatedSize) - { - bytesWritten = 0; - return false; - } - - int totalBytes = 0; - - totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); - - bytesWritten = totalBytes; - return true; - } - - /// Parses a UTF-8 span to a instance. - public static Vector2F Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) - { - int charCount = Encoding.UTF8.GetCharCount(utf8Text); - Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; - Encoding.UTF8.GetChars(utf8Text, charBuffer); - return Parse(charBuffer, provider); - } - - /// Tries to parse a UTF-8 span to a instance. - public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) - { - int charCount = Encoding.UTF8.GetCharCount(utf8Text); - Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; - Encoding.UTF8.GetChars(utf8Text, charBuffer); - return TryParse(charBuffer, provider, out result); - } - // Casts /// Explicitly casts a to a . @@ -388,45 +123,6 @@ public static explicit operator Vector2F(System.Numerics.Vector2 v) => public static explicit operator System.Numerics.Vector2(Vector2F v) => new(Convert.ToSingle(v.X), Convert.ToSingle(v.Y)); - // Component Operators - public static Vector2F operator +(Vector2F left, Vector2F right) => - new(left.X + right.X, left.Y + right.Y); - - public static Vector2F operator -(Vector2F left, Vector2F right) => - new(left.X - right.X, left.Y - right.Y); - - public static Vector2F operator *(Vector2F left, Vector2F right) => - new(left.X * right.X, left.Y * right.Y); - - public static Vector2F operator /(Vector2F left, Vector2F right) => - new(left.X / right.X, left.Y / right.Y); - - public static Vector2F operator %(Vector2F left, Vector2F right) => - new(left.X % right.X, left.Y % right.Y); - - // Scalar Operators - public static Vector2F operator +(Vector2F vector, T scalar) => - new(vector.X + scalar, vector.Y + scalar); - - public static Vector2F operator -(Vector2F vector, T scalar) => - new(vector.X - scalar, vector.Y - scalar); - - public static Vector2F operator *(Vector2F vector, T scalar) => - new(vector.X * scalar, vector.Y * scalar); - - public static Vector2F operator /(Vector2F vector, T scalar) => - new(vector.X / scalar, vector.Y / scalar); - - public static Vector2F operator %(Vector2F vector, T scalar) => - new(vector.X % scalar, vector.Y % scalar); - - // + operator: returns the vector - public static Vector2F operator +(Vector2F vector) => vector; - - // - operator: returns the negated vector - public static Vector2F operator -(Vector2F vector) => - new(-vector.X, -vector.Y); - // IFloatingPointIeee754 public static Vector2F Sqrt(Vector2F x) => new(T.Sqrt(x.X), T.Sqrt(x.Y)); @@ -616,4 +312,11 @@ public static Vector2F ScaleB(Vector2F x, Vector2I n) => public static Vector2F ScaleB(Vector2F x, int n) => new(T.ScaleB(x.X, n), T.ScaleB(x.Y, n)); } + + static partial class Vector2F + { + /// Computes the cross product of two vectors. + public static T Cross(this Vector2F left, Vector2F right) + where T : IFloatingPointIeee754 => (left.X * right.Y) - (left.Y * right.X); + } } diff --git a/sources/Maths/Maths/Vector2F.gen.cs b/sources/Maths/Maths/Vector2F.gen.cs index 34d27f31f1..b7c5cfc47f 100644 --- a/sources/Maths/Maths/Vector2F.gen.cs +++ b/sources/Maths/Maths/Vector2F.gen.cs @@ -3,10 +3,18 @@ namespace Silk.NET.Maths using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Numerics; + using System.Runtime.InteropServices; + using System.Text; partial struct Vector2F : IEquatable>, - IReadOnlyList + IReadOnlyList, + IFormattable, + IParsable>, + ISpanFormattable, + ISpanParsable>, + IUtf8SpanFormattable, + IUtf8SpanParsable> where T : IFloatingPointIeee754 { /// The X component of the vector. @@ -21,6 +29,31 @@ partial struct Vector2F : /// Initializes the vector with individual component values. public Vector2F(T x, T y) => (X, Y) = (x, y); + /// Initializes the vector from a span of 2 values. + public Vector2F(ReadOnlySpan values) + { + if (values.Length != 2) + throw new ArgumentException("Input span must contain exactly 2 elements.", nameof(values)); + + X = values[0]; + Y = values[1]; + } + + /// Gets a vector whose 2 elements are equal to one. + public static Vector2F One => new(Scalar.One); + + /// Returns a vector whose 2 elements are equal to zero. + public static Vector2F Zero => default; + + /// Gets the vector (1, 0). + public static Vector2F UnitX => new(Scalar.One, Scalar.Zero); + + /// Gets the vector (0, 1). + public static Vector2F UnitY => new(Scalar.Zero, Scalar.One); + + /// Gets the squared length of the vector (dot product with itself). + public T LengthSquared => Vector2F.Dot(this, this); + /// T IReadOnlyList.this[int index] => this[index]; @@ -55,6 +88,197 @@ public IEnumerator GetEnumerator() yield return Y; } + /// Copies the components of the vector to the specified array starting at index 0. + public void CopyTo(T[] array) => CopyTo(array, 0); + + /// Copies the components of the vector to the specified array starting at the given index. + public void CopyTo(T[] array, int startIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (startIndex < 0 || startIndex + 2 > array.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + array[startIndex] = X; + array[startIndex + 1] = Y; + } + + /// Copies the components of the vector to the specified span starting at index 0. + public void CopyTo(Span span) => CopyTo(span, 0); + + /// Copies the components of the vector to the specified span starting at the given index. + public void CopyTo(Span span, int startIndex) + { + if (startIndex < 0 || startIndex + 2 > span.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + span[startIndex] = X; + span[startIndex + 1] = Y; + } + + /// Returns a span over the vector components. + public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 2); + + /// Formats the vector as a string. + public override string ToString() => + $"<{X}, {Y}>"; + + /// Formats the vector as a string using the specified format and format provider. + public string ToString(string? format, IFormatProvider? formatProvider) => + $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}>"; + + /// Parses a string to a instance. + public static Vector2F Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); + + /// Parses a span to a instance. + public static Vector2F Parse(ReadOnlySpan s, IFormatProvider? provider) + { + if (!TryParse(s, provider, out var result)) + throw new FormatException("Invalid format for Vector2F."); + + return result; + } + + /// Formats the vector as a UTF-8 string using the specified format and format provider. + public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider)|| + !Y.TryFormat(yBuffer, out int yChars, format, provider)) + { + bytesWritten = 0; + return false; + } + + int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + + Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + + Encoding.UTF8.GetByteCount("<, >"); + + if (utf8Destination.Length < estimatedSize) + { + bytesWritten = 0; + return false; + } + + int totalBytes = 0; + + totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); + + bytesWritten = totalBytes; + return true; + } + + /// Formats the vector as a string using the specified format and format provider. + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider) || + !Y.TryFormat(yBuffer, out int yChars, format, provider)) + { + charsWritten = 0; + return false; + } + + int requiredLength = 1 + xChars + 2 + yChars + 1; + + if (destination.Length < requiredLength) + { + charsWritten = 0; + return false; + } + + int pos = 0; + destination[pos++] = '<'; + + xBuffer[..xChars].CopyTo(destination[pos..]); + pos += xChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + yBuffer[..yChars].CopyTo(destination[pos..]); + pos += yChars; + + destination[pos++] = '>'; + + charsWritten = pos; + return true; + } + + /// Tries to parse a span to a instance. + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) + { + result = default; + + s = s.Trim(); + if (s.Length < 4 || s[0] != '<' || s[^1] != '>') + return false; + + s = s[1..^1]; // Remove < and > + + int commaX = s.IndexOf(','); + if (commaX < 0) + return false; + + ReadOnlySpan xSpan = s[..commaX].Trim(); + ReadOnlySpan ySpan = s[(commaX + 1)..].Trim(); + + if (T.TryParse(xSpan, provider, out var x) && + T.TryParse(ySpan, provider, out var y)) + { + result = new Vector2F(x, y); + return true; + } + + return false; + } + + /// Parses a UTF-8 span to a instance. + public static Vector2F Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return Parse(charBuffer, provider); + } + + /// Tries to parse a UTF-8 span to a instance. + public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return TryParse(charBuffer, provider, out result); + } + + /// Tries to parse a string to a instance. + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) => + TryParse(s.AsSpan(), provider, out result); + + /// Parses a span to a instance. + static Vector2F ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => + Parse(s, provider); + + /// Parses a string to a instance. + static Vector2F IParsable>.Parse(string s, IFormatProvider? provider) => + Parse(s, provider); + + /// Tries to parse a span to a instance. + static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) => + TryParse(s, provider, out result); + + /// Tries to parse a string to a instance. + static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2F result) => + TryParse(s, provider, out result); + /// Returns a boolean indicating whether the given two vectors are equal. /// The first vector to compare. /// The second vector to compare. @@ -77,10 +301,76 @@ public IEnumerator GetEnumerator() /// public override int GetHashCode() => HashCode.Combine(X, Y); + + public static Vector2F operator +(Vector2F vector) => + vector; + + public static Vector2F operator -(Vector2F vector) => + new Vector2F(-vector.X, -vector.Y); + + public static Vector2F operator +(Vector2F left, Vector2F right) => + new Vector2F(left.X + right.X, left.Y + right.Y); + + public static Vector2F operator -(Vector2F left, Vector2F right) => + new Vector2F(left.X - right.X, left.Y - right.Y); + + public static Vector2F operator *(Vector2F left, Vector2F right) => + new Vector2F(left.X * right.X, left.Y * right.Y); + + public static Vector2F operator /(Vector2F left, Vector2F right) => + new Vector2F(left.X / right.X, left.Y / right.Y); + + public static Vector2F operator %(Vector2F left, Vector2F right) => + new Vector2F(left.X % right.X, left.Y % right.Y); + + public static Vector2F operator +(Vector2F vector, T scalar) => + new Vector2F(vector.X + scalar, vector.Y + scalar); + + public static Vector2F operator -(Vector2F vector, T scalar) => + new Vector2F(vector.X - scalar, vector.Y - scalar); + + public static Vector2F operator *(Vector2F vector, T scalar) => + new Vector2F(vector.X * scalar, vector.Y * scalar); + + public static Vector2F operator *(T scalar, Vector2F vector) => + new Vector2F(scalar * vector.X, scalar * vector.Y); + + public static Vector2F operator /(Vector2F vector, T scalar) => + new Vector2F(vector.X / scalar, vector.Y / scalar); + + public static Vector2F operator %(Vector2F vector, T scalar) => + new Vector2F(vector.X % scalar, vector.Y % scalar); + } static partial class Vector2F { + /// Computes the dot product of two vectors. + public static T Dot(this Vector2F left, Vector2F right) + where T : IFloatingPointIeee754 => + left.X * right.X + left.Y * right.Y; + + /// Reflects a vector over a normal vector. + public static Vector2F Reflect(Vector2F vector, Vector2F normal) + where T : IFloatingPointIeee754 + { + T dot = vector.Dot(normal); + return vector - (normal * (dot + dot)); + } + + /// Computes the length of the vector. + public static T GetLength(this Vector2F vector) + where T : IFloatingPointIeee754 => + T.Sqrt(vector.LengthSquared); + + /// Normalizes a vector. + public static Vector2F Normalize(this Vector2F vector) + where T : IFloatingPointIeee754 + { + T length = vector.GetLength(); + return length != T.Zero ? vector / length : Vector2F.Zero; + } + public static Vector2F Log(this Vector2F x) where TSelf : IFloatingPointIeee754, ILogarithmicFunctions => new(TSelf.Log(x.X), TSelf.Log(x.Y)); diff --git a/sources/Maths/Maths/Vector2I.cs b/sources/Maths/Maths/Vector2I.cs index 2a49a846b5..fceb7b5b44 100644 --- a/sources/Maths/Maths/Vector2I.cs +++ b/sources/Maths/Maths/Vector2I.cs @@ -12,58 +12,14 @@ namespace Silk.NET.Maths { /// A structure representing a 2D integer vector. - internal partial struct Vector2I : - ISpanFormattable, - ISpanParsable>, - IUtf8SpanFormattable, - IUtf8SpanParsable>, - IParsable>, - IFormattable - where T : IBinaryInteger + internal partial struct Vector2I { - /// Initializes the vector from a span of two values. - public Vector2I(ReadOnlySpan values) - { - if (values.Length != 2) - throw new ArgumentException("Input span must contain exactly 2 elements.", nameof(values)); - - X = values[0]; - Y = values[1]; - } - - /// Gets a vector whose 2 elements are equal to one. - public static Vector2I One => new(Scalar.One); - - /// Returns a vector whose 2 elements are equal to zero. - public static Vector2I Zero => default; - - /// Gets the vector (1, 0). - public static Vector2I UnitX => new(Scalar.One, Scalar.Zero); - - /// Gets the vector (0, 1). - public static Vector2I UnitY => new(Scalar.Zero, Scalar.One); - - /// Gets a vector with all bits set for each component. - public static Vector2I AllBitsSet => new Vector2I(T.AllBitsSet, T.AllBitsSet); - - /// Gets the squared length of the vector (dot product with itself). - public T LengthSquared => (X * X) + (Y * Y); - - /// Computes the dot product of this vector with another vector. - public T Dot(Vector2I other) => (X * other.X) + (Y * other.Y); - - /// Computes the dot product of two vectors. - public static T Dot(Vector2I left, Vector2I right) => (left.X * right.X) + (left.Y * right.Y); - /// Computes the cross product of this vector with another vector. public T Cross(Vector2I other) => (X * other.Y) - (Y * other.X); /// Computes the cross product of two vectors. public static T Cross(Vector2I left, Vector2I right) => (left.X * right.Y) - (left.Y * right.X); - /// Returns a span over the vector components. - public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 2); - /// Returns a vector with the component-wise maximum of this and another vector. public Vector2I Max(Vector2I other) => new Vector2I(T.Max(X, other.X), T.Max(Y, other.Y)); @@ -119,90 +75,6 @@ public static Vector2I Clamp(Vector2I vector, T min, T max) => public static Vector2I Abs(Vector2I vector) => new Vector2I(T.Abs(vector.X), T.Abs(vector.Y)); - /// Formats the vector as a string using the specified format and format provider. - public string ToString(string? format, IFormatProvider? formatProvider) => $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}>"; - - /// Formats the vector as a string. - public override string ToString() => $"<{X}, {Y}>"; - - /// Formats the vector as a string using the specified format and format provider. - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) - { - // Format components individually into temporary buffers - // Not too sure about this implementation - Span xBuffer = stackalloc char[64]; - Span yBuffer = stackalloc char[64]; - - if (!X.TryFormat(xBuffer, out int xChars, format, provider) || - !Y.TryFormat(yBuffer, out int yChars, format, provider)) - { - charsWritten = 0; - return false; - } - - // Calculate total required length: < + x + ", " + y + > - int requiredLength = 1 + xChars + 2 + yChars + 1; - - if (destination.Length < requiredLength) - { - charsWritten = 0; - return false; - } - - int pos = 0; - destination[pos++] = '<'; - - xBuffer[..xChars].CopyTo(destination[pos..]); - pos += xChars; - - destination[pos++] = ','; - destination[pos++] = ' '; - - yBuffer[..yChars].CopyTo(destination[pos..]); - pos += yChars; - - destination[pos++] = '>'; - - charsWritten = pos; - return true; - } - - /// Parses a span to a instance. - public static Vector2I Parse(ReadOnlySpan s, IFormatProvider? provider) - { - if (!TryParse(s, provider, out var result)) - throw new FormatException("Invalid format for Vector2I."); - - return result; - } - - /// Copies the components of the vector to the specified array starting at index 0. - public void CopyTo(T[] array) => CopyTo(array, 0); - - /// Copies the components of the vector to the specified array starting at the given index. - public void CopyTo(T[] array, int startIndex) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (startIndex < 0 || startIndex + 2 > array.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex)); - array[startIndex] = X; - array[startIndex + 1] = Y; - } - - /// Copies the components of the vector to the specified span starting at index 0. - public void CopyTo(Span span) => CopyTo(span, 0); - - /// Copies the components of the vector to the specified span starting at the given index. - public void CopyTo(Span span, int startIndex) - { - if (startIndex < 0 || startIndex + 2 > span.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex)); - - span[startIndex] = X; - span[startIndex + 1] = Y; - } - /// Returns a vector where each component is the sign of the original vector's component. public Vector2I Sign() => new Vector2I(T.CreateChecked(T.Sign(X)), T.CreateChecked(T.Sign(Y))); @@ -226,114 +98,6 @@ public Vector2I CopySign(T signScalar) => public static Vector2I CopySign(Vector2I value, T signScalar) => new Vector2I(T.CopySign(value.X, signScalar), T.CopySign(value.Y, signScalar)); - /// Parses a string to a instance. - public static Vector2I Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); - - /// Tries to parse a span to a instance. - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) - { - result = default; - - s = s.Trim(); - if (s.Length < 5 || s[0] != '<' || s[^1] != '>') - return false; - - s = s[1..^1]; // Remove < and > - - int commaIndex = s.IndexOf(','); - if (commaIndex < 0) - return false; - - ReadOnlySpan xSpan = s[..commaIndex].Trim(); - ReadOnlySpan ySpan = s[(commaIndex + 1)..].Trim(); - - if (T.TryParse(xSpan, provider, out var x) && - T.TryParse(ySpan, provider, out var y)) - { - result = new Vector2I(x, y); - return true; - } - - return false; - } - - - /// Tries to parse a string to a instance. - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) => - TryParse(s.AsSpan(), provider, out result); - - /// Parses a span to a instance. - static Vector2I ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => - Parse(s, provider); - - /// Parses a string to a instance. - static Vector2I IParsable>.Parse(string s, IFormatProvider? provider) => - Parse(s, provider); - - /// Tries to parse a span to a instance. - static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) => - TryParse(s, provider, out result); - - /// Tries to parse a string to a instance. - static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) => - TryParse(s, provider, out result); - - /// Formats the vector as a UTF-8 string using the specified format and format provider. - public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) - { - // Format components individually into temporary buffers - // Not too sure about this implementation - Span xBuffer = stackalloc char[64]; - Span yBuffer = stackalloc char[64]; - - if (!X.TryFormat(xBuffer, out int xChars, format, provider) || - !Y.TryFormat(yBuffer, out int yChars, format, provider)) - { - bytesWritten = 0; - return false; - } - - // Estimate total required UTF-8 bytes - int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + - Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + - Encoding.UTF8.GetByteCount("<, >"); - - if (utf8Destination.Length < estimatedSize) - { - bytesWritten = 0; - return false; - } - - int totalBytes = 0; - - totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); - - bytesWritten = totalBytes; - return true; - } - - /// Parses a UTF-8 span to a instance. - public static Vector2I Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) - { - int charCount = Encoding.UTF8.GetCharCount(utf8Text); - Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; - Encoding.UTF8.GetChars(utf8Text, charBuffer); - return Parse(charBuffer, provider); - } - - /// Tries to parse a UTF-8 span to a instance. - public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) - { - int charCount = Encoding.UTF8.GetCharCount(utf8Text); - Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; - Encoding.UTF8.GetChars(utf8Text, charBuffer); - return TryParse(charBuffer, provider, out result); - } - // Casts /// Explicitly casts a to a . @@ -344,77 +108,6 @@ public static explicit operator Vector2I(System.Numerics.Vector2 v) => public static explicit operator System.Numerics.Vector2(Vector2I v) => new System.Numerics.Vector2(Convert.ToSingle(v.X), Convert.ToSingle(v.Y)); - // Component Operators - public static Vector2I operator +(Vector2I left, Vector2I right) => - new Vector2I(left.X + right.X, left.Y + right.Y); - - public static Vector2I operator -(Vector2I left, Vector2I right) => - new Vector2I(left.X - right.X, left.Y - right.Y); - - public static Vector2I operator *(Vector2I left, Vector2I right) => - new Vector2I(left.X * right.X, left.Y * right.Y); - - public static Vector2I operator /(Vector2I left, Vector2I right) => - new Vector2I(left.X / right.X, left.Y / right.Y); - - public static Vector2I operator %(Vector2I left, Vector2I right) => - new Vector2I(left.X % right.X, left.Y % right.Y); - - // Scalar Operators - public static Vector2I operator +(Vector2I vector, T scalar) => - new Vector2I(vector.X + scalar, vector.Y + scalar); - - public static Vector2I operator -(Vector2I vector, T scalar) => - new Vector2I(vector.X - scalar, vector.Y - scalar); - - public static Vector2I operator *(Vector2I vector, T scalar) => - new Vector2I(vector.X * scalar, vector.Y * scalar); - - public static Vector2I operator /(Vector2I vector, T scalar) => - new Vector2I(vector.X / scalar, vector.Y / scalar); - - public static Vector2I operator %(Vector2I vector, T scalar) => - new Vector2I(vector.X % scalar, vector.Y % scalar); - - // + operator: returns the vector (?) - public static Vector2I operator +(Vector2I vector) => vector; - - // - operator: returns the negated vector - public static Vector2I operator -(Vector2I vector) => - new Vector2I(-vector.X, -vector.Y); - - // Bitwise Operators - public static Vector2I operator &(Vector2I left, Vector2I right) => - new Vector2I(left.X & right.X, left.Y & right.Y); - - public static Vector2I operator |(Vector2I left, Vector2I right) => - new Vector2I(left.X | right.X, left.Y | right.Y); - - public static Vector2I operator ^(Vector2I left, Vector2I right) => - new Vector2I(left.X ^ right.X, left.Y ^ right.Y); - - public static Vector2I operator &(Vector2I vector, T scalar) => - new Vector2I(vector.X & scalar, vector.Y & scalar); - - public static Vector2I operator &(T scalar, Vector2I vector) => - new Vector2I(scalar & vector.X, scalar & vector.Y); - - public static Vector2I operator |(Vector2I vector, T scalar) => - new Vector2I(vector.X | scalar, vector.Y | scalar); - - public static Vector2I operator |(T scalar, Vector2I vector) => - new Vector2I(scalar | vector.X, scalar | vector.Y); - - public static Vector2I operator ^(Vector2I vector, T scalar) => - new Vector2I(vector.X ^ scalar, vector.Y ^ scalar); - - public static Vector2I operator ^(T scalar, Vector2I vector) => - new Vector2I(scalar ^ vector.X, scalar ^ vector.Y); - - // NOT operator - public static Vector2I operator ~(Vector2I vector) => - new Vector2I(~vector.X, ~vector.Y); - // IBinaryInteger // TODO: Verify these are actually correct diff --git a/sources/Maths/Maths/Vector2I.gen.cs b/sources/Maths/Maths/Vector2I.gen.cs index c8631934e7..afe221d779 100644 --- a/sources/Maths/Maths/Vector2I.gen.cs +++ b/sources/Maths/Maths/Vector2I.gen.cs @@ -3,10 +3,18 @@ namespace Silk.NET.Maths using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Numerics; + using System.Runtime.InteropServices; + using System.Text; partial struct Vector2I : IEquatable>, - IReadOnlyList + IReadOnlyList, + IFormattable, + IParsable>, + ISpanFormattable, + ISpanParsable>, + IUtf8SpanFormattable, + IUtf8SpanParsable> where T : IBinaryInteger { /// The X component of the vector. @@ -21,6 +29,34 @@ partial struct Vector2I : /// Initializes the vector with individual component values. public Vector2I(T x, T y) => (X, Y) = (x, y); + /// Initializes the vector from a span of 2 values. + public Vector2I(ReadOnlySpan values) + { + if (values.Length != 2) + throw new ArgumentException("Input span must contain exactly 2 elements.", nameof(values)); + + X = values[0]; + Y = values[1]; + } + + /// Gets a vector whose 2 elements are equal to one. + public static Vector2I One => new(Scalar.One); + + /// Returns a vector whose 2 elements are equal to zero. + public static Vector2I Zero => default; + + /// Gets the vector (1, 0). + public static Vector2I UnitX => new(Scalar.One, Scalar.Zero); + + /// Gets the vector (0, 1). + public static Vector2I UnitY => new(Scalar.Zero, Scalar.One); + + /// Gets a vector with all bits set for each component. + public static Vector2I AllBitsSet => new Vector2I(T.AllBitsSet, T.AllBitsSet); + + /// Gets the squared length of the vector (dot product with itself). + public T LengthSquared => Vector2I.Dot(this, this); + /// T IReadOnlyList.this[int index] => this[index]; @@ -55,6 +91,197 @@ public IEnumerator GetEnumerator() yield return Y; } + /// Copies the components of the vector to the specified array starting at index 0. + public void CopyTo(T[] array) => CopyTo(array, 0); + + /// Copies the components of the vector to the specified array starting at the given index. + public void CopyTo(T[] array, int startIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (startIndex < 0 || startIndex + 2 > array.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + array[startIndex] = X; + array[startIndex + 1] = Y; + } + + /// Copies the components of the vector to the specified span starting at index 0. + public void CopyTo(Span span) => CopyTo(span, 0); + + /// Copies the components of the vector to the specified span starting at the given index. + public void CopyTo(Span span, int startIndex) + { + if (startIndex < 0 || startIndex + 2 > span.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + span[startIndex] = X; + span[startIndex + 1] = Y; + } + + /// Returns a span over the vector components. + public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 2); + + /// Formats the vector as a string. + public override string ToString() => + $"<{X}, {Y}>"; + + /// Formats the vector as a string using the specified format and format provider. + public string ToString(string? format, IFormatProvider? formatProvider) => + $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}>"; + + /// Parses a string to a instance. + public static Vector2I Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); + + /// Parses a span to a instance. + public static Vector2I Parse(ReadOnlySpan s, IFormatProvider? provider) + { + if (!TryParse(s, provider, out var result)) + throw new FormatException("Invalid format for Vector2I."); + + return result; + } + + /// Formats the vector as a UTF-8 string using the specified format and format provider. + public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider)|| + !Y.TryFormat(yBuffer, out int yChars, format, provider)) + { + bytesWritten = 0; + return false; + } + + int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + + Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + + Encoding.UTF8.GetByteCount("<, >"); + + if (utf8Destination.Length < estimatedSize) + { + bytesWritten = 0; + return false; + } + + int totalBytes = 0; + + totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); + + bytesWritten = totalBytes; + return true; + } + + /// Formats the vector as a string using the specified format and format provider. + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider) || + !Y.TryFormat(yBuffer, out int yChars, format, provider)) + { + charsWritten = 0; + return false; + } + + int requiredLength = 1 + xChars + 2 + yChars + 1; + + if (destination.Length < requiredLength) + { + charsWritten = 0; + return false; + } + + int pos = 0; + destination[pos++] = '<'; + + xBuffer[..xChars].CopyTo(destination[pos..]); + pos += xChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + yBuffer[..yChars].CopyTo(destination[pos..]); + pos += yChars; + + destination[pos++] = '>'; + + charsWritten = pos; + return true; + } + + /// Tries to parse a span to a instance. + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) + { + result = default; + + s = s.Trim(); + if (s.Length < 4 || s[0] != '<' || s[^1] != '>') + return false; + + s = s[1..^1]; // Remove < and > + + int commaX = s.IndexOf(','); + if (commaX < 0) + return false; + + ReadOnlySpan xSpan = s[..commaX].Trim(); + ReadOnlySpan ySpan = s[(commaX + 1)..].Trim(); + + if (T.TryParse(xSpan, provider, out var x) && + T.TryParse(ySpan, provider, out var y)) + { + result = new Vector2I(x, y); + return true; + } + + return false; + } + + /// Parses a UTF-8 span to a instance. + public static Vector2I Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return Parse(charBuffer, provider); + } + + /// Tries to parse a UTF-8 span to a instance. + public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return TryParse(charBuffer, provider, out result); + } + + /// Tries to parse a string to a instance. + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) => + TryParse(s.AsSpan(), provider, out result); + + /// Parses a span to a instance. + static Vector2I ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => + Parse(s, provider); + + /// Parses a string to a instance. + static Vector2I IParsable>.Parse(string s, IFormatProvider? provider) => + Parse(s, provider); + + /// Tries to parse a span to a instance. + static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) => + TryParse(s, provider, out result); + + /// Tries to parse a string to a instance. + static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector2I result) => + TryParse(s, provider, out result); + /// Returns a boolean indicating whether the given two vectors are equal. /// The first vector to compare. /// The second vector to compare. @@ -77,10 +304,92 @@ public IEnumerator GetEnumerator() /// public override int GetHashCode() => HashCode.Combine(X, Y); + + public static Vector2I operator +(Vector2I vector) => + vector; + + public static Vector2I operator -(Vector2I vector) => + new Vector2I(-vector.X, -vector.Y); + + public static Vector2I operator +(Vector2I left, Vector2I right) => + new Vector2I(left.X + right.X, left.Y + right.Y); + + public static Vector2I operator -(Vector2I left, Vector2I right) => + new Vector2I(left.X - right.X, left.Y - right.Y); + + public static Vector2I operator *(Vector2I left, Vector2I right) => + new Vector2I(left.X * right.X, left.Y * right.Y); + + public static Vector2I operator /(Vector2I left, Vector2I right) => + new Vector2I(left.X / right.X, left.Y / right.Y); + + public static Vector2I operator %(Vector2I left, Vector2I right) => + new Vector2I(left.X % right.X, left.Y % right.Y); + + public static Vector2I operator +(Vector2I vector, T scalar) => + new Vector2I(vector.X + scalar, vector.Y + scalar); + + public static Vector2I operator -(Vector2I vector, T scalar) => + new Vector2I(vector.X - scalar, vector.Y - scalar); + + public static Vector2I operator *(Vector2I vector, T scalar) => + new Vector2I(vector.X * scalar, vector.Y * scalar); + + public static Vector2I operator *(T scalar, Vector2I vector) => + new Vector2I(scalar * vector.X, scalar * vector.Y); + + public static Vector2I operator /(Vector2I vector, T scalar) => + new Vector2I(vector.X / scalar, vector.Y / scalar); + + public static Vector2I operator %(Vector2I vector, T scalar) => + new Vector2I(vector.X % scalar, vector.Y % scalar); + + public static Vector2I operator ~(Vector2I vector) => + new Vector2I(~vector.X, ~vector.Y); + + public static Vector2I operator &(Vector2I left, Vector2I right) => + new Vector2I(left.X & right.X, left.Y & right.Y); + + public static Vector2I operator |(Vector2I left, Vector2I right) => + new Vector2I(left.X | right.X, left.Y | right.Y); + + public static Vector2I operator ^(Vector2I left, Vector2I right) => + new Vector2I(left.X ^ right.X, left.Y ^ right.Y); + + public static Vector2I operator &(Vector2I vector, T scalar) => + new Vector2I(vector.X & scalar, vector.Y & scalar); + + public static Vector2I operator &(T scalar, Vector2I vector) => + new Vector2I(scalar & vector.X, scalar & vector.Y); + + public static Vector2I operator |(Vector2I vector, T scalar) => + new Vector2I(vector.X | scalar, vector.Y | scalar); + + public static Vector2I operator |(T scalar, Vector2I vector) => + new Vector2I(scalar | vector.X, scalar | vector.Y); + + public static Vector2I operator ^(Vector2I vector, T scalar) => + new Vector2I(vector.X ^ scalar, vector.Y ^ scalar); + + public static Vector2I operator ^(T scalar, Vector2I vector) => + new Vector2I(scalar ^ vector.X, scalar ^ vector.Y); } static partial class Vector2I { + /// Computes the dot product of two vectors. + public static T Dot(this Vector2I left, Vector2I right) + where T : IBinaryInteger => + left.X * right.X + left.Y * right.Y; + + /// Reflects a vector over a normal vector. + public static Vector2I Reflect(Vector2I vector, Vector2I normal) + where T : IBinaryInteger + { + T dot = vector.Dot(normal); + return vector - (normal * (dot + dot)); + } + public static Vector2I Log(this Vector2I x) where TSelf : IBinaryInteger, ILogarithmicFunctions => new(TSelf.Log(x.X), TSelf.Log(x.Y)); diff --git a/sources/Maths/Maths/Vector3F.gen.cs b/sources/Maths/Maths/Vector3F.gen.cs index 93b997b6e1..6c9a8a9f67 100644 --- a/sources/Maths/Maths/Vector3F.gen.cs +++ b/sources/Maths/Maths/Vector3F.gen.cs @@ -3,10 +3,18 @@ namespace Silk.NET.Maths using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Numerics; + using System.Runtime.InteropServices; + using System.Text; partial struct Vector3F : IEquatable>, - IReadOnlyList + IReadOnlyList, + IFormattable, + IParsable>, + ISpanFormattable, + ISpanParsable>, + IUtf8SpanFormattable, + IUtf8SpanParsable> where T : IFloatingPointIeee754 { /// The X component of the vector. @@ -24,6 +32,38 @@ partial struct Vector3F : /// Initializes the vector with individual component values. public Vector3F(T x, T y, T z) => (X, Y, Z) = (x, y, z); + /// Initializes the vector using a for the initial elements, and the specified component for the remainder. + public Vector3F(Vector2F other, T z) => (X, Y, Z) = (other.X, other.Y, z); + + /// Initializes the vector from a span of 3 values. + public Vector3F(ReadOnlySpan values) + { + if (values.Length != 3) + throw new ArgumentException("Input span must contain exactly 3 elements.", nameof(values)); + + X = values[0]; + Y = values[1]; + Z = values[2]; + } + + /// Gets a vector whose 3 elements are equal to one. + public static Vector3F One => new(Scalar.One); + + /// Returns a vector whose 3 elements are equal to zero. + public static Vector3F Zero => default; + + /// Gets the vector (1, 0, 0). + public static Vector3F UnitX => new(Scalar.One, Scalar.Zero, Scalar.Zero); + + /// Gets the vector (0, 1, 0). + public static Vector3F UnitY => new(Scalar.Zero, Scalar.One, Scalar.Zero); + + /// Gets the vector (0, 0, 1). + public static Vector3F UnitZ => new(Scalar.Zero, Scalar.Zero, Scalar.One); + + /// Gets the squared length of the vector (dot product with itself). + public T LengthSquared => Vector3F.Dot(this, this); + /// T IReadOnlyList.this[int index] => this[index]; @@ -61,6 +101,220 @@ public IEnumerator GetEnumerator() yield return Z; } + /// Copies the components of the vector to the specified array starting at index 0. + public void CopyTo(T[] array) => CopyTo(array, 0); + + /// Copies the components of the vector to the specified array starting at the given index. + public void CopyTo(T[] array, int startIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (startIndex < 0 || startIndex + 3 > array.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + array[startIndex] = X; + array[startIndex + 1] = Y; + array[startIndex + 2] = Z; + } + + /// Copies the components of the vector to the specified span starting at index 0. + public void CopyTo(Span span) => CopyTo(span, 0); + + /// Copies the components of the vector to the specified span starting at the given index. + public void CopyTo(Span span, int startIndex) + { + if (startIndex < 0 || startIndex + 3 > span.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + span[startIndex] = X; + span[startIndex + 1] = Y; + span[startIndex + 2] = Z; + } + + /// Returns a span over the vector components. + public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 3); + + /// Formats the vector as a string. + public override string ToString() => + $"<{X}, {Y}, {Z}>"; + + /// Formats the vector as a string using the specified format and format provider. + public string ToString(string? format, IFormatProvider? formatProvider) => + $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}, {Z.ToString(format, formatProvider)}>"; + + /// Parses a string to a instance. + public static Vector3F Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); + + /// Parses a span to a instance. + public static Vector3F Parse(ReadOnlySpan s, IFormatProvider? provider) + { + if (!TryParse(s, provider, out var result)) + throw new FormatException("Invalid format for Vector3F."); + + return result; + } + + /// Formats the vector as a UTF-8 string using the specified format and format provider. + public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + Span zBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider)|| + !Y.TryFormat(yBuffer, out int yChars, format, provider)|| + !Z.TryFormat(zBuffer, out int zChars, format, provider)) + { + bytesWritten = 0; + return false; + } + + int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + + Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + + Encoding.UTF8.GetByteCount(zBuffer[..zChars]) + + Encoding.UTF8.GetByteCount("<, >"); + + if (utf8Destination.Length < estimatedSize) + { + bytesWritten = 0; + return false; + } + + int totalBytes = 0; + + totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(zBuffer[..zChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); + + bytesWritten = totalBytes; + return true; + } + + /// Formats the vector as a string using the specified format and format provider. + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + Span zBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider) || + !Y.TryFormat(yBuffer, out int yChars, format, provider) || + !Z.TryFormat(zBuffer, out int zChars, format, provider)) + { + charsWritten = 0; + return false; + } + + int requiredLength = 1 + xChars + 2 + yChars + 2 + zChars + 1; + + if (destination.Length < requiredLength) + { + charsWritten = 0; + return false; + } + + int pos = 0; + destination[pos++] = '<'; + + xBuffer[..xChars].CopyTo(destination[pos..]); + pos += xChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + yBuffer[..yChars].CopyTo(destination[pos..]); + pos += yChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + zBuffer[..zChars].CopyTo(destination[pos..]); + pos += zChars; + + destination[pos++] = '>'; + + charsWritten = pos; + return true; + } + + /// Tries to parse a span to a instance. + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3F result) + { + result = default; + + s = s.Trim(); + if (s.Length < 6 || s[0] != '<' || s[^1] != '>') + return false; + + s = s[1..^1]; // Remove < and > + + int commaX = s.IndexOf(','); + if (commaX < 0) + return false; + + ReadOnlySpan remainder1 = s.Slice(commaX + 1); + int commaYRelative = remainder1.IndexOf(','); + if (commaYRelative < 0) + return false; + int commaY = commaX + 1 + commaYRelative; + + ReadOnlySpan xSpan = s[..commaX].Trim(); + ReadOnlySpan ySpan = s[(commaX + 1)..commaY].Trim(); + ReadOnlySpan zSpan = s[(commaY + 1)..].Trim(); + + if (T.TryParse(xSpan, provider, out var x) && + T.TryParse(ySpan, provider, out var y) && + T.TryParse(zSpan, provider, out var z)) + { + result = new Vector3F(x, y, z); + return true; + } + + return false; + } + + /// Parses a UTF-8 span to a instance. + public static Vector3F Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return Parse(charBuffer, provider); + } + + /// Tries to parse a UTF-8 span to a instance. + public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3F result) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return TryParse(charBuffer, provider, out result); + } + + /// Tries to parse a string to a instance. + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3F result) => + TryParse(s.AsSpan(), provider, out result); + + /// Parses a span to a instance. + static Vector3F ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => + Parse(s, provider); + + /// Parses a string to a instance. + static Vector3F IParsable>.Parse(string s, IFormatProvider? provider) => + Parse(s, provider); + + /// Tries to parse a span to a instance. + static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3F result) => + TryParse(s, provider, out result); + + /// Tries to parse a string to a instance. + static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3F result) => + TryParse(s, provider, out result); + /// Returns a boolean indicating whether the given two vectors are equal. /// The first vector to compare. /// The second vector to compare. @@ -84,10 +338,76 @@ public IEnumerator GetEnumerator() /// public override int GetHashCode() => HashCode.Combine(X, Y, Z); + + public static Vector3F operator +(Vector3F vector) => + vector; + + public static Vector3F operator -(Vector3F vector) => + new Vector3F(-vector.X, -vector.Y, -vector.Z); + + public static Vector3F operator +(Vector3F left, Vector3F right) => + new Vector3F(left.X + right.X, left.Y + right.Y, left.Z + right.Z); + + public static Vector3F operator -(Vector3F left, Vector3F right) => + new Vector3F(left.X - right.X, left.Y - right.Y, left.Z - right.Z); + + public static Vector3F operator *(Vector3F left, Vector3F right) => + new Vector3F(left.X * right.X, left.Y * right.Y, left.Z * right.Z); + + public static Vector3F operator /(Vector3F left, Vector3F right) => + new Vector3F(left.X / right.X, left.Y / right.Y, left.Z / right.Z); + + public static Vector3F operator %(Vector3F left, Vector3F right) => + new Vector3F(left.X % right.X, left.Y % right.Y, left.Z % right.Z); + + public static Vector3F operator +(Vector3F vector, T scalar) => + new Vector3F(vector.X + scalar, vector.Y + scalar, vector.Z + scalar); + + public static Vector3F operator -(Vector3F vector, T scalar) => + new Vector3F(vector.X - scalar, vector.Y - scalar, vector.Z - scalar); + + public static Vector3F operator *(Vector3F vector, T scalar) => + new Vector3F(vector.X * scalar, vector.Y * scalar, vector.Z * scalar); + + public static Vector3F operator *(T scalar, Vector3F vector) => + new Vector3F(scalar * vector.X, scalar * vector.Y, scalar * vector.Z); + + public static Vector3F operator /(Vector3F vector, T scalar) => + new Vector3F(vector.X / scalar, vector.Y / scalar, vector.Z / scalar); + + public static Vector3F operator %(Vector3F vector, T scalar) => + new Vector3F(vector.X % scalar, vector.Y % scalar, vector.Z % scalar); + } static partial class Vector3F { + /// Computes the dot product of two vectors. + public static T Dot(this Vector3F left, Vector3F right) + where T : IFloatingPointIeee754 => + left.X * right.X + left.Y * right.Y + left.Z * right.Z; + + /// Reflects a vector over a normal vector. + public static Vector3F Reflect(Vector3F vector, Vector3F normal) + where T : IFloatingPointIeee754 + { + T dot = vector.Dot(normal); + return vector - (normal * (dot + dot)); + } + + /// Computes the length of the vector. + public static T GetLength(this Vector3F vector) + where T : IFloatingPointIeee754 => + T.Sqrt(vector.LengthSquared); + + /// Normalizes a vector. + public static Vector3F Normalize(this Vector3F vector) + where T : IFloatingPointIeee754 + { + T length = vector.GetLength(); + return length != T.Zero ? vector / length : Vector3F.Zero; + } + public static Vector3F Log(this Vector3F x) where TSelf : IFloatingPointIeee754, ILogarithmicFunctions => new(TSelf.Log(x.X), TSelf.Log(x.Y), TSelf.Log(x.Z)); diff --git a/sources/Maths/Maths/Vector3I.cs b/sources/Maths/Maths/Vector3I.cs index ac7a810b7d..167273b467 100644 --- a/sources/Maths/Maths/Vector3I.cs +++ b/sources/Maths/Maths/Vector3I.cs @@ -12,57 +12,8 @@ namespace Silk.NET.Maths { /// A structure representing a 3D integer vector. - internal partial struct Vector3I : - ISpanFormattable, - ISpanParsable>, - IUtf8SpanFormattable, - IUtf8SpanParsable>, - IParsable>, - IFormattable - where T : IBinaryInteger + internal partial struct Vector3I { - /// Initializes the vector from a span of three values. - public Vector3I(ReadOnlySpan values) - { - if (values.Length != 3) - throw new ArgumentException("Input span must contain exactly 3 elements.", nameof(values)); - - X = values[0]; - Y = values[1]; - Z = values[2]; - } - - /// Initializes the vector using a Vector2I for X and Y, and a separate value for Z. - // TODO: Make sure lower dimensional constructors arent meant to zero-out the higher dimensions - public Vector3I(Vector2I xy, T z) => (X, Y, Z) = (xy.X, xy.Y, z); - - /// Gets a vector whose 3 elements are equal to one. - public static Vector3I One => new(Scalar.One); - - /// Returns a vector whose 3 elements are equal to zero. - public static Vector3I Zero => default; - - /// Gets the vector (1, 0, 0). - public static Vector3I UnitX => new(Scalar.One, Scalar.Zero, Scalar.Zero); - - /// Gets the vector (0, 1, 0). - public static Vector3I UnitY => new(Scalar.Zero, Scalar.One, Scalar.Zero); - - /// Gets the vector (0, 0, 1). - public static Vector3I UnitZ => new(Scalar.Zero, Scalar.Zero, Scalar.One); - - /// Gets a vector with all bits set for each component. - public static Vector3I AllBitsSet => new Vector3I(T.AllBitsSet, T.AllBitsSet, T.AllBitsSet); - - /// Gets the squared length of the vector (dot product with itself). - public T LengthSquared => (X * X) + (Y * Y) + (Z * Z); - - /// Computes the dot product of this vector with another vector. - public T Dot(Vector3I other) => (X * other.X) + (Y * other.Y) + (Z * other.Z); - - /// Computes the dot product of two vectors. - public static T Dot(Vector3I left, Vector3I right) => (left.X * right.X) + (left.Y * right.Y) + (left.Z * right.Z); - /// Computes the cross product of this vector with another vector. public Vector3I Cross(Vector3I other) => new Vector3I( @@ -79,9 +30,6 @@ public static Vector3I Cross(Vector3I left, Vector3I right) => (left.X * right.Y) - (left.Y * right.X) ); - /// Returns a span over the vector components. - public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 3); - /// Returns a vector with the component-wise maximum of this and another vector. public Vector3I Max(Vector3I other) => new Vector3I(T.Max(X, other.X), T.Max(Y, other.Y), T.Max(Z, other.Z)); @@ -153,99 +101,6 @@ public static Vector3I Clamp(Vector3I vector, T min, T max) => public static Vector3I Abs(Vector3I vector) => new Vector3I(T.Abs(vector.X), T.Abs(vector.Y), T.Abs(vector.Z)); - /// Formats the vector as a string using the specified format and format provider. - public string ToString(string? format, IFormatProvider? formatProvider) => - $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}, {Z.ToString(format, formatProvider)}>"; - - /// Formats the vector as a string. - public override string ToString() => $"<{X}, {Y}, {Z}>"; - - /// Formats the vector as a string using the specified format and format provider. - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) - { - // Format components individually into temporary buffers - Span xBuffer = stackalloc char[64]; - Span yBuffer = stackalloc char[64]; - Span zBuffer = stackalloc char[64]; - - if (!X.TryFormat(xBuffer, out int xChars, format, provider) || - !Y.TryFormat(yBuffer, out int yChars, format, provider) || - !Z.TryFormat(zBuffer, out int zChars, format, provider)) - { - charsWritten = 0; - return false; - } - - // Calculate total required length: < + x + ", " + y + ", " + z + > - int requiredLength = 1 + xChars + 2 + yChars + 2 + zChars + 1; - - if (destination.Length < requiredLength) - { - charsWritten = 0; - return false; - } - - int pos = 0; - destination[pos++] = '<'; - - xBuffer[..xChars].CopyTo(destination[pos..]); - pos += xChars; - - destination[pos++] = ','; - destination[pos++] = ' '; - - yBuffer[..yChars].CopyTo(destination[pos..]); - pos += yChars; - - destination[pos++] = ','; - destination[pos++] = ' '; - - zBuffer[..zChars].CopyTo(destination[pos..]); - pos += zChars; - - destination[pos++] = '>'; - - charsWritten = pos; - return true; - } - - /// Parses a span to a instance. - public static Vector3I Parse(ReadOnlySpan s, IFormatProvider? provider) - { - if (!TryParse(s, provider, out var result)) - throw new FormatException("Invalid format for Vector3I."); - - return result; - } - - /// Copies the components of the vector to the specified array starting at index 0. - public void CopyTo(T[] array) => CopyTo(array, 0); - - /// Copies the components of the vector to the specified array starting at the given index. - public void CopyTo(T[] array, int startIndex) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (startIndex < 0 || startIndex + 3 > array.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex)); - array[startIndex] = X; - array[startIndex + 1] = Y; - array[startIndex + 2] = Z; - } - - /// Copies the components of the vector to the specified span starting at index 0. - public void CopyTo(Span span) => CopyTo(span, 0); - - /// Copies the components of the vector to the specified span starting at the given index. - public void CopyTo(Span span, int startIndex) - { - if (startIndex < 0 || startIndex + 3 > span.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex)); - span[startIndex] = X; - span[startIndex + 1] = Y; - span[startIndex + 2] = Z; - } - /// Returns a vector where each component is the sign of the original vector's component. public Vector3I Sign() => new Vector3I(T.CreateChecked(T.Sign(X)), T.CreateChecked(T.Sign(Y)), T.CreateChecked(T.Sign(Z))); @@ -270,130 +125,6 @@ public Vector3I CopySign(T signScalar) => public static Vector3I CopySign(Vector3I value, T signScalar) => new Vector3I(T.CopySign(value.X, signScalar), T.CopySign(value.Y, signScalar), T.CopySign(value.Z, signScalar)); - /// Parses a string to a instance. - public static Vector3I Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); - - /// Tries to parse a span to a instance. - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) - { - result = default; - - s = s.Trim(); - if (s.Length < 7 || s[0] != '<' || s[^1] != '>') - return false; - - s = s[1..^1]; // Remove < and > - - int firstComma = s.IndexOf(','); - if (firstComma < 0) - return false; - - // Kind of hacky, but it works - // TODO: See if there's a better way - ReadOnlySpan remainder = s.Slice(firstComma + 1); - int secondCommaRelative = remainder.IndexOf(','); - if (secondCommaRelative < 0) - return false; - - int secondComma = firstComma + 1 + secondCommaRelative; - if (secondComma < 0) - return false; - - ReadOnlySpan xSpan = s[..firstComma].Trim(); - ReadOnlySpan ySpan = s[(firstComma + 1)..secondComma].Trim(); - ReadOnlySpan zSpan = s[(secondComma + 1)..].Trim(); - - if (T.TryParse(xSpan, provider, out var x) && - T.TryParse(ySpan, provider, out var y) && - T.TryParse(zSpan, provider, out var z)) - { - result = new Vector3I(x, y, z); - return true; - } - - return false; - } - - /// Tries to parse a string to a instance. - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) => - TryParse(s.AsSpan(), provider, out result); - - /// Parses a span to a instance. - static Vector3I ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => - Parse(s, provider); - - /// Parses a string to a instance. - static Vector3I IParsable>.Parse(string s, IFormatProvider? provider) => - Parse(s, provider); - - /// Tries to parse a span to a instance. - static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) => - TryParse(s, provider, out result); - - /// Tries to parse a string to a instance. - static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) => - TryParse(s, provider, out result); - - /// Formats the vector as a UTF-8 string using the specified format and format provider. - public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) - { - // Format components individually into temporary buffers - Span xBuffer = stackalloc char[64]; - Span yBuffer = stackalloc char[64]; - Span zBuffer = stackalloc char[64]; - - if (!X.TryFormat(xBuffer, out int xChars, format, provider) || - !Y.TryFormat(yBuffer, out int yChars, format, provider) || - !Z.TryFormat(zBuffer, out int zChars, format, provider)) - { - bytesWritten = 0; - return false; - } - - // Estimate total required UTF-8 bytes - int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + - Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + - Encoding.UTF8.GetByteCount(zBuffer[..zChars]) + - Encoding.UTF8.GetByteCount("<, , >"); - - if (utf8Destination.Length < estimatedSize) - { - bytesWritten = 0; - return false; - } - - int totalBytes = 0; - - totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(zBuffer[..zChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); - - bytesWritten = totalBytes; - return true; - } - - /// Parses a UTF-8 span to a instance. - public static Vector3I Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) - { - int charCount = Encoding.UTF8.GetCharCount(utf8Text); - Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; - Encoding.UTF8.GetChars(utf8Text, charBuffer); - return Parse(charBuffer, provider); - } - - /// Tries to parse a UTF-8 span to a instance. - public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) - { - int charCount = Encoding.UTF8.GetCharCount(utf8Text); - Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; - Encoding.UTF8.GetChars(utf8Text, charBuffer); - return TryParse(charBuffer, provider, out result); - } - // Casts /// Explicitly casts a to a . @@ -404,77 +135,6 @@ public static explicit operator Vector3I(System.Numerics.Vector3 v) => public static explicit operator System.Numerics.Vector3(Vector3I v) => new System.Numerics.Vector3(Convert.ToSingle(v.X), Convert.ToSingle(v.Y), Convert.ToSingle(v.Z)); - // Component Operators - public static Vector3I operator +(Vector3I left, Vector3I right) => - new Vector3I(left.X + right.X, left.Y + right.Y, left.Z + right.Z); - - public static Vector3I operator -(Vector3I left, Vector3I right) => - new Vector3I(left.X - right.X, left.Y - right.Y, left.Z - right.Z); - - public static Vector3I operator *(Vector3I left, Vector3I right) => - new Vector3I(left.X * right.X, left.Y * right.Y, left.Z * right.Z); - - public static Vector3I operator /(Vector3I left, Vector3I right) => - new Vector3I(left.X / right.X, left.Y / right.Y, left.Z / right.Z); - - public static Vector3I operator %(Vector3I left, Vector3I right) => - new Vector3I(left.X % right.X, left.Y % right.Y, left.Z % right.Z); - - // Scalar Operators - public static Vector3I operator +(Vector3I vector, T scalar) => - new Vector3I(vector.X + scalar, vector.Y + scalar, vector.Z + scalar); - - public static Vector3I operator -(Vector3I vector, T scalar) => - new Vector3I(vector.X - scalar, vector.Y - scalar, vector.Z - scalar); - - public static Vector3I operator *(Vector3I vector, T scalar) => - new Vector3I(vector.X * scalar, vector.Y * scalar, vector.Z * scalar); - - public static Vector3I operator /(Vector3I vector, T scalar) => - new Vector3I(vector.X / scalar, vector.Y / scalar, vector.Z / scalar); - - public static Vector3I operator %(Vector3I vector, T scalar) => - new Vector3I(vector.X % scalar, vector.Y % scalar, vector.Z % scalar); - - // + operator: returns the vector (?) - public static Vector3I operator +(Vector3I vector) => vector; - - // - operator: returns the negated vector - public static Vector3I operator -(Vector3I vector) => - new Vector3I(-vector.X, -vector.Y, -vector.Z); - - // Bitwise Operators - public static Vector3I operator &(Vector3I left, Vector3I right) => - new Vector3I(left.X & right.X, left.Y & right.Y, left.Z & right.Z); - - public static Vector3I operator |(Vector3I left, Vector3I right) => - new Vector3I(left.X | right.X, left.Y | right.Y, left.Z | right.Z); - - public static Vector3I operator ^(Vector3I left, Vector3I right) => - new Vector3I(left.X ^ right.X, left.Y ^ right.Y, left.Z ^ right.Z); - - public static Vector3I operator &(Vector3I vector, T scalar) => - new Vector3I(vector.X & scalar, vector.Y & scalar, vector.Z & scalar); - - public static Vector3I operator &(T scalar, Vector3I vector) => - new Vector3I(scalar & vector.X, scalar & vector.Y, scalar & vector.Z); - - public static Vector3I operator |(Vector3I vector, T scalar) => - new Vector3I(vector.X | scalar, vector.Y | scalar, vector.Z | scalar); - - public static Vector3I operator |(T scalar, Vector3I vector) => - new Vector3I(scalar | vector.X, scalar | vector.Y, scalar | vector.Z); - - public static Vector3I operator ^(Vector3I vector, T scalar) => - new Vector3I(vector.X ^ scalar, vector.Y ^ scalar, vector.Z ^ scalar); - - public static Vector3I operator ^(T scalar, Vector3I vector) => - new Vector3I(scalar ^ vector.X, scalar ^ vector.Y, scalar ^ vector.Z); - - // NOT operator - public static Vector3I operator ~(Vector3I vector) => - new Vector3I(~vector.X, ~vector.Y, ~vector.Z); - // IBinaryInteger public static Vector3I Log2(Vector3I x) => new Vector3I(T.Log2(x.X), T.Log2(x.Y), T.Log2(x.Z)); diff --git a/sources/Maths/Maths/Vector3I.gen.cs b/sources/Maths/Maths/Vector3I.gen.cs index 45ee97e364..05bb368e10 100644 --- a/sources/Maths/Maths/Vector3I.gen.cs +++ b/sources/Maths/Maths/Vector3I.gen.cs @@ -3,10 +3,18 @@ namespace Silk.NET.Maths using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Numerics; + using System.Runtime.InteropServices; + using System.Text; partial struct Vector3I : IEquatable>, - IReadOnlyList + IReadOnlyList, + IFormattable, + IParsable>, + ISpanFormattable, + ISpanParsable>, + IUtf8SpanFormattable, + IUtf8SpanParsable> where T : IBinaryInteger { /// The X component of the vector. @@ -24,6 +32,41 @@ partial struct Vector3I : /// Initializes the vector with individual component values. public Vector3I(T x, T y, T z) => (X, Y, Z) = (x, y, z); + /// Initializes the vector using a for the initial elements, and the specified component for the remainder. + public Vector3I(Vector2I other, T z) => (X, Y, Z) = (other.X, other.Y, z); + + /// Initializes the vector from a span of 3 values. + public Vector3I(ReadOnlySpan values) + { + if (values.Length != 3) + throw new ArgumentException("Input span must contain exactly 3 elements.", nameof(values)); + + X = values[0]; + Y = values[1]; + Z = values[2]; + } + + /// Gets a vector whose 3 elements are equal to one. + public static Vector3I One => new(Scalar.One); + + /// Returns a vector whose 3 elements are equal to zero. + public static Vector3I Zero => default; + + /// Gets the vector (1, 0, 0). + public static Vector3I UnitX => new(Scalar.One, Scalar.Zero, Scalar.Zero); + + /// Gets the vector (0, 1, 0). + public static Vector3I UnitY => new(Scalar.Zero, Scalar.One, Scalar.Zero); + + /// Gets the vector (0, 0, 1). + public static Vector3I UnitZ => new(Scalar.Zero, Scalar.Zero, Scalar.One); + + /// Gets a vector with all bits set for each component. + public static Vector3I AllBitsSet => new Vector3I(T.AllBitsSet, T.AllBitsSet, T.AllBitsSet); + + /// Gets the squared length of the vector (dot product with itself). + public T LengthSquared => Vector3I.Dot(this, this); + /// T IReadOnlyList.this[int index] => this[index]; @@ -61,6 +104,220 @@ public IEnumerator GetEnumerator() yield return Z; } + /// Copies the components of the vector to the specified array starting at index 0. + public void CopyTo(T[] array) => CopyTo(array, 0); + + /// Copies the components of the vector to the specified array starting at the given index. + public void CopyTo(T[] array, int startIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (startIndex < 0 || startIndex + 3 > array.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + array[startIndex] = X; + array[startIndex + 1] = Y; + array[startIndex + 2] = Z; + } + + /// Copies the components of the vector to the specified span starting at index 0. + public void CopyTo(Span span) => CopyTo(span, 0); + + /// Copies the components of the vector to the specified span starting at the given index. + public void CopyTo(Span span, int startIndex) + { + if (startIndex < 0 || startIndex + 3 > span.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + span[startIndex] = X; + span[startIndex + 1] = Y; + span[startIndex + 2] = Z; + } + + /// Returns a span over the vector components. + public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 3); + + /// Formats the vector as a string. + public override string ToString() => + $"<{X}, {Y}, {Z}>"; + + /// Formats the vector as a string using the specified format and format provider. + public string ToString(string? format, IFormatProvider? formatProvider) => + $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}, {Z.ToString(format, formatProvider)}>"; + + /// Parses a string to a instance. + public static Vector3I Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); + + /// Parses a span to a instance. + public static Vector3I Parse(ReadOnlySpan s, IFormatProvider? provider) + { + if (!TryParse(s, provider, out var result)) + throw new FormatException("Invalid format for Vector3I."); + + return result; + } + + /// Formats the vector as a UTF-8 string using the specified format and format provider. + public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + Span zBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider)|| + !Y.TryFormat(yBuffer, out int yChars, format, provider)|| + !Z.TryFormat(zBuffer, out int zChars, format, provider)) + { + bytesWritten = 0; + return false; + } + + int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + + Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + + Encoding.UTF8.GetByteCount(zBuffer[..zChars]) + + Encoding.UTF8.GetByteCount("<, >"); + + if (utf8Destination.Length < estimatedSize) + { + bytesWritten = 0; + return false; + } + + int totalBytes = 0; + + totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(zBuffer[..zChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); + + bytesWritten = totalBytes; + return true; + } + + /// Formats the vector as a string using the specified format and format provider. + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + Span zBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider) || + !Y.TryFormat(yBuffer, out int yChars, format, provider) || + !Z.TryFormat(zBuffer, out int zChars, format, provider)) + { + charsWritten = 0; + return false; + } + + int requiredLength = 1 + xChars + 2 + yChars + 2 + zChars + 1; + + if (destination.Length < requiredLength) + { + charsWritten = 0; + return false; + } + + int pos = 0; + destination[pos++] = '<'; + + xBuffer[..xChars].CopyTo(destination[pos..]); + pos += xChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + yBuffer[..yChars].CopyTo(destination[pos..]); + pos += yChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + zBuffer[..zChars].CopyTo(destination[pos..]); + pos += zChars; + + destination[pos++] = '>'; + + charsWritten = pos; + return true; + } + + /// Tries to parse a span to a instance. + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) + { + result = default; + + s = s.Trim(); + if (s.Length < 6 || s[0] != '<' || s[^1] != '>') + return false; + + s = s[1..^1]; // Remove < and > + + int commaX = s.IndexOf(','); + if (commaX < 0) + return false; + + ReadOnlySpan remainder1 = s.Slice(commaX + 1); + int commaYRelative = remainder1.IndexOf(','); + if (commaYRelative < 0) + return false; + int commaY = commaX + 1 + commaYRelative; + + ReadOnlySpan xSpan = s[..commaX].Trim(); + ReadOnlySpan ySpan = s[(commaX + 1)..commaY].Trim(); + ReadOnlySpan zSpan = s[(commaY + 1)..].Trim(); + + if (T.TryParse(xSpan, provider, out var x) && + T.TryParse(ySpan, provider, out var y) && + T.TryParse(zSpan, provider, out var z)) + { + result = new Vector3I(x, y, z); + return true; + } + + return false; + } + + /// Parses a UTF-8 span to a instance. + public static Vector3I Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return Parse(charBuffer, provider); + } + + /// Tries to parse a UTF-8 span to a instance. + public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return TryParse(charBuffer, provider, out result); + } + + /// Tries to parse a string to a instance. + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) => + TryParse(s.AsSpan(), provider, out result); + + /// Parses a span to a instance. + static Vector3I ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => + Parse(s, provider); + + /// Parses a string to a instance. + static Vector3I IParsable>.Parse(string s, IFormatProvider? provider) => + Parse(s, provider); + + /// Tries to parse a span to a instance. + static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) => + TryParse(s, provider, out result); + + /// Tries to parse a string to a instance. + static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector3I result) => + TryParse(s, provider, out result); + /// Returns a boolean indicating whether the given two vectors are equal. /// The first vector to compare. /// The second vector to compare. @@ -84,10 +341,92 @@ public IEnumerator GetEnumerator() /// public override int GetHashCode() => HashCode.Combine(X, Y, Z); + + public static Vector3I operator +(Vector3I vector) => + vector; + + public static Vector3I operator -(Vector3I vector) => + new Vector3I(-vector.X, -vector.Y, -vector.Z); + + public static Vector3I operator +(Vector3I left, Vector3I right) => + new Vector3I(left.X + right.X, left.Y + right.Y, left.Z + right.Z); + + public static Vector3I operator -(Vector3I left, Vector3I right) => + new Vector3I(left.X - right.X, left.Y - right.Y, left.Z - right.Z); + + public static Vector3I operator *(Vector3I left, Vector3I right) => + new Vector3I(left.X * right.X, left.Y * right.Y, left.Z * right.Z); + + public static Vector3I operator /(Vector3I left, Vector3I right) => + new Vector3I(left.X / right.X, left.Y / right.Y, left.Z / right.Z); + + public static Vector3I operator %(Vector3I left, Vector3I right) => + new Vector3I(left.X % right.X, left.Y % right.Y, left.Z % right.Z); + + public static Vector3I operator +(Vector3I vector, T scalar) => + new Vector3I(vector.X + scalar, vector.Y + scalar, vector.Z + scalar); + + public static Vector3I operator -(Vector3I vector, T scalar) => + new Vector3I(vector.X - scalar, vector.Y - scalar, vector.Z - scalar); + + public static Vector3I operator *(Vector3I vector, T scalar) => + new Vector3I(vector.X * scalar, vector.Y * scalar, vector.Z * scalar); + + public static Vector3I operator *(T scalar, Vector3I vector) => + new Vector3I(scalar * vector.X, scalar * vector.Y, scalar * vector.Z); + + public static Vector3I operator /(Vector3I vector, T scalar) => + new Vector3I(vector.X / scalar, vector.Y / scalar, vector.Z / scalar); + + public static Vector3I operator %(Vector3I vector, T scalar) => + new Vector3I(vector.X % scalar, vector.Y % scalar, vector.Z % scalar); + + public static Vector3I operator ~(Vector3I vector) => + new Vector3I(~vector.X, ~vector.Y, ~vector.Z); + + public static Vector3I operator &(Vector3I left, Vector3I right) => + new Vector3I(left.X & right.X, left.Y & right.Y, left.Z & right.Z); + + public static Vector3I operator |(Vector3I left, Vector3I right) => + new Vector3I(left.X | right.X, left.Y | right.Y, left.Z | right.Z); + + public static Vector3I operator ^(Vector3I left, Vector3I right) => + new Vector3I(left.X ^ right.X, left.Y ^ right.Y, left.Z ^ right.Z); + + public static Vector3I operator &(Vector3I vector, T scalar) => + new Vector3I(vector.X & scalar, vector.Y & scalar, vector.Z & scalar); + + public static Vector3I operator &(T scalar, Vector3I vector) => + new Vector3I(scalar & vector.X, scalar & vector.Y, scalar & vector.Z); + + public static Vector3I operator |(Vector3I vector, T scalar) => + new Vector3I(vector.X | scalar, vector.Y | scalar, vector.Z | scalar); + + public static Vector3I operator |(T scalar, Vector3I vector) => + new Vector3I(scalar | vector.X, scalar | vector.Y, scalar | vector.Z); + + public static Vector3I operator ^(Vector3I vector, T scalar) => + new Vector3I(vector.X ^ scalar, vector.Y ^ scalar, vector.Z ^ scalar); + + public static Vector3I operator ^(T scalar, Vector3I vector) => + new Vector3I(scalar ^ vector.X, scalar ^ vector.Y, scalar ^ vector.Z); } static partial class Vector3I { + /// Computes the dot product of two vectors. + public static T Dot(this Vector3I left, Vector3I right) + where T : IBinaryInteger => + left.X * right.X + left.Y * right.Y + left.Z * right.Z; + + /// Reflects a vector over a normal vector. + public static Vector3I Reflect(Vector3I vector, Vector3I normal) + where T : IBinaryInteger + { + T dot = vector.Dot(normal); + return vector - (normal * (dot + dot)); + } + public static Vector3I Log(this Vector3I x) where TSelf : IBinaryInteger, ILogarithmicFunctions => new(TSelf.Log(x.X), TSelf.Log(x.Y), TSelf.Log(x.Z)); diff --git a/sources/Maths/Maths/Vector4F.gen.cs b/sources/Maths/Maths/Vector4F.gen.cs index 871162afc5..be1a8e23ed 100644 --- a/sources/Maths/Maths/Vector4F.gen.cs +++ b/sources/Maths/Maths/Vector4F.gen.cs @@ -3,10 +3,18 @@ namespace Silk.NET.Maths using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Numerics; + using System.Runtime.InteropServices; + using System.Text; partial struct Vector4F : IEquatable>, - IReadOnlyList + IReadOnlyList, + IFormattable, + IParsable>, + ISpanFormattable, + ISpanParsable>, + IUtf8SpanFormattable, + IUtf8SpanParsable> where T : IFloatingPointIeee754 { /// The X component of the vector. @@ -27,6 +35,45 @@ partial struct Vector4F : /// Initializes the vector with individual component values. public Vector4F(T x, T y, T z, T w) => (X, Y, Z, W) = (x, y, z, w); + /// Initializes the vector using a for the initial elements, and the specified components for the remainder. + public Vector4F(Vector2F other, T z, T w) => (X, Y, Z, W) = (other.X, other.Y, z, w); + + /// Initializes the vector using a for the initial elements, and the specified component for the remainder. + public Vector4F(Vector3F other, T w) => (X, Y, Z, W) = (other.X, other.Y, other.Z, w); + + /// Initializes the vector from a span of 4 values. + public Vector4F(ReadOnlySpan values) + { + if (values.Length != 4) + throw new ArgumentException("Input span must contain exactly 4 elements.", nameof(values)); + + X = values[0]; + Y = values[1]; + Z = values[2]; + W = values[3]; + } + + /// Gets a vector whose 4 elements are equal to one. + public static Vector4F One => new(Scalar.One); + + /// Returns a vector whose 4 elements are equal to zero. + public static Vector4F Zero => default; + + /// Gets the vector (1, 0, 0, 0). + public static Vector4F UnitX => new(Scalar.One, Scalar.Zero, Scalar.Zero, Scalar.Zero); + + /// Gets the vector (0, 1, 0, 0). + public static Vector4F UnitY => new(Scalar.Zero, Scalar.One, Scalar.Zero, Scalar.Zero); + + /// Gets the vector (0, 0, 1, 0). + public static Vector4F UnitZ => new(Scalar.Zero, Scalar.Zero, Scalar.One, Scalar.Zero); + + /// Gets the vector (0, 0, 0, 1). + public static Vector4F UnitW => new(Scalar.Zero, Scalar.Zero, Scalar.Zero, Scalar.One); + + /// Gets the squared length of the vector (dot product with itself). + public T LengthSquared => Vector4F.Dot(this, this); + /// T IReadOnlyList.this[int index] => this[index]; @@ -67,6 +114,243 @@ public IEnumerator GetEnumerator() yield return W; } + /// Copies the components of the vector to the specified array starting at index 0. + public void CopyTo(T[] array) => CopyTo(array, 0); + + /// Copies the components of the vector to the specified array starting at the given index. + public void CopyTo(T[] array, int startIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (startIndex < 0 || startIndex + 4 > array.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + array[startIndex] = X; + array[startIndex + 1] = Y; + array[startIndex + 2] = Z; + array[startIndex + 3] = W; + } + + /// Copies the components of the vector to the specified span starting at index 0. + public void CopyTo(Span span) => CopyTo(span, 0); + + /// Copies the components of the vector to the specified span starting at the given index. + public void CopyTo(Span span, int startIndex) + { + if (startIndex < 0 || startIndex + 4 > span.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + span[startIndex] = X; + span[startIndex + 1] = Y; + span[startIndex + 2] = Z; + span[startIndex + 3] = W; + } + + /// Returns a span over the vector components. + public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 4); + + /// Formats the vector as a string. + public override string ToString() => + $"<{X}, {Y}, {Z}, {W}>"; + + /// Formats the vector as a string using the specified format and format provider. + public string ToString(string? format, IFormatProvider? formatProvider) => + $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}, {Z.ToString(format, formatProvider)}, {W.ToString(format, formatProvider)}>"; + + /// Parses a string to a instance. + public static Vector4F Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); + + /// Parses a span to a instance. + public static Vector4F Parse(ReadOnlySpan s, IFormatProvider? provider) + { + if (!TryParse(s, provider, out var result)) + throw new FormatException("Invalid format for Vector4F."); + + return result; + } + + /// Formats the vector as a UTF-8 string using the specified format and format provider. + public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + Span zBuffer = stackalloc char[64]; + Span wBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider)|| + !Y.TryFormat(yBuffer, out int yChars, format, provider)|| + !Z.TryFormat(zBuffer, out int zChars, format, provider)|| + !W.TryFormat(wBuffer, out int wChars, format, provider)) + { + bytesWritten = 0; + return false; + } + + int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + + Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + + Encoding.UTF8.GetByteCount(zBuffer[..zChars]) + + Encoding.UTF8.GetByteCount(wBuffer[..wChars]) + + Encoding.UTF8.GetByteCount("<, >"); + + if (utf8Destination.Length < estimatedSize) + { + bytesWritten = 0; + return false; + } + + int totalBytes = 0; + + totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(zBuffer[..zChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(wBuffer[..wChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); + + bytesWritten = totalBytes; + return true; + } + + /// Formats the vector as a string using the specified format and format provider. + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + Span zBuffer = stackalloc char[64]; + Span wBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider) || + !Y.TryFormat(yBuffer, out int yChars, format, provider) || + !Z.TryFormat(zBuffer, out int zChars, format, provider) || + !W.TryFormat(wBuffer, out int wChars, format, provider)) + { + charsWritten = 0; + return false; + } + + int requiredLength = 1 + xChars + 2 + yChars + 2 + zChars + 2 + wChars + 1; + + if (destination.Length < requiredLength) + { + charsWritten = 0; + return false; + } + + int pos = 0; + destination[pos++] = '<'; + + xBuffer[..xChars].CopyTo(destination[pos..]); + pos += xChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + yBuffer[..yChars].CopyTo(destination[pos..]); + pos += yChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + zBuffer[..zChars].CopyTo(destination[pos..]); + pos += zChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + wBuffer[..wChars].CopyTo(destination[pos..]); + pos += wChars; + + destination[pos++] = '>'; + + charsWritten = pos; + return true; + } + + /// Tries to parse a span to a instance. + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4F result) + { + result = default; + + s = s.Trim(); + if (s.Length < 8 || s[0] != '<' || s[^1] != '>') + return false; + + s = s[1..^1]; // Remove < and > + + int commaX = s.IndexOf(','); + if (commaX < 0) + return false; + + ReadOnlySpan remainder1 = s.Slice(commaX + 1); + int commaYRelative = remainder1.IndexOf(','); + if (commaYRelative < 0) + return false; + int commaY = commaX + 1 + commaYRelative; + + ReadOnlySpan remainder2 = s.Slice(commaY + 1); + int commaZRelative = remainder2.IndexOf(','); + if (commaZRelative < 0) + return false; + int commaZ = commaY + 1 + commaZRelative; + + ReadOnlySpan xSpan = s[..commaX].Trim(); + ReadOnlySpan ySpan = s[(commaX + 1)..commaY].Trim(); + ReadOnlySpan zSpan = s[(commaY + 1)..commaZ].Trim(); + ReadOnlySpan wSpan = s[(commaZ + 1)..].Trim(); + + if (T.TryParse(xSpan, provider, out var x) && + T.TryParse(ySpan, provider, out var y) && + T.TryParse(zSpan, provider, out var z) && + T.TryParse(wSpan, provider, out var w)) + { + result = new Vector4F(x, y, z, w); + return true; + } + + return false; + } + + /// Parses a UTF-8 span to a instance. + public static Vector4F Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return Parse(charBuffer, provider); + } + + /// Tries to parse a UTF-8 span to a instance. + public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4F result) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return TryParse(charBuffer, provider, out result); + } + + /// Tries to parse a string to a instance. + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4F result) => + TryParse(s.AsSpan(), provider, out result); + + /// Parses a span to a instance. + static Vector4F ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => + Parse(s, provider); + + /// Parses a string to a instance. + static Vector4F IParsable>.Parse(string s, IFormatProvider? provider) => + Parse(s, provider); + + /// Tries to parse a span to a instance. + static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4F result) => + TryParse(s, provider, out result); + + /// Tries to parse a string to a instance. + static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4F result) => + TryParse(s, provider, out result); + /// Returns a boolean indicating whether the given two vectors are equal. /// The first vector to compare. /// The second vector to compare. @@ -91,10 +375,76 @@ public IEnumerator GetEnumerator() /// public override int GetHashCode() => HashCode.Combine(X, Y, Z, W); + + public static Vector4F operator +(Vector4F vector) => + vector; + + public static Vector4F operator -(Vector4F vector) => + new Vector4F(-vector.X, -vector.Y, -vector.Z, -vector.W); + + public static Vector4F operator +(Vector4F left, Vector4F right) => + new Vector4F(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W); + + public static Vector4F operator -(Vector4F left, Vector4F right) => + new Vector4F(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W); + + public static Vector4F operator *(Vector4F left, Vector4F right) => + new Vector4F(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W); + + public static Vector4F operator /(Vector4F left, Vector4F right) => + new Vector4F(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W); + + public static Vector4F operator %(Vector4F left, Vector4F right) => + new Vector4F(left.X % right.X, left.Y % right.Y, left.Z % right.Z, left.W % right.W); + + public static Vector4F operator +(Vector4F vector, T scalar) => + new Vector4F(vector.X + scalar, vector.Y + scalar, vector.Z + scalar, vector.W + scalar); + + public static Vector4F operator -(Vector4F vector, T scalar) => + new Vector4F(vector.X - scalar, vector.Y - scalar, vector.Z - scalar, vector.W - scalar); + + public static Vector4F operator *(Vector4F vector, T scalar) => + new Vector4F(vector.X * scalar, vector.Y * scalar, vector.Z * scalar, vector.W * scalar); + + public static Vector4F operator *(T scalar, Vector4F vector) => + new Vector4F(scalar * vector.X, scalar * vector.Y, scalar * vector.Z, scalar * vector.W); + + public static Vector4F operator /(Vector4F vector, T scalar) => + new Vector4F(vector.X / scalar, vector.Y / scalar, vector.Z / scalar, vector.W / scalar); + + public static Vector4F operator %(Vector4F vector, T scalar) => + new Vector4F(vector.X % scalar, vector.Y % scalar, vector.Z % scalar, vector.W % scalar); + } static partial class Vector4F { + /// Computes the dot product of two vectors. + public static T Dot(this Vector4F left, Vector4F right) + where T : IFloatingPointIeee754 => + left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + + /// Reflects a vector over a normal vector. + public static Vector4F Reflect(Vector4F vector, Vector4F normal) + where T : IFloatingPointIeee754 + { + T dot = vector.Dot(normal); + return vector - (normal * (dot + dot)); + } + + /// Computes the length of the vector. + public static T GetLength(this Vector4F vector) + where T : IFloatingPointIeee754 => + T.Sqrt(vector.LengthSquared); + + /// Normalizes a vector. + public static Vector4F Normalize(this Vector4F vector) + where T : IFloatingPointIeee754 + { + T length = vector.GetLength(); + return length != T.Zero ? vector / length : Vector4F.Zero; + } + public static Vector4F Log(this Vector4F x) where TSelf : IFloatingPointIeee754, ILogarithmicFunctions => new(TSelf.Log(x.X), TSelf.Log(x.Y), TSelf.Log(x.Z), TSelf.Log(x.W)); diff --git a/sources/Maths/Maths/Vector4I.cs b/sources/Maths/Maths/Vector4I.cs index 2386d7c797..16c3e21720 100644 --- a/sources/Maths/Maths/Vector4I.cs +++ b/sources/Maths/Maths/Vector4I.cs @@ -11,67 +11,8 @@ namespace Silk.NET.Maths { /// A structure representing a 4D integer vector. - internal partial struct Vector4I : - ISpanFormattable, - ISpanParsable>, - IUtf8SpanFormattable, - IUtf8SpanParsable>, - IParsable>, - IFormattable - where T : IBinaryInteger + internal partial struct Vector4I { - /// Initializes the vector from a span of four values. - public Vector4I(ReadOnlySpan values) - { - if (values.Length != 4) - throw new ArgumentException("Input span must contain exactly 4 elements.", nameof(values)); - - X = values[0]; - Y = values[1]; - Z = values[2]; - W = values[3]; - } - - /// Initializes the vector using a Vector2I for X and Y, and a separate value for Z and W. - // TODO: Make sure lower dimensional constructors arent meant to zero-out the higher dimensions - public Vector4I(Vector2I xy, T z, T w) => (X, Y, Z, W) = (xy.X, xy.Y, z, w); - - /// Initializes the vector using a Vector3I for X, Y and Z, and a separate value for W. - public Vector4I(Vector3I xyz, T w) => (X, Y, Z, W) = (xyz.X, xyz.Y, xyz.Z, w); - - /// Gets a vector whose 4 elements are equal to one. - public static Vector4I One => new(Scalar.One); - - /// Returns a vector whose 4 elements are equal to zero. - public static Vector4I Zero => default; - - /// Gets the vector (1, 0, 0, 0). - public static Vector4I UnitX => new(Scalar.One, Scalar.Zero, Scalar.Zero, Scalar.Zero); - - /// Gets the vector (0, 1, 0, 0). - public static Vector4I UnitY => new(Scalar.Zero, Scalar.One, Scalar.Zero, Scalar.Zero); - - /// Gets the vector (0, 0, 1, 0). - public static Vector4I UnitZ => new(Scalar.Zero, Scalar.Zero, Scalar.One, Scalar.Zero); - - /// Gets the vector (0, 0, 0, 1). - public static Vector4I UnitW => new(Scalar.Zero, Scalar.Zero, Scalar.Zero, Scalar.One); - - /// Gets a vector with all bits set for each component. - public static Vector4I AllBitsSet => new Vector4I(T.AllBitsSet, T.AllBitsSet, T.AllBitsSet, T.AllBitsSet); - - /// Gets the squared length of the vector (dot product with itself). - public T LengthSquared => (X * X) + (Y * Y) + (Z * Z) + (W * W); - - /// Computes the dot product of this vector with another vector. - public T Dot(Vector4I other) => (X * other.X) + (Y * other.Y) + (Z * other.Z) + (W * other.W); - - /// Computes the dot product of two vectors. - public static T Dot(Vector4I left, Vector4I right) => (left.X * right.X) + (left.Y * right.Y) + (left.Z * right.Z) + (left.W * right.W); - - /// Returns a span over the vector components. - public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 4); - /// Returns a vector with the component-wise maximum of this and another vector. public Vector4I Max(Vector4I other) => new Vector4I(T.Max(X, other.X), T.Max(Y, other.Y), T.Max(Z, other.Z), T.Max(W, other.W)); @@ -147,109 +88,6 @@ public static Vector4I Clamp(Vector4I vector, T min, T max) => public static Vector4I Abs(Vector4I vector) => new Vector4I(T.Abs(vector.X), T.Abs(vector.Y), T.Abs(vector.Z), T.Abs(vector.W)); - /// Formats the vector as a string using the specified format and format provider. - public string ToString(string? format, IFormatProvider? formatProvider) => - $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}, {Z.ToString(format, formatProvider)}, {W.ToString(format, formatProvider)}>"; - - /// Formats the vector as a string. - public override string ToString() => $"<{X}, {Y}, {Z}, {W}>"; - - /// Formats the vector as a string using the specified format and format provider. - public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) - { - // Format components individually into temporary buffers - Span xBuffer = stackalloc char[64]; - Span yBuffer = stackalloc char[64]; - Span zBuffer = stackalloc char[64]; - Span wBuffer = stackalloc char[64]; - - if (!X.TryFormat(xBuffer, out int xChars, format, provider) || - !Y.TryFormat(yBuffer, out int yChars, format, provider) || - !Z.TryFormat(zBuffer, out int zChars, format, provider) || - !W.TryFormat(wBuffer, out int wChars, format, provider)) - { - charsWritten = 0; - return false; - } - - // Calculate total required length: < + x + ", " + y + ", " + z + ", " + w + > - int requiredLength = 1 + xChars + 2 + yChars + 2 + zChars + 2 + wChars + 1; - - if (destination.Length < requiredLength) - { - charsWritten = 0; - return false; - } - - int pos = 0; - destination[pos++] = '<'; - - xBuffer[..xChars].CopyTo(destination[pos..]); - pos += xChars; - - destination[pos++] = ','; - destination[pos++] = ' '; - - yBuffer[..yChars].CopyTo(destination[pos..]); - pos += yChars; - - destination[pos++] = ','; - destination[pos++] = ' '; - - zBuffer[..zChars].CopyTo(destination[pos..]); - pos += zChars; - - destination[pos++] = ','; - destination[pos++] = ' '; - - wBuffer[..wChars].CopyTo(destination[pos..]); - pos += wChars; - - destination[pos++] = '>'; - - charsWritten = pos; - return true; - } - - /// Parses a span to a Vector4I instance. - public static Vector4I Parse(ReadOnlySpan s, IFormatProvider? provider) - { - if (!TryParse(s, provider, out var result)) - throw new FormatException("Invalid format for Vector4I."); - - return result; - } - - /// Copies the components of the vector to the specified array starting at index 0. - public void CopyTo(T[] array) => CopyTo(array, 0); - - /// Copies the components of the vector to the specified array starting at the given index. - public void CopyTo(T[] array, int startIndex) - { - if (array == null) - throw new ArgumentNullException(nameof(array)); - if (startIndex < 0 || startIndex + 4 > array.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex)); - array[startIndex] = X; - array[startIndex + 1] = Y; - array[startIndex + 2] = Z; - array[startIndex + 3] = W; - } - - /// Copies the components of the vector to the specified span starting at index 0. - public void CopyTo(Span span) => CopyTo(span, 0); - - /// Copies the components of the vector to the specified span starting at the given index. - public void CopyTo(Span span, int startIndex) - { - if (startIndex < 0 || startIndex + 4 > span.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex)); - span[startIndex] = X; - span[startIndex + 1] = Y; - span[startIndex + 2] = Z; - span[startIndex + 3] = W; - } - /// Returns a vector where each component is the sign of the original vector's component. public Vector4I Sign() => new Vector4I(T.CreateChecked(T.Sign(X)), T.CreateChecked(T.Sign(Y)), T.CreateChecked(T.Sign(Z)), T.CreateChecked(T.Sign(W))); @@ -274,138 +112,6 @@ public Vector4I CopySign(T signScalar) => public static Vector4I CopySign(Vector4I value, T signScalar) => new Vector4I(T.CopySign(value.X, signScalar), T.CopySign(value.Y, signScalar), T.CopySign(value.Z, signScalar), T.CopySign(value.W, signScalar)); - /// Parses a string to a Vector4I instance. - public static Vector4I Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); - - /// Tries to parse a span to a Vector4I instance. - public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) - { - result = default; - - s = s.Trim(); - if (s.Length < 9 || s[0] != '<' || s[^1] != '>') - return false; - - s = s[1..^1]; // Remove < and > - - int firstComma = s.IndexOf(','); - if (firstComma < 0) - return false; - - ReadOnlySpan remainder1 = s.Slice(firstComma + 1); - int secondCommaRelative = remainder1.IndexOf(','); - if (secondCommaRelative < 0) - return false; - int secondComma = firstComma + 1 + secondCommaRelative; - - ReadOnlySpan remainder2 = s.Slice(secondComma + 1); - int thirdCommaRelative = remainder2.IndexOf(','); - if (thirdCommaRelative < 0) - return false; - int thirdComma = secondComma + 1 + thirdCommaRelative; - - ReadOnlySpan xSpan = s[..firstComma].Trim(); - ReadOnlySpan ySpan = s[(firstComma + 1)..secondComma].Trim(); - ReadOnlySpan zSpan = s[(secondComma + 1)..thirdComma].Trim(); - ReadOnlySpan wSpan = s[(thirdComma + 1)..].Trim(); - - if (T.TryParse(xSpan, provider, out var x) && - T.TryParse(ySpan, provider, out var y) && - T.TryParse(zSpan, provider, out var z) && - T.TryParse(wSpan, provider, out var w)) - { - result = new Vector4I(x, y, z, w); - return true; - } - - return false; - } - - /// Tries to parse a string to a Vector4I instance. - public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) => - TryParse(s.AsSpan(), provider, out result); - - /// Parses a span to a Vector4I instance. - static Vector4I ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => - Parse(s, provider); - - /// Parses a string to a Vector4I instance. - static Vector4I IParsable>.Parse(string s, IFormatProvider? provider) => - Parse(s, provider); - - /// Tries to parse a span to a Vector4I instance. - static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) => - TryParse(s, provider, out result); - - /// Tries to parse a string to a Vector4I instance. - static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) => - TryParse(s, provider, out result); - - /// Formats the vector as a UTF-8 string using the specified format and format provider. - public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) - { - // Format components individually into temporary buffers - Span xBuffer = stackalloc char[64]; - Span yBuffer = stackalloc char[64]; - Span zBuffer = stackalloc char[64]; - Span wBuffer = stackalloc char[64]; - - if (!X.TryFormat(xBuffer, out int xChars, format, provider) || - !Y.TryFormat(yBuffer, out int yChars, format, provider) || - !Z.TryFormat(zBuffer, out int zChars, format, provider) || - !W.TryFormat(wBuffer, out int wChars, format, provider)) - { - bytesWritten = 0; - return false; - } - - // Estimate total required UTF-8 bytes - int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + - Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + - Encoding.UTF8.GetByteCount(zBuffer[..zChars]) + - Encoding.UTF8.GetByteCount(wBuffer[..wChars]) + - Encoding.UTF8.GetByteCount("<, , , >"); - - if (utf8Destination.Length < estimatedSize) - { - bytesWritten = 0; - return false; - } - - int totalBytes = 0; - - totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(zBuffer[..zChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(wBuffer[..wChars], utf8Destination[totalBytes..]); - totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); - - bytesWritten = totalBytes; - return true; - } - - /// Parses a UTF-8 span to a Vector4I instance. - public static Vector4I Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) - { - int charCount = Encoding.UTF8.GetCharCount(utf8Text); - Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; - Encoding.UTF8.GetChars(utf8Text, charBuffer); - return Parse(charBuffer, provider); - } - - /// Tries to parse a UTF-8 span to a Vector4I instance. - public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) - { - int charCount = Encoding.UTF8.GetCharCount(utf8Text); - Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; - Encoding.UTF8.GetChars(utf8Text, charBuffer); - return TryParse(charBuffer, provider, out result); - } - // Casts /// Explicitly casts a System.Numerics.Vector4 to a Vector4I. @@ -416,77 +122,6 @@ public static explicit operator Vector4I(System.Numerics.Vector4 v) => public static explicit operator System.Numerics.Vector4(Vector4I v) => new System.Numerics.Vector4(Convert.ToSingle(v.X), Convert.ToSingle(v.Y), Convert.ToSingle(v.Z), Convert.ToSingle(v.W)); - // Component Operators - public static Vector4I operator +(Vector4I left, Vector4I right) => - new Vector4I(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W); - - public static Vector4I operator -(Vector4I left, Vector4I right) => - new Vector4I(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W); - - public static Vector4I operator *(Vector4I left, Vector4I right) => - new Vector4I(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W); - - public static Vector4I operator /(Vector4I left, Vector4I right) => - new Vector4I(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W); - - public static Vector4I operator %(Vector4I left, Vector4I right) => - new Vector4I(left.X % right.X, left.Y % right.Y, left.Z % right.Z, left.W % right.W); - - // Scalar Operators - public static Vector4I operator +(Vector4I vector, T scalar) => - new Vector4I(vector.X + scalar, vector.Y + scalar, vector.Z + scalar, vector.W + scalar); - - public static Vector4I operator -(Vector4I vector, T scalar) => - new Vector4I(vector.X - scalar, vector.Y - scalar, vector.Z - scalar, vector.W - scalar); - - public static Vector4I operator *(Vector4I vector, T scalar) => - new Vector4I(vector.X * scalar, vector.Y * scalar, vector.Z * scalar, vector.W * scalar); - - public static Vector4I operator /(Vector4I vector, T scalar) => - new Vector4I(vector.X / scalar, vector.Y / scalar, vector.Z / scalar, vector.W / scalar); - - public static Vector4I operator %(Vector4I vector, T scalar) => - new Vector4I(vector.X % scalar, vector.Y % scalar, vector.Z % scalar, vector.W % scalar); - - // + operator: returns the vector (?) - public static Vector4I operator +(Vector4I vector) => vector; - - // - operator: returns the negated vector - public static Vector4I operator -(Vector4I vector) => - new Vector4I(-vector.X, -vector.Y, -vector.Z, -vector.W); - - // Bitwise Operators - public static Vector4I operator &(Vector4I left, Vector4I right) => - new Vector4I(left.X & right.X, left.Y & right.Y, left.Z & right.Z, left.W & right.W); - - public static Vector4I operator |(Vector4I left, Vector4I right) => - new Vector4I(left.X | right.X, left.Y | right.Y, left.Z | right.Z, left.W | right.W); - - public static Vector4I operator ^(Vector4I left, Vector4I right) => - new Vector4I(left.X ^ right.X, left.Y ^ right.Y, left.Z ^ right.Z, left.W ^ right.W); - - public static Vector4I operator &(Vector4I vector, T scalar) => - new Vector4I(vector.X & scalar, vector.Y & scalar, vector.Z & scalar, vector.W & scalar); - - public static Vector4I operator &(T scalar, Vector4I vector) => - new Vector4I(scalar & vector.X, scalar & vector.Y, scalar & vector.Z, scalar & vector.W); - - public static Vector4I operator |(Vector4I vector, T scalar) => - new Vector4I(vector.X | scalar, vector.Y | scalar, vector.Z | scalar, vector.W | scalar); - - public static Vector4I operator |(T scalar, Vector4I vector) => - new Vector4I(scalar | vector.X, scalar | vector.Y, scalar | vector.Z, scalar | vector.W); - - public static Vector4I operator ^(Vector4I vector, T scalar) => - new Vector4I(vector.X ^ scalar, vector.Y ^ scalar, vector.Z ^ scalar, vector.W ^ scalar); - - public static Vector4I operator ^(T scalar, Vector4I vector) => - new Vector4I(scalar ^ vector.X, scalar ^ vector.Y, scalar ^ vector.Z, scalar ^ vector.W); - - // NOT operator - public static Vector4I operator ~(Vector4I vector) => - new Vector4I(~vector.X, ~vector.Y, ~vector.Z, ~vector.W); - // IBinaryInteger public static Vector4I Log2(Vector4I x) => new Vector4I(T.Log2(x.X), T.Log2(x.Y), T.Log2(x.Z), T.Log2(x.W)); diff --git a/sources/Maths/Maths/Vector4I.gen.cs b/sources/Maths/Maths/Vector4I.gen.cs index ef2d344376..04eb7ca61c 100644 --- a/sources/Maths/Maths/Vector4I.gen.cs +++ b/sources/Maths/Maths/Vector4I.gen.cs @@ -3,10 +3,18 @@ namespace Silk.NET.Maths using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Numerics; + using System.Runtime.InteropServices; + using System.Text; partial struct Vector4I : IEquatable>, - IReadOnlyList + IReadOnlyList, + IFormattable, + IParsable>, + ISpanFormattable, + ISpanParsable>, + IUtf8SpanFormattable, + IUtf8SpanParsable> where T : IBinaryInteger { /// The X component of the vector. @@ -27,6 +35,48 @@ partial struct Vector4I : /// Initializes the vector with individual component values. public Vector4I(T x, T y, T z, T w) => (X, Y, Z, W) = (x, y, z, w); + /// Initializes the vector using a for the initial elements, and the specified components for the remainder. + public Vector4I(Vector2I other, T z, T w) => (X, Y, Z, W) = (other.X, other.Y, z, w); + + /// Initializes the vector using a for the initial elements, and the specified component for the remainder. + public Vector4I(Vector3I other, T w) => (X, Y, Z, W) = (other.X, other.Y, other.Z, w); + + /// Initializes the vector from a span of 4 values. + public Vector4I(ReadOnlySpan values) + { + if (values.Length != 4) + throw new ArgumentException("Input span must contain exactly 4 elements.", nameof(values)); + + X = values[0]; + Y = values[1]; + Z = values[2]; + W = values[3]; + } + + /// Gets a vector whose 4 elements are equal to one. + public static Vector4I One => new(Scalar.One); + + /// Returns a vector whose 4 elements are equal to zero. + public static Vector4I Zero => default; + + /// Gets the vector (1, 0, 0, 0). + public static Vector4I UnitX => new(Scalar.One, Scalar.Zero, Scalar.Zero, Scalar.Zero); + + /// Gets the vector (0, 1, 0, 0). + public static Vector4I UnitY => new(Scalar.Zero, Scalar.One, Scalar.Zero, Scalar.Zero); + + /// Gets the vector (0, 0, 1, 0). + public static Vector4I UnitZ => new(Scalar.Zero, Scalar.Zero, Scalar.One, Scalar.Zero); + + /// Gets the vector (0, 0, 0, 1). + public static Vector4I UnitW => new(Scalar.Zero, Scalar.Zero, Scalar.Zero, Scalar.One); + + /// Gets a vector with all bits set for each component. + public static Vector4I AllBitsSet => new Vector4I(T.AllBitsSet, T.AllBitsSet, T.AllBitsSet, T.AllBitsSet); + + /// Gets the squared length of the vector (dot product with itself). + public T LengthSquared => Vector4I.Dot(this, this); + /// T IReadOnlyList.this[int index] => this[index]; @@ -67,6 +117,243 @@ public IEnumerator GetEnumerator() yield return W; } + /// Copies the components of the vector to the specified array starting at index 0. + public void CopyTo(T[] array) => CopyTo(array, 0); + + /// Copies the components of the vector to the specified array starting at the given index. + public void CopyTo(T[] array, int startIndex) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (startIndex < 0 || startIndex + 4 > array.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + array[startIndex] = X; + array[startIndex + 1] = Y; + array[startIndex + 2] = Z; + array[startIndex + 3] = W; + } + + /// Copies the components of the vector to the specified span starting at index 0. + public void CopyTo(Span span) => CopyTo(span, 0); + + /// Copies the components of the vector to the specified span starting at the given index. + public void CopyTo(Span span, int startIndex) + { + if (startIndex < 0 || startIndex + 4 > span.Length) + throw new ArgumentOutOfRangeException(nameof(startIndex)); + + span[startIndex] = X; + span[startIndex + 1] = Y; + span[startIndex + 2] = Z; + span[startIndex + 3] = W; + } + + /// Returns a span over the vector components. + public Span AsSpan() => MemoryMarshal.CreateSpan(ref X, 4); + + /// Formats the vector as a string. + public override string ToString() => + $"<{X}, {Y}, {Z}, {W}>"; + + /// Formats the vector as a string using the specified format and format provider. + public string ToString(string? format, IFormatProvider? formatProvider) => + $"<{X.ToString(format, formatProvider)}, {Y.ToString(format, formatProvider)}, {Z.ToString(format, formatProvider)}, {W.ToString(format, formatProvider)}>"; + + /// Parses a string to a instance. + public static Vector4I Parse(string s, IFormatProvider? provider) => Parse(s.AsSpan(), provider); + + /// Parses a span to a instance. + public static Vector4I Parse(ReadOnlySpan s, IFormatProvider? provider) + { + if (!TryParse(s, provider, out var result)) + throw new FormatException("Invalid format for Vector4I."); + + return result; + } + + /// Formats the vector as a UTF-8 string using the specified format and format provider. + public bool TryFormat(Span utf8Destination, out int bytesWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + Span zBuffer = stackalloc char[64]; + Span wBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider)|| + !Y.TryFormat(yBuffer, out int yChars, format, provider)|| + !Z.TryFormat(zBuffer, out int zChars, format, provider)|| + !W.TryFormat(wBuffer, out int wChars, format, provider)) + { + bytesWritten = 0; + return false; + } + + int estimatedSize = Encoding.UTF8.GetByteCount(xBuffer[..xChars]) + + Encoding.UTF8.GetByteCount(yBuffer[..yChars]) + + Encoding.UTF8.GetByteCount(zBuffer[..zChars]) + + Encoding.UTF8.GetByteCount(wBuffer[..wChars]) + + Encoding.UTF8.GetByteCount("<, >"); + + if (utf8Destination.Length < estimatedSize) + { + bytesWritten = 0; + return false; + } + + int totalBytes = 0; + + totalBytes += Encoding.UTF8.GetBytes("<", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(xBuffer[..xChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(yBuffer[..yChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(zBuffer[..zChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(", ", utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(wBuffer[..wChars], utf8Destination[totalBytes..]); + totalBytes += Encoding.UTF8.GetBytes(">", utf8Destination[totalBytes..]); + + bytesWritten = totalBytes; + return true; + } + + /// Formats the vector as a string using the specified format and format provider. + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + Span xBuffer = stackalloc char[64]; + Span yBuffer = stackalloc char[64]; + Span zBuffer = stackalloc char[64]; + Span wBuffer = stackalloc char[64]; + + if (!X.TryFormat(xBuffer, out int xChars, format, provider) || + !Y.TryFormat(yBuffer, out int yChars, format, provider) || + !Z.TryFormat(zBuffer, out int zChars, format, provider) || + !W.TryFormat(wBuffer, out int wChars, format, provider)) + { + charsWritten = 0; + return false; + } + + int requiredLength = 1 + xChars + 2 + yChars + 2 + zChars + 2 + wChars + 1; + + if (destination.Length < requiredLength) + { + charsWritten = 0; + return false; + } + + int pos = 0; + destination[pos++] = '<'; + + xBuffer[..xChars].CopyTo(destination[pos..]); + pos += xChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + yBuffer[..yChars].CopyTo(destination[pos..]); + pos += yChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + zBuffer[..zChars].CopyTo(destination[pos..]); + pos += zChars; + + destination[pos++] = ','; + destination[pos++] = ' '; + + wBuffer[..wChars].CopyTo(destination[pos..]); + pos += wChars; + + destination[pos++] = '>'; + + charsWritten = pos; + return true; + } + + /// Tries to parse a span to a instance. + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) + { + result = default; + + s = s.Trim(); + if (s.Length < 8 || s[0] != '<' || s[^1] != '>') + return false; + + s = s[1..^1]; // Remove < and > + + int commaX = s.IndexOf(','); + if (commaX < 0) + return false; + + ReadOnlySpan remainder1 = s.Slice(commaX + 1); + int commaYRelative = remainder1.IndexOf(','); + if (commaYRelative < 0) + return false; + int commaY = commaX + 1 + commaYRelative; + + ReadOnlySpan remainder2 = s.Slice(commaY + 1); + int commaZRelative = remainder2.IndexOf(','); + if (commaZRelative < 0) + return false; + int commaZ = commaY + 1 + commaZRelative; + + ReadOnlySpan xSpan = s[..commaX].Trim(); + ReadOnlySpan ySpan = s[(commaX + 1)..commaY].Trim(); + ReadOnlySpan zSpan = s[(commaY + 1)..commaZ].Trim(); + ReadOnlySpan wSpan = s[(commaZ + 1)..].Trim(); + + if (T.TryParse(xSpan, provider, out var x) && + T.TryParse(ySpan, provider, out var y) && + T.TryParse(zSpan, provider, out var z) && + T.TryParse(wSpan, provider, out var w)) + { + result = new Vector4I(x, y, z, w); + return true; + } + + return false; + } + + /// Parses a UTF-8 span to a instance. + public static Vector4I Parse(ReadOnlySpan utf8Text, IFormatProvider? provider) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return Parse(charBuffer, provider); + } + + /// Tries to parse a UTF-8 span to a instance. + public static bool TryParse(ReadOnlySpan utf8Text, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) + { + int charCount = Encoding.UTF8.GetCharCount(utf8Text); + Span charBuffer = charCount <= 128 ? stackalloc char[charCount] : new char[charCount]; + Encoding.UTF8.GetChars(utf8Text, charBuffer); + return TryParse(charBuffer, provider, out result); + } + + /// Tries to parse a string to a instance. + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) => + TryParse(s.AsSpan(), provider, out result); + + /// Parses a span to a instance. + static Vector4I ISpanParsable>.Parse(ReadOnlySpan s, IFormatProvider? provider) => + Parse(s, provider); + + /// Parses a string to a instance. + static Vector4I IParsable>.Parse(string s, IFormatProvider? provider) => + Parse(s, provider); + + /// Tries to parse a span to a instance. + static bool ISpanParsable>.TryParse(ReadOnlySpan s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) => + TryParse(s, provider, out result); + + /// Tries to parse a string to a instance. + static bool IParsable>.TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out Vector4I result) => + TryParse(s, provider, out result); + /// Returns a boolean indicating whether the given two vectors are equal. /// The first vector to compare. /// The second vector to compare. @@ -91,10 +378,92 @@ public IEnumerator GetEnumerator() /// public override int GetHashCode() => HashCode.Combine(X, Y, Z, W); + + public static Vector4I operator +(Vector4I vector) => + vector; + + public static Vector4I operator -(Vector4I vector) => + new Vector4I(-vector.X, -vector.Y, -vector.Z, -vector.W); + + public static Vector4I operator +(Vector4I left, Vector4I right) => + new Vector4I(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W); + + public static Vector4I operator -(Vector4I left, Vector4I right) => + new Vector4I(left.X - right.X, left.Y - right.Y, left.Z - right.Z, left.W - right.W); + + public static Vector4I operator *(Vector4I left, Vector4I right) => + new Vector4I(left.X * right.X, left.Y * right.Y, left.Z * right.Z, left.W * right.W); + + public static Vector4I operator /(Vector4I left, Vector4I right) => + new Vector4I(left.X / right.X, left.Y / right.Y, left.Z / right.Z, left.W / right.W); + + public static Vector4I operator %(Vector4I left, Vector4I right) => + new Vector4I(left.X % right.X, left.Y % right.Y, left.Z % right.Z, left.W % right.W); + + public static Vector4I operator +(Vector4I vector, T scalar) => + new Vector4I(vector.X + scalar, vector.Y + scalar, vector.Z + scalar, vector.W + scalar); + + public static Vector4I operator -(Vector4I vector, T scalar) => + new Vector4I(vector.X - scalar, vector.Y - scalar, vector.Z - scalar, vector.W - scalar); + + public static Vector4I operator *(Vector4I vector, T scalar) => + new Vector4I(vector.X * scalar, vector.Y * scalar, vector.Z * scalar, vector.W * scalar); + + public static Vector4I operator *(T scalar, Vector4I vector) => + new Vector4I(scalar * vector.X, scalar * vector.Y, scalar * vector.Z, scalar * vector.W); + + public static Vector4I operator /(Vector4I vector, T scalar) => + new Vector4I(vector.X / scalar, vector.Y / scalar, vector.Z / scalar, vector.W / scalar); + + public static Vector4I operator %(Vector4I vector, T scalar) => + new Vector4I(vector.X % scalar, vector.Y % scalar, vector.Z % scalar, vector.W % scalar); + + public static Vector4I operator ~(Vector4I vector) => + new Vector4I(~vector.X, ~vector.Y, ~vector.Z, ~vector.W); + + public static Vector4I operator &(Vector4I left, Vector4I right) => + new Vector4I(left.X & right.X, left.Y & right.Y, left.Z & right.Z, left.W & right.W); + + public static Vector4I operator |(Vector4I left, Vector4I right) => + new Vector4I(left.X | right.X, left.Y | right.Y, left.Z | right.Z, left.W | right.W); + + public static Vector4I operator ^(Vector4I left, Vector4I right) => + new Vector4I(left.X ^ right.X, left.Y ^ right.Y, left.Z ^ right.Z, left.W ^ right.W); + + public static Vector4I operator &(Vector4I vector, T scalar) => + new Vector4I(vector.X & scalar, vector.Y & scalar, vector.Z & scalar, vector.W & scalar); + + public static Vector4I operator &(T scalar, Vector4I vector) => + new Vector4I(scalar & vector.X, scalar & vector.Y, scalar & vector.Z, scalar & vector.W); + + public static Vector4I operator |(Vector4I vector, T scalar) => + new Vector4I(vector.X | scalar, vector.Y | scalar, vector.Z | scalar, vector.W | scalar); + + public static Vector4I operator |(T scalar, Vector4I vector) => + new Vector4I(scalar | vector.X, scalar | vector.Y, scalar | vector.Z, scalar | vector.W); + + public static Vector4I operator ^(Vector4I vector, T scalar) => + new Vector4I(vector.X ^ scalar, vector.Y ^ scalar, vector.Z ^ scalar, vector.W ^ scalar); + + public static Vector4I operator ^(T scalar, Vector4I vector) => + new Vector4I(scalar ^ vector.X, scalar ^ vector.Y, scalar ^ vector.Z, scalar ^ vector.W); } static partial class Vector4I { + /// Computes the dot product of two vectors. + public static T Dot(this Vector4I left, Vector4I right) + where T : IBinaryInteger => + left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + + /// Reflects a vector over a normal vector. + public static Vector4I Reflect(Vector4I vector, Vector4I normal) + where T : IBinaryInteger + { + T dot = vector.Dot(normal); + return vector - (normal * (dot + dot)); + } + public static Vector4I Log(this Vector4I x) where TSelf : IBinaryInteger, ILogarithmicFunctions => new(TSelf.Log(x.X), TSelf.Log(x.Y), TSelf.Log(x.Z), TSelf.Log(x.W));