// ----------------------------------------------------------------------------- // 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 { public T W; public T X; public T Y; public T Z; 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 Vec2 XY { get => Unsafe.As>(ref X); set { X = value.X; Y = value.Y; } } public Vec3 XYZ { get => Unsafe.As>(ref X); set { T w = W; Unsafe.As>(ref X) = value; 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 X, 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; } 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); } public static Vec4 FromSpan( ReadOnlySpan span ) { if (span.Length < 4) { throw new ArgumentException("Span length must be at least 4.", nameof(span)); } Unsafe.SkipInit(out Vec4 result); Span target = MemoryMarshal.CreateSpan(ref result.X, 4); span[..4].CopyTo(target); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan.Enumerator GetEnumerator() { return AsSpan().GetEnumerator(); } public override int GetHashCode() { return HashCode.Combine(X, Y, Z, W); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vec4 operator -( Vec4 left, Vec4 right ) { if (Unsafe.SizeOf() == 4) { return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() - right.AsVector128Unsafe()); } 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)); } 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; } [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)); } 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()); } 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(); } if (Unsafe.SizeOf() == 8) { return left.AsVector256Unsafe() == right.AsVector256Unsafe(); } #pragma warning disable CA1065 throw GraphicVector.ThrowUnsupportedTypeException(); #pragma warning restore CA1065 } } }