// ----------------------------------------------------------------------------- // file="GMatrix44_T" // Project: StgSharp // Copyright (c) Nitload. // SPDX-License-Identifier: MIT // ----------------------------------------------------------------------------- using Nitload.Mathematics; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Text; using System.Threading.Tasks; namespace Nitload.Mathematics.Numeric.Graphics { [StructLayout(LayoutKind.Sequential, Pack = 16)] public struct GMatrix44 where T : unmanaged, INumber { private Buffer _buffer; internal unsafe ref Vec4 this[ int x ] { get => ref Unsafe.Add(ref Unsafe.As, Vec4>(ref this), x); } public T this[ int x, int y ] { readonly get => _buffer[x][y]; set => _buffer[x][y] = value; } public static GMatrix44 Unit { get { GMatrix44 result = new(); result[0] = new Vec4(T.One, T.Zero, T.Zero, T.Zero); result[1] = new Vec4(T.Zero, T.One, T.Zero, T.Zero); result[2] = new Vec4(T.Zero, T.Zero, T.One, T.Zero); result[3] = new Vec4(T.Zero, T.Zero, T.Zero, T.One); return result; } } public GMatrix44 Transpose { get { GMatrix44 transpose = new(); // Native SK transpose is intentionally deferred until the module // startup path can guarantee that GlobalContext has been initialized. if (Unsafe.SizeOf() == 4) { Vector128 row0Source = _buffer[0].AsVector128Unsafe(); Vector128 row1Source = _buffer[1].AsVector128Unsafe(); Vector128 row2Source = _buffer[2].AsVector128Unsafe(); Vector128 row3Source = _buffer[3].AsVector128Unsafe(); Vector128 row0 = Unsafe.As, Vector128>(ref row0Source); Vector128 row1 = Unsafe.As, Vector128>(ref row1Source); Vector128 row2 = Unsafe.As, Vector128>(ref row2Source); Vector128 row3 = Unsafe.As, Vector128>(ref row3Source); Vector128 pairMask = Vector128.Create(-1, 0, -1, 0); Vector128 firstPairMask = Vector128.Create(-1, -1, 0, 0); Vector128 lowShuffle = Vector128.Create(0, 0, 1, 1); Vector128 highShuffle = Vector128.Create(2, 2, 3, 3); Vector128 secondLaneShuffle = Vector128.Create(2, 3, 2, 3); Vector128 pair01Low = Vector128.ConditionalSelect( pairMask, Vector128.Shuffle(row0, lowShuffle), Vector128.Shuffle(row1, lowShuffle)); Vector128 pair23Low = Vector128.ConditionalSelect( pairMask, Vector128.Shuffle(row2, lowShuffle), Vector128.Shuffle(row3, lowShuffle)); Vector128 pair01High = Vector128.ConditionalSelect( pairMask, Vector128.Shuffle(row0, highShuffle), Vector128.Shuffle(row1, highShuffle)); Vector128 pair23High = Vector128.ConditionalSelect( pairMask, Vector128.Shuffle(row2, highShuffle), Vector128.Shuffle(row3, highShuffle)); Vector128 result0 = Vector128.ConditionalSelect( firstPairMask, pair01Low, pair23Low); Vector128 result1 = Vector128.ConditionalSelect( firstPairMask, Vector128.Shuffle(pair01Low, secondLaneShuffle), Vector128.Shuffle(pair23Low, secondLaneShuffle)); Vector128 result2 = Vector128.ConditionalSelect( firstPairMask, pair01High, pair23High); Vector128 result3 = Vector128.ConditionalSelect( firstPairMask, Vector128.Shuffle(pair01High, secondLaneShuffle), Vector128.Shuffle(pair23High, secondLaneShuffle)); transpose._buffer[0] = Vec4.FromVector128Unsafe( Unsafe.As, Vector128>(ref result0)); transpose._buffer[1] = Vec4.FromVector128Unsafe( Unsafe.As, Vector128>(ref result1)); transpose._buffer[2] = Vec4.FromVector128Unsafe( Unsafe.As, Vector128>(ref result2)); transpose._buffer[3] = Vec4.FromVector128Unsafe( Unsafe.As, Vector128>(ref result3)); return transpose; } if (Unsafe.SizeOf() == 8) { Vector256 row0Source = _buffer[0].AsVector256Unsafe(); Vector256 row1Source = _buffer[1].AsVector256Unsafe(); Vector256 row2Source = _buffer[2].AsVector256Unsafe(); Vector256 row3Source = _buffer[3].AsVector256Unsafe(); Vector256 row0 = Unsafe.As, Vector256>(ref row0Source); Vector256 row1 = Unsafe.As, Vector256>(ref row1Source); Vector256 row2 = Unsafe.As, Vector256>(ref row2Source); Vector256 row3 = Unsafe.As, Vector256>(ref row3Source); Vector256 pairMask = Vector256.Create(-1L, 0L, -1L, 0L); Vector256 firstPairMask = Vector256.Create(-1L, -1L, 0L, 0L); Vector256 firstShuffle = Vector256.Create(0L, 0L, 1L, 1L); Vector256 secondShuffle = Vector256.Create(2L, 2L, 3L, 3L); Vector256 pair01First = Vector256.ConditionalSelect( pairMask, Vector256.Shuffle(row0, firstShuffle), Vector256.Shuffle(row1, firstShuffle)); Vector256 pair23First = Vector256.ConditionalSelect( pairMask, Vector256.Shuffle(row2, firstShuffle), Vector256.Shuffle(row3, firstShuffle)); Vector256 pair01Second = Vector256.ConditionalSelect( pairMask, Vector256.Shuffle(row0, secondShuffle), Vector256.Shuffle(row1, secondShuffle)); Vector256 pair23Second = Vector256.ConditionalSelect( pairMask, Vector256.Shuffle(row2, secondShuffle), Vector256.Shuffle(row3, secondShuffle)); Vector256 result0 = Vector256.ConditionalSelect( firstPairMask, pair01First, pair23First); Vector256 result1 = Vector256.ConditionalSelect( firstPairMask, Vector256.Shuffle(pair01First, secondShuffle), Vector256.Shuffle(pair23First, secondShuffle)); Vector256 result2 = Vector256.ConditionalSelect( firstPairMask, pair01Second, pair23Second); Vector256 result3 = Vector256.ConditionalSelect( firstPairMask, Vector256.Shuffle(pair01Second, secondShuffle), Vector256.Shuffle(pair23Second, secondShuffle)); transpose._buffer[0] = Vec4.FromVector256Unsafe( Unsafe.As, Vector256>(ref result0)); transpose._buffer[1] = Vec4.FromVector256Unsafe( Unsafe.As, Vector256>(ref result1)); transpose._buffer[2] = Vec4.FromVector256Unsafe( Unsafe.As, Vector256>(ref result2)); transpose._buffer[3] = Vec4.FromVector256Unsafe( Unsafe.As, Vector256>(ref result3)); return transpose; } throw GraphicVector.ThrowUnsupportedTypeException(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static GMatrix44 operator -( GMatrix44 left, GMatrix44 right ) { Unsafe.SkipInit(out GMatrix44 result); result._buffer[0] = left._buffer[0] - right._buffer[0]; result._buffer[1] = left._buffer[1] - right._buffer[1]; result._buffer[2] = left._buffer[2] - right._buffer[2]; result._buffer[3] = left._buffer[3] - right._buffer[3]; return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static GMatrix44 operator *( GMatrix44 left, T right ) { Unsafe.SkipInit(out GMatrix44 result); result._buffer[0] = left._buffer[0] * right; result._buffer[1] = left._buffer[1] * right; result._buffer[2] = left._buffer[2] * right; result._buffer[3] = left._buffer[3] * right; return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static GMatrix44 operator *( T left, GMatrix44 right ) { return right * left; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static GMatrix44 operator *( GMatrix44 left, GMatrix44 right ) { Unsafe.SkipInit(out GMatrix44 result); result._buffer[0] = left._buffer[0] + right._buffer[0]; result._buffer[1] = left._buffer[1] + right._buffer[1]; result._buffer[2] = left._buffer[2] + right._buffer[2]; result._buffer[3] = left._buffer[3] + right._buffer[3]; return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static GMatrix44 operator +( GMatrix44 left, GMatrix44 right ) { Unsafe.SkipInit(out GMatrix44 result); result._buffer[0] = left._buffer[0] + right._buffer[0]; result._buffer[1] = left._buffer[1] + right._buffer[1]; result._buffer[2] = left._buffer[2] + right._buffer[2]; result._buffer[3] = left._buffer[3] + right._buffer[3]; return result; } [InlineArray(4)] private struct Buffer { public Vec4 _column; } } }