summaryrefslogtreecommitdiff
path: root/modules/mono/glue/cs_files
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/glue/cs_files')
-rw-r--r--modules/mono/glue/cs_files/Basis.cs520
-rw-r--r--modules/mono/glue/cs_files/Color.cs590
-rw-r--r--modules/mono/glue/cs_files/Error.cs48
-rw-r--r--modules/mono/glue/cs_files/ExportAttribute.cs19
-rw-r--r--modules/mono/glue/cs_files/GD.cs191
-rw-r--r--modules/mono/glue/cs_files/GodotMethodAttribute.cs17
-rw-r--r--modules/mono/glue/cs_files/GodotSynchronizationContext.cs26
-rw-r--r--modules/mono/glue/cs_files/GodotTaskScheduler.cs94
-rw-r--r--modules/mono/glue/cs_files/IAwaitable.cs12
-rw-r--r--modules/mono/glue/cs_files/IAwaiter.cs19
-rw-r--r--modules/mono/glue/cs_files/MarshalUtils.cs36
-rw-r--r--modules/mono/glue/cs_files/Mathf.cs234
-rw-r--r--modules/mono/glue/cs_files/Plane.cs209
-rw-r--r--modules/mono/glue/cs_files/Quat.cs328
-rw-r--r--modules/mono/glue/cs_files/RPCAttributes.cs16
-rw-r--r--modules/mono/glue/cs_files/Rect2.cs233
-rw-r--r--modules/mono/glue/cs_files/Rect3.cs477
-rw-r--r--modules/mono/glue/cs_files/SignalAwaiter.cs59
-rw-r--r--modules/mono/glue/cs_files/StringExtensions.cs962
-rw-r--r--modules/mono/glue/cs_files/ToolAttribute.cs7
-rw-r--r--modules/mono/glue/cs_files/Transform.cs174
-rw-r--r--modules/mono/glue/cs_files/Transform2D.cs356
-rw-r--r--modules/mono/glue/cs_files/Vector2.cs362
-rw-r--r--modules/mono/glue/cs_files/Vector3.cs420
24 files changed, 5409 insertions, 0 deletions
diff --git a/modules/mono/glue/cs_files/Basis.cs b/modules/mono/glue/cs_files/Basis.cs
new file mode 100644
index 0000000000..c50e783349
--- /dev/null
+++ b/modules/mono/glue/cs_files/Basis.cs
@@ -0,0 +1,520 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Basis : IEquatable<Basis>
+ {
+ private static readonly Basis identity = new Basis
+ (
+ new Vector3(1f, 0f, 0f),
+ new Vector3(0f, 1f, 0f),
+ new Vector3(0f, 0f, 1f)
+ );
+
+ private static readonly Basis[] orthoBases = new Basis[24]
+ {
+ new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f),
+ new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f),
+ new Basis(-1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f),
+ new Basis(0f, 1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f),
+ new Basis(1f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f),
+ new Basis(0f, 0f, 1f, 1f, 0f, 0f, 0f, 1f, 0f),
+ new Basis(-1f, 0f, 0f, 0f, 0f, 1f, 0f, 1f, 0f),
+ new Basis(0f, 0f, -1f, -1f, 0f, 0f, 0f, 1f, 0f),
+ new Basis(1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, -1f),
+ new Basis(0f, 1f, 0f, 1f, 0f, 0f, 0f, 0f, -1f),
+ new Basis(-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, -1f),
+ new Basis(0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, -1f),
+ new Basis(1f, 0f, 0f, 0f, 0f, 1f, 0f, -1f, 0f),
+ new Basis(0f, 0f, -1f, 1f, 0f, 0f, 0f, -1f, 0f),
+ new Basis(-1f, 0f, 0f, 0f, 0f, -1f, 0f, -1f, 0f),
+ new Basis(0f, 0f, 1f, -1f, 0f, 0f, 0f, -1f, 0f),
+ new Basis(0f, 0f, 1f, 0f, 1f, 0f, -1f, 0f, 0f),
+ new Basis(0f, -1f, 0f, 0f, 0f, 1f, -1f, 0f, 0f),
+ new Basis(0f, 0f, -1f, 0f, -1f, 0f, -1f, 0f, 0f),
+ new Basis(0f, 1f, 0f, 0f, 0f, -1f, -1f, 0f, 0f),
+ new Basis(0f, 0f, 1f, 0f, -1f, 0f, 1f, 0f, 0f),
+ new Basis(0f, 1f, 0f, 0f, 0f, 1f, 1f, 0f, 0f),
+ new Basis(0f, 0f, -1f, 0f, 1f, 0f, 1f, 0f, 0f),
+ new Basis(0f, -1f, 0f, 0f, 0f, -1f, 1f, 0f, 0f)
+ };
+
+ public Vector3 x;
+ public Vector3 y;
+ public Vector3 z;
+
+ public static Basis Identity
+ {
+ get { return identity; }
+ }
+
+ public Vector3 Scale
+ {
+ get
+ {
+ return new Vector3
+ (
+ new Vector3(this[0, 0], this[1, 0], this[2, 0]).length(),
+ new Vector3(this[0, 1], this[1, 1], this[2, 1]).length(),
+ new Vector3(this[0, 2], this[1, 2], this[2, 2]).length()
+ );
+ }
+ }
+
+ public Vector3 this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ z = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public float this[int index, int axis]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x[axis];
+ case 1:
+ return y[axis];
+ case 2:
+ return z[axis];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x[axis] = value;
+ return;
+ case 1:
+ y[axis] = value;
+ return;
+ case 2:
+ z[axis] = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ internal static Basis create_from_axes(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
+ {
+ return new Basis
+ (
+ new Vector3(xAxis.x, yAxis.x, zAxis.x),
+ new Vector3(xAxis.y, yAxis.y, zAxis.y),
+ new Vector3(xAxis.z, yAxis.z, zAxis.z)
+ );
+ }
+
+ public float determinant()
+ {
+ return this[0, 0] * (this[1, 1] * this[2, 2] - this[2, 1] * this[1, 2]) -
+ this[1, 0] * (this[0, 1] * this[2, 2] - this[2, 1] * this[0, 2]) +
+ this[2, 0] * (this[0, 1] * this[1, 2] - this[1, 1] * this[0, 2]);
+ }
+
+ public Vector3 get_axis(int axis)
+ {
+ return new Vector3(this[0, axis], this[1, axis], this[2, axis]);
+ }
+
+ public Vector3 get_euler()
+ {
+ Basis m = this.orthonormalized();
+
+ Vector3 euler;
+ euler.z = 0.0f;
+
+ float mxy = m.y[2];
+
+
+ if (mxy < 1.0f)
+ {
+ if (mxy > -1.0f)
+ {
+ euler.x = Mathf.asin(-mxy);
+ euler.y = Mathf.atan2(m.x[2], m.z[2]);
+ euler.z = Mathf.atan2(m.y[0], m.y[1]);
+ }
+ else
+ {
+ euler.x = Mathf.PI * 0.5f;
+ euler.y = -Mathf.atan2(-m.x[1], m.x[0]);
+ }
+ }
+ else
+ {
+ euler.x = -Mathf.PI * 0.5f;
+ euler.y = -Mathf.atan2(m.x[1], m.x[0]);
+ }
+
+ return euler;
+ }
+
+ public int get_orthogonal_index()
+ {
+ Basis orth = this;
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ float v = orth[i, j];
+
+ if (v > 0.5f)
+ v = 1.0f;
+ else if (v < -0.5f)
+ v = -1.0f;
+ else
+ v = 0f;
+
+ orth[i, j] = v;
+ }
+ }
+
+ for (int i = 0; i < 24; i++)
+ {
+ if (orthoBases[i] == orth)
+ return i;
+ }
+
+ return 0;
+ }
+
+ public Basis inverse()
+ {
+ Basis inv = this;
+
+ float[] co = new float[3]
+ {
+ inv[1, 1] * inv[2, 2] - inv[1, 2] * inv[2, 1],
+ inv[1, 2] * inv[2, 0] - inv[1, 0] * inv[2, 2],
+ inv[1, 0] * inv[2, 1] - inv[1, 1] * inv[2, 0]
+ };
+
+ float det = inv[0, 0] * co[0] + inv[0, 1] * co[1] + inv[0, 2] * co[2];
+
+ if (det == 0)
+ {
+ return new Basis
+ (
+ float.NaN, float.NaN, float.NaN,
+ float.NaN, float.NaN, float.NaN,
+ float.NaN, float.NaN, float.NaN
+ );
+ }
+
+ float s = 1.0f / det;
+
+ inv = new Basis
+ (
+ co[0] * s,
+ inv[0, 2] * inv[2, 1] - inv[0, 1] * inv[2, 2] * s,
+ inv[0, 1] * inv[1, 2] - inv[0, 2] * inv[1, 1] * s,
+ co[1] * s,
+ inv[0, 0] * inv[2, 2] - inv[0, 2] * inv[2, 0] * s,
+ inv[0, 2] * inv[1, 0] - inv[0, 0] * inv[1, 2] * s,
+ co[2] * s,
+ inv[0, 1] * inv[2, 0] - inv[0, 0] * inv[2, 1] * s,
+ inv[0, 0] * inv[1, 1] - inv[0, 1] * inv[1, 0] * s
+ );
+
+ return inv;
+ }
+
+ public Basis orthonormalized()
+ {
+ Vector3 xAxis = get_axis(0);
+ Vector3 yAxis = get_axis(1);
+ Vector3 zAxis = get_axis(2);
+
+ xAxis.normalize();
+ yAxis = (yAxis - xAxis * (xAxis.dot(yAxis)));
+ yAxis.normalize();
+ zAxis = (zAxis - xAxis * (xAxis.dot(zAxis)) - yAxis * (yAxis.dot(zAxis)));
+ zAxis.normalize();
+
+ return Basis.create_from_axes(xAxis, yAxis, zAxis);
+ }
+
+ public Basis rotated(Vector3 axis, float phi)
+ {
+ return new Basis(axis, phi) * this;
+ }
+
+ public Basis scaled(Vector3 scale)
+ {
+ Basis m = this;
+
+ m[0, 0] *= scale.x;
+ m[0, 1] *= scale.x;
+ m[0, 2] *= scale.x;
+ m[1, 0] *= scale.y;
+ m[1, 1] *= scale.y;
+ m[1, 2] *= scale.y;
+ m[2, 0] *= scale.z;
+ m[2, 1] *= scale.z;
+ m[2, 2] *= scale.z;
+
+ return m;
+ }
+
+ public float tdotx(Vector3 with)
+ {
+ return this[0, 0] * with[0] + this[1, 0] * with[1] + this[2, 0] * with[2];
+ }
+
+ public float tdoty(Vector3 with)
+ {
+ return this[0, 1] * with[0] + this[1, 1] * with[1] + this[2, 1] * with[2];
+ }
+
+ public float tdotz(Vector3 with)
+ {
+ return this[0, 2] * with[0] + this[1, 2] * with[1] + this[2, 2] * with[2];
+ }
+
+ public Basis transposed()
+ {
+ Basis tr = this;
+
+ float temp = this[0, 1];
+ this[0, 1] = this[1, 0];
+ this[1, 0] = temp;
+
+ temp = this[0, 2];
+ this[0, 2] = this[2, 0];
+ this[2, 0] = temp;
+
+ temp = this[1, 2];
+ this[1, 2] = this[2, 1];
+ this[2, 1] = temp;
+
+ return tr;
+ }
+
+ public Vector3 xform(Vector3 v)
+ {
+ return new Vector3
+ (
+ this[0].dot(v),
+ this[1].dot(v),
+ this[2].dot(v)
+ );
+ }
+
+ public Vector3 xform_inv(Vector3 v)
+ {
+ return new Vector3
+ (
+ (this[0, 0] * v.x) + (this[1, 0] * v.y) + (this[2, 0] * v.z),
+ (this[0, 1] * v.x) + (this[1, 1] * v.y) + (this[2, 1] * v.z),
+ (this[0, 2] * v.x) + (this[1, 2] * v.y) + (this[2, 2] * v.z)
+ );
+ }
+
+ public Quat Quat() {
+ float trace = x[0] + y[1] + z[2];
+
+ if (trace > 0.0f) {
+ float s = Mathf.sqrt(trace + 1.0f) * 2f;
+ float inv_s = 1f / s;
+ return new Quat(
+ (z[1] - y[2]) * inv_s,
+ (x[2] - z[0]) * inv_s,
+ (y[0] - x[1]) * inv_s,
+ s * 0.25f
+ );
+ } else if (x[0] > y[1] && x[0] > z[2]) {
+ float s = Mathf.sqrt(x[0] - y[1] - z[2] + 1.0f) * 2f;
+ float inv_s = 1f / s;
+ return new Quat(
+ s * 0.25f,
+ (x[1] + y[0]) * inv_s,
+ (x[2] + z[0]) * inv_s,
+ (z[1] - y[2]) * inv_s
+ );
+ } else if (y[1] > z[2]) {
+ float s = Mathf.sqrt(-x[0] + y[1] - z[2] + 1.0f) * 2f;
+ float inv_s = 1f / s;
+ return new Quat(
+ (x[1] + y[0]) * inv_s,
+ s * 0.25f,
+ (y[2] + z[1]) * inv_s,
+ (x[2] - z[0]) * inv_s
+ );
+ } else {
+ float s = Mathf.sqrt(-x[0] - y[1] + z[2] + 1.0f) * 2f;
+ float inv_s = 1f / s;
+ return new Quat(
+ (x[2] + z[0]) * inv_s,
+ (y[2] + z[1]) * inv_s,
+ s * 0.25f,
+ (y[0] - x[1]) * inv_s
+ );
+ }
+ }
+
+ public Basis(Quat quat)
+ {
+ float s = 2.0f / quat.length_squared();
+
+ float xs = quat.x * s;
+ float ys = quat.y * s;
+ float zs = quat.z * s;
+ float wx = quat.w * xs;
+ float wy = quat.w * ys;
+ float wz = quat.w * zs;
+ float xx = quat.x * xs;
+ float xy = quat.x * ys;
+ float xz = quat.x * zs;
+ float yy = quat.y * ys;
+ float yz = quat.y * zs;
+ float zz = quat.z * zs;
+
+ this.x = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
+ this.y = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
+ this.z = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
+ }
+
+ public Basis(Vector3 axis, float phi)
+ {
+ Vector3 axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
+
+ float cosine = Mathf.cos(phi);
+ float sine = Mathf.sin(phi);
+
+ this.x = new Vector3
+ (
+ axis_sq.x + cosine * (1.0f - axis_sq.x),
+ axis.x * axis.y * (1.0f - cosine) - axis.z * sine,
+ axis.z * axis.x * (1.0f - cosine) + axis.y * sine
+ );
+
+ this.y = new Vector3
+ (
+ axis.x * axis.y * (1.0f - cosine) + axis.z * sine,
+ axis_sq.y + cosine * (1.0f - axis_sq.y),
+ axis.y * axis.z * (1.0f - cosine) - axis.x * sine
+ );
+
+ this.z = new Vector3
+ (
+ axis.z * axis.x * (1.0f - cosine) - axis.y * sine,
+ axis.y * axis.z * (1.0f - cosine) + axis.x * sine,
+ axis_sq.z + cosine * (1.0f - axis_sq.z)
+ );
+ }
+
+ public Basis(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
+ {
+ this.x = xAxis;
+ this.y = yAxis;
+ this.z = zAxis;
+ }
+
+ public Basis(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz)
+ {
+ this.x = new Vector3(xx, xy, xz);
+ this.y = new Vector3(yx, yy, yz);
+ this.z = new Vector3(zx, zy, zz);
+ }
+
+ public static Basis operator *(Basis left, Basis right)
+ {
+ return new Basis
+ (
+ right.tdotx(left[0]), right.tdoty(left[0]), right.tdotz(left[0]),
+ right.tdotx(left[1]), right.tdoty(left[1]), right.tdotz(left[1]),
+ right.tdotx(left[2]), right.tdoty(left[2]), right.tdotz(left[2])
+ );
+ }
+
+ public static bool operator ==(Basis left, Basis right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Basis left, Basis right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Basis)
+ {
+ return Equals((Basis)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Basis other)
+ {
+ return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.z.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.z.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Color.cs b/modules/mono/glue/cs_files/Color.cs
new file mode 100644
index 0000000000..df88a46832
--- /dev/null
+++ b/modules/mono/glue/cs_files/Color.cs
@@ -0,0 +1,590 @@
+using System;
+
+namespace Godot
+{
+ public struct Color : IEquatable<Color>
+ {
+ public float r;
+ public float g;
+ public float b;
+ public float a;
+
+ public int r8
+ {
+ get
+ {
+ return (int)(r * 255.0f);
+ }
+ }
+
+ public int g8
+ {
+ get
+ {
+ return (int)(g * 255.0f);
+ }
+ }
+
+ public int b8
+ {
+ get
+ {
+ return (int)(b * 255.0f);
+ }
+ }
+
+ public int a8
+ {
+ get
+ {
+ return (int)(a * 255.0f);
+ }
+ }
+
+ public float h
+ {
+ get
+ {
+ float max = Mathf.max(r, Mathf.max(g, b));
+ float min = Mathf.min(r, Mathf.min(g, b));
+
+ float delta = max - min;
+
+ if (delta == 0)
+ return 0;
+
+ float h;
+
+ if (r == max)
+ h = (g - b) / delta; // Between yellow & magenta
+ else if (g == max)
+ h = 2 + (b - r) / delta; // Between cyan & yellow
+ else
+ h = 4 + (r - g) / delta; // Between magenta & cyan
+
+ h /= 6.0f;
+
+ if (h < 0)
+ h += 1.0f;
+
+ return h;
+ }
+ set
+ {
+ this = from_hsv(value, s, v);
+ }
+ }
+
+ public float s
+ {
+ get
+ {
+ float max = Mathf.max(r, Mathf.max(g, b));
+ float min = Mathf.min(r, Mathf.min(g, b));
+
+ float delta = max - min;
+
+ return max != 0 ? delta / max : 0;
+ }
+ set
+ {
+ this = from_hsv(h, value, v);
+ }
+ }
+
+ public float v
+ {
+ get
+ {
+ return Mathf.max(r, Mathf.max(g, b));
+ }
+ set
+ {
+ this = from_hsv(h, s, value);
+ }
+ }
+
+ private static readonly Color black = new Color(0f, 0f, 0f, 1.0f);
+
+ public Color Black
+ {
+ get
+ {
+ return black;
+ }
+ }
+
+ public float this [int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return r;
+ case 1:
+ return g;
+ case 2:
+ return b;
+ case 3:
+ return a;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ r = value;
+ return;
+ case 1:
+ g = value;
+ return;
+ case 2:
+ b = value;
+ return;
+ case 3:
+ a = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public static void to_hsv(Color color, out float hue, out float saturation, out float value)
+ {
+ int max = Mathf.max(color.r8, Mathf.max(color.g8, color.b8));
+ int min = Mathf.min(color.r8, Mathf.min(color.g8, color.b8));
+
+ float delta = max - min;
+
+ if (delta == 0)
+ {
+ hue = 0;
+ }
+ else
+ {
+ if (color.r == max)
+ hue = (color.g - color.b) / delta; // Between yellow & magenta
+ else if (color.g == max)
+ hue = 2 + (color.b - color.r) / delta; // Between cyan & yellow
+ else
+ hue = 4 + (color.r - color.g) / delta; // Between magenta & cyan
+
+ hue /= 6.0f;
+
+ if (hue < 0)
+ hue += 1.0f;
+ }
+
+ saturation = (max == 0) ? 0 : 1f - (1f * min / max);
+ value = max / 255f;
+ }
+
+ public static Color from_hsv(float hue, float saturation, float value, float alpha = 1.0f)
+ {
+ if (saturation == 0)
+ {
+ // acp_hromatic (grey)
+ return new Color(value, value, value, alpha);
+ }
+
+ int i;
+ float f, p, q, t;
+
+ hue *= 6.0f;
+ hue %= 6f;
+ i = (int)hue;
+
+ f = hue - i;
+ p = value * (1 - saturation);
+ q = value * (1 - saturation * f);
+ t = value * (1 - saturation * (1 - f));
+
+ switch (i)
+ {
+ case 0: // Red is the dominant color
+ return new Color(value, t, p, alpha);
+ case 1: // Green is the dominant color
+ return new Color(q, value, p, alpha);
+ case 2:
+ return new Color(p, value, t, alpha);
+ case 3: // Blue is the dominant color
+ return new Color(p, q, value, alpha);
+ case 4:
+ return new Color(t, p, value, alpha);
+ default: // (5) Red is the dominant color
+ return new Color(value, p, q, alpha);
+ }
+ }
+
+ public Color blend(Color over)
+ {
+ Color res;
+
+ float sa = 1.0f - over.a;
+ res.a = a * sa + over.a;
+
+ if (res.a == 0)
+ {
+ return new Color(0, 0, 0, 0);
+ }
+ else
+ {
+ res.r = (r * a * sa + over.r * over.a) / res.a;
+ res.g = (g * a * sa + over.g * over.a) / res.a;
+ res.b = (b * a * sa + over.b * over.a) / res.a;
+ }
+
+ return res;
+ }
+
+ public Color contrasted()
+ {
+ return new Color(
+ (r + 0.5f) % 1.0f,
+ (g + 0.5f) % 1.0f,
+ (b + 0.5f) % 1.0f
+ );
+ }
+
+ public float gray()
+ {
+ return (r + g + b) / 3.0f;
+ }
+
+ public Color inverted()
+ {
+ return new Color(
+ 1.0f - r,
+ 1.0f - g,
+ 1.0f - b
+ );
+ }
+
+ public Color linear_interpolate(Color b, float t)
+ {
+ Color res = this;
+
+ res.r += (t * (b.r - this.r));
+ res.g += (t * (b.g - this.g));
+ res.b += (t * (b.b - this.b));
+ res.a += (t * (b.a - this.a));
+
+ return res;
+ }
+
+ public int to_32()
+ {
+ int c = (byte)(a * 255);
+ c <<= 8;
+ c |= (byte)(r * 255);
+ c <<= 8;
+ c |= (byte)(g * 255);
+ c <<= 8;
+ c |= (byte)(b * 255);
+
+ return c;
+ }
+
+ public int to_ARGB32()
+ {
+ int c = (byte)(a * 255);
+ c <<= 8;
+ c |= (byte)(r * 255);
+ c <<= 8;
+ c |= (byte)(g * 255);
+ c <<= 8;
+ c |= (byte)(b * 255);
+
+ return c;
+ }
+
+ public string to_html(bool include_alpha = true)
+ {
+ String txt = string.Empty;
+
+ txt += _to_hex(r);
+ txt += _to_hex(g);
+ txt += _to_hex(b);
+
+ if (include_alpha)
+ txt = _to_hex(a) + txt;
+
+ return txt;
+ }
+
+ public Color(float r, float g, float b, float a = 1.0f)
+ {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.a = a;
+ }
+
+ public Color(int rgba)
+ {
+ this.a = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ this.b = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ this.g = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ this.r = (rgba & 0xFF) / 255.0f;
+ }
+
+ private static float _parse_col(string str, int ofs)
+ {
+ int ig = 0;
+
+ for (int i = 0; i < 2; i++)
+ {
+ int c = str[i + ofs];
+ int v = 0;
+
+ if (c >= '0' && c <= '9')
+ {
+ v = c - '0';
+ }
+ else if (c >= 'a' && c <= 'f')
+ {
+ v = c - 'a';
+ v += 10;
+ }
+ else if (c >= 'A' && c <= 'F')
+ {
+ v = c - 'A';
+ v += 10;
+ }
+ else
+ {
+ return -1;
+ }
+
+ if (i == 0)
+ ig += v * 16;
+ else
+ ig += v;
+ }
+
+ return ig;
+ }
+
+ private String _to_hex(float val)
+ {
+ int v = (int)Mathf.clamp(val * 255.0f, 0, 255);
+
+ string ret = string.Empty;
+
+ for (int i = 0; i < 2; i++)
+ {
+ char[] c = { (char)0, (char)0 };
+ int lv = v & 0xF;
+
+ if (lv < 10)
+ c[0] = (char)('0' + lv);
+ else
+ c[0] = (char)('a' + lv - 10);
+
+ v >>= 4;
+ ret = c + ret;
+ }
+
+ return ret;
+ }
+
+ internal static bool html_is_valid(string color)
+ {
+ if (color.Length == 0)
+ return false;
+
+ if (color[0] == '#')
+ color = color.Substring(1, color.Length - 1);
+
+ bool alpha = false;
+
+ if (color.Length == 8)
+ alpha = true;
+ else if (color.Length == 6)
+ alpha = false;
+ else
+ return false;
+
+ if (alpha)
+ {
+ if ((int)_parse_col(color, 0) < 0)
+ return false;
+ }
+
+ int from = alpha ? 2 : 0;
+
+ if ((int)_parse_col(color, from + 0) < 0)
+ return false;
+ if ((int)_parse_col(color, from + 2) < 0)
+ return false;
+ if ((int)_parse_col(color, from + 4) < 0)
+ return false;
+
+ return true;
+ }
+
+ public static Color Color8(byte r8, byte g8, byte b8, byte a8)
+ {
+ return new Color((float)r8 / 255f, (float)g8 / 255f, (float)b8 / 255f, (float)a8 / 255f);
+ }
+
+ public Color(string rgba)
+ {
+ if (rgba.Length == 0)
+ {
+ r = 0f;
+ g = 0f;
+ b = 0f;
+ a = 1.0f;
+ return;
+ }
+
+ if (rgba[0] == '#')
+ rgba = rgba.Substring(1);
+
+ bool alpha = false;
+
+ if (rgba.Length == 8)
+ {
+ alpha = true;
+ }
+ else if (rgba.Length == 6)
+ {
+ alpha = false;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
+ }
+
+ if (alpha)
+ {
+ a = _parse_col(rgba, 0);
+
+ if (a < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Alpha is " + a + " but zero or greater is expected: " + rgba);
+ }
+ else
+ {
+ a = 1.0f;
+ }
+
+ int from = alpha ? 2 : 0;
+
+ r = _parse_col(rgba, from + 0);
+
+ if (r < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Red is " + r + " but zero or greater is expected: " + rgba);
+
+ g = _parse_col(rgba, from + 2);
+
+ if (g < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Green is " + g + " but zero or greater is expected: " + rgba);
+
+ b = _parse_col(rgba, from + 4);
+
+ if (b < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Blue is " + b + " but zero or greater is expected: " + rgba);
+ }
+
+ public static bool operator ==(Color left, Color right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Color left, Color right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Color left, Color right)
+ {
+ if (left.r == right.r)
+ {
+ if (left.g == right.g)
+ {
+ if (left.b == right.b)
+ return (left.a < right.a);
+ else
+ return (left.b < right.b);
+ }
+ else
+ {
+ return left.g < right.g;
+ }
+ }
+
+ return left.r < right.r;
+ }
+
+ public static bool operator >(Color left, Color right)
+ {
+ if (left.r == right.r)
+ {
+ if (left.g == right.g)
+ {
+ if (left.b == right.b)
+ return (left.a > right.a);
+ else
+ return (left.b > right.b);
+ }
+ else
+ {
+ return left.g > right.g;
+ }
+ }
+
+ return left.r > right.r;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Color)
+ {
+ return Equals((Color)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Color other)
+ {
+ return r == other.r && g == other.g && b == other.b && a == other.a;
+ }
+
+ public override int GetHashCode()
+ {
+ return r.GetHashCode() ^ g.GetHashCode() ^ b.GetHashCode() ^ a.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0},{1},{2},{3}", new object[]
+ {
+ this.r.ToString(),
+ this.g.ToString(),
+ this.b.ToString(),
+ this.a.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0},{1},{2},{3}", new object[]
+ {
+ this.r.ToString(format),
+ this.g.ToString(format),
+ this.b.ToString(format),
+ this.a.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Error.cs b/modules/mono/glue/cs_files/Error.cs
new file mode 100644
index 0000000000..3f4a92603d
--- /dev/null
+++ b/modules/mono/glue/cs_files/Error.cs
@@ -0,0 +1,48 @@
+namespace Godot
+{
+ public enum Error : int
+ {
+ OK = 0,
+ FAILED = 1,
+ ERR_UNAVAILABLE = 2,
+ ERR_UNCONFIGURED = 3,
+ ERR_UNAUTHORIZED = 4,
+ ERR_PARAMETER_RANGE_ERROR = 5,
+ ERR_OUT_OF_MEMORY = 6,
+ ERR_FILE_NOT_FOUND = 7,
+ ERR_FILE_BAD_DRIVE = 8,
+ ERR_FILE_BAD_PATH = 9,
+ ERR_FILE_NO_PERMISSION = 10,
+ ERR_FILE_ALREADY_IN_USE = 11,
+ ERR_FILE_CANT_OPEN = 12,
+ ERR_FILE_CANT_WRITE = 13,
+ ERR_FILE_CANT_READ = 14,
+ ERR_FILE_UNRECOGNIZED = 15,
+ ERR_FILE_CORRUPT = 16,
+ ERR_FILE_MISSING_DEPENDENCIES = 17,
+ ERR_FILE_EOF = 18,
+ ERR_CANT_OPEN = 19,
+ ERR_CANT_CREATE = 20,
+ ERR_PARSE_ERROR = 43,
+ ERROR_QUERY_FAILED = 21,
+ ERR_ALREADY_IN_USE = 22,
+ ERR_LOCKED = 23,
+ ERR_TIMEOUT = 24,
+ ERR_CANT_AQUIRE_RESOURCE = 28,
+ ERR_INVALID_DATA = 30,
+ ERR_INVALID_PARAMETER = 31,
+ ERR_ALREADY_EXISTS = 32,
+ ERR_DOES_NOT_EXIST = 33,
+ ERR_DATABASE_CANT_READ = 34,
+ ERR_DATABASE_CANT_WRITE = 35,
+ ERR_COMPILATION_FAILED = 36,
+ ERR_METHOD_NOT_FOUND = 37,
+ ERR_LINK_FAILED = 38,
+ ERR_SCRIPT_FAILED = 39,
+ ERR_CYCLIC_LINK = 40,
+ ERR_BUSY = 44,
+ ERR_HELP = 46,
+ ERR_BUG = 47,
+ ERR_WTF = 49
+ }
+}
diff --git a/modules/mono/glue/cs_files/ExportAttribute.cs b/modules/mono/glue/cs_files/ExportAttribute.cs
new file mode 100644
index 0000000000..af3f603d6d
--- /dev/null
+++ b/modules/mono/glue/cs_files/ExportAttribute.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public class ExportAttribute : Attribute
+ {
+ private int hint;
+ private string hint_string;
+ private int usage;
+
+ public ExportAttribute(int hint = GD.PROPERTY_HINT_NONE, string hint_string = "", int usage = GD.PROPERTY_USAGE_DEFAULT)
+ {
+ this.hint = hint;
+ this.hint_string = hint_string;
+ this.usage = usage;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs
new file mode 100644
index 0000000000..40a42d23b4
--- /dev/null
+++ b/modules/mono/glue/cs_files/GD.cs
@@ -0,0 +1,191 @@
+using System;
+
+namespace Godot
+{
+ public static class GD
+ {
+ /*{GodotGlobalConstants}*/
+
+ public static object bytes2var(byte[] bytes)
+ {
+ return NativeCalls.godot_icall_Godot_bytes2var(bytes);
+ }
+
+ public static object convert(object what, int type)
+ {
+ return NativeCalls.godot_icall_Godot_convert(what, type);
+ }
+
+ public static float db2linear(float db)
+ {
+ return (float)Math.Exp(db * 0.11512925464970228420089957273422);
+ }
+
+ public static float dectime(float value, float amount, float step)
+ {
+ float sgn = value < 0 ? -1.0f : 1.0f;
+ float val = Mathf.abs(value);
+ val -= amount * step;
+ if (val < 0.0f)
+ val = 0.0f;
+ return val * sgn;
+ }
+
+ public static FuncRef funcref(Object instance, string funcname)
+ {
+ var ret = new FuncRef();
+ ret.SetInstance(instance);
+ ret.SetFunction(funcname);
+ return ret;
+ }
+
+ public static int hash(object var)
+ {
+ return NativeCalls.godot_icall_Godot_hash(var);
+ }
+
+ public static Object instance_from_id(int instance_id)
+ {
+ return NativeCalls.godot_icall_Godot_instance_from_id(instance_id);
+ }
+
+ public static double linear2db(double linear)
+ {
+ return Math.Log(linear) * 8.6858896380650365530225783783321;
+ }
+
+ public static Resource load(string path)
+ {
+ return ResourceLoader.Load(path);
+ }
+
+ public static void print(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_print(what);
+ }
+
+ public static void print_stack()
+ {
+ print(System.Environment.StackTrace);
+ }
+
+ public static void printerr(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_printerr(what);
+ }
+
+ public static void printraw(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_printraw(what);
+ }
+
+ public static void prints(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_prints(what);
+ }
+
+ public static void printt(params object[] what)
+ {
+ NativeCalls.godot_icall_Godot_printt(what);
+ }
+
+ public static int[] range(int length)
+ {
+ int[] ret = new int[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ ret[i] = i;
+ }
+
+ return ret;
+ }
+
+ public static int[] range(int from, int to)
+ {
+ if (to < from)
+ return new int[0];
+
+ int[] ret = new int[to - from];
+
+ for (int i = from; i < to; i++)
+ {
+ ret[i - from] = i;
+ }
+
+ return ret;
+ }
+
+ public static int[] range(int from, int to, int increment)
+ {
+ if (to < from && increment > 0)
+ return new int[0];
+ if (to > from && increment < 0)
+ return new int[0];
+
+ // Calculate count
+ int count = 0;
+
+ if (increment > 0)
+ count = ((to - from - 1) / increment) + 1;
+ else
+ count = ((from - to - 1) / -increment) + 1;
+
+ int[] ret = new int[count];
+
+ if (increment > 0)
+ {
+ int idx = 0;
+ for (int i = from; i < to; i += increment)
+ {
+ ret[idx++] = i;
+ }
+ }
+ else
+ {
+ int idx = 0;
+ for (int i = from; i > to; i += increment)
+ {
+ ret[idx++] = i;
+ }
+ }
+
+ return ret;
+ }
+
+ public static void seed(int seed)
+ {
+ NativeCalls.godot_icall_Godot_seed(seed);
+ }
+
+ public static string str(params object[] what)
+ {
+ return NativeCalls.godot_icall_Godot_str(what);
+ }
+
+ public static object str2var(string str)
+ {
+ return NativeCalls.godot_icall_Godot_str2var(str);
+ }
+
+ public static bool type_exists(string type)
+ {
+ return NativeCalls.godot_icall_Godot_type_exists(type);
+ }
+
+ public static byte[] var2bytes(object var)
+ {
+ return NativeCalls.godot_icall_Godot_var2bytes(var);
+ }
+
+ public static string var2str(object var)
+ {
+ return NativeCalls.godot_icall_Godot_var2str(var);
+ }
+
+ public static WeakRef weakref(Object obj)
+ {
+ return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj));
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GodotMethodAttribute.cs b/modules/mono/glue/cs_files/GodotMethodAttribute.cs
new file mode 100644
index 0000000000..21333c8dab
--- /dev/null
+++ b/modules/mono/glue/cs_files/GodotMethodAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Method, Inherited = true)]
+ internal class GodotMethodAttribute : Attribute
+ {
+ private string methodName;
+
+ public string MethodName { get { return methodName; } }
+
+ public GodotMethodAttribute(string methodName)
+ {
+ this.methodName = methodName;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GodotSynchronizationContext.cs b/modules/mono/glue/cs_files/GodotSynchronizationContext.cs
new file mode 100644
index 0000000000..eb4d0bed1c
--- /dev/null
+++ b/modules/mono/glue/cs_files/GodotSynchronizationContext.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Godot
+{
+ public class GodotSynchronizationContext : SynchronizationContext
+ {
+ private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> queue = new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
+
+ public override void Post(SendOrPostCallback d, object state)
+ {
+ queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
+ }
+
+ public void ExecutePendingContinuations()
+ {
+ KeyValuePair<SendOrPostCallback, object> workItem;
+ while (queue.TryTake(out workItem))
+ {
+ workItem.Key(workItem.Value);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/GodotTaskScheduler.cs b/modules/mono/glue/cs_files/GodotTaskScheduler.cs
new file mode 100644
index 0000000000..f587645a49
--- /dev/null
+++ b/modules/mono/glue/cs_files/GodotTaskScheduler.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Godot
+{
+ public class GodotTaskScheduler : TaskScheduler
+ {
+ private GodotSynchronizationContext Context { get; set; }
+ private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
+
+ public GodotTaskScheduler()
+ {
+ Context = new GodotSynchronizationContext();
+ }
+
+ protected sealed override void QueueTask(Task task)
+ {
+ lock (_tasks)
+ {
+ _tasks.AddLast(task);
+ }
+ }
+
+ protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
+ {
+ if (SynchronizationContext.Current != Context)
+ {
+ return false;
+ }
+
+ if (taskWasPreviouslyQueued)
+ {
+ TryDequeue(task);
+ }
+
+ return base.TryExecuteTask(task);
+ }
+
+ protected sealed override bool TryDequeue(Task task)
+ {
+ lock (_tasks)
+ {
+ return _tasks.Remove(task);
+ }
+ }
+
+ protected sealed override IEnumerable<Task> GetScheduledTasks()
+ {
+ lock (_tasks)
+ {
+ return _tasks.ToArray();
+ }
+ }
+
+ public void Activate()
+ {
+ SynchronizationContext.SetSynchronizationContext(Context);
+ ExecuteQueuedTasks();
+ Context.ExecutePendingContinuations();
+ }
+
+ private void ExecuteQueuedTasks()
+ {
+ while (true)
+ {
+ Task task;
+
+ lock (_tasks)
+ {
+ if (_tasks.Any())
+ {
+ task = _tasks.First.Value;
+ _tasks.RemoveFirst();
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (task != null)
+ {
+ if (!TryExecuteTask(task))
+ {
+ throw new InvalidOperationException();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/IAwaitable.cs b/modules/mono/glue/cs_files/IAwaitable.cs
new file mode 100644
index 0000000000..0397957d00
--- /dev/null
+++ b/modules/mono/glue/cs_files/IAwaitable.cs
@@ -0,0 +1,12 @@
+namespace Godot
+{
+ public interface IAwaitable
+ {
+ IAwaiter GetAwaiter();
+ }
+
+ public interface IAwaitable<out TResult>
+ {
+ IAwaiter<TResult> GetAwaiter();
+ }
+}
diff --git a/modules/mono/glue/cs_files/IAwaiter.cs b/modules/mono/glue/cs_files/IAwaiter.cs
new file mode 100644
index 0000000000..73c71b5634
--- /dev/null
+++ b/modules/mono/glue/cs_files/IAwaiter.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public interface IAwaiter : INotifyCompletion
+ {
+ bool IsCompleted { get; }
+
+ void GetResult();
+ }
+
+ public interface IAwaiter<out TResult> : INotifyCompletion
+ {
+ bool IsCompleted { get; }
+
+ TResult GetResult();
+ }
+}
diff --git a/modules/mono/glue/cs_files/MarshalUtils.cs b/modules/mono/glue/cs_files/MarshalUtils.cs
new file mode 100644
index 0000000000..5d40111339
--- /dev/null
+++ b/modules/mono/glue/cs_files/MarshalUtils.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+
+namespace Godot
+{
+ internal static class MarshalUtils
+ {
+ private static Dictionary<object, object> ArraysToDictionary(object[] keys, object[] values)
+ {
+ Dictionary<object, object> ret = new Dictionary<object, object>();
+
+ for (int i = 0; i < keys.Length; i++)
+ {
+ ret.Add(keys[i], values[i]);
+ }
+
+ return ret;
+ }
+
+ private static void DictionaryToArrays(Dictionary<object, object> from, out object[] keysTo, out object[] valuesTo)
+ {
+ Dictionary<object, object>.KeyCollection keys = from.Keys;
+ keysTo = new object[keys.Count];
+ keys.CopyTo(keysTo, 0);
+
+ Dictionary<object, object>.ValueCollection values = from.Values;
+ valuesTo = new object[values.Count];
+ values.CopyTo(valuesTo, 0);
+ }
+
+ private static Type GetDictionaryType()
+ {
+ return typeof(Dictionary<object, object>);
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Mathf.cs b/modules/mono/glue/cs_files/Mathf.cs
new file mode 100644
index 0000000000..cb0eb1acdd
--- /dev/null
+++ b/modules/mono/glue/cs_files/Mathf.cs
@@ -0,0 +1,234 @@
+using System;
+
+namespace Godot
+{
+ public static class Mathf
+ {
+ public const float PI = 3.14159274f;
+ public const float Epsilon = 1e-06f;
+
+ private const float Deg2RadConst = 0.0174532924f;
+ private const float Rad2DegConst = 57.29578f;
+
+ public static float abs(float s)
+ {
+ return Math.Abs(s);
+ }
+
+ public static float acos(float s)
+ {
+ return (float)Math.Acos(s);
+ }
+
+ public static float asin(float s)
+ {
+ return (float)Math.Asin(s);
+ }
+
+ public static float atan(float s)
+ {
+ return (float)Math.Atan(s);
+ }
+
+ public static float atan2(float x, float y)
+ {
+ return (float)Math.Atan2(x, y);
+ }
+
+ public static float ceil(float s)
+ {
+ return (float)Math.Ceiling(s);
+ }
+
+ public static float clamp(float val, float min, float max)
+ {
+ if (val < min)
+ {
+ return min;
+ }
+ else if (val > max)
+ {
+ return max;
+ }
+
+ return val;
+ }
+
+ public static float cos(float s)
+ {
+ return (float)Math.Cos(s);
+ }
+
+ public static float cosh(float s)
+ {
+ return (float)Math.Cosh(s);
+ }
+
+ public static int decimals(float step)
+ {
+ return decimals(step);
+ }
+
+ public static int decimals(decimal step)
+ {
+ return BitConverter.GetBytes(decimal.GetBits(step)[3])[2];
+ }
+
+ public static float deg2rad(float deg)
+ {
+ return deg * Deg2RadConst;
+ }
+
+ public static float ease(float s, float curve)
+ {
+ if (s < 0f)
+ {
+ s = 0f;
+ }
+ else if (s > 1.0f)
+ {
+ s = 1.0f;
+ }
+
+ if (curve > 0f)
+ {
+ if (curve < 1.0f)
+ {
+ return 1.0f - pow(1.0f - s, 1.0f / curve);
+ }
+
+ return pow(s, curve);
+ }
+ else if (curve < 0f)
+ {
+ if (s < 0.5f)
+ {
+ return pow(s * 2.0f, -curve) * 0.5f;
+ }
+
+ return (1.0f - pow(1.0f - (s - 0.5f) * 2.0f, -curve)) * 0.5f + 0.5f;
+ }
+
+ return 0f;
+ }
+
+ public static float exp(float s)
+ {
+ return (float)Math.Exp(s);
+ }
+
+ public static float floor(float s)
+ {
+ return (float)Math.Floor(s);
+ }
+
+ public static float fposmod(float x, float y)
+ {
+ if (x >= 0f)
+ {
+ return x % y;
+ }
+ else
+ {
+ return y - (-x % y);
+ }
+ }
+
+ public static float lerp(float from, float to, float weight)
+ {
+ return from + (to - from) * clamp(weight, 0f, 1f);
+ }
+
+ public static float log(float s)
+ {
+ return (float)Math.Log(s);
+ }
+
+ public static int max(int a, int b)
+ {
+ return (a > b) ? a : b;
+ }
+
+ public static float max(float a, float b)
+ {
+ return (a > b) ? a : b;
+ }
+
+ public static int min(int a, int b)
+ {
+ return (a < b) ? a : b;
+ }
+
+ public static float min(float a, float b)
+ {
+ return (a < b) ? a : b;
+ }
+
+ public static int nearest_po2(int val)
+ {
+ val--;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val++;
+ return val;
+ }
+
+ public static float pow(float x, float y)
+ {
+ return (float)Math.Pow(x, y);
+ }
+
+ public static float rad2deg(float rad)
+ {
+ return rad * Rad2DegConst;
+ }
+
+ public static float round(float s)
+ {
+ return (float)Math.Round(s);
+ }
+
+ public static float sign(float s)
+ {
+ return (s < 0f) ? -1f : 1f;
+ }
+
+ public static float sin(float s)
+ {
+ return (float)Math.Sin(s);
+ }
+
+ public static float sinh(float s)
+ {
+ return (float)Math.Sinh(s);
+ }
+
+ public static float sqrt(float s)
+ {
+ return (float)Math.Sqrt(s);
+ }
+
+ public static float stepify(float s, float step)
+ {
+ if (step != 0f)
+ {
+ s = floor(s / step + 0.5f) * step;
+ }
+
+ return s;
+ }
+
+ public static float tan(float s)
+ {
+ return (float)Math.Tan(s);
+ }
+
+ public static float tanh(float s)
+ {
+ return (float)Math.Tanh(s);
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Plane.cs b/modules/mono/glue/cs_files/Plane.cs
new file mode 100644
index 0000000000..ada6e465ac
--- /dev/null
+++ b/modules/mono/glue/cs_files/Plane.cs
@@ -0,0 +1,209 @@
+using System;
+
+namespace Godot
+{
+ public struct Plane : IEquatable<Plane>
+ {
+ Vector3 normal;
+
+ public float x
+ {
+ get
+ {
+ return normal.x;
+ }
+ set
+ {
+ normal.x = value;
+ }
+ }
+
+ public float y
+ {
+ get
+ {
+ return normal.y;
+ }
+ set
+ {
+ normal.y = value;
+ }
+ }
+
+ public float z
+ {
+ get
+ {
+ return normal.z;
+ }
+ set
+ {
+ normal.z = value;
+ }
+ }
+
+ float d;
+
+ public Vector3 Center
+ {
+ get
+ {
+ return normal * d;
+ }
+ }
+
+ public float distance_to(Vector3 point)
+ {
+ return normal.dot(point) - d;
+ }
+
+ public Vector3 get_any_point()
+ {
+ return normal * d;
+ }
+
+ public bool has_point(Vector3 point, float epsilon = Mathf.Epsilon)
+ {
+ float dist = normal.dot(point) - d;
+ return Mathf.abs(dist) <= epsilon;
+ }
+
+ public Vector3 intersect_3(Plane b, Plane c)
+ {
+ float denom = normal.cross(b.normal).dot(c.normal);
+
+ if (Mathf.abs(denom) <= Mathf.Epsilon)
+ return new Vector3();
+
+ Vector3 result = (b.normal.cross(c.normal) * this.d) +
+ (c.normal.cross(normal) * b.d) +
+ (normal.cross(b.normal) * c.d);
+
+ return result / denom;
+ }
+
+ public Vector3 intersect_ray(Vector3 from, Vector3 dir)
+ {
+ float den = normal.dot(dir);
+
+ if (Mathf.abs(den) <= Mathf.Epsilon)
+ return new Vector3();
+
+ float dist = (normal.dot(from) - d) / den;
+
+ // This is a ray, before the emiting pos (from) does not exist
+ if (dist > Mathf.Epsilon)
+ return new Vector3();
+
+ return from + dir * -dist;
+ }
+
+ public Vector3 intersect_segment(Vector3 begin, Vector3 end)
+ {
+ Vector3 segment = begin - end;
+ float den = normal.dot(segment);
+
+ if (Mathf.abs(den) <= Mathf.Epsilon)
+ return new Vector3();
+
+ float dist = (normal.dot(begin) - d) / den;
+
+ if (dist < -Mathf.Epsilon || dist > (1.0f + Mathf.Epsilon))
+ return new Vector3();
+
+ return begin + segment * -dist;
+ }
+
+ public bool is_point_over(Vector3 point)
+ {
+ return normal.dot(point) > d;
+ }
+
+ public Plane normalized()
+ {
+ float len = normal.length();
+
+ if (len == 0)
+ return new Plane(0, 0, 0, 0);
+
+ return new Plane(normal / len, d / len);
+ }
+
+ public Vector3 project(Vector3 point)
+ {
+ return point - normal * distance_to(point);
+ }
+
+ public Plane(float a, float b, float c, float d)
+ {
+ normal = new Vector3(a, b, c);
+ this.d = d;
+ }
+
+ public Plane(Vector3 normal, float d)
+ {
+ this.normal = normal;
+ this.d = d;
+ }
+
+ public Plane(Vector3 v1, Vector3 v2, Vector3 v3)
+ {
+ normal = (v1 - v3).cross(v1 - v2);
+ normal.normalize();
+ d = normal.dot(v1);
+ }
+
+ public static Plane operator -(Plane plane)
+ {
+ return new Plane(-plane.normal, -plane.d);
+ }
+
+ public static bool operator ==(Plane left, Plane right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Plane left, Plane right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Plane)
+ {
+ return Equals((Plane)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Plane other)
+ {
+ return normal == other.normal && d == other.d;
+ }
+
+ public override int GetHashCode()
+ {
+ return normal.GetHashCode() ^ d.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.normal.ToString(),
+ this.d.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.normal.ToString(format),
+ this.d.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Quat.cs b/modules/mono/glue/cs_files/Quat.cs
new file mode 100644
index 0000000000..9b4b7fb297
--- /dev/null
+++ b/modules/mono/glue/cs_files/Quat.cs
@@ -0,0 +1,328 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Quat : IEquatable<Quat>
+ {
+ private static readonly Quat identity = new Quat(0f, 0f, 0f, 1f);
+
+ public float x;
+ public float y;
+ public float z;
+ public float w;
+
+ public static Quat Identity
+ {
+ get { return identity; }
+ }
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ case 3:
+ w = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public Quat cubic_slerp(Quat b, Quat preA, Quat postB, float t)
+ {
+ float t2 = (1.0f - t) * t * 2f;
+ Quat sp = slerp(b, t);
+ Quat sq = preA.slerpni(postB, t);
+ return sp.slerpni(sq, t2);
+ }
+
+ public float dot(Quat b)
+ {
+ return x * b.x + y * b.y + z * b.z + w * b.w;
+ }
+
+ public Quat inverse()
+ {
+ return new Quat(-x, -y, -z, w);
+ }
+
+ public float length()
+ {
+ return Mathf.sqrt(length_squared());
+ }
+
+ public float length_squared()
+ {
+ return dot(this);
+ }
+
+ public Quat normalized()
+ {
+ return this / length();
+ }
+
+ public void set(float x, float y, float z, float w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ public Quat slerp(Quat b, float t)
+ {
+ // Calculate cosine
+ float cosom = x * b.x + y * b.y + z * b.z + w * b.w;
+
+ float[] to1 = new float[4];
+
+ // Adjust signs if necessary
+ if (cosom < 0.0)
+ {
+ cosom = -cosom; to1[0] = -b.x;
+ to1[1] = -b.y;
+ to1[2] = -b.z;
+ to1[3] = -b.w;
+ }
+ else
+ {
+ to1[0] = b.x;
+ to1[1] = b.y;
+ to1[2] = b.z;
+ to1[3] = b.w;
+ }
+
+ float sinom, scale0, scale1;
+
+ // Calculate coefficients
+ if ((1.0 - cosom) > Mathf.Epsilon)
+ {
+ // Standard case (Slerp)
+ float omega = Mathf.acos(cosom);
+ sinom = Mathf.sin(omega);
+ scale0 = Mathf.sin((1.0f - t) * omega) / sinom;
+ scale1 = Mathf.sin(t * omega) / sinom;
+ }
+ else
+ {
+ // Quaternions are very close so we can do a linear interpolation
+ scale0 = 1.0f - t;
+ scale1 = t;
+ }
+
+ // Calculate final values
+ return new Quat
+ (
+ scale0 * x + scale1 * to1[0],
+ scale0 * y + scale1 * to1[1],
+ scale0 * z + scale1 * to1[2],
+ scale0 * w + scale1 * to1[3]
+ );
+ }
+
+ public Quat slerpni(Quat b, float t)
+ {
+ float dot = this.dot(b);
+
+ if (Mathf.abs(dot) > 0.9999f)
+ {
+ return this;
+ }
+
+ float theta = Mathf.acos(dot);
+ float sinT = 1.0f / Mathf.sin(theta);
+ float newFactor = Mathf.sin(t * theta) * sinT;
+ float invFactor = Mathf.sin((1.0f - t) * theta) * sinT;
+
+ return new Quat
+ (
+ invFactor * this.x + newFactor * b.x,
+ invFactor * this.y + newFactor * b.y,
+ invFactor * this.z + newFactor * b.z,
+ invFactor * this.w + newFactor * b.w
+ );
+ }
+
+ public Vector3 xform(Vector3 v)
+ {
+ Quat q = this * v;
+ q *= this.inverse();
+ return new Vector3(q.x, q.y, q.z);
+ }
+
+ public Quat(float x, float y, float z, float w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ public Quat(Vector3 axis, float angle)
+ {
+ float d = axis.length();
+
+ if (d == 0f)
+ {
+ x = 0f;
+ y = 0f;
+ z = 0f;
+ w = 0f;
+ }
+ else
+ {
+ float s = Mathf.sin(angle * 0.5f) / d;
+
+ x = axis.x * s;
+ y = axis.y * s;
+ z = axis.z * s;
+ w = Mathf.cos(angle * 0.5f);
+ }
+ }
+
+ public static Quat operator *(Quat left, Quat right)
+ {
+ return new Quat
+ (
+ left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y,
+ left.w * right.y + left.y * right.w + left.z * right.x - left.x * right.z,
+ left.w * right.z + left.z * right.w + left.x * right.y - left.y * right.x,
+ left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z
+ );
+ }
+
+ public static Quat operator +(Quat left, Quat right)
+ {
+ return new Quat(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
+ }
+
+ public static Quat operator -(Quat left, Quat right)
+ {
+ return new Quat(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
+ }
+
+ public static Quat operator -(Quat left)
+ {
+ return new Quat(-left.x, -left.y, -left.z, -left.w);
+ }
+
+ public static Quat operator *(Quat left, Vector3 right)
+ {
+ return new Quat
+ (
+ left.w * right.x + left.y * right.z - left.z * right.y,
+ left.w * right.y + left.z * right.x - left.x * right.z,
+ left.w * right.z + left.x * right.y - left.y * right.x,
+ -left.x * right.x - left.y * right.y - left.z * right.z
+ );
+ }
+
+ public static Quat operator *(Vector3 left, Quat right)
+ {
+ return new Quat
+ (
+ right.w * left.x + right.y * left.z - right.z * left.y,
+ right.w * left.y + right.z * left.x - right.x * left.z,
+ right.w * left.z + right.x * left.y - right.y * left.x,
+ -right.x * left.x - right.y * left.y - right.z * left.z
+ );
+ }
+
+ public static Quat operator *(Quat left, float right)
+ {
+ return new Quat(left.x * right, left.y * right, left.z * right, left.w * right);
+ }
+
+ public static Quat operator *(float left, Quat right)
+ {
+ return new Quat(right.x * left, right.y * left, right.z * left, right.w * left);
+ }
+
+ public static Quat operator /(Quat left, float right)
+ {
+ return left * (1.0f / right);
+ }
+
+ public static bool operator ==(Quat left, Quat right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Quat left, Quat right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector2)
+ {
+ return Equals((Vector2)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Quat other)
+ {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2}, {3})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.z.ToString(),
+ this.w.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2}, {3})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.z.ToString(format),
+ this.w.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/RPCAttributes.cs b/modules/mono/glue/cs_files/RPCAttributes.cs
new file mode 100644
index 0000000000..08841ffd76
--- /dev/null
+++ b/modules/mono/glue/cs_files/RPCAttributes.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class RemoteAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class SyncAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class MasterAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class SlaveAttribute : Attribute {}
+}
diff --git a/modules/mono/glue/cs_files/Rect2.cs b/modules/mono/glue/cs_files/Rect2.cs
new file mode 100644
index 0000000000..019342134a
--- /dev/null
+++ b/modules/mono/glue/cs_files/Rect2.cs
@@ -0,0 +1,233 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Rect2 : IEquatable<Rect2>
+ {
+ private Vector2 position;
+ private Vector2 size;
+
+ public Vector2 Position
+ {
+ get { return position; }
+ set { position = value; }
+ }
+
+ public Vector2 Size
+ {
+ get { return size; }
+ set { size = value; }
+ }
+
+ public Vector2 End
+ {
+ get { return position + size; }
+ }
+
+ public float Area
+ {
+ get { return get_area(); }
+ }
+
+ public Rect2 clip(Rect2 b)
+ {
+ Rect2 newRect = b;
+
+ if (!intersects(newRect))
+ return new Rect2();
+
+ newRect.position.x = Mathf.max(b.position.x, position.x);
+ newRect.position.y = Mathf.max(b.position.y, position.y);
+
+ Vector2 bEnd = b.position + b.size;
+ Vector2 end = position + size;
+
+ newRect.size.x = Mathf.min(bEnd.x, end.x) - newRect.position.x;
+ newRect.size.y = Mathf.min(bEnd.y, end.y) - newRect.position.y;
+
+ return newRect;
+ }
+
+ public bool encloses(Rect2 b)
+ {
+ return (b.position.x >= position.x) && (b.position.y >= position.y) &&
+ ((b.position.x + b.size.x) < (position.x + size.x)) &&
+ ((b.position.y + b.size.y) < (position.y + size.y));
+ }
+
+ public Rect2 expand(Vector2 to)
+ {
+ Rect2 expanded = this;
+
+ Vector2 begin = expanded.position;
+ Vector2 end = expanded.position + expanded.size;
+
+ if (to.x < begin.x)
+ begin.x = to.x;
+ if (to.y < begin.y)
+ begin.y = to.y;
+
+ if (to.x > end.x)
+ end.x = to.x;
+ if (to.y > end.y)
+ end.y = to.y;
+
+ expanded.position = begin;
+ expanded.size = end - begin;
+
+ return expanded;
+ }
+
+ public float get_area()
+ {
+ return size.x * size.y;
+ }
+
+ public Rect2 grow(float by)
+ {
+ Rect2 g = this;
+
+ g.position.x -= by;
+ g.position.y -= by;
+ g.size.x += by * 2;
+ g.size.y += by * 2;
+
+ return g;
+ }
+
+ public Rect2 grow_individual(float left, float top, float right, float bottom)
+ {
+ Rect2 g = this;
+
+ g.position.x -= left;
+ g.position.y -= top;
+ g.size.x += left + right;
+ g.size.y += top + bottom;
+
+ return g;
+ }
+
+ public Rect2 grow_margin(int margin, float by)
+ {
+ Rect2 g = this;
+
+ g.grow_individual((GD.MARGIN_LEFT == margin) ? by : 0,
+ (GD.MARGIN_TOP == margin) ? by : 0,
+ (GD.MARGIN_RIGHT == margin) ? by : 0,
+ (GD.MARGIN_BOTTOM == margin) ? by : 0);
+
+ return g;
+ }
+
+ public bool has_no_area()
+ {
+ return size.x <= 0 || size.y <= 0;
+ }
+
+ public bool has_point(Vector2 point)
+ {
+ if (point.x < position.x)
+ return false;
+ if (point.y < position.y)
+ return false;
+
+ if (point.x >= (position.x + size.x))
+ return false;
+ if (point.y >= (position.y + size.y))
+ return false;
+
+ return true;
+ }
+
+ public bool intersects(Rect2 b)
+ {
+ if (position.x > (b.position.x + b.size.x))
+ return false;
+ if ((position.x + size.x) < b.position.x)
+ return false;
+ if (position.y > (b.position.y + b.size.y))
+ return false;
+ if ((position.y + size.y) < b.position.y)
+ return false;
+
+ return true;
+ }
+
+ public Rect2 merge(Rect2 b)
+ {
+ Rect2 newRect;
+
+ newRect.position.x = Mathf.min(b.position.x, position.x);
+ newRect.position.y = Mathf.min(b.position.y, position.y);
+
+ newRect.size.x = Mathf.max(b.position.x + b.size.x, position.x + size.x);
+ newRect.size.y = Mathf.max(b.position.y + b.size.y, position.y + size.y);
+
+ newRect.size = newRect.size - newRect.position; // Make relative again
+
+ return newRect;
+ }
+
+ public Rect2(Vector2 position, Vector2 size)
+ {
+ this.position = position;
+ this.size = size;
+ }
+
+ public Rect2(float x, float y, float width, float height)
+ {
+ this.position = new Vector2(x, y);
+ this.size = new Vector2(width, height);
+ }
+
+ public static bool operator ==(Rect2 left, Rect2 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Rect2 left, Rect2 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Rect2)
+ {
+ return Equals((Rect2)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Rect2 other)
+ {
+ return position.Equals(other.position) && size.Equals(other.size);
+ }
+
+ public override int GetHashCode()
+ {
+ return position.GetHashCode() ^ size.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.position.ToString(),
+ this.size.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.position.ToString(format),
+ this.size.ToString(format)
+ });
+ }
+ }
+} \ No newline at end of file
diff --git a/modules/mono/glue/cs_files/Rect3.cs b/modules/mono/glue/cs_files/Rect3.cs
new file mode 100644
index 0000000000..0d25de1ec6
--- /dev/null
+++ b/modules/mono/glue/cs_files/Rect3.cs
@@ -0,0 +1,477 @@
+using System;
+
+// file: core/math/rect3.h
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/math/rect3.cpp
+// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+
+namespace Godot
+{
+ public struct Rect3 : IEquatable<Rect3>
+ {
+ private Vector3 position;
+ private Vector3 size;
+
+ public Vector3 Position
+ {
+ get
+ {
+ return position;
+ }
+ }
+
+ public Vector3 Size
+ {
+ get
+ {
+ return size;
+ }
+ }
+
+ public Vector3 End
+ {
+ get
+ {
+ return position + size;
+ }
+ }
+
+ public bool encloses(Rect3 with)
+ {
+ Vector3 src_min = position;
+ Vector3 src_max = position + size;
+ Vector3 dst_min = with.position;
+ Vector3 dst_max = with.position + with.size;
+
+ return ((src_min.x <= dst_min.x) &&
+ (src_max.x > dst_max.x) &&
+ (src_min.y <= dst_min.y) &&
+ (src_max.y > dst_max.y) &&
+ (src_min.z <= dst_min.z) &&
+ (src_max.z > dst_max.z));
+ }
+
+ public Rect3 expand(Vector3 to_point)
+ {
+ Vector3 begin = position;
+ Vector3 end = position + size;
+
+ if (to_point.x < begin.x)
+ begin.x = to_point.x;
+ if (to_point.y < begin.y)
+ begin.y = to_point.y;
+ if (to_point.z < begin.z)
+ begin.z = to_point.z;
+
+ if (to_point.x > end.x)
+ end.x = to_point.x;
+ if (to_point.y > end.y)
+ end.y = to_point.y;
+ if (to_point.z > end.z)
+ end.z = to_point.z;
+
+ return new Rect3(begin, end - begin);
+ }
+
+ public float get_area()
+ {
+ return size.x * size.y * size.z;
+ }
+
+ public Vector3 get_endpoint(int idx)
+ {
+ switch (idx)
+ {
+ case 0:
+ return new Vector3(position.x, position.y, position.z);
+ case 1:
+ return new Vector3(position.x, position.y, position.z + size.z);
+ case 2:
+ return new Vector3(position.x, position.y + size.y, position.z);
+ case 3:
+ return new Vector3(position.x, position.y + size.y, position.z + size.z);
+ case 4:
+ return new Vector3(position.x + size.x, position.y, position.z);
+ case 5:
+ return new Vector3(position.x + size.x, position.y, position.z + size.z);
+ case 6:
+ return new Vector3(position.x + size.x, position.y + size.y, position.z);
+ case 7:
+ return new Vector3(position.x + size.x, position.y + size.y, position.z + size.z);
+ default:
+ throw new ArgumentOutOfRangeException(nameof(idx), String.Format("Index is {0}, but a value from 0 to 7 is expected.", idx));
+ }
+ }
+
+ public Vector3 get_longest_axis()
+ {
+ Vector3 axis = new Vector3(1f, 0f, 0f);
+ float max_size = size.x;
+
+ if (size.y > max_size)
+ {
+ axis = new Vector3(0f, 1f, 0f);
+ max_size = size.y;
+ }
+
+ if (size.z > max_size)
+ {
+ axis = new Vector3(0f, 0f, 1f);
+ max_size = size.z;
+ }
+
+ return axis;
+ }
+
+ public Vector3.Axis get_longest_axis_index()
+ {
+ Vector3.Axis axis = Vector3.Axis.X;
+ float max_size = size.x;
+
+ if (size.y > max_size)
+ {
+ axis = Vector3.Axis.Y;
+ max_size = size.y;
+ }
+
+ if (size.z > max_size)
+ {
+ axis = Vector3.Axis.Z;
+ max_size = size.z;
+ }
+
+ return axis;
+ }
+
+ public float get_longest_axis_size()
+ {
+ float max_size = size.x;
+
+ if (size.y > max_size)
+ max_size = size.y;
+
+ if (size.z > max_size)
+ max_size = size.z;
+
+ return max_size;
+ }
+
+ public Vector3 get_shortest_axis()
+ {
+ Vector3 axis = new Vector3(1f, 0f, 0f);
+ float max_size = size.x;
+
+ if (size.y < max_size)
+ {
+ axis = new Vector3(0f, 1f, 0f);
+ max_size = size.y;
+ }
+
+ if (size.z < max_size)
+ {
+ axis = new Vector3(0f, 0f, 1f);
+ max_size = size.z;
+ }
+
+ return axis;
+ }
+
+ public Vector3.Axis get_shortest_axis_index()
+ {
+ Vector3.Axis axis = Vector3.Axis.X;
+ float max_size = size.x;
+
+ if (size.y < max_size)
+ {
+ axis = Vector3.Axis.Y;
+ max_size = size.y;
+ }
+
+ if (size.z < max_size)
+ {
+ axis = Vector3.Axis.Z;
+ max_size = size.z;
+ }
+
+ return axis;
+ }
+
+ public float get_shortest_axis_size()
+ {
+ float max_size = size.x;
+
+ if (size.y < max_size)
+ max_size = size.y;
+
+ if (size.z < max_size)
+ max_size = size.z;
+
+ return max_size;
+ }
+
+ public Vector3 get_support(Vector3 dir)
+ {
+ Vector3 half_extents = size * 0.5f;
+ Vector3 ofs = position + half_extents;
+
+ return ofs + new Vector3(
+ (dir.x > 0f) ? -half_extents.x : half_extents.x,
+ (dir.y > 0f) ? -half_extents.y : half_extents.y,
+ (dir.z > 0f) ? -half_extents.z : half_extents.z);
+ }
+
+ public Rect3 grow(float by)
+ {
+ Rect3 res = this;
+
+ res.position.x -= by;
+ res.position.y -= by;
+ res.position.z -= by;
+ res.size.x += 2.0f * by;
+ res.size.y += 2.0f * by;
+ res.size.z += 2.0f * by;
+
+ return res;
+ }
+
+ public bool has_no_area()
+ {
+ return size.x <= 0f || size.y <= 0f || size.z <= 0f;
+ }
+
+ public bool has_no_surface()
+ {
+ return size.x <= 0f && size.y <= 0f && size.z <= 0f;
+ }
+
+ public bool has_point(Vector3 point)
+ {
+ if (point.x < position.x)
+ return false;
+ if (point.y < position.y)
+ return false;
+ if (point.z < position.z)
+ return false;
+ if (point.x > position.x + size.x)
+ return false;
+ if (point.y > position.y + size.y)
+ return false;
+ if (point.z > position.z + size.z)
+ return false;
+
+ return true;
+ }
+
+ public Rect3 intersection(Rect3 with)
+ {
+ Vector3 src_min = position;
+ Vector3 src_max = position + size;
+ Vector3 dst_min = with.position;
+ Vector3 dst_max = with.position + with.size;
+
+ Vector3 min, max;
+
+ if (src_min.x > dst_max.x || src_max.x < dst_min.x)
+ {
+ return new Rect3();
+ }
+ else
+ {
+ min.x = (src_min.x > dst_min.x) ? src_min.x : dst_min.x;
+ max.x = (src_max.x < dst_max.x) ? src_max.x : dst_max.x;
+ }
+
+ if (src_min.y > dst_max.y || src_max.y < dst_min.y)
+ {
+ return new Rect3();
+ }
+ else
+ {
+ min.y = (src_min.y > dst_min.y) ? src_min.y : dst_min.y;
+ max.y = (src_max.y < dst_max.y) ? src_max.y : dst_max.y;
+ }
+
+ if (src_min.z > dst_max.z || src_max.z < dst_min.z)
+ {
+ return new Rect3();
+ }
+ else
+ {
+ min.z = (src_min.z > dst_min.z) ? src_min.z : dst_min.z;
+ max.z = (src_max.z < dst_max.z) ? src_max.z : dst_max.z;
+ }
+
+ return new Rect3(min, max - min);
+ }
+
+ public bool intersects(Rect3 with)
+ {
+ if (position.x >= (with.position.x + with.size.x))
+ return false;
+ if ((position.x + size.x) <= with.position.x)
+ return false;
+ if (position.y >= (with.position.y + with.size.y))
+ return false;
+ if ((position.y + size.y) <= with.position.y)
+ return false;
+ if (position.z >= (with.position.z + with.size.z))
+ return false;
+ if ((position.z + size.z) <= with.position.z)
+ return false;
+
+ return true;
+ }
+
+ public bool intersects_plane(Plane plane)
+ {
+ Vector3[] points =
+ {
+ new Vector3(position.x, position.y, position.z),
+ new Vector3(position.x, position.y, position.z + size.z),
+ new Vector3(position.x, position.y + size.y, position.z),
+ new Vector3(position.x, position.y + size.y, position.z + size.z),
+ new Vector3(position.x + size.x, position.y, position.z),
+ new Vector3(position.x + size.x, position.y, position.z + size.z),
+ new Vector3(position.x + size.x, position.y + size.y, position.z),
+ new Vector3(position.x + size.x, position.y + size.y, position.z + size.z),
+ };
+
+ bool over = false;
+ bool under = false;
+
+ for (int i = 0; i < 8; i++)
+ {
+ if (plane.distance_to(points[i]) > 0)
+ over = true;
+ else
+ under = true;
+ }
+
+ return under && over;
+ }
+
+ public bool intersects_segment(Vector3 from, Vector3 to)
+ {
+ float min = 0f;
+ float max = 1f;
+
+ for (int i = 0; i < 3; i++)
+ {
+ float seg_from = from[i];
+ float seg_to = to[i];
+ float box_begin = position[i];
+ float box_end = box_begin + size[i];
+ float cmin, cmax;
+
+ if (seg_from < seg_to)
+ {
+ if (seg_from > box_end || seg_to < box_begin)
+ return false;
+
+ float length = seg_to - seg_from;
+ cmin = seg_from < box_begin ? (box_begin - seg_from) / length : 0f;
+ cmax = seg_to > box_end ? (box_end - seg_from) / length : 1f;
+ }
+ else
+ {
+ if (seg_to > box_end || seg_from < box_begin)
+ return false;
+
+ float length = seg_to - seg_from;
+ cmin = seg_from > box_end ? (box_end - seg_from) / length : 0f;
+ cmax = seg_to < box_begin ? (box_begin - seg_from) / length : 1f;
+ }
+
+ if (cmin > min)
+ {
+ min = cmin;
+ }
+
+ if (cmax < max)
+ max = cmax;
+ if (max < min)
+ return false;
+ }
+
+ return true;
+ }
+
+ public Rect3 merge(Rect3 with)
+ {
+ Vector3 beg_1 = position;
+ Vector3 beg_2 = with.position;
+ Vector3 end_1 = new Vector3(size.x, size.y, size.z) + beg_1;
+ Vector3 end_2 = new Vector3(with.size.x, with.size.y, with.size.z) + beg_2;
+
+ Vector3 min = new Vector3(
+ (beg_1.x < beg_2.x) ? beg_1.x : beg_2.x,
+ (beg_1.y < beg_2.y) ? beg_1.y : beg_2.y,
+ (beg_1.z < beg_2.z) ? beg_1.z : beg_2.z
+ );
+
+ Vector3 max = new Vector3(
+ (end_1.x > end_2.x) ? end_1.x : end_2.x,
+ (end_1.y > end_2.y) ? end_1.y : end_2.y,
+ (end_1.z > end_2.z) ? end_1.z : end_2.z
+ );
+
+ return new Rect3(min, max - min);
+ }
+
+ public Rect3(Vector3 position, Vector3 size)
+ {
+ this.position = position;
+ this.size = size;
+ }
+
+ public static bool operator ==(Rect3 left, Rect3 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Rect3 left, Rect3 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Rect3)
+ {
+ return Equals((Rect3)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Rect3 other)
+ {
+ return position == other.position && size == other.size;
+ }
+
+ public override int GetHashCode()
+ {
+ return position.GetHashCode() ^ size.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ this.position.ToString(),
+ this.size.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ this.position.ToString(format),
+ this.size.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/SignalAwaiter.cs b/modules/mono/glue/cs_files/SignalAwaiter.cs
new file mode 100644
index 0000000000..19ccc26e79
--- /dev/null
+++ b/modules/mono/glue/cs_files/SignalAwaiter.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace Godot
+{
+ public class SignalAwaiter : IAwaiter<object[]>, IAwaitable<object[]>
+ {
+ private bool completed = false;
+ private object[] result = null;
+ private Action action = null;
+
+ public SignalAwaiter(Godot.Object source, string signal, Godot.Object target)
+ {
+ NativeCalls.godot_icall_Object_connect_signal_awaiter(
+ Godot.Object.GetPtr(source),
+ signal, Godot.Object.GetPtr(target), this
+ );
+ }
+
+ public bool IsCompleted
+ {
+ get
+ {
+ return completed;
+ }
+ }
+
+ public void OnCompleted(Action action)
+ {
+ this.action = action;
+ }
+
+ public object[] GetResult()
+ {
+ return result;
+ }
+
+ public IAwaiter<object[]> GetAwaiter()
+ {
+ return this;
+ }
+
+ internal void SignalCallback(object[] args)
+ {
+ completed = true;
+ result = args;
+
+ if (action != null)
+ {
+ action();
+ }
+ }
+
+ internal void FailureCallback()
+ {
+ action = null;
+ completed = true;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/StringExtensions.cs b/modules/mono/glue/cs_files/StringExtensions.cs
new file mode 100644
index 0000000000..96041827aa
--- /dev/null
+++ b/modules/mono/glue/cs_files/StringExtensions.cs
@@ -0,0 +1,962 @@
+//using System;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Security;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Godot
+{
+ public static class StringExtensions
+ {
+ private static int get_slice_count(this string instance, string splitter)
+ {
+ if (instance.empty() || splitter.empty())
+ return 0;
+
+ int pos = 0;
+ int slices = 1;
+
+ while ((pos = instance.find(splitter, pos)) >= 0)
+ {
+ slices++;
+ pos += splitter.Length;
+ }
+
+ return slices;
+ }
+
+ private static string get_slicec(this string instance, char splitter, int slice)
+ {
+ if (!instance.empty() && slice >= 0)
+ {
+ int i = 0;
+ int prev = 0;
+ int count = 0;
+
+ while (true)
+ {
+ if (instance[i] == 0 || instance[i] == splitter)
+ {
+ if (slice == count)
+ {
+ return instance.Substring(prev, i - prev);
+ }
+ else
+ {
+ count++;
+ prev = i + 1;
+ }
+ }
+
+ i++;
+ }
+ }
+
+ return string.Empty;
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the path to the file without the extension.
+ // </summary>
+ public static string basename(this string instance)
+ {
+ int index = instance.LastIndexOf('.');
+
+ if (index > 0)
+ return instance.Substring(0, index);
+
+ return instance;
+ }
+
+ // <summary>
+ // Return true if the strings begins with the given string.
+ // </summary>
+ public static bool begins_with(this string instance, string text)
+ {
+ return instance.StartsWith(text);
+ }
+
+ // <summary>
+ // Return the bigrams (pairs of consecutive letters) of this string.
+ // </summary>
+ public static string[] bigrams(this string instance)
+ {
+ string[] b = new string[instance.Length - 1];
+
+ for (int i = 0; i < b.Length; i++)
+ {
+ b[i] = instance.Substring(i, 2);
+ }
+
+ return b;
+ }
+
+ // <summary>
+ // Return a copy of the string with special characters escaped using the C language standard.
+ // </summary>
+ public static string c_escape(this string instance)
+ {
+ StringBuilder sb = new StringBuilder(string.Copy(instance));
+
+ sb.Replace("\\", "\\\\");
+ sb.Replace("\a", "\\a");
+ sb.Replace("\b", "\\b");
+ sb.Replace("\f", "\\f");
+ sb.Replace("\n", "\\n");
+ sb.Replace("\r", "\\r");
+ sb.Replace("\t", "\\t");
+ sb.Replace("\v", "\\v");
+ sb.Replace("\'", "\\'");
+ sb.Replace("\"", "\\\"");
+ sb.Replace("?", "\\?");
+
+ return sb.ToString();
+ }
+
+ // <summary>
+ // Return a copy of the string with escaped characters replaced by their meanings according to the C language standard.
+ // </summary>
+ public static string c_unescape(this string instance)
+ {
+ StringBuilder sb = new StringBuilder(string.Copy(instance));
+
+ sb.Replace("\\a", "\a");
+ sb.Replace("\\b", "\b");
+ sb.Replace("\\f", "\f");
+ sb.Replace("\\n", "\n");
+ sb.Replace("\\r", "\r");
+ sb.Replace("\\t", "\t");
+ sb.Replace("\\v", "\v");
+ sb.Replace("\\'", "\'");
+ sb.Replace("\\\"", "\"");
+ sb.Replace("\\?", "?");
+ sb.Replace("\\\\", "\\");
+
+ return sb.ToString();
+ }
+
+ // <summary>
+ // Change the case of some letters. Replace underscores with spaces, convert all letters to lowercase then capitalize first and every letter following the space character. For [code]capitalize camelCase mixed_with_underscores[/code] it will return [code]Capitalize Camelcase Mixed With Underscores[/code].
+ // </summary>
+ public static string capitalize(this string instance)
+ {
+ string aux = instance.Replace("_", " ").ToLower();
+ string cap = string.Empty;
+
+ for (int i = 0; i < aux.get_slice_count(" "); i++)
+ {
+ string slice = aux.get_slicec(' ', i);
+ if (slice.Length > 0)
+ {
+ slice = char.ToUpper(slice[0]) + slice.Substring(1);
+ if (i > 0)
+ cap += " ";
+ cap += slice;
+ }
+ }
+
+ return cap;
+ }
+
+ // <summary>
+ // Perform a case-sensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
+ // </summary>
+ public static int casecmp_to(this string instance, string to)
+ {
+ if (instance.empty())
+ return to.empty() ? 0 : -1;
+
+ if (to.empty())
+ return 1;
+
+ int instance_idx = 0;
+ int to_idx = 0;
+
+ while (true)
+ {
+ if (to[to_idx] == 0 && instance[instance_idx] == 0)
+ return 0; // We're equal
+ else if (instance[instance_idx] == 0)
+ return -1; // If this is empty, and the other one is not, then we're less... I think?
+ else if (to[to_idx] == 0)
+ return 1; // Otherwise the other one is smaller...
+ else if (instance[instance_idx] < to[to_idx]) // More than
+ return -1;
+ else if (instance[instance_idx] > to[to_idx]) // Less than
+ return 1;
+
+ instance_idx++;
+ to_idx++;
+ }
+ }
+
+ // <summary>
+ // Return true if the string is empty.
+ // </summary>
+ public static bool empty(this string instance)
+ {
+ return string.IsNullOrEmpty(instance);
+ }
+
+ // <summary>
+ // Return true if the strings ends with the given string.
+ // </summary>
+ public static bool ends_with(this string instance, string text)
+ {
+ return instance.EndsWith(text);
+ }
+
+ // <summary>
+ // Erase [code]chars[/code] characters from the string starting from [code]pos[/code].
+ // </summary>
+ public static void erase(this StringBuilder instance, int pos, int chars)
+ {
+ instance.Remove(pos, chars);
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the extension.
+ // </summary>
+ public static string extension(this string instance)
+ {
+ int pos = instance.find_last(".");
+
+ if (pos < 0)
+ return instance;
+
+ return instance.Substring(pos + 1, instance.Length);
+ }
+
+ // <summary>
+ // Find the first occurrence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int find(this string instance, string what, int from = 0)
+ {
+ return instance.IndexOf(what, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // <summary>
+ // Find the last occurrence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int find_last(this string instance, string what)
+ {
+ return instance.LastIndexOf(what, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // <summary>
+ // Find the first occurrence of a substring but search as case-insensitive, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int findn(this string instance, string what, int from = 0)
+ {
+ return instance.IndexOf(what, StringComparison.Ordinal);
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the base directory.
+ // </summary>
+ public static string get_base_dir(this string instance)
+ {
+ int basepos = instance.find("://");
+
+ string rs = string.Empty;
+ string @base = string.Empty;
+
+ if (basepos != -1)
+ {
+ int end = basepos + 3;
+ rs = instance.Substring(end, instance.Length);
+ @base = instance.Substring(0, end);
+ }
+ else
+ {
+ if (instance.begins_with("/"))
+ {
+ rs = instance.Substring(1, instance.Length);
+ @base = "/";
+ }
+ else
+ {
+ rs = instance;
+ }
+ }
+
+ int sep = Mathf.max(rs.find_last("/"), rs.find_last("\\"));
+
+ if (sep == -1)
+ return @base;
+
+ return @base + rs.substr(0, sep);
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the file and ignore the base directory.
+ // </summary>
+ public static string get_file(this string instance)
+ {
+ int sep = Mathf.max(instance.find_last("/"), instance.find_last("\\"));
+
+ if (sep == -1)
+ return instance;
+
+ return instance.Substring(sep + 1, instance.Length);
+ }
+
+ // <summary>
+ // Hash the string and return a 32 bits integer.
+ // </summary>
+ public static int hash(this string instance)
+ {
+ int index = 0;
+ int hashv = 5381;
+ int c;
+
+ while ((c = (int)instance[index++]) != 0)
+ hashv = ((hashv << 5) + hashv) + c; // hash * 33 + c
+
+ return hashv;
+ }
+
+ // <summary>
+ // Convert a string containing an hexadecimal number into an int.
+ // </summary>
+ public static int hex_to_int(this string instance)
+ {
+ int sign = 1;
+
+ if (instance[0] == '-')
+ {
+ sign = -1;
+ instance = instance.Substring(1);
+ }
+
+ if (!instance.StartsWith("0x"))
+ return 0;
+
+ return sign * int.Parse(instance.Substring(2), NumberStyles.HexNumber);
+ }
+
+ // <summary>
+ // Insert a substring at a given position.
+ // </summary>
+ public static string insert(this string instance, int pos, string what)
+ {
+ return instance.Insert(pos, what);
+ }
+
+ // <summary>
+ // If the string is a path to a file or directory, return true if the path is absolute.
+ // </summary>
+ public static bool is_abs_path(this string instance)
+ {
+ return System.IO.Path.IsPathRooted(instance);
+ }
+
+ // <summary>
+ // If the string is a path to a file or directory, return true if the path is relative.
+ // </summary>
+ public static bool is_rel_path(this string instance)
+ {
+ return !System.IO.Path.IsPathRooted(instance);
+ }
+
+ // <summary>
+ // Check whether this string is a subsequence of the given string.
+ // </summary>
+ public static bool is_subsequence_of(this string instance, string text, bool case_insensitive)
+ {
+ int len = instance.Length;
+
+ if (len == 0)
+ return true; // Technically an empty string is subsequence of any string
+
+ if (len > text.Length)
+ return false;
+
+ int src = 0;
+ int tgt = 0;
+
+ while (instance[src] != 0 && text[tgt] != 0)
+ {
+ bool match = false;
+
+ if (case_insensitive)
+ {
+ char srcc = char.ToLower(instance[src]);
+ char tgtc = char.ToLower(text[tgt]);
+ match = srcc == tgtc;
+ }
+ else
+ {
+ match = instance[src] == text[tgt];
+ }
+ if (match)
+ {
+ src++;
+ if (instance[src] == 0)
+ return true;
+ }
+
+ tgt++;
+ }
+
+ return false;
+ }
+
+ // <summary>
+ // Check whether this string is a subsequence of the given string, considering case.
+ // </summary>
+ public static bool is_subsequence_of(this string instance, string text)
+ {
+ return instance.is_subsequence_of(text, false);
+ }
+
+ // <summary>
+ // Check whether this string is a subsequence of the given string, without considering case.
+ // </summary>
+ public static bool is_subsequence_ofi(this string instance, string text)
+ {
+ return instance.is_subsequence_of(text, true);
+ }
+
+ // <summary>
+ // Check whether the string contains a valid float.
+ // </summary>
+ public static bool is_valid_float(this string instance)
+ {
+ float f;
+ return float.TryParse(instance, out f);
+ }
+
+ // <summary>
+ // Check whether the string contains a valid color in HTML notation.
+ // </summary>
+ public static bool is_valid_html_color(this string instance)
+ {
+ return Color.html_is_valid(instance);
+ }
+
+ // <summary>
+ // Check whether the string is a valid identifier. As is common in programming languages, a valid identifier may contain only letters, digits and underscores (_) and the first character may not be a digit.
+ // </summary>
+ public static bool is_valid_identifier(this string instance)
+ {
+ int len = instance.Length;
+
+ if (len == 0)
+ return false;
+
+ for (int i = 0; i < len; i++)
+ {
+ if (i == 0)
+ {
+ if (instance[0] >= '0' && instance[0] <= '9')
+ return false; // Don't start with number plz
+ }
+
+ bool valid_char = (instance[i] >= '0' && instance[i] <= '9') || (instance[i] >= 'a' && instance[i] <= 'z') || (instance[i] >= 'A' && instance[i] <= 'Z') || instance[i] == '_';
+
+ if (!valid_char)
+ return false;
+ }
+
+ return true;
+ }
+
+ // <summary>
+ // Check whether the string contains a valid integer.
+ // </summary>
+ public static bool is_valid_integer(this string instance)
+ {
+ int f;
+ return int.TryParse(instance, out f);
+ }
+
+ // <summary>
+ // Check whether the string contains a valid IP address.
+ // </summary>
+ public static bool is_valid_ip_address(this string instance)
+ {
+ string[] ip = instance.split(".");
+
+ if (ip.Length != 4)
+ return false;
+
+ for (int i = 0; i < ip.Length; i++)
+ {
+ string n = ip[i];
+ if (!n.is_valid_integer())
+ return false;
+
+ int val = n.to_int();
+ if (val < 0 || val > 255)
+ return false;
+ }
+
+ return true;
+ }
+
+ // <summary>
+ // Return a copy of the string with special characters escaped using the JSON standard.
+ // </summary>
+ public static string json_escape(this string instance)
+ {
+ StringBuilder sb = new StringBuilder(string.Copy(instance));
+
+ sb.Replace("\\", "\\\\");
+ sb.Replace("\b", "\\b");
+ sb.Replace("\f", "\\f");
+ sb.Replace("\n", "\\n");
+ sb.Replace("\r", "\\r");
+ sb.Replace("\t", "\\t");
+ sb.Replace("\v", "\\v");
+ sb.Replace("\"", "\\\"");
+
+ return sb.ToString();
+ }
+
+ // <summary>
+ // Return an amount of characters from the left of the string.
+ // </summary>
+ public static string left(this string instance, int pos)
+ {
+ if (pos <= 0)
+ return string.Empty;
+
+ if (pos >= instance.Length)
+ return instance;
+
+ return instance.Substring(0, pos);
+ }
+
+ /// <summary>
+ /// Return the length of the string in characters.
+ /// </summary>
+ public static int length(this string instance)
+ {
+ return instance.Length;
+ }
+
+ // <summary>
+ // Do a simple expression match, where '*' matches zero or more arbitrary characters and '?' matches any single character except '.'.
+ // </summary>
+ public static bool expr_match(this string instance, string expr, bool case_sensitive)
+ {
+ if (expr.Length == 0 || instance.Length == 0)
+ return false;
+
+ switch (expr[0])
+ {
+ case '\0':
+ return instance[0] == 0;
+ case '*':
+ return expr_match(expr + 1, instance, case_sensitive) || (instance[0] != 0 && expr_match(expr, instance + 1, case_sensitive));
+ case '?':
+ return instance[0] != 0 && instance[0] != '.' && expr_match(expr + 1, instance + 1, case_sensitive);
+ default:
+ return (case_sensitive ? instance[0] == expr[0] : char.ToUpper(instance[0]) == char.ToUpper(expr[0])) &&
+ expr_match(expr + 1, instance + 1, case_sensitive);
+ }
+ }
+
+ // <summary>
+ // Do a simple case sensitive expression match, using ? and * wildcards (see [method expr_match]).
+ // </summary>
+ public static bool match(this string instance, string expr)
+ {
+ return instance.expr_match(expr, true);
+ }
+
+ // <summary>
+ // Do a simple case insensitive expression match, using ? and * wildcards (see [method expr_match]).
+ // </summary>
+ public static bool matchn(this string instance, string expr)
+ {
+ return instance.expr_match(expr, false);
+ }
+
+ // <summary>
+ // Return the MD5 hash of the string as an array of bytes.
+ // </summary>
+ public static byte[] md5_buffer(this string instance)
+ {
+ return NativeCalls.godot_icall_String_md5_buffer(instance);
+ }
+
+ // <summary>
+ // Return the MD5 hash of the string as a string.
+ // </summary>
+ public static string md5_text(this string instance)
+ {
+ return NativeCalls.godot_icall_String_md5_text(instance);
+ }
+
+ // <summary>
+ // Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
+ // </summary>
+ public static int nocasecmp_to(this string instance, string to)
+ {
+ if (instance.empty())
+ return to.empty() ? 0 : -1;
+
+ if (to.empty())
+ return 1;
+
+ int instance_idx = 0;
+ int to_idx = 0;
+
+ while (true)
+ {
+ if (to[to_idx] == 0 && instance[instance_idx] == 0)
+ return 0; // We're equal
+ else if (instance[instance_idx] == 0)
+ return -1; // If this is empty, and the other one is not, then we're less... I think?
+ else if (to[to_idx] == 0)
+ return 1; // Otherwise the other one is smaller..
+ else if (char.ToUpper(instance[instance_idx]) < char.ToUpper(to[to_idx])) // More than
+ return -1;
+ else if (char.ToUpper(instance[instance_idx]) > char.ToUpper(to[to_idx])) // Less than
+ return 1;
+
+ instance_idx++;
+ to_idx++;
+ }
+ }
+
+ // <summary>
+ // Return the character code at position [code]at[/code].
+ // </summary>
+ public static int ord_at(this string instance, int at)
+ {
+ return instance[at];
+ }
+
+ // <summary>
+ // Format a number to have an exact number of [code]digits[/code] after the decimal point.
+ // </summary>
+ public static string pad_decimals(this string instance, int digits)
+ {
+ int c = instance.find(".");
+
+ if (c == -1)
+ {
+ if (digits <= 0)
+ return instance;
+
+ instance += ".";
+ c = instance.Length - 1;
+ }
+ else
+ {
+ if (digits <= 0)
+ return instance.Substring(0, c);
+ }
+
+ if (instance.Length - (c + 1) > digits)
+ {
+ instance = instance.Substring(0, c + digits + 1);
+ }
+ else
+ {
+ while (instance.Length - (c + 1) < digits)
+ {
+ instance += "0";
+ }
+ }
+
+ return instance;
+ }
+
+ // <summary>
+ // Format a number to have an exact number of [code]digits[/code] before the decimal point.
+ // </summary>
+ public static string pad_zeros(this string instance, int digits)
+ {
+ string s = instance;
+ int end = s.find(".");
+
+ if (end == -1)
+ end = s.Length;
+
+ if (end == 0)
+ return s;
+
+ int begin = 0;
+
+ while (begin < end && (s[begin] < '0' || s[begin] > '9'))
+ {
+ begin++;
+ }
+
+ if (begin >= end)
+ return s;
+
+ while (end - begin < digits)
+ {
+ s = s.Insert(begin, "0");
+ end++;
+ }
+
+ return s;
+ }
+
+ // <summary>
+ // Decode a percent-encoded string. See [method percent_encode].
+ // </summary>
+ public static string percent_decode(this string instance)
+ {
+ return Uri.UnescapeDataString(instance);
+ }
+
+ // <summary>
+ // Percent-encode a string. This is meant to encode parameters in a URL when sending a HTTP GET request and bodies of form-urlencoded POST request.
+ // </summary>
+ public static string percent_encode(this string instance)
+ {
+ return Uri.EscapeDataString(instance);
+ }
+
+ // <summary>
+ // If the string is a path, this concatenates [code]file[/code] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code].
+ // </summary>
+ public static string plus_file(this string instance, string file)
+ {
+ if (instance.Length > 0 && instance[instance.Length - 1] == '/')
+ return instance + file;
+ else
+ return instance + "/" + file;
+ }
+
+ // <summary>
+ // Replace occurrences of a substring for different ones inside the string.
+ // </summary>
+ public static string replace(this string instance, string what, string forwhat)
+ {
+ return instance.Replace(what, forwhat);
+ }
+
+ // <summary>
+ // Replace occurrences of a substring for different ones inside the string, but search case-insensitive.
+ // </summary>
+ public static string replacen(this string instance, string what, string forwhat)
+ {
+ return Regex.Replace(instance, what, forwhat, RegexOptions.IgnoreCase);
+ }
+
+ // <summary>
+ // Perform a search for a substring, but start from the end of the string instead of the beginning.
+ // </summary>
+ public static int rfind(this string instance, string what, int from = -1)
+ {
+ return NativeCalls.godot_icall_String_rfind(instance, what, from);
+ }
+
+ // <summary>
+ // Perform a search for a substring, but start from the end of the string instead of the beginning. Also search case-insensitive.
+ // </summary>
+ public static int rfindn(this string instance, string what, int from = -1)
+ {
+ return NativeCalls.godot_icall_String_rfindn(instance, what, from);
+ }
+
+ // <summary>
+ // Return the right side of the string from a given position.
+ // </summary>
+ public static string right(this string instance, int pos)
+ {
+ if (pos >= instance.Length)
+ return instance;
+
+ if (pos < 0)
+ return string.Empty;
+
+ return instance.Substring(pos, (instance.Length - pos));
+ }
+
+ public static byte[] sha256_buffer(this string instance)
+ {
+ return NativeCalls.godot_icall_String_sha256_buffer(instance);
+ }
+
+ // <summary>
+ // Return the SHA-256 hash of the string as a string.
+ // </summary>
+ public static string sha256_text(this string instance)
+ {
+ return NativeCalls.godot_icall_String_sha256_text(instance);
+ }
+
+ // <summary>
+ // Return the similarity index of the text compared to this string. 1 means totally similar and 0 means totally dissimilar.
+ // </summary>
+ public static float similarity(this string instance, string text)
+ {
+ if (instance == text)
+ {
+ // Equal strings are totally similar
+ return 1.0f;
+ }
+ if (instance.Length < 2 || text.Length < 2)
+ {
+ // No way to calculate similarity without a single bigram
+ return 0.0f;
+ }
+
+ string[] src_bigrams = instance.bigrams();
+ string[] tgt_bigrams = text.bigrams();
+
+ int src_size = src_bigrams.Length;
+ int tgt_size = tgt_bigrams.Length;
+
+ float sum = src_size + tgt_size;
+ float inter = 0;
+
+ for (int i = 0; i < src_size; i++)
+ {
+ for (int j = 0; j < tgt_size; j++)
+ {
+ if (src_bigrams[i] == tgt_bigrams[j])
+ {
+ inter++;
+ break;
+ }
+ }
+ }
+
+ return (2.0f * inter) / sum;
+ }
+
+ // <summary>
+ // Split the string by a divisor string, return an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",".
+ // </summary>
+ public static string[] split(this string instance, string divisor, bool allow_empty = true)
+ {
+ return instance.Split(new string[] { divisor }, StringSplitOptions.RemoveEmptyEntries);
+ }
+
+ // <summary>
+ // Split the string in floats by using a divisor string, return an array of the substrings. Example "1,2.5,3" will return [1,2.5,3] if split by ",".
+ // </summary>
+ public static float[] split_floats(this string instance, string divisor, bool allow_empty = true)
+ {
+ List<float> ret = new List<float>();
+ int from = 0;
+ int len = instance.Length;
+
+ while (true)
+ {
+ int end = instance.find(divisor, from);
+ if (end < 0)
+ end = len;
+ if (allow_empty || (end > from))
+ ret.Add(float.Parse(instance.Substring(from)));
+ if (end == len)
+ break;
+
+ from = end + divisor.Length;
+ }
+
+ return ret.ToArray();
+ }
+
+ private static readonly char[] non_printable = {
+ (char)00, (char)01, (char)02, (char)03, (char)04, (char)05,
+ (char)06, (char)07, (char)08, (char)09, (char)10, (char)11,
+ (char)12, (char)13, (char)14, (char)15, (char)16, (char)17,
+ (char)18, (char)19, (char)20, (char)21, (char)22, (char)23,
+ (char)24, (char)25, (char)26, (char)27, (char)28, (char)29,
+ (char)30, (char)31, (char)32
+ };
+
+ // <summary>
+ // Return a copy of the string stripped of any non-printable character at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively.
+ // </summary>
+ public static string strip_edges(this string instance, bool left = true, bool right = true)
+ {
+ if (left)
+ {
+ if (right)
+ return instance.Trim(non_printable);
+ else
+ return instance.TrimStart(non_printable);
+ }
+ else
+ {
+ return instance.TrimEnd(non_printable);
+ }
+ }
+
+ // <summary>
+ // Return part of the string from the position [code]from[/code], with length [code]len[/code].
+ // </summary>
+ public static string substr(this string instance, int from, int len)
+ {
+ return instance.Substring(from, len);
+ }
+
+ // <summary>
+ // Convert the String (which is a character array) to PoolByteArray (which is an array of bytes). The conversion is speeded up in comparison to to_utf8() with the assumption that all the characters the String contains are only ASCII characters.
+ // </summary>
+ public static byte[] to_ascii(this string instance)
+ {
+ return Encoding.ASCII.GetBytes(instance);
+ }
+
+ // <summary>
+ // Convert a string, containing a decimal number, into a [code]float[/code].
+ // </summary>
+ public static float to_float(this string instance)
+ {
+ return float.Parse(instance);
+ }
+
+ // <summary>
+ // Convert a string, containing an integer number, into an [code]int[/code].
+ // </summary>
+ public static int to_int(this string instance)
+ {
+ return int.Parse(instance);
+ }
+
+ // <summary>
+ // Return the string converted to lowercase.
+ // </summary>
+ public static string to_lower(this string instance)
+ {
+ return instance.ToLower();
+ }
+
+ // <summary>
+ // Return the string converted to uppercase.
+ // </summary>
+ public static string to_upper(this string instance)
+ {
+ return instance.ToUpper();
+ }
+
+ // <summary>
+ // Convert the String (which is an array of characters) to PoolByteArray (which is an array of bytes). The conversion is a bit slower than to_ascii(), but supports all UTF-8 characters. Therefore, you should prefer this function over to_ascii().
+ // </summary>
+ public static byte[] to_utf8(this string instance)
+ {
+ return Encoding.UTF8.GetBytes(instance);
+ }
+
+ // <summary>
+ // Return a copy of the string with special characters escaped using the XML standard.
+ // </summary>
+ public static string xml_escape(this string instance)
+ {
+ return SecurityElement.Escape(instance);
+ }
+
+ // <summary>
+ // Return a copy of the string with escaped characters replaced by their meanings according to the XML standard.
+ // </summary>
+ public static string xml_unescape(this string instance)
+ {
+ return SecurityElement.FromString(instance).Text;
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/ToolAttribute.cs b/modules/mono/glue/cs_files/ToolAttribute.cs
new file mode 100644
index 0000000000..0275982c7f
--- /dev/null
+++ b/modules/mono/glue/cs_files/ToolAttribute.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class ToolAttribute : Attribute {}
+}
diff --git a/modules/mono/glue/cs_files/Transform.cs b/modules/mono/glue/cs_files/Transform.cs
new file mode 100644
index 0000000000..74271e758b
--- /dev/null
+++ b/modules/mono/glue/cs_files/Transform.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Transform : IEquatable<Transform>
+ {
+ public Basis basis;
+ public Vector3 origin;
+
+ public Transform affine_inverse()
+ {
+ Basis basisInv = basis.inverse();
+ return new Transform(basisInv, basisInv.xform(-origin));
+ }
+
+ public Transform inverse()
+ {
+ Basis basisTr = basis.transposed();
+ return new Transform(basisTr, basisTr.xform(-origin));
+ }
+
+ public Transform looking_at(Vector3 target, Vector3 up)
+ {
+ Transform t = this;
+ t.set_look_at(origin, target, up);
+ return t;
+ }
+
+ public Transform orthonormalized()
+ {
+ return new Transform(basis.orthonormalized(), origin);
+ }
+
+ public Transform rotated(Vector3 axis, float phi)
+ {
+ return new Transform(new Basis(axis, phi), new Vector3()) * this;
+ }
+
+ public Transform scaled(Vector3 scale)
+ {
+ return new Transform(basis.scaled(scale), origin * scale);
+ }
+
+ public void set_look_at(Vector3 eye, Vector3 target, Vector3 up)
+ {
+ // Make rotation matrix
+ // Z vector
+ Vector3 zAxis = eye - target;
+
+ zAxis.normalize();
+
+ Vector3 yAxis = up;
+
+ Vector3 xAxis = yAxis.cross(zAxis);
+
+ // Recompute Y = Z cross X
+ yAxis = zAxis.cross(xAxis);
+
+ xAxis.normalize();
+ yAxis.normalize();
+
+ basis = Basis.create_from_axes(xAxis, yAxis, zAxis);
+
+ origin = eye;
+ }
+
+ public Transform translated(Vector3 ofs)
+ {
+ return new Transform(basis, new Vector3
+ (
+ origin[0] += basis[0].dot(ofs),
+ origin[1] += basis[1].dot(ofs),
+ origin[2] += basis[2].dot(ofs)
+ ));
+ }
+
+ public Vector3 xform(Vector3 v)
+ {
+ return new Vector3
+ (
+ basis[0].dot(v) + origin.x,
+ basis[1].dot(v) + origin.y,
+ basis[2].dot(v) + origin.z
+ );
+ }
+
+ public Vector3 xform_inv(Vector3 v)
+ {
+ Vector3 vInv = v - origin;
+
+ return new Vector3
+ (
+ (basis[0, 0] * vInv.x) + (basis[1, 0] * vInv.y) + (basis[2, 0] * vInv.z),
+ (basis[0, 1] * vInv.x) + (basis[1, 1] * vInv.y) + (basis[2, 1] * vInv.z),
+ (basis[0, 2] * vInv.x) + (basis[1, 2] * vInv.y) + (basis[2, 2] * vInv.z)
+ );
+ }
+
+ public Transform(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin)
+ {
+ this.basis = Basis.create_from_axes(xAxis, yAxis, zAxis);
+ this.origin = origin;
+ }
+
+ public Transform(Quat quat, Vector3 origin)
+ {
+ this.basis = new Basis(quat);
+ this.origin = origin;
+ }
+
+ public Transform(Basis basis, Vector3 origin)
+ {
+ this.basis = basis;
+ this.origin = origin;
+ }
+
+ public static Transform operator *(Transform left, Transform right)
+ {
+ left.origin = left.xform(right.origin);
+ left.basis *= right.basis;
+ return left;
+ }
+
+ public static bool operator ==(Transform left, Transform right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Transform left, Transform right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Transform)
+ {
+ return Equals((Transform)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Transform other)
+ {
+ return basis.Equals(other.basis) && origin.Equals(other.origin);
+ }
+
+ public override int GetHashCode()
+ {
+ return basis.GetHashCode() ^ origin.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ this.basis.ToString(),
+ this.origin.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ this.basis.ToString(format),
+ this.origin.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Transform2D.cs b/modules/mono/glue/cs_files/Transform2D.cs
new file mode 100644
index 0000000000..526dc767c6
--- /dev/null
+++ b/modules/mono/glue/cs_files/Transform2D.cs
@@ -0,0 +1,356 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Transform2D : IEquatable<Transform2D>
+ {
+ private static readonly Transform2D identity = new Transform2D
+ (
+ new Vector2(1f, 0f),
+ new Vector2(0f, 1f),
+ new Vector2(0f, 0f)
+ );
+
+ public Vector2 x;
+ public Vector2 y;
+ public Vector2 o;
+
+ public static Transform2D Identity
+ {
+ get { return identity; }
+ }
+
+ public Vector2 Origin
+ {
+ get { return o; }
+ }
+
+ public float Rotation
+ {
+ get { return Mathf.atan2(y.x, o.y); }
+ }
+
+ public Vector2 Scale
+ {
+ get { return new Vector2(x.length(), y.length()); }
+ }
+
+ public Vector2 this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return o;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ o = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+
+ public float this[int index, int axis]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x[axis];
+ case 1:
+ return y[axis];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x[axis] = value;
+ return;
+ case 1:
+ y[axis] = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public Transform2D affine_inverse()
+ {
+ Transform2D inv = this;
+
+ float det = this[0, 0] * this[1, 1] - this[1, 0] * this[0, 1];
+
+ if (det == 0)
+ {
+ return new Transform2D
+ (
+ float.NaN, float.NaN,
+ float.NaN, float.NaN,
+ float.NaN, float.NaN
+ );
+ }
+
+ float idet = 1.0f / det;
+
+ float temp = this[0, 0];
+ this[0, 0] = this[1, 1];
+ this[1, 1] = temp;
+
+ this[0] *= new Vector2(idet, -idet);
+ this[1] *= new Vector2(-idet, idet);
+
+ this[2] = basis_xform(-this[2]);
+
+ return inv;
+ }
+
+ public Vector2 basis_xform(Vector2 v)
+ {
+ return new Vector2(tdotx(v), tdoty(v));
+ }
+
+ public Vector2 basis_xform_inv(Vector2 v)
+ {
+ return new Vector2(x.dot(v), y.dot(v));
+ }
+
+ public Transform2D interpolate_with(Transform2D m, float c)
+ {
+ float r1 = Rotation;
+ float r2 = m.Rotation;
+
+ Vector2 s1 = Scale;
+ Vector2 s2 = m.Scale;
+
+ // Slerp rotation
+ Vector2 v1 = new Vector2(Mathf.cos(r1), Mathf.sin(r1));
+ Vector2 v2 = new Vector2(Mathf.cos(r2), Mathf.sin(r2));
+
+ float dot = v1.dot(v2);
+
+ // Clamp dot to [-1, 1]
+ dot = (dot < -1.0f) ? -1.0f : ((dot > 1.0f) ? 1.0f : dot);
+
+ Vector2 v = new Vector2();
+
+ if (dot > 0.9995f)
+ {
+ // Linearly interpolate to avoid numerical precision issues
+ v = v1.linear_interpolate(v2, c).normalized();
+ }
+ else
+ {
+ float angle = c * Mathf.acos(dot);
+ Vector2 v3 = (v2 - v1 * dot).normalized();
+ v = v1 * Mathf.cos(angle) + v3 * Mathf.sin(angle);
+ }
+
+ // Extract parameters
+ Vector2 p1 = Origin;
+ Vector2 p2 = m.Origin;
+
+ // Construct matrix
+ Transform2D res = new Transform2D(Mathf.atan2(v.y, v.x), p1.linear_interpolate(p2, c));
+ Vector2 scale = s1.linear_interpolate(s2, c);
+ res.x *= scale;
+ res.y *= scale;
+
+ return res;
+ }
+
+ public Transform2D inverse()
+ {
+ Transform2D inv = this;
+
+ // Swap
+ float temp = inv.x.y;
+ inv.x.y = inv.y.x;
+ inv.y.x = temp;
+
+ inv.o = inv.basis_xform(-inv.o);
+
+ return inv;
+ }
+
+ public Transform2D orthonormalized()
+ {
+ Transform2D on = this;
+
+ Vector2 onX = on.x;
+ Vector2 onY = on.y;
+
+ onX.normalize();
+ onY = onY - onX * (onX.dot(onY));
+ onY.normalize();
+
+ on.x = onX;
+ on.y = onY;
+
+ return on;
+ }
+
+ public Transform2D rotated(float phi)
+ {
+ return this * new Transform2D(phi, new Vector2());
+ }
+
+ public Transform2D scaled(Vector2 scale)
+ {
+ Transform2D copy = this;
+ copy.x *= scale;
+ copy.y *= scale;
+ copy.o *= scale;
+ return copy;
+ }
+
+ private float tdotx(Vector2 with)
+ {
+ return this[0, 0] * with[0] + this[1, 0] * with[1];
+ }
+
+ private float tdoty(Vector2 with)
+ {
+ return this[0, 1] * with[0] + this[1, 1] * with[1];
+ }
+
+ public Transform2D translated(Vector2 offset)
+ {
+ Transform2D copy = this;
+ copy.o += copy.basis_xform(offset);
+ return copy;
+ }
+
+ public Vector2 xform(Vector2 v)
+ {
+ return new Vector2(tdotx(v), tdoty(v)) + o;
+ }
+
+ public Vector2 xform_inv(Vector2 v)
+ {
+ Vector2 vInv = v - o;
+ return new Vector2(x.dot(vInv), y.dot(vInv));
+ }
+
+ public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin)
+ {
+ this.x = xAxis;
+ this.y = yAxis;
+ this.o = origin;
+ }
+ public Transform2D(float xx, float xy, float yx, float yy, float ox, float oy)
+ {
+ this.x = new Vector2(xx, xy);
+ this.y = new Vector2(yx, yy);
+ this.o = new Vector2(ox, oy);
+ }
+
+ public Transform2D(float rot, Vector2 pos)
+ {
+ float cr = Mathf.cos(rot);
+ float sr = Mathf.sin(rot);
+ x.x = cr;
+ y.y = cr;
+ x.y = -sr;
+ y.x = sr;
+ o = pos;
+ }
+
+ public static Transform2D operator *(Transform2D left, Transform2D right)
+ {
+ left.o = left.xform(right.o);
+
+ float x0, x1, y0, y1;
+
+ x0 = left.tdotx(right.x);
+ x1 = left.tdoty(right.x);
+ y0 = left.tdotx(right.y);
+ y1 = left.tdoty(right.y);
+
+ left.x.x = x0;
+ left.x.y = x1;
+ left.y.x = y0;
+ left.y.y = y1;
+
+ return left;
+ }
+
+ public static bool operator ==(Transform2D left, Transform2D right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Transform2D left, Transform2D right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Transform2D)
+ {
+ return Equals((Transform2D)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Transform2D other)
+ {
+ return x.Equals(other.x) && y.Equals(other.y) && o.Equals(other.o);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ y.GetHashCode() ^ o.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.o.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.o.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Vector2.cs b/modules/mono/glue/cs_files/Vector2.cs
new file mode 100644
index 0000000000..28fedc365b
--- /dev/null
+++ b/modules/mono/glue/cs_files/Vector2.cs
@@ -0,0 +1,362 @@
+using System;
+using System.Runtime.InteropServices;
+
+// file: core/math/math_2d.h
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/math/math_2d.cpp
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector2 : IEquatable<Vector2>
+ {
+ public float x;
+ public float y;
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ internal void normalize()
+ {
+ float length = x * x + y * y;
+
+ if (length != 0f)
+ {
+ length = Mathf.sqrt(length);
+ x /= length;
+ y /= length;
+ }
+ }
+
+ private float cross(Vector2 b)
+ {
+ return x * b.y - y * b.x;
+ }
+
+ public Vector2 abs()
+ {
+ return new Vector2(Mathf.abs(x), Mathf.abs(y));
+ }
+
+ public float angle()
+ {
+ return Mathf.atan2(y, x);
+ }
+
+ public float angle_to(Vector2 to)
+ {
+ return Mathf.atan2(cross(to), dot(to));
+ }
+
+ public float angle_to_point(Vector2 to)
+ {
+ return Mathf.atan2(x - to.x, y - to.y);
+ }
+
+ public float aspect()
+ {
+ return x / y;
+ }
+
+ public Vector2 bounce(Vector2 n)
+ {
+ return -reflect(n);
+ }
+
+ public Vector2 clamped(float length)
+ {
+ Vector2 v = this;
+ float l = this.length();
+
+ if (l > 0 && length < l)
+ {
+ v /= l;
+ v *= length;
+ }
+
+ return v;
+ }
+
+ public Vector2 cubic_interpolate(Vector2 b, Vector2 preA, Vector2 postB, float t)
+ {
+ Vector2 p0 = preA;
+ Vector2 p1 = this;
+ Vector2 p2 = b;
+ Vector2 p3 = postB;
+
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ return 0.5f * ((p1 * 2.0f) +
+ (-p0 + p2) * t +
+ (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 +
+ (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
+ }
+
+ public float distance_squared_to(Vector2 to)
+ {
+ return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y);
+ }
+
+ public float distance_to(Vector2 to)
+ {
+ return Mathf.sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y));
+ }
+
+ public float dot(Vector2 with)
+ {
+ return x * with.x + y * with.y;
+ }
+
+ public Vector2 floor()
+ {
+ return new Vector2(Mathf.floor(x), Mathf.floor(y));
+ }
+
+ public bool is_normalized()
+ {
+ return Mathf.abs(length_squared() - 1.0f) < Mathf.Epsilon;
+ }
+
+ public float length()
+ {
+ return Mathf.sqrt(x * x + y * y);
+ }
+
+ public float length_squared()
+ {
+ return x * x + y * y;
+ }
+
+ public Vector2 linear_interpolate(Vector2 b, float t)
+ {
+ Vector2 res = this;
+
+ res.x += (t * (b.x - x));
+ res.y += (t * (b.y - y));
+
+ return res;
+ }
+
+ public Vector2 normalized()
+ {
+ Vector2 result = this;
+ result.normalize();
+ return result;
+ }
+
+ public Vector2 reflect(Vector2 n)
+ {
+ return 2.0f * n * dot(n) - this;
+ }
+
+ public Vector2 rotated(float phi)
+ {
+ float rads = angle() + phi;
+ return new Vector2(Mathf.cos(rads), Mathf.sin(rads)) * length();
+ }
+
+ public Vector2 slide(Vector2 n)
+ {
+ return this - n * dot(n);
+ }
+
+ public Vector2 snapped(Vector2 by)
+ {
+ return new Vector2(Mathf.stepify(x, by.x), Mathf.stepify(y, by.y));
+ }
+
+ public Vector2 tangent()
+ {
+ return new Vector2(y, -x);
+ }
+
+ public Vector2(float x, float y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ public static Vector2 operator +(Vector2 left, Vector2 right)
+ {
+ left.x += right.x;
+ left.y += right.y;
+ return left;
+ }
+
+ public static Vector2 operator -(Vector2 left, Vector2 right)
+ {
+ left.x -= right.x;
+ left.y -= right.y;
+ return left;
+ }
+
+ public static Vector2 operator -(Vector2 vec)
+ {
+ vec.x = -vec.x;
+ vec.y = -vec.y;
+ return vec;
+ }
+
+ public static Vector2 operator *(Vector2 vec, float scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ return vec;
+ }
+
+ public static Vector2 operator *(float scale, Vector2 vec)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ return vec;
+ }
+
+ public static Vector2 operator *(Vector2 left, Vector2 right)
+ {
+ left.x *= right.x;
+ left.y *= right.y;
+ return left;
+ }
+
+ public static Vector2 operator /(Vector2 vec, float scale)
+ {
+ vec.x /= scale;
+ vec.y /= scale;
+ return vec;
+ }
+
+ public static Vector2 operator /(Vector2 left, Vector2 right)
+ {
+ left.x /= right.x;
+ left.y /= right.y;
+ return left;
+ }
+
+ public static bool operator ==(Vector2 left, Vector2 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Vector2 left, Vector2 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y < right.y;
+ }
+ else
+ {
+ return left.x < right.x;
+ }
+ }
+
+ public static bool operator >(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y > right.y;
+ }
+ else
+ {
+ return left.x > right.x;
+ }
+ }
+
+ public static bool operator <=(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y <= right.y;
+ }
+ else
+ {
+ return left.x <= right.x;
+ }
+ }
+
+ public static bool operator >=(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y >= right.y;
+ }
+ else
+ {
+ return left.x >= right.x;
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector2)
+ {
+ return Equals((Vector2)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Vector2 other)
+ {
+ return x == other.x && y == other.y;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/cs_files/Vector3.cs b/modules/mono/glue/cs_files/Vector3.cs
new file mode 100644
index 0000000000..c023cd83cf
--- /dev/null
+++ b/modules/mono/glue/cs_files/Vector3.cs
@@ -0,0 +1,420 @@
+using System;
+using System.Runtime.InteropServices;
+
+// file: core/math/vector3.h
+// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
+// file: core/math/vector3.cpp
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+
+namespace Godot
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector3 : IEquatable<Vector3>
+ {
+ public enum Axis
+ {
+ X = 0,
+ Y,
+ Z
+ }
+
+ public float x;
+ public float y;
+ public float z;
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ z = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ internal void normalize()
+ {
+ float length = this.length();
+
+ if (length == 0f)
+ {
+ x = y = z = 0f;
+ }
+ else
+ {
+ x /= length;
+ y /= length;
+ z /= length;
+ }
+ }
+
+ public Vector3 abs()
+ {
+ return new Vector3(Mathf.abs(x), Mathf.abs(y), Mathf.abs(z));
+ }
+
+ public float angle_to(Vector3 to)
+ {
+ return Mathf.atan2(cross(to).length(), dot(to));
+ }
+
+ public Vector3 bounce(Vector3 n)
+ {
+ return -reflect(n);
+ }
+
+ public Vector3 ceil()
+ {
+ return new Vector3(Mathf.ceil(x), Mathf.ceil(y), Mathf.ceil(z));
+ }
+
+ public Vector3 cross(Vector3 b)
+ {
+ return new Vector3
+ (
+ (y * b.z) - (z * b.y),
+ (z * b.x) - (x * b.z),
+ (x * b.y) - (y * b.x)
+ );
+ }
+
+ public Vector3 cubic_interpolate(Vector3 b, Vector3 preA, Vector3 postB, float t)
+ {
+ Vector3 p0 = preA;
+ Vector3 p1 = this;
+ Vector3 p2 = b;
+ Vector3 p3 = postB;
+
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ return 0.5f * (
+ (p1 * 2.0f) + (-p0 + p2) * t +
+ (2.0f * p0 - 5.0f * p1 + 4f * p2 - p3) * t2 +
+ (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3
+ );
+ }
+
+ public float distance_squared_to(Vector3 b)
+ {
+ return (b - this).length_squared();
+ }
+
+ public float distance_to(Vector3 b)
+ {
+ return (b - this).length();
+ }
+
+ public float dot(Vector3 b)
+ {
+ return x * b.x + y * b.y + z * b.z;
+ }
+
+ public Vector3 floor()
+ {
+ return new Vector3(Mathf.floor(x), Mathf.floor(y), Mathf.floor(z));
+ }
+
+ public Vector3 inverse()
+ {
+ return new Vector3(1.0f / x, 1.0f / y, 1.0f / z);
+ }
+
+ public bool is_normalized()
+ {
+ return Mathf.abs(length_squared() - 1.0f) < Mathf.Epsilon;
+ }
+
+ public float length()
+ {
+ float x2 = x * x;
+ float y2 = y * y;
+ float z2 = z * z;
+
+ return Mathf.sqrt(x2 + y2 + z2);
+ }
+
+ public float length_squared()
+ {
+ float x2 = x * x;
+ float y2 = y * y;
+ float z2 = z * z;
+
+ return x2 + y2 + z2;
+ }
+
+ public Vector3 linear_interpolate(Vector3 b, float t)
+ {
+ return new Vector3
+ (
+ x + (t * (b.x - x)),
+ y + (t * (b.y - y)),
+ z + (t * (b.z - z))
+ );
+ }
+
+ public Axis max_axis()
+ {
+ return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X);
+ }
+
+ public Axis min_axis()
+ {
+ return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
+ }
+
+ public Vector3 normalized()
+ {
+ Vector3 v = this;
+ v.normalize();
+ return v;
+ }
+
+ public Basis outer(Vector3 b)
+ {
+ return new Basis(
+ new Vector3(x * b.x, x * b.y, x * b.z),
+ new Vector3(y * b.x, y * b.y, y * b.z),
+ new Vector3(z * b.x, z * b.y, z * b.z)
+ );
+ }
+
+ public Vector3 reflect(Vector3 n)
+ {
+#if DEBUG
+ if (!n.is_normalized())
+ throw new ArgumentException(String.Format("{0} is not normalized", n), nameof(n));
+#endif
+ return 2.0f * n * dot(n) - this;
+ }
+
+ public Vector3 rotated(Vector3 axis, float phi)
+ {
+ return new Basis(axis, phi).xform(this);
+ }
+
+ public Vector3 slide(Vector3 n)
+ {
+ return this - n * dot(n);
+ }
+
+ public Vector3 snapped(Vector3 by)
+ {
+ return new Vector3
+ (
+ Mathf.stepify(x, by.x),
+ Mathf.stepify(y, by.y),
+ Mathf.stepify(z, by.z)
+ );
+ }
+
+ public Basis to_diagonal_matrix()
+ {
+ return new Basis(
+ x, 0f, 0f,
+ 0f, y, 0f,
+ 0f, 0f, z
+ );
+ }
+
+ public Vector3(float x, float y, float z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public static Vector3 operator +(Vector3 left, Vector3 right)
+ {
+ left.x += right.x;
+ left.y += right.y;
+ left.z += right.z;
+ return left;
+ }
+
+ public static Vector3 operator -(Vector3 left, Vector3 right)
+ {
+ left.x -= right.x;
+ left.y -= right.y;
+ left.z -= right.z;
+ return left;
+ }
+
+ public static Vector3 operator -(Vector3 vec)
+ {
+ vec.x = -vec.x;
+ vec.y = -vec.y;
+ vec.z = -vec.z;
+ return vec;
+ }
+
+ public static Vector3 operator *(Vector3 vec, float scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ return vec;
+ }
+
+ public static Vector3 operator *(float scale, Vector3 vec)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ return vec;
+ }
+
+ public static Vector3 operator *(Vector3 left, Vector3 right)
+ {
+ left.x *= right.x;
+ left.y *= right.y;
+ left.z *= right.z;
+ return left;
+ }
+
+ public static Vector3 operator /(Vector3 vec, float scale)
+ {
+ vec.x /= scale;
+ vec.y /= scale;
+ vec.z /= scale;
+ return vec;
+ }
+
+ public static Vector3 operator /(Vector3 left, Vector3 right)
+ {
+ left.x /= right.x;
+ left.y /= right.y;
+ left.z /= right.z;
+ return left;
+ }
+
+ public static bool operator ==(Vector3 left, Vector3 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Vector3 left, Vector3 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z < right.z;
+ else
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z > right.z;
+ else
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public static bool operator <=(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z <= right.z;
+ else
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >=(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z >= right.z;
+ else
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector3)
+ {
+ return Equals((Vector3)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Vector3 other)
+ {
+ return x == other.x && y == other.y && z == other.z;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(),
+ this.y.ToString(),
+ this.z.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ this.x.ToString(format),
+ this.y.ToString(format),
+ this.z.ToString(format)
+ });
+ }
+ }
+}