- ISPMDLane: add MaskGather, MaskStore, Scatter, MaskScatter; update MaskLoad/Gather signatures for hardware parity - WideLane/ScalarLane: implement new methods with HW/fallback logic - MathV: gather/mask-gather now delegate to lane methods - Vector2/3/4: add CompressStore, Scatter, MaskScatter - SPMD jobs/tests/README: migrate to new APIs for correctness - Use Unsafe.BitCast instead of Unsafe.As/AsRef - Add SPMDUtility for gather index extraction - Job system: add ICustomJob<TSelf>, ScheduleCustom overload - FreeList concurrency obsolete; always thread-safe - NuGet: include LICENSE/README, set license/readme in .csproj - Docs: update SPMD usage, clarify safety notes - Minor: doc fixes, CompressStore test improvements
1485 lines
70 KiB
C#
1485 lines
70 KiB
C#
/// <auto-generated/>
|
|
/// This code is automatically generated by a T4 template.
|
|
/// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
|
|
/// </auto-generated>
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Numerics;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.Intrinsics;
|
|
using System.Runtime.Intrinsics.Arm;
|
|
using System.Runtime.Intrinsics.X86;
|
|
|
|
namespace Misaki.HighPerformance.Mathematics.SPMD;
|
|
|
|
public static unsafe partial class MathV
|
|
{
|
|
# region Vector2
|
|
|
|
// Creation Functions
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Create<TLane, TNumber>(in TLane x, in TLane y)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = x,
|
|
y = y,
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> CreateVector2<TLane, TNumber>(in TLane value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = value,
|
|
y = value,
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> LoadVector2<TLane, TNumber>(TNumber* pSrc)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(pSrc + 0),
|
|
y = TLane.Load(pSrc + 1),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> LoadVector2<TLane, TNumber>(ref TNumber src)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return LoadVector2<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> MaskLoadVector2<TLane, TNumber>(TNumber* pSrc, TLane mask)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskLoad(pSrc + 0, mask),
|
|
y = TLane.MaskLoad(pSrc + 1, mask),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> MaskLoadVector2<TLane, TNumber>(ref TNumber src, TLane mask)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskLoadVector2<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src), mask);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Load<TLane, TNumber>(TNumber* px, TNumber* py)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(px),
|
|
y = TLane.Load(py),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Load<TLane, TNumber>(ref TNumber x, ref TNumber y)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(ref x),
|
|
y = TLane.Load(ref y),
|
|
};
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> GatherVector2<TLane, TNumber>(TNumber* pData, TLane indices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Gather(pData + 0, indices, scale),
|
|
y = TLane.Gather(pData + 1, indices, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> GatherVector2<TLane, TNumber>(TNumber* pData, int* pIndices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Gather(pData + 0, pIndices, scale),
|
|
y = TLane.Gather(pData + 1, pIndices, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> GatherVector2<TLane, TNumber>(ref TNumber baseAddress, TLane indices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return GatherVector2<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), indices, scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> GatherVector2<TLane, TNumber>(ref TNumber baseAddress, ref int baseIndex, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return GatherVector2<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), (int*)Unsafe.AsPointer(ref baseIndex), scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> MaskGatherVector2<TLane, TNumber>(TNumber* pData, TLane indices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskGather(pData + 0, indices, mask, scale),
|
|
y = TLane.MaskGather(pData + 1, indices, mask, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> MaskGatherVector2<TLane, TNumber>(TNumber* pData, int* pIndices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskGather(pData + 0, pIndices, mask, scale),
|
|
y = TLane.MaskGather(pData + 1, pIndices, mask, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> MaskGatherVector2<TLane, TNumber>(ref TNumber baseAddress, TLane indices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskGatherVector2<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), indices, mask, scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> MaskGatherVector2<TLane, TNumber>(ref TNumber baseAddress, ref int baseIndex, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskGatherVector2<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), (int*)Unsafe.AsPointer(ref baseIndex), mask, scale);
|
|
}
|
|
|
|
|
|
// Math Functions
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Abs<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Abs(vector.x),
|
|
y = TLane.Abs(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Dot<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return a.x * b.x + a.y * b.y;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Sin<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Sin(vector.x),
|
|
y = TLane.Sin(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Cos<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Cos(vector.x),
|
|
y = TLane.Cos(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SinCos<TLane, TNumber>(in Vector2<TLane, TNumber> vector, out Vector2<TLane, TNumber> sin, out Vector2<TLane, TNumber> cos)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
TLane.SinCos(vector.x, out sin.x, out cos.x);
|
|
TLane.SinCos(vector.y, out sin.y, out cos.y);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Sqrt<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Sqrt(vector.x),
|
|
y = TLane.Sqrt(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Tan<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Tan(vector.x),
|
|
y = TLane.Tan(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Asin<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Asin(vector.x),
|
|
y = TLane.Asin(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Acos<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Acos(vector.x),
|
|
y = TLane.Acos(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Atan<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Atan(vector.x),
|
|
y = TLane.Atan(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Atan2<TLane, TNumber>(in Vector2<TLane, TNumber> x, in Vector2<TLane, TNumber> y)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Atan2(x.x, y.x),
|
|
y = TLane.Atan2(x.y, y.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Rsqrt<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Rsqrt(vector.x),
|
|
y = TLane.Rsqrt(vector.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Normalize<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return vector * TLane.Rsqrt(Dot(vector, vector));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Reflect<TLane, TNumber>(in Vector2<TLane, TNumber> incident, in Vector2<TLane, TNumber> normal)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var dot = Dot(incident, normal);
|
|
return incident - normal * (dot + dot);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Min<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Min(a.x, b.x),
|
|
y = TLane.Min(a.y, b.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Max<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Max(a.x, b.x),
|
|
y = TLane.Max(a.y, b.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Clamp<TLane, TNumber>(in Vector2<TLane, TNumber> value, in Vector2<TLane, TNumber> min, in Vector2<TLane, TNumber> max)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Min(Max(value, min), max);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Saturate<TLane, TNumber>(in Vector2<TLane, TNumber> value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Clamp(value, CreateVector2<TLane, TNumber>(TLane.Zero), CreateVector2<TLane, TNumber>(TLane.One));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Lerp<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b, TLane t)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return a + (b - a) * t;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Length<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return TLane.Sqrt(Dot(vector, vector));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane LengthSquared<TLane, TNumber>(in Vector2<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Dot(vector, vector);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Distance<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var diff = b - a;
|
|
return TLane.Sqrt(Dot(diff, diff));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane DistanceSquared<TLane, TNumber>(in Vector2<TLane, TNumber> a, in Vector2<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var diff = b - a;
|
|
return Dot(diff, diff);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Step<TLane, TNumber>(in Vector2<TLane, TNumber> edge, in Vector2<TLane, TNumber> value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Select(value >= edge, Vector2<TLane, TNumber>.One, Vector2<TLane, TNumber>.Zero);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Smoothstep<TLane, TNumber>(Vector2<TLane, TNumber> xMin, Vector2<TLane, TNumber> xMax, Vector2<TLane, TNumber> x)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var t = Saturate((x - xMin) / (xMax - xMin));
|
|
var two = TLane.Create(TNumber.CreateTruncating(2));
|
|
var three = TLane.Create(TNumber.CreateTruncating(3));
|
|
|
|
return t * t * (CreateVector2<TLane, TNumber>(three) - (CreateVector2<TLane, TNumber>(two) * t));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Select<TLane, TNumber>(TLane condition, in Vector2<TLane, TNumber> isTrue, in Vector2<TLane, TNumber> isFalse)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Select(condition, isTrue.x, isFalse.x),
|
|
y = TLane.Select(condition, isTrue.y, isFalse.y),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector2<TLane, TNumber> Select<TLane, TNumber>(Vector2<TLane, TNumber> condition, in Vector2<TLane, TNumber> isTrue, in Vector2<TLane, TNumber> isFalse)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector2<TLane, TNumber>
|
|
{
|
|
x = TLane.Select(condition.x, isTrue.x, isFalse.x),
|
|
y = TLane.Select(condition.y, isTrue.y, isFalse.y),
|
|
};
|
|
}
|
|
|
|
# endregion
|
|
|
|
# region Vector3
|
|
|
|
// Creation Functions
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Create<TLane, TNumber>(in TLane x, in TLane y, in TLane z)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = x,
|
|
y = y,
|
|
z = z,
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> CreateVector3<TLane, TNumber>(in TLane value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = value,
|
|
y = value,
|
|
z = value,
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> LoadVector3<TLane, TNumber>(TNumber* pSrc)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(pSrc + 0),
|
|
y = TLane.Load(pSrc + 1),
|
|
z = TLane.Load(pSrc + 2),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> LoadVector3<TLane, TNumber>(ref TNumber src)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return LoadVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> MaskLoadVector3<TLane, TNumber>(TNumber* pSrc, TLane mask)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskLoad(pSrc + 0, mask),
|
|
y = TLane.MaskLoad(pSrc + 1, mask),
|
|
z = TLane.MaskLoad(pSrc + 2, mask),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> MaskLoadVector3<TLane, TNumber>(ref TNumber src, TLane mask)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskLoadVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src), mask);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(TNumber* px, TNumber* py, TNumber* pz)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(px),
|
|
y = TLane.Load(py),
|
|
z = TLane.Load(pz),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Load<TLane, TNumber>(ref TNumber x, ref TNumber y, ref TNumber z)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(ref x),
|
|
y = TLane.Load(ref y),
|
|
z = TLane.Load(ref z),
|
|
};
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> GatherVector3<TLane, TNumber>(TNumber* pData, TLane indices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Gather(pData + 0, indices, scale),
|
|
y = TLane.Gather(pData + 1, indices, scale),
|
|
z = TLane.Gather(pData + 2, indices, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> GatherVector3<TLane, TNumber>(TNumber* pData, int* pIndices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Gather(pData + 0, pIndices, scale),
|
|
y = TLane.Gather(pData + 1, pIndices, scale),
|
|
z = TLane.Gather(pData + 2, pIndices, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> GatherVector3<TLane, TNumber>(ref TNumber baseAddress, TLane indices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return GatherVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), indices, scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> GatherVector3<TLane, TNumber>(ref TNumber baseAddress, ref int baseIndex, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return GatherVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), (int*)Unsafe.AsPointer(ref baseIndex), scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> MaskGatherVector3<TLane, TNumber>(TNumber* pData, TLane indices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskGather(pData + 0, indices, mask, scale),
|
|
y = TLane.MaskGather(pData + 1, indices, mask, scale),
|
|
z = TLane.MaskGather(pData + 2, indices, mask, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> MaskGatherVector3<TLane, TNumber>(TNumber* pData, int* pIndices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskGather(pData + 0, pIndices, mask, scale),
|
|
y = TLane.MaskGather(pData + 1, pIndices, mask, scale),
|
|
z = TLane.MaskGather(pData + 2, pIndices, mask, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> MaskGatherVector3<TLane, TNumber>(ref TNumber baseAddress, TLane indices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskGatherVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), indices, mask, scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> MaskGatherVector3<TLane, TNumber>(ref TNumber baseAddress, ref int baseIndex, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskGatherVector3<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), (int*)Unsafe.AsPointer(ref baseIndex), mask, scale);
|
|
}
|
|
|
|
|
|
// Math Functions
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Abs<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Abs(vector.x),
|
|
y = TLane.Abs(vector.y),
|
|
z = TLane.Abs(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Dot<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return a.x * b.x + a.y * b.y + a.z * b.z;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Sin<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Sin(vector.x),
|
|
y = TLane.Sin(vector.y),
|
|
z = TLane.Sin(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Cos<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Cos(vector.x),
|
|
y = TLane.Cos(vector.y),
|
|
z = TLane.Cos(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SinCos<TLane, TNumber>(in Vector3<TLane, TNumber> vector, out Vector3<TLane, TNumber> sin, out Vector3<TLane, TNumber> cos)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
TLane.SinCos(vector.x, out sin.x, out cos.x);
|
|
TLane.SinCos(vector.y, out sin.y, out cos.y);
|
|
TLane.SinCos(vector.z, out sin.z, out cos.z);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Sqrt<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Sqrt(vector.x),
|
|
y = TLane.Sqrt(vector.y),
|
|
z = TLane.Sqrt(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Tan<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Tan(vector.x),
|
|
y = TLane.Tan(vector.y),
|
|
z = TLane.Tan(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Asin<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Asin(vector.x),
|
|
y = TLane.Asin(vector.y),
|
|
z = TLane.Asin(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Acos<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Acos(vector.x),
|
|
y = TLane.Acos(vector.y),
|
|
z = TLane.Acos(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Atan<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Atan(vector.x),
|
|
y = TLane.Atan(vector.y),
|
|
z = TLane.Atan(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Atan2<TLane, TNumber>(in Vector3<TLane, TNumber> x, in Vector3<TLane, TNumber> y)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Atan2(x.x, y.x),
|
|
y = TLane.Atan2(x.y, y.y),
|
|
z = TLane.Atan2(x.z, y.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Rsqrt<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Rsqrt(vector.x),
|
|
y = TLane.Rsqrt(vector.y),
|
|
z = TLane.Rsqrt(vector.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Normalize<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return vector * TLane.Rsqrt(Dot(vector, vector));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Reflect<TLane, TNumber>(in Vector3<TLane, TNumber> incident, in Vector3<TLane, TNumber> normal)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var dot = Dot(incident, normal);
|
|
return incident - normal * (dot + dot);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Min<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Min(a.x, b.x),
|
|
y = TLane.Min(a.y, b.y),
|
|
z = TLane.Min(a.z, b.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Max<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Max(a.x, b.x),
|
|
y = TLane.Max(a.y, b.y),
|
|
z = TLane.Max(a.z, b.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Clamp<TLane, TNumber>(in Vector3<TLane, TNumber> value, in Vector3<TLane, TNumber> min, in Vector3<TLane, TNumber> max)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Min(Max(value, min), max);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Saturate<TLane, TNumber>(in Vector3<TLane, TNumber> value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Clamp(value, CreateVector3<TLane, TNumber>(TLane.Zero), CreateVector3<TLane, TNumber>(TLane.One));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Lerp<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b, TLane t)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return a + (b - a) * t;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Length<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return TLane.Sqrt(Dot(vector, vector));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane LengthSquared<TLane, TNumber>(in Vector3<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Dot(vector, vector);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Distance<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var diff = b - a;
|
|
return TLane.Sqrt(Dot(diff, diff));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane DistanceSquared<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var diff = b - a;
|
|
return Dot(diff, diff);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Step<TLane, TNumber>(in Vector3<TLane, TNumber> edge, in Vector3<TLane, TNumber> value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Select(value >= edge, Vector3<TLane, TNumber>.One, Vector3<TLane, TNumber>.Zero);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Smoothstep<TLane, TNumber>(Vector3<TLane, TNumber> xMin, Vector3<TLane, TNumber> xMax, Vector3<TLane, TNumber> x)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var t = Saturate((x - xMin) / (xMax - xMin));
|
|
var two = TLane.Create(TNumber.CreateTruncating(2));
|
|
var three = TLane.Create(TNumber.CreateTruncating(3));
|
|
|
|
return t * t * (CreateVector3<TLane, TNumber>(three) - (CreateVector3<TLane, TNumber>(two) * t));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Select<TLane, TNumber>(TLane condition, in Vector3<TLane, TNumber> isTrue, in Vector3<TLane, TNumber> isFalse)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Select(condition, isTrue.x, isFalse.x),
|
|
y = TLane.Select(condition, isTrue.y, isFalse.y),
|
|
z = TLane.Select(condition, isTrue.z, isFalse.z),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Select<TLane, TNumber>(Vector3<TLane, TNumber> condition, in Vector3<TLane, TNumber> isTrue, in Vector3<TLane, TNumber> isFalse)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = TLane.Select(condition.x, isTrue.x, isFalse.x),
|
|
y = TLane.Select(condition.y, isTrue.y, isFalse.y),
|
|
z = TLane.Select(condition.z, isTrue.z, isFalse.z),
|
|
};
|
|
}
|
|
|
|
# endregion
|
|
|
|
# region Vector4
|
|
|
|
// Creation Functions
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Create<TLane, TNumber>(in TLane x, in TLane y, in TLane z, in TLane w)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = x,
|
|
y = y,
|
|
z = z,
|
|
w = w,
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> CreateVector4<TLane, TNumber>(in TLane value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = value,
|
|
y = value,
|
|
z = value,
|
|
w = value,
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> LoadVector4<TLane, TNumber>(TNumber* pSrc)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(pSrc + 0),
|
|
y = TLane.Load(pSrc + 1),
|
|
z = TLane.Load(pSrc + 2),
|
|
w = TLane.Load(pSrc + 3),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> LoadVector4<TLane, TNumber>(ref TNumber src)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return LoadVector4<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> MaskLoadVector4<TLane, TNumber>(TNumber* pSrc, TLane mask)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskLoad(pSrc + 0, mask),
|
|
y = TLane.MaskLoad(pSrc + 1, mask),
|
|
z = TLane.MaskLoad(pSrc + 2, mask),
|
|
w = TLane.MaskLoad(pSrc + 3, mask),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> MaskLoadVector4<TLane, TNumber>(ref TNumber src, TLane mask)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskLoadVector4<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref src), mask);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Load<TLane, TNumber>(TNumber* px, TNumber* py, TNumber* pz, TNumber* pw)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(px),
|
|
y = TLane.Load(py),
|
|
z = TLane.Load(pz),
|
|
w = TLane.Load(pw),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Load<TLane, TNumber>(ref TNumber x, ref TNumber y, ref TNumber z, ref TNumber w)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Load(ref x),
|
|
y = TLane.Load(ref y),
|
|
z = TLane.Load(ref z),
|
|
w = TLane.Load(ref w),
|
|
};
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> GatherVector4<TLane, TNumber>(TNumber* pData, TLane indices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Gather(pData + 0, indices, scale),
|
|
y = TLane.Gather(pData + 1, indices, scale),
|
|
z = TLane.Gather(pData + 2, indices, scale),
|
|
w = TLane.Gather(pData + 3, indices, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> GatherVector4<TLane, TNumber>(TNumber* pData, int* pIndices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Gather(pData + 0, pIndices, scale),
|
|
y = TLane.Gather(pData + 1, pIndices, scale),
|
|
z = TLane.Gather(pData + 2, pIndices, scale),
|
|
w = TLane.Gather(pData + 3, pIndices, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> GatherVector4<TLane, TNumber>(ref TNumber baseAddress, TLane indices, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return GatherVector4<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), indices, scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> GatherVector4<TLane, TNumber>(ref TNumber baseAddress, ref int baseIndex, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return GatherVector4<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), (int*)Unsafe.AsPointer(ref baseIndex), scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> MaskGatherVector4<TLane, TNumber>(TNumber* pData, TLane indices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskGather(pData + 0, indices, mask, scale),
|
|
y = TLane.MaskGather(pData + 1, indices, mask, scale),
|
|
z = TLane.MaskGather(pData + 2, indices, mask, scale),
|
|
w = TLane.MaskGather(pData + 3, indices, mask, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> MaskGatherVector4<TLane, TNumber>(TNumber* pData, int* pIndices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.MaskGather(pData + 0, pIndices, mask, scale),
|
|
y = TLane.MaskGather(pData + 1, pIndices, mask, scale),
|
|
z = TLane.MaskGather(pData + 2, pIndices, mask, scale),
|
|
w = TLane.MaskGather(pData + 3, pIndices, mask, scale),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> MaskGatherVector4<TLane, TNumber>(ref TNumber baseAddress, TLane indices, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskGatherVector4<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), indices, mask, scale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> MaskGatherVector4<TLane, TNumber>(ref TNumber baseAddress, ref int baseIndex, TLane mask, [ConstantExpected(Min = (byte)(1), Max = (byte)(8))] byte scale)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return MaskGatherVector4<TLane, TNumber>((TNumber*)Unsafe.AsPointer(ref baseAddress), (int*)Unsafe.AsPointer(ref baseIndex), mask, scale);
|
|
}
|
|
|
|
|
|
// Math Functions
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Abs<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Abs(vector.x),
|
|
y = TLane.Abs(vector.y),
|
|
z = TLane.Abs(vector.z),
|
|
w = TLane.Abs(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Dot<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Sin<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Sin(vector.x),
|
|
y = TLane.Sin(vector.y),
|
|
z = TLane.Sin(vector.z),
|
|
w = TLane.Sin(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Cos<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Cos(vector.x),
|
|
y = TLane.Cos(vector.y),
|
|
z = TLane.Cos(vector.z),
|
|
w = TLane.Cos(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void SinCos<TLane, TNumber>(in Vector4<TLane, TNumber> vector, out Vector4<TLane, TNumber> sin, out Vector4<TLane, TNumber> cos)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
TLane.SinCos(vector.x, out sin.x, out cos.x);
|
|
TLane.SinCos(vector.y, out sin.y, out cos.y);
|
|
TLane.SinCos(vector.z, out sin.z, out cos.z);
|
|
TLane.SinCos(vector.w, out sin.w, out cos.w);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Sqrt<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Sqrt(vector.x),
|
|
y = TLane.Sqrt(vector.y),
|
|
z = TLane.Sqrt(vector.z),
|
|
w = TLane.Sqrt(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Tan<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Tan(vector.x),
|
|
y = TLane.Tan(vector.y),
|
|
z = TLane.Tan(vector.z),
|
|
w = TLane.Tan(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Asin<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Asin(vector.x),
|
|
y = TLane.Asin(vector.y),
|
|
z = TLane.Asin(vector.z),
|
|
w = TLane.Asin(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Acos<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Acos(vector.x),
|
|
y = TLane.Acos(vector.y),
|
|
z = TLane.Acos(vector.z),
|
|
w = TLane.Acos(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Atan<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Atan(vector.x),
|
|
y = TLane.Atan(vector.y),
|
|
z = TLane.Atan(vector.z),
|
|
w = TLane.Atan(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Atan2<TLane, TNumber>(in Vector4<TLane, TNumber> x, in Vector4<TLane, TNumber> y)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Atan2(x.x, y.x),
|
|
y = TLane.Atan2(x.y, y.y),
|
|
z = TLane.Atan2(x.z, y.z),
|
|
w = TLane.Atan2(x.w, y.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Rsqrt<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Rsqrt(vector.x),
|
|
y = TLane.Rsqrt(vector.y),
|
|
z = TLane.Rsqrt(vector.z),
|
|
w = TLane.Rsqrt(vector.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Normalize<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return vector * TLane.Rsqrt(Dot(vector, vector));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Reflect<TLane, TNumber>(in Vector4<TLane, TNumber> incident, in Vector4<TLane, TNumber> normal)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var dot = Dot(incident, normal);
|
|
return incident - normal * (dot + dot);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Min<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Min(a.x, b.x),
|
|
y = TLane.Min(a.y, b.y),
|
|
z = TLane.Min(a.z, b.z),
|
|
w = TLane.Min(a.w, b.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Max<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Max(a.x, b.x),
|
|
y = TLane.Max(a.y, b.y),
|
|
z = TLane.Max(a.z, b.z),
|
|
w = TLane.Max(a.w, b.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Clamp<TLane, TNumber>(in Vector4<TLane, TNumber> value, in Vector4<TLane, TNumber> min, in Vector4<TLane, TNumber> max)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Min(Max(value, min), max);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Saturate<TLane, TNumber>(in Vector4<TLane, TNumber> value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Clamp(value, CreateVector4<TLane, TNumber>(TLane.Zero), CreateVector4<TLane, TNumber>(TLane.One));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Lerp<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b, TLane t)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return a + (b - a) * t;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Length<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return TLane.Sqrt(Dot(vector, vector));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane LengthSquared<TLane, TNumber>(in Vector4<TLane, TNumber> vector)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Dot(vector, vector);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane Distance<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var diff = b - a;
|
|
return TLane.Sqrt(Dot(diff, diff));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static TLane DistanceSquared<TLane, TNumber>(in Vector4<TLane, TNumber> a, in Vector4<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var diff = b - a;
|
|
return Dot(diff, diff);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Step<TLane, TNumber>(in Vector4<TLane, TNumber> edge, in Vector4<TLane, TNumber> value)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return Select(value >= edge, Vector4<TLane, TNumber>.One, Vector4<TLane, TNumber>.Zero);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Smoothstep<TLane, TNumber>(Vector4<TLane, TNumber> xMin, Vector4<TLane, TNumber> xMax, Vector4<TLane, TNumber> x)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
var t = Saturate((x - xMin) / (xMax - xMin));
|
|
var two = TLane.Create(TNumber.CreateTruncating(2));
|
|
var three = TLane.Create(TNumber.CreateTruncating(3));
|
|
|
|
return t * t * (CreateVector4<TLane, TNumber>(three) - (CreateVector4<TLane, TNumber>(two) * t));
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Select<TLane, TNumber>(TLane condition, in Vector4<TLane, TNumber> isTrue, in Vector4<TLane, TNumber> isFalse)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Select(condition, isTrue.x, isFalse.x),
|
|
y = TLane.Select(condition, isTrue.y, isFalse.y),
|
|
z = TLane.Select(condition, isTrue.z, isFalse.z),
|
|
w = TLane.Select(condition, isTrue.w, isFalse.w),
|
|
};
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4<TLane, TNumber> Select<TLane, TNumber>(Vector4<TLane, TNumber> condition, in Vector4<TLane, TNumber> isTrue, in Vector4<TLane, TNumber> isFalse)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector4<TLane, TNumber>
|
|
{
|
|
x = TLane.Select(condition.x, isTrue.x, isFalse.x),
|
|
y = TLane.Select(condition.y, isTrue.y, isFalse.y),
|
|
z = TLane.Select(condition.z, isTrue.z, isFalse.z),
|
|
w = TLane.Select(condition.w, isTrue.w, isFalse.w),
|
|
};
|
|
}
|
|
|
|
# endregion
|
|
|
|
|
|
# region Vector3 Specific
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector3<TLane, TNumber> Cross<TLane, TNumber>(in Vector3<TLane, TNumber> a, in Vector3<TLane, TNumber> b)
|
|
where TLane : unmanaged, ISPMDLane<TLane, TNumber>
|
|
where TNumber : unmanaged, INumber<TNumber>, IBinaryNumber<TNumber>, IMinMaxValue<TNumber>, IBitwiseOperators<TNumber, TNumber, TNumber>
|
|
{
|
|
return new Vector3<TLane, TNumber>
|
|
{
|
|
x = a.y * b.z - a.z * b.y,
|
|
y = a.z * b.x - a.x * b.z,
|
|
z = a.x * b.y - a.y * b.x,
|
|
};
|
|
}
|
|
|
|
# endregion
|
|
}
|
|
|