mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
ScriptCore: matrix generator
This commit is contained in:
@@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that fields for the components of a matrix should be generated as well as basic methods like constructors, type casts and equality checks.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Struct)]
|
||||||
|
public sealed class MatrixAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Type of the matrices components.
|
||||||
|
/// </summary>
|
||||||
|
public Type Type { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// The number of rows the matrix has.
|
||||||
|
/// </summary>
|
||||||
|
public int Rows { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// The number of columns the matrix has.
|
||||||
|
/// </summary>
|
||||||
|
public int Columns { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// The base name of the matrix. (Name of matrix without the row and column count)
|
||||||
|
/// </summary>
|
||||||
|
public string BaseName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="MatrixAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"><inheritdoc cref="Type"/></param>
|
||||||
|
/// <param name="rows"><inheritdoc cref="Rows"/></param>
|
||||||
|
/// <param name="columns"><inheritdoc cref="Columns"/></param>
|
||||||
|
/// <param name="baseName"><inheritdoc cref="BaseName"/></param>
|
||||||
|
public MatrixAttribute(Type type, int rows, int columns, string baseName)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Rows = rows;
|
||||||
|
Columns = columns;
|
||||||
|
BaseName = baseName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the matrix type should have comparison operators (>, <, >= and <=) generated for it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Struct)]
|
||||||
|
public sealed class ComparableMatrixAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the matrix type should have component wise math operators (+, -) generated for it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Struct)]
|
||||||
|
public class MatrixMathAttribute : Attribute { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the matrix type should have component wise logic operators (&, ^ and |) generated for it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Struct)]
|
||||||
|
public class MatrixLogicAttribute : Attribute { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a multiplication overload for matrix type with the specified vector type.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = true)]
|
||||||
|
public class MatrixVectorMultiplicationAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of the vector that will be multiplied with the matrix.
|
||||||
|
/// </summary>
|
||||||
|
public Type VectorType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="MatrixVectorMultiplicationAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vectorType"><inheritdoc cref="VectorType"/></param>
|
||||||
|
public MatrixVectorMultiplicationAttribute(Type vectorType)
|
||||||
|
{
|
||||||
|
VectorType = vectorType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a cast cast from the matrix type to the specified target type.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = true)]
|
||||||
|
public class MatrixCastAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The type of the target matrix type.
|
||||||
|
/// </summary>
|
||||||
|
public Type TargetType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If <see cref="true"/> the cast will be explicit; if <see cref="false"/> it will an implicit cast.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsExplicit { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="MatrixCastAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetType"><inheritdoc cref="TargetType"/></param>
|
||||||
|
/// <param name="isExplicit"><inheritdoc cref="IsExplicit"/></param>
|
||||||
|
public MatrixCastAttribute(Type targetType, bool isExplicit)
|
||||||
|
{
|
||||||
|
TargetType = targetType;
|
||||||
|
IsExplicit = isExplicit;
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
-4
@@ -9,7 +9,7 @@ namespace GlitchyEngine.Math;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides constants and methods for trigonometric and vector calculations.
|
/// Provides constants and methods for trigonometric and vector calculations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class Math
|
public static partial class Math
|
||||||
{
|
{
|
||||||
/// An optimal representation of π.
|
/// An optimal representation of π.
|
||||||
public const float Pi = 3.141592654f;
|
public const float Pi = 3.141592654f;
|
||||||
@@ -35,6 +35,7 @@ public static class Math
|
|||||||
/// Converts radians to degrees
|
/// Converts radians to degrees
|
||||||
public const float DegToRad = Pi / 180.0f;
|
public const float DegToRad = Pi / 180.0f;
|
||||||
|
|
||||||
|
#region any / all
|
||||||
|
|
||||||
/// Returns true if at least one of the components is true.
|
/// Returns true if at least one of the components is true.
|
||||||
public static bool any(bool value) => value;
|
public static bool any(bool value) => value;
|
||||||
@@ -48,18 +49,58 @@ public static class Math
|
|||||||
/// Returns true if at least one of the components is true.
|
/// Returns true if at least one of the components is true.
|
||||||
public static bool any(bool4 value) => value.X || value.Y || value.Z || value.W;
|
public static bool any(bool4 value) => value.X || value.Y || value.Z || value.W;
|
||||||
|
|
||||||
|
/// Returns true if at least one of the components is true.
|
||||||
|
public static bool any(bool2x2 value) => value.M11 || value.M12 || value.M21 || value.M22;
|
||||||
|
|
||||||
|
/// Returns true if at least one of the components is true.
|
||||||
|
public static bool any(bool3x3 value) => value.M11 || value.M12 || value.M13 ||
|
||||||
|
value.M21 || value.M22 || value.M23 ||
|
||||||
|
value.M31 || value.M32 || value.M33;
|
||||||
|
|
||||||
|
/// Returns true if at least one of the components is true.
|
||||||
|
public static bool any(bool4x4 value) => value.M11 || value.M12 || value.M13 || value.M14 ||
|
||||||
|
value.M21 || value.M22 || value.M23 || value.M24 ||
|
||||||
|
value.M31 || value.M32 || value.M33 || value.M34 ||
|
||||||
|
value.M41 || value.M42 || value.M43 || value.M44;
|
||||||
|
|
||||||
/// Returns true if all of the components are true.
|
/// Returns true if all of the components are true.
|
||||||
public static bool all(bool value) => value;
|
public static bool all(bool value) => value;
|
||||||
|
|
||||||
/// Returns true if all of the components are true.
|
/// Returns true if all of the components are true.
|
||||||
public static bool all(bool2 value) => value.X && value.Y;
|
public static bool all(bool2 value) => value is { X: true, Y: true };
|
||||||
|
|
||||||
/// Returns true if all of the components are true.
|
/// Returns true if all of the components are true.
|
||||||
public static bool all(bool3 value) => value.X && value.Y && value.Z;
|
public static bool all(bool3 value) => value is { X: true, Y: true, Z: true };
|
||||||
|
|
||||||
/// Returns true if all of the components are true.
|
/// Returns true if all of the components are true.
|
||||||
public static bool all(bool4 value) => value.X && value.Y && value.Z && value.W;
|
public static bool all(bool4 value) => value is { X: true, Y: true, Z: true, W: true };
|
||||||
|
|
||||||
|
/// Returns true if all of the components are true.
|
||||||
|
public static bool all(bool2x2 value) => value is
|
||||||
|
{
|
||||||
|
M11: true, M12: true,
|
||||||
|
M21: true, M22: true
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns true if all of the components are true.
|
||||||
|
public static bool all(bool3x3 value) => value is
|
||||||
|
{
|
||||||
|
M11: true, M12: true, M13: true,
|
||||||
|
M21: true, M22: true, M23: true,
|
||||||
|
M31: true, M32: true, M33: true
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns true if all of the components are true.
|
||||||
|
public static bool all(bool4x4 value) => value is
|
||||||
|
{
|
||||||
|
M11: true, M12: true, M13: true, M14: true,
|
||||||
|
M21: true, M22: true, M23: true, M24: true,
|
||||||
|
M31: true, M32: true, M33: true, M34: true,
|
||||||
|
M41: true, M42: true, M43: true, M44: true
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region abs
|
#region abs
|
||||||
|
|
||||||
public static float abs(float value)
|
public static float abs(float value)
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 2 rows and 2 columns of boolean values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(bool), 2, 2, "bool")]
|
||||||
|
[MatrixLogic]
|
||||||
|
public partial struct bool2x2
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 3 rows and 3 columns of boolean values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(bool), 3, 3, "bool")]
|
||||||
|
[MatrixLogic]
|
||||||
|
public partial struct bool3x3
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 4 rows and 4 columns of boolean values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(bool), 4, 4, "bool")]
|
||||||
|
[MatrixLogic]
|
||||||
|
public partial struct bool4x4
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 2 rows and 2 columns of double-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(double), 2, 2, "double")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixVectorMultiplication(typeof(double2))]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
public partial struct double2x2
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 2x2 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double2x2 Zero = new(0.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 2x2 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double2x2 One = new(1.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 2x2 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double2x2 Identity = new(
|
||||||
|
1.0, 0.0,
|
||||||
|
0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 3 rows and 3 columns of double-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(double), 3, 3, "double")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixVectorMultiplication(typeof(double3))]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
public partial struct double3x3
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 3x3 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double3x3 Zero = new(0.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 3x3 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double3x3 One = new(1.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 3x3 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double3x3 Identity = new(
|
||||||
|
1.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 4 rows and 4 columns of double-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(double), 4, 4, "double")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixVectorMultiplication(typeof(double4))]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
public partial struct double4x4
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 4x4 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double4x4 Zero = new(0.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 4x4 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double4x4 One = new(1.0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 4x4 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly double4x4 Identity = new(
|
||||||
|
1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 2 rows and 2 columns of single-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The matrix is stored in a column-major order.
|
||||||
|
/// The positions of the elements is the following:
|
||||||
|
/// <table>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>M11</td> <td>M12</td>
|
||||||
|
/// </tr>
|
||||||
|
/// <tr>
|
||||||
|
/// <td>M21</td> <td>M22</td>
|
||||||
|
/// </tr>
|
||||||
|
/// </table>
|
||||||
|
/// The memory order is M11, M21, M12, M22.
|
||||||
|
/// </remarks>
|
||||||
|
[Matrix(typeof(float), 2, 2, "float")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixVectorMultiplication(typeof(float2))]
|
||||||
|
[MatrixCast(typeof(double), true)]
|
||||||
|
[MatrixCast(typeof(Half), true)]
|
||||||
|
[MatrixCast(typeof(int), true)]
|
||||||
|
[MatrixCast(typeof(uint), true)]
|
||||||
|
public partial struct float2x2
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 2x2 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float2x2 Zero = new(0.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 2x2 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float2x2 One = new(1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 2x2 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float2x2 Identity = new(
|
||||||
|
1.0f, 0.0f,
|
||||||
|
0.0f, 1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new 2x2 matrix that represents a rotation by a specified angle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="angle">The angle of rotation.</param>
|
||||||
|
/// <returns>The matrix representing the rotation.</returns>
|
||||||
|
public static float2x2 Rotation(float angle)
|
||||||
|
{
|
||||||
|
float cos = Math.cos(angle);
|
||||||
|
float sin = Math.sin(angle);
|
||||||
|
|
||||||
|
return new float2x2(cos, -sin, sin, cos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 3 rows and 3 columns of single-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(float), 3, 3, "float")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixVectorMultiplication(typeof(float3))]
|
||||||
|
[MatrixCast(typeof(double), true)]
|
||||||
|
[MatrixCast(typeof(Half), true)]
|
||||||
|
[MatrixCast(typeof(int), true)]
|
||||||
|
[MatrixCast(typeof(uint), true)]
|
||||||
|
public partial struct float3x3
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 3x3 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float3x3 Zero = new(0.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 3x3 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float3x3 One = new(1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 3x3 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float3x3 Identity = new(
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 4 rows and 4 columns of single-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(float), 4, 4, "float")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixVectorMultiplication(typeof(float4))]
|
||||||
|
[MatrixCast(typeof(double), true)]
|
||||||
|
[MatrixCast(typeof(Half), true)]
|
||||||
|
[MatrixCast(typeof(int), true)]
|
||||||
|
[MatrixCast(typeof(uint), true)]
|
||||||
|
public partial struct float4x4
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 4x4 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float4x4 Zero = new(0.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 4x4 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float4x4 One = new(1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 4x4 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly float4x4 Identity = new(
|
||||||
|
1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 2 rows and 2 columns of half-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(Half), 2, 2, "half")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
public partial struct half2x2
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 2x2 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half2x2 Zero = new((Half)0.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 2x2 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half2x2 One = new((Half)1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 2x2 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half2x2 Identity = new(
|
||||||
|
(Half)1.0f, (Half)0.0f,
|
||||||
|
(Half)0.0f, (Half)1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 3 rows and 3 columns of half-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(Half), 3, 3, "half")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
public partial struct half3x3
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 3x3 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half3x3 Zero = new((Half)0.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 3x3 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half3x3 One = new((Half)1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 3x3 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half3x3 Identity = new(
|
||||||
|
(Half)1.0f, (Half)0.0f, (Half)0.0f,
|
||||||
|
(Half)0.0f, (Half)1.0f, (Half)0.0f,
|
||||||
|
(Half)0.0f, (Half)0.0f, (Half)1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 4 rows and 4 columns of half-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(Half), 4, 4, "half")]
|
||||||
|
[ComparableMatrix]
|
||||||
|
[MatrixMath]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
public partial struct half4x4
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A 4x4 matrix whose elements are all equal to zero.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half4x4 Zero = new((Half)0.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 4x4 matrix whose elements are all equal to one.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half4x4 One = new((Half)1.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The identity 4x4 matrix.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly half4x4 Identity = new(
|
||||||
|
(Half)1.0f, (Half)0.0f, (Half)0.0f, (Half)0.0f,
|
||||||
|
(Half)0.0f, (Half)1.0f, (Half)0.0f, (Half)0.0f,
|
||||||
|
(Half)0.0f, (Half)0.0f, (Half)1.0f, (Half)0.0f,
|
||||||
|
(Half)0.0f, (Half)0.0f, (Half)0.0f, (Half)1.0f);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 2 rows and 2 columns of 32-bit signed integer values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(int), 2, 2, "int")]
|
||||||
|
[MatrixLogic]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
[MatrixCast(typeof(uint), true)]
|
||||||
|
public partial struct int2x2
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 3 rows and 3 columns of 32-bit signed integer values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(int), 3, 3, "int")]
|
||||||
|
[MatrixLogic]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
[MatrixCast(typeof(uint), true)]
|
||||||
|
public partial struct int3x3
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 4 rows and 4 columns of 32-bit signed integer values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(int), 4, 4, "int")]
|
||||||
|
[MatrixLogic]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
[MatrixCast(typeof(uint), true)]
|
||||||
|
public partial struct int4x4
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using GlitchyEngine.Math.Attributes;
|
||||||
|
|
||||||
|
namespace GlitchyEngine.Math;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 2 rows and 2 columns of 32-bit unsigned integer values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(uint), 2, 2, "uint")]
|
||||||
|
[MatrixLogic]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
[MatrixCast(typeof(int), true)]
|
||||||
|
public partial struct uint2x2
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 3 rows and 3 columns of 32-bit unsigned integer values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(uint), 3, 3, "uint")]
|
||||||
|
[MatrixLogic]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
[MatrixCast(typeof(int), true)]
|
||||||
|
public partial struct uint3x3
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A matrix with 4 rows and 4 columns of 32-bit unsigned integer values.
|
||||||
|
/// </summary>
|
||||||
|
[Matrix(typeof(uint), 4, 4, "uint")]
|
||||||
|
[MatrixLogic]
|
||||||
|
[MatrixCast(typeof(float), true)]
|
||||||
|
[MatrixCast(typeof(int), true)]
|
||||||
|
public partial struct uint4x4
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,921 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
|
||||||
|
namespace ScriptCoreGenerator;
|
||||||
|
|
||||||
|
[Generator]
|
||||||
|
public class MatrixGenerator : ISourceGenerator
|
||||||
|
{
|
||||||
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
|
{
|
||||||
|
context.RegisterForSyntaxNotifications(() => new MatrixSyntaxReceiver());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(GeneratorExecutionContext context)
|
||||||
|
{
|
||||||
|
var receiver = (MatrixSyntaxReceiver?)context.SyntaxReceiver;
|
||||||
|
|
||||||
|
if (receiver == null) return;
|
||||||
|
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
|
foreach (var matrix in receiver.Matrices)
|
||||||
|
{
|
||||||
|
builder.Clear();
|
||||||
|
|
||||||
|
// Copy all usings from the original file
|
||||||
|
builder.AppendLine(matrix.Struct.GetParent<CompilationUnitSyntax>().Usings.ToFullString());
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
|
// For "DebuggerBrowsable" and "DebuggerBrowsableState"
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace {{matrix.Struct.GetNamespace()}};
|
||||||
|
|
||||||
|
public partial struct {{matrix.Name}}
|
||||||
|
{
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
GenerateFields(matrix, builder);
|
||||||
|
GenerateConstructors(matrix, builder);
|
||||||
|
|
||||||
|
GenerateCasts(matrix, builder);
|
||||||
|
|
||||||
|
GenerateArrayAccess(matrix, builder);
|
||||||
|
|
||||||
|
GenerateEqualityOperators(matrix, builder);
|
||||||
|
|
||||||
|
GenerateEqualsMethod(matrix, builder);
|
||||||
|
|
||||||
|
GenerateGetHashCode(matrix, builder);
|
||||||
|
|
||||||
|
if (receiver.ComparableReceiver.Matrices.Contains(matrix.Name))
|
||||||
|
{
|
||||||
|
GenerateComparisonOperators(matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receiver.MathReceiver.Matrices.Contains(matrix.Name))
|
||||||
|
{
|
||||||
|
GenerateMathOperators(matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receiver.LogicReceiver.Matrices.Contains(matrix.Name))
|
||||||
|
{
|
||||||
|
GenerateLogicOperators(matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateCastOperators(receiver.Matrices, matrix, matrix.ElementTypeName, builder, context);
|
||||||
|
|
||||||
|
foreach (var cast in receiver.CastReceiver.Casts.Where(c => c.SourceTypeName == matrix.Name))
|
||||||
|
{
|
||||||
|
GenerateCastOperators(receiver.Matrices, matrix, cast.TargetElementTypeName, builder, context);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var vectorMultiplication in receiver.VectorMultiplicationReceiver.Multiplications.Where(c => c.MatrixType == matrix.Name))
|
||||||
|
{
|
||||||
|
VectorSyntaxReceiver.VectorDefinition vectorDefinition = receiver.VectorReceiver.Vectors.First(v => v.Name == vectorMultiplication.VectorType);
|
||||||
|
|
||||||
|
if (vectorDefinition.ComponentCount != matrix.Rows && vectorDefinition.ComponentCount != matrix.Columns)
|
||||||
|
{
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor(
|
||||||
|
"SG0002",
|
||||||
|
"Vector dimensions don't match matrix dimensions.",
|
||||||
|
$"Cannot generate vector-matrix multiplication for \"{vectorDefinition.Name}\" to \"{matrix.Name}\" because the dimensions don't match. The vectors component-count must match the matrices rows or columns or both.",
|
||||||
|
"Vector Generator",
|
||||||
|
DiagnosticSeverity.Error,
|
||||||
|
true), matrix.Struct.GetLocation()));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateMatrixMulVector(matrix, vectorDefinition, builder);
|
||||||
|
GenerateVectorMulMatrix(matrix, vectorDefinition, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateToString(matrix, builder);
|
||||||
|
|
||||||
|
// There are too many swizzles for 4x4 matrices, Rider is literally dying :(
|
||||||
|
//GenerateSwizzle(matrix, builder);
|
||||||
|
|
||||||
|
builder.AppendLine("}");
|
||||||
|
|
||||||
|
context.AddSource($"{matrix.Name}.g.cs", builder.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateEqualsMethod(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj is not {{matrix.Name}} other)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return {{string.Join(" && ", Enumerable.Range(0, matrix.Rows).SelectMany(i =>
|
||||||
|
Enumerable.Range(0, matrix.Columns).Select(j =>
|
||||||
|
$"M{j + 1}{i + 1} == other.M{j + 1}{i + 1}")))}};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateGetHashCode(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append("""
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
// Unchecked to allow overflow
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
int hash = 17;
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (int c = 0; c < matrix.Columns; c++)
|
||||||
|
for (int r = 0; r < matrix.Rows; r++)
|
||||||
|
{
|
||||||
|
builder.Append($"\t\t\thash = hash * 23 + M{r + 1}{c + 1}.GetHashCode();\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("""
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateEqualityOperators(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
GenerateComparisonOperator("==", matrix, builder);
|
||||||
|
GenerateComparisonOperator("!=", matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateComparisonOperator(string op, MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
public static bool{{matrix.Columns}}x{{matrix.Rows}} operator {{op}}({{matrix.Name}} left, {{matrix.Name}} right)
|
||||||
|
{
|
||||||
|
{{ComponentWiseCore(op, matrix)}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateFields(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($"\tpublic {matrix.ElementTypeName} ");
|
||||||
|
|
||||||
|
for (int i = 0; i < matrix.Rows; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < matrix.Columns; j++)
|
||||||
|
{
|
||||||
|
if (i != 0 || j != 0)
|
||||||
|
builder.Append(", ");
|
||||||
|
|
||||||
|
builder.Append($"M{j + 1}{i + 1}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(";\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateConstructors(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
GenerateSingleConstructor(matrix, builder);
|
||||||
|
GenerateSingleElementConstructor(matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateSingleConstructor(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new {{matrix.Rows}}x{{matrix.Columns}} matrix with all elements set to the specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value that all elements will be initialized with.</param>
|
||||||
|
public {{matrix.Name}}({{matrix.ElementTypeName}} value)
|
||||||
|
{
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (int i = 0; i < matrix.Rows; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < matrix.Columns; j++)
|
||||||
|
{
|
||||||
|
builder.Append($"\t\tM{j + 1}{i + 1} = value;\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("\t}\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a constructor that takes an argument for each element in the matrix.
|
||||||
|
/// </summary>
|
||||||
|
private void GenerateSingleElementConstructor(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new {{matrix.Rows}}x{{matrix.Columns}} matrix with the specified elements.
|
||||||
|
/// </summary>
|
||||||
|
public {{matrix.Name}}({{string.Join(", ",
|
||||||
|
Enumerable.Range(0, matrix.Rows).SelectMany(i =>
|
||||||
|
Enumerable.Range(0, matrix.Columns).Select(j =>
|
||||||
|
$"{matrix.ElementTypeName} m{j + 1}{i + 1}")))
|
||||||
|
}})
|
||||||
|
{
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (int i = 0; i < matrix.Rows; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < matrix.Columns; j++)
|
||||||
|
{
|
||||||
|
builder.Append($"\t\tM{j + 1}{i + 1} = m{j + 1}{i + 1};\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("\t}\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateCasts(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
public static implicit operator {{matrix.Name}}({{matrix.ElementTypeName}} value)
|
||||||
|
{
|
||||||
|
return new {{matrix.Name}}(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
// TODO: Casts to other matrix sizes?
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateArrayAccess(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
Generate1DArrayAccess(matrix, builder);
|
||||||
|
Generate2DArrayAccess(matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Generate1DArrayAccess(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
StringBuilder getterSwitch = new();
|
||||||
|
StringBuilder setterSwitch = new();
|
||||||
|
|
||||||
|
for (int i = 0; i < matrix.Rows; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < matrix.Columns; j++)
|
||||||
|
{
|
||||||
|
getterSwitch.Append($$"""
|
||||||
|
|
||||||
|
case {{i * matrix.Columns + j}}:
|
||||||
|
return M{{j + 1}}{{i + 1}};
|
||||||
|
""");
|
||||||
|
|
||||||
|
setterSwitch.Append($$"""
|
||||||
|
|
||||||
|
case {{i * matrix.Columns + j}}:
|
||||||
|
M{{j + 1}}{{i + 1}} = value;
|
||||||
|
break;
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value at the specified index, indexed in a column-major order.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index of the element to get or set.</param>
|
||||||
|
/// <exception cref="IndexOutOfRangeException">Thrown when the index is out of range.</exception>
|
||||||
|
public {{matrix.ElementTypeName}} this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{{{getterSwitch}}
|
||||||
|
default:
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{{{setterSwitch}}
|
||||||
|
default:
|
||||||
|
throw new IndexOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Generate2DArrayAccess(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value at the specified row and column.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="row">The row of the element to get or set.</param>
|
||||||
|
/// <param name="column">The column of the element to get or set.</param>
|
||||||
|
/// <exception cref="IndexOutOfRangeException">Thrown when the index is out of range.</exception>
|
||||||
|
public {{matrix.ElementTypeName}} this[int row, int column]
|
||||||
|
{
|
||||||
|
get => this[row * {{matrix.Columns}} + column];
|
||||||
|
|
||||||
|
set => this[row * {{matrix.Columns}} + column] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateComparisonOperators(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
GenerateComparisonOperator(">", matrix, builder);
|
||||||
|
GenerateComparisonOperator("<", matrix, builder);
|
||||||
|
GenerateComparisonOperator(">=", matrix, builder);
|
||||||
|
GenerateComparisonOperator("<=", matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateMathOperators(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
GenerateUnaryOperatorOverload("+", matrix, builder);
|
||||||
|
GenerateUnaryOperatorOverload("-", matrix, builder);
|
||||||
|
|
||||||
|
GenerateComponentWiseOperator("+", matrix, builder);
|
||||||
|
GenerateComponentWiseOperator("-", matrix, builder);
|
||||||
|
|
||||||
|
GenerateMatrixMultiplications(matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateUnaryOperatorOverload(string op, MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
string args = string.Join(",\n", Enumerable.Range(0, matrix.Rows).SelectMany(i =>
|
||||||
|
Enumerable.Range(0, matrix.Columns).Select(j =>
|
||||||
|
$"\t\t\t{op}value.M{j + 1}{i + 1}")));
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
public static {{matrix.Name}} operator {{op}}({{matrix.Name}} value)
|
||||||
|
{
|
||||||
|
return new(
|
||||||
|
{{args}});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateComponentWiseOperator(string op, MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
string arguments = string.Join(",\n", Enumerable.Range(0, matrix.Rows).SelectMany(i =>
|
||||||
|
Enumerable.Range(0, matrix.Columns).Select(j =>
|
||||||
|
$"\t\t\tleft.M{j + 1}{i + 1} {op} right.M{j + 1}{i + 1}")));
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
public static {{matrix.Name}} operator {{op}}({{matrix.Name}} left, {{matrix.Name}} right)
|
||||||
|
{
|
||||||
|
{{ComponentWiseCore(op, matrix)}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ComponentWiseCore(string op, MatrixDefinition matrix)
|
||||||
|
{
|
||||||
|
string arguments = string.Join(",\n", Enumerable.Range(0, matrix.Rows).SelectMany(i =>
|
||||||
|
Enumerable.Range(0, matrix.Columns).Select(j =>
|
||||||
|
$"\t\t\tleft.M{j + 1}{i + 1} {op} right.M{j + 1}{i + 1}")));
|
||||||
|
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
return new(
|
||||||
|
{{arguments}});
|
||||||
|
""");
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateLogicOperators(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
GenerateComponentWiseOperator("&", matrix, builder);
|
||||||
|
GenerateComponentWiseOperator("^", matrix, builder);
|
||||||
|
GenerateComponentWiseOperator("|", matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateCastOperators(List<MatrixDefinition> matrices, MatrixDefinition sourceMatrix, string targetElementTypeName, StringBuilder builder, GeneratorExecutionContext context)
|
||||||
|
{
|
||||||
|
IEnumerable<MatrixDefinition> targetMatrices =
|
||||||
|
matrices.Where(target => target.ElementTypeName == targetElementTypeName &&
|
||||||
|
target.Columns <= sourceMatrix.Columns && target.Rows <= sourceMatrix.Rows &&
|
||||||
|
(target.Columns < sourceMatrix.Columns || target.Rows < sourceMatrix.Rows));
|
||||||
|
|
||||||
|
foreach (var targetMatrixDefinition in targetMatrices)
|
||||||
|
{
|
||||||
|
MatrixCastSyntaxReceiver.Cast cast = new MatrixCastSyntaxReceiver.Cast(sourceMatrix.Name, targetMatrixDefinition.Name, true);
|
||||||
|
|
||||||
|
GenerateCastOperator(cast, sourceMatrix, targetMatrixDefinition, builder, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateCastOperator(MatrixCastSyntaxReceiver.Cast cast, MatrixDefinition sourceMatrix, MatrixDefinition targetMatrix, StringBuilder builder, GeneratorExecutionContext context)
|
||||||
|
{
|
||||||
|
if (sourceMatrix.Columns < targetMatrix.Columns || sourceMatrix.Rows < targetMatrix.Rows)
|
||||||
|
{
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor(
|
||||||
|
"SG0001",
|
||||||
|
"Matrix-Dimensions don't match for cast.",
|
||||||
|
$"Cannot cast from \"{sourceMatrix.Name}\" to \"{targetMatrix.Name}\" because the source matrix is smaller than the target matrix.",
|
||||||
|
"Matrix Generator",
|
||||||
|
DiagnosticSeverity.Error,
|
||||||
|
true), sourceMatrix.Struct.GetLocation()));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
public static {{(cast.IsExplicit ? "explicit" : "implicit")}} operator {{targetMatrix.Name}}({{sourceMatrix.Name}} value)
|
||||||
|
{
|
||||||
|
{{targetMatrix.Name}} result = new();
|
||||||
|
{{string.Join("\n", Enumerable.Range(0, targetMatrix.Rows).SelectMany(i =>
|
||||||
|
Enumerable.Range(0, targetMatrix.Columns).Select(j =>
|
||||||
|
$"\t\tresult.M{j + 1}{i + 1} = ({targetMatrix.ElementTypeName})value.M{j + 1}{i + 1};")))}}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateMatrixMultiplications(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
public static {{matrix.Name}} operator *({{matrix.ElementTypeName}} left, {{matrix.Name}} right)
|
||||||
|
{
|
||||||
|
return new(
|
||||||
|
{{string.Join(",\n", Enumerable.Range(0, matrix.Rows).SelectMany(i =>
|
||||||
|
Enumerable.Range(0, matrix.Columns).Select(j =>
|
||||||
|
$"\t\t\tleft * right.M{j + 1}{i + 1}")))}}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static {{matrix.Name}} operator *({{matrix.Name}} left, {{matrix.ElementTypeName}} right)
|
||||||
|
{
|
||||||
|
return new(
|
||||||
|
{{string.Join(",\n", Enumerable.Range(0, matrix.Rows).SelectMany(i =>
|
||||||
|
Enumerable.Range(0, matrix.Columns).Select(j =>
|
||||||
|
$"\t\t\tleft.M{j + 1}{i + 1} * right")))}}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static {{matrix.Name}} ComponentWiseMultiply({{matrix.Name}} left, {{matrix.Name}} right)
|
||||||
|
{
|
||||||
|
{{ComponentWiseCore("*", matrix)}}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static {{matrix.Name}} ComponentWiseDivide({{matrix.Name}} left, {{matrix.Name}} right)
|
||||||
|
{
|
||||||
|
{{ComponentWiseCore("/", matrix)}}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static {{matrix.Name}} ComponentWiseModulo({{matrix.Name}} left, {{matrix.Name}} right)
|
||||||
|
{
|
||||||
|
{{ComponentWiseCore("%", matrix)}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
GenerateMatrixMulMatrix(matrix, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overloads the multiplication operator for the matrix multiplication from linear algebra.
|
||||||
|
/// </summary>
|
||||||
|
private void GenerateMatrixMulMatrix(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
public static {{matrix.Name}} operator *({{matrix.Name}} left, {{matrix.Name}} right)
|
||||||
|
{
|
||||||
|
{{matrix.Name}} result = new();
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (int r = 0; r < matrix.Rows; r++)
|
||||||
|
{
|
||||||
|
for (int c = 0; c < matrix.Columns; c++)
|
||||||
|
{
|
||||||
|
builder.Append($"\t\tresult.M{r + 1}{c + 1} = ");
|
||||||
|
|
||||||
|
for (int k = 0; k < matrix.Columns; k++)
|
||||||
|
{
|
||||||
|
if (k != 0)
|
||||||
|
builder.Append(" + ");
|
||||||
|
|
||||||
|
builder.Append($"left.M{r + 1}{k + 1} * right.M{k + 1}{c + 1}");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(";\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("""
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateMatrixMulVector(MatrixDefinition matrix, VectorSyntaxReceiver.VectorDefinition vector, StringBuilder builder)
|
||||||
|
{
|
||||||
|
if (vector.ComponentCount != matrix.Columns)
|
||||||
|
return;
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
public static {{vector.Name}} operator *({{matrix.Name}} left, {{vector.Name}} right)
|
||||||
|
{
|
||||||
|
{{vector.Name}} result = new();
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (int i = 0; i < vector.ComponentCount; i++)
|
||||||
|
{
|
||||||
|
builder.Append($"\t\tresult.{VectorGenerator.ComponentNames[i]} = ");
|
||||||
|
|
||||||
|
for (int j = 0; j < matrix.Columns; j++)
|
||||||
|
{
|
||||||
|
if (j != 0)
|
||||||
|
builder.Append(" + ");
|
||||||
|
|
||||||
|
builder.Append($"left.M{i + 1}{j + 1} * right.{VectorGenerator.ComponentNames[j]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(";\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("""
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateVectorMulMatrix(MatrixDefinition matrix, VectorSyntaxReceiver.VectorDefinition vector, StringBuilder builder)
|
||||||
|
{
|
||||||
|
if (vector.ComponentCount != matrix.Rows)
|
||||||
|
return;
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
public static {{vector.Name}} operator *({{vector.Name}} left, {{matrix.Name}} right)
|
||||||
|
{
|
||||||
|
{{vector.Name}} result = new();
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (int i = 0; i < vector.ComponentCount; i++)
|
||||||
|
{
|
||||||
|
builder.Append($"\t\tresult.{VectorGenerator.ComponentNames[i]} = ");
|
||||||
|
|
||||||
|
for (int j = 0; j < matrix.Rows; j++)
|
||||||
|
{
|
||||||
|
if (j != 0)
|
||||||
|
builder.Append(" + ");
|
||||||
|
|
||||||
|
builder.Append($"left.{VectorGenerator.ComponentNames[j]} * right.M{j + 1}{i + 1}");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(";\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("""
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateToString(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append("""
|
||||||
|
public override string ToString() => $"
|
||||||
|
""");
|
||||||
|
|
||||||
|
for (int i = 0; i < matrix.Rows; i++)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
builder.Append(", ");
|
||||||
|
|
||||||
|
builder.Append("{{");
|
||||||
|
|
||||||
|
for (int c = 0; c < matrix.Columns; c++)
|
||||||
|
{
|
||||||
|
if (c != 0)
|
||||||
|
builder.Append(", ");
|
||||||
|
|
||||||
|
builder.Append($"M{c + 1}{i + 1}: {{M{c + 1}{i + 1}}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("\";\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BuildSwizzleName(IEnumerable<int> components)
|
||||||
|
{
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
|
foreach (var component in components)
|
||||||
|
{
|
||||||
|
//Reconstruct row and column from index
|
||||||
|
builder.Append($"M{component % 4 + 1}{component / 4 + 1}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the swizzle operator is invalid (same component assigned twice).
|
||||||
|
*/
|
||||||
|
static bool IsSwizzleSetterValid(IEnumerable<int> components)
|
||||||
|
{
|
||||||
|
return components.Distinct().Count() == components.Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateSwizzle(MatrixDefinition matrix, StringBuilder builder)
|
||||||
|
{
|
||||||
|
int[] cmp = new int[4];
|
||||||
|
|
||||||
|
for (int componentCount = 2; componentCount <= 4; componentCount++)
|
||||||
|
{
|
||||||
|
int cmp2max = componentCount > 2 ? matrix.Rows * matrix.Columns : 1;
|
||||||
|
int cmp3max = componentCount > 3 ? matrix.Rows * matrix.Columns : 1;
|
||||||
|
|
||||||
|
for (cmp[0] = 0; cmp[0] < matrix.Rows * matrix.Columns; cmp[0]++)
|
||||||
|
for (cmp[1] = 0; cmp[1] < matrix.Rows * matrix.Columns; cmp[1]++)
|
||||||
|
for (cmp[2] = 0; cmp[2] < cmp2max; cmp[2]++)
|
||||||
|
for (cmp[3] = 0; cmp[3] < cmp3max; cmp[3]++)
|
||||||
|
{
|
||||||
|
StringBuilder swizzleName = new();
|
||||||
|
StringBuilder swizzleGetterConstructor = new();
|
||||||
|
StringBuilder swizzleSetterConstructor = new();
|
||||||
|
|
||||||
|
bool setterValid = IsSwizzleSetterValid(cmp.Take(componentCount));
|
||||||
|
|
||||||
|
for (int c = 0; c < componentCount; c++)
|
||||||
|
{
|
||||||
|
int elementIndex = cmp[c];
|
||||||
|
|
||||||
|
//Reconstruct row and column from index
|
||||||
|
string element = $"M{elementIndex % 4 + 1}{elementIndex / 4 + 1}";
|
||||||
|
|
||||||
|
swizzleName.Append(element);
|
||||||
|
|
||||||
|
if(c != 0)
|
||||||
|
{
|
||||||
|
swizzleGetterConstructor.Append(", ");
|
||||||
|
}
|
||||||
|
swizzleGetterConstructor.Append(element);
|
||||||
|
|
||||||
|
if (setterValid)
|
||||||
|
{
|
||||||
|
swizzleSetterConstructor.Append($"\n\t\t\t{element} = value.{VectorGenerator.ComponentNames[c]};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append($$"""
|
||||||
|
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
|
||||||
|
public {{matrix.BaseName}}{{componentCount}} {{swizzleName}}
|
||||||
|
{
|
||||||
|
get => new({{swizzleGetterConstructor}});
|
||||||
|
|
||||||
|
""");
|
||||||
|
|
||||||
|
if (setterValid)
|
||||||
|
{
|
||||||
|
builder.Append($$"""
|
||||||
|
set
|
||||||
|
{{{swizzleSetterConstructor}}
|
||||||
|
}
|
||||||
|
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append("\t}\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatrixDefinition
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public StructDeclarationSyntax Struct { get; }
|
||||||
|
|
||||||
|
public int Rows { get; }
|
||||||
|
public int Columns { get; }
|
||||||
|
|
||||||
|
public string BaseName { get; }
|
||||||
|
|
||||||
|
public string ElementTypeName { get; }
|
||||||
|
|
||||||
|
public MatrixDefinition(string name, StructDeclarationSyntax @struct, int rows, int columns, string baseName, string elementTypeName)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Struct = @struct;
|
||||||
|
Rows = rows;
|
||||||
|
Columns = columns;
|
||||||
|
BaseName = baseName;
|
||||||
|
ElementTypeName = elementTypeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatrixSyntaxReceiver : ISyntaxReceiver
|
||||||
|
{
|
||||||
|
public ComparableMatrixSyntaxReceiver ComparableReceiver = new();
|
||||||
|
public MatrixMathSyntaxReceiver MathReceiver = new();
|
||||||
|
public MatrixLogicSyntaxReceiver LogicReceiver = new();
|
||||||
|
public MatrixVectorMultiplicationSyntaxReceiver VectorMultiplicationReceiver = new();
|
||||||
|
public MatrixCastSyntaxReceiver CastReceiver = new();
|
||||||
|
|
||||||
|
public VectorSyntaxReceiver VectorReceiver = new();
|
||||||
|
|
||||||
|
public List<MatrixDefinition> Matrices { get; } = new();
|
||||||
|
|
||||||
|
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||||
|
{
|
||||||
|
VectorReceiver.OnVisitSyntaxNode(syntaxNode);
|
||||||
|
|
||||||
|
ComparableReceiver.OnVisitSyntaxNode(syntaxNode);
|
||||||
|
MathReceiver.OnVisitSyntaxNode(syntaxNode);
|
||||||
|
LogicReceiver.OnVisitSyntaxNode(syntaxNode);
|
||||||
|
VectorMultiplicationReceiver.OnVisitSyntaxNode(syntaxNode);
|
||||||
|
CastReceiver.OnVisitSyntaxNode(syntaxNode);
|
||||||
|
|
||||||
|
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "Matrix" } } attr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
||||||
|
var name = @struct.Identifier.Text;
|
||||||
|
|
||||||
|
if (attr?.ArgumentList?.Arguments == null || attr.ArgumentList.Arguments.Count != 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string? elementTypeName = (attr.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax)?.Type.ToFullString();
|
||||||
|
|
||||||
|
if (elementTypeName == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int? columnCount = (attr.ArgumentList.Arguments[1].Expression as LiteralExpressionSyntax)?.Token.Value as int?;
|
||||||
|
|
||||||
|
if (columnCount == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int? rowCount = (attr.ArgumentList.Arguments[2].Expression as LiteralExpressionSyntax)?.Token.Value as int?;
|
||||||
|
|
||||||
|
if (rowCount == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string? baseName = (attr.ArgumentList.Arguments[3].Expression as LiteralExpressionSyntax)?.Token.ValueText;
|
||||||
|
|
||||||
|
if (baseName == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Matrices.Add(new MatrixDefinition(name, @struct, rowCount.Value, columnCount.Value, baseName, elementTypeName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ComparableMatrixSyntaxReceiver : ISyntaxReceiver
|
||||||
|
{
|
||||||
|
public List<string> Matrices { get; } = new();
|
||||||
|
|
||||||
|
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||||
|
{
|
||||||
|
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "ComparableMatrix" } } attr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
||||||
|
var name = @struct.Identifier.Text;
|
||||||
|
|
||||||
|
Matrices.Add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatrixMathSyntaxReceiver : ISyntaxReceiver
|
||||||
|
{
|
||||||
|
public List<string> Matrices { get; } = new();
|
||||||
|
|
||||||
|
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||||
|
{
|
||||||
|
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "MatrixMath" } } attr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
||||||
|
var name = @struct.Identifier.Text;
|
||||||
|
|
||||||
|
Matrices.Add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatrixLogicSyntaxReceiver : ISyntaxReceiver
|
||||||
|
{
|
||||||
|
public List<string> Matrices { get; } = new();
|
||||||
|
|
||||||
|
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||||
|
{
|
||||||
|
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "MatrixLogic" } } attr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
||||||
|
var name = @struct.Identifier.Text;
|
||||||
|
|
||||||
|
Matrices.Add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatrixVectorMultiplicationSyntaxReceiver : ISyntaxReceiver
|
||||||
|
{
|
||||||
|
public List<Multiplication> Multiplications { get; } = new();
|
||||||
|
|
||||||
|
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||||
|
{
|
||||||
|
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "MatrixVectorMultiplication" } } attr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
||||||
|
var matrixType = @struct.Identifier.Text;
|
||||||
|
|
||||||
|
string? vectorType = (attr.ArgumentList?.Arguments[0].Expression as TypeOfExpressionSyntax)?.Type.ToFullString();
|
||||||
|
|
||||||
|
if (vectorType == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Multiplications.Add(new Multiplication(matrixType, vectorType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Multiplication(string MatrixType, string VectorType)
|
||||||
|
{
|
||||||
|
public string MatrixType { get; } = MatrixType;
|
||||||
|
public string VectorType { get; } = VectorType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatrixCastSyntaxReceiver : ISyntaxReceiver
|
||||||
|
{
|
||||||
|
public List<Cast> Casts { get; } = new();
|
||||||
|
|
||||||
|
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||||
|
{
|
||||||
|
if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "MatrixCast" } } attr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
||||||
|
var sourceTypeName = @struct.Identifier.Text;
|
||||||
|
|
||||||
|
var targetElementTypeName = (attr.ArgumentList?.Arguments[0].Expression as TypeOfExpressionSyntax)?.Type.ToFullString();
|
||||||
|
|
||||||
|
if (targetElementTypeName == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var isExplicit = (attr.ArgumentList?.Arguments[1].Expression as LiteralExpressionSyntax)?.Token.Value as bool?;
|
||||||
|
|
||||||
|
if (isExplicit == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Casts.Add(new Cast(sourceTypeName, targetElementTypeName, isExplicit.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Cast (string SourceTypeName, string TargetElementTypeName, bool IsExplicit)
|
||||||
|
{
|
||||||
|
public string SourceTypeName { get; } = SourceTypeName;
|
||||||
|
public string TargetElementTypeName { get; } = TargetElementTypeName;
|
||||||
|
public bool IsExplicit { get; } = IsExplicit;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<IsRoslynComponent>true</IsRoslynComponent>
|
<IsRoslynComponent>true</IsRoslynComponent>
|
||||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
|
||||||
var receiver = (VectorSyntaxReceiver)context.SyntaxReceiver;
|
var receiver = (VectorSyntaxReceiver?)context.SyntaxReceiver;
|
||||||
|
|
||||||
if (receiver == null) return;
|
if (receiver == null) return;
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
|
|
||||||
namespace {{vector.Struct.GetNamespace()}};
|
namespace {{vector.Struct.GetNamespace()}};
|
||||||
|
|
||||||
public partial struct {{vector.VectorName}}
|
public partial struct {{vector.Name}}
|
||||||
{
|
{
|
||||||
|
|
||||||
""");
|
""");
|
||||||
@@ -87,24 +87,24 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
GenerateEquals(vector, builder);
|
GenerateEquals(vector, builder);
|
||||||
GenerateGetHashCode(vector, builder);
|
GenerateGetHashCode(vector, builder);
|
||||||
|
|
||||||
if (receiver.ComparableReceiver.ComparableVectors.Contains(vector.VectorName))
|
if (receiver.ComparableReceiver.ComparableVectors.Contains(vector.Name))
|
||||||
{
|
{
|
||||||
GenerateComparisonOperators(vector, builder);
|
GenerateComparisonOperators(vector, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receiver.MathReceiver.MathVectors.Contains(vector.VectorName))
|
if (receiver.MathReceiver.MathVectors.Contains(vector.Name))
|
||||||
{
|
{
|
||||||
GenerateMathOperators(vector, builder);
|
GenerateMathOperators(vector, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receiver.LogicReceiver.LogicVectors.Contains(vector.VectorName))
|
if (receiver.LogicReceiver.LogicVectors.Contains(vector.Name))
|
||||||
{
|
{
|
||||||
GenerateLogicOperators(vector, builder);
|
GenerateLogicOperators(vector, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var cast in receiver.CastReceiver.VectorCasts.Where(c => c.FromType == vector.VectorName))
|
foreach (var cast in receiver.CastReceiver.VectorCasts.Where(c => c.FromType == vector.Name))
|
||||||
{
|
{
|
||||||
VectorDefinition toVectorDefinition = receiver.Vectors.First(v => v.VectorName == cast.ToType);
|
VectorDefinition toVectorDefinition = receiver.Vectors.First(v => v.Name == cast.ToType);
|
||||||
|
|
||||||
GenerateCastOperator(cast, vector, toVectorDefinition, builder);
|
GenerateCastOperator(cast, vector, toVectorDefinition, builder);
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
|
|
||||||
builder.Append('}');
|
builder.Append('}');
|
||||||
|
|
||||||
context.AddSource($"{vector.VectorName}.g.cs", builder.ToString());
|
context.AddSource($"{vector.Name}.g.cs", builder.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public override bool Equals(object other)
|
public override bool Equals(object other)
|
||||||
{
|
{
|
||||||
if (other is {{vector.VectorName}} otherVector)
|
if (other is {{vector.Name}} otherVector)
|
||||||
return Math.all(this == otherVector);
|
return Math.all(this == otherVector);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -183,7 +183,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
new DiagnosticDescriptor(
|
new DiagnosticDescriptor(
|
||||||
"SG0001",
|
"SG0001",
|
||||||
"Vector-Dimensions don't match for cast.",
|
"Vector-Dimensions don't match for cast.",
|
||||||
$"Cannot cast from \"{fromVector.VectorName}\" to \"{toVector.VectorName}\" because the dimensions don't match.",
|
$"Cannot cast from \"{fromVector.Name}\" to \"{toVector.Name}\" because the dimensions don't match.",
|
||||||
"Vector Generator",
|
"Vector Generator",
|
||||||
DiagnosticSeverity.Error,
|
DiagnosticSeverity.Error,
|
||||||
true), fromVector.Struct.GetLocation()));
|
true), fromVector.Struct.GetLocation()));
|
||||||
@@ -240,9 +240,9 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public static implicit operator {{vector.VectorName}}({{vector.ElementTypeName}} value)
|
public static implicit operator {{vector.Name}}({{vector.ElementTypeName}} value)
|
||||||
{
|
{
|
||||||
return new {{vector.VectorName}}({{castBuilder}});
|
return new {{vector.Name}}({{castBuilder}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -307,7 +307,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}} ({{parameters}})
|
public {{vector.Name}} ({{parameters}})
|
||||||
{{{body}}
|
{{{body}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
private void Generatefloat3Constructors(VectorDefinition vector, StringBuilder builder)
|
private void Generatefloat3Constructors(VectorDefinition vector, StringBuilder builder)
|
||||||
{
|
{
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}}({{vector.BaseName}}2 xy, {{vector.ElementTypeName}} z)
|
public {{vector.Name}}({{vector.BaseName}}2 xy, {{vector.ElementTypeName}} z)
|
||||||
{
|
{
|
||||||
X = xy.X;
|
X = xy.X;
|
||||||
Y = xy.Y;
|
Y = xy.Y;
|
||||||
@@ -328,7 +328,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
""");
|
""");
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}}({{vector.ElementTypeName}} x, {{vector.BaseName}}2 yz)
|
public {{vector.Name}}({{vector.ElementTypeName}} x, {{vector.BaseName}}2 yz)
|
||||||
{
|
{
|
||||||
X = x;
|
X = x;
|
||||||
Y = yz.X;
|
Y = yz.X;
|
||||||
@@ -341,7 +341,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
private void Generatefloat4Constructors(VectorDefinition vector, StringBuilder builder)
|
private void Generatefloat4Constructors(VectorDefinition vector, StringBuilder builder)
|
||||||
{
|
{
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}}({{vector.BaseName}}2 xy, {{vector.BaseName}}2 zw)
|
public {{vector.Name}}({{vector.BaseName}}2 xy, {{vector.BaseName}}2 zw)
|
||||||
{
|
{
|
||||||
//XY = xy;
|
//XY = xy;
|
||||||
//ZW = zw;
|
//ZW = zw;
|
||||||
@@ -355,7 +355,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
""");
|
""");
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}}({{vector.BaseName}}2 xy, {{vector.ElementTypeName}} z, {{vector.ElementTypeName}} w)
|
public {{vector.Name}}({{vector.BaseName}}2 xy, {{vector.ElementTypeName}} z, {{vector.ElementTypeName}} w)
|
||||||
{
|
{
|
||||||
X = xy.X;
|
X = xy.X;
|
||||||
Y = xy.Y;
|
Y = xy.Y;
|
||||||
@@ -367,7 +367,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
""");
|
""");
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}}({{vector.ElementTypeName}} x, {{vector.BaseName}}2 yz, {{vector.ElementTypeName}} w)
|
public {{vector.Name}}({{vector.ElementTypeName}} x, {{vector.BaseName}}2 yz, {{vector.ElementTypeName}} w)
|
||||||
{
|
{
|
||||||
X = x;
|
X = x;
|
||||||
Y = yz.X;
|
Y = yz.X;
|
||||||
@@ -379,7 +379,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
""");
|
""");
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}}({{vector.ElementTypeName}} x, {{vector.ElementTypeName}} y, {{vector.BaseName}}2 zw)
|
public {{vector.Name}}({{vector.ElementTypeName}} x, {{vector.ElementTypeName}} y, {{vector.BaseName}}2 zw)
|
||||||
{
|
{
|
||||||
X = x;
|
X = x;
|
||||||
Y = y;
|
Y = y;
|
||||||
@@ -391,7 +391,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
""");
|
""");
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}}({{vector.BaseName}}3 xyz, {{vector.ElementTypeName}} w)
|
public {{vector.Name}}({{vector.BaseName}}3 xyz, {{vector.ElementTypeName}} w)
|
||||||
{
|
{
|
||||||
X = xyz.X;
|
X = xyz.X;
|
||||||
Y = xyz.Y;
|
Y = xyz.Y;
|
||||||
@@ -403,7 +403,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
""");
|
""");
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public {{vector.VectorName}}({{vector.ElementTypeName}} x, {{vector.BaseName}}3 yzw)
|
public {{vector.Name}}({{vector.ElementTypeName}} x, {{vector.BaseName}}3 yzw)
|
||||||
{
|
{
|
||||||
X = x;
|
X = x;
|
||||||
Y = yzw.X;
|
Y = yzw.X;
|
||||||
@@ -482,7 +482,7 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public static bool{{vector.ComponentCount}} operator {{op}}({{vector.VectorName}} left, {{vector.VectorName}} right)
|
public static bool{{vector.ComponentCount}} operator {{op}}({{vector.Name}} left, {{vector.Name}} right)
|
||||||
{
|
{
|
||||||
return new bool{{vector.ComponentCount}}({{arguments}});
|
return new bool{{vector.ComponentCount}}({{arguments}});
|
||||||
}
|
}
|
||||||
@@ -524,9 +524,9 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} value)
|
public static {{vector.Name}} operator {{op}}({{vector.Name}} value)
|
||||||
{
|
{
|
||||||
return new {{vector.VectorName}}({{negativeArguments}});
|
return new {{vector.Name}}({{negativeArguments}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -548,9 +548,9 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} left, {{vector.VectorName}} right)
|
public static {{vector.Name}} operator {{op}}({{vector.Name}} left, {{vector.Name}} right)
|
||||||
{
|
{
|
||||||
return new {{vector.VectorName}}({{arguments}});
|
return new {{vector.Name}}({{arguments}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -567,9 +567,9 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} left, {{vector.ElementTypeName}} right)
|
public static {{vector.Name}} operator {{op}}({{vector.Name}} left, {{vector.ElementTypeName}} right)
|
||||||
{
|
{
|
||||||
return new {{vector.VectorName}}({{arguments}});
|
return new {{vector.Name}}({{arguments}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -586,9 +586,9 @@ public class VectorGenerator : ISourceGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.Append($$"""
|
builder.Append($$"""
|
||||||
public static {{vector.VectorName}} operator {{op}}({{vector.ElementTypeName}} left, {{vector.VectorName}} right)
|
public static {{vector.Name}} operator {{op}}({{vector.ElementTypeName}} left, {{vector.Name}} right)
|
||||||
{
|
{
|
||||||
return new {{vector.VectorName}}({{arguments}});
|
return new {{vector.Name}}({{arguments}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -720,21 +720,27 @@ public class VectorSyntaxReceiver : ISyntaxReceiver
|
|||||||
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
||||||
var name = @struct.Identifier.Text;
|
var name = @struct.Identifier.Text;
|
||||||
|
|
||||||
var elementTypeName = (attr.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax).Type.ToFullString();
|
var elementTypeName = (attr.ArgumentList?.Arguments[0].Expression as TypeOfExpressionSyntax)?.Type.ToFullString();
|
||||||
|
|
||||||
var componentCount = (attr.ArgumentList.Arguments[1].Expression as LiteralExpressionSyntax).Token.Value as int?;
|
if (elementTypeName == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var componentCount = (attr.ArgumentList?.Arguments[1].Expression as LiteralExpressionSyntax)?.Token.Value as int?;
|
||||||
|
|
||||||
if (componentCount == null)
|
if (componentCount == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var baseName = (attr.ArgumentList.Arguments[2].Expression as LiteralExpressionSyntax).Token.ValueText;
|
var baseName = (attr.ArgumentList?.Arguments[2].Expression as LiteralExpressionSyntax)?.Token.ValueText;
|
||||||
|
|
||||||
|
if (baseName == null)
|
||||||
|
return;
|
||||||
|
|
||||||
Vectors.Add(new VectorDefinition(name, @struct, componentCount.Value, baseName, elementTypeName));
|
Vectors.Add(new VectorDefinition(name, @struct, componentCount.Value, baseName, elementTypeName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VectorDefinition
|
public class VectorDefinition
|
||||||
{
|
{
|
||||||
public string VectorName { get; }
|
public string Name { get; }
|
||||||
public StructDeclarationSyntax Struct { get; }
|
public StructDeclarationSyntax Struct { get; }
|
||||||
|
|
||||||
public int ComponentCount { get; }
|
public int ComponentCount { get; }
|
||||||
@@ -743,9 +749,9 @@ public class VectorSyntaxReceiver : ISyntaxReceiver
|
|||||||
|
|
||||||
public string ElementTypeName { get; }
|
public string ElementTypeName { get; }
|
||||||
|
|
||||||
public VectorDefinition(string vectorName, StructDeclarationSyntax @struct, int componentCount, string baseName, string elementTypeName)
|
public VectorDefinition(string name, StructDeclarationSyntax @struct, int componentCount, string baseName, string elementTypeName)
|
||||||
{
|
{
|
||||||
VectorName = vectorName;
|
Name = name;
|
||||||
Struct = @struct;
|
Struct = @struct;
|
||||||
ComponentCount = componentCount;
|
ComponentCount = componentCount;
|
||||||
BaseName = baseName;
|
BaseName = baseName;
|
||||||
@@ -814,9 +820,12 @@ public class VectorCastSyntaxReceiver : ISyntaxReceiver
|
|||||||
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
var @struct = attr.GetParent<StructDeclarationSyntax>();
|
||||||
var fromType = @struct.Identifier.Text;
|
var fromType = @struct.Identifier.Text;
|
||||||
|
|
||||||
var toType = (attr.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax).Type.ToFullString();
|
var toType = (attr.ArgumentList?.Arguments[0].Expression as TypeOfExpressionSyntax)?.Type.ToFullString();
|
||||||
|
|
||||||
var isExplicit = (attr.ArgumentList.Arguments[1].Expression as LiteralExpressionSyntax).Token.Value as bool?;
|
if (toType == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var isExplicit = (attr.ArgumentList?.Arguments[1].Expression as LiteralExpressionSyntax)?.Token.Value as bool?;
|
||||||
|
|
||||||
if (isExplicit == null)
|
if (isExplicit == null)
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user