Graphic mat 44 is now generic; TextRegex source gen will use goto instead of do{}while()

This commit is contained in:
Youmu Liu
2026-09-07 17:51:15 +08:00
parent ee67dfbde1
commit 90c7538639
27 changed files with 805 additions and 713 deletions
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Root Type="DevExpress.CodeRush.Formatting.UI.Options.BracesOptionsContainer">
<Options Language="C#">
<Options>
<Item Id="{3920243c-1bac-46ce-960d-e4186d99c187}" Type="DevExpress.CodeRush.Formatting.UI.Options.Conversion.PropertyBracesOption">
<WrapOpenBrace>
<Option>Wrap</Option>
</WrapOpenBrace>
<WrapCloseBrace>
<Option>Wrap</Option>
</WrapCloseBrace>
</Item>
<Item Id="{692dd27b-3066-4dd3-beac-516a569f5203}" Type="DevExpress.CodeRush.Formatting.UI.Options.Conversion.SimplePropertyBracesOption">
<WrapOpenBrace>
<Option>Wrap</Option>
</WrapOpenBrace>
<WrapCloseBrace>
<Option>Wrap</Option>
</WrapCloseBrace>
</Item>
</Options>
</Options>
</Root>
-12
View File
@@ -1,12 +0,0 @@
[*]
end_of_line = lf
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[*.{bat,cmd,ps1}]
end_of_line = crlf
[*.cs]
# CS1591: 缺少对公共可见类型或成员的 XML 注释
dotnet_diagnostic.CS1591.severity = suggestion
+32 -32
View File
@@ -15,11 +15,11 @@ namespace Nitload.Mathematics.Numeric.Graphics
{ {
private bool _isLookAtAvailable; private bool _isLookAtAvailable;
internal GraphicsMatrix _lookAt; internal GMatrix44<float> _lookAt;
internal GraphicsMatrix _projection; internal GMatrix44<float> _projection;
internal GraphicsMatrix cameraAtt; internal GMatrix44<float> cameraAtt;
internal GraphicsMatrix rotation; internal GMatrix44<float> rotation;
internal GraphicsMatrix rotationAtt; internal GMatrix44<float> rotationAtt;
internal Radius _pitch; internal Radius _pitch;
internal Radius _row; internal Radius _row;
internal Radius _yaw; internal Radius _yaw;
@@ -27,13 +27,13 @@ namespace Nitload.Mathematics.Numeric.Graphics
public Camera() public Camera()
{ {
cameraAtt = GraphicsMatrix.Unit; cameraAtt = GMatrix44<float>.Unit;
_target = Vec3<float>.Zero; _target = Vec3<float>.Zero;
up = Vec3<float>.Zero; up = Vec3<float>.Zero;
_isLookAtAvailable = false; _isLookAtAvailable = false;
_lookAt = GraphicsMatrix.Unit; _lookAt = GMatrix44<float>.Unit;
rotationAtt = GraphicsMatrix.Unit; rotationAtt = GMatrix44<float>.Unit;
_projection = new GraphicsMatrix(); _projection = new GMatrix44<float>();
} }
public Camera( public Camera(
@@ -43,32 +43,32 @@ namespace Nitload.Mathematics.Numeric.Graphics
) )
: this() : this()
{ {
rotationAtt = GraphicsMatrix.Unit; rotationAtt = GMatrix44<float>.Unit;
cameraAtt = new GraphicsMatrix(); cameraAtt = new GMatrix44<float>();
SetViewDirection(position, target, up); SetViewDirection(position, target, up);
_pitch = Radius.Zero; _pitch = Radius.Zero;
_row = Radius.Zero; _row = Radius.Zero;
_yaw = Radius.Zero; _yaw = Radius.Zero;
} }
public GraphicsMatrix Projection => _projection; public GMatrix44<float> Projection => _projection;
public GraphicsMatrix View public GMatrix44<float> View
{ {
get get
{ {
if (_isLookAtAvailable) { if (_isLookAtAvailable) {
return _lookAt; return _lookAt;
} }
GraphicsMatrix move = GraphicsMatrix.Unit; GMatrix44<float> move = GMatrix44<float>.Unit;
move.column[3] -= cameraAtt.column[3]; move[3] = move[3] - cameraAtt[3];
_lookAt = rotationAtt.Transpose * move; _lookAt = rotationAtt.Transpose * move;
_isLookAtAvailable = true; _isLookAtAvailable = true;
return _lookAt; return _lookAt;
} }
} }
public GraphicsMatrix CameraMatrix() public GMatrix44<float> CameraMatrix()
{ {
return Projection * View; return Projection * View;
} }
@@ -77,7 +77,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
float distance float distance
) )
{ {
cameraAtt.column[3].Z -= distance; cameraAtt[3, 2] -= distance;
_isLookAtAvailable = false; _isLookAtAvailable = false;
} }
@@ -85,7 +85,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
float distance float distance
) )
{ {
cameraAtt.column[3].X -= distance; cameraAtt[3, 0] -= distance;
_isLookAtAvailable = false; _isLookAtAvailable = false;
} }
@@ -93,7 +93,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
float distance float distance
) )
{ {
cameraAtt.column[3].Y -= distance; cameraAtt[3, 1] -= distance;
_isLookAtAvailable = false; _isLookAtAvailable = false;
} }
@@ -104,9 +104,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
) )
{ {
Vec3<float> direction = position - target; Vec3<float> direction = position - target;
if ((position == cameraAtt.column[3].XYZ) && if ((position == new Vec3<float>(cameraAtt[3, 0], cameraAtt[3, 1], cameraAtt[3, 2])) &&
(this.up == up) && (this.up == up) &&
(cameraAtt.column[3].XYZ == direction)) { (new Vec3<float>(cameraAtt[3, 0], cameraAtt[3, 1], cameraAtt[3, 2]) == direction)) {
return; return;
} }
if (direction.GetLength() == 0) if (direction.GetLength() == 0)
@@ -126,10 +126,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
Vec3<float> right = Linear.Orthogonalize(Vec3.Cross(up, direction)); Vec3<float> right = Linear.Orthogonalize(Vec3.Cross(up, direction));
cameraAtt.column[0].XYZ = right; cameraAtt[0] = new Vec4<float>(right, 0);
cameraAtt.column[1].XYZ = up; cameraAtt[1] = new Vec4<float>(up, 0);
cameraAtt.column[2].XYZ = direction; cameraAtt[2] = new Vec4<float>(direction, 0);
cameraAtt.column[3].XYZ = position; cameraAtt[3] = new Vec4<float>(position, 1);
InternalPitch(); InternalPitch();
InternalRow(); InternalRow();
@@ -152,13 +152,13 @@ namespace Nitload.Mathematics.Numeric.Graphics
width = MathF.Abs(GeometryScaler.Tan(fovRadius / 2) * near * 2), width = MathF.Abs(GeometryScaler.Tan(fovRadius / 2) * near * 2),
height = (width * size.Y) / size.X; height = (width * size.Y) / size.X;
_projection.column[0].X = (2 * near) / width; _projection[0].X = (2 * near) / width;
_projection.column[1].Y = (2 * near) / height; _projection[1].Y = (2 * near) / height;
_projection.column[2].X = (2 * offsetX) / width; _projection[2].X = (2 * offsetX) / width;
_projection.column[2].Y = (2 * offsetY) / height; _projection[2].Y = (2 * offsetY) / height;
_projection.column[2].Z = (far + near) / (near - far); _projection[2].Z = (far + near) / (near - far);
_projection.column[2].W = -1; _projection[2].W = -1;
_projection.column[3].Z = (2 * near * far) / (near - far); _projection[3].Z = (2 * near * far) / (near - far);
} }
public void Test( public void Test(
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="EBO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL element-buffer handles.</summary>
public sealed record class ElementBuffer(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="FBO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL framebuffer handles.</summary>
public sealed record class FrameBuffer(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="RBO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL renderbuffer handles.</summary>
public sealed record class RenderBuffer(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
@@ -1,54 +0,0 @@
// -----------------------------------------------------------------------------
// file="TextureGL"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL texture handles.</summary>
public sealed record class TextureGL(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
public readonly record struct TextureProperty(
TextureFilter FilterOnMagnify,
TextureFilter FilterOnMinify,
TextureWrap WrapOnHorizontal,
TextureWrap WrapOnVertical
);
#pragma warning disable CA1008
public enum TextureFilter
#pragma warning restore CA1008
{
Nearest = glConst.NEAREST,
Linear = glConst.LINEAR,
NearestLinearMipmap = glConst.NEAREST_MIPMAP_LINEAR,
LinearLinearMipmap = glConst.LINEAR_MIPMAP_LINEAR,
NearestNearestMipmap = glConst.NEAREST_MIPMAP_NEAREST,
LinearNearestMipmap = glConst.LINEAR_MIPMAP_NEAREST,
}
#pragma warning disable CA1008
public enum TextureWrap
#pragma warning restore CA1008
{
Repeat = glConst.REPEAT,
MirroredRepeat = glConst.MIRRORED_REPEAT,
ClampToEdge = glConst.CLAMP_TO_EDGE,
ClampToBorder = glConst.CLAMP_TO_BORDER,
}
}
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="VAO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL vertex-array handles.</summary>
public sealed record class VertexArray(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
-21
View File
@@ -1,21 +0,0 @@
// -----------------------------------------------------------------------------
// file="VBO"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
namespace Nitload.Graphics.OpenGL
{
/// <summary>A set of OpenGL vertex-buffer handles.</summary>
public sealed record class VertexBuffer(
GlHandle[] Handles
)
{
public int Count => Handles.Length;
public GlHandle this[int index] => Handles[index];
}
}
@@ -1783,9 +1783,12 @@ namespace Nitload.Graphics.OpenGL
/// <para>See <see href="https://docs.gl/gl4/glUniform">docs.gl</see>.</para> /// <para>See <see href="https://docs.gl/gl4/glUniform">docs.gl</see>.</para>
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Uniform(int location, bool transpose, GraphicsMatrix value) public void Uniform(int location, bool transpose, GMatrix44<float> value)
{ {
__context->glUniformMatrix4fv(location, 1, transpose ? (byte)1 : (byte)0, (float*)&value); fixed (GMatrix44<float>* __value = &value)
{
__context->glUniformMatrix4fv(location, 1, transpose ? (byte)1 : (byte)0, (float*)__value);
}
} }
/// <summary> /// <summary>
@@ -1794,9 +1797,9 @@ namespace Nitload.Graphics.OpenGL
/// <para>See <see href="https://docs.gl/gl4/glUniform">docs.gl</see>.</para> /// <para>See <see href="https://docs.gl/gl4/glUniform">docs.gl</see>.</para>
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Uniform(int location, bool transpose, ReadOnlySpan<GraphicsMatrix> values) public void Uniform(int location, bool transpose, ReadOnlySpan<GMatrix44<float>> values)
{ {
fixed (GraphicsMatrix* __value = values) fixed (GMatrix44<float>* __value = values)
{ {
__context->glUniformMatrix4fv(location, values.Length, transpose ? (byte)1 : (byte)0, (float*)__value); __context->glUniformMatrix4fv(location, values.Length, transpose ? (byte)1 : (byte)0, (float*)__value);
} }
@@ -631,9 +631,12 @@ namespace Nitload.Graphics.OpenGL
/// <para>See <see href="https://docs.gl/gl4/glProgramUniform">docs.gl</see>.</para> /// <para>See <see href="https://docs.gl/gl4/glProgramUniform">docs.gl</see>.</para>
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ProgramUniform(GlHandle program, int location, bool transpose, GraphicsMatrix value) public void ProgramUniform(GlHandle program, int location, bool transpose, GMatrix44<float> value)
{ {
__context->glProgramUniformMatrix4fv(program.Value, location, 1, transpose ? (byte)1 : (byte)0, (float*)&value); fixed (GMatrix44<float>* __value = &value)
{
__context->glProgramUniformMatrix4fv(program.Value, location, 1, transpose ? (byte)1 : (byte)0, (float*)__value);
}
} }
/// <summary> /// <summary>
@@ -642,9 +645,9 @@ namespace Nitload.Graphics.OpenGL
/// <para>See <see href="https://docs.gl/gl4/glProgramUniform">docs.gl</see>.</para> /// <para>See <see href="https://docs.gl/gl4/glProgramUniform">docs.gl</see>.</para>
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ProgramUniform(GlHandle program, int location, bool transpose, ReadOnlySpan<GraphicsMatrix> values) public void ProgramUniform(GlHandle program, int location, bool transpose, ReadOnlySpan<GMatrix44<float>> values)
{ {
fixed (GraphicsMatrix* __value = values) fixed (GMatrix44<float>* __value = values)
{ {
__context->glProgramUniformMatrix4fv(program.Value, location, values.Length, transpose ? (byte)1 : (byte)0, (float*)__value); __context->glProgramUniformMatrix4fv(program.Value, location, values.Length, transpose ? (byte)1 : (byte)0, (float*)__value);
} }
@@ -16,41 +16,61 @@ namespace Nitload.Geometries
private bool globalCoordAvailable; private bool globalCoordAvailable;
private CoordinationBase localCoordination; private CoordinationBase localCoordination;
private GraphicsMatrix coordMat; private GMatrix44<float> coordMat;
public CoordinationBase( public CoordinationBase(
CoordinationBase localCoordination CoordinationBase localCoordination
) )
{ {
this.localCoordination = localCoordination; this.localCoordination = localCoordination;
coordMat = new GraphicsMatrix(); coordMat = new GMatrix44<float>();
} }
public virtual Point LocalOrigin public virtual Point LocalOrigin
{ {
get => new Point(coordMat.column[3].XYZ); get => new Point(new Vec3<float>(coordMat[3, 0], coordMat[3, 1], coordMat[3, 2]));
internal set => coordMat.column[3].XYZ = value.Coord; internal set
{
coordMat[3, 0] = value.Coord.X;
coordMat[3, 1] = value.Coord.Y;
coordMat[3, 2] = value.Coord.Z;
}
} }
public virtual Vec3<float> LocalX public virtual Vec3<float> LocalX
{ {
get => coordMat.column[3].XYZ; get => new Vec3<float>(coordMat[3, 0], coordMat[3, 1], coordMat[3, 2]);
internal set => coordMat.column[3].XYZ = value; internal set
{
coordMat[3, 0] = value.X;
coordMat[3, 1] = value.Y;
coordMat[3, 2] = value.Z;
}
} }
public virtual Vec3<float> LocalY public virtual Vec3<float> LocalY
{ {
get => coordMat.column[3].XYZ; get => new Vec3<float>(coordMat[3, 0], coordMat[3, 1], coordMat[3, 2]);
internal set => coordMat.column[3].XYZ = value; internal set
{
coordMat[3, 0] = value.X;
coordMat[3, 1] = value.Y;
coordMat[3, 2] = value.Z;
}
} }
public virtual Vec3<float> LocalZ public virtual Vec3<float> LocalZ
{ {
get => coordMat.column[3].XYZ; get => new Vec3<float>(coordMat[3, 0], coordMat[3, 1], coordMat[3, 2]);
set => coordMat.column[3].XYZ = value; set
{
coordMat[3, 0] = value.X;
coordMat[3, 1] = value.Y;
coordMat[3, 2] = value.Z;
}
} }
protected ref GraphicsMatrix CoordMat => ref coordMat; protected ref GMatrix44<float> CoordMat => ref coordMat;
} }
} }
@@ -26,11 +26,11 @@ namespace Nitload.Geometries
) )
: base(local) : base(local)
{ {
CoordMat = GraphicsMatrix.Unit; CoordMat = GMatrix44<float>.Unit;
CoordMat.column[0] = new Vec4<float>(xAxis, 0); CoordMat[0] = new Vec4<float>(xAxis, 0);
CoordMat.column[1] = new Vec4<float>(yAxis, 0); CoordMat[1] = new Vec4<float>(yAxis, 0);
CoordMat.column[2] = new Vec4<float>(Linear.Normalize(Vec3.Cross(xAxis, yAxis)), 0); CoordMat[2] = new Vec4<float>(Linear.Normalize(Vec3.Cross(xAxis, yAxis)), 0);
LocalOrigin = origin; LocalOrigin = origin;
} }
@@ -41,9 +41,7 @@ namespace Nitload.Geometries
public Vec3<float> CenterPositionGlobal { get; internal set; } public Vec3<float> CenterPositionGlobal { get; internal set; }
public Vec3<float> Coord// public Vec3<float> Coord { get => GlobalBuffer.CoordAndRotationList[BufferId].XYZ; set
{ get => GlobalBuffer.CoordAndRotationList[BufferId].XYZ;//
set
{ {
Vec4<float> v = new(value, 0); Vec4<float> v = new(value, 0);
GlobalBuffer.CoordAndRotationList[BufferId] = v; GlobalBuffer.CoordAndRotationList[BufferId] = v;
@@ -0,0 +1,190 @@
// -----------------------------------------------------------------------------
// 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<T> where T : unmanaged, INumber<T>
{
private Buffer _buffer;
public Vec4<T> this[
int x
]
{
readonly get => _buffer[x];
set => _buffer[x] = value;
}
public T this[
int x,
int y
]
{
readonly get => _buffer[x][y];
set => _buffer[x][y] = value;
}
public static GMatrix44<T> Unit
{
get
{
GMatrix44<T> result = new();
result[0] = new Vec4<T>(T.One, T.Zero, T.Zero, T.Zero);
result[1] = new Vec4<T>(T.Zero, T.One, T.Zero, T.Zero);
result[2] = new Vec4<T>(T.Zero, T.Zero, T.One, T.Zero);
result[3] = new Vec4<T>(T.Zero, T.Zero, T.Zero, T.One);
return result;
}
}
public GMatrix44<T> Transpose
{
get
{
GMatrix44<T> transpose = new();
// Native SK transpose is intentionally deferred until the module
// startup path can guarantee that GlobalContext has been initialized.
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> row0Source = _buffer[0].AsVector128Unsafe();
Vector128<T> row1Source = _buffer[1].AsVector128Unsafe();
Vector128<T> row2Source = _buffer[2].AsVector128Unsafe();
Vector128<T> row3Source = _buffer[3].AsVector128Unsafe();
Vector128<int> row0 = Unsafe.As<Vector128<T>, Vector128<int>>(ref row0Source);
Vector128<int> row1 = Unsafe.As<Vector128<T>, Vector128<int>>(ref row1Source);
Vector128<int> row2 = Unsafe.As<Vector128<T>, Vector128<int>>(ref row2Source);
Vector128<int> row3 = Unsafe.As<Vector128<T>, Vector128<int>>(ref row3Source);
Vector128<int> pairMask = Vector128.Create(-1, 0, -1, 0);
Vector128<int> firstPairMask = Vector128.Create(-1, -1, 0, 0);
Vector128<int> lowShuffle = Vector128.Create(0, 0, 1, 1);
Vector128<int> highShuffle = Vector128.Create(2, 2, 3, 3);
Vector128<int> secondLaneShuffle = Vector128.Create(2, 3, 2, 3);
Vector128<int> pair01Low = Vector128.ConditionalSelect(
pairMask,
Vector128.Shuffle(row0, lowShuffle),
Vector128.Shuffle(row1, lowShuffle));
Vector128<int> pair23Low = Vector128.ConditionalSelect(
pairMask,
Vector128.Shuffle(row2, lowShuffle),
Vector128.Shuffle(row3, lowShuffle));
Vector128<int> pair01High = Vector128.ConditionalSelect(
pairMask,
Vector128.Shuffle(row0, highShuffle),
Vector128.Shuffle(row1, highShuffle));
Vector128<int> pair23High = Vector128.ConditionalSelect(
pairMask,
Vector128.Shuffle(row2, highShuffle),
Vector128.Shuffle(row3, highShuffle));
Vector128<int> result0 = Vector128.ConditionalSelect(
firstPairMask, pair01Low, pair23Low);
Vector128<int> result1 = Vector128.ConditionalSelect(
firstPairMask,
Vector128.Shuffle(pair01Low, secondLaneShuffle),
Vector128.Shuffle(pair23Low, secondLaneShuffle));
Vector128<int> result2 = Vector128.ConditionalSelect(
firstPairMask, pair01High, pair23High);
Vector128<int> result3 = Vector128.ConditionalSelect(
firstPairMask,
Vector128.Shuffle(pair01High, secondLaneShuffle),
Vector128.Shuffle(pair23High, secondLaneShuffle));
transpose._buffer[0] = Vec4.FromVector128Unsafe(
Unsafe.As<Vector128<int>, Vector128<T>>(ref result0));
transpose._buffer[1] = Vec4.FromVector128Unsafe(
Unsafe.As<Vector128<int>, Vector128<T>>(ref result1));
transpose._buffer[2] = Vec4.FromVector128Unsafe(
Unsafe.As<Vector128<int>, Vector128<T>>(ref result2));
transpose._buffer[3] = Vec4.FromVector128Unsafe(
Unsafe.As<Vector128<int>, Vector128<T>>(ref result3));
return transpose;
}
if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> row0Source = _buffer[0].AsVector256Unsafe();
Vector256<T> row1Source = _buffer[1].AsVector256Unsafe();
Vector256<T> row2Source = _buffer[2].AsVector256Unsafe();
Vector256<T> row3Source = _buffer[3].AsVector256Unsafe();
Vector256<long> row0 = Unsafe.As<Vector256<T>, Vector256<long>>(ref row0Source);
Vector256<long> row1 = Unsafe.As<Vector256<T>, Vector256<long>>(ref row1Source);
Vector256<long> row2 = Unsafe.As<Vector256<T>, Vector256<long>>(ref row2Source);
Vector256<long> row3 = Unsafe.As<Vector256<T>, Vector256<long>>(ref row3Source);
Vector256<long> pairMask = Vector256.Create(-1L, 0L, -1L, 0L);
Vector256<long> firstPairMask = Vector256.Create(-1L, -1L, 0L, 0L);
Vector256<long> firstShuffle = Vector256.Create(0L, 0L, 1L, 1L);
Vector256<long> secondShuffle = Vector256.Create(2L, 2L, 3L, 3L);
Vector256<long> pair01First = Vector256.ConditionalSelect(
pairMask,
Vector256.Shuffle(row0, firstShuffle),
Vector256.Shuffle(row1, firstShuffle));
Vector256<long> pair23First = Vector256.ConditionalSelect(
pairMask,
Vector256.Shuffle(row2, firstShuffle),
Vector256.Shuffle(row3, firstShuffle));
Vector256<long> pair01Second = Vector256.ConditionalSelect(
pairMask,
Vector256.Shuffle(row0, secondShuffle),
Vector256.Shuffle(row1, secondShuffle));
Vector256<long> pair23Second = Vector256.ConditionalSelect(
pairMask,
Vector256.Shuffle(row2, secondShuffle),
Vector256.Shuffle(row3, secondShuffle));
Vector256<long> result0 = Vector256.ConditionalSelect(
firstPairMask, pair01First, pair23First);
Vector256<long> result1 = Vector256.ConditionalSelect(
firstPairMask,
Vector256.Shuffle(pair01First, secondShuffle),
Vector256.Shuffle(pair23First, secondShuffle));
Vector256<long> result2 = Vector256.ConditionalSelect(
firstPairMask, pair01Second, pair23Second);
Vector256<long> result3 = Vector256.ConditionalSelect(
firstPairMask,
Vector256.Shuffle(pair01Second, secondShuffle),
Vector256.Shuffle(pair23Second, secondShuffle));
transpose._buffer[0] = Vec4.FromVector256Unsafe(
Unsafe.As<Vector256<long>, Vector256<T>>(ref result0));
transpose._buffer[1] = Vec4.FromVector256Unsafe(
Unsafe.As<Vector256<long>, Vector256<T>>(ref result1));
transpose._buffer[2] = Vec4.FromVector256Unsafe(
Unsafe.As<Vector256<long>, Vector256<T>>(ref result2));
transpose._buffer[3] = Vec4.FromVector256Unsafe(
Unsafe.As<Vector256<long>, Vector256<T>>(ref result3));
return transpose;
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
}
[InlineArray(4)]
private struct Buffer
{
public Vec4<T> _column;
}
}
}
@@ -1,261 +0,0 @@
// -----------------------------------------------------------------------------
// file="GraphicsMatrix"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using Nitload.Mathematics;
using Nitload.Mathematics.Internal;
using Nitload.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.X86;
namespace Nitload.Mathematics.Numeric.Graphics
{
[StructLayout(LayoutKind.Explicit, Size = 16 * sizeof(float), Pack = 16)]
public unsafe struct GraphicsMatrix : IEquatable<GraphicsMatrix>
{
[FieldOffset(0 * sizeof(float))] internal Column column;
[FieldOffset(0)] internal ColumnSet4 mat;
[FieldOffset(0)] internal MatrixKernel<float> kernel;
internal GraphicsMatrix(
ColumnSet4 mat
)
{
Unsafe.SkipInit(out this);
this.mat = mat;
}
internal GraphicsMatrix(
Vector4 vec0,
Vector4 vec1,
Vector4 vec2,
Vector4 vec3
)
{
Unsafe.SkipInit(out this);
mat.colum0 = vec0;
mat.colum1 = vec1;
mat.colum2 = vec2;
mat.colum3 = vec3;
}
public GraphicsMatrix()
{
Unsafe.SkipInit(out this);
}
public unsafe GraphicsMatrix(
float a00,
float a01,
float a02,
float a03,
float a10,
float a11,
float a12,
float a13,
float a20,
float a21,
float a22,
float a23,
float a30,
float a31,
float a32,
float a33
)
{
Unsafe.SkipInit(out this);
mat.colum0 = new Vector4(a00, a10, a20, a30);
mat.colum1 = new Vector4(a01, a11, a21, a31);
mat.colum2 = new Vector4(a02, a12, a22, a32);
mat.colum3 = new Vector4(a03, a13, a23, a33);
}
public unsafe float this[
int rowNum,
int columNum
]
{
get
{
#if DEBUG
if (rowNum is > 3 or < 0)
{
throw new ArgumentOutOfRangeException(nameof(columNum));
}
if (columNum is > 3 or < 0) {
throw new ArgumentOutOfRangeException(nameof(columNum));
}
#endif
return kernel[rowNum + (4 * columNum)];
}
set
{
#if DEBUG
if (rowNum is > 3 or < 0)
{
throw new ArgumentOutOfRangeException(nameof(columNum));
}
if (columNum is > 3 or < 0) {
throw new ArgumentOutOfRangeException(nameof(columNum));
}
#endif
kernel[rowNum + (4 * columNum)] = value;
}
}
public GraphicsMatrix Transpose
{
get
{
GraphicsMatrix transpose = new();
InternalTranspose(ref transpose);
return transpose;
}
}
public static GraphicsMatrix Unit => new GraphicsMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
0, 0, 0, 1);
public static GraphicsMatrix WNegativeUnit => new GraphicsMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 1, 0, 0, 0, 0, -1);
public static GraphicsMatrix XNegativeUnit => new GraphicsMatrix(-1, 0, 0, 0, 0, 1, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1);
public static GraphicsMatrix YNegativeUnit => new GraphicsMatrix(1, 0, 0, 0, 0, -1, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1);
public static GraphicsMatrix ZNegativeUnit => new GraphicsMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0,
0, -1, 0, 0, 0, 0, 1);
public ReadOnlySpan<float> AsSpan()
{
return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As<ColumnSet4, float>(ref mat), 16);
}
public override bool Equals(
object? obj
)
{
return (obj is GraphicsMatrix x) && Equals(x);
}
public bool Equals(
GraphicsMatrix other
)
{
return mat.Equals(other.mat);
}
public override int GetHashCode()
{
return HashCode.Combine(mat.colum0.GetHashCode(), mat.colum1.GetHashCode(),
mat.colum2.GetHashCode(), mat.colum3.GetHashCode());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe void InternalTranspose(
ref GraphicsMatrix transpose
)
{
const int f32 = 0;
fixed (MatrixKernel<float>* source = &this.kernel, target = &transpose.kernel) {
NumericalModule.GlobalContext.mat_sk[f32].Call(MatrixIntrinsicHandle.Transpose,
null, (MatrixKernel*)source,
(MatrixKernel*)target, 0);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe GraphicsMatrix operator -(
GraphicsMatrix left,
GraphicsMatrix right
)
{
GraphicsMatrix ret = new();
int f32 = MatrixElementType.F32.IntrinsicNode;
NumericalModule.GlobalContext.mat_sk[f32].Call(MatrixIntrinsicHandle.Sub,
(MatrixKernel*)&left.kernel,
(MatrixKernel*)&right.kernel,
(MatrixKernel*)&ret.kernel, 1);
return ret;
}
public static bool operator !=(
GraphicsMatrix left,
GraphicsMatrix right
)
{
return !(left == right);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe GraphicsMatrix operator *(
GraphicsMatrix mat,
float value
)
{
int f32 = MatrixElementType.F32.IntrinsicNode;
return new GraphicsMatrix(mat.mat.colum0 * value, mat.mat.colum1 * value,
mat.mat.colum2 * value, mat.mat.colum3 * value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static GraphicsMatrix operator *(
GraphicsMatrix left,
GraphicsMatrix right
)
{
GraphicsMatrix ret = new();
int f32 = MatrixElementType.F32.IntrinsicNode;
NumericalModule.GlobalContext.mat_sk[f32].Call(MatrixIntrinsicHandle.Fma,
(MatrixKernel*)&left,
(MatrixKernel*)&right,
(MatrixKernel*)&ret, 0);
return ret;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe GraphicsMatrix operator +(
GraphicsMatrix left,
GraphicsMatrix right
)
{
GraphicsMatrix ret = new();
int f32 = MatrixElementType.F32.IntrinsicNode;
NumericalModule.GlobalContext.mat_sk[f32].Call(MatrixIntrinsicHandle.Add,
(MatrixKernel*)&left,
(MatrixKernel*)&right,
(MatrixKernel*)&ret, 1);
return ret;
}
public static bool operator ==(
GraphicsMatrix left,
GraphicsMatrix right
)
{
return left.Equals(right);
}
[InlineArray(4)]
internal struct Column
{
private Vec4<float> value;
}
}
}
@@ -15,13 +15,61 @@ namespace Nitload.Mathematics.Numeric.Graphics
public static class Vec3 public static class Vec3
{ {
public static bool IsParallel<T>(Vec3<T> left, Vec3<T> right) where T: unmanaged,INumber<T> [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<double> ConvertToDouble(
Vec3<long> source
)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<double> ConvertToDouble(
Vec3<ulong> source
)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<float> ConvertToSingle(
Vec3<int> source
)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<float> ConvertToSingle(
Vec3<uint> source
)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
}
public static Vec3<T> FromSpan<T>(
ReadOnlySpan<T> span
) where T : unmanaged, INumber<T>
{
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 static bool IsParallel<T>(
Vec3<T> left,
Vec3<T> right
) where T : unmanaged,INumber<T>
{ {
return Cross(left, right).Equals(T.Zero); return Cross(left, right).Equals(T.Zero);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector128<T> AsVector128Safe<T>(this Vec3<T> source) where T: unmanaged, INumber<T> internal static Vector128<T> AsVector128Safe<T>(
this Vec3<T> source
) where T : unmanaged, INumber<T>
{ {
Vector128<T> result = Vector128<T>.Zero; Vector128<T> result = Vector128<T>.Zero;
Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source); Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source);
@@ -29,7 +77,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector128<T> AsVector128Unsafe<T>(this Vec3<T> source) where T: unmanaged, INumber<T> internal static Vector128<T> AsVector128Unsafe<T>(
this Vec3<T> source
) where T : unmanaged, INumber<T>
{ {
Unsafe.SkipInit(out Vector128<T> result); Unsafe.SkipInit(out Vector128<T> result);
Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source); Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source);
@@ -37,7 +87,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector256<T> AsVector256Safe<T>(this Vec3<T> source) where T: unmanaged, INumber<T> internal static Vector256<T> AsVector256Safe<T>(
this Vec3<T> source
) where T : unmanaged, INumber<T>
{ {
Vector256<T> result = Vector256<T>.Zero; Vector256<T> result = Vector256<T>.Zero;
Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source); Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source);
@@ -45,7 +97,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector256<T> AsVector256Unsafe<T>(this Vec3<T> source) where T: unmanaged, INumber<T> internal static Vector256<T> AsVector256Unsafe<T>(
this Vec3<T> source
) where T : unmanaged, INumber<T>
{ {
Unsafe.SkipInit(out Vector256<T> result); Unsafe.SkipInit(out Vector256<T> result);
Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source); Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source);
@@ -53,45 +107,28 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vec3<T> FromVector128Unsafe<T>(Vector128<T> source) where T: unmanaged, INumber<T> internal static Vec3<T> FromVector128Unsafe<T>(
Vector128<T> source
) where T : unmanaged, INumber<T>
{ {
return Unsafe.As<Vector128<T>, Vec3<T>>(ref source); return Unsafe.As<Vector128<T>, Vec3<T>>(ref source);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vec3<T> FromVector256Unsafe<T>(Vector256<T> source) where T: unmanaged, INumber<T> internal static Vec3<T> FromVector256Unsafe<T>(
Vector256<T> source
) where T : unmanaged, INumber<T>
{ {
return Unsafe.As<Vector256<T>, Vec3<T>>(ref source); return Unsafe.As<Vector256<T>, Vec3<T>>(ref source);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<float> ConvertToSingle(Vec3<int> source)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<float> ConvertToSingle(Vec3<uint> source)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<double> ConvertToDouble(Vec3<long> source)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<double> ConvertToDouble(Vec3<ulong> source)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Safe()));
}
#region cross #region cross
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> Cross<T>(Vec3<T> left, Vec3<T> right) where T: unmanaged, INumber<T> public static Vec3<T> Cross<T>(
Vec3<T> left,
Vec3<T> right
) where T : unmanaged, INumber<T>
{ {
if (typeof(T) == typeof(float)) if (typeof(T) == typeof(float))
{ {
@@ -140,7 +177,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<double> CrossDouble(Vec3<double> left, Vec3<double> right) private static Vec3<double> CrossDouble(
Vec3<double> left,
Vec3<double> right
)
{ {
Vector256<double> l = left.AsVector256Safe(); Vector256<double> l = left.AsVector256Safe();
Vector256<double> r = right.AsVector256Safe(); Vector256<double> r = right.AsVector256Safe();
@@ -151,7 +191,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<int> CrossInt32(Vec3<int> left, Vec3<int> right) private static Vec3<int> CrossInt32(
Vec3<int> left,
Vec3<int> right
)
{ {
Vector128<int> l = left.AsVector128Safe(); Vector128<int> l = left.AsVector128Safe();
Vector128<int> r = right.AsVector128Safe(); Vector128<int> r = right.AsVector128Safe();
@@ -162,7 +205,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<float> CrossSingle(Vec3<float> left, Vec3<float> right) private static Vec3<float> CrossSingle(
Vec3<float> left,
Vec3<float> right
)
{ {
Vector128<float> l = left.AsVector128Safe(); Vector128<float> l = left.AsVector128Safe();
Vector128<float> r = right.AsVector128Safe(); Vector128<float> r = right.AsVector128Safe();
@@ -173,7 +219,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<uint> CrossUInt32(Vec3<uint> left, Vec3<uint> right) private static Vec3<uint> CrossUInt32(
Vec3<uint> left,
Vec3<uint> right
)
{ {
Vector128<uint> l = left.AsVector128Safe(); Vector128<uint> l = left.AsVector128Safe();
Vector128<uint> r = right.AsVector128Safe(); Vector128<uint> r = right.AsVector128Safe();
@@ -184,7 +233,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<ulong> CrossUInt64(Vec3<ulong> left, Vec3<ulong> right) private static Vec3<ulong> CrossUInt64(
Vec3<ulong> left,
Vec3<ulong> right
)
{ {
Vector256<ulong> l = left.AsVector256Safe(); Vector256<ulong> l = left.AsVector256Safe();
Vector256<ulong> r = right.AsVector256Safe(); Vector256<ulong> r = right.AsVector256Safe();
@@ -195,7 +247,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vec3<long> CrossInt64(Vec3<long> left, Vec3<long> right) private static Vec3<long> CrossInt64(
Vec3<long> left,
Vec3<long> right
)
{ {
Vector256<long> l = left.AsVector256Safe(); Vector256<long> l = left.AsVector256Safe();
Vector256<long> r = right.AsVector256Safe(); Vector256<long> r = right.AsVector256Safe();
@@ -28,14 +28,21 @@ namespace Nitload.Mathematics.Numeric.Graphics
public T Y; public T Y;
public T Z; public T Z;
public Vec3(Vec2<T> xy, T z) public Vec3(
Vec2<T> xy,
T z
)
{ {
X = xy.X; X = xy.X;
Y = xy.Y; Y = xy.Y;
Z = z; Z = z;
} }
public Vec3(T x, T y, T z) public Vec3(
T x,
T y,
T z
)
{ {
X = x; X = x;
Y = y; Y = y;
@@ -73,7 +80,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
public static Vec3<T> UnitZ => new(T.Zero, T.Zero, T.One); public static Vec3<T> UnitZ => new(T.Zero, T.Zero, T.One);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly T Dot(Vec3<T> right) public readonly T Dot(
Vec3<T> right
)
{ {
if (Unsafe.SizeOf<T>() == 8) if (Unsafe.SizeOf<T>() == 8)
{ {
@@ -89,31 +98,28 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Equals(Vec3<T> other) public readonly bool Equals(
Vec3<T> other
)
{
if (Unsafe.SizeOf<T>() == 4)
{ {
if (Unsafe.SizeOf<T>() == 4) {
return this.AsVector128Safe() == other.AsVector128Safe(); return this.AsVector128Safe() == other.AsVector128Safe();
} } else if (Unsafe.SizeOf<T>() == 8) {
if (Unsafe.SizeOf<T>() == 8) {
return this.AsVector256Safe() == other.AsVector256Safe(); return this.AsVector256Safe() == other.AsVector256Safe();
} }
#pragma warning disable CA1065
throw GraphicVector.ThrowUnsupportedTypeException<T>(); throw GraphicVector.ThrowUnsupportedTypeException<T>();
#pragma warning restore CA1065
} }
public override readonly bool Equals(object? obj) public override readonly bool Equals(
object? obj
)
{ {
return obj is Vec3<T> other && Equals(other); return obj is Vec3<T> other && Equals(other);
} }
public static Vec3<T> FromSpan(ReadOnlySpan<T> 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<T> GetEnumerator() public readonly IEnumerator<T> GetEnumerator()
{ {
yield return X; yield return X;
@@ -132,33 +138,40 @@ namespace Nitload.Mathematics.Numeric.Graphics
return T.Max(X, T.Max(Y, Z)); return T.Max(X, T.Max(Y, Z));
} }
public static bool IsParallel(Vec3<T> left, Vec3<T> right) public static bool IsParallel(
Vec3<T> left,
Vec3<T> right
)
{ {
return Vec3.Cross(left, right) == Zero; return Vec3.Cross(left, right) == Zero;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator -(Vec3<T> value) public static Vec3<T> operator -(
Vec3<T> value
)
{
if (Unsafe.SizeOf<T>() == 4)
{ {
if (Unsafe.SizeOf<T>() == 4) {
return Vec3.FromVector128Unsafe(Vector128<T>.Zero - value.AsVector128Unsafe()); return Vec3.FromVector128Unsafe(Vector128<T>.Zero - value.AsVector128Unsafe());
} } else if (Unsafe.SizeOf<T>() == 8) {
if (Unsafe.SizeOf<T>() == 8) {
return Vec3.FromVector256Unsafe(Vector256<T>.Zero - value.AsVector256Unsafe()); return Vec3.FromVector256Unsafe(Vector256<T>.Zero - value.AsVector256Unsafe());
} }
throw GraphicVector.ThrowUnsupportedTypeException<T>(); throw GraphicVector.ThrowUnsupportedTypeException<T>();
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator -(Vec3<T> left, Vec3<T> right) public static Vec3<T> operator -(
Vec3<T> left,
Vec3<T> right
)
{ {
if (Unsafe.SizeOf<T>() == 4) if (Unsafe.SizeOf<T>() == 4)
{ {
Vector128<T> left_v128 = left.AsVector128Unsafe(); Vector128<T> left_v128 = left.AsVector128Unsafe();
Vector128<T> right_v128 = right.AsVector128Unsafe(); Vector128<T> right_v128 = right.AsVector128Unsafe();
return Vec3.FromVector128Unsafe(left_v128 - right_v128); return Vec3.FromVector128Unsafe(left_v128 - right_v128);
} } else if (Unsafe.SizeOf<T>() == 8)
if (Unsafe.SizeOf<T>() == 8)
{ {
Vector256<T> left_v256 = left.AsVector256Unsafe(); Vector256<T> left_v256 = left.AsVector256Unsafe();
Vector256<T> right_v256 = right.AsVector256Unsafe(); Vector256<T> right_v256 = right.AsVector256Unsafe();
@@ -168,21 +181,26 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Vec3<T> left, Vec3<T> right) public static bool operator !=(
Vec3<T> left,
Vec3<T> right
)
{ {
return !left.Equals(right); return !left.Equals(right);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator *(Vec3<T> vector, T scalar) public static Vec3<T> operator *(
Vec3<T> vector,
T scalar
)
{ {
if (Unsafe.SizeOf<T>() == 4) if (Unsafe.SizeOf<T>() == 4)
{ {
Vector128<T> vector_v128 = vector.AsVector128Unsafe(); Vector128<T> vector_v128 = vector.AsVector128Unsafe();
Vector128<T> scalar_v128 = Vector128.Create(scalar); Vector128<T> scalar_v128 = Vector128.Create(scalar);
return Vec3.FromVector128Unsafe(vector_v128 * scalar_v128); return Vec3.FromVector128Unsafe(vector_v128 * scalar_v128);
} } else if (Unsafe.SizeOf<T>() == 8)
if (Unsafe.SizeOf<T>() == 8)
{ {
Vector256<T> vector_v256 = vector.AsVector256Unsafe(); Vector256<T> vector_v256 = vector.AsVector256Unsafe();
Vector256<T> scalar_v256 = Vector256.Create(scalar); Vector256<T> scalar_v256 = Vector256.Create(scalar);
@@ -192,27 +210,35 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator *(T scalar, Vec3<T> vector) public static Vec3<T> operator *(
T scalar,
Vec3<T> vector
)
{ {
return vector * scalar; return vector * scalar;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T operator *(Vec3<T> left, Vec3<T> right) public static T operator *(
Vec3<T> left,
Vec3<T> right
)
{ {
return left.Dot(right); return left.Dot(right);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator /(Vec3<T> vector, T scalar) public static Vec3<T> operator /(
Vec3<T> vector,
T scalar
)
{ {
if (Unsafe.SizeOf<T>() == 4) if (Unsafe.SizeOf<T>() == 4)
{ {
Vector128<T> vector_v128 = vector.AsVector128Unsafe(); Vector128<T> vector_v128 = vector.AsVector128Unsafe();
Vector128<T> scalar_v128 = Vector128.Create(scalar); Vector128<T> scalar_v128 = Vector128.Create(scalar);
return Vec3.FromVector128Unsafe(vector_v128 / scalar_v128); return Vec3.FromVector128Unsafe(vector_v128 / scalar_v128);
} } else if (Unsafe.SizeOf<T>() == 8)
if (Unsafe.SizeOf<T>() == 8)
{ {
Vector256<T> vector_v256 = vector.AsVector256Unsafe(); Vector256<T> vector_v256 = vector.AsVector256Unsafe();
Vector256<T> scalar_v256 = Vector256.Create(scalar); Vector256<T> scalar_v256 = Vector256.Create(scalar);
@@ -222,15 +248,17 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec3<T> operator +(Vec3<T> left, Vec3<T> right) public static Vec3<T> operator +(
Vec3<T> left,
Vec3<T> right
)
{ {
if (Unsafe.SizeOf<T>() == 4) if (Unsafe.SizeOf<T>() == 4)
{ {
Vector128<T> left_v128 = left.AsVector128Unsafe(); Vector128<T> left_v128 = left.AsVector128Unsafe();
Vector128<T> right_v128 = right.AsVector128Unsafe(); Vector128<T> right_v128 = right.AsVector128Unsafe();
return Vec3.FromVector128Unsafe(left_v128 + right_v128); return Vec3.FromVector128Unsafe(left_v128 + right_v128);
} } else if (Unsafe.SizeOf<T>() == 8)
if (Unsafe.SizeOf<T>() == 8)
{ {
Vector256<T> left_v256 = left.AsVector256Unsafe(); Vector256<T> left_v256 = left.AsVector256Unsafe();
Vector256<T> right_v256 = right.AsVector256Unsafe(); Vector256<T> right_v256 = right.AsVector256Unsafe();
@@ -240,13 +268,18 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vec3<T> left, Vec3<T> right) public static bool operator ==(
Vec3<T> left,
Vec3<T> right
)
{ {
return left.Equals(right); return left.Equals(right);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Vec3<T>((T X, T Y, T Z) tuple) public static implicit operator Vec3<T>(
(T X, T Y, T Z) tuple
)
{ {
return new(tuple.X, tuple.Y, tuple.Z); return new(tuple.X, tuple.Y, tuple.Z);
} }
@@ -256,5 +289,13 @@ namespace Nitload.Mathematics.Numeric.Graphics
return GetEnumerator(); return GetEnumerator();
} }
[InlineArray(3)]
private struct Buffer
{
internal T _element;
}
} }
} }
@@ -7,6 +7,7 @@
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
namespace Nitload.Mathematics.Numeric.Graphics namespace Nitload.Mathematics.Numeric.Graphics
@@ -15,7 +16,55 @@ namespace Nitload.Mathematics.Numeric.Graphics
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector128<T> AsVector128Unsafe<T>(this Vec4<T> source) where T: unmanaged, INumber<T> public static Vec4<double> ConvertToDouble(
Vec4<long> source
)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<double> ConvertToDouble(
Vec4<ulong> source
)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<float> ConvertToSingle(
Vec4<int> source
)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<float> ConvertToSingle(
Vec4<uint> source
)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Unsafe()));
}
public static Vec4<T> FromSpan<T>(
ReadOnlySpan<T> span
) where T : unmanaged, INumber<T>
{
if (span.Length < 4) {
throw new ArgumentException("Span length must be at least 4.", nameof(span));
}
Unsafe.SkipInit(out Vec4<T> result);
Span<T> target = MemoryMarshal.CreateSpan(ref Unsafe.As<Vec4<T>, T>(ref result), 4);
span[..4].CopyTo(target);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector128<T> AsVector128Unsafe<T>(
this Vec4<T> source
) where T : unmanaged, INumber<T>
{ {
Unsafe.SkipInit(out Vector128<T> result); Unsafe.SkipInit(out Vector128<T> result);
Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source); Unsafe.WriteUnaligned(ref Unsafe.As<Vector128<T>, byte>(ref result), source);
@@ -23,7 +72,9 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector256<T> AsVector256Unsafe<T>(this Vec4<T> source) where T: unmanaged, INumber<T> internal static Vector256<T> AsVector256Unsafe<T>(
this Vec4<T> source
) where T : unmanaged, INumber<T>
{ {
Unsafe.SkipInit(out Vector256<T> result); Unsafe.SkipInit(out Vector256<T> result);
Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source); Unsafe.WriteUnaligned(ref Unsafe.As<Vector256<T>, byte>(ref result), source);
@@ -31,40 +82,20 @@ namespace Nitload.Mathematics.Numeric.Graphics
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vec4<T> FromVector128Unsafe<T>(Vector128<T> source) where T: unmanaged, INumber<T> internal static Vec4<T> FromVector128Unsafe<T>(
Vector128<T> source
) where T : unmanaged, INumber<T>
{ {
return Unsafe.As<Vector128<T>, Vec4<T>>(ref source); return Unsafe.As<Vector128<T>, Vec4<T>>(ref source);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vec4<T> FromVector256Unsafe<T>(Vector256<T> source) where T: unmanaged, INumber<T> internal static Vec4<T> FromVector256Unsafe<T>(
Vector256<T> source
) where T : unmanaged, INumber<T>
{ {
return Unsafe.As<Vector256<T>, Vec4<T>>(ref source); return Unsafe.As<Vector256<T>, Vec4<T>>(ref source);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<float> ConvertToSingle(Vec4<int> source)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<float> ConvertToSingle(Vec4<uint> source)
{
return FromVector128Unsafe(Vector128.ConvertToSingle(source.AsVector128Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<double> ConvertToDouble(Vec4<long> source)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Unsafe()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<double> ConvertToDouble(Vec4<ulong> source)
{
return FromVector256Unsafe(Vector256.ConvertToDouble(source.AsVector256Unsafe()));
}
} }
} }
@@ -20,11 +20,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
public struct Vec4<T> : IUnmanagedVector<Vec4<T>> where T : unmanaged, INumber<T> public struct Vec4<T> : IUnmanagedVector<Vec4<T>> where T : unmanaged, INumber<T>
{ {
public T W; private Buffer _buffer;
public T X;
public T Y;
public T Z;
public Vec4( public Vec4(
Vec3<T> v3, Vec3<T> v3,
@@ -50,9 +46,41 @@ namespace Nitload.Mathematics.Numeric.Graphics
W = w; 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<T> XY public Vec2<T> XY
{ {
get => Unsafe.As<T, Vec2<T>>(ref X); get => Unsafe.As<T, Vec2<T>>(ref _buffer[0]);
set set
{ {
X = value.X; X = value.X;
@@ -62,11 +90,60 @@ namespace Nitload.Mathematics.Numeric.Graphics
public Vec3<T> XYZ public Vec3<T> XYZ
{ {
get => Unsafe.As<T, Vec3<T>>(ref X); get => Unsafe.As<T, Vec3<T>>(ref _buffer[0]);
set set
{ {
T w = W; T w = W;
Unsafe.As<T, Vec3<T>>(ref X) = value; Unsafe.As<T, Vec3<T>>(ref _buffer[0]) = value;
W = w;
}
}
public Vec3<T> ZXY
{
readonly get
{
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> source = this.AsVector128Unsafe();
Vector128<int> bits = Unsafe.As<Vector128<T>, Vector128<int>>(ref source);
Vector128<int> result = Vector128.Shuffle(bits, Vector128.Create(2, 0, 1, 3));
Vector128<T> shuffled = Unsafe.As<Vector128<int>, Vector128<T>>(ref result);
return Vec3.FromVector128Unsafe(shuffled);
}
if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> source = this.AsVector256Unsafe();
Vector256<long> bits = Unsafe.As<Vector256<T>, Vector256<long>>(ref source);
Vector256<long> result = Vector256.Shuffle(bits, Vector256.Create(2L, 0L, 1L,
3L));
Vector256<T> shuffled = Unsafe.As<Vector256<long>, Vector256<T>>(ref result);
return Vec3.FromVector256Unsafe(shuffled);
}
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
set
{
T w = W;
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> source = value.AsVector128Unsafe();
Vector128<int> bits = Unsafe.As<Vector128<T>, Vector128<int>>(ref source);
Vector128<int> result = Vector128.Shuffle(bits, Vector128.Create(1, 2, 0, 3));
Vector128<T> shuffled = Unsafe.As<Vector128<int>, Vector128<T>>(ref result);
Unsafe.As<T, Vec3<T>>(ref _buffer[0]) = Vec3.FromVector128Unsafe(shuffled);
} else if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> source = value.AsVector256Unsafe();
Vector256<long> bits = Unsafe.As<Vector256<T>, Vector256<long>>(ref source);
Vector256<long> result = Vector256.Shuffle(bits, Vector256.Create(1L, 2L, 0L,
3L));
Vector256<T> shuffled = Unsafe.As<Vector256<long>, Vector256<T>>(ref result);
Unsafe.As<T, Vec3<T>>(ref _buffer[0]) = Vec3.FromVector256Unsafe(shuffled);
} else
{
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
W = w; W = w;
} }
} }
@@ -86,7 +163,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
public ReadOnlySpan<T> AsSpan() public ReadOnlySpan<T> AsSpan()
{ {
return MemoryMarshal.CreateReadOnlySpan(ref X, 4); return MemoryMarshal.CreateReadOnlySpan(ref _buffer[0], 4);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -98,8 +175,7 @@ namespace Nitload.Mathematics.Numeric.Graphics
{ {
Vec4<T> product = Vec4.FromVector128Unsafe(this.AsVector128Unsafe() * right.AsVector128Unsafe()); Vec4<T> product = Vec4.FromVector128Unsafe(this.AsVector128Unsafe() * right.AsVector128Unsafe());
return product.X + product.Y + product.Z + product.W; return product.X + product.Y + product.Z + product.W;
} } else if (Unsafe.SizeOf<T>() == 8)
if (Unsafe.SizeOf<T>() == 8)
{ {
Vec4<T> product = Vec4.FromVector256Unsafe(this.AsVector256Unsafe() * right.AsVector256Unsafe()); Vec4<T> product = Vec4.FromVector256Unsafe(this.AsVector256Unsafe() * right.AsVector256Unsafe());
return product.X + product.Y + product.Z + product.W; return product.X + product.Y + product.Z + product.W;
@@ -114,20 +190,6 @@ namespace Nitload.Mathematics.Numeric.Graphics
return (obj is Vec4<T> v) && (v == this); return (obj is Vec4<T> v) && (v == this);
} }
public static Vec4<T> FromSpan(
ReadOnlySpan<T> span
)
{
if (span.Length < 4) {
throw new ArgumentException("Span length must be at least 4.", nameof(span));
}
Unsafe.SkipInit(out Vec4<T> result);
Span<T> target = MemoryMarshal.CreateSpan(ref result.X, 4);
span[..4].CopyTo(target);
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<T>.Enumerator GetEnumerator() public ReadOnlySpan<T>.Enumerator GetEnumerator()
{ {
@@ -139,16 +201,41 @@ namespace Nitload.Mathematics.Numeric.Graphics
return HashCode.Combine(X, Y, Z, W); return HashCode.Combine(X, Y, Z, W);
} }
public Vec4<T> Shuffle(
int t0,
int t1,
int t2,
int t3
)
{
if (Unsafe.SizeOf<T>() == 4)
{
Vector128<T> v = this.AsVector128Unsafe();
Vector128<int> bits = Unsafe.As<Vector128<T>, Vector128<int>>(ref v);
Vector128<int> result = Vector128.Shuffle(bits, Vector128.Create(t0, t1, t2, t3));
return Vec4.FromVector128Unsafe(Unsafe.As<Vector128<int>, Vector128<T>>(ref result));
} else if (Unsafe.SizeOf<T>() == 8)
{
Vector256<T> v = this.AsVector256Unsafe();
Vector256<long> bits = Unsafe.As<Vector256<T>, Vector256<long>>(ref v);
Vector256<long> result = Vector256.Shuffle(bits, Vector256.Create(t0, t1, t2, t3));
return Vec4.FromVector256Unsafe(Unsafe.As<Vector256<long>, Vector256<T>>(ref result));
} else
{
throw GraphicVector.ThrowUnsupportedTypeException<T>();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vec4<T> operator -( public static Vec4<T> operator -(
Vec4<T> left, Vec4<T> left,
Vec4<T> right Vec4<T> right
) )
{ {
if (Unsafe.SizeOf<T>() == 4) { if (Unsafe.SizeOf<T>() == 4)
{
return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() - right.AsVector128Unsafe()); return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() - right.AsVector128Unsafe());
} } else if (Unsafe.SizeOf<T>() == 8) {
if (Unsafe.SizeOf<T>() == 8) {
return Vec4.FromVector256Unsafe(left.AsVector256Unsafe() - right.AsVector256Unsafe()); return Vec4.FromVector256Unsafe(left.AsVector256Unsafe() - right.AsVector256Unsafe());
} }
throw GraphicVector.ThrowUnsupportedTypeException<T>(); throw GraphicVector.ThrowUnsupportedTypeException<T>();
@@ -168,10 +255,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
T scalar T scalar
) )
{ {
if (Unsafe.SizeOf<T>() == 4) { if (Unsafe.SizeOf<T>() == 4)
{
return Vec4.FromVector128Unsafe(vector.AsVector128Unsafe() * Vector128.Create(scalar)); return Vec4.FromVector128Unsafe(vector.AsVector128Unsafe() * Vector128.Create(scalar));
} } else if (Unsafe.SizeOf<T>() == 8) {
if (Unsafe.SizeOf<T>() == 8) {
return Vec4.FromVector256Unsafe(vector.AsVector256Unsafe() * Vector256.Create(scalar)); return Vec4.FromVector256Unsafe(vector.AsVector256Unsafe() * Vector256.Create(scalar));
} }
throw GraphicVector.ThrowUnsupportedTypeException<T>(); throw GraphicVector.ThrowUnsupportedTypeException<T>();
@@ -186,6 +273,14 @@ namespace Nitload.Mathematics.Numeric.Graphics
return vector * scalar; return vector * scalar;
} }
public static Vec4<T> operator *(
GMatrix44<T> mat,
Vec4<T> vec
)
{
return (mat[0] * vec.X) + (mat[1] * vec.Y) + (mat[2] * vec.Z) + (mat[3] * vec.W);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T operator *( public static T operator *(
Vec4<T> left, Vec4<T> left,
@@ -201,10 +296,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
T scalar T scalar
) )
{ {
if (Unsafe.SizeOf<T>() == 4) { if (Unsafe.SizeOf<T>() == 4)
{
return Vec4.FromVector128Unsafe(vector.AsVector128Unsafe() / Vector128.Create(scalar)); return Vec4.FromVector128Unsafe(vector.AsVector128Unsafe() / Vector128.Create(scalar));
} } else if (Unsafe.SizeOf<T>() == 8) {
if (Unsafe.SizeOf<T>() == 8) {
return Vec4.FromVector256Unsafe(vector.AsVector256Unsafe() / Vector256.Create(scalar)); return Vec4.FromVector256Unsafe(vector.AsVector256Unsafe() / Vector256.Create(scalar));
} }
throw GraphicVector.ThrowUnsupportedTypeException<T>(); throw GraphicVector.ThrowUnsupportedTypeException<T>();
@@ -216,10 +311,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
Vec4<T> right Vec4<T> right
) )
{ {
if (Unsafe.SizeOf<T>() == 4) { if (Unsafe.SizeOf<T>() == 4)
{
return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() + right.AsVector128Unsafe()); return Vec4.FromVector128Unsafe(left.AsVector128Unsafe() + right.AsVector128Unsafe());
} } else if (Unsafe.SizeOf<T>() == 8) {
if (Unsafe.SizeOf<T>() == 8) {
return Vec4.FromVector256Unsafe(left.AsVector256Unsafe() + right.AsVector256Unsafe()); return Vec4.FromVector256Unsafe(left.AsVector256Unsafe() + right.AsVector256Unsafe());
} }
throw GraphicVector.ThrowUnsupportedTypeException<T>(); throw GraphicVector.ThrowUnsupportedTypeException<T>();
@@ -230,10 +325,10 @@ namespace Nitload.Mathematics.Numeric.Graphics
Vec4<T> right Vec4<T> right
) )
{ {
if (Unsafe.SizeOf<T>() == 4) { if (Unsafe.SizeOf<T>() == 4)
{
return left.AsVector128Unsafe() == right.AsVector128Unsafe(); return left.AsVector128Unsafe() == right.AsVector128Unsafe();
} } else if (Unsafe.SizeOf<T>() == 8) {
if (Unsafe.SizeOf<T>() == 8) {
return left.AsVector256Unsafe() == right.AsVector256Unsafe(); return left.AsVector256Unsafe() == right.AsVector256Unsafe();
} }
#pragma warning disable CA1065 #pragma warning disable CA1065
@@ -241,5 +336,13 @@ namespace Nitload.Mathematics.Numeric.Graphics
#pragma warning restore CA1065 #pragma warning restore CA1065
} }
[InlineArray(4)]
private struct Buffer
{
private T _element;
}
} }
} }
@@ -0,0 +1,47 @@
// -----------------------------------------------------------------------------
// file="TextRegexSourceGen.ExitLabel"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.RegularAnalysis.Text
{
internal partial class TextRegexSourceGen
{
internal enum ExitMode
{
Break,
Continue,
Goto,
}
internal readonly record struct ExitLabel
{
public ExitLabel(
ExitMode mode,
int order
)
{
Mode = mode;
LabelOrder = order;
}
public ExitMode Mode { get; init; }
public int LabelOrder { get; init; }
}
}
}
@@ -183,6 +183,8 @@ namespace Nitload.RegularAnalysis.Text
) )
{ {
RegexAstNode current = node.Right; RegexAstNode current = node.Right;
// TODO(NGRA-NAMING): Reserve exclusive names for future ALT cursor/capture snapshots;
// their lifetime extends through retry labels, not just the candidate's emitted block.
string exit_label = context.RequestExitLabel(); string exit_label = context.RequestExitLabel();
// TODO(NGRA): Walk every normalized ALT candidate exactly once. The final traversal // TODO(NGRA): Walk every normalized ALT candidate exactly once. The final traversal
@@ -229,9 +231,10 @@ namespace Nitload.RegularAnalysis.Text
// TODO(NGRA): Advance by code.Length rather than one character and // TODO(NGRA): Advance by code.Length rather than one character and
// preserve the ALT rollback cursor on failure. // preserve the ALT rollback cursor on failure.
_ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({FormatStringLiteral(code)}))") string liteal = FormatStringLiteral(code);
_ = sc.AppendLine(@$"if({context.RemainSpan}.{MemoryExtensions.StartsWith}({liteal}))")
.AppendLine("{") .AppendLine("{")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);") .AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice({code.Length});")
.AppendLine($@"goto {exit_label};") .AppendLine($@"goto {exit_label};")
.AppendLine("}"); .AppendLine("}");
@@ -269,6 +272,9 @@ namespace Nitload.RegularAnalysis.Text
RegexGroupPayload config = node.PayloadAs<RegexGroupPayload>(); RegexGroupPayload config = node.PayloadAs<RegexGroupPayload>();
// TODO(NGRA-NAMING): Reserve exclusive names for generated group snapshots and capture
// temporaries. A capture's user-provided name is not a unique generated local name.
// TODO(NGRA): Select the owned group body using Empty-sentinel checks, snapshot its // TODO(NGRA): Select the owned group body using Empty-sentinel checks, snapshot its
// start cursor, and restore it when the child matcher fails. // start cursor, and restore it when the child matcher fails.
if (left is not null) if (left is not null)
@@ -343,7 +349,8 @@ namespace Nitload.RegularAnalysis.Text
int max, int max,
bool is_greedy, bool is_greedy,
[NotNull] in SequenceEmitter<string> sc, [NotNull] in SequenceEmitter<string> sc,
in SourceGenContext context in SourceGenContext context,
string exit_label
) )
{ {
if (min < 0 || (max >= 0 && max < min)) { if (min < 0 || (max >= 0 && max < min)) {
@@ -359,16 +366,16 @@ namespace Nitload.RegularAnalysis.Text
char expected = literal[0]; char expected = literal[0];
string expected_literal = FormatCharLiteral(expected); string expected_literal = FormatCharLiteral(expected);
string remain_span = context.RemainSpan; string remain_span = context.RemainSpan;
int scratch_scope_index = context.RentScratchScopeIndex(); // TODO(NGRA-NAMING): Allocate required_rest, required_matched, required_chunk_index,
// and additional_count through the exclusive-name pool, including loop-local names.
int scratch_scope_index = context.RequestScratchScopeIndex();
string required_rest = $"__required_rest_{scratch_scope_index}"; string required_rest = $"__required_rest_{scratch_scope_index}";
string required_matched = $"__required_matched_{scratch_scope_index}"; string required_matched = $"__required_matched_{scratch_scope_index}";
string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}"; string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}";
string additional_count = $"__additional_count_{scratch_scope_index}"; string additional_count = $"__additional_count_{scratch_scope_index}";
// TODO(NGRA): Move ownership of this work region to the enclosing CONCAT or match // TODO(NGRA): Replace this local COUNT exit with the inherited failure ExitLabel.
// method. Until then, break demonstrates the local failure path but cannot prevent a // The temporary goto preserves the former local exit but still lets siblings execute.
// later sibling node from being emitted and executed.
_ = sc.AppendLine("do").AppendLine("{");
if (min <= flattened_unit_count_threshold) if (min <= flattened_unit_count_threshold)
{ {
@@ -377,7 +384,7 @@ namespace Nitload.RegularAnalysis.Text
string required_prefix = new(expected, min); string required_prefix = new(expected, min);
_ = sc.AppendLine($"if (!{remain_span}.{nameof(MemoryExtensions.StartsWith)}({FormatStringLiteral(required_prefix)}))") _ = sc.AppendLine($"if (!{remain_span}.{nameof(MemoryExtensions.StartsWith)}({FormatStringLiteral(required_prefix)}))")
.AppendLine("{") .AppendLine("{")
.AppendLine("break;") .AppendLine($"goto {exit_label};")
.AppendLine("}") .AppendLine("}")
.AppendLine($"{remain_span} = {remain_span}.Slice({min});"); .AppendLine($"{remain_span} = {remain_span}.Slice({min});");
} }
@@ -392,7 +399,7 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine($"if ({remain_span}.Length < {min})") _ = sc.AppendLine($"if ({remain_span}.Length < {min})")
.AppendLine("{") .AppendLine("{")
.AppendLine("break;") .AppendLine($"goto {exit_label};")
.AppendLine("}") .AppendLine("}")
.AppendLine($"{ROS_char} {required_rest} = {remain_span};") .AppendLine($"{ROS_char} {required_rest} = {remain_span};")
.AppendLine($"bool {required_matched} = true;") .AppendLine($"bool {required_matched} = true;")
@@ -417,7 +424,7 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine($"if (!{required_matched})") _ = sc.AppendLine($"if (!{required_matched})")
.AppendLine("{") .AppendLine("{")
.AppendLine("break;") .AppendLine($"goto {exit_label};")
.AppendLine("}") .AppendLine("}")
.AppendLine($"{remain_span} = {remain_span}.Slice({min});"); .AppendLine($"{remain_span} = {remain_span}.Slice({min});");
} }
@@ -445,8 +452,6 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation."); _ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation.");
} }
_ = sc.AppendLine("} while (false);");
context.ReturnScratchScopeIndex(scratch_scope_index);
} }
private static void GenerateUnitSetCount( private static void GenerateUnitSetCount(
@@ -472,33 +477,52 @@ namespace Nitload.RegularAnalysis.Text
IReadOnlyList<RegexCharSet> charset = payload.Set; IReadOnlyList<RegexCharSet> charset = payload.Set;
string remain_span = context.RemainSpan; string remain_span = context.RemainSpan;
int scratch_scope_index = context.RentScratchScopeIndex(); // TODO(NGRA-NAMING): Allocate required_matched and additional_count through the
// exclusive-name pool. Reserve required_rest/required_chunk_index if emitted later.
int scratch_scope_index = context.RequestScratchScopeIndex();
string required_rest = $"__required_rest_{scratch_scope_index}"; string required_rest = $"__required_rest_{scratch_scope_index}";
string required_matched = $"__required_matched_{scratch_scope_index}"; string required_matched = $"__required_matched_{scratch_scope_index}";
string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}"; string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}";
string additional_count = $"__additional_count_{scratch_scope_index}"; string additional_count = $"__additional_count_{scratch_scope_index}";
// TODO(NGRA): Move ownership of this work region to the enclosing CONCAT or match // TODO(NGRA): Route a failed minimum check through the inherited failure ExitLabel.
// method. Until then, break demonstrates the local failure path but cannot prevent a // The break below only stops charset scanning and must remain local to that loop.
// later sibling node from being emitted and executed.
bool accept = payload.Accept; bool accept = payload.Accept;
RegexCharSet _set = charset[0]; RegexCharSet _set = charset[0];
_ = sc.AppendLine($"{ROS_char} {required_matched} = {remain_span}") _ = sc.AppendLine($"{ROS_char} {required_matched} = {remain_span}")
.AppendLine($"int {additional_count} = 0;") .AppendLine($"int {additional_count} = 0;")
.AppendLine() .AppendLine($"for(; {additional_count} < {max}; {additional_count} ++)")
.AppendLine() //TODO loop head .AppendLine("{");
.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)} ||"); if (charset.Count == 1)
{
// single charset rule
_ = sc.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)})");
} else
{
// multi charset rule
_ = sc.AppendLine($"if({(accept ? string.Empty : "!(")} {GenerateCharSetExpression(_set)} ||");
for (int i = 1; i < charset.Count - 1; i++) for (int i = 1; i < charset.Count - 1; i++)
{ {
_set = charset[i]; _set = charset[i];
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ||"); _ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ||");
} }
_set = charset[^1]; _set = charset[^1];
_ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ){(accept ? string.Empty : ')')}") _ = sc.AppendLine($" {GenerateCharSetExpression(_set)} ){(accept ? string.Empty : ')')}");
.AppendLine("{") }
_ = sc .AppendLine("{")
.AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);") .AppendLine($@"{context.RemainSpan} = {context.RemainSpan}.Slice(1);")
.AppendLine("}")
.AppendLine("else")
.AppendLine("{")
.AppendLine($@"break;") .AppendLine($@"break;")
.AppendLine("}")
.AppendLine("}")
.AppendLine($"if({additional_count} < {min})")
.AppendLine("{")
.AppendLine("}")
.AppendLine("else")
.AppendLine("{")
.AppendLine("}"); .AppendLine("}");
} }
@@ -508,7 +532,8 @@ namespace Nitload.RegularAnalysis.Text
int max, int max,
bool is_greedy, bool is_greedy,
[NotNull] in SequenceEmitter<string> sc, [NotNull] in SequenceEmitter<string> sc,
in SourceGenContext context in SourceGenContext context,
string exit_label
) )
{ {
if (min < 0 || (max >= 0 && max < min)) { if (min < 0 || (max >= 0 && max < min)) {
@@ -523,7 +548,10 @@ namespace Nitload.RegularAnalysis.Text
string expected_literal = FormatStringLiteral(literal); string expected_literal = FormatStringLiteral(literal);
string remain_span = context.RemainSpan; string remain_span = context.RemainSpan;
int scratch_scope_index = context.RentScratchScopeIndex(); // TODO(NGRA-NAMING): Allocate required_rest, required_matched, required_chunk_index,
// required_count, and additional_count through the exclusive-name pool. Flattened
// sibling COUNT nodes share the declaration space even after their exit labels.
int scratch_scope_index = context.RequestScratchScopeIndex();
string required_rest = $"__required_rest_{scratch_scope_index}"; string required_rest = $"__required_rest_{scratch_scope_index}";
string required_matched = $"__required_matched_{scratch_scope_index}"; string required_matched = $"__required_matched_{scratch_scope_index}";
string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}"; string required_chunk_index = $"__required_chunk_index_{scratch_scope_index}";
@@ -531,10 +559,8 @@ namespace Nitload.RegularAnalysis.Text
string additional_count = $"__additional_count_{scratch_scope_index}"; string additional_count = $"__additional_count_{scratch_scope_index}";
string starts_with = $"{nameof(MemoryExtensions.StartsWith)}"; string starts_with = $"{nameof(MemoryExtensions.StartsWith)}";
// TODO(NGRA): Move ownership of this work region to the enclosing CONCAT or match // TODO(NGRA): Replace this local COUNT exit with the inherited failure ExitLabel.
// method. Until then, break demonstrates the local failure path but cannot prevent a // The temporary goto preserves the former local exit but still lets siblings execute.
// later sibling node from being emitted and executed.
_ = sc.AppendLine("do").AppendLine("{");
if (literal.Length > flattened_unit_count_threshold) if (literal.Length > flattened_unit_count_threshold)
{ {
@@ -549,7 +575,7 @@ namespace Nitload.RegularAnalysis.Text
.AppendLine("}") .AppendLine("}")
.AppendLine($"if ({required_count} != {min})") .AppendLine($"if ({required_count} != {min})")
.AppendLine("{") .AppendLine("{")
.AppendLine("break;") .AppendLine($"goto {exit_label};")
.AppendLine("}") .AppendLine("}")
.AppendLine($"{remain_span} = {required_rest};"); .AppendLine($"{remain_span} = {required_rest};");
} else if (min <= flattened_unit_count_threshold / literal.Length) } else if (min <= flattened_unit_count_threshold / literal.Length)
@@ -563,7 +589,7 @@ namespace Nitload.RegularAnalysis.Text
string required_prefix = required_prefix_span.ToString(); string required_prefix = required_prefix_span.ToString();
_ = sc.AppendLine($"if (!{remain_span}.{starts_with}({FormatStringLiteral(required_prefix)}))") _ = sc.AppendLine($"if (!{remain_span}.{starts_with}({FormatStringLiteral(required_prefix)}))")
.AppendLine("{") .AppendLine("{")
.AppendLine("break;") .AppendLine($"goto {exit_label};")
.AppendLine("}") .AppendLine("}")
.AppendLine($"{remain_span} = {remain_span}.Slice({min * literal.Length});"); .AppendLine($"{remain_span} = {remain_span}.Slice({min * literal.Length});");
} }
@@ -612,7 +638,7 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine($"if (!{required_matched})") _ = sc.AppendLine($"if (!{required_matched})")
.AppendLine("{") .AppendLine("{")
.AppendLine("break;") .AppendLine($"goto {exit_label};")
.AppendLine("}") .AppendLine("}")
.AppendLine($"{remain_span} = {required_rest};"); .AppendLine($"{remain_span} = {required_rest};");
} }
@@ -640,8 +666,6 @@ namespace Nitload.RegularAnalysis.Text
_ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation."); _ = sc.AppendLine("// TODO(NGRA): Retry the lazy COUNT tail from its continuation.");
} }
_ = sc.AppendLine("} while (false);");
context.ReturnScratchScopeIndex(scratch_scope_index);
} }
private static void GenerateCount( private static void GenerateCount(
@@ -659,6 +683,8 @@ namespace Nitload.RegularAnalysis.Text
int min = payload.Min; int min = payload.Min;
int max = payload.Max; int max = payload.Max;
bool is_greedy = payload.IsGreedy; bool is_greedy = payload.IsGreedy;
// TODO(NGRA-NAMING): Reserve exclusive names for future repetition/rollback state
// across complex COUNT retries; recursive children must use the same method pool.
string exit_label = context.RequestExitLabel(); string exit_label = context.RequestExitLabel();
if ((value.Label & RegexElementLabel.SEQUENCE) == 0) if ((value.Label & RegexElementLabel.SEQUENCE) == 0)
{ {
@@ -670,15 +696,16 @@ namespace Nitload.RegularAnalysis.Text
switch (value.Label & RegexElementLabel.SEQUENCE) switch (value.Label & RegexElementLabel.SEQUENCE)
{ {
case RegexElementLabel.UNIT: case RegexElementLabel.UNIT:
GenerateUnitCount(value, min, max, is_greedy, sc, context); GenerateUnitCount(value, min, max, is_greedy, sc, context, exit_label);
break; break;
case RegexElementLabel.UNIT_SET: case RegexElementLabel.UNIT_SET:
GenerateUnitSetCount(value, min, max, is_greedy, sc, context);
// TODO(NGRA): Emit a bounded/unbounded charset counting loop, preferably // TODO(NGRA): Emit a bounded/unbounded charset counting loop, preferably
// using IndexOfAnyExcept where the charset shape permits it. // using IndexOfAnyExcept where the charset shape permits it.
break; break;
case RegexElementLabel.UNIT_SPAN: case RegexElementLabel.UNIT_SPAN:
GenerateUnitSpanCount(value, min, max, is_greedy, sc, context); GenerateUnitSpanCount(value, min, max, is_greedy, sc, context, exit_label);
break; break;
default: default:
@@ -26,8 +26,8 @@ namespace Nitload.RegularAnalysis.Text
/// <remarks> /// <remarks>
/// Method level state is limited to the active cursor and the result of the most recent /// Method level state is limited to the active cursor and the result of the most recent
/// instruction. Everything else is either a region slot, a line slot, a capture slot, or /// instruction. Everything else is either a region slot, a line slot, a capture slot, or
/// a block scoped scratch variable. Scratch indices remain unique while rented and are /// a scratch variable. Scratch indices remain unique throughout the generated method;
/// recycled after their generated lexical scope has closed. /// flattened regions cannot release their names for reuse by later nodes.
/// </remarks> /// </remarks>
internal sealed class SourceGenContext internal sealed class SourceGenContext
{ {
@@ -40,8 +40,6 @@ namespace Nitload.RegularAnalysis.Text
private int _scratch_scope_count; private int _scratch_scope_count;
private readonly Stack<int> _free_scratch_scope_indices = [];
public string RemainSpan { get; } = _remain_span; public string RemainSpan { get; } = _remain_span;
public string FirstOfRemain { get; } = $@"{_remain_span}[0]"; public string FirstOfRemain { get; } = $@"{_remain_span}[0]";
@@ -57,36 +55,22 @@ namespace Nitload.RegularAnalysis.Text
public string RequestExitLabel() public string RequestExitLabel()
{ {
// TODO(NGRA-NAMING): Route ALT and COUNT labels through the method-wide label pool.
// Keep every emitted label exclusive until method generation is complete.
string code = $@"_exit_alt_{_exit_alt_count}"; string code = $@"_exit_alt_{_exit_alt_count}";
_exit_alt_count++; _exit_alt_count++;
return code; return code;
} }
public int RentScratchScopeIndex() public int RequestScratchScopeIndex()
{ {
if (_free_scratch_scope_indices.TryPop(out int recycled_index)) { // TODO(NGRA-NAMING): Integrate scratch names with the method-wide exclusive-name
return recycled_index; // allocator. Until then, reserve each suffix permanently for this method.
}
int index = _scratch_scope_count; int index = _scratch_scope_count;
_scratch_scope_count++; _scratch_scope_count++;
return index; return index;
} }
public void ReturnScratchScopeIndex(
int index
)
{
if ((uint)index >= (uint)_scratch_scope_count) {
throw new ArgumentOutOfRangeException(nameof(index));
}
if (_free_scratch_scope_indices.Contains(index)) {
throw new InvalidOperationException($"Scratch scope {index} was returned twice.");
}
_free_scratch_scope_indices.Push(index);
}
} }
} }
@@ -60,7 +60,7 @@ namespace Nitload.RegularAnalysis.Text
string static_modifier; string static_modifier;
int brace_count = 0; int brace_count = 0;
do while (type is not null)
{ {
_ = file_name_sb.Append(CultureInfo.InvariantCulture, $@"{type.TypeName}."); _ = file_name_sb.Append(CultureInfo.InvariantCulture, $@"{type.TypeName}.");
string declare_type = type.DeclType switch string declare_type = type.DeclType switch
@@ -74,7 +74,7 @@ namespace Nitload.RegularAnalysis.Text
.AppendLine("{"); .AppendLine("{");
brace_count++; brace_count++;
type = type.InnerType!; type = type.InnerType!;
} while (type is not null); }
static_modifier = gen_source.IsMethodStatic ? "static" : string.Empty; static_modifier = gen_source.IsMethodStatic ? "static" : string.Empty;
_ = ce.AppendLine(@$"{ToKeyword(gen_source.MethodAccessibility)} {static_modifier} {Text_Regex} {gen_source.MethodName}({ROS_char} {regex_gen_context.InputString})") _ = ce.AppendLine(@$"{ToKeyword(gen_source.MethodAccessibility)} {static_modifier} {Text_Regex} {gen_source.MethodName}({ROS_char} {regex_gen_context.InputString})")
@@ -90,8 +90,7 @@ namespace Nitload.RegularAnalysis.Text
brace_count = 0; brace_count = 0;
foreach (string line in ce) foreach (string line in ce)
{ {
bool is_right_brace = (line == "}") || bool is_right_brace = line == "}";
line.StartsWith("} while", StringComparison.InvariantCulture);
brace_count -= is_right_brace ? 1 : 0; brace_count -= is_right_brace ? 1 : 0;
for (int i = 0; i < brace_count; i++) { for (int i = 0; i < brace_count; i++) {
_ = code_source.Append(" "); _ = code_source.Append(" ");
@@ -232,13 +232,13 @@ namespace StgSharp.GenerateGL.Generation
List<ManagedParameterDefinition> singleParameters = new List<ManagedParameterDefinition>(prefix) List<ManagedParameterDefinition> singleParameters = new List<ManagedParameterDefinition>(prefix)
{ {
new ManagedParameterDefinition("bool", "transpose", transposeSource), new ManagedParameterDefinition("bool", "transpose", transposeSource),
new ManagedParameterDefinition("GraphicsMatrix", "value", valueSource), new ManagedParameterDefinition("GMatrix44<float>", "value", valueSource),
}; };
List<ManagedParameterDefinition> spanParameters = new List<ManagedParameterDefinition>(prefix) List<ManagedParameterDefinition> spanParameters = new List<ManagedParameterDefinition>(prefix)
{ {
new ManagedParameterDefinition("bool", "transpose", transposeSource), new ManagedParameterDefinition("bool", "transpose", transposeSource),
new ManagedParameterDefinition( new ManagedParameterDefinition(
"ReadOnlySpan<GraphicsMatrix>", "ReadOnlySpan<GMatrix44<float>>",
"values", "values",
valueSource), valueSource),
}; };
@@ -740,7 +740,7 @@ namespace StgSharp.GenerateGL.Generation
string matrixName = EscapeIdentifier(matrix.Name); string matrixName = EscapeIdentifier(matrix.Name);
if (invocation.IsSpan) if (invocation.IsSpan)
{ {
builder.Append(" fixed (GraphicsMatrix* __value = "); builder.Append(" fixed (GMatrix44<float>* __value = ");
builder.Append(matrixName); builder.Append(matrixName);
builder.Append(")\n"); builder.Append(")\n");
builder.Append(" {\n"); builder.Append(" {\n");
+1 -1
View File
@@ -92,7 +92,7 @@ The generator merges a family only when it can validate the resulting signatures
| `glUniform1*v` | `Uniform(..., ReadOnlySpan<T>)` | | `glUniform1*v` | `Uniform(..., ReadOnlySpan<T>)` |
| `glUniform4*v` | `Uniform(..., ReadOnlySpan<Vec4<T>>)` | | `glUniform4*v` | `Uniform(..., ReadOnlySpan<Vec4<T>>)` |
| `glUniform2*v` and `glUniform3*v` | Omitted because `Vec2` and `Vec3` storage is not a tightly packed C array | | `glUniform2*v` and `glUniform3*v` | Omitted because `Vec2` and `Vec3` storage is not a tightly packed C array |
| `glUniformMatrix4fv` | `Uniform(..., GraphicsMatrix)` and matrix-span overloads | | `glUniformMatrix4fv` | `Uniform(..., GMatrix44<float>)` and matrix-span overloads |
| Other matrix sizes and double matrices | Omitted because only the graphics-oriented 4x4 float layout is defined | | Other matrix sizes and double matrices | Omitted because only the graphics-oriented 4x4 float layout is defined |
| `glGetBooleanv`, `glGetFloatv`, `glGetIntegerv`, and related queries | `GetValue(..., Span<T>)` | | `glGetBooleanv`, `glGetFloatv`, `glGetIntegerv`, and related queries | `GetValue(..., Span<T>)` |
| `glVertexAttrib1f/2f/3f/4f` and equivalent scalar forms | `VertexAttribute(...)`; component count is expressed by the parameter list | | `glVertexAttrib1f/2f/3f/4f` and equivalent scalar forms | `VertexAttribute(...)`; component count is expressed by the parameter list |