diff options
Diffstat (limited to 'modules/mono/glue')
16 files changed, 2519 insertions, 72 deletions
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs index 0a1c8322d7..fb37838ffa 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttribute.cs @@ -5,8 +5,8 @@ namespace Godot /// <summary> /// Attribute that changes the RPC mode for the annotated <c>method</c> to the given <see cref="Mode"/>, /// optionally specifying the <see cref="TransferMode"/> and <see cref="TransferChannel"/> (on supported peers). - /// See <see cref="RPCMode"/> and <see cref="TransferMode"/>. By default, methods are not exposed to networking - /// (and RPCs). + /// See <see cref="MultiplayerAPI.RPCMode"/> and <see cref="MultiplayerPeer.TransferModeEnum"/>. + /// By default, methods are not exposed to networking (and RPCs). /// </summary> [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class RPCAttribute : Attribute @@ -14,7 +14,7 @@ namespace Godot /// <summary> /// RPC mode for the annotated method. /// </summary> - public RPCMode Mode { get; } = RPCMode.Disabled; + public MultiplayerAPI.RPCMode Mode { get; } = MultiplayerAPI.RPCMode.Disabled; /// <summary> /// If the method will also be called locally; otherwise, it is only called remotely. @@ -24,7 +24,7 @@ namespace Godot /// <summary> /// Transfer mode for the annotated method. /// </summary> - public TransferMode TransferMode { get; set; } = TransferMode.Reliable; + public MultiplayerPeer.TransferModeEnum TransferMode { get; set; } = MultiplayerPeer.TransferModeEnum.Reliable; /// <summary> /// Transfer channel for the annotated mode. @@ -35,7 +35,7 @@ namespace Godot /// Constructs a <see cref="RPCAttribute"/> instance. /// </summary> /// <param name="mode">The RPC mode to use.</param> - public RPCAttribute(RPCMode mode = RPCMode.Authority) + public RPCAttribute(MultiplayerAPI.RPCMode mode = MultiplayerAPI.RPCMode.Authority) { Mode = mode; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 37bdc42c2d..437878818c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -531,9 +531,9 @@ namespace Godot /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated basis matrix.</returns> - public Basis Rotated(Vector3 axis, real_t phi) + public Basis Rotated(Vector3 axis, real_t angle) { - return new Basis(axis, phi) * this; + return new Basis(axis, angle) * this; } /// <summary> @@ -774,15 +774,15 @@ namespace Godot /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> - public Basis(Vector3 axis, real_t phi) + public Basis(Vector3 axis, real_t angle) { Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); - real_t cosine = Mathf.Cos(phi); + real_t cosine = Mathf.Cos(angle); Row0.x = axisSq.x + cosine * (1.0f - axisSq.x); Row1.y = axisSq.y + cosine * (1.0f - axisSq.y); Row2.z = axisSq.z + cosine * (1.0f - axisSq.z); - real_t sine = Mathf.Sin(phi); + real_t sine = Mathf.Sin(angle); real_t t = 1.0f - cosine; real_t xyzt = axis.x * axis.y * t; @@ -828,6 +828,22 @@ namespace Godot } /// <summary> + /// Constructs a pure scale basis matrix with no rotation or shearing. + /// The scale values are set as the main diagonal of the matrix, + /// and all of the other parts of the matrix are zero. + /// </summary> + /// <param name="scale">The scale Vector3.</param> + /// <returns>A pure scale Basis matrix.</returns> + public static Basis FromScale(Vector3 scale) + { + return new Basis( + scale.x, 0, 0, + 0, scale.y, 0, + 0, 0, scale.z + ); + } + + /// <summary> /// Composes these two basis matrices by multiplying them /// together. This has the effect of transforming the second basis /// (the child) by the first basis (the parent). diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index fc9d40ca48..a6324504fc 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -916,7 +916,7 @@ namespace Godot /// <c>new Color(1 - c.r, 1 - c.g, 1 - c.b, 1 - c.a)</c>. /// </summary> /// <param name="color">The color to invert.</param> - /// <returns>The inverted color</returns> + /// <returns>The inverted color.</returns> public static Color operator -(Color color) { return Colors.White - color; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index bb076a9633..236d0666bc 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -239,11 +239,20 @@ namespace Godot } /// <summary> - /// Converts one or more arguments of any type to string in the best way possible and prints them to the console. The following BBCode tags are supported: b, i, u, s, indent, code, url, center, right, color, bgcolor, fgcolor. Color tags only support named colors such as [code]red[/code], [i]not[/i] hexadecimal color codes. Unsupported tags will be left as-is in standard output. - /// When printing to standard output, the supported subset of BBCode is converted to ANSI escape codes for the terminal emulator to display. Displaying ANSI escape codes is currently only supported on Linux and macOS. Support for ANSI escape codes may vary across terminal emulators, especially for italic and strikethrough. + /// Converts one or more arguments of any type to string in the best way possible + /// and prints them to the console. + /// The following BBCode tags are supported: b, i, u, s, indent, code, url, center, + /// right, color, bgcolor, fgcolor. + /// Color tags only support named colors such as <c>red</c>, not hexadecimal color codes. + /// Unsupported tags will be left as-is in standard output. + /// When printing to standard output, the supported subset of BBCode is converted to + /// ANSI escape codes for the terminal emulator to display. Displaying ANSI escape codes + /// is currently only supported on Linux and macOS. Support for ANSI escape codes may vary + /// across terminal emulators, especially for italic and strikethrough. /// /// Note: Consider using <see cref="PushError(string)"/> and <see cref="PushWarning(string)"/> - /// to print error and warning messages instead of <see cref="Print(object[])"/> or <see cref="PrintRich(object[])"/>. + /// to print error and warning messages instead of <see cref="Print(object[])"/> or + /// <see cref="PrintRich(object[])"/>. /// This distinguishes them from print messages used for debugging purposes, /// while also displaying a stack trace when an error or warning is printed. /// </summary> @@ -253,7 +262,6 @@ namespace Godot /// </code> /// </example> /// <param name="what">Arguments that will be printed.</param> - /// </summary> public static void PrintRich(params object[] what) { godot_icall_GD_print_rich(GetPrintParams(what)); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 63af1c5892..fd97a71e47 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -118,15 +118,15 @@ namespace Godot /// <summary> /// Returns <see langword="true"/> if point is inside the plane. - /// Comparison uses a custom minimum epsilon threshold. + /// Comparison uses a custom minimum tolerance threshold. /// </summary> /// <param name="point">The point to check.</param> - /// <param name="epsilon">The tolerance threshold.</param> + /// <param name="tolerance">The tolerance threshold.</param> /// <returns>A <see langword="bool"/> for whether or not the plane has the point.</returns> - public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon) + public bool HasPoint(Vector3 point, real_t tolerance = Mathf.Epsilon) { real_t dist = _normal.Dot(point) - D; - return Mathf.Abs(dist) <= epsilon; + return Mathf.Abs(dist) <= tolerance; } /// <summary> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs new file mode 100644 index 0000000000..d774021131 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -0,0 +1,820 @@ +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif +using System; +using System.Runtime.InteropServices; + +namespace Godot +{ + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Projection : IEquatable<Projection> + { + /// <summary> + /// Enumerated index values for the planes. + /// </summary> + public enum Planes + { + /// <summary> + /// The projection's near plane. + /// </summary> + Near, + /// <summary> + /// The projection's far plane. + /// </summary> + Far, + /// <summary> + /// The projection's left plane. + /// </summary> + Left, + /// <summary> + /// The projection's top plane. + /// </summary> + Top, + /// <summary> + /// The projection's right plane. + /// </summary> + Right, + /// <summary> + /// The projection's bottom plane. + /// </summary> + Bottom, + } + + /// <summary> + /// The projections's X column. Also accessible by using the index position <c>[0]</c>. + /// </summary> + public Vector4 x; + + /// <summary> + /// The projections's Y column. Also accessible by using the index position <c>[1]</c>. + /// </summary> + public Vector4 y; + + /// <summary> + /// The projections's Z column. Also accessible by using the index position <c>[2]</c>. + /// </summary> + public Vector4 z; + + /// <summary> + /// The projections's W column. Also accessible by using the index position <c>[3]</c>. + /// </summary> + public Vector4 w; + + /// <summary> + /// Constructs a projection from 4 vectors (matrix columns). + /// </summary> + /// <param name="x">The X column, or column index 0.</param> + /// <param name="y">The Y column, or column index 1.</param> + /// <param name="z">The Z column, or column index 2.</param> + /// <param name="w">The W column, or column index 3.</param> + public Projection(Vector4 x, Vector4 y, Vector4 z, Vector4 w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /// <summary> + /// Constructs a new <see cref="Projection"/> from an existing <see cref="Projection"/>. + /// </summary> + /// <param name="proj">The existing <see cref="Projection"/>.</param> + public Projection(Projection proj) + { + x = proj.x; + y = proj.y; + z = proj.z; + w = proj.w; + } + + /// <summary> + /// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>. + /// </summary> + /// <param name="transform">The <see cref="Transform3D"/>.</param> + public Projection(Transform3D transform) + { + x = new Vector4(transform.basis.Row0.x, transform.basis.Row1.x, transform.basis.Row2.x, 0); + y = new Vector4(transform.basis.Row0.y, transform.basis.Row1.y, transform.basis.Row2.y, 0); + z = new Vector4(transform.basis.Row0.z, transform.basis.Row1.z, transform.basis.Row2.z, 0); + w = new Vector4(transform.origin.x, transform.origin.y, transform.origin.z, 1); + } + + /// <summary> + /// Constructs a new <see cref="Transform3D"/> from the <see cref="Projection"/>. + /// </summary> + /// <param name="proj">The <see cref="Projection"/>.</param> + public static explicit operator Transform3D(Projection proj) + { + return new Transform3D( + new Basis( + new Vector3(proj.x.x, proj.x.y, proj.x.z), + new Vector3(proj.y.x, proj.y.y, proj.y.z), + new Vector3(proj.z.x, proj.z.y, proj.z.z) + ), + new Vector3(proj.w.x, proj.w.y, proj.w.z) + ); + } + + public static Projection CreateDepthCorrection(bool flipY) + { + return new Projection( + new Vector4(1, 0, 0, 0), + new Vector4(0, flipY ? -1 : 1, 0, 0), + new Vector4(0, 0, (real_t)0.5, 0), + new Vector4(0, 0, (real_t)0.5, 1) + ); + } + + public static Projection CreateFitAabb(AABB aabb) + { + Vector3 min = aabb.Position; + Vector3 max = aabb.Position + aabb.Size; + + return new Projection( + new Vector4(2 / (max.x - min.x), 0, 0, 0), + new Vector4(0, 2 / (max.y - min.y), 0, 0), + new Vector4(0, 0, 2 / (max.z - min.z), 0), + new Vector4(-(max.x + min.x) / (max.x - min.x), -(max.y + min.y) / (max.y - min.y), -(max.z + min.z) / (max.z - min.z), 1) + ); + } + + public static Projection CreateForHmd(int eye, real_t aspect, real_t intraocularDist, real_t displayWidth, real_t displayToLens, real_t oversample, real_t zNear, real_t zFar) + { + real_t f1 = (intraocularDist * (real_t)0.5) / displayToLens; + real_t f2 = ((displayWidth - intraocularDist) * (real_t)0.5) / displayToLens; + real_t f3 = (displayWidth / (real_t)4.0) / displayToLens; + + real_t add = ((f1 + f2) * (oversample - (real_t)1.0)) / (real_t)2.0; + f1 += add; + f2 += add; + f3 *= oversample; + + f3 /= aspect; + + switch (eye) + { + case 1: + return CreateFrustum(-f2 * zNear, f1 * zNear, -f3 * zNear, f3 * zNear, zNear, zFar); + case 2: + return CreateFrustum(-f1 * zNear, f2 * zNear, -f3 * zNear, f3 * zNear, zNear, zFar); + default: + return Zero; + } + } + + public static Projection CreateFrustum(real_t left, real_t right, real_t bottom, real_t top, real_t near, real_t far) + { + if (right <= left) + { + throw new ArgumentException("right is less or equal to left."); + } + if (top <= bottom) + { + throw new ArgumentException("top is less or equal to bottom."); + } + if (far <= near) + { + throw new ArgumentException("far is less or equal to near."); + } + + real_t x = 2 * near / (right - left); + real_t y = 2 * near / (top - bottom); + + real_t a = (right + left) / (right - left); + real_t b = (top + bottom) / (top - bottom); + real_t c = -(far + near) / (far - near); + real_t d = -2 * far * near / (far - near); + + return new Projection( + new Vector4(x, 0, 0, 0), + new Vector4(0, y, 0, 0), + new Vector4(a, b, c, -1), + new Vector4(0, 0, d, 0) + ); + } + + public static Projection CreateFrustumAspect(real_t size, real_t aspect, Vector2 offset, real_t near, real_t far, bool flipFov) + { + if (!flipFov) + { + size *= aspect; + } + return CreateFrustum(-size / 2 + offset.x, +size / 2 + offset.x, -size / aspect / 2 + offset.y, +size / aspect / 2 + offset.y, near, far); + } + + public static Projection CreateLightAtlasRect(Rect2 rect) + { + return new Projection( + new Vector4(rect.Size.x, 0, 0, 0), + new Vector4(0, rect.Size.y, 0, 0), + new Vector4(0, 0, 1, 0), + new Vector4(rect.Position.x, rect.Position.y, 0, 1) + ); + } + + public static Projection CreateOrthogonal(real_t left, real_t right, real_t bottom, real_t top, real_t zNear, real_t zFar) + { + Projection proj = Projection.Identity; + proj.x.x = (real_t)2.0 / (right - left); + proj.w.x = -((right + left) / (right - left)); + proj.y.y = (real_t)2.0 / (top - bottom); + proj.w.y = -((top + bottom) / (top - bottom)); + proj.z.z = (real_t)(-2.0) / (zFar - zNear); + proj.w.z = -((zFar + zNear) / (zFar - zNear)); + proj.w.w = (real_t)1.0; + return proj; + } + + public static Projection CreateOrthogonalAspect(real_t size, real_t aspect, real_t zNear, real_t zFar, bool flipFov) + { + if (!flipFov) + { + size *= aspect; + } + return CreateOrthogonal(-size / 2, +size / 2, -size / aspect / 2, +size / aspect / 2, zNear, zFar); + } + + public static Projection CreatePerspective(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov) + { + if (flipFov) + { + fovyDegrees = GetFovy(fovyDegrees, (real_t)1.0 / aspect); + } + real_t radians = Mathf.Deg2Rad(fovyDegrees / (real_t)2.0); + real_t deltaZ = zFar - zNear; + real_t sine = Mathf.Sin(radians); + + if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) + { + return Zero; + } + + real_t cotangent = Mathf.Cos(radians) / sine; + + Projection proj = Projection.Identity; + + proj.x.x = cotangent / aspect; + proj.y.y = cotangent; + proj.z.z = -(zFar + zNear) / deltaZ; + proj.z.w = -1; + proj.w.z = -2 * zNear * zFar / deltaZ; + proj.w.w = 0; + + return proj; + } + + public static Projection CreatePerspectiveHmd(real_t fovyDegrees, real_t aspect, real_t zNear, real_t zFar, bool flipFov, int eye, real_t intraocularDist, real_t convergenceDist) + { + if (flipFov) + { + fovyDegrees = GetFovy(fovyDegrees, (real_t)1.0 / aspect); + } + + real_t ymax = zNear * Mathf.Tan(Mathf.Deg2Rad(fovyDegrees / (real_t)2.0)); + real_t xmax = ymax * aspect; + real_t frustumshift = (intraocularDist / (real_t)2.0) * zNear / convergenceDist; + real_t left; + real_t right; + real_t modeltranslation; + switch (eye) + { + case 1: + left = -xmax + frustumshift; + right = xmax + frustumshift; + modeltranslation = intraocularDist / (real_t)2.0; + break; + case 2: + left = -xmax - frustumshift; + right = xmax - frustumshift; + modeltranslation = -intraocularDist / (real_t)2.0; + break; + default: + left = -xmax; + right = xmax; + modeltranslation = (real_t)0.0; + break; + } + Projection proj = CreateFrustum(left, right, -ymax, ymax, zNear, zFar); + Projection cm = Projection.Identity; + cm.w.x = modeltranslation; + return proj * cm; + } + + public real_t Determinant() + { + return x.w * y.z * z.y * w.x - x.z * y.w * z.y * w.x - + x.w * y.y * z.z * w.x + x.y * y.w * z.z * w.x + + x.z * y.y * z.w * w.x - x.y * y.z * z.w * w.x - + x.w * y.z * z.x * w.y + x.z * y.w * z.x * w.y + + x.w * y.x * z.z * w.y - x.x * y.w * z.z * w.y - + x.z * y.x * z.w * w.y + x.x * y.z * z.w * w.y + + x.w * y.y * z.x * w.z - x.y * y.w * z.x * w.z - + x.w * y.x * z.y * w.z + x.x * y.w * z.y * w.z + + x.y * y.x * z.w * w.z - x.x * y.y * z.w * w.z - + x.z * y.y * z.x * w.w + x.y * y.z * z.x * w.w + + x.z * y.x * z.y * w.w - x.x * y.z * z.y * w.w - + x.y * y.x * z.z * w.w + x.x * y.y * z.z * w.w; + } + + public real_t GetAspect() + { + Vector2 vpHe = GetViewportHalfExtents(); + return vpHe.x / vpHe.y; + } + + public real_t GetFov() + { + Plane rightPlane = new Plane(x.w - x.x, y.w - y.x, z.w - z.x, -w.w + w.x).Normalized(); + if (z.x == 0 && z.y == 0) + { + return Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x))) * (real_t)2.0; + } + else + { + Plane leftPlane = new Plane(x.w + x.x, y.w + y.x, z.w + z.x, w.w + w.x).Normalized(); + return Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(leftPlane.Normal.x))) + Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x))); + } + } + + public static real_t GetFovy(real_t fovx, real_t aspect) + { + return Mathf.Rad2Deg(Mathf.Atan(aspect * Mathf.Tan(Mathf.Deg2Rad(fovx) * (real_t)0.5)) * (real_t)2.0); + } + + public real_t GetLodMultiplier() + { + if (IsOrthogonal()) + { + return GetViewportHalfExtents().x; + } + else + { + real_t zn = GetZNear(); + real_t width = GetViewportHalfExtents().x * (real_t)2.0; + return (real_t)1.0 / (zn / width); + } + } + + public int GetPixelsPerMeter(int forPixelWidth) + { + Vector3 result = Xform(new Vector3(1, 0, -1)); + + return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth); + } + + public Plane GetProjectionPlane(Planes plane) + { + Plane newPlane = plane switch + { + Planes.Near => new Plane(x.w + x.z, y.w + y.z, z.w + z.z, w.w + w.z), + Planes.Far => new Plane(x.w - x.z, y.w - y.z, z.w - z.z, w.w - w.z), + Planes.Left => new Plane(x.w + x.x, y.w + y.x, z.w + z.x, w.w + w.x), + Planes.Top => new Plane(x.w - x.y, y.w - y.y, z.w - z.y, w.w - w.y), + Planes.Right => new Plane(x.w - x.x, y.w - y.x, z.w - z.x, w.w - w.x), + Planes.Bottom => new Plane(x.w + x.y, y.w + y.y, z.w + z.y, w.w + w.y), + _ => new Plane(), + }; + newPlane.Normal = -newPlane.Normal; + return newPlane.Normalized(); + } + + public Vector2 GetFarPlaneHalfExtents() + { + var res = GetProjectionPlane(Planes.Far).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); + return new Vector2(res.Value.x, res.Value.y); + } + + public Vector2 GetViewportHalfExtents() + { + var res = GetProjectionPlane(Planes.Near).Intersect3(GetProjectionPlane(Planes.Right), GetProjectionPlane(Planes.Top)); + return new Vector2(res.Value.x, res.Value.y); + } + + public real_t GetZFar() + { + return GetProjectionPlane(Planes.Far).D; + } + + public real_t GetZNear() + { + return -GetProjectionPlane(Planes.Near).D; + } + + public Projection FlippedY() + { + Projection proj = this; + proj.y = -proj.y; + return proj; + } + + public Projection PerspectiveZNearAdjusted(real_t newZNear) + { + Projection proj = this; + real_t zFar = GetZFar(); + real_t zNear = newZNear; + real_t deltaZ = zFar - zNear; + proj.z.z = -(zFar + zNear) / deltaZ; + proj.w.z = -2 * zNear * zFar / deltaZ; + return proj; + } + + public Projection JitterOffseted(Vector2 offset) + { + Projection proj = this; + proj.w.x += offset.x; + proj.w.y += offset.y; + return proj; + } + + public Projection Inverse() + { + Projection proj = this; + int i, j, k; + int[] pvt_i = new int[4]; + int[] pvt_j = new int[4]; /* Locations of pivot matrix */ + real_t pvt_val; /* Value of current pivot element */ + real_t hold; /* Temporary storage */ + real_t determinant = 1.0f; + for (k = 0; k < 4; k++) + { + /* Locate k'th pivot element */ + pvt_val = proj[k][k]; /* Initialize for search */ + pvt_i[k] = k; + pvt_j[k] = k; + for (i = k; i < 4; i++) + { + for (j = k; j < 4; j++) + { + if (Mathf.Abs(proj[i][j]) > Mathf.Abs(pvt_val)) + { + pvt_i[k] = i; + pvt_j[k] = j; + pvt_val = proj[i][j]; + } + } + } + + /* Product of pivots, gives determinant when finished */ + determinant *= pvt_val; + if (Mathf.IsZeroApprox(determinant)) + { + return Zero; + } + + /* "Interchange" rows (with sign change stuff) */ + i = pvt_i[k]; + if (i != k) + { /* If rows are different */ + for (j = 0; j < 4; j++) + { + hold = -proj[k][j]; + proj[k, j] = proj[i][j]; + proj[i, j] = hold; + } + } + + /* "Interchange" columns */ + j = pvt_j[k]; + if (j != k) + { /* If columns are different */ + for (i = 0; i < 4; i++) + { + hold = -proj[i][k]; + proj[i, k] = proj[i][j]; + proj[i, j] = hold; + } + } + + /* Divide column by minus pivot value */ + for (i = 0; i < 4; i++) + { + if (i != k) + { + proj[i, k] /= (-pvt_val); + } + } + + /* Reduce the matrix */ + for (i = 0; i < 4; i++) + { + hold = proj[i][k]; + for (j = 0; j < 4; j++) + { + if (i != k && j != k) + { + proj[i, j] += hold * proj[k][j]; + } + } + } + + /* Divide row by pivot */ + for (j = 0; j < 4; j++) + { + if (j != k) + { + proj[k, j] /= pvt_val; + } + } + + /* Replace pivot by reciprocal (at last we can touch it). */ + proj[k, k] = (real_t)1.0 / pvt_val; + } + + /* That was most of the work, one final pass of row/column interchange */ + /* to finish */ + for (k = 4 - 2; k >= 0; k--) + { /* Don't need to work with 1 by 1 corner*/ + i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */ + if (i != k) + { /* If rows are different */ + for (j = 0; j < 4; j++) + { + hold = proj[k][j]; + proj[k, j] = -proj[i][j]; + proj[i, j] = hold; + } + } + + j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */ + if (j != k) + { /* If columns are different */ + for (i = 0; i < 4; i++) + { + hold = proj[i][k]; + proj[i, k] = -proj[i][j]; + proj[i, j] = hold; + } + } + } + return proj; + } + + public bool IsOrthogonal() + { + return w.w == (real_t)1.0; + } + + /// <summary> + /// Composes these two projections by multiplying them + /// together. This has the effect of applying the right + /// and then the left projection. + /// </summary> + /// <param name="left">The parent transform.</param> + /// <param name="right">The child transform.</param> + /// <returns>The composed projection.</returns> + public static Projection operator *(Projection left, Projection right) + { + return new Projection( + new Vector4( + left.x.x * right.x.x + left.y.x * right.x.y + left.z.x * right.x.z + left.w.x * right.x.w, + left.x.y * right.x.x + left.y.y * right.x.y + left.z.y * right.x.z + left.w.y * right.x.w, + left.x.z * right.x.x + left.y.z * right.x.y + left.z.z * right.x.z + left.w.z * right.x.w, + left.x.w * right.x.x + left.y.w * right.x.y + left.z.w * right.x.z + left.w.w * right.x.w + ), new Vector4( + left.x.x * right.y.x + left.y.x * right.y.y + left.z.x * right.y.z + left.w.x * right.y.w, + left.x.y * right.y.x + left.y.y * right.y.y + left.z.y * right.y.z + left.w.y * right.y.w, + left.x.z * right.y.x + left.y.z * right.y.y + left.z.z * right.y.z + left.w.z * right.y.w, + left.x.w * right.y.x + left.y.w * right.y.y + left.z.w * right.y.z + left.w.w * right.y.w + ), new Vector4( + left.x.x * right.z.x + left.y.x * right.z.y + left.z.x * right.z.z + left.w.x * right.z.w, + left.x.y * right.z.x + left.y.y * right.z.y + left.z.y * right.z.z + left.w.y * right.z.w, + left.x.z * right.z.x + left.y.z * right.z.y + left.z.z * right.z.z + left.w.z * right.z.w, + left.x.w * right.z.x + left.y.w * right.z.y + left.z.w * right.z.z + left.w.w * right.z.w + ), new Vector4( + left.x.x * right.w.x + left.y.x * right.w.y + left.z.x * right.w.z + left.w.x * right.w.w, + left.x.y * right.w.x + left.y.y * right.w.y + left.z.y * right.w.z + left.w.y * right.w.w, + left.x.z * right.w.x + left.y.z * right.w.y + left.z.z * right.w.z + left.w.z * right.w.w, + left.x.w * right.w.x + left.y.w * right.w.y + left.z.w * right.w.z + left.w.w * right.w.w + ) + ); + } + + /// <summary> + /// Returns a vector transformed (multiplied) by this projection. + /// </summary> + /// <param name="proj">The projection to apply.</param> + /// <param name="v">A vector to transform.</param> + /// <returns>The transformed vector.</returns> + public static Vector4 operator *(Projection proj, Vector4 v) + { + return new Vector4( + proj.x.x * v.x + proj.y.x * v.y + proj.z.x * v.z + proj.w.x * v.w, + proj.x.y * v.x + proj.y.y * v.y + proj.z.y * v.z + proj.w.y * v.w, + proj.x.z * v.x + proj.y.z * v.y + proj.z.z * v.z + proj.w.z * v.w, + proj.x.w * v.x + proj.y.w * v.y + proj.z.w * v.z + proj.w.w * v.w + ); + } + + /// <summary> + /// Returns <see langword="true"/> if the projections are exactly equal. + /// </summary> + /// <param name="left">The left projection.</param> + /// <param name="right">The right projection.</param> + /// <returns>Whether or not the projections are exactly equal.</returns> + public static bool operator ==(Projection left, Projection right) + { + return left.Equals(right); + } + + /// <summary> + /// Returns <see langword="true"/> if the projections are not exactly equal. + /// </summary> + /// <param name="left">The left projection.</param> + /// <param name="right">The right projection.</param> + /// <returns>Whether or not the projections are not exactly equal.</returns> + public static bool operator !=(Projection left, Projection right) + { + return !left.Equals(right); + } + + /// <summary> + /// Access whole columns in the form of <see cref="Vector4"/>. + /// </summary> + /// <param name="column">Which column vector.</param> + public Vector4 this[int column] + { + get + { + switch (column) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + default: + throw new IndexOutOfRangeException(); + } + } + set + { + switch (column) + { + case 0: + x = value; + return; + case 1: + y = value; + return; + case 2: + z = value; + return; + case 3: + w = value; + return; + default: + throw new IndexOutOfRangeException(); + } + } + } + + /// <summary> + /// Access single values. + /// </summary> + /// <param name="column">Which column vector.</param> + /// <param name="row">Which row of the column.</param> + public real_t this[int column, int row] + { + get + { + switch (column) + { + case 0: + return x[row]; + case 1: + return y[row]; + case 2: + return z[row]; + case 3: + return w[row]; + default: + throw new IndexOutOfRangeException(); + } + } + set + { + switch (column) + { + case 0: + x[row] = value; + return; + case 1: + y[row] = value; + return; + case 2: + z[row] = value; + return; + case 3: + w[row] = value; + return; + default: + throw new IndexOutOfRangeException(); + } + } + } + + /// <summary> + /// Returns a vector transformed (multiplied) by this projection. + /// </summary> + /// <param name="v">A vector to transform.</param> + /// <returns>The transformed vector.</returns> + private Vector3 Xform(Vector3 v) + { + Vector3 ret = new Vector3( + x.x * v.x + y.x * v.y + z.x * v.z + w.x, + x.y * v.x + y.y * v.y + z.y * v.z + w.y, + x.z * v.x + y.z * v.y + z.z * v.z + w.z + ); + return ret / (x.w * v.x + y.w * v.y + z.w * v.z + w.w); + } + + // Constants + private static readonly Projection _zero = new Projection( + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0), + new Vector4(0, 0, 0, 0) + ); + private static readonly Projection _identity = new Projection( + new Vector4(1, 0, 0, 0), + new Vector4(0, 1, 0, 0), + new Vector4(0, 0, 1, 0), + new Vector4(0, 0, 0, 1) + ); + + /// <summary> + /// Zero projection, a projection with all components set to <c>0</c>. + /// </summary> + /// <value>Equivalent to <c>new Projection(Vector4.Zero, Vector4.Zero, Vector4.Zero, Vector4.Zero)</c>.</value> + public static Projection Zero { get { return _zero; } } + + /// <summary> + /// The identity projection, with no distortion applied. + /// This is used as a replacement for <c>Projection()</c> in GDScript. + /// Do not use <c>new Projection()</c> with no arguments in C#, because it sets all values to zero. + /// </summary> + /// <value>Equivalent to <c>new Projection(new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), new Vector4(0, 0, 1, 0), new Vector4(0, 0, 0, 1))</c>.</value> + public static Projection Identity { get { return _identity; } } + + /// <summary> + /// Serves as the hash function for <see cref="Projection"/>. + /// </summary> + /// <returns>A hash code for this projection.</returns> + public override int GetHashCode() + { + return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); + } + + /// <summary> + /// Converts this <see cref="Projection"/> to a string. + /// </summary> + /// <returns>A string representation of this projection.</returns> + public override string ToString() + { + return $"{x.x}, {x.y}, {x.z}, {x.w}\n{y.x}, {y.y}, {y.z}, {y.w}\n{z.x}, {z.y}, {z.z}, {z.w}\n{w.x}, {w.y}, {w.z}, {w.w}\n"; + } + + /// <summary> + /// Converts this <see cref="Projection"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this projection.</returns> + public string ToString(string format) + { + return $"{x.x.ToString(format)}, {x.y.ToString(format)}, {x.z.ToString(format)}, {x.w.ToString(format)}\n" + + $"{y.x.ToString(format)}, {y.y.ToString(format)}, {y.z.ToString(format)}, {y.w.ToString(format)}\n" + + $"{z.x.ToString(format)}, {z.y.ToString(format)}, {z.z.ToString(format)}, {z.w.ToString(format)}\n" + + $"{w.x.ToString(format)}, {w.y.ToString(format)}, {w.z.ToString(format)}, {w.w.ToString(format)}\n"; + } + + /// <summary> + /// Returns <see langword="true"/> if the projection is exactly equal + /// to the given object (<see paramref="obj"/>). + /// </summary> + /// <param name="obj">The object to compare with.</param> + /// <returns>Whether or not the vector and the object are equal.</returns> + public override bool Equals(object obj) + { + if (obj is Projection) + { + return Equals((Projection)obj); + } + return false; + } + + /// <summary> + /// Returns <see langword="true"/> if the projections are exactly equal. + /// </summary> + /// <param name="other">The other projection.</param> + /// <returns>Whether or not the projections are exactly equal.</returns> + public bool Equals(Projection other) + { + return x == other.x && y == other.y && z == other.z && w == other.w; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs index 5680c9d55a..da01300586 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs @@ -18,7 +18,7 @@ namespace Godot public StringName Name => _signalName; /// <summary> - /// Creates a new <see cref="Signal"/> with the name <paramref name="name"/> + /// Creates a new <see cref="SignalInfo"/> with the name <paramref name="name"/> /// in the specified <paramref name="owner"/>. /// </summary> /// <param name="owner">Object that contains the signal.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 89947899cb..68d097eb4e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -297,17 +297,33 @@ namespace Godot } /// <summary> - /// Rotates the transform by <paramref name="angle"/> (in radians), using matrix multiplication. + /// Rotates the transform by <paramref name="angle"/> (in radians). + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform2D Rotated(real_t phi) + public Transform2D Rotated(real_t angle) { - return this * new Transform2D(phi, new Vector2()); + return this * new Transform2D(angle, new Vector2()); } /// <summary> - /// Scales the transform by the given scaling factor, using matrix multiplication. + /// Rotates the transform by <paramref name="angle"/> (in radians). + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="angle">The angle to rotate, in radians.</param> + /// <returns>The rotated transformation matrix.</returns> + public Transform2D RotatedLocal(real_t angle) + { + return new Transform2D(angle, new Vector2()) * this; + } + + /// <summary> + /// Scales the transform by the given scaling factor. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> @@ -320,12 +336,19 @@ namespace Godot return copy; } - private void ScaleBasis(Vector2 scale) + /// <summary> + /// Scales the transform by the given scaling factor. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="scale">The scale to introduce.</param> + /// <returns>The scaled transformation matrix.</returns> + public Transform2D ScaledLocal(Vector2 scale) { - x.x *= scale.x; - x.y *= scale.y; - y.x *= scale.x; - y.y *= scale.y; + Transform2D copy = this; + copy.x *= scale; + copy.y *= scale; + return copy; } private real_t Tdotx(Vector2 with) @@ -339,17 +362,29 @@ namespace Godot } /// <summary> - /// Translates the transform by the given <paramref name="offset"/>, - /// relative to the transform's basis vectors. - /// - /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>, - /// this does not use matrix multiplication. + /// Translates the transform by the given <paramref name="offset"/>. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> public Transform2D Translated(Vector2 offset) { Transform2D copy = this; + copy.origin += offset; + return copy; + } + + /// <summary> + /// Translates the transform by the given <paramref name="offset"/>. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="offset">The offset to translate by.</param> + /// <returns>The translated matrix.</returns> + public Transform2D TranslatedLocal(Vector2 offset) + { + Transform2D copy = this; copy.origin += copy.BasisXform(offset); return copy; } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 7b211b6577..9eaf4f3252 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -186,19 +186,38 @@ namespace Godot } /// <summary> - /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians), - /// using matrix multiplication. The axis must be a normalized vector. + /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians). + /// The axis must be a normalized vector. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform3D Rotated(Vector3 axis, real_t phi) + public Transform3D Rotated(Vector3 axis, real_t angle) { - return new Transform3D(new Basis(axis, phi), new Vector3()) * this; + return new Transform3D(new Basis(axis, angle), new Vector3()) * this; } /// <summary> - /// Scales the transform by the given 3D scaling factor, using matrix multiplication. + /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians). + /// The axis must be a normalized vector. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="axis">The axis to rotate around. Must be normalized.</param> + /// <param name="angle">The angle to rotate, in radians.</param> + /// <returns>The rotated transformation matrix.</returns> + public Transform3D RotatedLocal(Vector3 axis, real_t angle) + { + Basis tmpBasis = new Basis(axis, angle); + return new Transform3D(basis * tmpBasis, origin); + } + + /// <summary> + /// Scales the transform by the given 3D <paramref name="scale"/> factor. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> @@ -207,6 +226,19 @@ namespace Godot return new Transform3D(basis.Scaled(scale), origin * scale); } + /// <summary> + /// Scales the transform by the given 3D <paramref name="scale"/> factor. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="scale">The scale to introduce.</param> + /// <returns>The scaled transformation matrix.</returns> + public Transform3D ScaledLocal(Vector3 scale) + { + Basis tmpBasis = Basis.FromScale(scale); + return new Transform3D(basis * tmpBasis, origin); + } + private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) { // Make rotation matrix @@ -231,21 +263,31 @@ namespace Godot } /// <summary> - /// Translates the transform by the given <paramref name="offset"/>, - /// relative to the transform's basis vectors. - /// - /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>, - /// this does not use matrix multiplication. + /// Translates the transform by the given <paramref name="offset"/>. + /// The operation is done in the parent/global frame, equivalent to + /// multiplying the matrix from the left. /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> public Transform3D Translated(Vector3 offset) { + return new Transform3D(basis, origin + offset); + } + + /// <summary> + /// Translates the transform by the given <paramref name="offset"/>. + /// The operation is done in the local frame, equivalent to + /// multiplying the matrix from the right. + /// </summary> + /// <param name="offset">The offset to translate by.</param> + /// <returns>The translated matrix.</returns> + public Transform3D TranslatedLocal(Vector3 offset) + { return new Transform3D(basis, new Vector3 ( - origin[0] += basis.Row0.Dot(offset), - origin[1] += basis.Row1.Dot(offset), - origin[2] += basis.Row2.Dot(offset) + origin[0] + basis.Row0.Dot(offset), + origin[1] + basis.Row1.Dot(offset), + origin[2] + basis.Row2.Dot(offset) )); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 7bdbe1c28b..67f70390dd 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -495,10 +495,10 @@ namespace Godot /// </summary> /// <param name="angle">The angle to rotate by, in radians.</param> /// <returns>The rotated vector.</returns> - public Vector2 Rotated(real_t phi) + public Vector2 Rotated(real_t angle) { - real_t sine = Mathf.Sin(phi); - real_t cosi = Mathf.Cos(phi); + real_t sine = Mathf.Sin(angle); + real_t cosi = Mathf.Cos(angle); return new Vector2( x * cosi - y * sine, x * sine + y * cosi); @@ -534,7 +534,7 @@ namespace Godot /// /// This method also handles interpolating the lengths if the input vectors /// have different lengths. For the special case of one or both input vectors - /// having zero length, this method behaves like <see cref="Lerp"/>. + /// having zero length, this method behaves like <see cref="Lerp(Vector2, real_t)"/>. /// </summary> /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 480165d44a..67a98efc2d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -515,7 +515,7 @@ namespace Godot /// <param name="axis">The vector to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate by, in radians.</param> /// <returns>The rotated vector.</returns> - public Vector3 Rotated(Vector3 axis, real_t phi) + public Vector3 Rotated(Vector3 axis, real_t angle) { #if DEBUG if (!axis.IsNormalized()) @@ -523,7 +523,7 @@ namespace Godot throw new ArgumentException("Argument is not normalized", nameof(axis)); } #endif - return new Basis(axis, phi).Xform(this); + return new Basis(axis, angle).Xform(this); } /// <summary> @@ -574,7 +574,7 @@ namespace Godot /// /// This method also handles interpolating the lengths if the input vectors /// have different lengths. For the special case of one or both input vectors - /// having zero length, this method behaves like <see cref="Lerp"/>. + /// having zero length, this method behaves like <see cref="Lerp(Vector3, real_t)"/>. /// </summary> /// <param name="to">The destination vector for interpolation.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> @@ -620,22 +620,6 @@ namespace Godot ); } - /// <summary> - /// Returns a diagonal matrix with the vector as main diagonal. - /// - /// This is equivalent to a <see cref="Basis"/> with no rotation or shearing and - /// this vector's components set as the scale. - /// </summary> - /// <returns>A <see cref="Basis"/> with the vector as its main diagonal.</returns> - public Basis ToDiagonalMatrix() - { - return new Basis( - x, 0, 0, - 0, y, 0, - 0, 0, z - ); - } - // Constants private static readonly Vector3 _zero = new Vector3(0, 0, 0); private static readonly Vector3 _one = new Vector3(1, 1, 1); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs new file mode 100644 index 0000000000..4af817455c --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs @@ -0,0 +1,832 @@ +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif +using System; +using System.Runtime.InteropServices; + +namespace Godot +{ + /// <summary> + /// 4-element structure that can be used to represent positions in 4D space or any other pair of numeric values. + /// </summary> + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector4 : IEquatable<Vector4> + { + /// <summary> + /// Enumerated index values for the axes. + /// Returned by <see cref="MaxAxisIndex"/> and <see cref="MinAxisIndex"/>. + /// </summary> + public enum Axis + { + /// <summary> + /// The vector's X axis. + /// </summary> + X = 0, + /// <summary> + /// The vector's Y axis. + /// </summary> + Y, + /// <summary> + /// The vector's Z axis. + /// </summary> + Z, + /// <summary> + /// The vector's W axis. + /// </summary> + W + } + + /// <summary> + /// The vector's X component. Also accessible by using the index position <c>[0]</c>. + /// </summary> + public real_t x; + + /// <summary> + /// The vector's Y component. Also accessible by using the index position <c>[1]</c>. + /// </summary> + public real_t y; + + /// <summary> + /// The vector's Z component. Also accessible by using the index position <c>[2]</c>. + /// </summary> + public real_t z; + + /// <summary> + /// The vector's W component. Also accessible by using the index position <c>[3]</c>. + /// </summary> + public real_t w; + + /// <summary> + /// Access vector components using their index. + /// </summary> + /// <exception cref="IndexOutOfRangeException"> + /// Thrown when the given the <paramref name="index"/> is not 0, 1, 2 or 3. + /// </exception> + /// <value> + /// <c>[0]</c> is equivalent to <see cref="x"/>, + /// <c>[1]</c> is equivalent to <see cref="y"/>, + /// <c>[2]</c> is equivalent to <see cref="z"/>. + /// <c>[3]</c> is equivalent to <see cref="w"/>. + /// </value> + public real_t 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; + return; + case 1: + y = value; + return; + case 2: + z = value; + return; + case 3: + w = value; + return; + default: + throw new IndexOutOfRangeException(); + } + } + } + + /// <summary> + /// Helper method for deconstruction into a tuple. + /// </summary> + public void Deconstruct(out real_t x, out real_t y, out real_t z, out real_t w) + { + x = this.x; + y = this.y; + z = this.z; + w = this.w; + } + + internal void Normalize() + { + real_t lengthsq = LengthSquared(); + + if (lengthsq == 0) + { + x = y = z = w = 0f; + } + else + { + real_t length = Mathf.Sqrt(lengthsq); + x /= length; + y /= length; + z /= length; + w /= length; + } + } + + /// <summary> + /// Returns a new vector with all components in absolute values (i.e. positive). + /// </summary> + /// <returns>A vector with <see cref="Mathf.Abs(real_t)"/> called on each component.</returns> + public Vector4 Abs() + { + return new Vector4(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z), Mathf.Abs(w)); + } + + /// <summary> + /// Returns a new vector with all components rounded up (towards positive infinity). + /// </summary> + /// <returns>A vector with <see cref="Mathf.Ceil"/> called on each component.</returns> + public Vector4 Ceil() + { + return new Vector4(Mathf.Ceil(x), Mathf.Ceil(y), Mathf.Ceil(z), Mathf.Ceil(w)); + } + + /// <summary> + /// Returns a new vector with all components clamped between the + /// components of <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(real_t, real_t, real_t)"/>. + /// </summary> + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector4 Clamp(Vector4 min, Vector4 max) + { + return new Vector4 + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y), + Mathf.Clamp(z, min.z, max.z), + Mathf.Clamp(w, min.w, max.w) + ); + } + + /// <summary> + /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector, + /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>. + /// </summary> + /// <param name="b">The destination vector.</param> + /// <param name="preA">A vector before this vector.</param> + /// <param name="postB">A vector after <paramref name="b"/>.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <returns>The interpolated vector.</returns> + public Vector4 CubicInterpolate(Vector4 b, Vector4 preA, Vector4 postB, real_t weight) + { + return new Vector4 + ( + Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight), + Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight), + Mathf.CubicInterpolate(y, b.z, preA.z, postB.z, weight), + Mathf.CubicInterpolate(w, b.w, preA.w, postB.w, weight) + ); + } + + /// <summary> + /// Returns the normalized vector pointing from this vector to <paramref name="to"/>. + /// </summary> + /// <param name="to">The other vector to point towards.</param> + /// <returns>The direction from this vector to <paramref name="to"/>.</returns> + public Vector4 DirectionTo(Vector4 to) + { + Vector4 ret = new Vector4(to.x - x, to.y - y, to.z - z, to.w - w); + ret.Normalize(); + return ret; + } + + /// <summary> + /// Returns the squared distance between this vector and <paramref name="to"/>. + /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if + /// you need to compare vectors or need the squared distance for some formula. + /// </summary> + /// <param name="to">The other vector to use.</param> + /// <returns>The squared distance between the two vectors.</returns> + public real_t DistanceSquaredTo(Vector4 to) + { + return (to - this).LengthSquared(); + } + + /// <summary> + /// Returns the distance between this vector and <paramref name="to"/>. + /// </summary> + /// <param name="to">The other vector to use.</param> + /// <returns>The distance between the two vectors.</returns> + public real_t DistanceTo(Vector4 to) + { + return (to - this).Length(); + } + + /// <summary> + /// Returns the dot product of this vector and <paramref name="with"/>. + /// </summary> + /// <param name="with">The other vector to use.</param> + /// <returns>The dot product of the two vectors.</returns> + public real_t Dot(Vector4 with) + { + return (x * with.x) + (y * with.y) + (z * with.z) + (w + with.w); + } + + /// <summary> + /// Returns a new vector with all components rounded down (towards negative infinity). + /// </summary> + /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns> + public Vector4 Floor() + { + return new Vector4(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z), Mathf.Floor(w)); + } + + /// <summary> + /// Returns the inverse of this vector. This is the same as <c>new Vector4(1 / v.x, 1 / v.y, 1 / v.z, 1 / v.w)</c>. + /// </summary> + /// <returns>The inverse of this vector.</returns> + public Vector4 Inverse() + { + return new Vector4(1 / x, 1 / y, 1 / z, 1 / w); + } + + /// <summary> + /// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise. + /// </summary> + /// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns> + public bool IsNormalized() + { + return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon; + } + + /// <summary> + /// Returns the length (magnitude) of this vector. + /// </summary> + /// <seealso cref="LengthSquared"/> + /// <returns>The length of this vector.</returns> + public real_t Length() + { + real_t x2 = x * x; + real_t y2 = y * y; + real_t z2 = z * z; + real_t w2 = w * w; + + return Mathf.Sqrt(x2 + y2 + z2 + w2); + } + + /// <summary> + /// Returns the squared length (squared magnitude) of this vector. + /// This method runs faster than <see cref="Length"/>, so prefer it if + /// you need to compare vectors or need the squared length for some formula. + /// </summary> + /// <returns>The squared length of this vector.</returns> + public real_t LengthSquared() + { + real_t x2 = x * x; + real_t y2 = y * y; + real_t z2 = z * z; + real_t w2 = w * w; + + return x2 + y2 + z2 + w2; + } + + /// <summary> + /// Returns the result of the linear interpolation between + /// this vector and <paramref name="to"/> by amount <paramref name="weight"/>. + /// </summary> + /// <param name="to">The destination vector for interpolation.</param> + /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> + /// <returns>The resulting vector of the interpolation.</returns> + public Vector4 Lerp(Vector4 to, real_t weight) + { + return new Vector4 + ( + Mathf.Lerp(x, to.x, weight), + Mathf.Lerp(y, to.y, weight), + Mathf.Lerp(z, to.z, weight), + Mathf.Lerp(w, to.w, weight) + ); + } + + /// <summary> + /// Returns the axis of the vector's highest value. See <see cref="Axis"/>. + /// If all components are equal, this method returns <see cref="Axis.X"/>. + /// </summary> + /// <returns>The index of the highest axis.</returns> + public Axis MaxAxisIndex() + { + int max_index = 0; + real_t max_value = x; + for (int i = 1; i < 4; i++) + { + if (this[i] > max_value) + { + max_index = i; + max_value = this[i]; + } + } + return (Axis)max_index; + } + + /// <summary> + /// Returns the axis of the vector's lowest value. See <see cref="Axis"/>. + /// If all components are equal, this method returns <see cref="Axis.W"/>. + /// </summary> + /// <returns>The index of the lowest axis.</returns> + public Axis MinAxisIndex() + { + int min_index = 0; + real_t min_value = x; + for (int i = 1; i < 4; i++) + { + if (this[i] <= min_value) + { + min_index = i; + min_value = this[i]; + } + } + return (Axis)min_index; + } + + /// <summary> + /// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>. + /// </summary> + /// <returns>A normalized version of the vector.</returns> + public Vector4 Normalized() + { + Vector4 v = this; + v.Normalize(); + return v; + } + + /// <summary> + /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components + /// and <paramref name="mod"/>. + /// </summary> + /// <param name="mod">A value representing the divisor of the operation.</param> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>. + /// </returns> + public Vector4 PosMod(real_t mod) + { + return new Vector4( + Mathf.PosMod(x, mod), + Mathf.PosMod(y, mod), + Mathf.PosMod(z, mod), + Mathf.PosMod(w, mod) + ); + } + + /// <summary> + /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components + /// and <paramref name="modv"/>'s components. + /// </summary> + /// <param name="modv">A vector representing the divisors of the operation.</param> + /// <returns> + /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components. + /// </returns> + public Vector4 PosMod(Vector4 modv) + { + return new Vector4( + Mathf.PosMod(x, modv.x), + Mathf.PosMod(y, modv.y), + Mathf.PosMod(z, modv.z), + Mathf.PosMod(w, modv.w) + ); + } + + /// <summary> + /// Returns this vector with all components rounded to the nearest integer, + /// with halfway cases rounded towards the nearest multiple of two. + /// </summary> + /// <returns>The rounded vector.</returns> + public Vector4 Round() + { + return new Vector4(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z), Mathf.Round(w)); + } + + /// <summary> + /// Returns a vector with each component set to one or negative one, depending + /// on the signs of this vector's components, or zero if the component is zero, + /// by calling <see cref="Mathf.Sign(real_t)"/> on each component. + /// </summary> + /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> + public Vector4 Sign() + { + Vector4 v; + v.x = Mathf.Sign(x); + v.y = Mathf.Sign(y); + v.z = Mathf.Sign(z); + v.w = Mathf.Sign(w); + return v; + } + + /// <summary> + /// Returns this vector with each component snapped to the nearest multiple of <paramref name="step"/>. + /// This can also be used to round to an arbitrary number of decimals. + /// </summary> + /// <param name="step">A vector value representing the step size to snap to.</param> + public Vector4 Snapped(Vector4 step) + { + return new Vector4( + Mathf.Snapped(x, step.x), + Mathf.Snapped(y, step.y), + Mathf.Snapped(z, step.z), + Mathf.Snapped(w, step.w) + ); + } + + // Constants + private static readonly Vector4 _zero = new Vector4(0, 0, 0, 0); + private static readonly Vector4 _one = new Vector4(1, 1, 1, 1); + private static readonly Vector4 _inf = new Vector4(Mathf.Inf, Mathf.Inf, Mathf.Inf, Mathf.Inf); + + /// <summary> + /// Zero vector, a vector with all components set to <c>0</c>. + /// </summary> + /// <value>Equivalent to <c>new Vector4(0, 0, 0, 0)</c>.</value> + public static Vector4 Zero { get { return _zero; } } + /// <summary> + /// One vector, a vector with all components set to <c>1</c>. + /// </summary> + /// <value>Equivalent to <c>new Vector4(1, 1, 1, 1)</c>.</value> + public static Vector4 One { get { return _one; } } + /// <summary> + /// Infinity vector, a vector with all components set to <see cref="Mathf.Inf"/>. + /// </summary> + /// <value>Equivalent to <c>new Vector4(Mathf.Inf, Mathf.Inf, Mathf.Inf, Mathf.Inf)</c>.</value> + public static Vector4 Inf { get { return _inf; } } + + /// <summary> + /// Constructs a new <see cref="Vector4"/> with the given components. + /// </summary> + /// <param name="x">The vector's X component.</param> + /// <param name="y">The vector's Y component.</param> + /// <param name="z">The vector's Z component.</param> + /// <param name="w">The vector's W component.</param> + public Vector4(real_t x, real_t y, real_t z, real_t w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /// <summary> + /// Constructs a new <see cref="Vector4"/> from an existing <see cref="Vector4"/>. + /// </summary> + /// <param name="v">The existing <see cref="Vector4"/>.</param> + public Vector4(Vector4 v) + { + x = v.x; + y = v.y; + z = v.z; + w = v.w; + } + + /// <summary> + /// Adds each component of the <see cref="Vector4"/> + /// with the components of the given <see cref="Vector4"/>. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>The added vector.</returns> + public static Vector4 operator +(Vector4 left, Vector4 right) + { + left.x += right.x; + left.y += right.y; + left.z += right.z; + left.w += right.w; + return left; + } + + /// <summary> + /// Subtracts each component of the <see cref="Vector4"/> + /// by the components of the given <see cref="Vector4"/>. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>The subtracted vector.</returns> + public static Vector4 operator -(Vector4 left, Vector4 right) + { + left.x -= right.x; + left.y -= right.y; + left.z -= right.z; + left.w -= right.w; + return left; + } + + /// <summary> + /// Returns the negative value of the <see cref="Vector4"/>. + /// This is the same as writing <c>new Vector4(-v.x, -v.y, -v.z, -v.w)</c>. + /// This operation flips the direction of the vector while + /// keeping the same magnitude. + /// With floats, the number zero can be either positive or negative. + /// </summary> + /// <param name="vec">The vector to negate/flip.</param> + /// <returns>The negated/flipped vector.</returns> + public static Vector4 operator -(Vector4 vec) + { + vec.x = -vec.x; + vec.y = -vec.y; + vec.z = -vec.z; + vec.w = -vec.w; + return vec; + } + + /// <summary> + /// Multiplies each component of the <see cref="Vector4"/> + /// by the given <see cref="real_t"/>. + /// </summary> + /// <param name="vec">The vector to multiply.</param> + /// <param name="scale">The scale to multiply by.</param> + /// <returns>The multiplied vector.</returns> + public static Vector4 operator *(Vector4 vec, real_t scale) + { + vec.x *= scale; + vec.y *= scale; + vec.z *= scale; + vec.w *= scale; + return vec; + } + + /// <summary> + /// Multiplies each component of the <see cref="Vector4"/> + /// by the given <see cref="real_t"/>. + /// </summary> + /// <param name="scale">The scale to multiply by.</param> + /// <param name="vec">The vector to multiply.</param> + /// <returns>The multiplied vector.</returns> + public static Vector4 operator *(real_t scale, Vector4 vec) + { + vec.x *= scale; + vec.y *= scale; + vec.z *= scale; + vec.w *= scale; + return vec; + } + + /// <summary> + /// Multiplies each component of the <see cref="Vector4"/> + /// by the components of the given <see cref="Vector4"/>. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>The multiplied vector.</returns> + public static Vector4 operator *(Vector4 left, Vector4 right) + { + left.x *= right.x; + left.y *= right.y; + left.z *= right.z; + left.w *= right.w; + return left; + } + + /// <summary> + /// Divides each component of the <see cref="Vector4"/> + /// by the given <see cref="real_t"/>. + /// </summary> + /// <param name="vec">The dividend vector.</param> + /// <param name="divisor">The divisor value.</param> + /// <returns>The divided vector.</returns> + public static Vector4 operator /(Vector4 vec, real_t divisor) + { + vec.x /= divisor; + vec.y /= divisor; + vec.z /= divisor; + vec.w /= divisor; + return vec; + } + + /// <summary> + /// Divides each component of the <see cref="Vector4"/> + /// by the components of the given <see cref="Vector4"/>. + /// </summary> + /// <param name="vec">The dividend vector.</param> + /// <param name="divisorv">The divisor vector.</param> + /// <returns>The divided vector.</returns> + public static Vector4 operator /(Vector4 vec, Vector4 divisorv) + { + vec.x /= divisorv.x; + vec.y /= divisorv.y; + vec.z /= divisorv.z; + vec.w /= divisorv.w; + return vec; + } + + /// <summary> + /// Returns <see langword="true"/> if the vectors are exactly equal. + /// Note: Due to floating-point precision errors, consider using + /// <see cref="IsEqualApprox"/> instead, which is more reliable. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the vectors are exactly equal.</returns> + public static bool operator ==(Vector4 left, Vector4 right) + { + return left.Equals(right); + } + + /// <summary> + /// Returns <see langword="true"/> if the vectors are not equal. + /// Note: Due to floating-point precision errors, consider using + /// <see cref="IsEqualApprox"/> instead, which is more reliable. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the vectors are not equal.</returns> + public static bool operator !=(Vector4 left, Vector4 right) + { + return !left.Equals(right); + } + + /// <summary> + /// Compares two <see cref="Vector4"/> vectors by first checking if + /// the X value of the <paramref name="left"/> vector is less than + /// the X value of the <paramref name="right"/> vector. + /// If the X values are exactly equal, then it repeats this check + /// with the Y, Z and finally W values of the two vectors. + /// This operator is useful for sorting vectors. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the left is less than the right.</returns> + public static bool operator <(Vector4 left, Vector4 right) + { + if (left.x == right.x) + { + if (left.y == right.y) + { + if (left.z == right.z) + { + return left.w < right.w; + } + return left.z < right.z; + } + return left.y < right.y; + } + return left.x < right.x; + } + + /// <summary> + /// Compares two <see cref="Vector4"/> vectors by first checking if + /// the X value of the <paramref name="left"/> vector is greater than + /// the X value of the <paramref name="right"/> vector. + /// If the X values are exactly equal, then it repeats this check + /// with the Y, Z and finally W values of the two vectors. + /// This operator is useful for sorting vectors. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the left is greater than the right.</returns> + public static bool operator >(Vector4 left, Vector4 right) + { + if (left.x == right.x) + { + if (left.y == right.y) + { + if (left.z == right.z) + { + return left.w > right.w; + } + return left.z > right.z; + } + return left.y > right.y; + } + return left.x > right.x; + } + + /// <summary> + /// Compares two <see cref="Vector4"/> vectors by first checking if + /// the X value of the <paramref name="left"/> vector is less than + /// or equal to the X value of the <paramref name="right"/> vector. + /// If the X values are exactly equal, then it repeats this check + /// with the Y, Z and finally W values of the two vectors. + /// This operator is useful for sorting vectors. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the left is less than or equal to the right.</returns> + public static bool operator <=(Vector4 left, Vector4 right) + { + if (left.x == right.x) + { + if (left.y == right.y) + { + if (left.z == right.z) + { + return left.w <= right.w; + } + return left.z < right.z; + } + return left.y < right.y; + } + return left.x < right.x; + } + + /// <summary> + /// Compares two <see cref="Vector4"/> vectors by first checking if + /// the X value of the <paramref name="left"/> vector is greater than + /// or equal to the X value of the <paramref name="right"/> vector. + /// If the X values are exactly equal, then it repeats this check + /// with the Y, Z and finally W values of the two vectors. + /// This operator is useful for sorting vectors. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the left is greater than or equal to the right.</returns> + public static bool operator >=(Vector4 left, Vector4 right) + { + if (left.x == right.x) + { + if (left.y == right.y) + { + if (left.z == right.z) + { + return left.w >= right.w; + } + return left.z > right.z; + } + return left.y > right.y; + } + return left.x > right.x; + } + + /// <summary> + /// Returns <see langword="true"/> if the vector is exactly equal + /// to the given object (<see paramref="obj"/>). + /// Note: Due to floating-point precision errors, consider using + /// <see cref="IsEqualApprox"/> instead, which is more reliable. + /// </summary> + /// <param name="obj">The object to compare with.</param> + /// <returns>Whether or not the vector and the object are equal.</returns> + public override bool Equals(object obj) + { + if (obj is Vector4) + { + return Equals((Vector4)obj); + } + + return false; + } + + /// <summary> + /// Returns <see langword="true"/> if the vectors are exactly equal. + /// Note: Due to floating-point precision errors, consider using + /// <see cref="IsEqualApprox"/> instead, which is more reliable. + /// </summary> + /// <param name="other">The other vector.</param> + /// <returns>Whether or not the vectors are exactly equal.</returns> + public bool Equals(Vector4 other) + { + return x == other.x && y == other.y && z == other.z && w == other.w; + } + + /// <summary> + /// Returns <see langword="true"/> if this vector and <paramref name="other"/> are approximately equal, + /// by running <see cref="Mathf.IsEqualApprox(real_t, real_t)"/> on each component. + /// </summary> + /// <param name="other">The other vector to compare.</param> + /// <returns>Whether or not the vectors are approximately equal.</returns> + public bool IsEqualApprox(Vector4 other) + { + return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w); + } + + /// <summary> + /// Serves as the hash function for <see cref="Vector4"/>. + /// </summary> + /// <returns>A hash code for this vector.</returns> + public override int GetHashCode() + { + return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); + } + + /// <summary> + /// Converts this <see cref="Vector4"/> to a string. + /// </summary> + /// <returns>A string representation of this vector.</returns> + public override string ToString() + { + return $"({x}, {y}, {z}, {w})"; + } + + /// <summary> + /// Converts this <see cref="Vector4"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this vector.</returns> + public string ToString(string format) + { + return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}, {w.ToString(format)})"; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs new file mode 100644 index 0000000000..365dcef486 --- /dev/null +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs @@ -0,0 +1,702 @@ +#if REAL_T_IS_DOUBLE +using real_t = System.Double; +#else +using real_t = System.Single; +#endif +using System; +using System.Runtime.InteropServices; + +namespace Godot +{ + /// <summary> + /// 4-element structure that can be used to represent 4D grid coordinates or sets of integers. + /// </summary> + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct Vector4i : IEquatable<Vector4i> + { + /// <summary> + /// Enumerated index values for the axes. + /// Returned by <see cref="MaxAxisIndex"/> and <see cref="MinAxisIndex"/>. + /// </summary> + public enum Axis + { + /// <summary> + /// The vector's X axis. + /// </summary> + X = 0, + /// <summary> + /// The vector's Y axis. + /// </summary> + Y, + /// <summary> + /// The vector's Z axis. + /// </summary> + Z, + /// <summary> + /// The vector's W axis. + /// </summary> + W + } + + /// <summary> + /// The vector's X component. Also accessible by using the index position <c>[0]</c>. + /// </summary> + public int x; + + /// <summary> + /// The vector's Y component. Also accessible by using the index position <c>[1]</c>. + /// </summary> + public int y; + + /// <summary> + /// The vector's Z component. Also accessible by using the index position <c>[2]</c>. + /// </summary> + public int z; + + /// <summary> + /// The vector's W component. Also accessible by using the index position <c>[3]</c>. + /// </summary> + public int w; + + /// <summary> + /// Access vector components using their <paramref name="index"/>. + /// </summary> + /// <exception cref="IndexOutOfRangeException"> + /// Thrown when the given the <paramref name="index"/> is not 0, 1, 2 or 3. + /// </exception> + /// <value> + /// <c>[0]</c> is equivalent to <see cref="x"/>, + /// <c>[1]</c> is equivalent to <see cref="y"/>, + /// <c>[2]</c> is equivalent to <see cref="z"/>. + /// <c>[3]</c> is equivalent to <see cref="w"/>. + /// </value> + public int 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; + return; + case 1: + y = value; + return; + case 2: + z = value; + return; + case 3: + w = value; + return; + default: + throw new IndexOutOfRangeException(); + } + } + } + + /// <summary> + /// Helper method for deconstruction into a tuple. + /// </summary> + public void Deconstruct(out int x, out int y, out int z, out int w) + { + x = this.x; + y = this.y; + z = this.z; + w = this.w; + } + + /// <summary> + /// Returns a new vector with all components in absolute values (i.e. positive). + /// </summary> + /// <returns>A vector with <see cref="Mathf.Abs(int)"/> called on each component.</returns> + public Vector4i Abs() + { + return new Vector4i(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z), Mathf.Abs(w)); + } + + /// <summary> + /// Returns a new vector with all components clamped between the + /// components of <paramref name="min"/> and <paramref name="max"/> using + /// <see cref="Mathf.Clamp(int, int, int)"/>. + /// </summary> + /// <param name="min">The vector with minimum allowed values.</param> + /// <param name="max">The vector with maximum allowed values.</param> + /// <returns>The vector with all components clamped.</returns> + public Vector4i Clamp(Vector4i min, Vector4i max) + { + return new Vector4i + ( + Mathf.Clamp(x, min.x, max.x), + Mathf.Clamp(y, min.y, max.y), + Mathf.Clamp(z, min.z, max.z), + Mathf.Clamp(w, min.w, max.w) + ); + } + + /// <summary> + /// Returns the length (magnitude) of this vector. + /// </summary> + /// <seealso cref="LengthSquared"/> + /// <returns>The length of this vector.</returns> + public real_t Length() + { + int x2 = x * x; + int y2 = y * y; + int z2 = z * z; + int w2 = w * w; + + return Mathf.Sqrt(x2 + y2 + z2 + w2); + } + + /// <summary> + /// Returns the squared length (squared magnitude) of this vector. + /// This method runs faster than <see cref="Length"/>, so prefer it if + /// you need to compare vectors or need the squared length for some formula. + /// </summary> + /// <returns>The squared length of this vector.</returns> + public int LengthSquared() + { + int x2 = x * x; + int y2 = y * y; + int z2 = z * z; + int w2 = w * w; + + return x2 + y2 + z2 + w2; + } + + /// <summary> + /// Returns the axis of the vector's highest value. See <see cref="Axis"/>. + /// If all components are equal, this method returns <see cref="Axis.X"/>. + /// </summary> + /// <returns>The index of the highest axis.</returns> + public Axis MaxAxisIndex() + { + int max_index = 0; + int max_value = x; + for (int i = 1; i < 4; i++) + { + if (this[i] > max_value) + { + max_index = i; + max_value = this[i]; + } + } + return (Axis)max_index; + } + + /// <summary> + /// Returns the axis of the vector's lowest value. See <see cref="Axis"/>. + /// If all components are equal, this method returns <see cref="Axis.W"/>. + /// </summary> + /// <returns>The index of the lowest axis.</returns> + public Axis MinAxisIndex() + { + int min_index = 0; + int min_value = x; + for (int i = 1; i < 4; i++) + { + if (this[i] <= min_value) + { + min_index = i; + min_value = this[i]; + } + } + return (Axis)min_index; + } + + /// <summary> + /// Returns a vector with each component set to one or negative one, depending + /// on the signs of this vector's components, or zero if the component is zero, + /// by calling <see cref="Mathf.Sign(int)"/> on each component. + /// </summary> + /// <returns>A vector with all components as either <c>1</c>, <c>-1</c>, or <c>0</c>.</returns> + public Vector4i Sign() + { + return new Vector4i(Mathf.Sign(x), Mathf.Sign(y), Mathf.Sign(z), Mathf.Sign(w)); + } + + // Constants + private static readonly Vector4i _zero = new Vector4i(0, 0, 0, 0); + private static readonly Vector4i _one = new Vector4i(1, 1, 1, 1); + + /// <summary> + /// Zero vector, a vector with all components set to <c>0</c>. + /// </summary> + /// <value>Equivalent to <c>new Vector4i(0, 0, 0, 0)</c>.</value> + public static Vector4i Zero { get { return _zero; } } + /// <summary> + /// One vector, a vector with all components set to <c>1</c>. + /// </summary> + /// <value>Equivalent to <c>new Vector4i(1, 1, 1, 1)</c>.</value> + public static Vector4i One { get { return _one; } } + + /// <summary> + /// Constructs a new <see cref="Vector4i"/> with the given components. + /// </summary> + /// <param name="x">The vector's X component.</param> + /// <param name="y">The vector's Y component.</param> + /// <param name="z">The vector's Z component.</param> + /// <param name="w">The vector's W component.</param> + public Vector4i(int x, int y, int z, int w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /// <summary> + /// Constructs a new <see cref="Vector4i"/> from an existing <see cref="Vector4i"/>. + /// </summary> + /// <param name="vi">The existing <see cref="Vector4i"/>.</param> + public Vector4i(Vector4i vi) + { + this.x = vi.x; + this.y = vi.y; + this.z = vi.z; + this.w = vi.w; + } + + /// <summary> + /// Constructs a new <see cref="Vector4i"/> from an existing <see cref="Vector4"/> + /// by rounding the components via <see cref="Mathf.RoundToInt(real_t)"/>. + /// </summary> + /// <param name="v">The <see cref="Vector4"/> to convert.</param> + public Vector4i(Vector4 v) + { + this.x = Mathf.RoundToInt(v.x); + this.y = Mathf.RoundToInt(v.y); + this.z = Mathf.RoundToInt(v.z); + this.w = Mathf.RoundToInt(v.w); + } + + /// <summary> + /// Adds each component of the <see cref="Vector4i"/> + /// with the components of the given <see cref="Vector4i"/>. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>The added vector.</returns> + public static Vector4i operator +(Vector4i left, Vector4i right) + { + left.x += right.x; + left.y += right.y; + left.z += right.z; + left.w += right.w; + return left; + } + + /// <summary> + /// Subtracts each component of the <see cref="Vector4i"/> + /// by the components of the given <see cref="Vector4i"/>. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>The subtracted vector.</returns> + public static Vector4i operator -(Vector4i left, Vector4i right) + { + left.x -= right.x; + left.y -= right.y; + left.z -= right.z; + left.w -= right.w; + return left; + } + + /// <summary> + /// Returns the negative value of the <see cref="Vector4i"/>. + /// This is the same as writing <c>new Vector4i(-v.x, -v.y, -v.z, -v.w)</c>. + /// This operation flips the direction of the vector while + /// keeping the same magnitude. + /// </summary> + /// <param name="vec">The vector to negate/flip.</param> + /// <returns>The negated/flipped vector.</returns> + public static Vector4i operator -(Vector4i vec) + { + vec.x = -vec.x; + vec.y = -vec.y; + vec.z = -vec.z; + vec.w = -vec.w; + return vec; + } + + /// <summary> + /// Multiplies each component of the <see cref="Vector4i"/> + /// by the given <see langword="int"/>. + /// </summary> + /// <param name="vec">The vector to multiply.</param> + /// <param name="scale">The scale to multiply by.</param> + /// <returns>The multiplied vector.</returns> + public static Vector4i operator *(Vector4i vec, int scale) + { + vec.x *= scale; + vec.y *= scale; + vec.z *= scale; + vec.w *= scale; + return vec; + } + + /// <summary> + /// Multiplies each component of the <see cref="Vector4i"/> + /// by the given <see langword="int"/>. + /// </summary> + /// <param name="scale">The scale to multiply by.</param> + /// <param name="vec">The vector to multiply.</param> + /// <returns>The multiplied vector.</returns> + public static Vector4i operator *(int scale, Vector4i vec) + { + vec.x *= scale; + vec.y *= scale; + vec.z *= scale; + vec.w *= scale; + return vec; + } + + /// <summary> + /// Multiplies each component of the <see cref="Vector4i"/> + /// by the components of the given <see cref="Vector4i"/>. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>The multiplied vector.</returns> + public static Vector4i operator *(Vector4i left, Vector4i right) + { + left.x *= right.x; + left.y *= right.y; + left.z *= right.z; + left.w *= right.w; + return left; + } + + /// <summary> + /// Divides each component of the <see cref="Vector4i"/> + /// by the given <see langword="int"/>. + /// </summary> + /// <param name="vec">The dividend vector.</param> + /// <param name="divisor">The divisor value.</param> + /// <returns>The divided vector.</returns> + public static Vector4i operator /(Vector4i vec, int divisor) + { + vec.x /= divisor; + vec.y /= divisor; + vec.z /= divisor; + vec.w /= divisor; + return vec; + } + + /// <summary> + /// Divides each component of the <see cref="Vector4i"/> + /// by the components of the given <see cref="Vector4i"/>. + /// </summary> + /// <param name="vec">The dividend vector.</param> + /// <param name="divisorv">The divisor vector.</param> + /// <returns>The divided vector.</returns> + public static Vector4i operator /(Vector4i vec, Vector4i divisorv) + { + vec.x /= divisorv.x; + vec.y /= divisorv.y; + vec.z /= divisorv.z; + vec.w /= divisorv.w; + return vec; + } + + /// <summary> + /// Gets the remainder of each component of the <see cref="Vector4i"/> + /// with the components of the given <see langword="int"/>. + /// This operation uses truncated division, which is often not desired + /// as it does not work well with negative numbers. + /// </summary> + /// <example> + /// <code> + /// GD.Print(new Vecto43i(10, -20, 30, -40) % 7); // Prints "(3, -6, 2, -5)" + /// </code> + /// </example> + /// <param name="vec">The dividend vector.</param> + /// <param name="divisor">The divisor value.</param> + /// <returns>The remainder vector.</returns> + public static Vector4i operator %(Vector4i vec, int divisor) + { + vec.x %= divisor; + vec.y %= divisor; + vec.z %= divisor; + vec.w %= divisor; + return vec; + } + + /// <summary> + /// Gets the remainder of each component of the <see cref="Vector4i"/> + /// with the components of the given <see cref="Vector4i"/>. + /// This operation uses truncated division, which is often not desired + /// as it does not work well with negative numbers. + /// </summary> + /// <example> + /// <code> + /// GD.Print(new Vector4i(10, -20, 30, -40) % new Vector4i(6, 7, 8, 9)); // Prints "(4, -6, 6, -4)" + /// </code> + /// </example> + /// <param name="vec">The dividend vector.</param> + /// <param name="divisorv">The divisor vector.</param> + /// <returns>The remainder vector.</returns> + public static Vector4i operator %(Vector4i vec, Vector4i divisorv) + { + vec.x %= divisorv.x; + vec.y %= divisorv.y; + vec.z %= divisorv.z; + vec.w %= divisorv.w; + return vec; + } + + /// <summary> + /// Performs a bitwise AND operation with this <see cref="Vector4i"/> + /// and the given <see langword="int"/>. + /// </summary> + /// <param name="vec">The vector to AND with.</param> + /// <param name="and">The integer to AND with.</param> + /// <returns>The result of the bitwise AND.</returns> + public static Vector4i operator &(Vector4i vec, int and) + { + vec.x &= and; + vec.y &= and; + vec.z &= and; + vec.w &= and; + return vec; + } + + /// <summary> + /// Performs a bitwise AND operation with this <see cref="Vector4i"/> + /// and the given <see cref="Vector4i"/>. + /// </summary> + /// <param name="vec">The left vector to AND with.</param> + /// <param name="andv">The right vector to AND with.</param> + /// <returns>The result of the bitwise AND.</returns> + public static Vector4i operator &(Vector4i vec, Vector4i andv) + { + vec.x &= andv.x; + vec.y &= andv.y; + vec.z &= andv.z; + vec.w &= andv.w; + return vec; + } + + /// <summary> + /// Returns <see langword="true"/> if the vectors are equal. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the vectors are equal.</returns> + public static bool operator ==(Vector4i left, Vector4i right) + { + return left.Equals(right); + } + + /// <summary> + /// Returns <see langword="true"/> if the vectors are not equal. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the vectors are not equal.</returns> + public static bool operator !=(Vector4i left, Vector4i right) + { + return !left.Equals(right); + } + + /// <summary> + /// Compares two <see cref="Vector4i"/> vectors by first checking if + /// the X value of the <paramref name="left"/> vector is less than + /// the X value of the <paramref name="right"/> vector. + /// If the X values are exactly equal, then it repeats this check + /// with the Y, Z and finally W values of the two vectors. + /// This operator is useful for sorting vectors. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the left is less than the right.</returns> + public static bool operator <(Vector4i left, Vector4i right) + { + if (left.x == right.x) + { + if (left.y == right.y) + { + if (left.z == right.z) + { + return left.w < right.w; + } + return left.z < right.z; + } + return left.y < right.y; + } + return left.x < right.x; + } + + /// <summary> + /// Compares two <see cref="Vector4i"/> vectors by first checking if + /// the X value of the <paramref name="left"/> vector is greater than + /// the X value of the <paramref name="right"/> vector. + /// If the X values are exactly equal, then it repeats this check + /// with the Y, Z and finally W values of the two vectors. + /// This operator is useful for sorting vectors. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the left is greater than the right.</returns> + public static bool operator >(Vector4i left, Vector4i right) + { + if (left.x == right.x) + { + if (left.y == right.y) + { + if (left.z == right.z) + { + return left.w > right.w; + } + return left.z > right.z; + } + return left.y > right.y; + } + return left.x > right.x; + } + + /// <summary> + /// Compares two <see cref="Vector4i"/> vectors by first checking if + /// the X value of the <paramref name="left"/> vector is less than + /// or equal to the X value of the <paramref name="right"/> vector. + /// If the X values are exactly equal, then it repeats this check + /// with the Y, Z and finally W values of the two vectors. + /// This operator is useful for sorting vectors. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the left is less than or equal to the right.</returns> + public static bool operator <=(Vector4i left, Vector4i right) + { + if (left.x == right.x) + { + if (left.y == right.y) + { + if (left.z == right.z) + { + return left.w <= right.w; + } + return left.z < right.z; + } + return left.y < right.y; + } + return left.x < right.x; + } + + /// <summary> + /// Compares two <see cref="Vector4i"/> vectors by first checking if + /// the X value of the <paramref name="left"/> vector is greater than + /// or equal to the X value of the <paramref name="right"/> vector. + /// If the X values are exactly equal, then it repeats this check + /// with the Y, Z and finally W values of the two vectors. + /// This operator is useful for sorting vectors. + /// </summary> + /// <param name="left">The left vector.</param> + /// <param name="right">The right vector.</param> + /// <returns>Whether or not the left is greater than or equal to the right.</returns> + public static bool operator >=(Vector4i left, Vector4i right) + { + if (left.x == right.x) + { + if (left.y == right.y) + { + if (left.z == right.z) + { + return left.w >= right.w; + } + return left.z > right.z; + } + return left.y > right.y; + } + return left.x > right.x; + } + + /// <summary> + /// Converts this <see cref="Vector4i"/> to a <see cref="Vector4"/>. + /// </summary> + /// <param name="value">The vector to convert.</param> + public static implicit operator Vector4(Vector4i value) + { + return new Vector4(value.x, value.y, value.z, value.w); + } + + /// <summary> + /// Converts a <see cref="Vector4"/> to a <see cref="Vector4i"/>. + /// </summary> + /// <param name="value">The vector to convert.</param> + public static explicit operator Vector4i(Vector4 value) + { + return new Vector4i(value); + } + + /// <summary> + /// Returns <see langword="true"/> if the vector is equal + /// to the given object (<see paramref="obj"/>). + /// </summary> + /// <param name="obj">The object to compare with.</param> + /// <returns>Whether or not the vector and the object are equal.</returns> + public override bool Equals(object obj) + { + if (obj is Vector4i) + { + return Equals((Vector4i)obj); + } + + return false; + } + + /// <summary> + /// Returns <see langword="true"/> if the vectors are equal. + /// </summary> + /// <param name="other">The other vector.</param> + /// <returns>Whether or not the vectors are equal.</returns> + public bool Equals(Vector4i other) + { + return x == other.x && y == other.y && z == other.z && w == other.w; + } + + /// <summary> + /// Serves as the hash function for <see cref="Vector4i"/>. + /// </summary> + /// <returns>A hash code for this vector.</returns> + public override int GetHashCode() + { + return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); + } + + /// <summary> + /// Converts this <see cref="Vector4i"/> to a string. + /// </summary> + /// <returns>A string representation of this vector.</returns> + public override string ToString() + { + return $"({x}, {y}, {z}, {w})"; + } + + /// <summary> + /// Converts this <see cref="Vector4i"/> to a string with the given <paramref name="format"/>. + /// </summary> + /// <returns>A string representation of this vector.</returns> + public string ToString(string format) + { + return $"({x.ToString(format)}, {y.ToString(format)}, {z.ToString(format)}), {w.ToString(format)})"; + } + } +} diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index e59f45bbf6..4f55ce47e8 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -50,6 +50,7 @@ <Compile Include="Core\NodePath.cs" /> <Compile Include="Core\Object.base.cs" /> <Compile Include="Core\Plane.cs" /> + <Compile Include="Core\Projection.cs" /> <Compile Include="Core\Quaternion.cs" /> <Compile Include="Core\Rect2.cs" /> <Compile Include="Core\Rect2i.cs" /> @@ -65,6 +66,8 @@ <Compile Include="Core\Vector2i.cs" /> <Compile Include="Core\Vector3.cs" /> <Compile Include="Core\Vector3i.cs" /> + <Compile Include="Core\Vector4.cs" /> + <Compile Include="Core\Vector4i.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup> <!-- diff --git a/modules/mono/glue/callable_glue.cpp b/modules/mono/glue/callable_glue.cpp index e59b34313c..521dc3dff7 100644 --- a/modules/mono/glue/callable_glue.cpp +++ b/modules/mono/glue/callable_glue.cpp @@ -49,7 +49,7 @@ MonoObject *godot_icall_Callable_Call(GDMonoMarshal::M_Callable *p_callable, Mon Variant result; Callable::CallError error; - callable.call(args.ptr(), argc, result, error); + callable.callp(args.ptr(), argc, result, error); return GDMonoMarshal::variant_to_mono_object(result); } @@ -68,7 +68,7 @@ void godot_icall_Callable_CallDeferred(GDMonoMarshal::M_Callable *p_callable, Mo args.set(i, &arg_store.get(i)); } - callable.call_deferred(args.ptr(), argc); + callable.call_deferredp(args.ptr(), argc); } void godot_register_callable_icalls() { diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index 9638b23410..f9ad1a9893 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -28,6 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#ifndef GLUE_HEADER_H +#define GLUE_HEADER_H + #ifdef MONO_GLUE_ENABLED #include "../mono_gd/gd_mono_marshal.h" @@ -84,3 +87,5 @@ void godot_register_glue_header_icalls() { #include "arguments_vector.h" #endif // MONO_GLUE_ENABLED + +#endif // GLUE_HEADER_H |