summaryrefslogtreecommitdiff
path: root/modules/mono/glue/GodotSharp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/mono/glue/GodotSharp')
-rw-r--r--modules/mono/glue/GodotSharp/.gitignore3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp.sln24
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs489
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs380
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs28
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs9
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs700
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs755
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs305
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs89
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs469
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs13
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs213
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs45
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs266
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs24
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs91
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs37
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs212
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs361
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs60
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs153
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs130
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs238
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs414
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs84
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs262
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs60
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs1046
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs216
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs390
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs489
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs553
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj85
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs27
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj45
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs25
45 files changed, 8900 insertions, 0 deletions
diff --git a/modules/mono/glue/GodotSharp/.gitignore b/modules/mono/glue/GodotSharp/.gitignore
new file mode 100644
index 0000000000..aa9f614a9d
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/.gitignore
@@ -0,0 +1,3 @@
+# Generated Godot API sources directories
+GodotSharp/Generated
+GodotSharpEditor/Generated
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln b/modules/mono/glue/GodotSharp/GodotSharp.sln
new file mode 100644
index 0000000000..a496e36da3
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharp", "GodotSharp\GodotSharp.csproj", "{AEBF0036-DA76-4341-B651-A3F2856AB2FA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpEditor", "GodotSharpEditor\GodotSharpEditor.csproj", "{8FBEC238-D944-4074-8548-B3B524305905}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8FBEC238-D944-4074-8548-B3B524305905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8FBEC238-D944-4074-8548-B3B524305905}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8FBEC238-D944-4074-8548-B3B524305905}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8FBEC238-D944-4074-8548-B3B524305905}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
new file mode 100644
index 0000000000..6a4f785551
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -0,0 +1,489 @@
+// file: core/math/aabb.h
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/math/aabb.cpp
+// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct AABB : IEquatable<AABB>
+ {
+ private Vector3 _position;
+ private Vector3 _size;
+
+ public Vector3 Position
+ {
+ get { return _position; }
+ set { _position = value; }
+ }
+
+ public Vector3 Size
+ {
+ get { return _size; }
+ set { _size = value; }
+ }
+
+ public Vector3 End
+ {
+ get { return _position + _size; }
+ set { _size = value - _position; }
+ }
+
+ public bool Encloses(AABB 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 AABB Expand(Vector3 point)
+ {
+ Vector3 begin = _position;
+ Vector3 end = _position + _size;
+
+ if (point.x < begin.x)
+ begin.x = point.x;
+ if (point.y < begin.y)
+ begin.y = point.y;
+ if (point.z < begin.z)
+ begin.z = point.z;
+
+ if (point.x > end.x)
+ end.x = point.x;
+ if (point.y > end.y)
+ end.y = point.y;
+ if (point.z > end.z)
+ end.z = point.z;
+
+ return new AABB(begin, end - begin);
+ }
+
+ public real_t GetArea()
+ {
+ return _size.x * _size.y * _size.z;
+ }
+
+ public Vector3 GetEndpoint(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 GetLongestAxis()
+ {
+ var axis = new Vector3(1f, 0f, 0f);
+ real_t 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);
+ }
+
+ return axis;
+ }
+
+ public Vector3.Axis GetLongestAxisIndex()
+ {
+ var axis = Vector3.Axis.X;
+ real_t 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;
+ }
+
+ return axis;
+ }
+
+ public real_t GetLongestAxisSize()
+ {
+ real_t 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 GetShortestAxis()
+ {
+ var axis = new Vector3(1f, 0f, 0f);
+ real_t 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);
+ }
+
+ return axis;
+ }
+
+ public Vector3.Axis GetShortestAxisIndex()
+ {
+ var axis = Vector3.Axis.X;
+ real_t 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;
+ }
+
+ return axis;
+ }
+
+ public real_t GetShortestAxisSize()
+ {
+ real_t 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 GetSupport(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 AABB Grow(real_t by)
+ {
+ var 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 HasNoArea()
+ {
+ return _size.x <= 0f || _size.y <= 0f || _size.z <= 0f;
+ }
+
+ public bool HasNoSurface()
+ {
+ return _size.x <= 0f && _size.y <= 0f && _size.z <= 0f;
+ }
+
+ public bool HasPoint(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 AABB Intersection(AABB 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 AABB();
+ }
+
+ 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 AABB();
+ }
+
+ 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 AABB();
+ }
+
+ 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 AABB(min, max - min);
+ }
+
+ public bool Intersects(AABB 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 IntersectsPlane(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.DistanceTo(points[i]) > 0)
+ over = true;
+ else
+ under = true;
+ }
+
+ return under && over;
+ }
+
+ public bool IntersectsSegment(Vector3 from, Vector3 to)
+ {
+ real_t min = 0f;
+ real_t max = 1f;
+
+ for (int i = 0; i < 3; i++)
+ {
+ real_t segFrom = from[i];
+ real_t segTo = to[i];
+ real_t boxBegin = _position[i];
+ real_t boxEnd = boxBegin + _size[i];
+ real_t cmin, cmax;
+
+ if (segFrom < segTo)
+ {
+ if (segFrom > boxEnd || segTo < boxBegin)
+ return false;
+
+ real_t length = segTo - segFrom;
+ cmin = segFrom < boxBegin ? (boxBegin - segFrom) / length : 0f;
+ cmax = segTo > boxEnd ? (boxEnd - segFrom) / length : 1f;
+ }
+ else
+ {
+ if (segTo > boxEnd || segFrom < boxBegin)
+ return false;
+
+ real_t length = segTo - segFrom;
+ cmin = segFrom > boxEnd ? (boxEnd - segFrom) / length : 0f;
+ cmax = segTo < boxBegin ? (boxBegin - segFrom) / length : 1f;
+ }
+
+ if (cmin > min)
+ {
+ min = cmin;
+ }
+
+ if (cmax < max)
+ max = cmax;
+ if (max < min)
+ return false;
+ }
+
+ return true;
+ }
+
+ public AABB Merge(AABB with)
+ {
+ Vector3 beg1 = _position;
+ Vector3 beg2 = with._position;
+ var end1 = new Vector3(_size.x, _size.y, _size.z) + beg1;
+ var end2 = new Vector3(with._size.x, with._size.y, with._size.z) + beg2;
+
+ var min = new Vector3(
+ beg1.x < beg2.x ? beg1.x : beg2.x,
+ beg1.y < beg2.y ? beg1.y : beg2.y,
+ beg1.z < beg2.z ? beg1.z : beg2.z
+ );
+
+ var max = new Vector3(
+ end1.x > end2.x ? end1.x : end2.x,
+ end1.y > end2.y ? end1.y : end2.y,
+ end1.z > end2.z ? end1.z : end2.z
+ );
+
+ return new AABB(min, max - min);
+ }
+
+ // Constructors
+ public AABB(Vector3 position, Vector3 size)
+ {
+ _position = position;
+ _size = size;
+ }
+ public AABB(Vector3 position, real_t width, real_t height, real_t depth)
+ {
+ _position = position;
+ _size = new Vector3(width, height, depth);
+ }
+ public AABB(real_t x, real_t y, real_t z, Vector3 size)
+ {
+ _position = new Vector3(x, y, z);
+ _size = size;
+ }
+ public AABB(real_t x, real_t y, real_t z, real_t width, real_t height, real_t depth)
+ {
+ _position = new Vector3(x, y, z);
+ _size = new Vector3(width, height, depth);
+ }
+
+ public static bool operator ==(AABB left, AABB right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(AABB left, AABB right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is AABB)
+ {
+ return Equals((AABB)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(AABB other)
+ {
+ return _position == other._position && _size == other._size;
+ }
+
+ public bool IsEqualApprox(AABB other)
+ {
+ return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other._size);
+ }
+
+ public override int GetHashCode()
+ {
+ return _position.GetHashCode() ^ _size.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ _position.ToString(),
+ _size.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ _position.ToString(format),
+ _size.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
new file mode 100644
index 0000000000..aba1065498
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -0,0 +1,380 @@
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Godot.Collections
+{
+ class ArraySafeHandle : SafeHandle
+ {
+ public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
+ {
+ this.handle = handle;
+ }
+
+ public override bool IsInvalid
+ {
+ get
+ {
+ return handle == IntPtr.Zero;
+ }
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Array.godot_icall_Array_Dtor(handle);
+ return true;
+ }
+ }
+
+ public class Array : IList, IDisposable
+ {
+ ArraySafeHandle safeHandle;
+ bool disposed = false;
+
+ public Array()
+ {
+ safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
+ }
+
+ public Array(IEnumerable collection) : this()
+ {
+ if (collection == null)
+ throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
+
+ MarshalUtils.EnumerableToArray(collection, GetPtr());
+ }
+
+ internal Array(ArraySafeHandle handle)
+ {
+ safeHandle = handle;
+ }
+
+ internal Array(IntPtr handle)
+ {
+ safeHandle = new ArraySafeHandle(handle);
+ }
+
+ internal IntPtr GetPtr()
+ {
+ if (disposed)
+ throw new ObjectDisposedException(GetType().FullName);
+
+ return safeHandle.DangerousGetHandle();
+ }
+
+ public Array Duplicate(bool deep = false)
+ {
+ return new Array(godot_icall_Array_Duplicate(GetPtr(), deep));
+ }
+
+ public Error Resize(int newSize)
+ {
+ return godot_icall_Array_Resize(GetPtr(), newSize);
+ }
+
+ // IDisposable
+
+ public void Dispose()
+ {
+ if (disposed)
+ return;
+
+ if (safeHandle != null)
+ {
+ safeHandle.Dispose();
+ safeHandle = null;
+ }
+
+ disposed = true;
+ }
+
+ // IList
+
+ public bool IsReadOnly => false;
+
+ public bool IsFixedSize => false;
+
+ public object this[int index]
+ {
+ get => godot_icall_Array_At(GetPtr(), index);
+ set => godot_icall_Array_SetAt(GetPtr(), index, value);
+ }
+
+ public int Add(object value) => godot_icall_Array_Add(GetPtr(), value);
+
+ public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value);
+
+ public void Clear() => godot_icall_Array_Clear(GetPtr());
+
+ public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value);
+
+ public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value);
+
+ public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value);
+
+ public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index);
+
+ // ICollection
+
+ public int Count => godot_icall_Array_Count(GetPtr());
+
+ public object SyncRoot => this;
+
+ public bool IsSynchronized => false;
+
+ public void CopyTo(System.Array array, int index)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
+
+ // Internal call may throw ArgumentException
+ godot_icall_Array_CopyTo(GetPtr(), array, index);
+ }
+
+ // IEnumerable
+
+ public IEnumerator GetEnumerator()
+ {
+ int count = Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ yield return this[i];
+ }
+ }
+
+ public override string ToString()
+ {
+ return godot_icall_Array_ToString(GetPtr());
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_Array_Ctor();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Array_Dtor(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static object godot_icall_Array_At(IntPtr ptr, int index);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_Array_Count(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_Array_Add(IntPtr ptr, object item);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Array_Clear(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_Array_Contains(IntPtr ptr, object item);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_Array_Duplicate(IntPtr ptr, bool deep);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_Array_IndexOf(IntPtr ptr, object item);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_Array_Remove(IntPtr ptr, object item);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_Array_ToString(IntPtr ptr);
+ }
+
+ public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
+ {
+ Array objectArray;
+
+ internal static int elemTypeEncoding;
+ internal static IntPtr elemTypeClass;
+
+ static Array()
+ {
+ Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass);
+ }
+
+ public Array()
+ {
+ objectArray = new Array();
+ }
+
+ public Array(IEnumerable<T> collection)
+ {
+ if (collection == null)
+ throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
+
+ objectArray = new Array(collection);
+ }
+
+ public Array(Array array)
+ {
+ objectArray = array;
+ }
+
+ internal Array(IntPtr handle)
+ {
+ objectArray = new Array(handle);
+ }
+
+ internal Array(ArraySafeHandle handle)
+ {
+ objectArray = new Array(handle);
+ }
+
+ internal IntPtr GetPtr()
+ {
+ return objectArray.GetPtr();
+ }
+
+ public static explicit operator Array(Array<T> from)
+ {
+ return from.objectArray;
+ }
+
+ public Array<T> Duplicate(bool deep = false)
+ {
+ return new Array<T>(objectArray.Duplicate(deep));
+ }
+
+ public Error Resize(int newSize)
+ {
+ return objectArray.Resize(newSize);
+ }
+
+ // IList<T>
+
+ public T this[int index]
+ {
+ get
+ {
+ return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass);
+ }
+ set
+ {
+ objectArray[index] = value;
+ }
+ }
+
+ public int IndexOf(T item)
+ {
+ return objectArray.IndexOf(item);
+ }
+
+ public void Insert(int index, T item)
+ {
+ objectArray.Insert(index, item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ objectArray.RemoveAt(index);
+ }
+
+ // ICollection<T>
+
+ public int Count
+ {
+ get
+ {
+ return objectArray.Count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return objectArray.IsReadOnly;
+ }
+ }
+
+ public void Add(T item)
+ {
+ objectArray.Add(item);
+ }
+
+ public void Clear()
+ {
+ objectArray.Clear();
+ }
+
+ public bool Contains(T item)
+ {
+ return objectArray.Contains(item);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+
+ // TODO This may be quite slow because every element access is an internal call.
+ // It could be moved entirely to an internal call if we find out how to do the cast there.
+
+ int count = objectArray.Count;
+
+ if (array.Length < (arrayIndex + count))
+ throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+
+ for (int i = 0; i < count; i++)
+ {
+ array[arrayIndex] = (T)this[i];
+ arrayIndex++;
+ }
+ }
+
+ public bool Remove(T item)
+ {
+ return Array.godot_icall_Array_Remove(GetPtr(), item);
+ }
+
+ // IEnumerable<T>
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ int count = objectArray.Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ yield return (T)this[i];
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public override string ToString() => objectArray.ToString();
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
new file mode 100644
index 0000000000..6adf044886
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public class ExportAttribute : Attribute
+ {
+ private PropertyHint hint;
+ private string hintString;
+
+ public ExportAttribute(PropertyHint hint = PropertyHint.None, string hintString = "")
+ {
+ this.hint = hint;
+ this.hintString = hintString;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
new file mode 100644
index 0000000000..55848769d5
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Method)]
+ 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/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
new file mode 100644
index 0000000000..1bf6d5199a
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
+ public class RemoteAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
+ public class SyncAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
+ public class MasterAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
+ public class PuppetAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
+ public class SlaveAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
+ public class RemoteSyncAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
+ public class MasterSyncAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
+ public class PuppetSyncAttribute : Attribute {}
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
new file mode 100644
index 0000000000..3957387be9
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Delegate)]
+ public class SignalAttribute : Attribute
+ {
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs
new file mode 100644
index 0000000000..d0437409af
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ToolAttribute.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class ToolAttribute : Attribute {}
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
new file mode 100644
index 0000000000..d38589013e
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -0,0 +1,700 @@
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Basis : IEquatable<Basis>
+ {
+ // NOTE: x, y and z are public-only. Use Column0, Column1 and Column2 internally.
+
+ /// <summary>
+ /// Returns the basis matrix’s x vector.
+ /// This is equivalent to <see cref="Column0"/>.
+ /// </summary>
+ public Vector3 x
+ {
+ get => Column0;
+ set => Column0 = value;
+ }
+
+ /// <summary>
+ /// Returns the basis matrix’s y vector.
+ /// This is equivalent to <see cref="Column1"/>.
+ /// </summary>
+ public Vector3 y
+ {
+ get => Column1;
+ set => Column1 = value;
+ }
+
+ /// <summary>
+ /// Returns the basis matrix’s z vector.
+ /// This is equivalent to <see cref="Column2"/>.
+ /// </summary>
+ public Vector3 z
+ {
+ get => Column2;
+ set => Column2 = value;
+ }
+
+ public Vector3 Row0;
+ public Vector3 Row1;
+ public Vector3 Row2;
+
+ public Vector3 Column0
+ {
+ get => new Vector3(Row0.x, Row1.x, Row2.x);
+ set
+ {
+ this.Row0.x = value.x;
+ this.Row1.x = value.y;
+ this.Row2.x = value.z;
+ }
+ }
+ public Vector3 Column1
+ {
+ get => new Vector3(Row0.y, Row1.y, Row2.y);
+ set
+ {
+ this.Row0.y = value.x;
+ this.Row1.y = value.y;
+ this.Row2.y = value.z;
+ }
+ }
+ public Vector3 Column2
+ {
+ get => new Vector3(Row0.z, Row1.z, Row2.z);
+ set
+ {
+ this.Row0.z = value.x;
+ this.Row1.z = value.y;
+ this.Row2.z = value.z;
+ }
+ }
+
+ public Vector3 Scale
+ {
+ get
+ {
+ real_t detSign = Mathf.Sign(Determinant());
+ return detSign * new Vector3
+ (
+ new Vector3(this.Row0[0], this.Row1[0], this.Row2[0]).Length(),
+ new Vector3(this.Row0[1], this.Row1[1], this.Row2[1]).Length(),
+ new Vector3(this.Row0[2], this.Row1[2], this.Row2[2]).Length()
+ );
+ }
+ }
+
+ public Vector3 this[int columnIndex]
+ {
+ get
+ {
+ switch (columnIndex)
+ {
+ case 0:
+ return Column0;
+ case 1:
+ return Column1;
+ case 2:
+ return Column2;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (columnIndex)
+ {
+ case 0:
+ Column0 = value;
+ return;
+ case 1:
+ Column1 = value;
+ return;
+ case 2:
+ Column2 = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public real_t this[int columnIndex, int rowIndex]
+ {
+ get
+ {
+ switch (columnIndex)
+ {
+ case 0:
+ return Column0[rowIndex];
+ case 1:
+ return Column1[rowIndex];
+ case 2:
+ return Column2[rowIndex];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (columnIndex)
+ {
+ case 0:
+ {
+ var column0 = Column0;
+ column0[rowIndex] = value;
+ Column0 = column0;
+ return;
+ }
+ case 1:
+ {
+ var column1 = Column1;
+ column1[rowIndex] = value;
+ Column1 = column1;
+ return;
+ }
+ case 2:
+ {
+ var column2 = Column2;
+ column2[rowIndex] = value;
+ Column2 = column2;
+ return;
+ }
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ internal Quat RotationQuat()
+ {
+ Basis orthonormalizedBasis = Orthonormalized();
+ real_t det = orthonormalizedBasis.Determinant();
+ if (det < 0)
+ {
+ // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles.
+ orthonormalizedBasis = orthonormalizedBasis.Scaled(Vector3.NegOne);
+ }
+
+ return orthonormalizedBasis.Quat();
+ }
+
+ internal void SetQuatScale(Quat quat, Vector3 scale)
+ {
+ SetDiagonal(scale);
+ Rotate(quat);
+ }
+
+ private void Rotate(Quat quat)
+ {
+ this *= new Basis(quat);
+ }
+
+ private void SetDiagonal(Vector3 diagonal)
+ {
+ Row0 = new Vector3(diagonal.x, 0, 0);
+ Row1 = new Vector3(0, diagonal.y, 0);
+ Row2 = new Vector3(0, 0, diagonal.z);
+ }
+
+ public real_t Determinant()
+ {
+ real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
+ real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2];
+ real_t cofac20 = Row1[0] * Row2[1] - Row1[1] * Row2[0];
+
+ return Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20;
+ }
+
+ public Vector3 GetEuler()
+ {
+ Basis m = Orthonormalized();
+
+ Vector3 euler;
+ euler.z = 0.0f;
+
+ real_t mzy = m.Row1[2];
+
+ if (mzy < 1.0f)
+ {
+ if (mzy > -1.0f)
+ {
+ euler.x = Mathf.Asin(-mzy);
+ euler.y = Mathf.Atan2(m.Row0[2], m.Row2[2]);
+ euler.z = Mathf.Atan2(m.Row1[0], m.Row1[1]);
+ }
+ else
+ {
+ euler.x = Mathf.Pi * 0.5f;
+ euler.y = -Mathf.Atan2(-m.Row0[1], m.Row0[0]);
+ }
+ }
+ else
+ {
+ euler.x = -Mathf.Pi * 0.5f;
+ euler.y = -Mathf.Atan2(-m.Row0[1], m.Row0[0]);
+ }
+
+ return euler;
+ }
+
+ public Vector3 GetRow(int index)
+ {
+ switch (index)
+ {
+ case 0:
+ return Row0;
+ case 1:
+ return Row1;
+ case 2:
+ return Row2;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ public void SetRow(int index, Vector3 value)
+ {
+ switch (index)
+ {
+ case 0:
+ Row0 = value;
+ return;
+ case 1:
+ Row1 = value;
+ return;
+ case 2:
+ Row2 = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ public Vector3 GetColumn(int index)
+ {
+ return this[index];
+ }
+
+ public void SetColumn(int index, Vector3 value)
+ {
+ this[index] = value;
+ }
+
+ [Obsolete("GetAxis is deprecated. Use GetColumn instead.")]
+ public Vector3 GetAxis(int axis)
+ {
+ return new Vector3(this.Row0[axis], this.Row1[axis], this.Row2[axis]);
+ }
+
+ public int GetOrthogonalIndex()
+ {
+ var orth = this;
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ var row = orth.GetRow(i);
+
+ real_t v = row[j];
+
+ if (v > 0.5f)
+ v = 1.0f;
+ else if (v < -0.5f)
+ v = -1.0f;
+ else
+ v = 0f;
+
+ row[j] = v;
+
+ orth.SetRow(i, row);
+ }
+ }
+
+ for (int i = 0; i < 24; i++)
+ {
+ if (orth == _orthoBases[i])
+ return i;
+ }
+
+ return 0;
+ }
+
+ public Basis Inverse()
+ {
+ real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
+ real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2];
+ real_t cofac20 = Row1[0] * Row2[1] - Row1[1] * Row2[0];
+
+ real_t det = Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20;
+
+ if (det == 0)
+ throw new InvalidOperationException("Matrix determinant is zero and cannot be inverted.");
+
+ real_t detInv = 1.0f / det;
+
+ real_t cofac01 = Row0[2] * Row2[1] - Row0[1] * Row2[2];
+ real_t cofac02 = Row0[1] * Row1[2] - Row0[2] * Row1[1];
+ real_t cofac11 = Row0[0] * Row2[2] - Row0[2] * Row2[0];
+ real_t cofac12 = Row0[2] * Row1[0] - Row0[0] * Row1[2];
+ real_t cofac21 = Row0[1] * Row2[0] - Row0[0] * Row2[1];
+ real_t cofac22 = Row0[0] * Row1[1] - Row0[1] * Row1[0];
+
+ return new Basis
+ (
+ cofac00 * detInv, cofac01 * detInv, cofac02 * detInv,
+ cofac10 * detInv, cofac11 * detInv, cofac12 * detInv,
+ cofac20 * detInv, cofac21 * detInv, cofac22 * detInv
+ );
+ }
+
+ public Basis Orthonormalized()
+ {
+ Vector3 column0 = GetColumn(0);
+ Vector3 column1 = GetColumn(1);
+ Vector3 column2 = GetColumn(2);
+
+ column0.Normalize();
+ column1 = column1 - column0 * column0.Dot(column1);
+ column1.Normalize();
+ column2 = column2 - column0 * column0.Dot(column2) - column1 * column1.Dot(column2);
+ column2.Normalize();
+
+ return new Basis(column0, column1, column2);
+ }
+
+ public Basis Rotated(Vector3 axis, real_t phi)
+ {
+ return new Basis(axis, phi) * this;
+ }
+
+ public Basis Scaled(Vector3 scale)
+ {
+ var b = this;
+ b.Row0 *= scale.x;
+ b.Row1 *= scale.y;
+ b.Row2 *= scale.z;
+ return b;
+ }
+
+ public Basis Slerp(Basis target, real_t t)
+ {
+ var from = new Quat(this);
+ var to = new Quat(target);
+
+ var b = new Basis(from.Slerp(to, t));
+ b.Row0 *= Mathf.Lerp(Row0.Length(), target.Row0.Length(), t);
+ b.Row1 *= Mathf.Lerp(Row1.Length(), target.Row1.Length(), t);
+ b.Row2 *= Mathf.Lerp(Row2.Length(), target.Row2.Length(), t);
+
+ return b;
+ }
+
+ public real_t Tdotx(Vector3 with)
+ {
+ return this.Row0[0] * with[0] + this.Row1[0] * with[1] + this.Row2[0] * with[2];
+ }
+
+ public real_t Tdoty(Vector3 with)
+ {
+ return this.Row0[1] * with[0] + this.Row1[1] * with[1] + this.Row2[1] * with[2];
+ }
+
+ public real_t Tdotz(Vector3 with)
+ {
+ return this.Row0[2] * with[0] + this.Row1[2] * with[1] + this.Row2[2] * with[2];
+ }
+
+ public Basis Transposed()
+ {
+ var tr = this;
+
+ real_t temp = tr.Row0[1];
+ tr.Row0[1] = tr.Row1[0];
+ tr.Row1[0] = temp;
+
+ temp = tr.Row0[2];
+ tr.Row0[2] = tr.Row2[0];
+ tr.Row2[0] = temp;
+
+ temp = tr.Row1[2];
+ tr.Row1[2] = tr.Row2[1];
+ tr.Row2[1] = temp;
+
+ return tr;
+ }
+
+ public Vector3 Xform(Vector3 v)
+ {
+ return new Vector3
+ (
+ this.Row0.Dot(v),
+ this.Row1.Dot(v),
+ this.Row2.Dot(v)
+ );
+ }
+
+ public Vector3 XformInv(Vector3 v)
+ {
+ return new Vector3
+ (
+ this.Row0[0] * v.x + this.Row1[0] * v.y + this.Row2[0] * v.z,
+ this.Row0[1] * v.x + this.Row1[1] * v.y + this.Row2[1] * v.z,
+ this.Row0[2] * v.x + this.Row1[2] * v.y + this.Row2[2] * v.z
+ );
+ }
+
+ public Quat Quat()
+ {
+ real_t trace = Row0[0] + Row1[1] + Row2[2];
+
+ if (trace > 0.0f)
+ {
+ real_t s = Mathf.Sqrt(trace + 1.0f) * 2f;
+ real_t inv_s = 1f / s;
+ return new Quat(
+ (Row2[1] - Row1[2]) * inv_s,
+ (Row0[2] - Row2[0]) * inv_s,
+ (Row1[0] - Row0[1]) * inv_s,
+ s * 0.25f
+ );
+ }
+
+ if (Row0[0] > Row1[1] && Row0[0] > Row2[2])
+ {
+ real_t s = Mathf.Sqrt(Row0[0] - Row1[1] - Row2[2] + 1.0f) * 2f;
+ real_t inv_s = 1f / s;
+ return new Quat(
+ s * 0.25f,
+ (Row0[1] + Row1[0]) * inv_s,
+ (Row0[2] + Row2[0]) * inv_s,
+ (Row2[1] - Row1[2]) * inv_s
+ );
+ }
+
+ if (Row1[1] > Row2[2])
+ {
+ real_t s = Mathf.Sqrt(-Row0[0] + Row1[1] - Row2[2] + 1.0f) * 2f;
+ real_t inv_s = 1f / s;
+ return new Quat(
+ (Row0[1] + Row1[0]) * inv_s,
+ s * 0.25f,
+ (Row1[2] + Row2[1]) * inv_s,
+ (Row0[2] - Row2[0]) * inv_s
+ );
+ }
+ else
+ {
+ real_t s = Mathf.Sqrt(-Row0[0] - Row1[1] + Row2[2] + 1.0f) * 2f;
+ real_t inv_s = 1f / s;
+ return new Quat(
+ (Row0[2] + Row2[0]) * inv_s,
+ (Row1[2] + Row2[1]) * inv_s,
+ s * 0.25f,
+ (Row1[0] - Row0[1]) * inv_s
+ );
+ }
+ }
+
+ private static readonly Basis[] _orthoBases = {
+ 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)
+ };
+
+ private static readonly Basis _identity = new Basis(1, 0, 0, 0, 1, 0, 0, 0, 1);
+ private static readonly Basis _flipX = new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1);
+ private static readonly Basis _flipY = new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1);
+ private static readonly Basis _flipZ = new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1);
+
+ public static Basis Identity { get { return _identity; } }
+ public static Basis FlipX { get { return _flipX; } }
+ public static Basis FlipY { get { return _flipY; } }
+ public static Basis FlipZ { get { return _flipZ; } }
+
+ public Basis(Quat quat)
+ {
+ real_t s = 2.0f / quat.LengthSquared;
+
+ real_t xs = quat.x * s;
+ real_t ys = quat.y * s;
+ real_t zs = quat.z * s;
+ real_t wx = quat.w * xs;
+ real_t wy = quat.w * ys;
+ real_t wz = quat.w * zs;
+ real_t xx = quat.x * xs;
+ real_t xy = quat.x * ys;
+ real_t xz = quat.x * zs;
+ real_t yy = quat.y * ys;
+ real_t yz = quat.y * zs;
+ real_t zz = quat.z * zs;
+
+ Row0 = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
+ Row1 = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
+ Row2 = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
+ }
+
+ public Basis(Vector3 euler)
+ {
+ real_t c;
+ real_t s;
+
+ c = Mathf.Cos(euler.x);
+ s = Mathf.Sin(euler.x);
+ var xmat = new Basis(1, 0, 0, 0, c, -s, 0, s, c);
+
+ c = Mathf.Cos(euler.y);
+ s = Mathf.Sin(euler.y);
+ var ymat = new Basis(c, 0, s, 0, 1, 0, -s, 0, c);
+
+ c = Mathf.Cos(euler.z);
+ s = Mathf.Sin(euler.z);
+ var zmat = new Basis(c, -s, 0, s, c, 0, 0, 0, 1);
+
+ this = ymat * xmat * zmat;
+ }
+
+ public Basis(Vector3 axis, real_t phi)
+ {
+ Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
+ real_t cosine = Mathf.Cos(phi);
+ Row0.x = axisSq.x + cosine * (1.0f - axisSq.x);
+ Row1.y = axisSq.y + cosine * (1.0f - axisSq.y);
+ Row2.z = axisSq.z + cosine * (1.0f - axisSq.z);
+
+ real_t sine = Mathf.Sin(phi);
+ real_t t = 1.0f - cosine;
+
+ real_t xyzt = axis.x * axis.y * t;
+ real_t zyxs = axis.z * sine;
+ Row0.y = xyzt - zyxs;
+ Row1.x = xyzt + zyxs;
+
+ xyzt = axis.x * axis.z * t;
+ zyxs = axis.y * sine;
+ Row0.z = xyzt + zyxs;
+ Row2.x = xyzt - zyxs;
+
+ xyzt = axis.y * axis.z * t;
+ zyxs = axis.x * sine;
+ Row1.z = xyzt - zyxs;
+ Row2.y = xyzt + zyxs;
+ }
+
+ public Basis(Vector3 column0, Vector3 column1, Vector3 column2)
+ {
+ Row0 = new Vector3(column0.x, column1.x, column2.x);
+ Row1 = new Vector3(column0.y, column1.y, column2.y);
+ Row2 = new Vector3(column0.z, column1.z, column2.z);
+ // Same as:
+ // Column0 = column0;
+ // Column1 = column1;
+ // Column2 = column2;
+ // We need to assign the struct fields here first so we can't do it that way...
+ }
+
+ // Arguments are named such that xy is equal to calling x.y
+ internal Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz)
+ {
+ Row0 = new Vector3(xx, yx, zx);
+ Row1 = new Vector3(xy, yy, zy);
+ Row2 = new Vector3(xz, yz, zz);
+ }
+
+ public static Basis operator *(Basis left, Basis right)
+ {
+ return new Basis
+ (
+ right.Tdotx(left.Row0), right.Tdoty(left.Row0), right.Tdotz(left.Row0),
+ right.Tdotx(left.Row1), right.Tdoty(left.Row1), right.Tdotz(left.Row1),
+ right.Tdotx(left.Row2), right.Tdoty(left.Row2), right.Tdotz(left.Row2)
+ );
+ }
+
+ 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 Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2);
+ }
+
+ public bool IsEqualApprox(Basis other)
+ {
+ return Row0.IsEqualApprox(other.Row0) && Row1.IsEqualApprox(other.Row1) && Row2.IsEqualApprox(other.Row2);
+ }
+
+ public override int GetHashCode()
+ {
+ return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ Row0.ToString(),
+ Row1.ToString(),
+ Row2.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ Row0.ToString(format),
+ Row1.ToString(format),
+ Row2.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
new file mode 100644
index 0000000000..1d1a49945f
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -0,0 +1,755 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Color : IEquatable<Color>
+ {
+ public float r;
+ public float g;
+ public float b;
+ public float a;
+
+ public int r8
+ {
+ get
+ {
+ return (int)Math.Round(r * 255.0f);
+ }
+ set
+ {
+ r = value / 255.0f;
+ }
+ }
+
+ public int g8
+ {
+ get
+ {
+ return (int)Math.Round(g * 255.0f);
+ }
+ set
+ {
+ g = value / 255.0f;
+ }
+ }
+
+ public int b8
+ {
+ get
+ {
+ return (int)Math.Round(b * 255.0f);
+ }
+ set
+ {
+ b = value / 255.0f;
+ }
+ }
+
+ public int a8
+ {
+ get
+ {
+ return (int)Math.Round(a * 255.0f);
+ }
+ set
+ {
+ a = value / 255.0f;
+ }
+ }
+
+ public float h
+ {
+ get
+ {
+ float max = Math.Max(r, Math.Max(g, b));
+ float min = Math.Min(r, Math.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 = FromHsv(value, s, v, a);
+ }
+ }
+
+ public float s
+ {
+ get
+ {
+ float max = Math.Max(r, Math.Max(g, b));
+ float min = Math.Min(r, Math.Min(g, b));
+
+ float delta = max - min;
+
+ return max != 0 ? delta / max : 0;
+ }
+ set
+ {
+ this = FromHsv(h, value, v, a);
+ }
+ }
+
+ public float v
+ {
+ get
+ {
+ return Math.Max(r, Math.Max(g, b));
+ }
+ set
+ {
+ this = FromHsv(h, s, value, a);
+ }
+ }
+
+ public static Color ColorN(string name, float alpha = 1f)
+ {
+ name = name.Replace(" ", String.Empty);
+ name = name.Replace("-", String.Empty);
+ name = name.Replace("_", String.Empty);
+ name = name.Replace("'", String.Empty);
+ name = name.Replace(".", String.Empty);
+ name = name.ToLower();
+
+ if (!Colors.namedColors.ContainsKey(name))
+ {
+ throw new ArgumentOutOfRangeException($"Invalid Color Name: {name}");
+ }
+
+ Color color = Colors.namedColors[name];
+ color.a = alpha;
+ return color;
+ }
+
+ 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 void ToHsv(out float hue, out float saturation, out float value)
+ {
+ float max = (float)Mathf.Max(r, Mathf.Max(g, b));
+ float min = (float)Mathf.Min(r, Mathf.Min(g, b));
+
+ float delta = max - min;
+
+ if (delta == 0)
+ {
+ hue = 0;
+ }
+ else
+ {
+ if (r == max)
+ hue = (g - b) / delta; // Between yellow & magenta
+ else if (g == max)
+ hue = 2 + (b - r) / delta; // Between cyan & yellow
+ else
+ hue = 4 + (r - g) / delta; // Between magenta & cyan
+
+ hue /= 6.0f;
+
+ if (hue < 0)
+ hue += 1.0f;
+ }
+
+ saturation = max == 0 ? 0 : 1f - 1f * min / max;
+ value = max;
+ }
+
+ public static Color FromHsv(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);
+ }
+
+ 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,
+ a
+ );
+ }
+
+ public Color Darkened(float amount)
+ {
+ Color res = this;
+ res.r = res.r * (1.0f - amount);
+ res.g = res.g * (1.0f - amount);
+ res.b = res.b * (1.0f - amount);
+ return res;
+ }
+
+ public Color Inverted()
+ {
+ return new Color(
+ 1.0f - r,
+ 1.0f - g,
+ 1.0f - b,
+ a
+ );
+ }
+
+ public Color Lightened(float amount)
+ {
+ Color res = this;
+ res.r = res.r + (1.0f - res.r) * amount;
+ res.g = res.g + (1.0f - res.g) * amount;
+ res.b = res.b + (1.0f - res.b) * amount;
+ return res;
+ }
+
+ public Color LinearInterpolate(Color c, float t)
+ {
+ var res = this;
+
+ res.r += t * (c.r - r);
+ res.g += t * (c.g - g);
+ res.b += t * (c.b - b);
+ res.a += t * (c.a - a);
+
+ return res;
+ }
+
+ public uint ToAbgr32()
+ {
+ uint c = (byte)Math.Round(a * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(b * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(g * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(r * 255);
+
+ return c;
+ }
+
+ public ulong ToAbgr64()
+ {
+ ulong c = (ushort)Math.Round(a * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(b * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(g * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(r * 65535);
+
+ return c;
+ }
+
+ public uint ToArgb32()
+ {
+ uint c = (byte)Math.Round(a * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(r * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(g * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(b * 255);
+
+ return c;
+ }
+
+ public ulong ToArgb64()
+ {
+ ulong c = (ushort)Math.Round(a * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(r * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(g * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(b * 65535);
+
+ return c;
+ }
+
+ public uint ToRgba32()
+ {
+ uint c = (byte)Math.Round(r * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(g * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(b * 255);
+ c <<= 8;
+ c |= (byte)Math.Round(a * 255);
+
+ return c;
+ }
+
+ public ulong ToRgba64()
+ {
+ ulong c = (ushort)Math.Round(r * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(g * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(b * 65535);
+ c <<= 16;
+ c |= (ushort)Math.Round(a * 65535);
+
+ return c;
+ }
+
+ public string ToHtml(bool includeAlpha = true)
+ {
+ var txt = string.Empty;
+
+ txt += ToHex32(r);
+ txt += ToHex32(g);
+ txt += ToHex32(b);
+
+ if (includeAlpha)
+ txt = ToHex32(a) + txt;
+
+ return txt;
+ }
+
+ // Constructors
+ 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(uint rgba)
+ {
+ a = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ b = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ g = (rgba & 0xFF) / 255.0f;
+ rgba >>= 8;
+ r = (rgba & 0xFF) / 255.0f;
+ }
+
+ public Color(ulong rgba)
+ {
+ a = (rgba & 0xFFFF) / 65535.0f;
+ rgba >>= 16;
+ b = (rgba & 0xFFFF) / 65535.0f;
+ rgba >>= 16;
+ g = (rgba & 0xFFFF) / 65535.0f;
+ rgba >>= 16;
+ r = (rgba & 0xFFFF) / 65535.0f;
+ }
+
+ private static int ParseCol8(string str, int ofs)
+ {
+ int ig = 0;
+
+ for (int i = 0; i < 2; i++)
+ {
+ int c = str[i + ofs];
+ int v;
+
+ 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 ToHex32(float val)
+ {
+ int v = Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255));
+
+ var ret = string.Empty;
+
+ for (int i = 0; i < 2; i++)
+ {
+ char c;
+ int lv = v & 0xF;
+
+ if (lv < 10)
+ c = (char)('0' + lv);
+ else
+ c = (char)('a' + lv - 10);
+
+ v >>= 4;
+ ret = c + ret;
+ }
+
+ return ret;
+ }
+
+ internal static bool HtmlIsValid(string color)
+ {
+ if (color.Length == 0)
+ return false;
+
+ if (color[0] == '#')
+ color = color.Substring(1, color.Length - 1);
+
+ bool alpha;
+
+ switch (color.Length)
+ {
+ case 8:
+ alpha = true;
+ break;
+ case 6:
+ alpha = false;
+ break;
+ default:
+ return false;
+ }
+
+ if (alpha)
+ {
+ if (ParseCol8(color, 0) < 0)
+ return false;
+ }
+
+ int from = alpha ? 2 : 0;
+
+ if (ParseCol8(color, from + 0) < 0)
+ return false;
+ if (ParseCol8(color, from + 2) < 0)
+ return false;
+ if (ParseCol8(color, from + 4) < 0)
+ return false;
+
+ return true;
+ }
+
+ public static Color Color8(byte r8, byte g8, byte b8, byte a8 = 255)
+ {
+ return new Color(r8 / 255f, g8 / 255f, b8 / 255f, 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;
+
+ 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 = ParseCol8(rgba, 0) / 255f;
+
+ if (a < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba);
+ }
+ else
+ {
+ a = 1.0f;
+ }
+
+ int from = alpha ? 2 : 0;
+
+ r = ParseCol8(rgba, from + 0) / 255f;
+
+ if (r < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba);
+
+ g = ParseCol8(rgba, from + 2) / 255f;
+
+ if (g < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba);
+
+ b = ParseCol8(rgba, from + 4) / 255f;
+
+ if (b < 0)
+ throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba);
+ }
+
+ public static Color operator +(Color left, Color right)
+ {
+ left.r += right.r;
+ left.g += right.g;
+ left.b += right.b;
+ left.a += right.a;
+ return left;
+ }
+
+ public static Color operator -(Color left, Color right)
+ {
+ left.r -= right.r;
+ left.g -= right.g;
+ left.b -= right.b;
+ left.a -= right.a;
+ return left;
+ }
+
+ public static Color operator -(Color color)
+ {
+ return Colors.White - color;
+ }
+
+ public static Color operator *(Color color, float scale)
+ {
+ color.r *= scale;
+ color.g *= scale;
+ color.b *= scale;
+ color.a *= scale;
+ return color;
+ }
+
+ public static Color operator *(float scale, Color color)
+ {
+ color.r *= scale;
+ color.g *= scale;
+ color.b *= scale;
+ color.a *= scale;
+ return color;
+ }
+
+ public static Color operator *(Color left, Color right)
+ {
+ left.r *= right.r;
+ left.g *= right.g;
+ left.b *= right.b;
+ left.a *= right.a;
+ return left;
+ }
+
+ public static Color operator /(Color color, float scale)
+ {
+ color.r /= scale;
+ color.g /= scale;
+ color.b /= scale;
+ color.a /= scale;
+ return color;
+ }
+
+ public static Color operator /(Color left, Color right)
+ {
+ left.r /= right.r;
+ left.g /= right.g;
+ left.b /= right.b;
+ left.a /= right.a;
+ return left;
+ }
+
+ 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 (Mathf.IsEqualApprox(left.r, right.r))
+ {
+ if (Mathf.IsEqualApprox(left.g, right.g))
+ {
+ if (Mathf.IsEqualApprox(left.b, right.b))
+ return left.a < right.a;
+ return left.b < right.b;
+ }
+
+ return left.g < right.g;
+ }
+
+ return left.r < right.r;
+ }
+
+ public static bool operator >(Color left, Color right)
+ {
+ if (Mathf.IsEqualApprox(left.r, right.r))
+ {
+ if (Mathf.IsEqualApprox(left.g, right.g))
+ {
+ if (Mathf.IsEqualApprox(left.b, right.b))
+ return left.a > right.a;
+ return left.b > right.b;
+ }
+
+ 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 bool IsEqualApprox(Color other)
+ {
+ return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(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}", r.ToString(), g.ToString(), b.ToString(), a.ToString());
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0},{1},{2},{3}", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format));
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
new file mode 100644
index 0000000000..f41f5e9fc8
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Collections.Generic;
+
+namespace Godot
+{
+ public static class Colors
+ {
+ // Color names and values are derived from core/color_names.inc
+ internal static readonly Dictionary<string, Color> namedColors = new Dictionary<string, Color> {
+ {"aliceblue", new Color(0.94f, 0.97f, 1.00f)},
+ {"antiquewhite", new Color(0.98f, 0.92f, 0.84f)},
+ {"aqua", new Color(0.00f, 1.00f, 1.00f)},
+ {"aquamarine", new Color(0.50f, 1.00f, 0.83f)},
+ {"azure", new Color(0.94f, 1.00f, 1.00f)},
+ {"beige", new Color(0.96f, 0.96f, 0.86f)},
+ {"bisque", new Color(1.00f, 0.89f, 0.77f)},
+ {"black", new Color(0.00f, 0.00f, 0.00f)},
+ {"blanchedalmond", new Color(1.00f, 0.92f, 0.80f)},
+ {"blue", new Color(0.00f, 0.00f, 1.00f)},
+ {"blueviolet", new Color(0.54f, 0.17f, 0.89f)},
+ {"brown", new Color(0.65f, 0.16f, 0.16f)},
+ {"burlywood", new Color(0.87f, 0.72f, 0.53f)},
+ {"cadetblue", new Color(0.37f, 0.62f, 0.63f)},
+ {"chartreuse", new Color(0.50f, 1.00f, 0.00f)},
+ {"chocolate", new Color(0.82f, 0.41f, 0.12f)},
+ {"coral", new Color(1.00f, 0.50f, 0.31f)},
+ {"cornflower", new Color(0.39f, 0.58f, 0.93f)},
+ {"cornsilk", new Color(1.00f, 0.97f, 0.86f)},
+ {"crimson", new Color(0.86f, 0.08f, 0.24f)},
+ {"cyan", new Color(0.00f, 1.00f, 1.00f)},
+ {"darkblue", new Color(0.00f, 0.00f, 0.55f)},
+ {"darkcyan", new Color(0.00f, 0.55f, 0.55f)},
+ {"darkgoldenrod", new Color(0.72f, 0.53f, 0.04f)},
+ {"darkgray", new Color(0.66f, 0.66f, 0.66f)},
+ {"darkgreen", new Color(0.00f, 0.39f, 0.00f)},
+ {"darkkhaki", new Color(0.74f, 0.72f, 0.42f)},
+ {"darkmagenta", new Color(0.55f, 0.00f, 0.55f)},
+ {"darkolivegreen", new Color(0.33f, 0.42f, 0.18f)},
+ {"darkorange", new Color(1.00f, 0.55f, 0.00f)},
+ {"darkorchid", new Color(0.60f, 0.20f, 0.80f)},
+ {"darkred", new Color(0.55f, 0.00f, 0.00f)},
+ {"darksalmon", new Color(0.91f, 0.59f, 0.48f)},
+ {"darkseagreen", new Color(0.56f, 0.74f, 0.56f)},
+ {"darkslateblue", new Color(0.28f, 0.24f, 0.55f)},
+ {"darkslategray", new Color(0.18f, 0.31f, 0.31f)},
+ {"darkturquoise", new Color(0.00f, 0.81f, 0.82f)},
+ {"darkviolet", new Color(0.58f, 0.00f, 0.83f)},
+ {"deeppink", new Color(1.00f, 0.08f, 0.58f)},
+ {"deepskyblue", new Color(0.00f, 0.75f, 1.00f)},
+ {"dimgray", new Color(0.41f, 0.41f, 0.41f)},
+ {"dodgerblue", new Color(0.12f, 0.56f, 1.00f)},
+ {"firebrick", new Color(0.70f, 0.13f, 0.13f)},
+ {"floralwhite", new Color(1.00f, 0.98f, 0.94f)},
+ {"forestgreen", new Color(0.13f, 0.55f, 0.13f)},
+ {"fuchsia", new Color(1.00f, 0.00f, 1.00f)},
+ {"gainsboro", new Color(0.86f, 0.86f, 0.86f)},
+ {"ghostwhite", new Color(0.97f, 0.97f, 1.00f)},
+ {"gold", new Color(1.00f, 0.84f, 0.00f)},
+ {"goldenrod", new Color(0.85f, 0.65f, 0.13f)},
+ {"gray", new Color(0.75f, 0.75f, 0.75f)},
+ {"green", new Color(0.00f, 1.00f, 0.00f)},
+ {"greenyellow", new Color(0.68f, 1.00f, 0.18f)},
+ {"honeydew", new Color(0.94f, 1.00f, 0.94f)},
+ {"hotpink", new Color(1.00f, 0.41f, 0.71f)},
+ {"indianred", new Color(0.80f, 0.36f, 0.36f)},
+ {"indigo", new Color(0.29f, 0.00f, 0.51f)},
+ {"ivory", new Color(1.00f, 1.00f, 0.94f)},
+ {"khaki", new Color(0.94f, 0.90f, 0.55f)},
+ {"lavender", new Color(0.90f, 0.90f, 0.98f)},
+ {"lavenderblush", new Color(1.00f, 0.94f, 0.96f)},
+ {"lawngreen", new Color(0.49f, 0.99f, 0.00f)},
+ {"lemonchiffon", new Color(1.00f, 0.98f, 0.80f)},
+ {"lightblue", new Color(0.68f, 0.85f, 0.90f)},
+ {"lightcoral", new Color(0.94f, 0.50f, 0.50f)},
+ {"lightcyan", new Color(0.88f, 1.00f, 1.00f)},
+ {"lightgoldenrod", new Color(0.98f, 0.98f, 0.82f)},
+ {"lightgray", new Color(0.83f, 0.83f, 0.83f)},
+ {"lightgreen", new Color(0.56f, 0.93f, 0.56f)},
+ {"lightpink", new Color(1.00f, 0.71f, 0.76f)},
+ {"lightsalmon", new Color(1.00f, 0.63f, 0.48f)},
+ {"lightseagreen", new Color(0.13f, 0.70f, 0.67f)},
+ {"lightskyblue", new Color(0.53f, 0.81f, 0.98f)},
+ {"lightslategray", new Color(0.47f, 0.53f, 0.60f)},
+ {"lightsteelblue", new Color(0.69f, 0.77f, 0.87f)},
+ {"lightyellow", new Color(1.00f, 1.00f, 0.88f)},
+ {"lime", new Color(0.00f, 1.00f, 0.00f)},
+ {"limegreen", new Color(0.20f, 0.80f, 0.20f)},
+ {"linen", new Color(0.98f, 0.94f, 0.90f)},
+ {"magenta", new Color(1.00f, 0.00f, 1.00f)},
+ {"maroon", new Color(0.69f, 0.19f, 0.38f)},
+ {"mediumaquamarine", new Color(0.40f, 0.80f, 0.67f)},
+ {"mediumblue", new Color(0.00f, 0.00f, 0.80f)},
+ {"mediumorchid", new Color(0.73f, 0.33f, 0.83f)},
+ {"mediumpurple", new Color(0.58f, 0.44f, 0.86f)},
+ {"mediumseagreen", new Color(0.24f, 0.70f, 0.44f)},
+ {"mediumslateblue", new Color(0.48f, 0.41f, 0.93f)},
+ {"mediumspringgreen", new Color(0.00f, 0.98f, 0.60f)},
+ {"mediumturquoise", new Color(0.28f, 0.82f, 0.80f)},
+ {"mediumvioletred", new Color(0.78f, 0.08f, 0.52f)},
+ {"midnightblue", new Color(0.10f, 0.10f, 0.44f)},
+ {"mintcream", new Color(0.96f, 1.00f, 0.98f)},
+ {"mistyrose", new Color(1.00f, 0.89f, 0.88f)},
+ {"moccasin", new Color(1.00f, 0.89f, 0.71f)},
+ {"navajowhite", new Color(1.00f, 0.87f, 0.68f)},
+ {"navyblue", new Color(0.00f, 0.00f, 0.50f)},
+ {"oldlace", new Color(0.99f, 0.96f, 0.90f)},
+ {"olive", new Color(0.50f, 0.50f, 0.00f)},
+ {"olivedrab", new Color(0.42f, 0.56f, 0.14f)},
+ {"orange", new Color(1.00f, 0.65f, 0.00f)},
+ {"orangered", new Color(1.00f, 0.27f, 0.00f)},
+ {"orchid", new Color(0.85f, 0.44f, 0.84f)},
+ {"palegoldenrod", new Color(0.93f, 0.91f, 0.67f)},
+ {"palegreen", new Color(0.60f, 0.98f, 0.60f)},
+ {"paleturquoise", new Color(0.69f, 0.93f, 0.93f)},
+ {"palevioletred", new Color(0.86f, 0.44f, 0.58f)},
+ {"papayawhip", new Color(1.00f, 0.94f, 0.84f)},
+ {"peachpuff", new Color(1.00f, 0.85f, 0.73f)},
+ {"peru", new Color(0.80f, 0.52f, 0.25f)},
+ {"pink", new Color(1.00f, 0.75f, 0.80f)},
+ {"plum", new Color(0.87f, 0.63f, 0.87f)},
+ {"powderblue", new Color(0.69f, 0.88f, 0.90f)},
+ {"purple", new Color(0.63f, 0.13f, 0.94f)},
+ {"rebeccapurple", new Color(0.40f, 0.20f, 0.60f)},
+ {"red", new Color(1.00f, 0.00f, 0.00f)},
+ {"rosybrown", new Color(0.74f, 0.56f, 0.56f)},
+ {"royalblue", new Color(0.25f, 0.41f, 0.88f)},
+ {"saddlebrown", new Color(0.55f, 0.27f, 0.07f)},
+ {"salmon", new Color(0.98f, 0.50f, 0.45f)},
+ {"sandybrown", new Color(0.96f, 0.64f, 0.38f)},
+ {"seagreen", new Color(0.18f, 0.55f, 0.34f)},
+ {"seashell", new Color(1.00f, 0.96f, 0.93f)},
+ {"sienna", new Color(0.63f, 0.32f, 0.18f)},
+ {"silver", new Color(0.75f, 0.75f, 0.75f)},
+ {"skyblue", new Color(0.53f, 0.81f, 0.92f)},
+ {"slateblue", new Color(0.42f, 0.35f, 0.80f)},
+ {"slategray", new Color(0.44f, 0.50f, 0.56f)},
+ {"snow", new Color(1.00f, 0.98f, 0.98f)},
+ {"springgreen", new Color(0.00f, 1.00f, 0.50f)},
+ {"steelblue", new Color(0.27f, 0.51f, 0.71f)},
+ {"tan", new Color(0.82f, 0.71f, 0.55f)},
+ {"teal", new Color(0.00f, 0.50f, 0.50f)},
+ {"thistle", new Color(0.85f, 0.75f, 0.85f)},
+ {"tomato", new Color(1.00f, 0.39f, 0.28f)},
+ {"transparent", new Color(1.00f, 1.00f, 1.00f, 0.00f)},
+ {"turquoise", new Color(0.25f, 0.88f, 0.82f)},
+ {"violet", new Color(0.93f, 0.51f, 0.93f)},
+ {"webgreen", new Color(0.00f, 0.50f, 0.00f)},
+ {"webgray", new Color(0.50f, 0.50f, 0.50f)},
+ {"webmaroon", new Color(0.50f, 0.00f, 0.00f)},
+ {"webpurple", new Color(0.50f, 0.00f, 0.50f)},
+ {"wheat", new Color(0.96f, 0.87f, 0.70f)},
+ {"white", new Color(1.00f, 1.00f, 1.00f)},
+ {"whitesmoke", new Color(0.96f, 0.96f, 0.96f)},
+ {"yellow", new Color(1.00f, 1.00f, 0.00f)},
+ {"yellowgreen", new Color(0.60f, 0.80f, 0.20f)},
+ };
+
+ public static Color AliceBlue { get { return namedColors["aliceblue"]; } }
+ public static Color AntiqueWhite { get { return namedColors["antiquewhite"]; } }
+ public static Color Aqua { get { return namedColors["aqua"]; } }
+ public static Color Aquamarine { get { return namedColors["aquamarine"]; } }
+ public static Color Azure { get { return namedColors["azure"]; } }
+ public static Color Beige { get { return namedColors["beige"]; } }
+ public static Color Bisque { get { return namedColors["bisque"]; } }
+ public static Color Black { get { return namedColors["black"]; } }
+ public static Color BlanchedAlmond { get { return namedColors["blanchedalmond"]; } }
+ public static Color Blue { get { return namedColors["blue"]; } }
+ public static Color BlueViolet { get { return namedColors["blueviolet"]; } }
+ public static Color Brown { get { return namedColors["brown"]; } }
+ public static Color BurlyWood { get { return namedColors["burlywood"]; } }
+ public static Color CadetBlue { get { return namedColors["cadetblue"]; } }
+ public static Color Chartreuse { get { return namedColors["chartreuse"]; } }
+ public static Color Chocolate { get { return namedColors["chocolate"]; } }
+ public static Color Coral { get { return namedColors["coral"]; } }
+ public static Color Cornflower { get { return namedColors["cornflower"]; } }
+ public static Color Cornsilk { get { return namedColors["cornsilk"]; } }
+ public static Color Crimson { get { return namedColors["crimson"]; } }
+ public static Color Cyan { get { return namedColors["cyan"]; } }
+ public static Color DarkBlue { get { return namedColors["darkblue"]; } }
+ public static Color DarkCyan { get { return namedColors["darkcyan"]; } }
+ public static Color DarkGoldenrod { get { return namedColors["darkgoldenrod"]; } }
+ public static Color DarkGray { get { return namedColors["darkgray"]; } }
+ public static Color DarkGreen { get { return namedColors["darkgreen"]; } }
+ public static Color DarkKhaki { get { return namedColors["darkkhaki"]; } }
+ public static Color DarkMagenta { get { return namedColors["darkmagenta"]; } }
+ public static Color DarkOliveGreen { get { return namedColors["darkolivegreen"]; } }
+ public static Color DarkOrange { get { return namedColors["darkorange"]; } }
+ public static Color DarkOrchid { get { return namedColors["darkorchid"]; } }
+ public static Color DarkRed { get { return namedColors["darkred"]; } }
+ public static Color DarkSalmon { get { return namedColors["darksalmon"]; } }
+ public static Color DarkSeaGreen { get { return namedColors["darkseagreen"]; } }
+ public static Color DarkSlateBlue { get { return namedColors["darkslateblue"]; } }
+ public static Color DarkSlateGray { get { return namedColors["darkslategray"]; } }
+ public static Color DarkTurquoise { get { return namedColors["darkturquoise"]; } }
+ public static Color DarkViolet { get { return namedColors["darkviolet"]; } }
+ public static Color DeepPink { get { return namedColors["deeppink"]; } }
+ public static Color DeepSkyBlue { get { return namedColors["deepskyblue"]; } }
+ public static Color DimGray { get { return namedColors["dimgray"]; } }
+ public static Color DodgerBlue { get { return namedColors["dodgerblue"]; } }
+ public static Color Firebrick { get { return namedColors["firebrick"]; } }
+ public static Color FloralWhite { get { return namedColors["floralwhite"]; } }
+ public static Color ForestGreen { get { return namedColors["forestgreen"]; } }
+ public static Color Fuchsia { get { return namedColors["fuchsia"]; } }
+ public static Color Gainsboro { get { return namedColors["gainsboro"]; } }
+ public static Color GhostWhite { get { return namedColors["ghostwhite"]; } }
+ public static Color Gold { get { return namedColors["gold"]; } }
+ public static Color Goldenrod { get { return namedColors["goldenrod"]; } }
+ public static Color Gray { get { return namedColors["gray"]; } }
+ public static Color Green { get { return namedColors["green"]; } }
+ public static Color GreenYellow { get { return namedColors["greenyellow"]; } }
+ public static Color Honeydew { get { return namedColors["honeydew"]; } }
+ public static Color HotPink { get { return namedColors["hotpink"]; } }
+ public static Color IndianRed { get { return namedColors["indianred"]; } }
+ public static Color Indigo { get { return namedColors["indigo"]; } }
+ public static Color Ivory { get { return namedColors["ivory"]; } }
+ public static Color Khaki { get { return namedColors["khaki"]; } }
+ public static Color Lavender { get { return namedColors["lavender"]; } }
+ public static Color LavenderBlush { get { return namedColors["lavenderblush"]; } }
+ public static Color LawnGreen { get { return namedColors["lawngreen"]; } }
+ public static Color LemonChiffon { get { return namedColors["lemonchiffon"]; } }
+ public static Color LightBlue { get { return namedColors["lightblue"]; } }
+ public static Color LightCoral { get { return namedColors["lightcoral"]; } }
+ public static Color LightCyan { get { return namedColors["lightcyan"]; } }
+ public static Color LightGoldenrod { get { return namedColors["lightgoldenrod"]; } }
+ public static Color LightGray { get { return namedColors["lightgray"]; } }
+ public static Color LightGreen { get { return namedColors["lightgreen"]; } }
+ public static Color LightPink { get { return namedColors["lightpink"]; } }
+ public static Color LightSalmon { get { return namedColors["lightsalmon"]; } }
+ public static Color LightSeaGreen { get { return namedColors["lightseagreen"]; } }
+ public static Color LightSkyBlue { get { return namedColors["lightskyblue"]; } }
+ public static Color LightSlateGray { get { return namedColors["lightslategray"]; } }
+ public static Color LightSteelBlue { get { return namedColors["lightsteelblue"]; } }
+ public static Color LightYellow { get { return namedColors["lightyellow"]; } }
+ public static Color Lime { get { return namedColors["lime"]; } }
+ public static Color Limegreen { get { return namedColors["limegreen"]; } }
+ public static Color Linen { get { return namedColors["linen"]; } }
+ public static Color Magenta { get { return namedColors["magenta"]; } }
+ public static Color Maroon { get { return namedColors["maroon"]; } }
+ public static Color MediumAquamarine { get { return namedColors["mediumaquamarine"]; } }
+ public static Color MediumBlue { get { return namedColors["mediumblue"]; } }
+ public static Color MediumOrchid { get { return namedColors["mediumorchid"]; } }
+ public static Color MediumPurple { get { return namedColors["mediumpurple"]; } }
+ public static Color MediumSeaGreen { get { return namedColors["mediumseagreen"]; } }
+ public static Color MediumSlateBlue { get { return namedColors["mediumslateblue"]; } }
+ public static Color MediumSpringGreen { get { return namedColors["mediumspringgreen"]; } }
+ public static Color MediumTurquoise { get { return namedColors["mediumturquoise"]; } }
+ public static Color MediumVioletRed { get { return namedColors["mediumvioletred"]; } }
+ public static Color MidnightBlue { get { return namedColors["midnightblue"]; } }
+ public static Color MintCream { get { return namedColors["mintcream"]; } }
+ public static Color MistyRose { get { return namedColors["mistyrose"]; } }
+ public static Color Moccasin { get { return namedColors["moccasin"]; } }
+ public static Color NavajoWhite { get { return namedColors["navajowhite"]; } }
+ public static Color NavyBlue { get { return namedColors["navyblue"]; } }
+ public static Color OldLace { get { return namedColors["oldlace"]; } }
+ public static Color Olive { get { return namedColors["olive"]; } }
+ public static Color OliveDrab { get { return namedColors["olivedrab"]; } }
+ public static Color Orange { get { return namedColors["orange"]; } }
+ public static Color OrangeRed { get { return namedColors["orangered"]; } }
+ public static Color Orchid { get { return namedColors["orchid"]; } }
+ public static Color PaleGoldenrod { get { return namedColors["palegoldenrod"]; } }
+ public static Color PaleGreen { get { return namedColors["palegreen"]; } }
+ public static Color PaleTurquoise { get { return namedColors["paleturquoise"]; } }
+ public static Color PaleVioletRed { get { return namedColors["palevioletred"]; } }
+ public static Color PapayaWhip { get { return namedColors["papayawhip"]; } }
+ public static Color PeachPuff { get { return namedColors["peachpuff"]; } }
+ public static Color Peru { get { return namedColors["peru"]; } }
+ public static Color Pink { get { return namedColors["pink"]; } }
+ public static Color Plum { get { return namedColors["plum"]; } }
+ public static Color PowderBlue { get { return namedColors["powderblue"]; } }
+ public static Color Purple { get { return namedColors["purple"]; } }
+ public static Color RebeccaPurple { get { return namedColors["rebeccapurple"]; } }
+ public static Color Red { get { return namedColors["red"]; } }
+ public static Color RosyBrown { get { return namedColors["rosybrown"]; } }
+ public static Color RoyalBlue { get { return namedColors["royalblue"]; } }
+ public static Color SaddleBrown { get { return namedColors["saddlebrown"]; } }
+ public static Color Salmon { get { return namedColors["salmon"]; } }
+ public static Color SandyBrown { get { return namedColors["sandybrown"]; } }
+ public static Color SeaGreen { get { return namedColors["seagreen"]; } }
+ public static Color SeaShell { get { return namedColors["seashell"]; } }
+ public static Color Sienna { get { return namedColors["sienna"]; } }
+ public static Color Silver { get { return namedColors["silver"]; } }
+ public static Color SkyBlue { get { return namedColors["skyblue"]; } }
+ public static Color SlateBlue { get { return namedColors["slateblue"]; } }
+ public static Color SlateGray { get { return namedColors["slategray"]; } }
+ public static Color Snow { get { return namedColors["snow"]; } }
+ public static Color SpringGreen { get { return namedColors["springgreen"]; } }
+ public static Color SteelBlue { get { return namedColors["steelblue"]; } }
+ public static Color Tan { get { return namedColors["tan"]; } }
+ public static Color Teal { get { return namedColors["teal"]; } }
+ public static Color Thistle { get { return namedColors["thistle"]; } }
+ public static Color Tomato { get { return namedColors["tomato"]; } }
+ public static Color Transparent { get { return namedColors["transparent"]; } }
+ public static Color Turquoise { get { return namedColors["turquoise"]; } }
+ public static Color Violet { get { return namedColors["violet"]; } }
+ public static Color WebGreen { get { return namedColors["webgreen"]; } }
+ public static Color WebGray { get { return namedColors["webgray"]; } }
+ public static Color WebMaroon { get { return namedColors["webmaroon"]; } }
+ public static Color WebPurple { get { return namedColors["webpurple"]; } }
+ public static Color Wheat { get { return namedColors["wheat"]; } }
+ public static Color White { get { return namedColors["white"]; } }
+ public static Color WhiteSmoke { get { return namedColors["whitesmoke"]; } }
+ public static Color Yellow { get { return namedColors["yellow"]; } }
+ public static Color YellowGreen { get { return namedColors["yellowgreen"]; } }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
new file mode 100644
index 0000000000..edfe3464ec
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using System.Text;
+
+namespace Godot
+{
+ internal static class DebuggingUtils
+ {
+ internal static void AppendTypeName(this StringBuilder sb, Type type)
+ {
+ if (type.IsPrimitive)
+ sb.Append(type.Name);
+ else if (type == typeof(void))
+ sb.Append("void");
+ else
+ sb.Append(type);
+
+ sb.Append(" ");
+ }
+
+ public static void InstallTraceListener()
+ {
+ Trace.Listeners.Clear();
+ Trace.Listeners.Add(new GodotTraceListener());
+ }
+
+ public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber, out string methodDecl)
+ {
+ fileName = frame.GetFileName();
+ fileLineNumber = frame.GetFileLineNumber();
+
+ MethodBase methodBase = frame.GetMethod();
+
+ if (methodBase == null)
+ {
+ methodDecl = string.Empty;
+ return;
+ }
+
+ var sb = new StringBuilder();
+
+ if (methodBase is MethodInfo)
+ sb.AppendTypeName(((MethodInfo)methodBase).ReturnType);
+
+ sb.Append(methodBase.DeclaringType.FullName);
+ sb.Append(".");
+ sb.Append(methodBase.Name);
+
+ if (methodBase.IsGenericMethod)
+ {
+ Type[] genericParams = methodBase.GetGenericArguments();
+
+ sb.Append("<");
+
+ for (int j = 0; j < genericParams.Length; j++)
+ {
+ if (j > 0)
+ sb.Append(", ");
+
+ sb.AppendTypeName(genericParams[j]);
+ }
+
+ sb.Append(">");
+ }
+
+ sb.Append("(");
+
+ bool varArgs = (methodBase.CallingConvention & CallingConventions.VarArgs) != 0;
+
+ ParameterInfo[] parameter = methodBase.GetParameters();
+
+ for (int i = 0; i < parameter.Length; i++)
+ {
+ if (i > 0)
+ sb.Append(", ");
+
+ if (i == parameter.Length - 1 && varArgs)
+ sb.Append("params ");
+
+ sb.AppendTypeName(parameter[i].ParameterType);
+ }
+
+ sb.Append(")");
+
+ methodDecl = sb.ToString();
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
new file mode 100644
index 0000000000..d72109de92
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -0,0 +1,469 @@
+using System;
+using System.Collections.Generic;
+using System.Collections;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Godot.Collections
+{
+ class DictionarySafeHandle : SafeHandle
+ {
+ public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
+ {
+ this.handle = handle;
+ }
+
+ public override bool IsInvalid
+ {
+ get
+ {
+ return handle == IntPtr.Zero;
+ }
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Dictionary.godot_icall_Dictionary_Dtor(handle);
+ return true;
+ }
+ }
+
+ public class Dictionary :
+ IDictionary,
+ IDisposable
+ {
+ DictionarySafeHandle safeHandle;
+ bool disposed = false;
+
+ public Dictionary()
+ {
+ safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
+ }
+
+ public Dictionary(IDictionary dictionary) : this()
+ {
+ if (dictionary == null)
+ throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
+
+ MarshalUtils.IDictionaryToDictionary(dictionary, GetPtr());
+ }
+
+ internal Dictionary(DictionarySafeHandle handle)
+ {
+ safeHandle = handle;
+ }
+
+ internal Dictionary(IntPtr handle)
+ {
+ safeHandle = new DictionarySafeHandle(handle);
+ }
+
+ internal IntPtr GetPtr()
+ {
+ if (disposed)
+ throw new ObjectDisposedException(GetType().FullName);
+
+ return safeHandle.DangerousGetHandle();
+ }
+
+ public void Dispose()
+ {
+ if (disposed)
+ return;
+
+ if (safeHandle != null)
+ {
+ safeHandle.Dispose();
+ safeHandle = null;
+ }
+
+ disposed = true;
+ }
+
+ public Dictionary Duplicate(bool deep = false)
+ {
+ return new Dictionary(godot_icall_Dictionary_Duplicate(GetPtr(), deep));
+ }
+
+ // IDictionary
+
+ public ICollection Keys
+ {
+ get
+ {
+ IntPtr handle = godot_icall_Dictionary_Keys(GetPtr());
+ return new Array(new ArraySafeHandle(handle));
+ }
+ }
+
+ public ICollection Values
+ {
+ get
+ {
+ IntPtr handle = godot_icall_Dictionary_Values(GetPtr());
+ return new Array(new ArraySafeHandle(handle));
+ }
+ }
+
+ public bool IsFixedSize => false;
+
+ public bool IsReadOnly => false;
+
+ public object this[object key]
+ {
+ get => godot_icall_Dictionary_GetValue(GetPtr(), key);
+ set => godot_icall_Dictionary_SetValue(GetPtr(), key, value);
+ }
+
+ public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value);
+
+ public void Clear() => godot_icall_Dictionary_Clear(GetPtr());
+
+ public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key);
+
+ public IDictionaryEnumerator GetEnumerator() => new DictionaryEnumerator(this);
+
+ public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+
+ // ICollection
+
+ public object SyncRoot => this;
+
+ public bool IsSynchronized => false;
+
+ public int Count => godot_icall_Dictionary_Count(GetPtr());
+
+ public void CopyTo(System.Array array, int index)
+ {
+ // TODO Can be done with single internal call
+
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (index < 0)
+ throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
+
+ Array keys = (Array)Keys;
+ Array values = (Array)Values;
+ int count = Count;
+
+ if (array.Length < (index + count))
+ throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+
+ for (int i = 0; i < count; i++)
+ {
+ array.SetValue(new DictionaryEntry(keys[i], values[i]), index);
+ index++;
+ }
+ }
+
+ // IEnumerable
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ private class DictionaryEnumerator : IDictionaryEnumerator
+ {
+ Array keys;
+ Array values;
+ int count;
+ int index = -1;
+
+ public DictionaryEnumerator(Dictionary dictionary)
+ {
+ // TODO 3 internal calls, can reduce to 1
+ keys = (Array)dictionary.Keys;
+ values = (Array)dictionary.Values;
+ count = dictionary.Count;
+ }
+
+ public object Current => Entry;
+
+ public DictionaryEntry Entry =>
+ // TODO 2 internal calls, can reduce to 1
+ new DictionaryEntry(keys[index], values[index]);
+
+ public object Key => Entry.Key;
+
+ public object Value => Entry.Value;
+
+ public bool MoveNext()
+ {
+ index++;
+ return index < count;
+ }
+
+ public void Reset()
+ {
+ index = -1;
+ }
+ }
+
+ public override string ToString()
+ {
+ return godot_icall_Dictionary_ToString(GetPtr());
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_Dictionary_Ctor();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Dictionary_Dtor(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static object godot_icall_Dictionary_GetValue(IntPtr ptr, object key);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_Dictionary_Count(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_Dictionary_Duplicate(IntPtr ptr, bool deep);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_Dictionary_ToString(IntPtr ptr);
+ }
+
+ public class Dictionary<TKey, TValue> :
+ IDictionary<TKey, TValue>
+ {
+ Dictionary objectDict;
+
+ internal static int valTypeEncoding;
+ internal static IntPtr valTypeClass;
+
+ static Dictionary()
+ {
+ Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass);
+ }
+
+ public Dictionary()
+ {
+ objectDict = new Dictionary();
+ }
+
+ public Dictionary(IDictionary<TKey, TValue> dictionary)
+ {
+ objectDict = new Dictionary();
+
+ if (dictionary == null)
+ throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
+
+ // TODO: Can be optimized
+
+ IntPtr godotDictionaryPtr = GetPtr();
+
+ foreach (KeyValuePair<TKey, TValue> entry in dictionary)
+ {
+ Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
+ }
+ }
+
+ public Dictionary(Dictionary dictionary)
+ {
+ objectDict = dictionary;
+ }
+
+ internal Dictionary(IntPtr handle)
+ {
+ objectDict = new Dictionary(handle);
+ }
+
+ internal Dictionary(DictionarySafeHandle handle)
+ {
+ objectDict = new Dictionary(handle);
+ }
+
+ public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
+ {
+ return from.objectDict;
+ }
+
+ internal IntPtr GetPtr()
+ {
+ return objectDict.GetPtr();
+ }
+
+ public Dictionary<TKey, TValue> Duplicate(bool deep = false)
+ {
+ return new Dictionary<TKey, TValue>(objectDict.Duplicate(deep));
+ }
+
+ // IDictionary<TKey, TValue>
+
+ public TValue this[TKey key]
+ {
+ get
+ {
+ return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass);
+ }
+ set
+ {
+ objectDict[key] = value;
+ }
+ }
+
+ public ICollection<TKey> Keys
+ {
+ get
+ {
+ IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(objectDict.GetPtr());
+ return new Array<TKey>(new ArraySafeHandle(handle));
+ }
+ }
+
+ public ICollection<TValue> Values
+ {
+ get
+ {
+ IntPtr handle = Dictionary.godot_icall_Dictionary_Values(objectDict.GetPtr());
+ return new Array<TValue>(new ArraySafeHandle(handle));
+ }
+ }
+
+ public void Add(TKey key, TValue value)
+ {
+ objectDict.Add(key, value);
+ }
+
+ public bool ContainsKey(TKey key)
+ {
+ return objectDict.Contains(key);
+ }
+
+ public bool Remove(TKey key)
+ {
+ return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ object retValue;
+ bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass);
+ value = found ? (TValue)retValue : default(TValue);
+ return found;
+ }
+
+ // ICollection<KeyValuePair<TKey, TValue>>
+
+ public int Count
+ {
+ get
+ {
+ return objectDict.Count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return objectDict.IsReadOnly;
+ }
+ }
+
+ public void Add(KeyValuePair<TKey, TValue> item)
+ {
+ objectDict.Add(item.Key, item.Value);
+ }
+
+ public void Clear()
+ {
+ objectDict.Clear();
+ }
+
+ public bool Contains(KeyValuePair<TKey, TValue> item)
+ {
+ return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
+ }
+
+ public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+
+ // TODO 3 internal calls, can reduce to 1
+ Array<TKey> keys = (Array<TKey>)Keys;
+ Array<TValue> values = (Array<TValue>)Values;
+ int count = Count;
+
+ if (array.Length < (arrayIndex + count))
+ throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+
+ for (int i = 0; i < count; i++)
+ {
+ // TODO 2 internal calls, can reduce to 1
+ array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]);
+ arrayIndex++;
+ }
+ }
+
+ public bool Remove(KeyValuePair<TKey, TValue> item)
+ {
+ return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); ;
+ }
+
+ // IEnumerable<KeyValuePair<TKey, TValue>>
+
+ public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+ {
+ // TODO 3 internal calls, can reduce to 1
+ Array<TKey> keys = (Array<TKey>)Keys;
+ Array<TValue> values = (Array<TValue>)Values;
+ int count = Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ // TODO 2 internal calls, can reduce to 1
+ yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]);
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public override string ToString() => objectDict.ToString();
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
new file mode 100644
index 0000000000..072e0f20ff
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
@@ -0,0 +1,13 @@
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public static class Dispatcher
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern GodotTaskScheduler godot_icall_DefaultGodotTaskScheduler();
+
+ public static GodotSynchronizationContext SynchronizationContext =>
+ godot_icall_DefaultGodotTaskScheduler().Context;
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs
new file mode 100644
index 0000000000..a0f105d55e
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs
@@ -0,0 +1,213 @@
+
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq.Expressions;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ /// <summary>
+ /// Represents an <see cref="Godot.Object"/> whose members can be dynamically accessed at runtime through the Variant API.
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// The <see cref="Godot.DynamicGodotObject"/> class enables access to the Variant
+ /// members of a <see cref="Godot.Object"/> instance at runtime.
+ /// </para>
+ /// <para>
+ /// This allows accessing the class members using their original names in the engine as well as the members from the
+ /// script attached to the <see cref="Godot.Object"/>, regardless of the scripting language it was written in.
+ /// </para>
+ /// </remarks>
+ /// <example>
+ /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Godot.Object"/>.
+ /// <code>
+ /// dynamic sprite = GetNode("Sprite").DynamicGodotObject;
+ /// sprite.add_child(this);
+ ///
+ /// if ((sprite.hframes * sprite.vframes) &gt; 0)
+ /// sprite.frame = 0;
+ /// </code>
+ /// </example>
+ /// <example>
+ /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the members of the script attached to a <see cref="Godot.Object"/>.
+ /// <code>
+ /// dynamic childNode = GetNode("ChildNode").DynamicGodotObject;
+ ///
+ /// if (childNode.print_allowed)
+ /// {
+ /// childNode.message = "Hello from C#";
+ /// childNode.print_message(3);
+ /// }
+ /// </code>
+ /// The <c>ChildNode</c> node has the following GDScript script attached:
+ /// <code>
+ /// // # ChildNode.gd
+ /// // var print_allowed = true
+ /// // var message = ""
+ /// //
+ /// // func print_message(times):
+ /// // for i in times:
+ /// // print(message)
+ /// </code>
+ /// </example>
+ public class DynamicGodotObject : DynamicObject
+ {
+ /// <summary>
+ /// Gets the <see cref="Godot.Object"/> associated with this <see cref="Godot.DynamicGodotObject"/>.
+ /// </summary>
+ public Object Value { get; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Godot.DynamicGodotObject"/> class.
+ /// </summary>
+ /// <param name="godotObject">
+ /// The <see cref="Godot.Object"/> that will be associated with this <see cref="Godot.DynamicGodotObject"/>.
+ /// </param>
+ /// <exception cref="System.ArgumentNullException">
+ /// Thrown when the <paramref name="godotObject"/> parameter is null.
+ /// </exception>
+ public DynamicGodotObject(Object godotObject)
+ {
+ if (godotObject == null)
+ throw new ArgumentNullException(nameof(godotObject));
+
+ this.Value = godotObject;
+ }
+
+ public override IEnumerable<string> GetDynamicMemberNames()
+ {
+ return godot_icall_DynamicGodotObject_SetMemberList(Object.GetPtr(Value));
+ }
+
+ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
+ {
+ switch (binder.Operation)
+ {
+ case ExpressionType.Equal:
+ case ExpressionType.NotEqual:
+ if (binder.ReturnType == typeof(bool) || binder.ReturnType.IsAssignableFrom(typeof(bool)))
+ {
+ if (arg == null)
+ {
+ bool boolResult = Object.IsInstanceValid(Value);
+
+ if (binder.Operation == ExpressionType.Equal)
+ boolResult = !boolResult;
+
+ result = boolResult;
+ return true;
+ }
+
+ if (arg is Object other)
+ {
+ bool boolResult = (Value == other);
+
+ if (binder.Operation == ExpressionType.NotEqual)
+ boolResult = !boolResult;
+
+ result = boolResult;
+ return true;
+ }
+ }
+
+ break;
+ default:
+ // We're not implementing operators <, <=, >, and >= (LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual).
+ // These are used on the actual pointers in variant_op.cpp. It's better to let the user do that explicitly.
+ break;
+ }
+
+ return base.TryBinaryOperation(binder, arg, out result);
+ }
+
+ public override bool TryConvert(ConvertBinder binder, out object result)
+ {
+ if (binder.Type == typeof(Object))
+ {
+ result = Value;
+ return true;
+ }
+
+ if (typeof(Object).IsAssignableFrom(binder.Type))
+ {
+ // Throws InvalidCastException when the cast fails
+ result = Convert.ChangeType(Value, binder.Type);
+ return true;
+ }
+
+ return base.TryConvert(binder, out result);
+ }
+
+ public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
+ {
+ if (indexes.Length == 1)
+ {
+ if (indexes[0] is string name)
+ {
+ return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), name, out result);
+ }
+ }
+
+ return base.TryGetIndex(binder, indexes, out result);
+ }
+
+ public override bool TryGetMember(GetMemberBinder binder, out object result)
+ {
+ return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), binder.Name, out result);
+ }
+
+ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
+ {
+ return godot_icall_DynamicGodotObject_InvokeMember(Object.GetPtr(Value), binder.Name, args, out result);
+ }
+
+ public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
+ {
+ if (indexes.Length == 1)
+ {
+ if (indexes[0] is string name)
+ {
+ return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), name, value);
+ }
+ }
+
+ return base.TrySetIndex(binder, indexes, value);
+ }
+
+ public override bool TrySetMember(SetMemberBinder binder, object value)
+ {
+ return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), binder.Name, value);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string[] godot_icall_DynamicGodotObject_SetMemberList(IntPtr godotObject);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_InvokeMember(IntPtr godotObject, string name, object[] args, out object result);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_GetMember(IntPtr godotObject, string name, out object result);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_SetMember(IntPtr godotObject, string name, object value);
+
+ #region We don't override these methods
+
+ // Looks like this is not usable from C#
+ //public override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result);
+
+ // Object members cannot be deleted
+ //public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes);
+ //public override bool TryDeleteMember(DeleteMemberBinder binder);
+
+ // Invocation on the object itself, e.g.: obj(param)
+ //public override bool TryInvoke(InvokeBinder binder, object[] args, out object result);
+
+ // No unnary operations to handle
+ //public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result);
+
+ #endregion
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
new file mode 100644
index 0000000000..5d16260f5d
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
@@ -0,0 +1,45 @@
+namespace Godot
+{
+ public partial class Node
+ {
+ public T GetNode<T>(NodePath path) where T : class
+ {
+ return (T)(object)GetNode(path);
+ }
+
+ public T GetNodeOrNull<T>(NodePath path) where T : class
+ {
+ return GetNodeOrNull(path) as T;
+ }
+
+ public T GetChild<T>(int idx) where T : class
+ {
+ return (T)(object)GetChild(idx);
+ }
+
+ public T GetChildOrNull<T>(int idx) where T : class
+ {
+ return GetChild(idx) as T;
+ }
+
+ public T GetOwner<T>() where T : class
+ {
+ return (T)(object)Owner;
+ }
+
+ public T GetOwnerOrNull<T>() where T : class
+ {
+ return Owner as T;
+ }
+
+ public T GetParent<T>() where T : class
+ {
+ return (T)(object)GetParent();
+ }
+
+ public T GetParentOrNull<T>() where T : class
+ {
+ return GetParent() as T;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs
new file mode 100644
index 0000000000..9ef0959750
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public partial class Object
+ {
+ public static bool IsInstanceValid(Object instance)
+ {
+ return instance != null && instance.NativeInstance != IntPtr.Zero;
+ }
+
+ public static WeakRef WeakRef(Object obj)
+ {
+ return godot_icall_Object_weakref(Object.GetPtr(obj));
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static WeakRef godot_icall_Object_weakref(IntPtr obj);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
new file mode 100644
index 0000000000..684d160b57
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
@@ -0,0 +1,10 @@
+namespace Godot
+{
+ public static partial class ResourceLoader
+ {
+ public static T Load<T>(string path) where T : class
+ {
+ return (T)(object)Load(path);
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
new file mode 100644
index 0000000000..19962d418a
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -0,0 +1,266 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+// TODO: Add comments describing what this class does. It is not obvious.
+
+namespace Godot
+{
+ public static partial class GD
+ {
+ public static object Bytes2Var(byte[] bytes, bool allow_objects = false)
+ {
+ return godot_icall_GD_bytes2var(bytes, allow_objects);
+ }
+
+ public static object Convert(object what, Variant.Type type)
+ {
+ return godot_icall_GD_convert(what, type);
+ }
+
+ public static real_t Db2Linear(real_t db)
+ {
+ return (real_t)Math.Exp(db * 0.11512925464970228420089957273422);
+ }
+
+ public static real_t DecTime(real_t value, real_t amount, real_t step)
+ {
+ real_t sgn = Mathf.Sign(value);
+ real_t val = Mathf.Abs(value);
+ val -= amount * step;
+ if (val < 0)
+ val = 0;
+ 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 godot_icall_GD_hash(var);
+ }
+
+ public static Object InstanceFromId(ulong instanceId)
+ {
+ return godot_icall_GD_instance_from_id(instanceId);
+ }
+
+ public static real_t Linear2Db(real_t linear)
+ {
+ return (real_t)(Math.Log(linear) * 8.6858896380650365530225783783321);
+ }
+
+ public static Resource Load(string path)
+ {
+ return ResourceLoader.Load(path);
+ }
+
+ public static T Load<T>(string path) where T : class
+ {
+ return ResourceLoader.Load<T>(path);
+ }
+
+ public static void PushError(string message)
+ {
+ godot_icall_GD_pusherror(message);
+ }
+
+ public static void PushWarning(string message)
+ {
+ godot_icall_GD_pushwarning(message);
+ }
+
+ public static void Print(params object[] what)
+ {
+ godot_icall_GD_print(Array.ConvertAll(what, x => x.ToString()));
+ }
+
+ public static void PrintStack()
+ {
+ Print(System.Environment.StackTrace);
+ }
+
+ public static void PrintErr(params object[] what)
+ {
+ godot_icall_GD_printerr(Array.ConvertAll(what, x => x?.ToString()));
+ }
+
+ public static void PrintRaw(params object[] what)
+ {
+ godot_icall_GD_printraw(Array.ConvertAll(what, x => x?.ToString()));
+ }
+
+ public static void PrintS(params object[] what)
+ {
+ godot_icall_GD_prints(Array.ConvertAll(what, x => x?.ToString()));
+ }
+
+ public static void PrintT(params object[] what)
+ {
+ godot_icall_GD_printt(Array.ConvertAll(what, x => x?.ToString()));
+ }
+
+ public static float Randf()
+ {
+ return godot_icall_GD_randf();
+ }
+
+ public static uint Randi()
+ {
+ return godot_icall_GD_randi();
+ }
+
+ public static void Randomize()
+ {
+ godot_icall_GD_randomize();
+ }
+
+ public static double RandRange(double from, double to)
+ {
+ return godot_icall_GD_rand_range(from, to);
+ }
+
+ public static uint RandSeed(ulong seed, out ulong newSeed)
+ {
+ return godot_icall_GD_rand_seed(seed, out newSeed);
+ }
+
+ public static IEnumerable<int> Range(int end)
+ {
+ return Range(0, end, 1);
+ }
+
+ public static IEnumerable<int> Range(int start, int end)
+ {
+ return Range(start, end, 1);
+ }
+
+ public static IEnumerable<int> Range(int start, int end, int step)
+ {
+ if (end < start && step > 0)
+ yield break;
+
+ if (end > start && step < 0)
+ yield break;
+
+ if (step > 0)
+ {
+ for (int i = start; i < end; i += step)
+ yield return i;
+ }
+ else
+ {
+ for (int i = start; i > end; i += step)
+ yield return i;
+ }
+ }
+
+ public static void Seed(ulong seed)
+ {
+ godot_icall_GD_seed(seed);
+ }
+
+ public static string Str(params object[] what)
+ {
+ return godot_icall_GD_str(what);
+ }
+
+ public static object Str2Var(string str)
+ {
+ return godot_icall_GD_str2var(str);
+ }
+
+ public static bool TypeExists(string type)
+ {
+ return godot_icall_GD_type_exists(type);
+ }
+
+ public static byte[] Var2Bytes(object var, bool full_objects = false)
+ {
+ return godot_icall_GD_var2bytes(var, full_objects);
+ }
+
+ public static string Var2Str(object var)
+ {
+ return godot_icall_GD_var2str(var);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static object godot_icall_GD_bytes2var(byte[] bytes, bool allow_objects);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static object godot_icall_GD_convert(object what, Variant.Type type);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_GD_hash(object var);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static Object godot_icall_GD_instance_from_id(ulong instance_id);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_print(object[] what);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_printerr(object[] what);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_printraw(object[] what);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_prints(object[] what);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_printt(object[] what);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static float godot_icall_GD_randf();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static uint godot_icall_GD_randi();
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_randomize();
+
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static double godot_icall_GD_rand_range(double from, double to);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_seed(ulong seed);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_GD_str(object[] what);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static object godot_icall_GD_str2var(string str);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_GD_type_exists(string type);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static byte[] godot_icall_GD_var2bytes(object what, bool full_objects);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_GD_var2str(object var);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_pusherror(string type);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_GD_pushwarning(string type);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
new file mode 100644
index 0000000000..4b5e3f8761
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotSynchronizationContext.cs
@@ -0,0 +1,24 @@
+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()
+ {
+ while (_queue.TryTake(out var workItem))
+ {
+ workItem.Key(workItem.Value);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
new file mode 100644
index 0000000000..8eaeea50dc
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTaskScheduler.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Godot
+{
+ public class GodotTaskScheduler : TaskScheduler
+ {
+ internal GodotSynchronizationContext Context { get; }
+ private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
+
+ public GodotTaskScheduler()
+ {
+ Context = new GodotSynchronizationContext();
+ SynchronizationContext.SetSynchronizationContext(Context);
+ }
+
+ 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 TryExecuteTask(task);
+ }
+
+ protected sealed override bool TryDequeue(Task task)
+ {
+ lock (_tasks)
+ {
+ return _tasks.Remove(task);
+ }
+ }
+
+ protected sealed override IEnumerable<Task> GetScheduledTasks()
+ {
+ lock (_tasks)
+ {
+ foreach (Task task in _tasks)
+ yield return task;
+ }
+ }
+
+ public void Activate()
+ {
+ 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/GodotSharp/GodotSharp/Core/GodotTraceListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs
new file mode 100644
index 0000000000..f1a00ae0fa
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Diagnostics;
+
+namespace Godot
+{
+ internal class GodotTraceListener : TraceListener
+ {
+ public override void Write(string message)
+ {
+ GD.PrintRaw(message);
+ }
+
+ public override void WriteLine(string message)
+ {
+ GD.Print(message);
+ }
+
+ public override void Fail(string message, string detailMessage)
+ {
+ GD.PrintErr("Assertion failed: ", message);
+ if (detailMessage != null)
+ {
+ GD.PrintErr(" Details: ", detailMessage);
+ }
+
+ try
+ {
+ var stackTrace = new StackTrace(true).ToString();
+ GD.PrintErr(stackTrace);
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaitable.cs
new file mode 100644
index 0000000000..0397957d00
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/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/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs
new file mode 100644
index 0000000000..d3be9d781c
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/IAwaiter.cs
@@ -0,0 +1,18 @@
+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/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
new file mode 100644
index 0000000000..c3fa2f3e82
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Interfaces/ISerializationListener.cs
@@ -0,0 +1,8 @@
+namespace Godot
+{
+ public interface ISerializationListener
+ {
+ void OnBeforeSerialize();
+ void OnAfterDeserialize();
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
new file mode 100644
index 0000000000..a1d63a62ef
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
@@ -0,0 +1,212 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Godot
+{
+ using Array = Godot.Collections.Array;
+ using Dictionary = Godot.Collections.Dictionary;
+
+ static class MarshalUtils
+ {
+ /// <summary>
+ /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
+ /// is <see cref="Godot.Collections.Array{T}"/>; otherwise returns <see langword="false"/>.
+ /// </summary>
+ /// <exception cref="System.InvalidOperationException">
+ /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
+ /// </exception>
+ static bool TypeIsGenericArray(Type type)
+ {
+ return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Array<>);
+ }
+
+ /// <summary>
+ /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
+ /// is <see cref="Godot.Collections.Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>.
+ /// </summary>
+ /// <exception cref="System.InvalidOperationException">
+ /// <paramref name="type"/> is not a generic type. That is, IsGenericType returns false.
+ /// </exception>
+ static bool TypeIsGenericDictionary(Type type)
+ {
+ return type.GetGenericTypeDefinition() == typeof(Godot.Collections.Dictionary<,>);
+ }
+
+ static void ArrayGetElementType(Type arrayType, out Type elementType)
+ {
+ elementType = arrayType.GetGenericArguments()[0];
+ }
+
+ static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
+ {
+ var genericArgs = dictionaryType.GetGenericArguments();
+ keyType = genericArgs[0];
+ valueType = genericArgs[1];
+ }
+
+ static bool GenericIEnumerableIsAssignableFromType(Type type)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ return true;
+
+ foreach (var interfaceType in type.GetInterfaces())
+ {
+ if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ return true;
+ }
+
+ Type baseType = type.BaseType;
+
+ if (baseType == null)
+ return false;
+
+ return GenericIEnumerableIsAssignableFromType(baseType);
+ }
+
+ static bool GenericIDictionaryIsAssignableFromType(Type type)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+ return true;
+
+ foreach (var interfaceType in type.GetInterfaces())
+ {
+ if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+ return true;
+ }
+
+ Type baseType = type.BaseType;
+
+ if (baseType == null)
+ return false;
+
+ return GenericIDictionaryIsAssignableFromType(baseType);
+ }
+
+ static bool GenericIEnumerableIsAssignableFromType(Type type, out Type elementType)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ {
+ elementType = type.GetGenericArguments()[0];
+ return true;
+ }
+
+ foreach (var interfaceType in type.GetInterfaces())
+ {
+ if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ {
+ elementType = interfaceType.GetGenericArguments()[0];
+ return true;
+ }
+ }
+
+ Type baseType = type.BaseType;
+
+ if (baseType == null)
+ {
+ elementType = null;
+ return false;
+ }
+
+ return GenericIEnumerableIsAssignableFromType(baseType, out elementType);
+ }
+
+ static bool GenericIDictionaryIsAssignableFromType(Type type, out Type keyType, out Type valueType)
+ {
+ if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+ {
+ var genericArgs = type.GetGenericArguments();
+ keyType = genericArgs[0];
+ valueType = genericArgs[1];
+ return true;
+ }
+
+ foreach (var interfaceType in type.GetInterfaces())
+ {
+ if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
+ {
+ var genericArgs = interfaceType.GetGenericArguments();
+ keyType = genericArgs[0];
+ valueType = genericArgs[1];
+ return true;
+ }
+ }
+
+ Type baseType = type.BaseType;
+
+ if (baseType == null)
+ {
+ keyType = null;
+ valueType = null;
+ return false;
+ }
+
+ return GenericIDictionaryIsAssignableFromType(baseType, out keyType, out valueType);
+ }
+
+ static Type MakeGenericArrayType(Type elemType)
+ {
+ return typeof(Godot.Collections.Array<>).MakeGenericType(elemType);
+ }
+
+ static Type MakeGenericDictionaryType(Type keyType, Type valueType)
+ {
+ return typeof(Godot.Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
+ }
+
+ // TODO Add support for IEnumerable<T> and IDictionary<TKey, TValue>
+ // TODO: EnumerableToArray and IDictionaryToDictionary can be optimized
+
+ internal static void EnumerableToArray(IEnumerable enumerable, IntPtr godotArrayPtr)
+ {
+ if (enumerable is ICollection collection)
+ {
+ int count = collection.Count;
+
+ object[] tempArray = new object[count];
+ collection.CopyTo(tempArray, 0);
+
+ for (int i = 0; i < count; i++)
+ {
+ Array.godot_icall_Array_Add(godotArrayPtr, tempArray[i]);
+ }
+ }
+ else
+ {
+ foreach (object element in enumerable)
+ {
+ Array.godot_icall_Array_Add(godotArrayPtr, element);
+ }
+ }
+ }
+
+ internal static void IDictionaryToDictionary(IDictionary dictionary, IntPtr godotDictionaryPtr)
+ {
+ foreach (DictionaryEntry entry in dictionary)
+ {
+ Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
+ }
+ }
+
+ internal static void GenericIDictionaryToDictionary(object dictionary, IntPtr godotDictionaryPtr)
+ {
+#if DEBUG
+ if (!GenericIDictionaryIsAssignableFromType(dictionary.GetType()))
+ throw new InvalidOperationException("The type does not implement IDictionary<,>");
+#endif
+
+ // TODO: Can we optimize this?
+
+ var keys = ((IEnumerable)dictionary.GetType().GetProperty("Keys").GetValue(dictionary)).GetEnumerator();
+ var values = ((IEnumerable)dictionary.GetType().GetProperty("Values").GetValue(dictionary)).GetEnumerator();
+
+ while (keys.MoveNext() && values.MoveNext())
+ {
+ object key = keys.Current;
+ object value = values.Current;
+
+ Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, key, value);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
new file mode 100644
index 0000000000..ddfed180b5
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -0,0 +1,361 @@
+using System;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ public static partial class Mathf
+ {
+ // Define constants with Decimal precision and cast down to double or float.
+
+ public const real_t Tau = (real_t) 6.2831853071795864769252867666M; // 6.2831855f and 6.28318530717959
+ public const real_t Pi = (real_t) 3.1415926535897932384626433833M; // 3.1415927f and 3.14159265358979
+ public const real_t Inf = real_t.PositiveInfinity;
+ public const real_t NaN = real_t.NaN;
+
+ private const real_t Deg2RadConst = (real_t) 0.0174532925199432957692369077M; // 0.0174532924f and 0.0174532925199433
+ private const real_t Rad2DegConst = (real_t) 57.295779513082320876798154814M; // 57.29578f and 57.2957795130823
+
+ public static int Abs(int s)
+ {
+ return Math.Abs(s);
+ }
+
+ public static real_t Abs(real_t s)
+ {
+ return Math.Abs(s);
+ }
+
+ public static real_t Acos(real_t s)
+ {
+ return (real_t)Math.Acos(s);
+ }
+
+ public static real_t Asin(real_t s)
+ {
+ return (real_t)Math.Asin(s);
+ }
+
+ public static real_t Atan(real_t s)
+ {
+ return (real_t)Math.Atan(s);
+ }
+
+ public static real_t Atan2(real_t y, real_t x)
+ {
+ return (real_t)Math.Atan2(y, x);
+ }
+
+ public static Vector2 Cartesian2Polar(real_t x, real_t y)
+ {
+ return new Vector2(Sqrt(x * x + y * y), Atan2(y, x));
+ }
+
+ public static real_t Ceil(real_t s)
+ {
+ return (real_t)Math.Ceiling(s);
+ }
+
+ public static int Clamp(int value, int min, int max)
+ {
+ return value < min ? min : value > max ? max : value;
+ }
+
+ public static real_t Clamp(real_t value, real_t min, real_t max)
+ {
+ return value < min ? min : value > max ? max : value;
+ }
+
+ public static real_t Cos(real_t s)
+ {
+ return (real_t)Math.Cos(s);
+ }
+
+ public static real_t Cosh(real_t s)
+ {
+ return (real_t)Math.Cosh(s);
+ }
+
+ public static real_t Deg2Rad(real_t deg)
+ {
+ return deg * Deg2RadConst;
+ }
+
+ public static real_t Ease(real_t s, real_t 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);
+ }
+
+ 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 real_t Exp(real_t s)
+ {
+ return (real_t)Math.Exp(s);
+ }
+
+ public static real_t Floor(real_t s)
+ {
+ return (real_t)Math.Floor(s);
+ }
+
+ public static real_t InverseLerp(real_t from, real_t to, real_t weight)
+ {
+ return (weight - from) / (to - from);
+ }
+
+ public static bool IsEqualApprox(real_t a, real_t b)
+ {
+ // Check for exact equality first, required to handle "infinity" values.
+ if (a == b)
+ {
+ return true;
+ }
+ // Then check for approximate equality.
+ real_t tolerance = Epsilon * Abs(a);
+ if (tolerance < Epsilon)
+ {
+ tolerance = Epsilon;
+ }
+ return Abs(a - b) < tolerance;
+ }
+
+ public static bool IsInf(real_t s)
+ {
+ return real_t.IsInfinity(s);
+ }
+
+ public static bool IsNaN(real_t s)
+ {
+ return real_t.IsNaN(s);
+ }
+
+ public static bool IsZeroApprox(real_t s)
+ {
+ return Abs(s) < Epsilon;
+ }
+
+ public static real_t Lerp(real_t from, real_t to, real_t weight)
+ {
+ return from + (to - from) * weight;
+ }
+
+ public static real_t LerpAngle(real_t from, real_t to, real_t weight)
+ {
+ real_t difference = (to - from) % Mathf.Tau;
+ real_t distance = ((2 * difference) % Mathf.Tau) - difference;
+ return from + distance * weight;
+ }
+
+ public static real_t Log(real_t s)
+ {
+ return (real_t)Math.Log(s);
+ }
+
+ public static int Max(int a, int b)
+ {
+ return a > b ? a : b;
+ }
+
+ public static real_t Max(real_t a, real_t b)
+ {
+ return a > b ? a : b;
+ }
+
+ public static int Min(int a, int b)
+ {
+ return a < b ? a : b;
+ }
+
+ public static real_t Min(real_t a, real_t b)
+ {
+ return a < b ? a : b;
+ }
+
+ public static real_t MoveToward(real_t from, real_t to, real_t delta)
+ {
+ return Abs(to - from) <= delta ? to : from + Sign(to - from) * delta;
+ }
+
+ public static int NearestPo2(int value)
+ {
+ value--;
+ value |= value >> 1;
+ value |= value >> 2;
+ value |= value >> 4;
+ value |= value >> 8;
+ value |= value >> 16;
+ value++;
+ return value;
+ }
+
+ public static Vector2 Polar2Cartesian(real_t r, real_t th)
+ {
+ return new Vector2(r * Cos(th), r * Sin(th));
+ }
+
+ /// <summary>
+ /// Performs a canonical Modulus operation, where the output is on the range [0, b).
+ /// </summary>
+ public static int PosMod(int a, int b)
+ {
+ int c = a % b;
+ if ((c < 0 && b > 0) || (c > 0 && b < 0))
+ {
+ c += b;
+ }
+ return c;
+ }
+
+ /// <summary>
+ /// Performs a canonical Modulus operation, where the output is on the range [0, b).
+ /// </summary>
+ public static real_t PosMod(real_t a, real_t b)
+ {
+ real_t c = a % b;
+ if ((c < 0 && b > 0) || (c > 0 && b < 0))
+ {
+ c += b;
+ }
+ return c;
+ }
+
+ public static real_t Pow(real_t x, real_t y)
+ {
+ return (real_t)Math.Pow(x, y);
+ }
+
+ public static real_t Rad2Deg(real_t rad)
+ {
+ return rad * Rad2DegConst;
+ }
+
+ public static real_t Round(real_t s)
+ {
+ return (real_t)Math.Round(s);
+ }
+
+ public static int Sign(int s)
+ {
+ if (s == 0) return 0;
+ return s < 0 ? -1 : 1;
+ }
+
+ public static int Sign(real_t s)
+ {
+ if (s == 0) return 0;
+ return s < 0 ? -1 : 1;
+ }
+
+ public static real_t Sin(real_t s)
+ {
+ return (real_t)Math.Sin(s);
+ }
+
+ public static real_t Sinh(real_t s)
+ {
+ return (real_t)Math.Sinh(s);
+ }
+
+ public static real_t SmoothStep(real_t from, real_t to, real_t weight)
+ {
+ if (IsEqualApprox(from, to))
+ {
+ return from;
+ }
+ real_t x = Clamp((weight - from) / (to - from), (real_t)0.0, (real_t)1.0);
+ return x * x * (3 - 2 * x);
+ }
+
+ public static real_t Sqrt(real_t s)
+ {
+ return (real_t)Math.Sqrt(s);
+ }
+
+ public static int StepDecimals(real_t step)
+ {
+ double[] sd = new double[] {
+ 0.9999,
+ 0.09999,
+ 0.009999,
+ 0.0009999,
+ 0.00009999,
+ 0.000009999,
+ 0.0000009999,
+ 0.00000009999,
+ 0.000000009999,
+ };
+ double abs = Mathf.Abs(step);
+ double decs = abs - (int)abs; // Strip away integer part
+ for (int i = 0; i < sd.Length; i++)
+ {
+ if (decs >= sd[i])
+ {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ public static real_t Stepify(real_t s, real_t step)
+ {
+ if (step != 0f)
+ {
+ s = Floor(s / step + 0.5f) * step;
+ }
+
+ return s;
+ }
+
+ public static real_t Tan(real_t s)
+ {
+ return (real_t)Math.Tan(s);
+ }
+
+ public static real_t Tanh(real_t s)
+ {
+ return (real_t)Math.Tanh(s);
+ }
+
+ public static int Wrap(int value, int min, int max)
+ {
+ int range = max - min;
+ return range == 0 ? min : min + ((value - min) % range + range) % range;
+ }
+
+ public static real_t Wrap(real_t value, real_t min, real_t max)
+ {
+ real_t range = max - min;
+ return IsZeroApprox(range) ? min : min + ((value - min) % range + range) % range;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
new file mode 100644
index 0000000000..1b7fd4906f
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
@@ -0,0 +1,60 @@
+using System;
+
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ public static partial class Mathf
+ {
+ // Define constants with Decimal precision and cast down to double or float.
+
+ public const real_t E = (real_t) 2.7182818284590452353602874714M; // 2.7182817f and 2.718281828459045
+ public const real_t Sqrt2 = (real_t) 1.4142135623730950488016887242M; // 1.4142136f and 1.414213562373095
+
+#if REAL_T_IS_DOUBLE
+ public const real_t Epsilon = 1e-14; // Epsilon size should depend on the precision used.
+#else
+ public const real_t Epsilon = 1e-06f;
+#endif
+
+ public static int DecimalCount(real_t s)
+ {
+ return DecimalCount((decimal)s);
+ }
+
+ public static int DecimalCount(decimal s)
+ {
+ return BitConverter.GetBytes(decimal.GetBits(s)[3])[2];
+ }
+
+ public static int CeilToInt(real_t s)
+ {
+ return (int)Math.Ceiling(s);
+ }
+
+ public static int FloorToInt(real_t s)
+ {
+ return (int)Math.Floor(s);
+ }
+
+ public static int RoundToInt(real_t s)
+ {
+ return (int)Math.Round(s);
+ }
+
+ public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance)
+ {
+ // Check for exact equality first, required to handle "infinity" values.
+ if (a == b)
+ {
+ return true;
+ }
+ // Then check for approximate equality.
+ return Abs(a - b) < tolerance;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
new file mode 100644
index 0000000000..8c5872ba5a
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public sealed partial class NodePath : IDisposable
+ {
+ private bool disposed = false;
+
+ internal IntPtr ptr;
+
+ internal static IntPtr GetPtr(NodePath instance)
+ {
+ if (instance == null)
+ throw new NullReferenceException($"The instance of type {nameof(NodePath)} is null.");
+
+ if (instance.disposed)
+ throw new ObjectDisposedException(instance.GetType().FullName);
+
+ return instance.ptr;
+ }
+
+ ~NodePath()
+ {
+ Dispose(false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (disposed)
+ return;
+
+ if (ptr != IntPtr.Zero)
+ {
+ godot_icall_NodePath_Dtor(ptr);
+ ptr = IntPtr.Zero;
+ }
+
+ disposed = true;
+ }
+
+ internal NodePath(IntPtr ptr)
+ {
+ this.ptr = ptr;
+ }
+
+ public IntPtr NativeInstance
+ {
+ get { return ptr; }
+ }
+
+ public NodePath() : this(string.Empty) {}
+
+ public NodePath(string path)
+ {
+ this.ptr = godot_icall_NodePath_Ctor(path);
+ }
+
+ public static implicit operator NodePath(string from)
+ {
+ return new NodePath(from);
+ }
+
+ public static implicit operator string(NodePath from)
+ {
+ return godot_icall_NodePath_operator_String(NodePath.GetPtr(from));
+ }
+
+ public override string ToString()
+ {
+ return (string)this;
+ }
+
+ public NodePath GetAsPropertyPath()
+ {
+ return new NodePath(godot_icall_NodePath_get_as_property_path(NodePath.GetPtr(this)));
+ }
+
+ public string GetConcatenatedSubnames()
+ {
+ return godot_icall_NodePath_get_concatenated_subnames(NodePath.GetPtr(this));
+ }
+
+ public string GetName(int idx)
+ {
+ return godot_icall_NodePath_get_name(NodePath.GetPtr(this), idx);
+ }
+
+ public int GetNameCount()
+ {
+ return godot_icall_NodePath_get_name_count(NodePath.GetPtr(this));
+ }
+
+ public string GetSubname(int idx)
+ {
+ return godot_icall_NodePath_get_subname(NodePath.GetPtr(this), idx);
+ }
+
+ public int GetSubnameCount()
+ {
+ return godot_icall_NodePath_get_subname_count(NodePath.GetPtr(this));
+ }
+
+ public bool IsAbsolute()
+ {
+ return godot_icall_NodePath_is_absolute(NodePath.GetPtr(this));
+ }
+
+ public bool IsEmpty()
+ {
+ return godot_icall_NodePath_is_empty(NodePath.GetPtr(this));
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_NodePath_Ctor(string path);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_NodePath_Dtor(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_NodePath_operator_String(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_NodePath_get_name(IntPtr ptr, int arg1);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_NodePath_get_name_count(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_NodePath_get_subname_count(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_NodePath_is_absolute(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_NodePath_is_empty(IntPtr ptr);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
new file mode 100644
index 0000000000..de80f7fddc
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public partial class Object : IDisposable
+ {
+ private bool disposed = false;
+
+ private const string nativeName = "Object";
+
+ internal IntPtr ptr;
+ internal bool memoryOwn;
+
+ public Object() : this(false)
+ {
+ if (ptr == IntPtr.Zero)
+ ptr = godot_icall_Object_Ctor(this);
+ }
+
+ internal Object(bool memoryOwn)
+ {
+ this.memoryOwn = memoryOwn;
+ }
+
+ public IntPtr NativeInstance
+ {
+ get { return ptr; }
+ }
+
+ internal static IntPtr GetPtr(Object instance)
+ {
+ if (instance == null)
+ return IntPtr.Zero;
+
+ if (instance.disposed)
+ throw new ObjectDisposedException(instance.GetType().FullName);
+
+ return instance.ptr;
+ }
+
+ ~Object()
+ {
+ Dispose(false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposed)
+ return;
+
+ if (ptr != IntPtr.Zero)
+ {
+ if (memoryOwn)
+ {
+ memoryOwn = false;
+ godot_icall_Reference_Disposed(this, ptr, !disposing);
+ }
+ else
+ {
+ godot_icall_Object_Disposed(this, ptr);
+ }
+
+ this.ptr = IntPtr.Zero;
+ }
+
+ disposed = true;
+ }
+
+ public override string ToString()
+ {
+ return godot_icall_Object_ToString(GetPtr(this));
+ }
+
+ /// <summary>
+ /// Returns a new <see cref="Godot.SignalAwaiter"/> awaiter configured to complete when the instance
+ /// <paramref name="source"/> emits the signal specified by the <paramref name="signal"/> parameter.
+ /// </summary>
+ /// <param name="source">
+ /// The instance the awaiter will be listening to.
+ /// </param>
+ /// <param name="signal">
+ /// The signal the awaiter will be waiting for.
+ /// </param>
+ /// <example>
+ /// This sample prints a message once every frame up to 100 times.
+ /// <code>
+ /// public override void _Ready()
+ /// {
+ /// for (int i = 0; i &lt; 100; i++)
+ /// {
+ /// await ToSignal(GetTree(), "idle_frame");
+ /// GD.Print($"Frame {i}");
+ /// }
+ /// }
+ /// </code>
+ /// </example>
+ public SignalAwaiter ToSignal(Object source, string signal)
+ {
+ return new SignalAwaiter(source, signal, this);
+ }
+
+ /// <summary>
+ /// Gets a new <see cref="Godot.DynamicGodotObject"/> associated with this instance.
+ /// </summary>
+ public dynamic DynamicObject => new DynamicGodotObject(this);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_Object_Ctor(Object obj);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Object_Disposed(Object obj, IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_Object_ToString(IntPtr ptr);
+
+ // Used by the generated API
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_Object_ClassDB_get_method(string type, string method);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
new file mode 100644
index 0000000000..885845e3a4
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -0,0 +1,238 @@
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Plane : IEquatable<Plane>
+ {
+ private Vector3 _normal;
+
+ public Vector3 Normal
+ {
+ get { return _normal; }
+ set { _normal = value; }
+ }
+
+ public real_t x
+ {
+ get
+ {
+ return _normal.x;
+ }
+ set
+ {
+ _normal.x = value;
+ }
+ }
+
+ public real_t y
+ {
+ get
+ {
+ return _normal.y;
+ }
+ set
+ {
+ _normal.y = value;
+ }
+ }
+
+ public real_t z
+ {
+ get
+ {
+ return _normal.z;
+ }
+ set
+ {
+ _normal.z = value;
+ }
+ }
+
+ public real_t D { get; set; }
+
+ public Vector3 Center
+ {
+ get
+ {
+ return _normal * D;
+ }
+ }
+
+ public real_t DistanceTo(Vector3 point)
+ {
+ return _normal.Dot(point) - D;
+ }
+
+ public Vector3 GetAnyPoint()
+ {
+ return _normal * D;
+ }
+
+ public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon)
+ {
+ real_t dist = _normal.Dot(point) - D;
+ return Mathf.Abs(dist) <= epsilon;
+ }
+
+ public Vector3? Intersect3(Plane b, Plane c)
+ {
+ real_t denom = _normal.Cross(b._normal).Dot(c._normal);
+
+ if (Mathf.IsZeroApprox(denom))
+ return null;
+
+ Vector3 result = b._normal.Cross(c._normal) * D +
+ c._normal.Cross(_normal) * b.D +
+ _normal.Cross(b._normal) * c.D;
+
+ return result / denom;
+ }
+
+ public Vector3? IntersectRay(Vector3 from, Vector3 dir)
+ {
+ real_t den = _normal.Dot(dir);
+
+ if (Mathf.IsZeroApprox(den))
+ return null;
+
+ real_t dist = (_normal.Dot(from) - D) / den;
+
+ // This is a ray, before the emitting pos (from) does not exist
+ if (dist > Mathf.Epsilon)
+ return null;
+
+ return from + dir * -dist;
+ }
+
+ public Vector3? IntersectSegment(Vector3 begin, Vector3 end)
+ {
+ Vector3 segment = begin - end;
+ real_t den = _normal.Dot(segment);
+
+ if (Mathf.IsZeroApprox(den))
+ return null;
+
+ real_t dist = (_normal.Dot(begin) - D) / den;
+
+ // Only allow dist to be in the range of 0 to 1, with tolerance.
+ if (dist < -Mathf.Epsilon || dist > 1.0f + Mathf.Epsilon)
+ return null;
+
+ return begin + segment * -dist;
+ }
+
+ public bool IsPointOver(Vector3 point)
+ {
+ return _normal.Dot(point) > D;
+ }
+
+ public Plane Normalized()
+ {
+ real_t 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 * DistanceTo(point);
+ }
+
+ // Constants
+ private static readonly Plane _planeYZ = new Plane(1, 0, 0, 0);
+ private static readonly Plane _planeXZ = new Plane(0, 1, 0, 0);
+ private static readonly Plane _planeXY = new Plane(0, 0, 1, 0);
+
+ public static Plane PlaneYZ { get { return _planeYZ; } }
+ public static Plane PlaneXZ { get { return _planeXZ; } }
+ public static Plane PlaneXY { get { return _planeXY; } }
+
+ // Constructors
+ public Plane(real_t a, real_t b, real_t c, real_t d)
+ {
+ _normal = new Vector3(a, b, c);
+ this.D = d;
+ }
+ public Plane(Vector3 normal, real_t 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 bool IsEqualApprox(Plane other)
+ {
+ return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(D, other.D);
+ }
+
+ public override int GetHashCode()
+ {
+ return _normal.GetHashCode() ^ D.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ _normal.ToString(),
+ D.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ _normal.ToString(format),
+ D.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
new file mode 100644
index 0000000000..6702634c51
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
@@ -0,0 +1,414 @@
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Quat : IEquatable<Quat>
+ {
+ public real_t x;
+ public real_t y;
+ public real_t z;
+ public real_t w;
+
+ public real_t this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ case 3:
+ w = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public real_t Length
+ {
+ get { return Mathf.Sqrt(LengthSquared); }
+ }
+
+ public real_t LengthSquared
+ {
+ get { return Dot(this); }
+ }
+
+ public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t t)
+ {
+ real_t t2 = (1.0f - t) * t * 2f;
+ Quat sp = Slerp(b, t);
+ Quat sq = preA.Slerpni(postB, t);
+ return sp.Slerpni(sq, t2);
+ }
+
+ public real_t Dot(Quat b)
+ {
+ return x * b.x + y * b.y + z * b.z + w * b.w;
+ }
+
+ public Vector3 GetEuler()
+ {
+#if DEBUG
+ if (!IsNormalized())
+ throw new InvalidOperationException("Quat is not normalized");
+#endif
+ var basis = new Basis(this);
+ return basis.GetEuler();
+ }
+
+ public Quat Inverse()
+ {
+#if DEBUG
+ if (!IsNormalized())
+ throw new InvalidOperationException("Quat is not normalized");
+#endif
+ return new Quat(-x, -y, -z, w);
+ }
+
+ public Quat Normalized()
+ {
+ return this / Length;
+ }
+
+ [Obsolete("Set is deprecated. Use the Quat(" + nameof(real_t) + ", " + nameof(real_t) + ", " + nameof(real_t) + ", " + nameof(real_t) + ") constructor instead.", error: true)]
+ public void Set(real_t x, real_t y, real_t z, real_t w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ [Obsolete("Set is deprecated. Use the Quat(" + nameof(Quat) + ") constructor instead.", error: true)]
+ public void Set(Quat q)
+ {
+ this = q;
+ }
+
+ [Obsolete("SetAxisAngle is deprecated. Use the Quat(" + nameof(Vector3) + ", " + nameof(real_t) + ") constructor instead.", error: true)]
+ public void SetAxisAngle(Vector3 axis, real_t angle)
+ {
+ this = new Quat(axis, angle);
+ }
+
+ [Obsolete("SetEuler is deprecated. Use the Quat(" + nameof(Vector3) + ") constructor instead.", error: true)]
+ public void SetEuler(Vector3 eulerYXZ)
+ {
+ this = new Quat(eulerYXZ);
+ }
+
+ public Quat Slerp(Quat b, real_t t)
+ {
+#if DEBUG
+ if (!IsNormalized())
+ throw new InvalidOperationException("Quat is not normalized");
+ if (!b.IsNormalized())
+ throw new ArgumentException("Argument is not normalized", nameof(b));
+#endif
+
+ // Calculate cosine
+ real_t cosom = x * b.x + y * b.y + z * b.z + w * b.w;
+
+ var to1 = new Quat();
+
+ // Adjust signs if necessary
+ if (cosom < 0.0)
+ {
+ cosom = -cosom;
+ to1.x = -b.x;
+ to1.y = -b.y;
+ to1.z = -b.z;
+ to1.w = -b.w;
+ }
+ else
+ {
+ to1.x = b.x;
+ to1.y = b.y;
+ to1.z = b.z;
+ to1.w = b.w;
+ }
+
+ real_t sinom, scale0, scale1;
+
+ // Calculate coefficients
+ if (1.0 - cosom > Mathf.Epsilon)
+ {
+ // Standard case (Slerp)
+ real_t 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.x,
+ scale0 * y + scale1 * to1.y,
+ scale0 * z + scale1 * to1.z,
+ scale0 * w + scale1 * to1.w
+ );
+ }
+
+ public Quat Slerpni(Quat b, real_t t)
+ {
+ real_t dot = Dot(b);
+
+ if (Mathf.Abs(dot) > 0.9999f)
+ {
+ return this;
+ }
+
+ real_t theta = Mathf.Acos(dot);
+ real_t sinT = 1.0f / Mathf.Sin(theta);
+ real_t newFactor = Mathf.Sin(t * theta) * sinT;
+ real_t invFactor = Mathf.Sin((1.0f - t) * theta) * sinT;
+
+ return new Quat
+ (
+ invFactor * x + newFactor * b.x,
+ invFactor * y + newFactor * b.y,
+ invFactor * z + newFactor * b.z,
+ invFactor * w + newFactor * b.w
+ );
+ }
+
+ public Vector3 Xform(Vector3 v)
+ {
+#if DEBUG
+ if (!IsNormalized())
+ throw new InvalidOperationException("Quat is not normalized");
+#endif
+ var u = new Vector3(x, y, z);
+ Vector3 uv = u.Cross(v);
+ return v + ((uv * w) + u.Cross(uv)) * 2;
+ }
+
+ // Static Readonly Properties
+ public static Quat Identity { get; } = new Quat(0f, 0f, 0f, 1f);
+
+ // Constructors
+ public Quat(real_t x, real_t y, real_t z, real_t w)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ public bool IsNormalized()
+ {
+ return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon;
+ }
+
+ public Quat(Quat q)
+ {
+ this = q;
+ }
+
+ public Quat(Basis basis)
+ {
+ this = basis.Quat();
+ }
+
+ public Quat(Vector3 eulerYXZ)
+ {
+ real_t half_a1 = eulerYXZ.y * 0.5f;
+ real_t half_a2 = eulerYXZ.x * 0.5f;
+ real_t half_a3 = eulerYXZ.z * 0.5f;
+
+ // R = Y(a1).X(a2).Z(a3) convention for Euler angles.
+ // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6)
+ // a3 is the angle of the first rotation, following the notation in this reference.
+
+ real_t cos_a1 = Mathf.Cos(half_a1);
+ real_t sin_a1 = Mathf.Sin(half_a1);
+ real_t cos_a2 = Mathf.Cos(half_a2);
+ real_t sin_a2 = Mathf.Sin(half_a2);
+ real_t cos_a3 = Mathf.Cos(half_a3);
+ real_t sin_a3 = Mathf.Sin(half_a3);
+
+ x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3;
+ y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3;
+ z = cos_a1 * cos_a2 * sin_a3 - sin_a1 * sin_a2 * cos_a3;
+ w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
+ }
+
+ public Quat(Vector3 axis, real_t angle)
+ {
+#if DEBUG
+ if (!axis.IsNormalized())
+ throw new ArgumentException("Argument is not normalized", nameof(axis));
+#endif
+
+ real_t d = axis.Length();
+
+ if (d == 0f)
+ {
+ x = 0f;
+ y = 0f;
+ z = 0f;
+ w = 0f;
+ }
+ else
+ {
+ real_t sinAngle = Mathf.Sin(angle * 0.5f);
+ real_t cosAngle = Mathf.Cos(angle * 0.5f);
+ real_t s = sinAngle / d;
+
+ x = axis.x * s;
+ y = axis.y * s;
+ z = axis.z * s;
+ w = cosAngle;
+ }
+ }
+
+ 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, real_t right)
+ {
+ return new Quat(left.x * right, left.y * right, left.z * right, left.w * right);
+ }
+
+ public static Quat operator *(real_t left, Quat right)
+ {
+ return new Quat(right.x * left, right.y * left, right.z * left, right.w * left);
+ }
+
+ public static Quat operator /(Quat left, real_t 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 Quat)
+ {
+ return Equals((Quat)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Quat other)
+ {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+
+ public bool IsEqualApprox(Quat other)
+ {
+ return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(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})", x.ToString(), y.ToString(), z.ToString(), w.ToString());
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2}, {3})", x.ToString(format), y.ToString(format), z.ToString(format), w.ToString(format));
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
new file mode 100644
index 0000000000..94761531b1
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public sealed partial class RID : IDisposable
+ {
+ private bool disposed = false;
+
+ internal IntPtr ptr;
+
+ internal static IntPtr GetPtr(RID instance)
+ {
+ if (instance == null)
+ throw new NullReferenceException($"The instance of type {nameof(RID)} is null.");
+
+ if (instance.disposed)
+ throw new ObjectDisposedException(instance.GetType().FullName);
+
+ return instance.ptr;
+ }
+
+ ~RID()
+ {
+ Dispose(false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (disposed)
+ return;
+
+ if (ptr != IntPtr.Zero)
+ {
+ godot_icall_RID_Dtor(ptr);
+ ptr = IntPtr.Zero;
+ }
+
+ disposed = true;
+ }
+
+ internal RID(IntPtr ptr)
+ {
+ this.ptr = ptr;
+ }
+
+ public IntPtr NativeInstance
+ {
+ get { return ptr; }
+ }
+
+ internal RID()
+ {
+ this.ptr = IntPtr.Zero;
+ }
+
+ public RID(Object from)
+ {
+ this.ptr = godot_icall_RID_Ctor(Object.GetPtr(from));
+ }
+
+ public int GetId()
+ {
+ return godot_icall_RID_get_id(RID.GetPtr(this));
+ }
+
+ public override string ToString() => "[RID]";
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static IntPtr godot_icall_RID_Ctor(IntPtr from);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static void godot_icall_RID_Dtor(IntPtr ptr);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_RID_get_id(IntPtr ptr);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
new file mode 100644
index 0000000000..91e614dc7b
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -0,0 +1,262 @@
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ [Serializable]
+ [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; }
+ set { _size = value - _position; }
+ }
+
+ public real_t Area
+ {
+ get { return GetArea(); }
+ }
+
+ public Rect2 Abs()
+ {
+ Vector2 end = End;
+ Vector2 topLeft = new Vector2(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y));
+ return new Rect2(topLeft, _size.Abs());
+ }
+
+ public Rect2 Clip(Rect2 b)
+ {
+ var 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)
+ {
+ var 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 real_t GetArea()
+ {
+ return _size.x * _size.y;
+ }
+
+ public Rect2 Grow(real_t by)
+ {
+ var g = this;
+
+ g._position.x -= by;
+ g._position.y -= by;
+ g._size.x += by * 2;
+ g._size.y += by * 2;
+
+ return g;
+ }
+
+ public Rect2 GrowIndividual(real_t left, real_t top, real_t right, real_t bottom)
+ {
+ var g = this;
+
+ g._position.x -= left;
+ g._position.y -= top;
+ g._size.x += left + right;
+ g._size.y += top + bottom;
+
+ return g;
+ }
+
+ public Rect2 GrowMargin(Margin margin, real_t by)
+ {
+ var g = this;
+
+ g.GrowIndividual(Margin.Left == margin ? by : 0,
+ Margin.Top == margin ? by : 0,
+ Margin.Right == margin ? by : 0,
+ Margin.Bottom == margin ? by : 0);
+
+ return g;
+ }
+
+ public bool HasNoArea()
+ {
+ return _size.x <= 0 || _size.y <= 0;
+ }
+
+ public bool HasPoint(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;
+ }
+
+ // Constructors
+ public Rect2(Vector2 position, Vector2 size)
+ {
+ _position = position;
+ _size = size;
+ }
+ public Rect2(Vector2 position, real_t width, real_t height)
+ {
+ _position = position;
+ _size = new Vector2(width, height);
+ }
+ public Rect2(real_t x, real_t y, Vector2 size)
+ {
+ _position = new Vector2(x, y);
+ _size = size;
+ }
+ public Rect2(real_t x, real_t y, real_t width, real_t height)
+ {
+ _position = new Vector2(x, y);
+ _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 bool IsEqualApprox(Rect2 other)
+ {
+ return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other.Size);
+ }
+
+ public override int GetHashCode()
+ {
+ return _position.GetHashCode() ^ _size.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ _position.ToString(),
+ _size.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ _position.ToString(format),
+ _size.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
new file mode 100644
index 0000000000..9483b6ffb4
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public class SignalAwaiter : IAwaiter<object[]>, IAwaitable<object[]>
+ {
+ private bool completed;
+ private object[] result;
+ private Action action;
+
+ public SignalAwaiter(Object source, string signal, Object target)
+ {
+ godot_icall_SignalAwaiter_connect(Object.GetPtr(source), signal, Object.GetPtr(target), this);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static Error godot_icall_SignalAwaiter_connect(IntPtr source, string signal, IntPtr target, SignalAwaiter awaiter);
+
+ 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/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
new file mode 100644
index 0000000000..e096d37a6f
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -0,0 +1,1046 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Security;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Godot
+{
+ public static class StringExtensions
+ {
+ private static int GetSliceCount(this string instance, string splitter)
+ {
+ if (instance.Empty() || splitter.Empty())
+ return 0;
+
+ int pos = 0;
+ int slices = 1;
+
+ while ((pos = instance.Find(splitter, pos, caseSensitive: true)) >= 0)
+ {
+ slices++;
+ pos += splitter.Length;
+ }
+
+ return slices;
+ }
+
+ private static string GetSliceCharacter(this string instance, char splitter, int slice)
+ {
+ if (!instance.Empty() && slice >= 0)
+ {
+ int i = 0;
+ int prev = 0;
+ int count = 0;
+
+ while (true)
+ {
+ bool end = instance.Length <= i;
+
+ if (end || instance[i] == splitter)
+ {
+ if (slice == count)
+ {
+ return instance.Substring(prev, i - prev);
+ }
+ else if (end)
+ {
+ return string.Empty;
+ }
+
+ 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 BeginsWith(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)
+ {
+ var b = new string[instance.Length - 1];
+
+ for (int i = 0; i < b.Length; i++)
+ {
+ b[i] = instance.Substring(i, 2);
+ }
+
+ return b;
+ }
+
+ // <summary>
+ // Return the amount of substrings in string.
+ // </summary>
+ public static int Count(this string instance, string what, bool caseSensitive = true, int from = 0, int to = 0)
+ {
+ if (what.Length == 0)
+ {
+ return 0;
+ }
+
+ int len = instance.Length;
+ int slen = what.Length;
+
+ if (len < slen)
+ {
+ return 0;
+ }
+
+ string str;
+
+ if (from >= 0 && to >= 0)
+ {
+ if (to == 0)
+ {
+ to = len;
+ }
+ else if (from >= to)
+ {
+ return 0;
+ }
+ if (from == 0 && to == len)
+ {
+ str = instance;
+ }
+ else
+ {
+ str = instance.Substring(from, to - from);
+ }
+ }
+ else
+ {
+ return 0;
+ }
+
+ int c = 0;
+ int idx;
+
+ do
+ {
+ idx = str.IndexOf(what, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+ if (idx != -1)
+ {
+ str = str.Substring(idx + slen);
+ ++c;
+ }
+ } while (idx != -1);
+
+ return c;
+ }
+
+ // <summary>
+ // Return a copy of the string with special characters escaped using the C language standard.
+ // </summary>
+ public static string CEscape(this string instance)
+ {
+ var 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 CUnescape(this string instance)
+ {
+ var 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();
+ var cap = string.Empty;
+
+ for (int i = 0; i < aux.GetSliceCount(" "); i++)
+ {
+ string slice = aux.GetSliceCharacter(' ', 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 CasecmpTo(this string instance, string to)
+ {
+ return instance.CompareTo(to, caseSensitive: true);
+ }
+
+ // <summary>
+ // Perform a comparison to another string, return -1 if less, 0 if equal and +1 if greater.
+ // </summary>
+ public static int CompareTo(this string instance, string to, bool caseSensitive = true)
+ {
+ if (instance.Empty())
+ return to.Empty() ? 0 : -1;
+
+ if (to.Empty())
+ return 1;
+
+ int instanceIndex = 0;
+ int toIndex = 0;
+
+ if (caseSensitive) // Outside while loop to avoid checking multiple times, despite some code duplication.
+ {
+ while (true)
+ {
+ if (to[toIndex] == 0 && instance[instanceIndex] == 0)
+ return 0; // We're equal
+ if (instance[instanceIndex] == 0)
+ return -1; // If this is empty, and the other one is not, then we're less... I think?
+ if (to[toIndex] == 0)
+ return 1; // Otherwise the other one is smaller...
+ if (instance[instanceIndex] < to[toIndex]) // More than
+ return -1;
+ if (instance[instanceIndex] > to[toIndex]) // Less than
+ return 1;
+
+ instanceIndex++;
+ toIndex++;
+ }
+ } else
+ {
+ while (true)
+ {
+ if (to[toIndex] == 0 && instance[instanceIndex] == 0)
+ return 0; // We're equal
+ if (instance[instanceIndex] == 0)
+ return -1; // If this is empty, and the other one is not, then we're less... I think?
+ if (to[toIndex] == 0)
+ return 1; // Otherwise the other one is smaller..
+ if (char.ToUpper(instance[instanceIndex]) < char.ToUpper(to[toIndex])) // More than
+ return -1;
+ if (char.ToUpper(instance[instanceIndex]) > char.ToUpper(to[toIndex])) // Less than
+ return 1;
+
+ instanceIndex++;
+ toIndex++;
+ }
+ }
+ }
+
+ // <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 EndsWith(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.FindLast(".");
+
+ if (pos < 0)
+ return instance;
+
+ return instance.Substring(pos + 1);
+ }
+
+ /// <summary>Find the first occurrence of a substring. Optionally, the search starting position can be passed.</summary>
+ /// <returns>The starting position of the substring, or -1 if not found.</returns>
+ public static int Find(this string instance, string what, int from = 0, bool caseSensitive = true)
+ {
+ return instance.IndexOf(what, from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+ }
+
+ /// <summary>Find the last occurrence of a substring.</summary>
+ /// <returns>The starting position of the substring, or -1 if not found.</returns>
+ public static int FindLast(this string instance, string what, bool caseSensitive = true)
+ {
+ return instance.FindLast(what, instance.Length - 1, caseSensitive);
+ }
+
+ /// <summary>Find the last occurrence of a substring specifying the search starting position.</summary>
+ /// <returns>The starting position of the substring, or -1 if not found.</returns>
+ public static int FindLast(this string instance, string what, int from, bool caseSensitive = true)
+ {
+ return instance.LastIndexOf(what, from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+ }
+
+ /// <summary>Find the first occurrence of a substring but search as case-insensitive. Optionally, the search starting position can be passed.</summary>
+ /// <returns>The starting position of the substring, or -1 if not found.</returns>
+ public static int FindN(this string instance, string what, int from = 0)
+ {
+ return instance.IndexOf(what, from, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the base directory.
+ // </summary>
+ public static string GetBaseDir(this string instance)
+ {
+ int basepos = instance.Find("://");
+
+ string rs;
+ var @base = string.Empty;
+
+ if (basepos != -1)
+ {
+ var end = basepos + 3;
+ rs = instance.Substring(end);
+ @base = instance.Substring(0, end);
+ }
+ else
+ {
+ if (instance.BeginsWith("/"))
+ {
+ rs = instance.Substring(1);
+ @base = "/";
+ }
+ else
+ {
+ rs = instance;
+ }
+ }
+
+ int sep = Mathf.Max(rs.FindLast("/"), rs.FindLast("\\"));
+
+ 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 GetFile(this string instance)
+ {
+ int sep = Mathf.Max(instance.FindLast("/"), instance.FindLast("\\"));
+
+ if (sep == -1)
+ return instance;
+
+ return instance.Substring(sep + 1);
+ }
+
+ // <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 = 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 HexToInt(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 IsAbsPath(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 IsRelPath(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 IsSubsequenceOf(this string instance, string text, bool caseSensitive = true)
+ {
+ 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 source = 0;
+ int target = 0;
+
+ while (source < len && target < text.Length)
+ {
+ bool match;
+
+ if (!caseSensitive)
+ {
+ char sourcec = char.ToLower(instance[source]);
+ char targetc = char.ToLower(text[target]);
+ match = sourcec == targetc;
+ }
+ else
+ {
+ match = instance[source] == text[target];
+ }
+ if (match)
+ {
+ source++;
+ if (source >= len)
+ return true;
+ }
+
+ target++;
+ }
+
+ return false;
+ }
+
+ // <summary>
+ // Check whether this string is a subsequence of the given string, ignoring case differences.
+ // </summary>
+ public static bool IsSubsequenceOfI(this string instance, string text)
+ {
+ return instance.IsSubsequenceOf(text, caseSensitive: false);
+ }
+
+ // <summary>
+ // Check whether the string contains a valid float.
+ // </summary>
+ public static bool IsValidFloat(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 IsValidHtmlColor(this string instance)
+ {
+ return Color.HtmlIsValid(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 IsValidIdentifier(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 validChar = instance[i] >= '0' &&
+ instance[i] <= '9' || instance[i] >= 'a' &&
+ instance[i] <= 'z' || instance[i] >= 'A' &&
+ instance[i] <= 'Z' || instance[i] == '_';
+
+ if (!validChar)
+ return false;
+ }
+
+ return true;
+ }
+
+ // <summary>
+ // Check whether the string contains a valid integer.
+ // </summary>
+ public static bool IsValidInteger(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 IsValidIPAddress(this string instance)
+ {
+ // TODO: Support IPv6 addresses
+ string[] ip = instance.Split(".");
+
+ if (ip.Length != 4)
+ return false;
+
+ for (int i = 0; i < ip.Length; i++)
+ {
+ string n = ip[i];
+ if (!n.IsValidInteger())
+ return false;
+
+ int val = n.ToInt();
+ 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 JSONEscape(this string instance)
+ {
+ var 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 ExprMatch(this string instance, string expr, bool caseSensitive)
+ {
+ if (expr.Length == 0 || instance.Length == 0)
+ return false;
+
+ switch (expr[0])
+ {
+ case '\0':
+ return instance[0] == 0;
+ case '*':
+ return ExprMatch(expr + 1, instance, caseSensitive) || instance[0] != 0 && ExprMatch(expr, instance + 1, caseSensitive);
+ case '?':
+ return instance[0] != 0 && instance[0] != '.' && ExprMatch(expr + 1, instance + 1, caseSensitive);
+ default:
+ return (caseSensitive ? instance[0] == expr[0] : char.ToUpper(instance[0]) == char.ToUpper(expr[0])) &&
+ ExprMatch(expr + 1, instance + 1, caseSensitive);
+ }
+ }
+
+ // <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, bool caseSensitive = true)
+ {
+ return instance.ExprMatch(expr, caseSensitive);
+ }
+
+ // <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.ExprMatch(expr, caseSensitive: false);
+ }
+
+ // <summary>
+ // Return the MD5 hash of the string as an array of bytes.
+ // </summary>
+ public static byte[] MD5Buffer(this string instance)
+ {
+ return godot_icall_String_md5_buffer(instance);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static byte[] godot_icall_String_md5_buffer(string str);
+
+ // <summary>
+ // Return the MD5 hash of the string as a string.
+ // </summary>
+ public static string MD5Text(this string instance)
+ {
+ return godot_icall_String_md5_text(instance);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_String_md5_text(string str);
+
+ // <summary>
+ // Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
+ // </summary>
+ public static int NocasecmpTo(this string instance, string to)
+ {
+ return instance.CompareTo(to, caseSensitive: false);
+ }
+
+ // <summary>
+ // Return the character code at position [code]at[/code].
+ // </summary>
+ public static int OrdAt(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 PadDecimals(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 PadZeros(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 PercentDecode(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 PercentEncode(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 PlusFile(this string instance, string file)
+ {
+ if (instance.Length > 0 && instance[instance.Length - 1] == '/')
+ return instance + file;
+ 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 godot_icall_String_rfind(instance, what, from);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_String_rfind(string str, string what, int 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 godot_icall_String_rfindn(instance, what, from);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static int godot_icall_String_rfindn(string str, string what, int 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[] SHA256Buffer(this string instance)
+ {
+ return godot_icall_String_sha256_buffer(instance);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static byte[] godot_icall_String_sha256_buffer(string str);
+
+ // <summary>
+ // Return the SHA-256 hash of the string as a string.
+ // </summary>
+ public static string SHA256Text(this string instance)
+ {
+ return godot_icall_String_sha256_text(instance);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_String_sha256_text(string str);
+
+ // <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[] sourceBigrams = instance.Bigrams();
+ string[] targetBigrams = text.Bigrams();
+
+ int sourceSize = sourceBigrams.Length;
+ int targetSize = targetBigrams.Length;
+
+ float sum = sourceSize + targetSize;
+ float inter = 0;
+
+ for (int i = 0; i < sourceSize; i++)
+ {
+ for (int j = 0; j < targetSize; j++)
+ {
+ if (sourceBigrams[i] == targetBigrams[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 allowEmpty = true)
+ {
+ return instance.Split(new[] { 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[] SplitFloats(this string instance, string divisor, bool allowEmpty = true)
+ {
+ var ret = new List<float>();
+ int from = 0;
+ int len = instance.Length;
+
+ while (true)
+ {
+ int end = instance.Find(divisor, from, caseSensitive: true);
+ if (end < 0)
+ end = len;
+ if (allowEmpty || end > from)
+ ret.Add(float.Parse(instance.Substring(from)));
+ if (end == len)
+ break;
+
+ from = end + divisor.Length;
+ }
+
+ return ret.ToArray();
+ }
+
+ private static readonly char[] _nonPrintable = {
+ (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 StripEdges(this string instance, bool left = true, bool right = true)
+ {
+ if (left)
+ {
+ if (right)
+ return instance.Trim(_nonPrintable);
+ return instance.TrimStart(_nonPrintable);
+ }
+
+ return instance.TrimEnd(_nonPrintable);
+ }
+
+ // <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)
+ {
+ int max = instance.Length - from;
+ return instance.Substring(from, len > max ? max : 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[] ToAscii(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 ToFloat(this string instance)
+ {
+ return float.Parse(instance);
+ }
+
+ // <summary>
+ // Convert a string, containing an integer number, into an [code]int[/code].
+ // </summary>
+ public static int ToInt(this string instance)
+ {
+ return int.Parse(instance);
+ }
+
+ // <summary>
+ // Return the string converted to lowercase.
+ // </summary>
+ public static string ToLower(this string instance)
+ {
+ return instance.ToLower();
+ }
+
+ // <summary>
+ // Return the string converted to uppercase.
+ // </summary>
+ public static string ToUpper(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[] ToUTF8(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 XMLEscape(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 XMLUnescape(this string instance)
+ {
+ return SecurityElement.FromString(instance).Text;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs
new file mode 100644
index 0000000000..0b84050f07
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs
@@ -0,0 +1,216 @@
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Transform : IEquatable<Transform>
+ {
+ public Basis basis;
+ public Vector3 origin;
+
+ public Transform AffineInverse()
+ {
+ Basis basisInv = basis.Inverse();
+ return new Transform(basisInv, basisInv.Xform(-origin));
+ }
+
+ public Transform InterpolateWith(Transform transform, real_t c)
+ {
+ /* not sure if very "efficient" but good enough? */
+
+ Vector3 sourceScale = basis.Scale;
+ Quat sourceRotation = basis.RotationQuat();
+ Vector3 sourceLocation = origin;
+
+ Vector3 destinationScale = transform.basis.Scale;
+ Quat destinationRotation = transform.basis.RotationQuat();
+ Vector3 destinationLocation = transform.origin;
+
+ var interpolated = new Transform();
+ interpolated.basis.SetQuatScale(sourceRotation.Slerp(destinationRotation, c).Normalized(), sourceScale.LinearInterpolate(destinationScale, c));
+ interpolated.origin = sourceLocation.LinearInterpolate(destinationLocation, c);
+
+ return interpolated;
+ }
+
+ public Transform Inverse()
+ {
+ Basis basisTr = basis.Transposed();
+ return new Transform(basisTr, basisTr.Xform(-origin));
+ }
+
+ public Transform LookingAt(Vector3 target, Vector3 up)
+ {
+ var t = this;
+ t.SetLookAt(origin, target, up);
+ return t;
+ }
+
+ public Transform Orthonormalized()
+ {
+ return new Transform(basis.Orthonormalized(), origin);
+ }
+
+ public Transform Rotated(Vector3 axis, real_t 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 SetLookAt(Vector3 eye, Vector3 target, Vector3 up)
+ {
+ // Make rotation matrix
+ // Z vector
+ Vector3 column2 = eye - target;
+
+ column2.Normalize();
+
+ Vector3 column1 = up;
+
+ Vector3 column0 = column1.Cross(column2);
+
+ // Recompute Y = Z cross X
+ column1 = column2.Cross(column0);
+
+ column0.Normalize();
+ column1.Normalize();
+
+ basis = new Basis(column0, column1, column2);
+
+ origin = eye;
+ }
+
+ public Transform Translated(Vector3 ofs)
+ {
+ return new Transform(basis, new Vector3
+ (
+ origin[0] += basis.Row0.Dot(ofs),
+ origin[1] += basis.Row1.Dot(ofs),
+ origin[2] += basis.Row2.Dot(ofs)
+ ));
+ }
+
+ public Vector3 Xform(Vector3 v)
+ {
+ return new Vector3
+ (
+ basis.Row0.Dot(v) + origin.x,
+ basis.Row1.Dot(v) + origin.y,
+ basis.Row2.Dot(v) + origin.z
+ );
+ }
+
+ public Vector3 XformInv(Vector3 v)
+ {
+ Vector3 vInv = v - origin;
+
+ return new Vector3
+ (
+ basis.Row0[0] * vInv.x + basis.Row1[0] * vInv.y + basis.Row2[0] * vInv.z,
+ basis.Row0[1] * vInv.x + basis.Row1[1] * vInv.y + basis.Row2[1] * vInv.z,
+ basis.Row0[2] * vInv.x + basis.Row1[2] * vInv.y + basis.Row2[2] * vInv.z
+ );
+ }
+
+ // Constants
+ private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero);
+ private static readonly Transform _flipX = new Transform(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero);
+ private static readonly Transform _flipY = new Transform(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero);
+ private static readonly Transform _flipZ = new Transform(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero);
+
+ public static Transform Identity { get { return _identity; } }
+ public static Transform FlipX { get { return _flipX; } }
+ public static Transform FlipY { get { return _flipY; } }
+ public static Transform FlipZ { get { return _flipZ; } }
+
+ // Constructors
+ public Transform(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin)
+ {
+ basis = new Basis(column0, column1, column2);
+ this.origin = origin;
+ }
+
+ public Transform(Quat quat, Vector3 origin)
+ {
+ 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 bool IsEqualApprox(Transform other)
+ {
+ return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin);
+ }
+
+ public override int GetHashCode()
+ {
+ return basis.GetHashCode() ^ origin.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ basis.ToString(),
+ origin.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("{0} - {1}", new object[]
+ {
+ basis.ToString(format),
+ origin.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
new file mode 100644
index 0000000000..77ea3e5830
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -0,0 +1,390 @@
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Transform2D : IEquatable<Transform2D>
+ {
+ public Vector2 x;
+ public Vector2 y;
+ public Vector2 origin;
+
+ public real_t Rotation
+ {
+ get
+ {
+ real_t det = BasisDeterminant();
+ Transform2D t = Orthonormalized();
+ if (det < 0)
+ {
+ t.ScaleBasis(new Vector2(1, -1));
+ }
+ return Mathf.Atan2(t.x.y, t.x.x);
+ }
+ set
+ {
+ Vector2 scale = Scale;
+ x.x = y.y = Mathf.Cos(value);
+ x.y = y.x = Mathf.Sin(value);
+ y.x *= -1;
+ Scale = scale;
+ }
+ }
+
+ public Vector2 Scale
+ {
+ get
+ {
+ real_t detSign = Mathf.Sign(BasisDeterminant());
+ return new Vector2(x.Length(), detSign * y.Length());
+ }
+ set
+ {
+ x = x.Normalized();
+ y = y.Normalized();
+ x *= value.x;
+ y *= value.y;
+ }
+ }
+
+ public Vector2 this[int rowIndex]
+ {
+ get
+ {
+ switch (rowIndex)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return origin;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (rowIndex)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ origin = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public real_t this[int rowIndex, int columnIndex]
+ {
+ get
+ {
+ switch (rowIndex)
+ {
+ case 0:
+ return x[columnIndex];
+ case 1:
+ return y[columnIndex];
+ case 2:
+ return origin[columnIndex];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (rowIndex)
+ {
+ case 0:
+ x[columnIndex] = value;
+ return;
+ case 1:
+ y[columnIndex] = value;
+ return;
+ case 2:
+ origin[columnIndex] = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public Transform2D AffineInverse()
+ {
+ real_t det = BasisDeterminant();
+
+ if (det == 0)
+ throw new InvalidOperationException("Matrix determinant is zero and cannot be inverted.");
+
+ var inv = this;
+
+ real_t temp = inv[0, 0];
+ inv[0, 0] = inv[1, 1];
+ inv[1, 1] = temp;
+
+ real_t detInv = 1.0f / det;
+
+ inv[0] *= new Vector2(detInv, -detInv);
+ inv[1] *= new Vector2(-detInv, detInv);
+
+ inv[2] = inv.BasisXform(-inv[2]);
+
+ return inv;
+ }
+
+ private real_t BasisDeterminant()
+ {
+ return x.x * y.y - x.y * y.x;
+ }
+
+ public Vector2 BasisXform(Vector2 v)
+ {
+ return new Vector2(Tdotx(v), Tdoty(v));
+ }
+
+ public Vector2 BasisXformInv(Vector2 v)
+ {
+ return new Vector2(x.Dot(v), y.Dot(v));
+ }
+
+ public Transform2D InterpolateWith(Transform2D m, real_t c)
+ {
+ real_t r1 = Rotation;
+ real_t r2 = m.Rotation;
+
+ Vector2 s1 = Scale;
+ Vector2 s2 = m.Scale;
+
+ // Slerp rotation
+ var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1));
+ var v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2));
+
+ real_t dot = v1.Dot(v2);
+
+ // Clamp dot to [-1, 1]
+ dot = dot < -1.0f ? -1.0f : (dot > 1.0f ? 1.0f : dot);
+
+ Vector2 v;
+
+ if (dot > 0.9995f)
+ {
+ // Linearly interpolate to avoid numerical precision issues
+ v = v1.LinearInterpolate(v2, c).Normalized();
+ }
+ else
+ {
+ real_t 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
+ var res = new Transform2D(Mathf.Atan2(v.y, v.x), p1.LinearInterpolate(p2, c));
+ Vector2 scale = s1.LinearInterpolate(s2, c);
+ res.x *= scale;
+ res.y *= scale;
+
+ return res;
+ }
+
+ public Transform2D Inverse()
+ {
+ var inv = this;
+
+ // Swap
+ real_t temp = inv.x.y;
+ inv.x.y = inv.y.x;
+ inv.y.x = temp;
+
+ inv.origin = inv.BasisXform(-inv.origin);
+
+ return inv;
+ }
+
+ public Transform2D Orthonormalized()
+ {
+ var 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(real_t phi)
+ {
+ return this * new Transform2D(phi, new Vector2());
+ }
+
+ public Transform2D Scaled(Vector2 scale)
+ {
+ var copy = this;
+ copy.x *= scale;
+ copy.y *= scale;
+ copy.origin *= scale;
+ return copy;
+ }
+
+ private void ScaleBasis(Vector2 scale)
+ {
+ x.x *= scale.x;
+ x.y *= scale.y;
+ y.x *= scale.x;
+ y.y *= scale.y;
+ }
+
+ private real_t Tdotx(Vector2 with)
+ {
+ return this[0, 0] * with[0] + this[1, 0] * with[1];
+ }
+
+ private real_t Tdoty(Vector2 with)
+ {
+ return this[0, 1] * with[0] + this[1, 1] * with[1];
+ }
+
+ public Transform2D Translated(Vector2 offset)
+ {
+ var copy = this;
+ copy.origin += copy.BasisXform(offset);
+ return copy;
+ }
+
+ public Vector2 Xform(Vector2 v)
+ {
+ return new Vector2(Tdotx(v), Tdoty(v)) + origin;
+ }
+
+ public Vector2 XformInv(Vector2 v)
+ {
+ Vector2 vInv = v - origin;
+ return new Vector2(x.Dot(vInv), y.Dot(vInv));
+ }
+
+ // Constants
+ private static readonly Transform2D _identity = new Transform2D(1, 0, 0, 1, 0, 0);
+ private static readonly Transform2D _flipX = new Transform2D(-1, 0, 0, 1, 0, 0);
+ private static readonly Transform2D _flipY = new Transform2D(1, 0, 0, -1, 0, 0);
+
+ public static Transform2D Identity => _identity;
+ public static Transform2D FlipX => _flipX;
+ public static Transform2D FlipY => _flipY;
+
+ // Constructors
+ public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 originPos)
+ {
+ x = xAxis;
+ y = yAxis;
+ origin = originPos;
+ }
+
+ // Arguments are named such that xy is equal to calling x.y
+ public Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy)
+ {
+ x = new Vector2(xx, xy);
+ y = new Vector2(yx, yy);
+ origin = new Vector2(ox, oy);
+ }
+
+ public Transform2D(real_t rot, Vector2 pos)
+ {
+ x.x = y.y = Mathf.Cos(rot);
+ x.y = y.x = Mathf.Sin(rot);
+ y.x *= -1;
+ origin = pos;
+ }
+
+ public static Transform2D operator *(Transform2D left, Transform2D right)
+ {
+ left.origin = left.Xform(right.origin);
+
+ real_t x0 = left.Tdotx(right.x);
+ real_t x1 = left.Tdoty(right.x);
+ real_t y0 = left.Tdotx(right.y);
+ real_t 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)
+ {
+ return obj is Transform2D transform2D && Equals(transform2D);
+ }
+
+ public bool Equals(Transform2D other)
+ {
+ return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin);
+ }
+
+ public bool IsEqualApprox(Transform2D other)
+ {
+ return x.IsEqualApprox(other.x) && y.IsEqualApprox(other.y) && origin.IsEqualApprox(other.origin);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ y.GetHashCode() ^ origin.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ x.ToString(),
+ y.ToString(),
+ origin.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ x.ToString(format),
+ y.ToString(format),
+ origin.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
new file mode 100644
index 0000000000..f92453f546
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -0,0 +1,489 @@
+// file: core/math/math_2d.h
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/math/math_2d.cpp
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ /// <summary>
+ /// 2-element structure that can be used to represent positions in 2D space or any other pair of numeric values.
+ /// </summary>
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector2 : IEquatable<Vector2>
+ {
+ public enum Axis
+ {
+ X = 0,
+ Y
+ }
+
+ public real_t x;
+ public real_t y;
+
+ public real_t 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()
+ {
+ real_t lengthsq = LengthSquared();
+
+ if (lengthsq == 0)
+ {
+ x = y = 0f;
+ }
+ else
+ {
+ real_t length = Mathf.Sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ }
+ }
+
+ public real_t Cross(Vector2 b)
+ {
+ return x * b.y - y * b.x;
+ }
+
+ public Vector2 Abs()
+ {
+ return new Vector2(Mathf.Abs(x), Mathf.Abs(y));
+ }
+
+ public real_t Angle()
+ {
+ return Mathf.Atan2(y, x);
+ }
+
+ public real_t AngleTo(Vector2 to)
+ {
+ return Mathf.Atan2(Cross(to), Dot(to));
+ }
+
+ public real_t AngleToPoint(Vector2 to)
+ {
+ return Mathf.Atan2(y - to.y, x - to.x);
+ }
+
+ public real_t Aspect()
+ {
+ return x / y;
+ }
+
+ public Vector2 Bounce(Vector2 n)
+ {
+ return -Reflect(n);
+ }
+
+ public Vector2 Ceil()
+ {
+ return new Vector2(Mathf.Ceil(x), Mathf.Ceil(y));
+ }
+
+ public Vector2 Clamped(real_t length)
+ {
+ var v = this;
+ real_t l = Length();
+
+ if (l > 0 && length < l)
+ {
+ v /= l;
+ v *= length;
+ }
+
+ return v;
+ }
+
+ public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t)
+ {
+ var p0 = preA;
+ var p1 = this;
+ var p2 = b;
+ var p3 = postB;
+
+ real_t t2 = t * t;
+ real_t 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 Vector2 DirectionTo(Vector2 b)
+ {
+ return new Vector2(b.x - x, b.y - y).Normalized();
+ }
+
+ public real_t DistanceSquaredTo(Vector2 to)
+ {
+ return (x - to.x) * (x - to.x) + (y - to.y) * (y - to.y);
+ }
+
+ public real_t DistanceTo(Vector2 to)
+ {
+ return Mathf.Sqrt((x - to.x) * (x - to.x) + (y - to.y) * (y - to.y));
+ }
+
+ public real_t Dot(Vector2 with)
+ {
+ return x * with.x + y * with.y;
+ }
+
+ public Vector2 Floor()
+ {
+ return new Vector2(Mathf.Floor(x), Mathf.Floor(y));
+ }
+
+ public bool IsNormalized()
+ {
+ return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
+ }
+
+ public real_t Length()
+ {
+ return Mathf.Sqrt(x * x + y * y);
+ }
+
+ public real_t LengthSquared()
+ {
+ return x * x + y * y;
+ }
+
+ public Vector2 LinearInterpolate(Vector2 b, real_t t)
+ {
+ var res = this;
+
+ res.x += t * (b.x - x);
+ res.y += t * (b.y - y);
+
+ return res;
+ }
+
+ public Vector2 MoveToward(Vector2 to, real_t delta)
+ {
+ var v = this;
+ var vd = to - v;
+ var len = vd.Length();
+ return len <= delta || len < Mathf.Epsilon ? to : v + vd / len * delta;
+ }
+
+ public Vector2 Normalized()
+ {
+ var v = this;
+ v.Normalize();
+ return v;
+ }
+
+ public Vector2 PosMod(real_t mod)
+ {
+ Vector2 v;
+ v.x = Mathf.PosMod(x, mod);
+ v.y = Mathf.PosMod(y, mod);
+ return v;
+ }
+
+ public Vector2 PosMod(Vector2 modv)
+ {
+ Vector2 v;
+ v.x = Mathf.PosMod(x, modv.x);
+ v.y = Mathf.PosMod(y, modv.y);
+ return v;
+ }
+
+ public Vector2 Project(Vector2 onNormal)
+ {
+ return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
+ }
+
+ public Vector2 Reflect(Vector2 n)
+ {
+ return 2.0f * n * Dot(n) - this;
+ }
+
+ public Vector2 Rotated(real_t phi)
+ {
+ real_t rads = Angle() + phi;
+ return new Vector2(Mathf.Cos(rads), Mathf.Sin(rads)) * Length();
+ }
+
+ public Vector2 Round()
+ {
+ return new Vector2(Mathf.Round(x), Mathf.Round(y));
+ }
+
+ [Obsolete("Set is deprecated. Use the Vector2(" + nameof(real_t) + ", " + nameof(real_t) + ") constructor instead.", error: true)]
+ public void Set(real_t x, real_t y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+ [Obsolete("Set is deprecated. Use the Vector2(" + nameof(Vector2) + ") constructor instead.", error: true)]
+ public void Set(Vector2 v)
+ {
+ x = v.x;
+ y = v.y;
+ }
+
+ public Vector2 Sign()
+ {
+ Vector2 v;
+ v.x = Mathf.Sign(x);
+ v.y = Mathf.Sign(y);
+ return v;
+ }
+
+ public Vector2 Slerp(Vector2 b, real_t t)
+ {
+ real_t theta = AngleTo(b);
+ return Rotated(theta * t);
+ }
+
+ 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);
+ }
+
+ // Constants
+ private static readonly Vector2 _zero = new Vector2(0, 0);
+ private static readonly Vector2 _one = new Vector2(1, 1);
+ private static readonly Vector2 _negOne = new Vector2(-1, -1);
+ private static readonly Vector2 _inf = new Vector2(Mathf.Inf, Mathf.Inf);
+
+ private static readonly Vector2 _up = new Vector2(0, -1);
+ private static readonly Vector2 _down = new Vector2(0, 1);
+ private static readonly Vector2 _right = new Vector2(1, 0);
+ private static readonly Vector2 _left = new Vector2(-1, 0);
+
+ public static Vector2 Zero { get { return _zero; } }
+ public static Vector2 NegOne { get { return _negOne; } }
+ public static Vector2 One { get { return _one; } }
+ public static Vector2 Inf { get { return _inf; } }
+
+ public static Vector2 Up { get { return _up; } }
+ public static Vector2 Down { get { return _down; } }
+ public static Vector2 Right { get { return _right; } }
+ public static Vector2 Left { get { return _left; } }
+
+ // Constructors
+ public Vector2(real_t x, real_t y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+ public Vector2(Vector2 v)
+ {
+ x = v.x;
+ y = v.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, real_t scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ return vec;
+ }
+
+ public static Vector2 operator *(real_t 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, real_t 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 Vector2 operator %(Vector2 vec, real_t divisor)
+ {
+ vec.x %= divisor;
+ vec.y %= divisor;
+ return vec;
+ }
+
+ public static Vector2 operator %(Vector2 vec, Vector2 divisorv)
+ {
+ vec.x %= divisorv.x;
+ vec.y %= divisorv.y;
+ return vec;
+ }
+
+ 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 (Mathf.IsEqualApprox(left.x, right.x))
+ {
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >(Vector2 left, Vector2 right)
+ {
+ if (Mathf.IsEqualApprox(left.x, right.x))
+ {
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public static bool operator <=(Vector2 left, Vector2 right)
+ {
+ if (Mathf.IsEqualApprox(left.x, right.x))
+ {
+ return left.y <= right.y;
+ }
+
+ return left.x <= right.x;
+ }
+
+ public static bool operator >=(Vector2 left, Vector2 right)
+ {
+ if (Mathf.IsEqualApprox(left.x, right.x))
+ {
+ return left.y >= right.y;
+ }
+
+ 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 bool IsEqualApprox(Vector2 other)
+ {
+ return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y);
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ x.ToString(),
+ y.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1})", new object[]
+ {
+ x.ToString(format),
+ y.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
new file mode 100644
index 0000000000..fded34002d
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -0,0 +1,553 @@
+// file: core/math/vector3.h
+// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
+// file: core/math/vector3.cpp
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+using System;
+using System.Runtime.InteropServices;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ /// <summary>
+ /// 3-element structure that can be used to represent positions in 3D space or any other pair of numeric values.
+ /// </summary>
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector3 : IEquatable<Vector3>
+ {
+ public enum Axis
+ {
+ X = 0,
+ Y,
+ Z
+ }
+
+ public real_t x;
+ public real_t y;
+ public real_t z;
+
+ public real_t 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()
+ {
+ real_t lengthsq = LengthSquared();
+
+ if (lengthsq == 0)
+ {
+ x = y = z = 0f;
+ }
+ else
+ {
+ real_t length = Mathf.Sqrt(lengthsq);
+ x /= length;
+ y /= length;
+ z /= length;
+ }
+ }
+
+ public Vector3 Abs()
+ {
+ return new Vector3(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z));
+ }
+
+ public real_t AngleTo(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 CubicInterpolate(Vector3 b, Vector3 preA, Vector3 postB, real_t t)
+ {
+ var p0 = preA;
+ var p1 = this;
+ var p2 = b;
+ var p3 = postB;
+
+ real_t t2 = t * t;
+ real_t 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 Vector3 DirectionTo(Vector3 b)
+ {
+ return new Vector3(b.x - x, b.y - y, b.z - z).Normalized();
+ }
+
+ public real_t DistanceSquaredTo(Vector3 b)
+ {
+ return (b - this).LengthSquared();
+ }
+
+ public real_t DistanceTo(Vector3 b)
+ {
+ return (b - this).Length();
+ }
+
+ public real_t 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 IsNormalized()
+ {
+ return Mathf.Abs(LengthSquared() - 1.0f) < Mathf.Epsilon;
+ }
+
+ public real_t Length()
+ {
+ real_t x2 = x * x;
+ real_t y2 = y * y;
+ real_t z2 = z * z;
+
+ return Mathf.Sqrt(x2 + y2 + z2);
+ }
+
+ public real_t LengthSquared()
+ {
+ real_t x2 = x * x;
+ real_t y2 = y * y;
+ real_t z2 = z * z;
+
+ return x2 + y2 + z2;
+ }
+
+ public Vector3 LinearInterpolate(Vector3 b, real_t t)
+ {
+ return new Vector3
+ (
+ x + t * (b.x - x),
+ y + t * (b.y - y),
+ z + t * (b.z - z)
+ );
+ }
+
+ public Vector3 MoveToward(Vector3 to, real_t delta)
+ {
+ var v = this;
+ var vd = to - v;
+ var len = vd.Length();
+ return len <= delta || len < Mathf.Epsilon ? to : v + vd / len * delta;
+ }
+
+ public Axis MaxAxis()
+ {
+ return x < y ? (y < z ? Axis.Z : Axis.Y) : (x < z ? Axis.Z : Axis.X);
+ }
+
+ public Axis MinAxis()
+ {
+ return x < y ? (x < z ? Axis.X : Axis.Z) : (y < z ? Axis.Y : Axis.Z);
+ }
+
+ public Vector3 Normalized()
+ {
+ var v = this;
+ v.Normalize();
+ return v;
+ }
+
+ public Basis Outer(Vector3 b)
+ {
+ return new Basis(
+ x * b.x, x * b.y, x * b.z,
+ y * b.x, y * b.y, y * b.z,
+ z * b.x, z * b.y, z * b.z
+ );
+ }
+
+ public Vector3 PosMod(real_t mod)
+ {
+ Vector3 v;
+ v.x = Mathf.PosMod(x, mod);
+ v.y = Mathf.PosMod(y, mod);
+ v.z = Mathf.PosMod(z, mod);
+ return v;
+ }
+
+ public Vector3 PosMod(Vector3 modv)
+ {
+ Vector3 v;
+ v.x = Mathf.PosMod(x, modv.x);
+ v.y = Mathf.PosMod(y, modv.y);
+ v.z = Mathf.PosMod(z, modv.z);
+ return v;
+ }
+
+ public Vector3 Project(Vector3 onNormal)
+ {
+ return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
+ }
+
+ public Vector3 Reflect(Vector3 n)
+ {
+#if DEBUG
+ if (!n.IsNormalized())
+ throw new ArgumentException("Argument is not normalized", nameof(n));
+#endif
+ return 2.0f * n * Dot(n) - this;
+ }
+
+ public Vector3 Round()
+ {
+ return new Vector3(Mathf.Round(x), Mathf.Round(y), Mathf.Round(z));
+ }
+
+ public Vector3 Rotated(Vector3 axis, real_t phi)
+ {
+ return new Basis(axis, phi).Xform(this);
+ }
+
+ [Obsolete("Set is deprecated. Use the Vector3(" + nameof(real_t) + ", " + nameof(real_t) + ", " + nameof(real_t) + ") constructor instead.", error: true)]
+ public void Set(real_t x, real_t y, real_t z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+ [Obsolete("Set is deprecated. Use the Vector3(" + nameof(Vector3) + ") constructor instead.", error: true)]
+ public void Set(Vector3 v)
+ {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ }
+
+ public Vector3 Sign()
+ {
+ Vector3 v;
+ v.x = Mathf.Sign(x);
+ v.y = Mathf.Sign(y);
+ v.z = Mathf.Sign(z);
+ return v;
+ }
+
+ public Vector3 Slerp(Vector3 b, real_t t)
+ {
+#if DEBUG
+ if (!IsNormalized())
+ throw new InvalidOperationException("Vector3 is not normalized");
+#endif
+ real_t theta = AngleTo(b);
+ return Rotated(Cross(b), theta * t);
+ }
+
+ 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 ToDiagonalMatrix()
+ {
+ return new Basis(
+ x, 0f, 0f,
+ 0f, y, 0f,
+ 0f, 0f, z
+ );
+ }
+
+ // Constants
+ private static readonly Vector3 _zero = new Vector3(0, 0, 0);
+ private static readonly Vector3 _one = new Vector3(1, 1, 1);
+ private static readonly Vector3 _negOne = new Vector3(-1, -1, -1);
+ private static readonly Vector3 _inf = new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf);
+
+ private static readonly Vector3 _up = new Vector3(0, 1, 0);
+ private static readonly Vector3 _down = new Vector3(0, -1, 0);
+ private static readonly Vector3 _right = new Vector3(1, 0, 0);
+ private static readonly Vector3 _left = new Vector3(-1, 0, 0);
+ private static readonly Vector3 _forward = new Vector3(0, 0, -1);
+ private static readonly Vector3 _back = new Vector3(0, 0, 1);
+
+ public static Vector3 Zero { get { return _zero; } }
+ public static Vector3 One { get { return _one; } }
+ public static Vector3 NegOne { get { return _negOne; } }
+ public static Vector3 Inf { get { return _inf; } }
+
+ public static Vector3 Up { get { return _up; } }
+ public static Vector3 Down { get { return _down; } }
+ public static Vector3 Right { get { return _right; } }
+ public static Vector3 Left { get { return _left; } }
+ public static Vector3 Forward { get { return _forward; } }
+ public static Vector3 Back { get { return _back; } }
+
+ // Constructors
+ public Vector3(real_t x, real_t y, real_t z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+ public Vector3(Vector3 v)
+ {
+ x = v.x;
+ y = v.y;
+ z = v.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, real_t scale)
+ {
+ vec.x *= scale;
+ vec.y *= scale;
+ vec.z *= scale;
+ return vec;
+ }
+
+ public static Vector3 operator *(real_t 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, real_t 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 Vector3 operator %(Vector3 vec, real_t divisor)
+ {
+ vec.x %= divisor;
+ vec.y %= divisor;
+ vec.z %= divisor;
+ return vec;
+ }
+
+ public static Vector3 operator %(Vector3 vec, Vector3 divisorv)
+ {
+ vec.x %= divisorv.x;
+ vec.y %= divisorv.y;
+ vec.z %= divisorv.z;
+ return vec;
+ }
+
+ 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 (Mathf.IsEqualApprox(left.x, right.x))
+ {
+ if (Mathf.IsEqualApprox(left.y, right.y))
+ return left.z < right.z;
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >(Vector3 left, Vector3 right)
+ {
+ if (Mathf.IsEqualApprox(left.x, right.x))
+ {
+ if (Mathf.IsEqualApprox(left.y, right.y))
+ return left.z > right.z;
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public static bool operator <=(Vector3 left, Vector3 right)
+ {
+ if (Mathf.IsEqualApprox(left.x, right.x))
+ {
+ if (Mathf.IsEqualApprox(left.y, right.y))
+ return left.z <= right.z;
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >=(Vector3 left, Vector3 right)
+ {
+ if (Mathf.IsEqualApprox(left.x, right.x))
+ {
+ if (Mathf.IsEqualApprox(left.y, right.y))
+ return left.z >= right.z;
+ 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 bool IsEqualApprox(Vector3 other)
+ {
+ return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(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[]
+ {
+ x.ToString(),
+ y.ToString(),
+ z.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ x.ToString(format),
+ y.ToString(format),
+ z.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
new file mode 100644
index 0000000000..5419cd06e6
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{AEBF0036-DA76-4341-B651-A3F2856AB2FA}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <OutputPath>bin/$(Configuration)</OutputPath>
+ <RootNamespace>Godot</RootNamespace>
+ <AssemblyName>GodotSharp</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
+ <BaseIntermediateOutputPath>obj</BaseIntermediateOutputPath>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>portable</DebugType>
+ <Optimize>false</Optimize>
+ <DefineConstants>$(GodotDefineConstants);GODOT;DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>portable</DebugType>
+ <Optimize>true</Optimize>
+ <DefineConstants>$(GodotDefineConstants);GODOT;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Core\AABB.cs" />
+ <Compile Include="Core\Array.cs" />
+ <Compile Include="Core\Attributes\ExportAttribute.cs" />
+ <Compile Include="Core\Attributes\GodotMethodAttribute.cs" />
+ <Compile Include="Core\Attributes\RPCAttributes.cs" />
+ <Compile Include="Core\Attributes\SignalAttribute.cs" />
+ <Compile Include="Core\Attributes\ToolAttribute.cs" />
+ <Compile Include="Core\Basis.cs" />
+ <Compile Include="Core\Color.cs" />
+ <Compile Include="Core\Colors.cs" />
+ <Compile Include="Core\DebuggingUtils.cs" />
+ <Compile Include="Core\Dictionary.cs" />
+ <Compile Include="Core\Dispatcher.cs" />
+ <Compile Include="Core\DynamicObject.cs" />
+ <Compile Include="Core\Extensions\NodeExtensions.cs" />
+ <Compile Include="Core\Extensions\ObjectExtensions.cs" />
+ <Compile Include="Core\Extensions\ResourceLoaderExtensions.cs" />
+ <Compile Include="Core\GD.cs" />
+ <Compile Include="Core\GodotSynchronizationContext.cs" />
+ <Compile Include="Core\GodotTaskScheduler.cs" />
+ <Compile Include="Core\GodotTraceListener.cs" />
+ <Compile Include="Core\Interfaces\IAwaitable.cs" />
+ <Compile Include="Core\Interfaces\IAwaiter.cs" />
+ <Compile Include="Core\Interfaces\ISerializationListener.cs" />
+ <Compile Include="Core\MarshalUtils.cs" />
+ <Compile Include="Core\Mathf.cs" />
+ <Compile Include="Core\MathfEx.cs" />
+ <Compile Include="Core\NodePath.cs" />
+ <Compile Include="Core\Object.base.cs" />
+ <Compile Include="Core\Plane.cs" />
+ <Compile Include="Core\Quat.cs" />
+ <Compile Include="Core\Rect2.cs" />
+ <Compile Include="Core\RID.cs" />
+ <Compile Include="Core\SignalAwaiter.cs" />
+ <Compile Include="Core\StringExtensions.cs" />
+ <Compile Include="Core\Transform.cs" />
+ <Compile Include="Core\Transform2D.cs" />
+ <Compile Include="Core\Vector2.cs" />
+ <Compile Include="Core\Vector3.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <!--
+ We import a props file with auto-generated includes. This works well with Rider.
+ However, Visual Studio and MonoDevelop won't list them in the solution explorer.
+ We can't use wildcards as there may be undesired old files still hanging around.
+ Fortunately code completion, go to definition and such still work.
+ -->
+ <Import Project="Generated\GeneratedIncludes.props" />
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..f84e0183f6
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Properties/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("GodotSharp")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+[assembly: InternalsVisibleTo("GodotSharpEditor")]
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
new file mode 100644
index 0000000000..22853797c1
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{8FBEC238-D944-4074-8548-B3B524305905}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <OutputPath>bin/$(Configuration)</OutputPath>
+ <RootNamespace>Godot</RootNamespace>
+ <AssemblyName>GodotSharpEditor</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
+ <BaseIntermediateOutputPath>obj</BaseIntermediateOutputPath>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>portable</DebugType>
+ <Optimize>false</Optimize>
+ <DefineConstants>$(GodotDefineConstants);GODOT;DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>portable</DebugType>
+ <Optimize>true</Optimize>
+ <DefineConstants>$(GodotDefineConstants);GODOT;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <Import Project="Generated\GeneratedIncludes.props" />
+ <ItemGroup>
+ <ProjectReference Include="..\GodotSharp\GodotSharp.csproj">
+ <Private>False</Private>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..3684b7a3cb
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/Properties/AssemblyInfo.cs
@@ -0,0 +1,25 @@
+using System.Reflection;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("GodotSharpEditor")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]