From 3e55a1614a9ddcbc683a368822a32b095fad1bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Thu, 20 Jul 2023 17:48:15 +0200 Subject: [PATCH] Shader like vectors for C# Scripting --- .../Assets/Scripts/MyTestEntity.cs | 14 +- GlitchyEngine/src/Math/Math.bf | 6 + GlitchyEngine/src/Scripting/ScriptGlue.bf | 14 + ScriptCore/Components/RigidBody2D.cs | 4 +- ScriptCore/Components/Transform.cs | 4 +- ScriptCore/Entity.cs | 4 +- ScriptCore/Math/Attributes/VectorAttribute.cs | 21 +- ScriptCore/Math/BoolVectors.cs | 35 + ScriptCore/Math/DoubleVectors.cs | 29 + ScriptCore/Math/FloatVectors.cs | 60 ++ ScriptCore/Math/HalfVectors.cs | 23 + ScriptCore/Math/IntVectors.cs | 47 + ScriptCore/Math/Math.cs | 841 ++++++++++++++++++ ScriptCore/Math/UIntVectors.cs | 46 + ScriptCore/Math/Vector2.cs | 122 --- ScriptCore/Math/Vector3.cs | 139 --- ScriptCore/Math/Vector4.cs | 155 ---- ScriptCore/Math/float2.cs | 22 - ScriptCore/Physics2D.cs | 4 +- ScriptCore/ScriptCore.csproj | 4 + ScriptCore/ScriptCore.csproj.DotSettings | 2 + ScriptCore/ScriptGlue.cs | 28 +- .../ScriptCoreGenerator.csproj | 1 + ScriptCoreGenerator/VectorGenerator.cs | 433 ++++++++- 24 files changed, 1572 insertions(+), 486 deletions(-) create mode 100644 ScriptCore/Math/BoolVectors.cs create mode 100644 ScriptCore/Math/DoubleVectors.cs create mode 100644 ScriptCore/Math/FloatVectors.cs create mode 100644 ScriptCore/Math/HalfVectors.cs create mode 100644 ScriptCore/Math/IntVectors.cs create mode 100644 ScriptCore/Math/Math.cs create mode 100644 ScriptCore/Math/UIntVectors.cs delete mode 100644 ScriptCore/Math/Vector2.cs delete mode 100644 ScriptCore/Math/Vector3.cs delete mode 100644 ScriptCore/Math/Vector4.cs delete mode 100644 ScriptCore/Math/float2.cs create mode 100644 ScriptCore/ScriptCore.csproj.DotSettings diff --git a/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs b/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs index 40cdd49..572c61d 100644 --- a/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs +++ b/GlitchyEditor/SandboxProject/Assets/Scripts/MyTestEntity.cs @@ -1,9 +1,10 @@ using System; +using System.Runtime.Remoting.Metadata.W3cXsd2001; using GlitchyEngine; using GlitchyEngine.Editor; using GlitchyEngine.Math; -//using GlitchyEngine.Math; +using static GlitchyEngine.Math.Math; namespace Sandbox { @@ -122,7 +123,16 @@ namespace Sandbox float4 floaty = new float4(f2, f2); - Log.Info($"Haleluja2! {floaty}"); + float2 bbb = f2.XY * floaty.XY; + + float4 megaFloat = floaty.WXYZ; + + if (all(abs(normalize(megaFloat) - normalize(floaty)) < 0.01f)) + { + Log.Info($"Haleluja3!"); + } + + Log.Info($"Haleluja2! {bbb.X} {bbb.Y}"); } /// diff --git a/GlitchyEngine/src/Math/Math.bf b/GlitchyEngine/src/Math/Math.bf index c678b91..62573a5 100644 --- a/GlitchyEngine/src/Math/Math.bf +++ b/GlitchyEngine/src/Math/Math.bf @@ -69,6 +69,12 @@ static #endregion #region modf / frac / trunc + + // Splits the value x into fractional and integer parts, each of which has the same sign as x. + public static float modf(float x, out float integerPart) + { + return Math.[Friend]modff(x.X, out integerPart); + } // Splits the value x into fractional and integer parts, each of which has the same sign as x. public static float2 modf(float2 x, out float2 integerPart) diff --git a/GlitchyEngine/src/Scripting/ScriptGlue.bf b/GlitchyEngine/src/Scripting/ScriptGlue.bf index 4b91215..4551dc5 100644 --- a/GlitchyEngine/src/Scripting/ScriptGlue.bf +++ b/GlitchyEngine/src/Scripting/ScriptGlue.bf @@ -53,6 +53,8 @@ static class ScriptGlue public static void Init() { RegisterCalls(); + + RegisterMathFunctions(); } public static void RegisterManagedComponents() @@ -284,6 +286,18 @@ static class ScriptGlue #endregion Physics2D +#region Math + + private static void RegisterMathFunctions() + { + RegisterCall("ScriptGlue::modf_float", => GlitchyEngine.Math.modf); + RegisterCall("ScriptGlue::modf_float2", => GlitchyEngine.Math.modf); + RegisterCall("ScriptGlue::modf_float3", => GlitchyEngine.Math.modf); + RegisterCall("ScriptGlue::modf_float4", => GlitchyEngine.Math.modf); + } + +#endregion + private static void RegisterCall(String name, T method) where T : var { Mono.mono_add_internal_call(scope $"GlitchyEngine.{name}", (void*)method); diff --git a/ScriptCore/Components/RigidBody2D.cs b/ScriptCore/Components/RigidBody2D.cs index 36ebe05..d79fdc7 100644 --- a/ScriptCore/Components/RigidBody2D.cs +++ b/ScriptCore/Components/RigidBody2D.cs @@ -12,7 +12,7 @@ public class RigidBody2D : Component /// The world force vector, usually in Newtons (N). /// The world position of the point of application. /// Wake up the body - public void ApplyForce(Vector2 force, Vector2 point, bool wakeUp = true) + public void ApplyForce(float2 force, float2 point, bool wakeUp = true) { ScriptGlue.RigidBody2D_ApplyForce(Entity._uuid, force, point, wakeUp); } @@ -23,7 +23,7 @@ public class RigidBody2D : Component /// /// The world force vector, usually in Newtons (N). /// Wake up the body - public void ApplyForceToCenter(Vector2 force, bool wakeUp = true) + public void ApplyForceToCenter(float2 force, bool wakeUp = true) { ScriptGlue.RigidBody2D_ApplyForceToCenter(Entity._uuid, force, wakeUp); } diff --git a/ScriptCore/Components/Transform.cs b/ScriptCore/Components/Transform.cs index 939f3bc..ddea614 100644 --- a/ScriptCore/Components/Transform.cs +++ b/ScriptCore/Components/Transform.cs @@ -5,11 +5,11 @@ namespace GlitchyEngine; public class Transform : Component { - public Vector3 Translation + public float3 Translation { get { - ScriptGlue.Transform_GetTranslation(Entity.UUID, out Vector3 translation); + ScriptGlue.Transform_GetTranslation(Entity.UUID, out float3 translation); return translation; } set diff --git a/ScriptCore/Entity.cs b/ScriptCore/Entity.cs index c3649cd..d8f6f2e 100644 --- a/ScriptCore/Entity.cs +++ b/ScriptCore/Entity.cs @@ -143,9 +143,7 @@ public class Entity : EngineObject public static Entity FindEntityWithName(string name) { ScriptGlue.Entity_FindEntityWithName(name, out UUID entityId); - - Log.Error($"Found EntityID {entityId}"); - + if (entityId == UUID.Zero) return null; diff --git a/ScriptCore/Math/Attributes/VectorAttribute.cs b/ScriptCore/Math/Attributes/VectorAttribute.cs index 626631c..aad8bbc 100644 --- a/ScriptCore/Math/Attributes/VectorAttribute.cs +++ b/ScriptCore/Math/Attributes/VectorAttribute.cs @@ -2,8 +2,9 @@ using System.Collections.Generic; using System.Text; -namespace ScriptCore.Math.Attributes; +namespace GlitchyEngine.Math.Attributes; +[AttributeUsage(AttributeTargets.Struct)] public class VectorAttribute : Attribute { public Type Type { get; set; } @@ -19,9 +20,23 @@ public class VectorAttribute : Attribute } } -public class SwizzleVectorAttribute : Attribute +[AttributeUsage(AttributeTargets.Struct)] +public class ComparableVectorAttribute : Attribute { } +[AttributeUsage(AttributeTargets.Struct)] +public class VectorMathAttribute : Attribute { } +[AttributeUsage(AttributeTargets.Struct)] +public class VectorLogicAttribute : Attribute { } + +[AttributeUsage(AttributeTargets.Struct, AllowMultiple = true)] +public class VectorCastAttribute : Attribute { - public SwizzleVectorAttribute() + public Type TargetType { get; set; } + + public bool IsExplicit { get; set; } + + public VectorCastAttribute(Type targetType, bool isExplicit) { + TargetType = targetType; + IsExplicit = isExplicit; } } diff --git a/ScriptCore/Math/BoolVectors.cs b/ScriptCore/Math/BoolVectors.cs new file mode 100644 index 0000000..6572c51 --- /dev/null +++ b/ScriptCore/Math/BoolVectors.cs @@ -0,0 +1,35 @@ +using System; +using GlitchyEngine.Math; +using GlitchyEngine.Math.Attributes; + +namespace GlitchyEngine.Math; + +[Vector(typeof(bool), 2, "bool")] +[VectorLogic] +public partial struct bool2 +{ + public static bool2 operator !(bool2 value) + { + return new bool2(!value.X, !value.Y); + } +} + +[Vector(typeof(bool), 3, "bool")] +[VectorLogic] +public partial struct bool3 +{ + public static bool3 operator !(bool3 value) + { + return new bool3(!value.X, !value.Y, !value.Z); + } +} + +[Vector(typeof(bool), 4, "bool")] +[VectorLogic] +public partial struct bool4 +{ + public static bool4 operator !(bool4 value) + { + return new bool4(!value.X, !value.Y, !value.Z, !value.W); + } +} diff --git a/ScriptCore/Math/DoubleVectors.cs b/ScriptCore/Math/DoubleVectors.cs new file mode 100644 index 0000000..800dc7f --- /dev/null +++ b/ScriptCore/Math/DoubleVectors.cs @@ -0,0 +1,29 @@ +using System; +using GlitchyEngine.Math; +using GlitchyEngine.Math.Attributes; + +namespace GlitchyEngine.Math; + +[Vector(typeof(double), 2, "double")] +[VectorMath] +[ComparableVector] +[VectorCast(typeof(float2), true)] +public partial struct double2 +{ +} + +[Vector(typeof(double), 3, "double")] +[VectorMath] +[ComparableVector] +[VectorCast(typeof(float3), true)] +public partial struct double3 +{ +} + +[Vector(typeof(double), 4, "double")] +[VectorMath] +[ComparableVector] +[VectorCast(typeof(float4), true)] +public partial struct double4 +{ +} diff --git a/ScriptCore/Math/FloatVectors.cs b/ScriptCore/Math/FloatVectors.cs new file mode 100644 index 0000000..29e2a0a --- /dev/null +++ b/ScriptCore/Math/FloatVectors.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using GlitchyEngine.Math; +using GlitchyEngine.Math.Attributes; + +namespace GlitchyEngine.Math; + +[Vector(typeof(float), 2, "float")] +[ComparableVector] +[VectorMath] +[VectorCast(typeof(int2), true)] +[VectorCast(typeof(double2), true)] +[VectorCast(typeof(half2), true)] +public partial struct float2 +{ + public static readonly float2 Zero = new(0.0f, 0.0f); + public static readonly float2 UnitX = new(1.0f, 0.0f); + public static readonly float2 UnitY = new(0.0f, 1.0f); + public static readonly float2 One = new(0.0f, 0.0f); +} + +[Vector(typeof(float), 3, "float")] +[ComparableVector] +[VectorMath] +[VectorCast(typeof(int3), true)] +[VectorCast(typeof(double3), true)] +[VectorCast(typeof(half3), true)] +public partial struct float3 +{ + public static readonly float3 Zero = new(0.0f, 0.0f, 0.0f); + public static readonly float3 UnitX = new(1.0f, 0.0f, 0.0f); + public static readonly float3 UnitY = new(0.0f, 1.0f, 0.0f); + public static readonly float3 UnitZ = new(0.0f, 0.0f, 1.0f); + public static readonly float3 One = new(0.0f, 0.0f, 0.0f); + + public static readonly float3 Forward = new(0.0f, 0.0f, 1.0f); + public static readonly float3 Backward = new(0.0f, 0.0f, -1.0f); + public static readonly float3 Left = new(-1.0f, 0.0f, 0.0f); + public static readonly float3 Right = new(1.0f, 0.0f, 0.0f); + public static readonly float3 Up = new(0.0f, 1.0f, 0.0f); + public static readonly float3 Down = new(0.0f, -1.0f, 0.0f); +} + +[Vector(typeof(float), 4, "float")] +[ComparableVector] +[VectorMath] +[VectorCast(typeof(int4), true)] +[VectorCast(typeof(double4), true)] +[VectorCast(typeof(half4), true)] +public partial struct float4 +{ + public static readonly float4 Zero = new(0f, 0f, 0f, 0f); + public static readonly float4 UnitX = new(1f, 0f, 0f, 0f); + public static readonly float4 UnitY = new(0f, 1f, 0f, 0f); + public static readonly float4 UnitZ = new(0f, 0f, 1f, 0f); + public static readonly float4 UnitW = new(0f, 0f, 0f, 1f); + public static readonly float4 One = new(1f, 1f, 1f, 1f); +} diff --git a/ScriptCore/Math/HalfVectors.cs b/ScriptCore/Math/HalfVectors.cs new file mode 100644 index 0000000..da8ef70 --- /dev/null +++ b/ScriptCore/Math/HalfVectors.cs @@ -0,0 +1,23 @@ +using System; +using GlitchyEngine.Math; +using GlitchyEngine.Math.Attributes; + +namespace GlitchyEngine.Math; + +[Vector(typeof(Half), 2, "half")] +[VectorCast(typeof(float2), true)] +public partial struct half2 +{ +} + +[Vector(typeof(Half), 3, "half")] +[VectorCast(typeof(float3), true)] +public partial struct half3 +{ +} + +[Vector(typeof(Half), 4, "half")] +[VectorCast(typeof(float4), true)] +public partial struct half4 +{ +} diff --git a/ScriptCore/Math/IntVectors.cs b/ScriptCore/Math/IntVectors.cs new file mode 100644 index 0000000..983a142 --- /dev/null +++ b/ScriptCore/Math/IntVectors.cs @@ -0,0 +1,47 @@ +using System; +using GlitchyEngine.Math; +using GlitchyEngine.Math.Attributes; + +namespace GlitchyEngine.Math; + +[Vector(typeof(int), 2, "int")] +[VectorMath] +[VectorLogic] +[ComparableVector] +[VectorCast(typeof(float2), true)] +[VectorCast(typeof(uint2), true)] +public partial struct int2 +{ + public static int2 operator ~(int2 value) + { + return new int2(~value.X, ~value.Y); + } +} + +[Vector(typeof(int), 3, "int")] +[VectorMath] +[VectorLogic] +[ComparableVector] +[VectorCast(typeof(float3), true)] +[VectorCast(typeof(uint3), true)] +public partial struct int3 +{ + public static int3 operator ~(int3 value) + { + return new int3(~value.X, ~value.Y, ~value.Z); + } +} + +[Vector(typeof(int), 4, "int")] +[VectorMath] +[VectorLogic] +[ComparableVector] +[VectorCast(typeof(float4), true)] +[VectorCast(typeof(uint4), true)] +public partial struct int4 +{ + public static int4 operator ~(int4 value) + { + return new int4(~value.X, ~value.Y, ~value.Z, ~value.W); + } +} diff --git a/ScriptCore/Math/Math.cs b/ScriptCore/Math/Math.cs new file mode 100644 index 0000000..fead2a7 --- /dev/null +++ b/ScriptCore/Math/Math.cs @@ -0,0 +1,841 @@ +using System; +using System.Runtime.CompilerServices; + +namespace GlitchyEngine.Math; + +public static class Math +{ + /// An optimal representation of π. + public const float Pi = 3.141592654f; + /// An optimal representation of 2*π. + public const float TwoPi = 6.283185307f; + /// An optimal representation of 1/π. + public const float OneOverPi = 0.318309886f; + /// An optimal representation of 2/π. + public const float OneOverTwoPi = 0.159154943f; + /// An optimal representation of π/2. + public const float PiOverTwo = 1.570796327f; + /// An optimal representation of π/4. + public const float PiOverFour = 0.785398163f; + + /// Converts radians to degrees + public const float RadToDeg = 180.0f / Pi; + + /// Converts radians to degrees + public const float DegToRad = Pi / 180.0f; + + + /// Returns true if at least one of the components is true. + public static bool any(bool value) => value; + /// Returns true if at least one of the components is true. + public static bool any(bool2 value) => value.X || value.Y; + /// Returns true if at least one of the components is true. + public static bool any(bool3 value) => value.X || value.Y || value.Z; + /// 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; + + /// Returns true if all of the components are true. + public static bool all(bool value) => value; + /// Returns true if all of the components are true. + public static bool all(bool2 value) => value.X && value.Y; + /// Returns true if all of the components are true. + public static bool all(bool3 value) => value.X && value.Y && value.Z; + /// Returns true if all of the components are true. + public static bool all(bool4 value) => value.X && value.Y && value.Z && value.W; + +#region abs + + public static float abs(float value) + { + return System.Math.Abs(value); + } + + public static float2 abs(float2 value) + { + return new float2(System.Math.Abs(value.X), System.Math.Abs(value.Y)); + } + + public static float3 abs(float3 value) + { + return new float3(System.Math.Abs(value.X), System.Math.Abs(value.Y), System.Math.Abs(value.Z)); + } + + public static float4 abs(float4 value) + { + return new float4(System.Math.Abs(value.X), System.Math.Abs(value.Y), System.Math.Abs(value.Z), System.Math.Abs(value.W)); + } + + public static int abs(int value) + { + return System.Math.Abs(value); + } + + public static int2 abs(int2 value) + { + return new int2(System.Math.Abs(value.X), System.Math.Abs(value.Y)); + } + + public static int3 abs(int3 value) + { + return new int3(System.Math.Abs(value.X), System.Math.Abs(value.Y), System.Math.Abs(value.Z)); + } + + public static int4 abs(int4 value) + { + return new int4(System.Math.Abs(value.X), System.Math.Abs(value.Y), System.Math.Abs(value.Z), System.Math.Abs(value.W)); + } + + #endregion + + #region modf / frac / trunc + + // Splits the value x into fractional and integer parts, each of which has the same sign as x. + public static float modf(float x, out float integerPart) => ScriptGlue.modf_float(x, out integerPart); + + // Splits the value x into fractional and integer parts, each of which has the same sign as x. + public static float2 modf(float2 x, out float2 integerPart) => ScriptGlue.modf_float2(x, out integerPart); + + // Splits the value x into fractional and integer parts, each of which has the same sign as x. + public static float3 modf(float3 x, out float3 integerPart) => ScriptGlue.modf_float3(x, out integerPart); + + // Splits the value x into fractional and integer parts, each of which has the same sign as x. + public static float4 modf(float4 x, out float4 integerPart) => ScriptGlue.modf_float4(x, out integerPart); + + // Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1. + public static float frac(float x) => modf(x, out _); + + // Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1. + public static float2 frac(float2 x) => modf(x, out _); + + // Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1. + public static float3 frac(float3 x) => modf(x, out _); + + // Returns the fractional (or decimal) part of x; which is greater than or equal to 0 and less than 1. + public static float4 frac(float4 x) => modf(x, out _); + + + /// + /// Truncates a floating-point value to the integer component. + /// + public static float trunc(float x) + { + return (float)System.Math.Truncate(x); + } + + /// + /// Truncates a floating-point value to the integer component. + /// + public static float2 trunc(float2 x) + { + return new float2((float)System.Math.Truncate(x.X), (float)System.Math.Truncate(x.Y)); + } + + /// + /// Truncates a floating-point value to the integer component. + /// + public static float3 trunc(float3 x) + { + return new float3((float)System.Math.Truncate(x.X), (float)System.Math.Truncate(x.Y), (float)System.Math.Truncate(x.Z)); + } + + /// + /// Truncates a floating-point value to the integer component. + /// + public static float4 trunc(float4 x) + { + return new float4((float)System.Math.Truncate(x.X), (float)System.Math.Truncate(x.Y), (float)System.Math.Truncate(x.Z), (float)System.Math.Truncate(x.W)); + } + + #endregion + + #region infinity and nan check + + /// Determines if the specified floating-point value is finite. + public static bool2 isfinite(float2 value) + { + return new bool2(!float.IsInfinity(value.X), !float.IsInfinity(value.Y)); + } + + /// Determines if the specified floating-point value is finite. + public static bool3 isfinite(float3 value) + { + return new bool3(!float.IsInfinity(value.X), !float.IsInfinity(value.Y), !float.IsInfinity(value.Z)); + } + + /// Determines if the specified floating-point value is finite. + public static bool4 isfinite(float4 value) + { + return new bool4(!float.IsInfinity(value.X), !float.IsInfinity(value.Y), !float.IsInfinity(value.Z), !float.IsInfinity(value.W)); + } + + /// Determines if the specified value is infinite. + public static bool2 isinf(float2 value) + { + return new bool2(float.IsInfinity(value.X), float.IsInfinity(value.Y)); + } + + /// Determines if the specified value is infinite. + public static bool3 isinf(float3 value) + { + return new bool3(float.IsInfinity(value.X), float.IsInfinity(value.Y), float.IsInfinity(value.Z)); + } + + /// Determines if the specified value is infinite. + public static bool4 isinf(float4 value) + { + return new bool4(float.IsInfinity(value.X), float.IsInfinity(value.Y), float.IsInfinity(value.Z), float.IsInfinity(value.W)); + } + + /// Determines if the specified value is infinite. + public static bool2 isnan(float2 value) + { + return new bool2(float.IsNaN(value.X), float.IsNaN(value.Y)); + } + + /// Determines if the specified value is infinite. + public static bool3 isnan(float3 value) + { + return new bool3(float.IsNaN(value.X), float.IsNaN(value.Y), float.IsNaN(value.Z)); + } + + /// Determines if the specified value is infinite. + public static bool4 isnan(float4 value) + { + return new bool4(float.IsNaN(value.X), float.IsNaN(value.Y), float.IsNaN(value.Z), float.IsNaN(value.W)); + } + +#endregion + +#region Sign + + /// Returns the sign of x. + public static int sign(float x) + { + return System.Math.Sign(x); + } + + /// Returns the sign of x. + public static int2 sign(float2 x) + { + return new int2(System.Math.Sign(x.X), System.Math.Sign(x.Y)); + } + + /// Returns the sign of x. + public static int3 sign(float3 x) + { + return new int3(System.Math.Sign(x.X), System.Math.Sign(x.Y), System.Math.Sign(x.Z)); + } + + /// Returns the sign of x. + public static int4 sign(float4 x) + { + return new int4(System.Math.Sign(x.X), System.Math.Sign(x.Y), System.Math.Sign(x.Z), System.Math.Sign(x.W)); + } + + /// Returns the sign of x. + public static int sign(int x) + { + return System.Math.Sign(x); + } + + /// Returns the sign of x. + public static int2 sign(int2 x) + { + return new int2(System.Math.Sign(x.X), System.Math.Sign(x.Y)); + } + + /// Returns the sign of x. + public static int3 sign(int3 x) + { + return new int3(System.Math.Sign(x.X), System.Math.Sign(x.Y), System.Math.Sign(x.Z)); + } + + /// Returns the sign of x. + public static int4 sign(int4 x) + { + return new int4(System.Math.Sign(x.X), System.Math.Sign(x.Y), System.Math.Sign(x.Z), System.Math.Sign(x.W)); + } + + #endregion + + #region ceil / floor / round + + public static float ceil(float value) + { + return (float)System.Math.Ceiling(value); + } + + public static float2 ceil(float2 value) + { + return new float2((float)System.Math.Ceiling(value.X), (float)System.Math.Ceiling(value.Y)); + } + + public static float3 ceil(float3 value) + { + return new float3((float)System.Math.Ceiling(value.X), (float)System.Math.Ceiling(value.Y), (float)System.Math.Ceiling(value.Z)); + } + + public static float4 ceil(float4 value) + { + return new float4((float)System.Math.Ceiling(value.X), (float)System.Math.Ceiling(value.Y), (float)System.Math.Ceiling(value.Z), (float)System.Math.Ceiling(value.W)); + } + + public static float floor(float value) + { + return (float)System.Math.Floor(value); + } + + public static float2 floor(float2 value) + { + return new float2((float)System.Math.Floor(value.X), (float)System.Math.Floor(value.Y)); + } + + public static float3 floor(float3 value) + { + return new float3((float)System.Math.Floor(value.X), (float)System.Math.Floor(value.Y), (float)System.Math.Floor(value.Z)); + } + + public static float4 floor(float4 value) + { + return new float4((float)System.Math.Floor(value.X), (float)System.Math.Floor(value.Y), (float)System.Math.Floor(value.Z), (float)System.Math.Floor(value.W)); + } + + /// Rounds the specified value to the nearest integer. + public static float round(float value) + { + return (float)System.Math.Round(value); + } + + /// Rounds the specified value to the nearest integer. + public static float2 round(float2 value) + { + return new float2((float)System.Math.Round(value.X), (float)System.Math.Round(value.Y)); + } + + /// Rounds the specified value to the nearest integer. + public static float3 round(float3 value) + { + return new float3((float)System.Math.Round(value.X), (float)System.Math.Round(value.Y), (float)System.Math.Round(value.Z)); + } + + /// Rounds the specified value to the nearest integer. + public static float4 round(float4 value) + { + return new float4((float)System.Math.Round(value.X), (float)System.Math.Round(value.Y), (float)System.Math.Round(value.Z), (float)System.Math.Round(value.W)); + } + + #endregion + + #region min / max + + public static float min(float x, float y) + { + return (float)System.Math.Min(x, y); + } + + public static float2 min(float2 x, float2 y) + { + return new float2((float)System.Math.Min(x.X, y.X), (float)System.Math.Min(x.Y, y.Y)); + } + + public static float3 min(float3 x, float3 y) + { + return new float3((float)System.Math.Min(x.X, y.X), (float)System.Math.Min(x.Y, y.Y), (float)System.Math.Min(x.Z, y.Z)); + } + + public static float4 min(float4 x, float4 y) + { + return new float4((float)System.Math.Min(x.X, y.X), (float)System.Math.Min(x.Y, y.Y), (float)System.Math.Min(x.Z, y.Z), (float)System.Math.Min(x.W, y.W)); + } + + public static float max(float x, float y) + { + return (float)System.Math.Max(x, y); + } + + public static float2 max(float2 x, float2 y) + { + return new float2((float)System.Math.Max(x.X, y.X), (float)System.Math.Max(x.Y, y.Y)); + } + + public static float3 max(float3 x, float3 y) + { + return new float3((float)System.Math.Max(x.X, y.X), (float)System.Math.Max(x.Y, y.Y), (float)System.Math.Max(x.Z, y.Z)); + } + + public static float4 max(float4 x, float4 y) + { + return new float4((float)System.Math.Max(x.X, y.X), (float)System.Math.Max(x.Y, y.Y), (float)System.Math.Max(x.Z, y.Z), (float)System.Math.Max(x.W, y.W)); + } + +#endregion + +#region exp, pow, log + + // TODO: log, log10, log2 + + // Returns x raised to the power of y. + public static float pow(float x, float y) + { + return (float)System.Math.Pow(x, y); + } + + /// Returns x raised to the power of y. + public static float2 pow(float2 x, float2 y) + { + return new float2((float)System.Math.Pow(x.X, y.X), (float)System.Math.Pow(x.Y, y.Y)); + } + + /// Returns x raised to the power of y. + public static float3 pow(float3 x, float3 y) + { + return new float3((float)System.Math.Pow(x.X, y.X), (float)System.Math.Pow(x.Y, y.Y), (float)System.Math.Pow(x.Z, y.Z)); + } + + /// Returns x raised to the power of y. + public static float4 pow(float4 x, float4 y) + { + return new float4((float)System.Math.Pow(x.X, y.X), (float)System.Math.Pow(x.Y, y.Y), (float)System.Math.Pow(x.Z, y.Z), (float)System.Math.Pow(x.W, y.W)); + } + + /// Returns the base-e exponential, or e^x, of the specified value. + public static float exp(float x) + { + return (float)System.Math.Exp(x); + } + + /// Returns the base-e exponential, or e^x, of the specified value. + public static float2 exp(float2 x) + { + return new float2((float)System.Math.Exp(x.X), (float)System.Math.Exp(x.Y)); + } + + /// Returns the base-e exponential, or e^x, of the specified value. + public static float3 exp(float3 x) + { + return new float3((float)System.Math.Exp(x.X), (float)System.Math.Exp(x.Y), (float)System.Math.Exp(x.Z)); + } + + /// Returns the base-e exponential, or e^x, of the specified value. + public static float4 exp(float4 x) + { + return new float4((float)System.Math.Exp(x.X), (float)System.Math.Exp(x.Y), (float)System.Math.Exp(x.Z), (float)System.Math.Exp(x.W)); + } + + /// Returns the base 2 exponential, or 2^x, of the specified value. + public static float exp2(float x) + { + return (float)System.Math.Pow(2, x); + } + + /// Returns the base 2 exponential, or 2^x, of the specified value. + public static float2 exp2(float2 x) + { + return new float2((float)System.Math.Pow(2, x.X), (float)System.Math.Pow(2, x.Y)); + } + + /// Returns the base 2 exponential, or 2^x, of the specified value. + public static float3 exp2(float3 x) + { + return new float3((float)System.Math.Pow(2, x.X), (float)System.Math.Pow(2, x.Y), (float)System.Math.Pow(2, x.Z)); + } + + /// Returns the base 2 exponential, or 2^x, of the specified value. + public static float4 exp2(float4 x) + { + return new float4((float)System.Math.Pow(2, x.X), (float)System.Math.Pow(2, x.Y), (float)System.Math.Pow(2, x.Z), (float)System.Math.Pow(2, x.W)); + } + + #endregion + + #region Degrees / Radians + + public static float toDegrees(float radians) => radians * RadToDeg; + public static float2 toDegrees(float2 radians) => radians * RadToDeg; + public static float3 toDegrees(float3 radians) => radians * RadToDeg; + public static float4 toDegrees(float4 radians) => radians * RadToDeg; + + public static float toRadians(float degrees) => degrees * DegToRad; + public static float2 toRadians(float2 degrees) => degrees * DegToRad; + public static float3 toRadians(float3 degrees) => degrees * DegToRad; + public static float4 toRadians(float4 degrees) => degrees * DegToRad; + +#endregion + +#region Clamp + + public static float clamp(float value, float min, float max) + { + return value < min ? min : (value > max ? max : value); + } + + public static float2 clamp(float2 value, float2 min, float2 max) + { + return new float2(clamp(value.X, min.X, max.X), clamp(value.Y, min.Y, max.Y)); + } + + public static float3 clamp(float3 value, float3 min, float3 max) + { + return new float3(clamp(value.X, min.X, max.X), clamp(value.Y, min.Y, max.Y), clamp(value.Z, min.Z, max.Z)); + } + + public static float4 clamp(float4 value, float4 min, float4 max) + { + return new float4(clamp(value.X, min.X, max.X), clamp(value.Y, min.Y, max.Y), clamp(value.Z, min.Z, max.Z), clamp(value.W, min.W, max.W)); + } + + public static int clamp(int value, int min, int max) + { + return value < min ? min : (value > max ? max : value); + } + + public static int2 clamp(int2 value, int2 min, int2 max) + { + return new int2(clamp(value.X, min.X, max.X), clamp(value.Y, min.Y, max.Y)); + } + + public static int3 clamp(int3 value, int3 min, int3 max) + { + return new int3(clamp(value.X, min.X, max.X), clamp(value.Y, min.Y, max.Y), clamp(value.Z, min.Z, max.Z)); + } + + public static int4 clamp(int4 value, int4 min, int4 max) + { + return new int4(clamp(value.X, min.X, max.X), clamp(value.Y, min.Y, max.Y), clamp(value.Z, min.Z, max.Z), clamp(value.W, min.W, max.W)); + } + + +#endregion + +#region Lerp + + /// Performs a linear interpolation. + // @param x The first vector value. + // @param y The second vector value. + // @param y A value that linearly interpolates between x and y. + public static float lerp(float x, float y, float s) + { + return x + s * (y - x); + } + + /// Performs a linear interpolation. + // @param x The first vector value. + // @param y The second vector value. + // @param y A value that linearly interpolates between x and y. + public static float2 lerp(float2 x, float2 y, float s) + { + return x + s * (y - x); + } + + /// Performs a linear interpolation. + // @param x The first vector value. + // @param y The second vector value. + // @param y A value that linearly interpolates between x and y. + public static float3 lerp(float3 x, float3 y, float s) + { + return x + s * (y - x); + } + + /// Performs a linear interpolation. + // @param x The first vector value. + // @param y The second vector value. + // @param y A value that linearly interpolates between x and y. + public static float4 lerp(float4 x, float4 y, float s) + { + return x + s * (y - x); + } + +#endregion + + // mul? hlsl has like 280 overloads... + + public static float normalize(float value) => 1.0f; + public static float2 normalize(float2 value) => value / length(value); + public static float3 normalize(float3 value) => value / length(value); + public static float4 normalize(float4 value) => value / length(value); + + // pow + +#region Reflect and Refract + + /// Returns a reflection vector using an incident ray and a surface normal. + public static float2 reflect(float2 incident, float2 normal) => incident - 2 * normal * dot(incident, normal); + /// Returns a reflection vector using an incident ray and a surface normal. + public static float3 reflect(float3 incident, float3 normal) => incident - 2 * normal * dot(incident, normal); + /// Returns a reflection vector using an incident ray and a surface normal. + public static float4 reflect(float4 incident, float4 normal) => incident - 2 * normal * dot(incident, normal); + + // Source: https://thebookofshaders.com/glossary/?search=refract + /// Returns a refraction vector using an entering ray, a surface normal, and a refraction index. + public static float2 refract(float2 incident, float2 normal, float refractionIndex) + { + float dot_n_i = dot(normal, incident); + + float k = 1.0f - refractionIndex * refractionIndex * (1.0f - dot_n_i * dot_n_i); + + if (k < 0.0f) + return 0.0f; + else + return refractionIndex * incident - (refractionIndex * dot_n_i + sqrt(k)); + } + + /// Returns a refraction vector using an entering ray, a surface normal, and a refraction index. + public static float3 refract(float3 incident, float3 normal, float refractionIndex) + { + float dot_n_i = dot(normal, incident); + + float k = 1.0f - refractionIndex * refractionIndex * (1.0f - dot_n_i * dot_n_i); + + if (k < 0.0f) + return 0.0f; + else + return refractionIndex * incident - (refractionIndex * dot_n_i + sqrt(k)); + } + + /// Returns a refraction vector using an entering ray, a surface normal, and a refraction index. + public static float4 refract(float4 incident, float4 normal, float refractionIndex) + { + float dot_n_i = dot(normal, incident); + + float k = 1.0f - refractionIndex * refractionIndex * (1.0f - dot_n_i * dot_n_i); + + if (k < 0.0f) + return 0.0f; + else + return refractionIndex * incident - (refractionIndex * dot_n_i + sqrt(k)); + } + + #endregion + + /// Calculates the per component square root of the given value. + public static float sqrt(float value) + { + return (float)System.Math.Sqrt(value); + } + + /// Calculates the per component square root of the given value. + public static float2 sqrt(float2 value) + { + return new float2((float)System.Math.Sqrt(value.X), (float)System.Math.Sqrt(value.Y)); + } + + /// Calculates the per component square root of the given value. + public static float3 sqrt(float3 value) + { + return new float3((float)System.Math.Sqrt(value.X), (float)System.Math.Sqrt(value.Y), (float)System.Math.Sqrt(value.Z)); + } + + /// Calculates the per component square root of the given value. + public static float4 sqrt(float4 value) + { + return new float4((float)System.Math.Sqrt(value.X), (float)System.Math.Sqrt(value.Y), (float)System.Math.Sqrt(value.Z), (float)System.Math.Sqrt(value.W)); + } + + // saturate (I don't think there is a faster way than simply using clamp, so simply use clamp...) + + #region Step / Smoothstep + + /// Compares two values, returning 0 or 1 based on which value is greater. + /// @returns 1 if the x parameter is greater than or equal to the y parameter; otherwise, 0. + public static float step(float y, float x) + { + return (x >= y) ? 1.0f : 0.0f; + } + + /// Compares two values, returning 0 or 1 based on which value is greater. + /// @returns 1 if the x parameter is greater than or equal to the y parameter; otherwise, 0. + public static float2 step(float2 y, float2 x) + { + bool2 b = (x >= y); + + return new float2(b.X ? 1.0f : 0.0f, b.Y ? 1.0f : 0.0f); + } + + /// Compares two values, returning 0 or 1 based on which value is greater. + /// @returns 1 if the x parameter is greater than or equal to the y parameter; otherwise, 0. + public static float3 step(float3 y, float3 x) + { + bool3 b = (x >= y); + + return new float3(b.X ? 1.0f : 0.0f, b.Y ? 1.0f : 0.0f, b.Z ? 1.0f : 0.0f); + } + + /// Compares two values, returning 0 or 1 based on which value is greater. + /// @returns 1 if the x parameter is greater than or equal to the y parameter; otherwise, 0. + public static float4 step(float4 y, float4 x) + { + bool4 b = (x >= y); + + return new float4(b.X ? 1.0f : 0.0f, b.Y ? 1.0f : 0.0f, b.Z ? 1.0f : 0.0f, b.W ? 1.0f : 0.0f); + } + + // Source: https://thebookofshaders.com/glossary/?search=smoothstep + + /// Returns a smooth Hermite interpolation between 0 and 1, if x is in the range [min, max]. + /// @returns Returns 0 if x is less than min; 1 if x is greater than max; otherwise, a value between 0 and 1 if x is in the range [min, max]. + public static float smoothstep(float min, float max, float x) + { + float t = clamp((x - min) / (max - min), 0.0f, 1.0f); + return t * t * (3.0f - 2.0f * t); + } + + /// Returns a smooth Hermite interpolation between 0 and 1, if x is in the range [min, max]. + /// @returns Returns 0 if x is less than min; 1 if x is greater than max; otherwise, a value between 0 and 1 if x is in the range [min, max]. + public static float2 smoothstep(float2 min, float2 max, float2 x) + { + float2 t = clamp((x - min) / (max - min), 0.0f, 1.0f); + return t * t * (3.0f - 2.0f * t); + } + + /// Returns a smooth Hermite interpolation between 0 and 1, if x is in the range [min, max]. + /// @returns Returns 0 if x is less than min; 1 if x is greater than max; otherwise, a value between 0 and 1 if x is in the range [min, max]. + public static float3 smoothstep(float3 min, float3 max, float3 x) + { + float3 t = clamp((x - min) / (max - min), 0.0f, 1.0f); + return t * t * (3.0f - 2.0f * t); + } + + /// Returns a smooth Hermite interpolation between 0 and 1, if x is in the range [min, max]. + /// @returns Returns 0 if x is less than min; 1 if x is greater than max; otherwise, a value between 0 and 1 if x is in the range [min, max]. + public static float4 smoothstep(float4 min, float4 max, float4 x) + { + float4 t = clamp((x - min) / (max - min), 0.0f, 1.0f); + return t * t * (3.0f - 2.0f * t); + } + +#endregion + +#region Reject / Project + + /** + * Calculates the projection of a onto b + */ + public static float2 project(float2 a, float2 b) + { + return (b * (dot(a, b) / dot(b, b))); + } + + /** + * Calculates the projection of a onto b + */ + public static float3 project(float3 a, float3 b) + { + return (b * (dot(a, b) / dot(b, b))); + } + + /** + * Calculates the projection of a onto b + */ + public static float4 project(float4 a, float4 b) + { + return (b * (dot(a, b) / dot(b, b))); + } + + /** + * Calculates the rejection of a from b + */ + public static float2 reject(float2 a, float2 b) + { + return (a - b * (dot(a, b) / dot(b, b))); + } + + /** + * Calculates the rejection of a from b + */ + public static float3 reject(float3 a, float3 b) + { + return (a - b * (dot(a, b) / dot(b, b))); + } + + /** + * Calculates the rejection of a from b + */ + public static float4 reject(float4 a, float4 b) + { + return (a - b * (dot(a, b) / dot(b, b))); + } + +#endregion + +#region dot + + public static float dot(float2 left, float2 right) + { + return left.X * right.X + left.Y * right.Y; + } + + public static float dot(float3 left, float3 right) + { + return left.X * right.X + left.Y * right.Y + left.Z * right.Z; + } + + public static float dot(float4 left, float4 right) + { + return left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + } + + public static int dot(int2 left, int2 right) + { + return left.X * right.X + left.Y * right.Y; + } + + public static int dot(int3 left, int3 right) + { + return left.X * right.X + left.Y * right.Y + left.Z * right.Z; + } + + public static int dot(int4 left, int4 right) + { + return left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W; + } + +#endregion + +#region lengthSq / length / DistanceSq / Distance + + public static float lengthSq(float2 value) => dot(value, value); + + public static float lengthSq(float3 value) => dot(value, value); + + public static float lengthSq(float4 value) => dot(value, value); + + public static int lengthSq(int2 value) => dot(value, value); + + public static int lengthSq(int3 value) => dot(value, value); + + public static int lengthSq(int4 value) => dot(value, value); + + public static float length(float2 value) => (float)System.Math.Sqrt(lengthSq(value)); + + public static float length(float3 value) => (float)System.Math.Sqrt(lengthSq(value)); + + public static float length(float4 value) => (float)System.Math.Sqrt(lengthSq(value)); + + + + public static float distanceSq(float2 left, float2 right) => dot(left, right); + + public static float distanceSq(float3 left, float3 right) => dot(left, right); + + public static float distanceSq(float4 left, float4 right) => dot(left, right); + + public static float distance(float2 left, float2 right) => (float)System.Math.Sqrt(distanceSq(left, right)); + + public static float distance(float3 left, float3 right) => (float)System.Math.Sqrt(distanceSq(left, right)); + + public static float distance(float4 left, float4 right) => (float)System.Math.Sqrt(distanceSq(left, right)); + +#endregion + + public static float3 cross(float3 left, float3 right) + { + return new float3( + left.Y * right.Z - left.Z * right.Y, + left.Z * right.X - left.X * right.Z, + left.X * right.Y - left.Y * right.X); + } + + // transpose und determinante für Matrizen + + // sin, cos, tan, asin, acos, atan, atan2, cosh, sinh, tanh +} diff --git a/ScriptCore/Math/UIntVectors.cs b/ScriptCore/Math/UIntVectors.cs new file mode 100644 index 0000000..18f60e4 --- /dev/null +++ b/ScriptCore/Math/UIntVectors.cs @@ -0,0 +1,46 @@ +using System; +using GlitchyEngine.Math; +using GlitchyEngine.Math.Attributes; + +namespace GlitchyEngine.Math; + +// TODO: Currently no VectorMath-Attribute because -uint results in long + +[Vector(typeof(uint), 2, "uint")] +[VectorLogic] +[ComparableVector] +[VectorCast(typeof(int2), true)] +[VectorCast(typeof(float2), true)] +public partial struct uint2 +{ + public static uint2 operator ~(uint2 value) + { + return new uint2(~value.X, ~value.Y); + } +} + +[Vector(typeof(uint), 3, "uint")] +[VectorLogic] +[ComparableVector] +[VectorCast(typeof(int3), true)] +[VectorCast(typeof(float3), true)] +public partial struct uint3 +{ + public static uint3 operator ~(uint3 value) + { + return new uint3(~value.X, ~value.Y, ~value.Z); + } +} + +[Vector(typeof(uint), 4, "uint")] +[VectorLogic] +[ComparableVector] +[VectorCast(typeof(int4), true)] +[VectorCast(typeof(float4), true)] +public partial struct uint4 +{ + public static uint4 operator ~(uint4 value) + { + return new uint4(~value.X, ~value.Y, ~value.Z, ~value.W); + } +} diff --git a/ScriptCore/Math/Vector2.cs b/ScriptCore/Math/Vector2.cs deleted file mode 100644 index 9d7d53c..0000000 --- a/ScriptCore/Math/Vector2.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace GlitchyEngine.Math; - -public struct Vector2 -{ - public static readonly Vector2 Zero = new(0.0f, 0.0f); - public static readonly Vector2 UnitX = new(1.0f, 0.0f); - public static readonly Vector2 UnitY = new(0.0f, 1.0f); - public static readonly Vector2 One = new(0.0f, 0.0f); - - public const int ComponentCount = 2; - - public float X, Y; - - public Vector2() - { - X = Y = 0.0f; - } - - public Vector2(float x, float y) - { - X = x; - Y = y; - } - - public float this[int index] - { - get - { - switch(index) - { - case 0: return X; - case 1: return Y; - default: throw new IndexOutOfRangeException(); - } - } - - set - { - switch(index) - { - case 0: - X = value; - break; - case 1: - Y = value; - break; - default: throw new IndexOutOfRangeException(); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator +(in Vector2 a, in Vector2 b) => new(a.X + b.X, a.Y + b.Y); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator +(float a, in Vector2 b) => new(a + b.X, a + b.Y); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator +(in Vector2 a, float b) => new(a.X + b, a.Y + b); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator +(in Vector2 a) => a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator -(in Vector2 a, in Vector2 b) => new(a.X - b.X, a.Y - b.Y); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator -(float a, in Vector2 b) => new(a - b.X, a - b.Y); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator -(in Vector2 a, float b) => new(a.X - b, a.Y - b); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator -(in Vector2 a) => new Vector2(-a.X, -a.Y); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator *(in Vector2 a, in Vector2 b) => new(a.X * b.X, a.Y * b.Y); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator *(float a, in Vector2 b) => new(a * b.X, a * b.Y); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator *(in Vector2 a, float b) => new(a.X * b, a.Y * b); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator /(in Vector2 a, in Vector2 b) => new(a.X / b.X, a.Y / b.Y); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator /(float a, in Vector2 b) => new(a / b.X, a / b.Y); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 operator /(in Vector2 a, float b) => new(a.X / b, a.Y / b); - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Vector2 a, Vector2 b) - { - float diffX = a.X - b.X; - float diffY = a.Y - b.Y; - - return diffX * diffX + diffY * diffY < 0.00001f; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Vector2 a, Vector2 b) - { - return !(a == b); - } - - public float Length() - { - return (float)System.Math.Sqrt(X * X + Y * Y); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = X.GetHashCode(); - hashCode = (hashCode * 397) ^ Y.GetHashCode(); - return hashCode; - } - } - - public override string ToString() - { - return $"X:{X}, Y:{Y}"; - } -} \ No newline at end of file diff --git a/ScriptCore/Math/Vector3.cs b/ScriptCore/Math/Vector3.cs deleted file mode 100644 index ab4b524..0000000 --- a/ScriptCore/Math/Vector3.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System; -using System.CodeDom; -using System.Runtime.CompilerServices; - -namespace GlitchyEngine.Math; - -public struct Vector3 -{ - public static readonly Vector3 Zero = new(0.0f, 0.0f, 0.0f); - public static readonly Vector3 UnitX = new(1.0f, 0.0f, 0.0f); - public static readonly Vector3 UnitY = new(0.0f, 1.0f, 0.0f); - public static readonly Vector3 UnitZ = new(0.0f, 0.0f, 1.0f); - public static readonly Vector3 One = new(0.0f, 0.0f, 0.0f); - - public static readonly Vector3 Forward = new(0.0f, 0.0f, 1.0f); - public static readonly Vector3 Backward = new(0.0f, 0.0f, -1.0f); - public static readonly Vector3 Left = new(-1.0f, 0.0f, 0.0f); - public static readonly Vector3 Right = new(1.0f, 0.0f, 0.0f); - public static readonly Vector3 Up = new(0.0f, 1.0f, 0.0f); - public static readonly Vector3 Down = new(0.0f, -1.0f, 0.0f); - - public const int ComponentCount = 3; - - public float X, Y, Z; - - public Vector3() - { - X = Y = Z = 0.0f; - } - - public Vector3(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } - public Vector3(Vector2 xy, float z) - { - X = xy.X; - Y = xy.Y; - Z = z; - } - - public float this[int index] - { - get - { - switch(index) - { - case 0: return X; - case 1: return Y; - case 2: return Z; - default: throw new IndexOutOfRangeException(); - } - } - - set - { - switch(index) - { - case 0: - X = value; - break; - case 1: - Y = value; - break; - case 2: - Z = value; - break; - default: throw new IndexOutOfRangeException(); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator +(in Vector3 a, in Vector3 b) => new(a.X + b.X, a.Y + b.Y, a.Z + b.Z); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator +(float a, in Vector3 b) => new(a + b.X, a + b.Y, a + b.Z); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator +(in Vector3 a, float b) => new(a.X + b, a.Y + b, a.Z + b); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator +(in Vector3 a) => a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator -(in Vector3 a, in Vector3 b) => new(a.X - b.X, a.Y - b.Y, a.Z - b.Z); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator -(float a, in Vector3 b) => new(a - b.X, a - b.Y, a - b.Z); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator -(in Vector3 a, float b) => new(a.X - b, a.Y - b, a.Z - b); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator -(in Vector3 a) => new Vector3(-a.X, -a.Y, -a.Z); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator *(in Vector3 a, in Vector3 b) => new(a.X * b.X, a.Y * b.Y, a.Z * b.Z); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator *(float a, in Vector3 b) => new(a * b.X, a * b.Y, a * b.Z); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator *(in Vector3 a, float b) => new(a.X * b, a.Y * b, a.Z * b); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator /(in Vector3 a, in Vector3 b) => new(a.X / b.X, a.Y / b.Y, a.Z / b.Z); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator /(float a, in Vector3 b) => new(a / b.X, a / b.Y, a / b.Z); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 operator /(in Vector3 a, float b) => new(a.X / b, a.Y / b, a.Z / b); - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Vector3 a, Vector3 b) - { - float diffX = a.X - b.X; - float diffY = a.Y - b.Y; - float diffZ = a.Z - b.Z; - - return diffX * diffX + diffY * diffY + diffZ * diffZ < 0.00001f; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Vector3 a, Vector3 b) - { - return !(a == b); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = X.GetHashCode(); - hashCode = (hashCode * 397) ^ Y.GetHashCode(); - hashCode = (hashCode * 397) ^ Z.GetHashCode(); - return hashCode; - } - } - - public override string ToString() - { - return $"X:{X}, Y:{Y}, Z:{Z}"; - } -} \ No newline at end of file diff --git a/ScriptCore/Math/Vector4.cs b/ScriptCore/Math/Vector4.cs deleted file mode 100644 index cee01c8..0000000 --- a/ScriptCore/Math/Vector4.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace GlitchyEngine.Math; - -public struct Vector4 -{ - //public static readonly Vector3 Zero = new(0.0f, 0.0f, 0.0f); - //public static readonly Vector3 UnitX = new(1.0f, 0.0f, 0.0f); - //public static readonly Vector3 UnitY = new(0.0f, 1.0f, 0.0f); - //public static readonly Vector3 UnitZ = new(0.0f, 0.0f, 1.0f); - //public static readonly Vector3 One = new(0.0f, 0.0f, 0.0f); - - //public static readonly Vector3 Forward = new(0.0f, 0.0f, 1.0f); - //public static readonly Vector3 Backward = new(0.0f, 0.0f, -1.0f); - //public static readonly Vector3 Left = new(-1.0f, 0.0f, 0.0f); - //public static readonly Vector3 Right = new(1.0f, 0.0f, 0.0f); - //public static readonly Vector3 Up = new(0.0f, 1.0f, 0.0f); - //public static readonly Vector3 Down = new(0.0f, -1.0f, 0.0f); - - public const int ComponentCount = 4; - - public float X, Y, Z, W; - - public Vector4() - { - X = Y = Z = W = 0.0f; - } - - public Vector4(float x, float y, float z, float w) - { - X = x; - Y = y; - Z = z; - W = w; - } - - public Vector4(Vector2 xy, Vector2 zw) - { - X = xy.X; - Y = xy.Y; - Z = zw.X; - W = zw.Y; - } - - public Vector4(Vector3 xyz, float w) - { - X = xyz.X; - Y = xyz.Y; - Z = xyz.Z; - W = w; - } - - public float this[int index] - { - get - { - switch (index) - { - case 0: return X; - case 1: return Y; - case 2: return Z; - case 3: return W; - default: throw new IndexOutOfRangeException(); - } - } - - set - { - switch (index) - { - case 0: - X = value; - break; - case 1: - Y = value; - break; - case 2: - Z = value; - break; - case 3: - W = value; - break; - default: throw new IndexOutOfRangeException(); - } - } - } - - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator +(in Vector3 a, in Vector3 b) => new(a.X + b.X, a.Y + b.Y, a.Z + b.Z); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator +(float a, in Vector3 b) => new(a + b.X, a + b.Y, a + b.Z); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator +(in Vector3 a, float b) => new(a.X + b, a.Y + b, a.Z + b); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator +(in Vector3 a) => a; - - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator -(in Vector3 a, in Vector3 b) => new(a.X - b.X, a.Y - b.Y, a.Z - b.Z); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator -(float a, in Vector3 b) => new(a - b.X, a - b.Y, a - b.Z); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator -(in Vector3 a, float b) => new(a.X - b, a.Y - b, a.Z - b); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator -(in Vector3 a) => new Vector3(-a.X, -a.Y, -a.Z); - - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator *(in Vector3 a, in Vector3 b) => new(a.X * b.X, a.Y * b.Y, a.Z * b.Z); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator *(float a, in Vector3 b) => new(a * b.X, a * b.Y, a * b.Z); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator *(in Vector3 a, float b) => new(a.X * b, a.Y * b, a.Z * b); - - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator /(in Vector3 a, in Vector3 b) => new(a.X / b.X, a.Y / b.Y, a.Z / b.Z); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator /(float a, in Vector3 b) => new(a / b.X, a / b.Y, a / b.Z); - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public static Vector3 operator /(in Vector3 a, float b) => new(a.X / b, a.Y / b, a.Z / b); - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Vector4 a, Vector4 b) - { - float diffX = a.X - b.X; - float diffY = a.Y - b.Y; - float diffZ = a.Z - b.Z; - float diffW = a.W - b.W; - - return diffX * diffX + diffY * diffY + diffZ * diffZ + diffW * diffW < 0.00001f; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Vector4 a, Vector4 b) - { - return !(a == b); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = X.GetHashCode(); - hashCode = (hashCode * 397) ^ Y.GetHashCode(); - hashCode = (hashCode * 397) ^ Z.GetHashCode(); - hashCode = (hashCode * 397) ^ Z.GetHashCode(); - return hashCode; - } - } - - public override string ToString() - { - return $"X:{X}, Y:{Y}, Z:{Z}, W:{W}"; - } -} \ No newline at end of file diff --git a/ScriptCore/Math/float2.cs b/ScriptCore/Math/float2.cs deleted file mode 100644 index c6b2ec0..0000000 --- a/ScriptCore/Math/float2.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using GlitchyEngine.Math; -using ScriptCore.Math.Attributes; - -namespace GlitchyEngine.Math; - -[Vector(typeof(float), 2, "float")] -public partial struct float2 -{ -} - -[Vector(typeof(float), 3, "float")] -public partial struct float3 -{ -} - -[Vector(typeof(float), 4, "float")] -public partial struct float4 -{ -} diff --git a/ScriptCore/Physics2D.cs b/ScriptCore/Physics2D.cs index 33b3348..73a3f86 100644 --- a/ScriptCore/Physics2D.cs +++ b/ScriptCore/Physics2D.cs @@ -10,11 +10,11 @@ public static class Physics2D /// /// Gets or sets the gravity of the current scene. /// - public static Vector2 Gravity + public static float2 Gravity { get { - ScriptGlue.Physics2D_GetGravity(out Vector2 gravity); + ScriptGlue.Physics2D_GetGravity(out float2 gravity); return gravity; } set => ScriptGlue.Physics2D_SetGravity(in value); diff --git a/ScriptCore/ScriptCore.csproj b/ScriptCore/ScriptCore.csproj index 56777b2..402ac00 100644 --- a/ScriptCore/ScriptCore.csproj +++ b/ScriptCore/ScriptCore.csproj @@ -11,6 +11,10 @@ + + + + diff --git a/ScriptCore/ScriptCore.csproj.DotSettings b/ScriptCore/ScriptCore.csproj.DotSettings new file mode 100644 index 0000000..d46bfc5 --- /dev/null +++ b/ScriptCore/ScriptCore.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/ScriptCore/ScriptGlue.cs b/ScriptCore/ScriptGlue.cs index 2ed317a..2d3b54e 100644 --- a/ScriptCore/ScriptGlue.cs +++ b/ScriptCore/ScriptGlue.cs @@ -32,31 +32,47 @@ internal static class ScriptGlue #region TransformComponent [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void Transform_GetTranslation(UUID entityId, out Vector3 translation); + internal static extern void Transform_GetTranslation(UUID entityId, out float3 translation); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void Transform_SetTranslation(UUID entityId, in Vector3 translation); + internal static extern void Transform_SetTranslation(UUID entityId, in float3 translation); #endregion TransformComponent #region RigidBody2D [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void RigidBody2D_ApplyForce(UUID entityId, in Vector2 force, Vector2 point, bool wakeUp); + internal static extern void RigidBody2D_ApplyForce(UUID entityId, in float2 force, float2 point, bool wakeUp); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void RigidBody2D_ApplyForceToCenter(UUID entityId, in Vector2 force, bool wakeUp); + internal static extern void RigidBody2D_ApplyForceToCenter(UUID entityId, in float2 force, bool wakeUp); #endregion RigidBody2D #region Physics2D [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void Physics2D_GetGravity(out Vector2 gravity); + internal static extern void Physics2D_GetGravity(out float2 gravity); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void Physics2D_SetGravity(in Vector2 gravity); + internal static extern void Physics2D_SetGravity(in float2 gravity); #endregion Physics2D +#region Math + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern float modf_float(float x, out float integerPart); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern float2 modf_float2(float2 x, out float2 integerPart); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern float3 modf_float3(float3 x, out float3 integerPart); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern float4 modf_float4(float4 x, out float4 integerPart); + +#endregion + } diff --git a/ScriptCoreGenerator/ScriptCoreGenerator.csproj b/ScriptCoreGenerator/ScriptCoreGenerator.csproj index 7615ede..713630e 100644 --- a/ScriptCoreGenerator/ScriptCoreGenerator.csproj +++ b/ScriptCoreGenerator/ScriptCoreGenerator.csproj @@ -4,6 +4,7 @@ netstandard2.0 latest true + true diff --git a/ScriptCoreGenerator/VectorGenerator.cs b/ScriptCoreGenerator/VectorGenerator.cs index ac997e0..b43079a 100644 --- a/ScriptCoreGenerator/VectorGenerator.cs +++ b/ScriptCoreGenerator/VectorGenerator.cs @@ -2,8 +2,10 @@ using System.Collections.Generic; using System.Linq; using System.Net.Mail; +using System.Numerics; using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using static ScriptCoreGenerator.VectorSyntaxReceiver; @@ -16,13 +18,45 @@ public class VectorGenerator : ISourceGenerator public static readonly string[] LowerComponentNames = {"x", "y", "z", "w"}; + private GeneratorExecutionContext _context; + public void Execute(GeneratorExecutionContext context) { + _context = context; + var receiver = (VectorSyntaxReceiver)context.SyntaxReceiver; if (receiver == null) return; StringBuilder builder = new(); + + //foreach(var vector in receiver.Vectors) + //{ + // var symbol = context.Compilation.GetSymbolsWithName(vector.VectorName); + + // var firstSym = symbol.FirstOrDefault(); + + // context.ReportDiagnostic(Diagnostic.Create( + // new DiagnosticDescriptor( + // "SG0001", + // "Non-void method return type", + // "Type {0} iscool!.", + // "yeet", + // DiagnosticSeverity.Error, + // true), firstSym?.Locations.FirstOrDefault(), firstSym?.Name)); + + // //if(symbol.ReturnType.SpecialType != SpecialType.System_Void) + // //{ + // // context.ReportDiagnostic(Diagnostic.Create( + // // new DiagnosticDescriptor( + // // "SG0001", + // // "Non-void method return type", + // // "Method {0} returns {1}. All methods must return void.", + // // "yeet", + // // DiagnosticSeverity.Error, + // // true), symbol.Locations.FirstOrDefault(), symbol.Name, symbol.ReturnType.Name)); + // //} + //} foreach (var vector in receiver.Vectors) { @@ -40,11 +74,35 @@ public class VectorGenerator : ISourceGenerator """); GenerateFields(vector, builder); + GenerateCasts(vector, builder); GenerateConstructors(vector, builder); - //var swizzle = receiver.VectorSwizzle.Swizzles.FirstOrDefault(s => s.VectorName == vector.VectorName); + GenerateArrayAccess(vector, builder); - //if (swizzle != null) + GenerateEqualityOperators(vector, builder); + + if (receiver.ComparableReceiver.ComparableVectors.Contains(vector.VectorName)) + { + GenerateComparisonOperators(vector, builder); + } + + if (receiver.MathReceiver.MathVectors.Contains(vector.VectorName)) + { + GenerateMathOperators(vector, builder); + } + + if (receiver.LogicReceiver.LogicVectors.Contains(vector.VectorName)) + { + GenerateLogicOperators(vector, builder); + } + + foreach (var cast in receiver.CastReceiver.VectorCasts.Where(c => c.FromType == vector.VectorName)) + { + VectorDefinition toVectorDefinition = receiver.Vectors.First(v => v.VectorName == cast.ToType); + + GenerateCastOperator(cast, vector, toVectorDefinition, builder); + } + GenerateSwizzle(vector, builder); builder.Append('}'); @@ -53,6 +111,43 @@ public class VectorGenerator : ISourceGenerator } } + private void GenerateCastOperator(VectorCastSyntaxReceiver.VectorCast cast, VectorDefinition fromVector, VectorDefinition toVector, StringBuilder builder) + { + if (fromVector.ComponentCount != toVector.ComponentCount) + { + _context.ReportDiagnostic(Diagnostic.Create( + new DiagnosticDescriptor( + "SG0001", + "Vector-Dimensions don't match for cast.", + $"Cannot cast from \"{fromVector.VectorName}\" to \"{toVector.VectorName}\" because the dimensions don't match.", + "Vector Generator", + DiagnosticSeverity.Error, + true), fromVector.Struct.GetLocation())); + + return; + } + + StringBuilder castBuilder = new(); + + for (int i = 0; i < fromVector.ComponentCount; i++) + { + if (i != 0) + castBuilder.Append(", "); + + castBuilder.Append($"({toVector.ElementTypeName})value.{ComponentNames[i]}"); + } + + + builder.Append($$""" + public static {{(cast.IsExplicit ? "explicit" : "implicit")}} operator {{cast.ToType}}({{cast.FromType}} value) + { + return new {{cast.ToType}}({{castBuilder}}); + } + + + """); + } + private void GenerateFields(VectorDefinition vector, StringBuilder builder) { builder.Append($"\tpublic {vector.ElementTypeName} "); @@ -68,6 +163,53 @@ public class VectorGenerator : ISourceGenerator builder.Append(";\n\n"); } + private void GenerateCasts(VectorDefinition vector, StringBuilder builder) + { + StringBuilder castBuilder = new(); + + for (int i = 0; i < vector.ComponentCount; i++) + { + if (i != 0) + castBuilder.Append(", "); + + castBuilder.Append("value"); + } + + builder.Append($$""" + public static implicit operator {{vector.VectorName}}({{vector.ElementTypeName}} value) + { + return new {{vector.VectorName}}({{castBuilder}}); + } + + + """); + + // ??? + // StringBuilder constructorBody = new(); + + // for (int i = 0; i < vector.ComponentCount; i++) + // { + // if (i != 0) + // constructorBody.Append(", "); + + // constructorBody.Append("value"); + // } + + // builder.Append($$""" + // public static implicit operator {{}} + // """); + + // String castSingleToVector = scope $""" + + //public static implicit operator Self({typeof(T)} value) + //{{ + // return Self({constructorBody}); + // }} + + + //"""; + } + private void GenerateConstructors(VectorDefinition vector, StringBuilder builder) { GenerateSingleConstructor(vector, builder); @@ -208,6 +350,193 @@ public class VectorGenerator : ISourceGenerator """); } + + private static void GenerateArrayAccess(VectorDefinition vector, StringBuilder builder) + { + StringBuilder getterSwitch = new(); + StringBuilder setterSwitch = new(); + + for (int i = 0; i < vector.ComponentCount; i++) + { + getterSwitch.Append($$""" + + case {{i}}: + return {{ComponentNames[i]}}; + """); + + setterSwitch.Append($$""" + + case {{i}}: + {{ComponentNames[i]}} = value; + break; + """); + } + + + builder.Append($$""" + public {{vector.ElementTypeName}} this[int index] + { + get + { + switch (index) + {{{getterSwitch}} + default: + throw new IndexOutOfRangeException(); + } + } + + set + { + switch (index) + {{{setterSwitch}} + default: + throw new IndexOutOfRangeException(); + } + } + } + + + """); + } + + private void GenerateEqualityOperators(VectorDefinition vector, StringBuilder builder) + { + GenerateComparison("==", vector, builder); + GenerateComparison("!=", vector, builder); + } + + public static void GenerateComparison(string op, VectorDefinition vector, StringBuilder builder) + { + StringBuilder arguments = new(); + + for (int i = 0; i < vector.ComponentCount; i++) + { + if (i != 0) + arguments.Append(", "); + + arguments.Append($"left.{ComponentNames[i]} {op} right.{ComponentNames[i]}"); + } + + builder.Append($$""" + public static bool{{vector.ComponentCount}} operator {{op}}({{vector.VectorName}} left, {{vector.VectorName}} right) + { + return new bool{{vector.ComponentCount}}({{arguments}}); + } + + + """); + } + + private void GenerateComparisonOperators(VectorDefinition vector, StringBuilder builder) + { + GenerateComparison(">", vector, builder); + GenerateComparison(">=", vector, builder); + GenerateComparison("<", vector, builder); + GenerateComparison("<=", vector, builder); + } + + public static void GenerateMathOperators(VectorDefinition vector, StringBuilder builder) + { + GenerateUnaryOperatorOverload("+", vector, builder); + GenerateUnaryOperatorOverload("-", vector, builder); + + GenerateOperatorOverloads("+", vector, builder); + GenerateOperatorOverloads("-", vector, builder); + GenerateOperatorOverloads("*", vector, builder); + GenerateOperatorOverloads("/", vector, builder); + GenerateOperatorOverloads("%", vector, builder); + } + + public static void GenerateUnaryOperatorOverload(string op, VectorDefinition vector, StringBuilder builder) + { + StringBuilder negativeArguments = new(); + + for (int i = 0; i < vector.ComponentCount; i++) + { + if (i != 0) + negativeArguments.Append(", "); + + negativeArguments.Append($"{op}value.{ComponentNames[i]}"); + } + + builder.Append($$""" + public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} value) + { + return new {{vector.VectorName}}({{negativeArguments}}); + } + + + """); + } + + public static void GenerateOperatorOverloads(string op, VectorDefinition vector, StringBuilder builder) + { + StringBuilder arguments = new(); + + // Vector Vector + + for (int i = 0; i < vector.ComponentCount; i++) + { + if (i != 0) + arguments.Append(", "); + + arguments.Append($"left.{ComponentNames[i]} {op} right.{ComponentNames[i]}"); + } + + builder.Append($$""" + public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} left, {{vector.VectorName}} right) + { + return new {{vector.VectorName}}({{arguments}}); + } + + + """); + + // Vector Scalar + arguments.Clear(); + for (int i = 0; i < vector.ComponentCount; i++) + { + if (i != 0) + arguments.Append(", "); + + arguments.Append($"left.{ComponentNames[i]} {op} right"); + } + + builder.Append($$""" + public static {{vector.VectorName}} operator {{op}}({{vector.VectorName}} left, {{vector.ElementTypeName}} right) + { + return new {{vector.VectorName}}({{arguments}}); + } + + + """); + + // Scalar Vector + arguments.Clear(); + for (int i = 0; i < vector.ComponentCount; i++) + { + if (i != 0) + arguments.Append(", "); + + arguments.Append($"left {op} right.{ComponentNames[i]}"); + } + + builder.Append($$""" + public static {{vector.VectorName}} operator {{op}}({{vector.ElementTypeName}} left, {{vector.VectorName}} right) + { + return new {{vector.VectorName}}({{arguments}}); + } + + + """); + } + + public static void GenerateLogicOperators(VectorDefinition vector, StringBuilder builder) + { + GenerateOperatorOverloads("&", vector, builder); + GenerateOperatorOverloads("|", vector, builder); + GenerateOperatorOverloads("^", vector, builder); + } /** * Returns true if the swizzle operator is invalid (same component assigned twice). @@ -304,23 +633,26 @@ public class VectorGenerator : ISourceGenerator public class VectorSyntaxReceiver : ISyntaxReceiver { - public List Vectors { get; } = new(); + public ComparableVectorSyntaxReceiver ComparableReceiver = new(); + public VectorMathSyntaxReceiver MathReceiver = new(); + public VectorLogicSyntaxReceiver LogicReceiver = new(); + public VectorCastSyntaxReceiver CastReceiver = new(); - public VectorSwizzleReceiver VectorSwizzle { get; } = new(); + public List Vectors { get; } = new(); public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { - VectorSwizzle.OnVisitSyntaxNode(syntaxNode); + ComparableReceiver.OnVisitSyntaxNode(syntaxNode); + MathReceiver.OnVisitSyntaxNode(syntaxNode); + LogicReceiver.OnVisitSyntaxNode(syntaxNode); + CastReceiver.OnVisitSyntaxNode(syntaxNode); if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "Vector" } } attr) - { return; - } - + var @struct = attr.GetParent(); var name = @struct.Identifier.Text; - - // ToFullString should like probably always work + var elementTypeName = (attr.ArgumentList.Arguments[0].Expression as TypeOfExpressionSyntax).Type.ToFullString(); var componentCount = (attr.ArgumentList.Arguments[1].Expression as LiteralExpressionSyntax).Token.Value as int?; @@ -355,35 +687,80 @@ public class VectorSyntaxReceiver : ISyntaxReceiver } } -public class VectorSwizzleReceiver : ISyntaxReceiver +public class ComparableVectorSyntaxReceiver : ISyntaxReceiver { - public List Swizzles { get; } = new(); - + public List ComparableVectors { get; } = new(); + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { - if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "SwizzleVector" } } attr) - { + if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "ComparableVector" } } attr) return; - } - + var @struct = attr.GetParent(); var name = @struct.Identifier.Text; - - // var baseName = (attr.ArgumentList.Arguments[0].Expression as LiteralExpressionSyntax).Token.ValueText; - Swizzles.Add(new VectorSwizzle(name));//, baseName)); + ComparableVectors.Add(name); } +} + +public class VectorMathSyntaxReceiver : ISyntaxReceiver +{ + public List MathVectors { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "VectorMath" } } attr) + return; + + var @struct = attr.GetParent(); + var name = @struct.Identifier.Text; + + MathVectors.Add(name); + } +} + +public class VectorLogicSyntaxReceiver : ISyntaxReceiver +{ + public List LogicVectors { get; } = new(); - public class VectorSwizzle + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { - public string VectorName { get; } + if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "VectorLogic" } } attr) + return; - //public string BaseName { get; } + var @struct = attr.GetParent(); + var name = @struct.Identifier.Text; + + LogicVectors.Add(name); + } +} - public VectorSwizzle(string vectorName)//, string baseName) - { - VectorName = vectorName; - //BaseName = baseName; - } +public class VectorCastSyntaxReceiver : ISyntaxReceiver +{ + public List VectorCasts { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is not AttributeSyntax { Name: IdentifierNameSyntax { Identifier.Text: "VectorCast" } } attr) + return; + + var @struct = attr.GetParent(); + var fromType = @struct.Identifier.Text; + + 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 (isExplicit == null) + return; + + VectorCasts.Add(new VectorCast(fromType, toType, isExplicit.Value)); + } + + public record VectorCast (string FromType, string ToType, bool IsExplicit) + { + public string FromType { get; } = FromType; + public string ToType { get; } = ToType; + public bool IsExplicit { get; } = IsExplicit; } }