diff options
Diffstat (limited to 'modules/mono/glue')
25 files changed, 5711 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) + }); + } + } +} diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h new file mode 100644 index 0000000000..0751a0160f --- /dev/null +++ b/modules/mono/glue/glue_header.h @@ -0,0 +1,302 @@ +/*************************************************************************/ +/* glue_header.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "../csharp_script.h" +#include "../mono_gd/gd_mono_class.h" +#include "../mono_gd/gd_mono_internals.h" +#include "../mono_gd/gd_mono_marshal.h" +#include "../signal_awaiter_utils.h" + +#include "bind/core_bind.h" +#include "class_db.h" +#include "io/marshalls.h" +#include "object.h" +#include "os/os.h" +#include "project_settings.h" +#include "reference.h" +#include "variant_parser.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_node.h" +#endif + +#define GODOTSHARP_INSTANCE_OBJECT(m_instance, m_type) \ + static ClassDB::ClassInfo *ci = NULL; \ + if (!ci) { \ + ci = ClassDB::classes.getptr(m_type); \ + } \ + Object *m_instance = ci->creation_func(); + +void godot_icall_Object_Dtor(Object *ptr) { + ERR_FAIL_NULL(ptr); + _GodotSharp::get_singleton()->queue_dispose(ptr); +} + +// -- ClassDB -- + +MethodBind *godot_icall_ClassDB_get_method(MonoString *p_type, MonoString *p_method) { + StringName type(GDMonoMarshal::mono_string_to_godot(p_type)); + StringName method(GDMonoMarshal::mono_string_to_godot(p_method)); + return ClassDB::get_method(type, method); +} + +// -- SignalAwaiter -- + +Error godot_icall_Object_connect_signal_awaiter(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter) { + String signal = GDMonoMarshal::mono_string_to_godot(p_signal); + return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter); +} + +// -- NodePath -- + +NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) { + return memnew(NodePath(GDMonoMarshal::mono_string_to_godot(p_path))); +} + +void godot_icall_NodePath_Dtor(NodePath *p_ptr) { + ERR_FAIL_NULL(p_ptr); + _GodotSharp::get_singleton()->queue_dispose(p_ptr); +} + +MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) { + return GDMonoMarshal::mono_string_from_godot(p_np->operator String()); +} + +MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) { + Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer(); + // TODO Check possible Array/Vector<uint8_t> problem? + return GDMonoMarshal::Array_to_mono_array(Variant(ret)); +} + +// -- RID -- + +RID *godot_icall_RID_Ctor(Object *p_from) { + Resource *res_from = Object::cast_to<Resource>(p_from); + + if (res_from) + return memnew(RID(res_from->get_rid())); + + return memnew(RID); +} + +void godot_icall_RID_Dtor(RID *p_ptr) { + ERR_FAIL_NULL(p_ptr); + _GodotSharp::get_singleton()->queue_dispose(p_ptr); +} + +// -- String -- + +MonoString *godot_icall_String_md5_text(MonoString *p_str) { + String ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_text(); + return GDMonoMarshal::mono_string_from_godot(ret); +} + +int godot_icall_String_rfind(MonoString *p_str, MonoString *p_what, int p_from) { + String what = GDMonoMarshal::mono_string_to_godot(p_what); + return GDMonoMarshal::mono_string_to_godot(p_str).rfind(what, p_from); +} + +int godot_icall_String_rfindn(MonoString *p_str, MonoString *p_what, int p_from) { + String what = GDMonoMarshal::mono_string_to_godot(p_what); + return GDMonoMarshal::mono_string_to_godot(p_str).rfindn(what, p_from); +} + +MonoArray *godot_icall_String_sha256_buffer(MonoString *p_str) { + Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_buffer(); + return GDMonoMarshal::Array_to_mono_array(Variant(ret)); +} + +MonoString *godot_icall_String_sha256_text(MonoString *p_str) { + String ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_text(); + return GDMonoMarshal::mono_string_from_godot(ret); +} + +// -- Global Scope -- + +MonoObject *godot_icall_Godot_bytes2var(MonoArray *p_bytes) { + Variant ret; + PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes); + PoolByteArray::Read r = varr.read(); + Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); + if (err != OK) { + ret = RTR("Not enough bytes for decoding bytes, or invalid format."); + } + return GDMonoMarshal::variant_to_mono_object(ret); +} + +MonoObject *godot_icall_Godot_convert(MonoObject *p_what, int p_type) { + Variant what = GDMonoMarshal::mono_object_to_variant(p_what); + const Variant *args[1] = { &what }; + Variant::CallError ce; + Variant ret = Variant::construct(Variant::Type(p_type), args, 1, ce); + ERR_FAIL_COND_V(ce.error != Variant::CallError::CALL_OK, NULL); + return GDMonoMarshal::variant_to_mono_object(ret); +} + +int godot_icall_Godot_hash(MonoObject *p_var) { + return GDMonoMarshal::mono_object_to_variant(p_var).hash(); +} + +MonoObject *godot_icall_Godot_instance_from_id(int p_instance_id) { + return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(p_instance_id)); +} + +void godot_icall_Godot_print(MonoArray *p_what) { + Array what = GDMonoMarshal::mono_array_to_Array(p_what); + String str; + for (int i = 0; i < what.size(); i++) + str += what[i].operator String(); + print_line(str); +} + +void godot_icall_Godot_printerr(MonoArray *p_what) { + Array what = GDMonoMarshal::mono_array_to_Array(p_what); + String str; + for (int i = 0; i < what.size(); i++) + str += what[i].operator String(); + OS::get_singleton()->printerr("%s\n", str.utf8().get_data()); +} + +void godot_icall_Godot_printraw(MonoArray *p_what) { + Array what = GDMonoMarshal::mono_array_to_Array(p_what); + String str; + for (int i = 0; i < what.size(); i++) + str += what[i].operator String(); + OS::get_singleton()->print("%s", str.utf8().get_data()); +} + +void godot_icall_Godot_prints(MonoArray *p_what) { + Array what = GDMonoMarshal::mono_array_to_Array(p_what); + String str; + for (int i = 0; i < what.size(); i++) { + if (i) + str += " "; + str += what[i].operator String(); + } + print_line(str); +} + +void godot_icall_Godot_printt(MonoArray *p_what) { + Array what = GDMonoMarshal::mono_array_to_Array(p_what); + String str; + for (int i = 0; i < what.size(); i++) { + if (i) + str += "\t"; + str += what[i].operator String(); + } + print_line(str); +} + +void godot_icall_Godot_seed(int p_seed) { + Math::seed(p_seed); +} + +MonoString *godot_icall_Godot_str(MonoArray *p_what) { + String str; + Array what = GDMonoMarshal::mono_array_to_Array(p_what); + + for (int i = 0; i < what.size(); i++) { + String os = what[i].operator String(); + + if (i == 0) + str = os; + else + str += os; + } + + return GDMonoMarshal::mono_string_from_godot(str); +} + +MonoObject *godot_icall_Godot_str2var(MonoString *p_str) { + Variant ret; + + VariantParser::StreamString ss; + ss.s = GDMonoMarshal::mono_string_to_godot(p_str); + + String errs; + int line; + Error err = VariantParser::parse(&ss, ret, errs, line); + if (err != OK) { + String err_str = "Parse error at line " + itos(line) + ": " + errs; + ERR_PRINTS(err_str); + ret = err_str; + } + + return GDMonoMarshal::variant_to_mono_object(ret); +} + +bool godot_icall_Godot_type_exists(MonoString *p_type) { + return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type)); +} + +MonoArray *godot_icall_Godot_var2bytes(MonoObject *p_var) { + Variant var = GDMonoMarshal::mono_object_to_variant(p_var); + + PoolByteArray barr; + int len; + Error err = encode_variant(var, NULL, len); + ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."); + ERR_FAIL_COND_V(err != OK, NULL); + + barr.resize(len); + { + PoolByteArray::Write w = barr.write(); + encode_variant(var, w.ptr(), len); + } + + return GDMonoMarshal::PoolByteArray_to_mono_array(barr); +} + +MonoString *godot_icall_Godot_var2str(MonoObject *p_var) { + String vars; + VariantWriter::write_to_string(GDMonoMarshal::mono_object_to_variant(p_var), vars); + return GDMonoMarshal::mono_string_from_godot(vars); +} + +MonoObject *godot_icall_Godot_weakref(Object *p_obj) { + if (!p_obj) + return NULL; + + Ref<WeakRef> wref; + Reference *ref = Object::cast_to<Reference>(p_obj); + + if (ref) { + REF r = ref; + if (!r.is_valid()) + return NULL; + + wref.instance(); + wref->set_ref(r); + } else { + wref.instance(); + wref->set_obj(p_obj); + } + + return GDMonoUtils::create_managed_for_godot_object(CACHED_CLASS(WeakRef), Reference::get_class_static(), Object::cast_to<Object>(wref.ptr())); +} |