// ----------------------------------------------------------------------------- // file="Vec3" // Project: StgSharp // Copyright (c) Nitload. // SPDX-License-Identifier: MIT // ----------------------------------------------------------------------------- using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; namespace Nitload.Mathematics.Numeric.Graphics { public static class Vec3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 ConvertToDouble( Vec3 source ) { return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe())); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 ConvertToDouble( Vec3 source ) { return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe())); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 ConvertToSingle( Vec3 source ) { return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe())); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 ConvertToSingle( Vec3 source ) { return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe())); } public static Vec3 FromSpan( ReadOnlySpan span ) where T : unmanaged, INumber { 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 static bool IsParallel( Vec3 left, Vec3 right ) where T : unmanaged,INumber { return Cross(left, right).Equals(T.Zero); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector128 AsVector128Safe( this Vec3 source ) where T : unmanaged, INumber { Vector128 result = Vector128.Zero; Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), source); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector128 AsVector128Unsafe( this Vec3 source ) where T : unmanaged, INumber { Unsafe.SkipInit(out Vector128 result); Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), source); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector256 AsVector256Safe( this Vec3 source ) where T : unmanaged, INumber { Vector256 result = Vector256.Zero; Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), source); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector256 AsVector256Unsafe( this Vec3 source ) where T : unmanaged, INumber { Unsafe.SkipInit(out Vector256 result); Unsafe.WriteUnaligned(ref Unsafe.As, byte>(ref result), source); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vec3 FromVector128Unsafe( Vector128 source ) where T : unmanaged, INumber { return Unsafe.As, Vec3>(ref source); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vec3 FromVector256Unsafe( Vector256 source ) where T : unmanaged, INumber { return Unsafe.As, Vec3>(ref source); } #region cross [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec3 Cross( Vec3 left, Vec3 right ) where T : unmanaged, INumber { if (typeof(T) == typeof(float)) { Vec3 result = CrossSingle( Unsafe.As, Vec3>(ref left), Unsafe.As, Vec3>(ref right)); return Unsafe.As, Vec3>(ref result); } if (typeof(T) == typeof(double)) { Vec3 result = CrossDouble( Unsafe.As, Vec3>(ref left), Unsafe.As, Vec3>(ref right)); return Unsafe.As, Vec3>(ref result); } if (typeof(T) == typeof(int)) { Vec3 result = CrossInt32( Unsafe.As, Vec3>(ref left), Unsafe.As, Vec3>(ref right)); return Unsafe.As, Vec3>(ref result); } if (typeof(T) == typeof(uint)) { Vec3 result = CrossUInt32( Unsafe.As, Vec3>(ref left), Unsafe.As, Vec3>(ref right)); return Unsafe.As, Vec3>(ref result); } if (typeof(T) == typeof(ulong)) { Vec3 result = CrossUInt64( Unsafe.As, Vec3>(ref left), Unsafe.As, Vec3>(ref right)); return Unsafe.As, Vec3>(ref result); } if (typeof(T) == typeof(long)) { Vec3 result = CrossInt64( Unsafe.As, Vec3>(ref left), Unsafe.As, Vec3>(ref right)); return Unsafe.As, Vec3>(ref result); } throw new NotSupportedException($"Cross product is not supported for {typeof(T)}."); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vec3 CrossDouble( Vec3 left, Vec3 right ) { Vector256 l = left.AsVector256Safe(); Vector256 r = right.AsVector256Safe(); Vector256 yzx = Vector256.Create(1L, 2L, 0L, 3L); Vector256 zxy = Vector256.Create(2L, 0L, 1L, 3L); Vector256 result = (Vector256.Shuffle(l, yzx) * Vector256.Shuffle(r, zxy)) - (Vector256.Shuffle(l, zxy) * Vector256.Shuffle(r, yzx)); return FromVector256Unsafe(result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vec3 CrossInt32( Vec3 left, Vec3 right ) { Vector128 l = left.AsVector128Safe(); Vector128 r = right.AsVector128Safe(); Vector128 yzx = Vector128.Create(1, 2, 0, 3); Vector128 zxy = Vector128.Create(2, 0, 1, 3); Vector128 result = (Vector128.Shuffle(l, yzx) * Vector128.Shuffle(r, zxy)) - (Vector128.Shuffle(l, zxy) * Vector128.Shuffle(r, yzx)); return FromVector128Unsafe(result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vec3 CrossSingle( Vec3 left, Vec3 right ) { Vector128 l = left.AsVector128Safe(); Vector128 r = right.AsVector128Safe(); Vector128 yzx = Vector128.Create(1, 2, 0, 3); Vector128 zxy = Vector128.Create(2, 0, 1, 3); Vector128 result = (Vector128.Shuffle(l, yzx) * Vector128.Shuffle(r, zxy)) - (Vector128.Shuffle(l, zxy) * Vector128.Shuffle(r, yzx)); return FromVector128Unsafe(result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vec3 CrossUInt32( Vec3 left, Vec3 right ) { Vector128 l = left.AsVector128Safe(); Vector128 r = right.AsVector128Safe(); Vector128 yzx = Vector128.Create(1U, 2U, 0U, 3U); Vector128 zxy = Vector128.Create(2U, 0U, 1U, 3U); Vector128 result = (Vector128.Shuffle(l, yzx) * Vector128.Shuffle(r, zxy)) - (Vector128.Shuffle(l, zxy) * Vector128.Shuffle(r, yzx)); return FromVector128Unsafe(result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vec3 CrossUInt64( Vec3 left, Vec3 right ) { Vector256 l = left.AsVector256Safe(); Vector256 r = right.AsVector256Safe(); Vector256 yzx = Vector256.Create(1UL, 2UL, 0UL, 3UL); Vector256 zxy = Vector256.Create(2UL, 0UL, 1UL, 3UL); Vector256 result = (Vector256.Shuffle(l, yzx) * Vector256.Shuffle(r, zxy)) - (Vector256.Shuffle(l, zxy) * Vector256.Shuffle(r, yzx)); return FromVector256Unsafe(result); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vec3 CrossInt64( Vec3 left, Vec3 right ) { Vector256 l = left.AsVector256Safe(); Vector256 r = right.AsVector256Safe(); Vector256 yzx = Vector256.Create(1U, 2U, 0U, 3U); Vector256 zxy = Vector256.Create(2U, 0U, 1U, 3U); Vector256 result = (Vector256.Shuffle(l, yzx) * Vector256.Shuffle(r, zxy)) - (Vector256.Shuffle(l, zxy) * Vector256.Shuffle(r, yzx)); return FromVector256Unsafe(result); } #endregion } }