Browse Source

create vector4, vector4i and projection for csharp

antonWetzel 3 years ago
parent
commit
87ebfff46d

+ 6 - 33
.github/workflows/linux_builds.yml

@@ -19,30 +19,15 @@ jobs:
       fail-fast: false
       fail-fast: false
       matrix:
       matrix:
         include:
         include:
-# Temporarily disabled until Mono is fixed
-#
-#          - name: Editor w Mono (target=release_debug, tools=yes, tests=yes)
-#            cache-name: linux-editor-mono
-#            target: release_debug
-#            tools: true
-#            tests: false # Disabled due freeze caused by mix Mono build and CI
-#            sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no
-#            doc-test: true
-#            bin: "./bin/godot.linuxbsd.opt.tools.64.mono"
-#            build-mono: true
-#            proj-conv: true
-#            artifact: true
-
-# Temporary replacement:
-
-          - name: Editor w/o Mono (target=release_debug, tools=yes, tests=yes)
+          - name: Editor w Mono (target=release_debug, tools=yes, tests=yes)
             cache-name: linux-editor-mono
             cache-name: linux-editor-mono
             target: release_debug
             target: release_debug
             tools: true
             tools: true
             tests: false # Disabled due freeze caused by mix Mono build and CI
             tests: false # Disabled due freeze caused by mix Mono build and CI
+            sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no
             doc-test: true
             doc-test: true
-            bin: "./bin/godot.linuxbsd.opt.tools.64"
-            build-mono: false
+            bin: "./bin/godot.linuxbsd.opt.tools.64.mono"
+            build-mono: true
             proj-conv: true
             proj-conv: true
             artifact: true
             artifact: true
 
 
@@ -72,24 +57,12 @@ jobs:
             # Skip 2GiB artifact speeding up action.
             # Skip 2GiB artifact speeding up action.
             artifact: false
             artifact: false
 
 
-# Temporarily disabled:
-#
-#          - name: Template w/ Mono (target=release, tools=no)
-#            cache-name: linux-template-mono
-#            target: release
-#            tools: false
-#            tests: false
-#            sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no debug_symbols=no
-#            build-mono: false
-#            artifact: true
-
-# Temporary replacement:
-
-          - name: Template w/o Mono (target=release, tools=no)
+          - name: Template w/ Mono (target=release, tools=no)
             cache-name: linux-template-mono
             cache-name: linux-template-mono
             target: release
             target: release
             tools: false
             tools: false
             tests: false
             tests: false
+            sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no debug_symbols=no
             build-mono: false
             build-mono: false
             artifact: true
             artifact: true
 
 

+ 820 - 0
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;
+        }
+    }
+}

+ 730 - 0
modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs

@@ -0,0 +1,730 @@
+#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>
+        /// 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 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 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 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;
+        }
+
+        // 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)})";
+        }
+    }
+}

+ 702 - 0
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)})";
+        }
+    }
+}

+ 3 - 0
modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj

@@ -50,6 +50,7 @@
     <Compile Include="Core\NodePath.cs" />
     <Compile Include="Core\NodePath.cs" />
     <Compile Include="Core\Object.base.cs" />
     <Compile Include="Core\Object.base.cs" />
     <Compile Include="Core\Plane.cs" />
     <Compile Include="Core\Plane.cs" />
+    <Compile Include="Core\Projection.cs" />
     <Compile Include="Core\Quaternion.cs" />
     <Compile Include="Core\Quaternion.cs" />
     <Compile Include="Core\Rect2.cs" />
     <Compile Include="Core\Rect2.cs" />
     <Compile Include="Core\Rect2i.cs" />
     <Compile Include="Core\Rect2i.cs" />
@@ -65,6 +66,8 @@
     <Compile Include="Core\Vector2i.cs" />
     <Compile Include="Core\Vector2i.cs" />
     <Compile Include="Core\Vector3.cs" />
     <Compile Include="Core\Vector3.cs" />
     <Compile Include="Core\Vector3i.cs" />
     <Compile Include="Core\Vector3i.cs" />
+    <Compile Include="Core\Vector4.cs" />
+    <Compile Include="Core\Vector4i.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   </ItemGroup>
   <!--
   <!--

+ 1 - 1
modules/mono/mono_gd/gd_mono_marshal.h

@@ -262,7 +262,7 @@ enum {
 			offsetof(Vector4, z) == (sizeof(real_t) * 2) &&
 			offsetof(Vector4, z) == (sizeof(real_t) * 2) &&
 			offsetof(Vector4, w) == (sizeof(real_t) * 3)),
 			offsetof(Vector4, w) == (sizeof(real_t) * 3)),
 
 
-	MATCHES_Vector4i = (MATCHES_int && (sizeof(Vector4i) == (sizeof(int32_t) * 4i)) &&
+	MATCHES_Vector4i = (MATCHES_int && (sizeof(Vector4i) == (sizeof(int32_t) * 4)) &&
 			offsetof(Vector4i, x) == (sizeof(int32_t) * 0) &&
 			offsetof(Vector4i, x) == (sizeof(int32_t) * 0) &&
 			offsetof(Vector4i, y) == (sizeof(int32_t) * 1) &&
 			offsetof(Vector4i, y) == (sizeof(int32_t) * 1) &&
 			offsetof(Vector4i, z) == (sizeof(int32_t) * 2) &&
 			offsetof(Vector4i, z) == (sizeof(int32_t) * 2) &&