// -----------------------------------------------------------------------------
// 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;
}
}
}