// ----------------------------------------------------------------------------- // file="Vec4_T" // Project: StgSharp // Copyright (c) Nitload. // SPDX-License-Identifier: MIT // ----------------------------------------------------------------------------- using Nitload.Mathematics.Numeric; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; namespace Nitload.Mathematics.Numeric.Graphics { /// /// A four-dimensional numeric vector. /// [StructLayout(LayoutKind.Sequential, Pack = 16)] public struct Vec4 : IUnmanagedVector> where T : unmanaged, INumber { private Buffer _buffer; public Vec4( Vec3 v3, T w ) { X = v3.X; Y = v3.Y; Z = v3.Z; W = w; } public Vec4( T x, T y, T z, T w ) { X = x; Y = y; Z = z; W = w; } public T this[ int index ] { get => _buffer[index]; set => _buffer[index] = value; } public T X { get => _buffer[0]; set => _buffer[0] = value; } public T Y { get => _buffer[1]; set => _buffer[1] = value; } public T Z { get => _buffer[2]; set => _buffer[2] = value; } public T W { get => _buffer[3]; set => _buffer[3] = value; } public Vec2 XY { get => Unsafe.As>(ref _buffer[0]); set { X = value.X; Y = value.Y; } } public Vec3 XYZ { get => Unsafe.As>(ref _buffer[0]); set { T w = W; Unsafe.As>(ref _buffer[0]) = value; W = w; } } public Vec3 ZXY { readonly get { if (Unsafe.SizeOf() == 4) { Vector128 source = this.AsVector128Unsafe(); Vector128 bits = Unsafe.As, Vector128>(ref source); Vector128 result = Vector128.Shuffle(bits, Vector128.Create(2, 0, 1, 3)); Vector128 shuffled = Unsafe.As, Vector128>(ref result); return Vec3.FromVector128Unsafe(shuffled); } if (Unsafe.SizeOf() == 8) { Vector256 source = this.AsVector256Unsafe(); Vector256 bits = Unsafe.As, Vector256>(ref source); Vector256 result = Vector256.Shuffle(bits, Vector256.Create(2L, 0L, 1L, 3L)); Vector256 shuffled = Unsafe.As, Vector256>(ref result); return Vec3.FromVector256Unsafe(shuffled); } throw GraphicVector.ThrowUnsupportedTypeException(); } set { T w = W; if (Unsafe.SizeOf() == 4) { Vector128 source = value.AsVector128Unsafe(); Vector128 bits = Unsafe.As, Vector128>(ref source); Vector128 result = Vector128.Shuffle(bits, Vector128.Create(1, 2, 0, 3)); Vector128 shuffled = Unsafe.As, Vector128>(ref result); Unsafe.As>(ref _buffer[0]) = Vec3.FromVector128Unsafe(shuffled); } else if (Unsafe.SizeOf() == 8) { Vector256 source = value.AsVector256Unsafe(); Vector256 bits = Unsafe.As, Vector256>(ref source); Vector256 result = Vector256.Shuffle(bits, Vector256.Create(1L, 2L, 0L, 3L)); Vector256 shuffled = Unsafe.As, Vector256>(ref result); Unsafe.As>(ref _buffer[0]) = Vec3.FromVector256Unsafe(shuffled); } else { throw GraphicVector.ThrowUnsupportedTypeException(); } W = w; } } public static Vec4 One => new(T.One, T.One, T.One, T.One); public static Vec4 Zero => new(T.Zero, T.Zero, T.Zero, T.Zero); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec4 Add( Vec4 left, Vec4 right ) { return left + right; } public ReadOnlySpan AsSpan() { return MemoryMarshal.CreateReadOnlySpan(ref _buffer[0], 4); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly T Dot( Vec4 right ) { if (Unsafe.SizeOf() == 4) { Vec4 product = Vec4.FromVector128Unsafe(this.AsVector128Unsafe() * right.AsVector128Unsafe()); return product.X + product.Y + product.Z + product.W; } else if (Unsafe.SizeOf() == 8) { Vec4 product = Vec4.FromVector256Unsafe(this.AsVector256Unsafe() * right.AsVector256Unsafe()); return product.X + product.Y + product.Z + product.W; } throw GraphicVector.ThrowUnsupportedTypeException(); } public override bool Equals( object? obj ) { return (obj is Vec4 v) && (v == this); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan.Enumerator GetEnumerator() { return AsSpan().GetEnumerator(); } public override int GetHashCode() { return HashCode.Combine(X, Y, Z, W); } public Vec4 Shuffle( int t0, int t1, int t2, int t3 ) { if (Unsafe.SizeOf() == 4) { Vector128 v = this.AsVector128Unsafe(); Vector128 bits = Unsafe.As, Vector128>(ref v); Vector128 result = Vector128.Shuffle(bits, Vector128.Create(t0, t1, t2, t3)); return Vec4.FromVector128Unsafe(Unsafe.As, Vector128>(ref result)); } else if (Unsafe.SizeOf() == 8) { Vector256 v = this.AsVector256Unsafe(); Vector256 bits = Unsafe.As, Vector256>(ref v); Vector256 result = Vector256.Shuffle(bits, Vector256.Create(t0, t1, t2, t3)); return Vec4.FromVector256Unsafe(Unsafe.As, Vector256>(ref result)); } else { throw GraphicVector.ThrowUnsupportedTypeException(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec4 operator -( Vec4 left, Vec4 right ) { if (Unsafe.SizeOf() == 4) { return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() - right.AsVector128Unsafe()); } else if (Unsafe.SizeOf() == 8) { return Vec4.FromVector256Unsafe(left.AsVector256Unsafe() - right.AsVector256Unsafe()); } throw GraphicVector.ThrowUnsupportedTypeException(); } public static bool operator !=( Vec4 left, Vec4 right ) { return !(left == right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec4 operator *( Vec4 vector, T scalar ) { if (Unsafe.SizeOf() == 4) { return Vec4.FromVector128Unsafe(vector.AsVector128Unsafe() * Vector128.Create(scalar)); } else if (Unsafe.SizeOf() == 8) { return Vec4.FromVector256Unsafe(vector.AsVector256Unsafe() * Vector256.Create(scalar)); } throw GraphicVector.ThrowUnsupportedTypeException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec4 operator *( T scalar, Vec4 vector ) { return vector * scalar; } public static Vec4 operator *( GMatrix44 mat, Vec4 vec ) { return (mat[0] * vec.X) + (mat[1] * vec.Y) + (mat[2] * vec.Z) + (mat[3] * vec.W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T operator *( Vec4 left, Vec4 right ) { return left.Dot(right); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec4 operator /( Vec4 vector, T scalar ) { if (Unsafe.SizeOf() == 4) { return Vec4.FromVector128Unsafe(vector.AsVector128Unsafe() / Vector128.Create(scalar)); } else if (Unsafe.SizeOf() == 8) { return Vec4.FromVector256Unsafe(vector.AsVector256Unsafe() / Vector256.Create(scalar)); } throw GraphicVector.ThrowUnsupportedTypeException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec4 operator +( Vec4 left, Vec4 right ) { if (Unsafe.SizeOf() == 4) { return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() + right.AsVector128Unsafe()); } else if (Unsafe.SizeOf() == 8) { return Vec4.FromVector256Unsafe(left.AsVector256Unsafe() + right.AsVector256Unsafe()); } throw GraphicVector.ThrowUnsupportedTypeException(); } public static bool operator ==( Vec4 left, Vec4 right ) { if (Unsafe.SizeOf() == 4) { return left.AsVector128Unsafe() == right.AsVector128Unsafe(); } else if (Unsafe.SizeOf() == 8) { return left.AsVector256Unsafe() == right.AsVector256Unsafe(); } #pragma warning disable CA1065 throw GraphicVector.ThrowUnsupportedTypeException(); #pragma warning restore CA1065 } [InlineArray(4)] private struct Buffer { private T _element; } } }