// -----------------------------------------------------------------------------
// file="Vec3_T"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using StgSharp.Mathematics.Numeric;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace StgSharp.Mathematics.Numeric.Graphics
{
///
/// A tightly packed three-dimensional numeric vector.
///
[StructLayout(LayoutKind.Sequential, Pack = 16)]
public struct Vec3 : IUnmanagedVector>, IEquatable>, IEnumerable
where T: unmanaged, INumber
{
public T X;
public T Y;
public T Z;
public Vec3(Vec2 xy, T z)
{
X = xy.X;
Y = xy.Y;
Z = z;
}
public Vec3(T x, T y, T z)
{
X = x;
Y = y;
Z = z;
}
public Vec2 XY
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => new(X, Y);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
X = value.X;
Y = value.Y;
}
}
public Vec3 XYZ
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => this;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => this = value;
}
public static Vec3 Zero => new(T.Zero, T.Zero, T.Zero);
public static Vec3 One => new(T.One, T.One, T.One);
public static Vec3 UnitX => new(T.One, T.Zero, T.Zero);
public static Vec3 UnitY => new(T.Zero, T.One, T.Zero);
public static Vec3 UnitZ => new(T.Zero, T.Zero, T.One);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly T Dot(Vec3 right)
{
if (Unsafe.SizeOf() == 8)
{
Vec4 v = Vec4.FromVector256Unsafe(this.AsVector256Unsafe() * right.AsVector256Unsafe());
return v.X + v.Y + v.Z;
}
if (Unsafe.SizeOf() == 4)
{
Vec4 v = Vec4.FromVector128Unsafe(this.AsVector128Unsafe() * right.AsVector128Unsafe());
return v.X + v.Y + v.Z;
}
throw GraphicVector.ThrowUnsupportedTypeException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Vec3 other)
{
if (Unsafe.SizeOf() == 4) {
return this.AsVector128Safe() == other.AsVector128Safe();
}
if (Unsafe.SizeOf() == 8) {
return this.AsVector256Safe() == other.AsVector256Safe();
}
throw GraphicVector.ThrowUnsupportedTypeException();
}
public override readonly bool Equals(object? obj)
{
return obj is Vec3 other && Equals(other);
}
public static Vec3 FromSpan(ReadOnlySpan span)
{
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 readonly IEnumerator GetEnumerator()
{
yield return X;
yield return Y;
yield return Z;
}
public override readonly int GetHashCode()
{
return HashCode.Combine(X, Y, Z);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly T GetMaxValue()
{
return T.Max(X, T.Max(Y, Z));
}
public static bool IsParallel(Vec3 left, Vec3 right)
{
return Vec3.Cross(left, right) == Zero;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator -(Vec3 value)
{
if (Unsafe.SizeOf() == 4) {
return Vec3.FromVector128Unsafe(Vector128.Zero - value.AsVector128Unsafe());
}
if (Unsafe.SizeOf() == 8) {
return Vec3.FromVector256Unsafe(Vector256.Zero - value.AsVector256Unsafe());
}
throw GraphicVector.ThrowUnsupportedTypeException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator -(Vec3 left, Vec3 right)
{
if (Unsafe.SizeOf() == 4)
{
Vector128 left_v128 = left.AsVector128Unsafe();
Vector128 right_v128 = right.AsVector128Unsafe();
return Vec3.FromVector128Unsafe(left_v128 - right_v128);
}
if (Unsafe.SizeOf() == 8)
{
Vector256 left_v256 = left.AsVector256Unsafe();
Vector256 right_v256 = right.AsVector256Unsafe();
return Vec3.FromVector256Unsafe(left_v256 - right_v256);
}
throw GraphicVector.ThrowUnsupportedTypeException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vec3 left, Vec3 right)
{
return !left.Equals(right);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator *(Vec3 vector, T scalar)
{
if (Unsafe.SizeOf() == 4)
{
Vector128 vector_v128 = vector.AsVector128Unsafe();
Vector128 scalar_v128 = Vector128.Create(scalar);
return Vec3.FromVector128Unsafe(vector_v128 * scalar_v128);
}
if (Unsafe.SizeOf() == 8)
{
Vector256 vector_v256 = vector.AsVector256Unsafe();
Vector256 scalar_v256 = Vector256.Create(scalar);
return Vec3.FromVector256Unsafe(vector_v256 * scalar_v256);
}
throw GraphicVector.ThrowUnsupportedTypeException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator *(T scalar, Vec3 vector)
{
return vector * scalar;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T operator *(Vec3 left, Vec3 right)
{
return left.Dot(right);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator /(Vec3 vector, T scalar)
{
if (Unsafe.SizeOf() == 4)
{
Vector128 vector_v128 = vector.AsVector128Unsafe();
Vector128 scalar_v128 = Vector128.Create(scalar);
return Vec3.FromVector128Unsafe(vector_v128 / scalar_v128);
}
if (Unsafe.SizeOf() == 8)
{
Vector256 vector_v256 = vector.AsVector256Unsafe();
Vector256 scalar_v256 = Vector256.Create(scalar);
return Vec3.FromVector256Unsafe(vector_v256 / scalar_v256);
}
throw GraphicVector.ThrowUnsupportedTypeException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3 operator +(Vec3 left, Vec3 right)
{
if (Unsafe.SizeOf() == 4)
{
Vector128 left_v128 = left.AsVector128Unsafe();
Vector128 right_v128 = right.AsVector128Unsafe();
return Vec3.FromVector128Unsafe(left_v128 + right_v128);
}
if (Unsafe.SizeOf() == 8)
{
Vector256 left_v256 = left.AsVector256Unsafe();
Vector256 right_v256 = right.AsVector256Unsafe();
return Vec3.FromVector256Unsafe(left_v256 + right_v256);
}
throw GraphicVector.ThrowUnsupportedTypeException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vec3 left, Vec3 right)
{
return left.Equals(right);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Vec3((T X, T Y, T Z) tuple)
{
return new(tuple.X, tuple.Y, tuple.Z);
}
readonly IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}