// ----------------------------------------------------------------------------- // file="Vec3_T" // Project: StgSharp // Copyright (c) Nitload. // SPDX-License-Identifier: MIT // ----------------------------------------------------------------------------- using StgSharp.Mathematics.Numeric; using System; using System.Collections; using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; namespace StgSharp.Mathematics.Numeric.Graphics { /// /// A tightly packed three-dimensional numeric vector. /// [StructLayout(LayoutKind.Sequential, Pack = 16)] public struct Vec3 : IUnmanagedVector>, IEquatable>, IEnumerable where T: unmanaged, INumber { public T X; public T Y; public T Z; public Vec3(Vec2 xy, T z) { X = xy.X; Y = xy.Y; Z = z; } public Vec3(T x, T y, T z) { X = x; Y = y; Z = z; } public Vec2 XY { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => new(X, Y); [MethodImpl(MethodImplOptions.AggressiveInlining)] set { X = value.X; Y = value.Y; } } public Vec3 XYZ { [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => this; [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this = value; } public static Vec3 Zero => new(T.Zero, T.Zero, T.Zero); public static Vec3 One => new(T.One, T.One, T.One); public static Vec3 UnitX => new(T.One, T.Zero, T.Zero); public static Vec3 UnitY => new(T.Zero, T.One, T.Zero); public static Vec3 UnitZ => new(T.Zero, T.Zero, T.One); [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly T Dot(Vec3 right) { if (Unsafe.SizeOf() == 8) { Vec4 v = Vec4.FromVector256Unsafe(this.AsVector256Unsafe() * right.AsVector256Unsafe()); return v.X + v.Y + v.Z; } if (Unsafe.SizeOf() == 4) { Vec4 v = Vec4.FromVector128Unsafe(this.AsVector128Unsafe() * right.AsVector128Unsafe()); return v.X + v.Y + v.Z; } throw GraphicVector.ThrowUnsupportedTypeException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(Vec3 other) { if (Unsafe.SizeOf() == 4) { return this.AsVector128Safe() == other.AsVector128Safe(); } if (Unsafe.SizeOf() == 8) { return this.AsVector256Safe() == other.AsVector256Safe(); } throw GraphicVector.ThrowUnsupportedTypeException(); } public override readonly bool Equals(object? obj) { return obj is Vec3 other && Equals(other); } public static Vec3 FromSpan(ReadOnlySpan span) { if (span.Length < 3) { throw new ArgumentException("Span length must be at least 3.", nameof(span)); } return new(span[0], span[1], span[2]); } public readonly IEnumerator GetEnumerator() { yield return X; yield return Y; yield return Z; } public override readonly int GetHashCode() { return HashCode.Combine(X, Y, Z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly T GetMaxValue() { return T.Max(X, T.Max(Y, Z)); } public static bool IsParallel(Vec3 left, Vec3 right) { return Vec3.Cross(left, right) == Zero; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 operator -(Vec3 value) { if (Unsafe.SizeOf() == 4) { return Vec3.FromVector128Unsafe(Vector128.Zero - value.AsVector128Unsafe()); } if (Unsafe.SizeOf() == 8) { return Vec3.FromVector256Unsafe(Vector256.Zero - value.AsVector256Unsafe()); } throw GraphicVector.ThrowUnsupportedTypeException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 operator -(Vec3 left, Vec3 right) { if (Unsafe.SizeOf() == 4) { Vector128 left_v128 = left.AsVector128Unsafe(); Vector128 right_v128 = right.AsVector128Unsafe(); return Vec3.FromVector128Unsafe(left_v128 - right_v128); } if (Unsafe.SizeOf() == 8) { Vector256 left_v256 = left.AsVector256Unsafe(); Vector256 right_v256 = right.AsVector256Unsafe(); return Vec3.FromVector256Unsafe(left_v256 - right_v256); } throw GraphicVector.ThrowUnsupportedTypeException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Vec3 left, Vec3 right) { return !left.Equals(right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 operator *(Vec3 vector, T scalar) { if (Unsafe.SizeOf() == 4) { Vector128 vector_v128 = vector.AsVector128Unsafe(); Vector128 scalar_v128 = Vector128.Create(scalar); return Vec3.FromVector128Unsafe(vector_v128 * scalar_v128); } if (Unsafe.SizeOf() == 8) { Vector256 vector_v256 = vector.AsVector256Unsafe(); Vector256 scalar_v256 = Vector256.Create(scalar); return Vec3.FromVector256Unsafe(vector_v256 * scalar_v256); } throw GraphicVector.ThrowUnsupportedTypeException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 operator *(T scalar, Vec3 vector) { return vector * scalar; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T operator *(Vec3 left, Vec3 right) { return left.Dot(right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 operator /(Vec3 vector, T scalar) { if (Unsafe.SizeOf() == 4) { Vector128 vector_v128 = vector.AsVector128Unsafe(); Vector128 scalar_v128 = Vector128.Create(scalar); return Vec3.FromVector128Unsafe(vector_v128 / scalar_v128); } if (Unsafe.SizeOf() == 8) { Vector256 vector_v256 = vector.AsVector256Unsafe(); Vector256 scalar_v256 = Vector256.Create(scalar); return Vec3.FromVector256Unsafe(vector_v256 / scalar_v256); } throw GraphicVector.ThrowUnsupportedTypeException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 operator +(Vec3 left, Vec3 right) { if (Unsafe.SizeOf() == 4) { Vector128 left_v128 = left.AsVector128Unsafe(); Vector128 right_v128 = right.AsVector128Unsafe(); return Vec3.FromVector128Unsafe(left_v128 + right_v128); } if (Unsafe.SizeOf() == 8) { Vector256 left_v256 = left.AsVector256Unsafe(); Vector256 right_v256 = right.AsVector256Unsafe(); return Vec3.FromVector256Unsafe(left_v256 + right_v256); } throw GraphicVector.ThrowUnsupportedTypeException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Vec3 left, Vec3 right) { return left.Equals(right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Vec3((T X, T Y, T Z) tuple) { return new(tuple.X, tuple.Y, tuple.Z); } readonly IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }