summaryrefslogtreecommitdiff
path: root/modules/mono/glue/Managed/Files
diff options
context:
space:
mode:
authorIgnacio Etcheverry <neikeq@users.noreply.github.com>2018-09-12 22:08:54 +0200
committerGitHub <noreply@github.com>2018-09-12 22:08:54 +0200
commit8704b7787624da98cece35c1b8b8e51bde709488 (patch)
tree398ab2ee1e88e3b853c6157458362dced14d64da /modules/mono/glue/Managed/Files
parent4cd3dd821932660a7d89d90da7626fa46c07ac39 (diff)
parent995a40e8efa9f7a868a6706e30c476305e16180b (diff)
Merge pull request #22007 from neikeq/<name_of_your_new_branch>
Move modules/mono/glue/cs_files to modules/mono/glue/Managed/Files
Diffstat (limited to 'modules/mono/glue/Managed/Files')
-rw-r--r--modules/mono/glue/Managed/Files/AABB.cs466
-rw-r--r--modules/mono/glue/Managed/Files/Array.cs335
-rw-r--r--modules/mono/glue/Managed/Files/Attributes/ExportAttribute.cs17
-rw-r--r--modules/mono/glue/Managed/Files/Attributes/GodotMethodAttribute.cs17
-rw-r--r--modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs25
-rw-r--r--modules/mono/glue/Managed/Files/Attributes/SignalAttribute.cs9
-rw-r--r--modules/mono/glue/Managed/Files/Attributes/ToolAttribute.cs7
-rw-r--r--modules/mono/glue/Managed/Files/Basis.cs572
-rw-r--r--modules/mono/glue/Managed/Files/Color.cs647
-rw-r--r--modules/mono/glue/Managed/Files/DebuggingUtils.cs83
-rw-r--r--modules/mono/glue/Managed/Files/Dictionary.cs400
-rw-r--r--modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs45
-rw-r--r--modules/mono/glue/Managed/Files/Extensions/ObjectExtensions.cs21
-rw-r--r--modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs10
-rw-r--r--modules/mono/glue/Managed/Files/GD.cs242
-rw-r--r--modules/mono/glue/Managed/Files/GodotSynchronizationContext.cs25
-rw-r--r--modules/mono/glue/Managed/Files/GodotTaskScheduler.cs94
-rw-r--r--modules/mono/glue/Managed/Files/Interfaces/IAwaitable.cs12
-rw-r--r--modules/mono/glue/Managed/Files/Interfaces/IAwaiter.cs18
-rw-r--r--modules/mono/glue/Managed/Files/MarshalUtils.cs18
-rw-r--r--modules/mono/glue/Managed/Files/Mathf.cs301
-rw-r--r--modules/mono/glue/Managed/Files/MathfEx.cs39
-rw-r--r--modules/mono/glue/Managed/Files/NodePath.cs147
-rw-r--r--modules/mono/glue/Managed/Files/Object.base.cs88
-rw-r--r--modules/mono/glue/Managed/Files/Plane.cs229
-rw-r--r--modules/mono/glue/Managed/Files/Quat.cs378
-rw-r--r--modules/mono/glue/Managed/Files/RID.cs76
-rw-r--r--modules/mono/glue/Managed/Files/Rect2.cs256
-rw-r--r--modules/mono/glue/Managed/Files/SignalAwaiter.cs60
-rw-r--r--modules/mono/glue/Managed/Files/StringExtensions.cs981
-rw-r--r--modules/mono/glue/Managed/Files/Transform.cs191
-rw-r--r--modules/mono/glue/Managed/Files/Transform2D.cs360
-rw-r--r--modules/mono/glue/Managed/Files/Vector2.cs417
-rw-r--r--modules/mono/glue/Managed/Files/Vector3.cs481
34 files changed, 7067 insertions, 0 deletions
diff --git a/modules/mono/glue/Managed/Files/AABB.cs b/modules/mono/glue/Managed/Files/AABB.cs
new file mode 100644
index 0000000000..66490b5e25
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/AABB.cs
@@ -0,0 +1,466 @@
+// file: core/math/aabb.h
+// commit: 7ad14e7a3e6f87ddc450f7e34621eb5200808451
+// file: core/math/aabb.cpp
+// commit: bd282ff43f23fe845f29a3e25c8efc01bd65ffb0
+// file: core/variant_call.cpp
+// commit: 5ad9be4c24e9d7dc5672fdc42cea896622fe5685
+using System;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ 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 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 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/Managed/Files/Array.cs b/modules/mono/glue/Managed/Files/Array.cs
new file mode 100644
index 0000000000..c80cb7cc83
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Array.cs
@@ -0,0 +1,335 @@
+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<object>, ICollection<object>, IEnumerable<object>, IDisposable
+ {
+ ArraySafeHandle safeHandle;
+ bool disposed = false;
+
+ public Array()
+ {
+ safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
+ }
+
+ internal Array(ArraySafeHandle handle)
+ {
+ safeHandle = handle;
+ }
+
+ internal Array(IntPtr handle)
+ {
+ safeHandle = new ArraySafeHandle(handle);
+ }
+
+ internal IntPtr GetPtr()
+ {
+ return safeHandle.DangerousGetHandle();
+ }
+
+ public void Dispose()
+ {
+ if (disposed)
+ return;
+
+ if (safeHandle != null)
+ {
+ safeHandle.Dispose();
+ safeHandle = null;
+ }
+
+ disposed = true;
+ }
+
+ public object this[int index]
+ {
+ get
+ {
+ return godot_icall_Array_At(GetPtr(), index);
+ }
+ set
+ {
+ godot_icall_Array_SetAt(GetPtr(), index, value);
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ return godot_icall_Array_Count(GetPtr());
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public void Add(object item)
+ {
+ godot_icall_Array_Add(GetPtr(), item);
+ }
+
+ public void Clear()
+ {
+ godot_icall_Array_Clear(GetPtr());
+ }
+
+ public bool Contains(object item)
+ {
+ return godot_icall_Array_Contains(GetPtr(), item);
+ }
+
+ public void CopyTo(object[] 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.");
+
+ // Internal call may throw ArgumentException
+ godot_icall_Array_CopyTo(GetPtr(), array, arrayIndex);
+ }
+
+ public IEnumerator<object> GetEnumerator()
+ {
+ int count = Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ yield return godot_icall_Array_At(GetPtr(), i);
+ }
+ }
+
+ public int IndexOf(object item)
+ {
+ return godot_icall_Array_IndexOf(GetPtr(), item);
+ }
+
+ public void Insert(int index, object item)
+ {
+ godot_icall_Array_Insert(GetPtr(), index, item);
+ }
+
+ public bool Remove(object item)
+ {
+ return godot_icall_Array_Remove(GetPtr(), item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ godot_icall_Array_RemoveAt(GetPtr(), index);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ [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 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 void 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, object[] array, int arrayIndex);
+
+ [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);
+ }
+
+ public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
+ {
+ Array objectArray;
+
+ public Array()
+ {
+ objectArray = new Array();
+ }
+
+ public Array(Array array)
+ {
+ objectArray = array;
+ }
+
+ internal Array(IntPtr handle)
+ {
+ objectArray = new Array(handle);
+ }
+
+ internal Array(ArraySafeHandle handle)
+ {
+ objectArray = new Array(handle);
+ }
+
+ public static explicit operator Array(Array<T> from)
+ {
+ return from.objectArray;
+ }
+
+ public T this[int index]
+ {
+ get
+ {
+ return (T)objectArray[index];
+ }
+ set
+ {
+ objectArray[index] = value;
+ }
+ }
+
+ 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)objectArray[i];
+ arrayIndex++;
+ }
+ }
+
+ public IEnumerator<T> GetEnumerator()
+ {
+ int count = objectArray.Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ yield return (T)objectArray[i];
+ }
+ }
+
+ public int IndexOf(T item)
+ {
+ return objectArray.IndexOf(item);
+ }
+
+ public void Insert(int index, T item)
+ {
+ objectArray.Insert(index, item);
+ }
+
+ public bool Remove(T item)
+ {
+ return objectArray.Remove(item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ objectArray.RemoveAt(index);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ internal IntPtr GetPtr()
+ {
+ return objectArray.GetPtr();
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/Attributes/ExportAttribute.cs b/modules/mono/glue/Managed/Files/Attributes/ExportAttribute.cs
new file mode 100644
index 0000000000..6adf044886
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/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/Managed/Files/Attributes/GodotMethodAttribute.cs b/modules/mono/glue/Managed/Files/Attributes/GodotMethodAttribute.cs
new file mode 100644
index 0000000000..55848769d5
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/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/Managed/Files/Attributes/RPCAttributes.cs b/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs
new file mode 100644
index 0000000000..6bf9560bfa
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class RemoteAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class SyncAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class MasterAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class SlaveAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class RemoteSyncAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class MasterSyncAttribute : Attribute {}
+
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
+ public class SlaveSyncAttribute : Attribute {}
+}
diff --git a/modules/mono/glue/Managed/Files/Attributes/SignalAttribute.cs b/modules/mono/glue/Managed/Files/Attributes/SignalAttribute.cs
new file mode 100644
index 0000000000..3957387be9
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Attributes/SignalAttribute.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Delegate)]
+ public class SignalAttribute : Attribute
+ {
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/Attributes/ToolAttribute.cs b/modules/mono/glue/Managed/Files/Attributes/ToolAttribute.cs
new file mode 100644
index 0000000000..d0437409af
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Attributes/ToolAttribute.cs
@@ -0,0 +1,7 @@
+using System;
+
+namespace Godot
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class ToolAttribute : Attribute {}
+}
diff --git a/modules/mono/glue/Managed/Files/Basis.cs b/modules/mono/glue/Managed/Files/Basis.cs
new file mode 100644
index 0000000000..ec96a9e2fa
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Basis.cs
@@ -0,0 +1,572 @@
+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
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Basis : IEquatable<Basis>
+ {
+ private static readonly Basis identity = new Basis
+ (
+ new Vector3(1f, 0f, 0f),
+ new Vector3(0f, 1f, 0f),
+ new Vector3(0f, 0f, 1f)
+ );
+
+ private static readonly Basis[] orthoBases = {
+ new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f),
+ new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f),
+ new Basis(-1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f),
+ new Basis(0f, 1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f),
+ new Basis(1f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f),
+ new Basis(0f, 0f, 1f, 1f, 0f, 0f, 0f, 1f, 0f),
+ new Basis(-1f, 0f, 0f, 0f, 0f, 1f, 0f, 1f, 0f),
+ new Basis(0f, 0f, -1f, -1f, 0f, 0f, 0f, 1f, 0f),
+ new Basis(1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, -1f),
+ new Basis(0f, 1f, 0f, 1f, 0f, 0f, 0f, 0f, -1f),
+ new Basis(-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, -1f),
+ new Basis(0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, -1f),
+ new Basis(1f, 0f, 0f, 0f, 0f, 1f, 0f, -1f, 0f),
+ new Basis(0f, 0f, -1f, 1f, 0f, 0f, 0f, -1f, 0f),
+ new Basis(-1f, 0f, 0f, 0f, 0f, -1f, 0f, -1f, 0f),
+ new Basis(0f, 0f, 1f, -1f, 0f, 0f, 0f, -1f, 0f),
+ new Basis(0f, 0f, 1f, 0f, 1f, 0f, -1f, 0f, 0f),
+ new Basis(0f, -1f, 0f, 0f, 0f, 1f, -1f, 0f, 0f),
+ new Basis(0f, 0f, -1f, 0f, -1f, 0f, -1f, 0f, 0f),
+ new Basis(0f, 1f, 0f, 0f, 0f, -1f, -1f, 0f, 0f),
+ new Basis(0f, 0f, 1f, 0f, -1f, 0f, 1f, 0f, 0f),
+ new Basis(0f, 1f, 0f, 0f, 0f, 1f, 1f, 0f, 0f),
+ new Basis(0f, 0f, -1f, 0f, 1f, 0f, 1f, 0f, 0f),
+ new Basis(0f, -1f, 0f, 0f, 0f, -1f, 1f, 0f, 0f)
+ };
+
+ public Vector3 x
+ {
+ get { return GetAxis(0); }
+ set { SetAxis(0, value); }
+ }
+
+ public Vector3 y
+ {
+ get { return GetAxis(1); }
+ set { SetAxis(1, value); }
+ }
+
+ public Vector3 z
+ {
+ get { return GetAxis(2); }
+ set { SetAxis(2, value); }
+ }
+
+ private Vector3 _x;
+ private Vector3 _y;
+ private Vector3 _z;
+
+ public static Basis Identity
+ {
+ get { return identity; }
+ }
+
+ public Vector3 Scale
+ {
+ get
+ {
+ return new Vector3
+ (
+ new Vector3(this[0, 0], this[1, 0], this[2, 0]).Length(),
+ new Vector3(this[0, 1], this[1, 1], this[2, 1]).Length(),
+ new Vector3(this[0, 2], this[1, 2], this[2, 2]).Length()
+ );
+ }
+ }
+
+ public Vector3 this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return _x;
+ case 1:
+ return _y;
+ case 2:
+ return _z;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ _x = value;
+ return;
+ case 1:
+ _y = value;
+ return;
+ case 2:
+ _z = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public real_t this[int index, int axis]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return _x[axis];
+ case 1:
+ return _y[axis];
+ case 2:
+ return _z[axis];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ _x[axis] = value;
+ return;
+ case 1:
+ _y[axis] = value;
+ return;
+ case 2:
+ _z[axis] = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ internal static Basis CreateFromAxes(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
+ {
+ return new Basis
+ (
+ new Vector3(xAxis.x, yAxis.x, zAxis.x),
+ new Vector3(xAxis.y, yAxis.y, zAxis.y),
+ new Vector3(xAxis.z, yAxis.z, zAxis.z)
+ );
+ }
+
+ public real_t Determinant()
+ {
+ return this[0, 0] * (this[1, 1] * this[2, 2] - this[2, 1] * this[1, 2]) -
+ this[1, 0] * (this[0, 1] * this[2, 2] - this[2, 1] * this[0, 2]) +
+ this[2, 0] * (this[0, 1] * this[1, 2] - this[1, 1] * this[0, 2]);
+ }
+
+ public Vector3 GetAxis(int axis)
+ {
+ return new Vector3(this[0, axis], this[1, axis], this[2, axis]);
+ }
+
+ public void SetAxis(int axis, Vector3 value)
+ {
+ this[0, axis] = value.x;
+ this[1, axis] = value.y;
+ this[2, axis] = value.z;
+ }
+
+ public Vector3 GetEuler()
+ {
+ Basis m = Orthonormalized();
+
+ Vector3 euler;
+ euler.z = 0.0f;
+
+ real_t mxy = m[1, 2];
+
+
+ if (mxy < 1.0f)
+ {
+ if (mxy > -1.0f)
+ {
+ euler.x = Mathf.Asin(-mxy);
+ euler.y = Mathf.Atan2(m[0, 2], m[2, 2]);
+ euler.z = Mathf.Atan2(m[1, 0], m[1, 1]);
+ }
+ else
+ {
+ euler.x = Mathf.Pi * 0.5f;
+ euler.y = -Mathf.Atan2(-m[0, 1], m[0, 0]);
+ }
+ }
+ else
+ {
+ euler.x = -Mathf.Pi * 0.5f;
+ euler.y = -Mathf.Atan2(-m[0, 1], m[0, 0]);
+ }
+
+ return euler;
+ }
+
+ public int GetOrthogonalIndex()
+ {
+ var orth = this;
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ real_t v = orth[i, j];
+
+ if (v > 0.5f)
+ v = 1.0f;
+ else if (v < -0.5f)
+ v = -1.0f;
+ else
+ v = 0f;
+
+ orth[i, j] = v;
+ }
+ }
+
+ for (int i = 0; i < 24; i++)
+ {
+ if (orthoBases[i] == orth)
+ return i;
+ }
+
+ return 0;
+ }
+
+ public Basis Inverse()
+ {
+ var inv = this;
+
+ real_t[] co = {
+ inv[1, 1] * inv[2, 2] - inv[1, 2] * inv[2, 1],
+ inv[1, 2] * inv[2, 0] - inv[1, 0] * inv[2, 2],
+ inv[1, 0] * inv[2, 1] - inv[1, 1] * inv[2, 0]
+ };
+
+ real_t det = inv[0, 0] * co[0] + inv[0, 1] * co[1] + inv[0, 2] * co[2];
+
+ if (det == 0)
+ {
+ return new Basis
+ (
+ real_t.NaN, real_t.NaN, real_t.NaN,
+ real_t.NaN, real_t.NaN, real_t.NaN,
+ real_t.NaN, real_t.NaN, real_t.NaN
+ );
+ }
+
+ real_t s = 1.0f / det;
+
+ inv = new Basis
+ (
+ co[0] * s,
+ inv[0, 2] * inv[2, 1] - inv[0, 1] * inv[2, 2] * s,
+ inv[0, 1] * inv[1, 2] - inv[0, 2] * inv[1, 1] * s,
+ co[1] * s,
+ inv[0, 0] * inv[2, 2] - inv[0, 2] * inv[2, 0] * s,
+ inv[0, 2] * inv[1, 0] - inv[0, 0] * inv[1, 2] * s,
+ co[2] * s,
+ inv[0, 1] * inv[2, 0] - inv[0, 0] * inv[2, 1] * s,
+ inv[0, 0] * inv[1, 1] - inv[0, 1] * inv[1, 0] * s
+ );
+
+ return inv;
+ }
+
+ public Basis Orthonormalized()
+ {
+ Vector3 xAxis = GetAxis(0);
+ Vector3 yAxis = GetAxis(1);
+ Vector3 zAxis = GetAxis(2);
+
+ xAxis.Normalize();
+ yAxis = yAxis - xAxis * xAxis.Dot(yAxis);
+ yAxis.Normalize();
+ zAxis = zAxis - xAxis * xAxis.Dot(zAxis) - yAxis * yAxis.Dot(zAxis);
+ zAxis.Normalize();
+
+ return CreateFromAxes(xAxis, yAxis, zAxis);
+ }
+
+ public Basis Rotated(Vector3 axis, real_t phi)
+ {
+ return new Basis(axis, phi) * this;
+ }
+
+ public Basis Scaled(Vector3 scale)
+ {
+ var m = this;
+
+ m[0, 0] *= scale.x;
+ m[0, 1] *= scale.x;
+ m[0, 2] *= scale.x;
+ m[1, 0] *= scale.y;
+ m[1, 1] *= scale.y;
+ m[1, 2] *= scale.y;
+ m[2, 0] *= scale.z;
+ m[2, 1] *= scale.z;
+ m[2, 2] *= scale.z;
+
+ return m;
+ }
+
+ public real_t Tdotx(Vector3 with)
+ {
+ return this[0, 0] * with[0] + this[1, 0] * with[1] + this[2, 0] * with[2];
+ }
+
+ public real_t Tdoty(Vector3 with)
+ {
+ return this[0, 1] * with[0] + this[1, 1] * with[1] + this[2, 1] * with[2];
+ }
+
+ public real_t Tdotz(Vector3 with)
+ {
+ return this[0, 2] * with[0] + this[1, 2] * with[1] + this[2, 2] * with[2];
+ }
+
+ public Basis Transposed()
+ {
+ var tr = this;
+
+ real_t temp = tr[0, 1];
+ tr[0, 1] = tr[1, 0];
+ tr[1, 0] = temp;
+
+ temp = tr[0, 2];
+ tr[0, 2] = tr[2, 0];
+ tr[2, 0] = temp;
+
+ temp = tr[1, 2];
+ tr[1, 2] = tr[2, 1];
+ tr[2, 1] = temp;
+
+ return tr;
+ }
+
+ public Vector3 Xform(Vector3 v)
+ {
+ return new Vector3
+ (
+ this[0].Dot(v),
+ this[1].Dot(v),
+ this[2].Dot(v)
+ );
+ }
+
+ public Vector3 XformInv(Vector3 v)
+ {
+ return new Vector3
+ (
+ this[0, 0] * v.x + this[1, 0] * v.y + this[2, 0] * v.z,
+ this[0, 1] * v.x + this[1, 1] * v.y + this[2, 1] * v.z,
+ this[0, 2] * v.x + this[1, 2] * v.y + this[2, 2] * v.z
+ );
+ }
+
+ public Quat Quat() {
+ real_t trace = _x[0] + _y[1] + _z[2];
+
+ if (trace > 0.0f) {
+ real_t s = Mathf.Sqrt(trace + 1.0f) * 2f;
+ real_t inv_s = 1f / s;
+ return new Quat(
+ (_z[1] - _y[2]) * inv_s,
+ (_x[2] - _z[0]) * inv_s,
+ (_y[0] - _x[1]) * inv_s,
+ s * 0.25f
+ );
+ }
+
+ if (_x[0] > _y[1] && _x[0] > _z[2]) {
+ real_t s = Mathf.Sqrt(_x[0] - _y[1] - _z[2] + 1.0f) * 2f;
+ real_t inv_s = 1f / s;
+ return new Quat(
+ s * 0.25f,
+ (_x[1] + _y[0]) * inv_s,
+ (_x[2] + _z[0]) * inv_s,
+ (_z[1] - _y[2]) * inv_s
+ );
+ }
+
+ if (_y[1] > _z[2]) {
+ real_t s = Mathf.Sqrt(-_x[0] + _y[1] - _z[2] + 1.0f) * 2f;
+ real_t inv_s = 1f / s;
+ return new Quat(
+ (_x[1] + _y[0]) * inv_s,
+ s * 0.25f,
+ (_y[2] + _z[1]) * inv_s,
+ (_x[2] - _z[0]) * inv_s
+ );
+ } else {
+ real_t s = Mathf.Sqrt(-_x[0] - _y[1] + _z[2] + 1.0f) * 2f;
+ real_t inv_s = 1f / s;
+ return new Quat(
+ (_x[2] + _z[0]) * inv_s,
+ (_y[2] + _z[1]) * inv_s,
+ s * 0.25f,
+ (_y[0] - _x[1]) * inv_s
+ );
+ }
+ }
+
+ public Basis(Quat quat)
+ {
+ 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;
+
+ _x = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
+ _y = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
+ _z = 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)
+ {
+ var axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
+
+ real_t cosine = Mathf.Cos( phi);
+ real_t sine = Mathf.Sin( phi);
+
+ _x = new Vector3
+ (
+ axis_sq.x + cosine * (1.0f - axis_sq.x),
+ axis.x * axis.y * (1.0f - cosine) - axis.z * sine,
+ axis.z * axis.x * (1.0f - cosine) + axis.y * sine
+ );
+
+ _y = new Vector3
+ (
+ axis.x * axis.y * (1.0f - cosine) + axis.z * sine,
+ axis_sq.y + cosine * (1.0f - axis_sq.y),
+ axis.y * axis.z * (1.0f - cosine) - axis.x * sine
+ );
+
+ _z = new Vector3
+ (
+ axis.z * axis.x * (1.0f - cosine) - axis.y * sine,
+ axis.y * axis.z * (1.0f - cosine) + axis.x * sine,
+ axis_sq.z + cosine * (1.0f - axis_sq.z)
+ );
+ }
+
+ public Basis(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
+ {
+ _x = xAxis;
+ _y = yAxis;
+ _z = zAxis;
+ }
+
+ public Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz)
+ {
+ _x = new Vector3(xx, xy, xz);
+ _y = new Vector3(yx, yy, yz);
+ _z = new Vector3(zx, zy, zz);
+ }
+
+ public static Basis operator *(Basis left, Basis right)
+ {
+ return new Basis
+ (
+ right.Tdotx(left[0]), right.Tdoty(left[0]), right.Tdotz(left[0]),
+ right.Tdotx(left[1]), right.Tdoty(left[1]), right.Tdotz(left[1]),
+ right.Tdotx(left[2]), right.Tdoty(left[2]), right.Tdotz(left[2])
+ );
+ }
+
+ public static bool operator ==(Basis left, Basis right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Basis left, Basis right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Basis)
+ {
+ return Equals((Basis)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Basis other)
+ {
+ return _x.Equals(other[0]) && _y.Equals(other[1]) && _z.Equals(other[2]);
+ }
+
+ public override int GetHashCode()
+ {
+ return _x.GetHashCode() ^ _y.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/Managed/Files/Color.cs b/modules/mono/glue/Managed/Files/Color.cs
new file mode 100644
index 0000000000..88cb8524b8
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Color.cs
@@ -0,0 +1,647 @@
+using System;
+
+namespace Godot
+{
+ public struct Color : IEquatable<Color>
+ {
+ public float r;
+ public float g;
+ public float b;
+ public float a;
+
+ public int r8
+ {
+ get
+ {
+ return (int)(r * 255.0f);
+ }
+ }
+
+ public int g8
+ {
+ get
+ {
+ return (int)(g * 255.0f);
+ }
+ }
+
+ public int b8
+ {
+ get
+ {
+ return (int)(b * 255.0f);
+ }
+ }
+
+ public int a8
+ {
+ get
+ {
+ return (int)(a * 255.0f);
+ }
+ }
+
+ public float h
+ {
+ get
+ {
+ float max = 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);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ public float v
+ {
+ get
+ {
+ return Math.Max(r, Math.Max(g, b));
+ }
+ set
+ {
+ this = FromHsv(h, s, value);
+ }
+ }
+
+ private static readonly Color black = new Color(0f, 0f, 0f);
+
+ public Color Black
+ {
+ get
+ {
+ return black;
+ }
+ }
+
+ public float this [int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return r;
+ case 1:
+ return g;
+ case 2:
+ return b;
+ case 3:
+ return a;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ r = value;
+ return;
+ case 1:
+ g = value;
+ return;
+ case 2:
+ b = value;
+ return;
+ case 3:
+ a = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public static void ToHsv(Color color, out float hue, out float saturation, out float value)
+ {
+ int max = Mathf.Max(color.r8, Mathf.Max(color.g8, color.b8));
+ int min = Mathf.Min(color.r8, Mathf.Min(color.g8, color.b8));
+
+ float delta = max - min;
+
+ if (delta == 0)
+ {
+ hue = 0;
+ }
+ else
+ {
+ if (color.r == max)
+ hue = (color.g - color.b) / delta; // Between yellow & magenta
+ else if (color.g == max)
+ hue = 2 + (color.b - color.r) / delta; // Between cyan & yellow
+ else
+ hue = 4 + (color.r - color.g) / delta; // Between magenta & cyan
+
+ hue /= 6.0f;
+
+ if (hue < 0)
+ hue += 1.0f;
+ }
+
+ saturation = max == 0 ? 0 : 1f - 1f * min / max;
+ value = max / 255f;
+ }
+
+ public static Color 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
+ );
+ }
+
+ 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
+ );
+ }
+
+ 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 int ToAbgr32()
+ {
+ int 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 long ToAbgr64()
+ {
+ long 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 int ToArgb32()
+ {
+ int 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 long ToArgb64()
+ {
+ long 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 int ToRgba32()
+ {
+ int 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 long ToRgba64()
+ {
+ long 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 include_alpha = true)
+ {
+ var txt = string.Empty;
+
+ txt += ToHex32(r);
+ txt += ToHex32(g);
+ txt += ToHex32(b);
+
+ if (include_alpha)
+ 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(int 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(long 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 = { (char)0, (char)0 };
+ int lv = v & 0xF;
+
+ if (lv < 10)
+ c[0] = (char)('0' + lv);
+ else
+ c[0] = (char)('a' + lv - 10);
+
+ v >>= 4;
+ ret = c + ret;
+ }
+
+ return ret;
+ }
+
+ internal static bool HtmlIsValid(string color)
+ {
+ if (color.Length == 0)
+ return false;
+
+ if (color[0] == '#')
+ color = color.Substring(1, color.Length - 1);
+
+ bool alpha;
+
+ if (color.Length == 8)
+ alpha = true;
+ else if (color.Length == 6)
+ alpha = false;
+ else
+ 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)
+ {
+ 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 bool operator ==(Color left, Color right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Color left, Color right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Color left, Color right)
+ {
+ if (left.r == right.r)
+ {
+ if (left.g == right.g)
+ {
+ if (left.b == right.b)
+ return left.a < right.a;
+ return left.b < right.b;
+ }
+
+ return left.g < right.g;
+ }
+
+ return left.r < right.r;
+ }
+
+ public static bool operator >(Color left, Color right)
+ {
+ if (left.r == right.r)
+ {
+ if (left.g == right.g)
+ {
+ if (left.b == right.b)
+ return left.a > right.a;
+ 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 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/Managed/Files/DebuggingUtils.cs b/modules/mono/glue/Managed/Files/DebuggingUtils.cs
new file mode 100644
index 0000000000..b27816084e
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/DebuggingUtils.cs
@@ -0,0 +1,83 @@
+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 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/Managed/Files/Dictionary.cs b/modules/mono/glue/Managed/Files/Dictionary.cs
new file mode 100644
index 0000000000..523e48c31a
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Dictionary.cs
@@ -0,0 +1,400 @@
+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<object, object>,
+ ICollection<KeyValuePair<object, object>>,
+ IEnumerable<KeyValuePair<object, object>>,
+ IDisposable
+ {
+ DictionarySafeHandle safeHandle;
+ bool disposed = false;
+
+ public Dictionary()
+ {
+ safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
+ }
+
+ internal Dictionary(DictionarySafeHandle handle)
+ {
+ safeHandle = handle;
+ }
+
+ internal Dictionary(IntPtr handle)
+ {
+ safeHandle = new DictionarySafeHandle(handle);
+ }
+
+ internal IntPtr GetPtr()
+ {
+ return safeHandle.DangerousGetHandle();
+ }
+
+ public void Dispose()
+ {
+ if (disposed)
+ return;
+
+ if (safeHandle != null)
+ {
+ safeHandle.Dispose();
+ safeHandle = null;
+ }
+
+ disposed = true;
+ }
+
+ public object this[object key]
+ {
+ get
+ {
+ return godot_icall_Dictionary_GetValue(GetPtr(), key);
+ }
+ set
+ {
+ godot_icall_Dictionary_SetValue(GetPtr(), key, value);
+ }
+ }
+
+ public ICollection<object> Keys
+ {
+ get
+ {
+ IntPtr handle = godot_icall_Dictionary_Keys(GetPtr());
+ return new Array(new ArraySafeHandle(handle));
+ }
+ }
+
+ public ICollection<object> Values
+ {
+ get
+ {
+ IntPtr handle = godot_icall_Dictionary_Values(GetPtr());
+ return new Array(new ArraySafeHandle(handle));
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ return godot_icall_Dictionary_Count(GetPtr());
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public void Add(object key, object value)
+ {
+ godot_icall_Dictionary_Add(GetPtr(), key, value);
+ }
+
+ public void Add(KeyValuePair<object, object> item)
+ {
+ Add(item.Key, item.Value);
+ }
+
+ public void Clear()
+ {
+ godot_icall_Dictionary_Clear(GetPtr());
+ }
+
+ public bool Contains(KeyValuePair<object, object> item)
+ {
+ return godot_icall_Dictionary_Contains(GetPtr(), item.Key, item.Value);
+ }
+
+ public bool ContainsKey(object key)
+ {
+ return godot_icall_Dictionary_ContainsKey(GetPtr(), key);
+ }
+
+ public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex)
+ {
+ // TODO 3 internal calls, can reduce to 1
+ Array keys = (Array)Keys;
+ Array values = (Array)Values;
+ int count = Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ // TODO 2 internal calls, can reduce to 1
+ array[arrayIndex] = new KeyValuePair<object, object>(keys[i], values[i]);
+ arrayIndex++;
+ }
+ }
+
+ public IEnumerator<KeyValuePair<object, object>> GetEnumerator()
+ {
+ // TODO 3 internal calls, can reduce to 1
+ Array keys = (Array)Keys;
+ Array values = (Array)Values;
+ int count = Count;
+
+ for (int i = 0; i < count; i++)
+ {
+ // TODO 2 internal calls, can reduce to 1
+ yield return new KeyValuePair<object, object>(keys[i], values[i]);
+ }
+ }
+
+ public bool Remove(object key)
+ {
+ return godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+ }
+
+ public bool Remove(KeyValuePair<object, object> item)
+ {
+ return godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
+ }
+
+ public bool TryGetValue(object key, out object value)
+ {
+ object retValue;
+ bool found = godot_icall_Dictionary_TryGetValue(GetPtr(), key, out retValue);
+ value = found ? retValue : default(object);
+ return found;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ [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 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 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);
+ }
+
+ public class Dictionary<TKey, TValue> :
+ IDictionary<TKey, TValue>,
+ ICollection<KeyValuePair<TKey, TValue>>,
+ IEnumerable<KeyValuePair<TKey, TValue>>
+ {
+ Dictionary objectDict;
+
+ public Dictionary()
+ {
+ objectDict = new Dictionary();
+ }
+
+ 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;
+ }
+
+ public TValue this[TKey key]
+ {
+ get
+ {
+ return (TValue)objectDict[key];
+ }
+ 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 int Count
+ {
+ get
+ {
+ return objectDict.Count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return objectDict.IsReadOnly;
+ }
+ }
+
+ public void Add(TKey key, TValue value)
+ {
+ objectDict.Add(key, value);
+ }
+
+ 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 bool ContainsKey(TKey key)
+ {
+ return objectDict.ContainsKey(key);
+ }
+
+ public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+ {
+ // 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
+ array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]);
+ arrayIndex++;
+ }
+ }
+
+ 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]);
+ }
+ }
+
+ public bool Remove(TKey key)
+ {
+ return objectDict.Remove(key);
+ }
+
+ public bool Remove(KeyValuePair<TKey, TValue> item)
+ {
+ return objectDict.Remove(new KeyValuePair<object, object>(item.Key, item.Value));
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ object retValue;
+ bool found = objectDict.TryGetValue(key, out retValue);
+ value = found ? (TValue)retValue : default(TValue);
+ return found;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ internal IntPtr GetPtr()
+ {
+ return objectDict.GetPtr();
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs
new file mode 100644
index 0000000000..71534d7782
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Extensions/NodeExtensions.cs
@@ -0,0 +1,45 @@
+namespace Godot
+{
+ public partial class Node
+ {
+ public T GetNode<T>(NodePath path) where T : Godot.Node
+ {
+ return (T)GetNode(path);
+ }
+
+ public T GetNodeOrNull<T>(NodePath path) where T : Godot.Node
+ {
+ return GetNode(path) as T;
+ }
+
+ public T GetChild<T>(int idx) where T : Godot.Node
+ {
+ return (T)GetChild(idx);
+ }
+
+ public T GetChildOrNull<T>(int idx) where T : Godot.Node
+ {
+ return GetChild(idx) as T;
+ }
+
+ public T GetOwner<T>() where T : Godot.Node
+ {
+ return (T)GetOwner();
+ }
+
+ public T GetOwnerOrNull<T>() where T : Godot.Node
+ {
+ return GetOwner() as T;
+ }
+
+ public T GetParent<T>() where T : Godot.Node
+ {
+ return (T)GetParent();
+ }
+
+ public T GetParentOrNull<T>() where T : Godot.Node
+ {
+ return GetParent() as T;
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/Extensions/ObjectExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/ObjectExtensions.cs
new file mode 100644
index 0000000000..9ef0959750
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/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/Managed/Files/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs
new file mode 100644
index 0000000000..ceecc589e6
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Extensions/ResourceLoaderExtensions.cs
@@ -0,0 +1,10 @@
+namespace Godot
+{
+ public static partial class ResourceLoader
+ {
+ public static T Load<T>(string path) where T : Godot.Resource
+ {
+ return (T) Load(path);
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs
new file mode 100644
index 0000000000..264be23588
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/GD.cs
@@ -0,0 +1,242 @@
+using System;
+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)
+ {
+ return godot_icall_GD_bytes2var(bytes);
+ }
+
+ public static object Convert(object what, int 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(int 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 : Godot.Resource
+ {
+ return (T) ResourceLoader.Load(path);
+ }
+
+ public static void Print(params object[] what)
+ {
+ godot_icall_GD_print(what);
+ }
+
+ public static void PrintStack()
+ {
+ Print(System.Environment.StackTrace);
+ }
+
+ public static void PrintErr(params object[] what)
+ {
+ godot_icall_GD_printerr(what);
+ }
+
+ public static void PrintRaw(params object[] what)
+ {
+ godot_icall_GD_printraw(what);
+ }
+
+ public static void PrintS(params object[] what)
+ {
+ godot_icall_GD_prints(what);
+ }
+
+ public static void PrintT(params object[] what)
+ {
+ godot_icall_GD_printt(what);
+ }
+
+ public static int[] Range(int length)
+ {
+ var ret = new int[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ ret[i] = i;
+ }
+
+ return ret;
+ }
+
+ public static int[] Range(int from, int to)
+ {
+ if (to < from)
+ return new int[0];
+
+ var ret = new int[to - from];
+
+ for (int i = from; i < to; i++)
+ {
+ ret[i - from] = i;
+ }
+
+ return ret;
+ }
+
+ public static int[] Range(int from, int to, int increment)
+ {
+ if (to < from && increment > 0)
+ return new int[0];
+ if (to > from && increment < 0)
+ return new int[0];
+
+ // Calculate count
+ int count;
+
+ if (increment > 0)
+ count = (to - from - 1) / increment + 1;
+ else
+ count = (from - to - 1) / -increment + 1;
+
+ var ret = new int[count];
+
+ if (increment > 0)
+ {
+ int idx = 0;
+ for (int i = from; i < to; i += increment)
+ {
+ ret[idx++] = i;
+ }
+ }
+ else
+ {
+ int idx = 0;
+ for (int i = from; i > to; i += increment)
+ {
+ ret[idx++] = i;
+ }
+ }
+
+ return ret;
+ }
+
+ public static void Seed(int seed)
+ {
+ 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)
+ {
+ return godot_icall_GD_var2bytes(var);
+ }
+
+ 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);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static object godot_icall_GD_convert(object what, int 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(int 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 void godot_icall_GD_seed(int 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);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string godot_icall_GD_var2str(object var);
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/GodotSynchronizationContext.cs b/modules/mono/glue/Managed/Files/GodotSynchronizationContext.cs
new file mode 100644
index 0000000000..e727781d63
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/GodotSynchronizationContext.cs
@@ -0,0 +1,25 @@
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Godot
+{
+ public class GodotSynchronizationContext : SynchronizationContext
+ {
+ private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> queue = new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
+
+ public override void Post(SendOrPostCallback d, object state)
+ {
+ queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
+ }
+
+ public void ExecutePendingContinuations()
+ {
+ KeyValuePair<SendOrPostCallback, object> workItem;
+ while (queue.TryTake(out workItem))
+ {
+ workItem.Key(workItem.Value);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/GodotTaskScheduler.cs b/modules/mono/glue/Managed/Files/GodotTaskScheduler.cs
new file mode 100644
index 0000000000..9a40fef5a9
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/GodotTaskScheduler.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Godot
+{
+ public class GodotTaskScheduler : TaskScheduler
+ {
+ private GodotSynchronizationContext Context { get; set; }
+ private readonly LinkedList<Task> _tasks = new LinkedList<Task>();
+
+ public GodotTaskScheduler()
+ {
+ Context = new GodotSynchronizationContext();
+ 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)
+ {
+ return _tasks.ToArray();
+ }
+ }
+
+ 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/Managed/Files/Interfaces/IAwaitable.cs b/modules/mono/glue/Managed/Files/Interfaces/IAwaitable.cs
new file mode 100644
index 0000000000..0397957d00
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/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/Managed/Files/Interfaces/IAwaiter.cs b/modules/mono/glue/Managed/Files/Interfaces/IAwaiter.cs
new file mode 100644
index 0000000000..d3be9d781c
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/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/Managed/Files/MarshalUtils.cs b/modules/mono/glue/Managed/Files/MarshalUtils.cs
new file mode 100644
index 0000000000..f7699a15bf
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/MarshalUtils.cs
@@ -0,0 +1,18 @@
+using System;
+using Godot.Collections;
+
+namespace Godot
+{
+ static class MarshalUtils
+ {
+ static bool IsArrayGenericType(Type type)
+ {
+ return type.GetGenericTypeDefinition() == typeof(Array<>);
+ }
+
+ static bool IsDictionaryGenericType(Type type)
+ {
+ return type.GetGenericTypeDefinition() == typeof(Dictionary<, >);
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs
new file mode 100644
index 0000000000..a89dfe5f27
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Mathf.cs
@@ -0,0 +1,301 @@
+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 real_t Abs(real_t s)
+ {
+ return Math.Abs(s);
+ }
+
+ public static int Abs(int 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 x, real_t y)
+ {
+ return (real_t)Math.Atan2(x, y);
+ }
+
+ 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 int Decimals(real_t step)
+ {
+ return Decimals((decimal)step);
+ }
+
+ public static int Decimals(decimal step)
+ {
+ return BitConverter.GetBytes(decimal.GetBits(step)[3])[2];
+ }
+
+ 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 IsInf(real_t s)
+ {
+ return real_t.IsInfinity(s);
+ }
+
+ public static bool IsNaN(real_t s)
+ {
+ return real_t.IsNaN(s);
+ }
+
+ public static real_t Lerp(real_t from, real_t to, real_t weight)
+ {
+ return from + (to - from) * 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 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 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;
+ }
+
+ /// <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;
+ }
+
+ 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)
+ {
+ return s < 0 ? -1 : 1;
+ }
+
+ public static real_t Sign(real_t s)
+ {
+ return s < 0f ? -1f : 1f;
+ }
+
+ 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 Sqrt(real_t s)
+ {
+ return (real_t)Math.Sqrt(s);
+ }
+
+ 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 rng = max - min;
+ return min + ((value - min) % rng + rng) % rng;
+ }
+
+ public static real_t Wrap(real_t value, real_t min, real_t max)
+ {
+ real_t rng = max - min;
+ return min + ((value - min) % rng + rng) % rng;
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/MathfEx.cs b/modules/mono/glue/Managed/Files/MathfEx.cs
new file mode 100644
index 0000000000..739b7fb568
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/MathfEx.cs
@@ -0,0 +1,39 @@
+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 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);
+ }
+ }
+} \ No newline at end of file
diff --git a/modules/mono/glue/Managed/Files/NodePath.cs b/modules/mono/glue/Managed/Files/NodePath.cs
new file mode 100644
index 0000000000..2c89bec87f
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/NodePath.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public partial class NodePath : IDisposable
+ {
+ private bool disposed = false;
+
+ internal IntPtr ptr;
+
+ internal static IntPtr GetPtr(NodePath instance)
+ {
+ return instance == null ? IntPtr.Zero : instance.ptr;
+ }
+
+ ~NodePath()
+ {
+ Dispose(false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual 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/Managed/Files/Object.base.cs b/modules/mono/glue/Managed/Files/Object.base.cs
new file mode 100644
index 0000000000..30490a715f
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Object.base.cs
@@ -0,0 +1,88 @@
+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)
+ {
+ return instance == null ? IntPtr.Zero : 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 SignalAwaiter ToSignal(Object source, string signal)
+ {
+ return new SignalAwaiter(source, signal, 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);
+
+ // 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/Managed/Files/Plane.cs b/modules/mono/glue/Managed/Files/Plane.cs
new file mode 100644
index 0000000000..9611dce11e
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Plane.cs
@@ -0,0 +1,229 @@
+using System;
+#if REAL_T_IS_DOUBLE
+using real_t = System.Double;
+#else
+using real_t = System.Single;
+#endif
+
+namespace Godot
+{
+ 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.Abs(denom) <= Mathf.Epsilon)
+ return new Vector3();
+
+ 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.Abs(den) <= Mathf.Epsilon)
+ return new Vector3();
+
+ 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 new Vector3();
+
+ return from + dir * -dist;
+ }
+
+ public Vector3 IntersectSegment(Vector3 begin, Vector3 end)
+ {
+ Vector3 segment = begin - end;
+ real_t den = _normal.Dot(segment);
+
+ if (Mathf.Abs(den) <= Mathf.Epsilon)
+ return new Vector3();
+
+ real_t dist = (_normal.Dot(begin) - D) / den;
+
+ if (dist < -Mathf.Epsilon || dist > 1.0f + Mathf.Epsilon)
+ return new Vector3();
+
+ 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 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/Managed/Files/Quat.cs b/modules/mono/glue/Managed/Files/Quat.cs
new file mode 100644
index 0000000000..eaa027eb69
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Quat.cs
@@ -0,0 +1,378 @@
+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
+{
+ [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()
+ {
+ var basis = new Basis(this);
+ return basis.GetEuler();
+ }
+
+ public Quat Inverse()
+ {
+ return new Quat(-x, -y, -z, w);
+ }
+
+ public Quat Normalized()
+ {
+ return this / Length;
+ }
+
+ 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;
+ }
+
+ public void Set(Quat q)
+ {
+ this = q;
+ }
+
+ public void SetAxisAngle(Vector3 axis, real_t angle)
+ {
+ this = new Quat(axis, angle);
+ }
+
+ public void SetEuler(Vector3 eulerYXZ)
+ {
+ this = new Quat(eulerYXZ);
+ }
+
+ public Quat Slerp(Quat b, real_t t)
+ {
+ // Calculate cosine
+ real_t cosom = x * b.x + y * b.y + z * b.z + w * b.w;
+
+ var to1 = new real_t[4];
+
+ // Adjust signs if necessary
+ if (cosom < 0.0)
+ {
+ cosom = -cosom; to1[0] = -b.x;
+ to1[1] = -b.y;
+ to1[2] = -b.z;
+ to1[3] = -b.w;
+ }
+ else
+ {
+ to1[0] = b.x;
+ to1[1] = b.y;
+ to1[2] = b.z;
+ to1[3] = b.w;
+ }
+
+ 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[0],
+ scale0 * y + scale1 * to1[1],
+ scale0 * z + scale1 * to1[2],
+ scale0 * w + scale1 * to1[3]
+ );
+ }
+
+ 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)
+ {
+ Quat q = this * v;
+ q *= Inverse();
+ return new Vector3(q.x, q.y, q.z);
+ }
+
+ // 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 * (real_t)0.5;
+ real_t half_a2 = eulerYXZ.x * (real_t)0.5;
+ real_t half_a3 = eulerYXZ.z * (real_t)0.5;
+
+ // 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 = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3;
+ w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
+ }
+
+ public Quat(Vector3 axis, real_t angle)
+ {
+ real_t d = axis.Length();
+ real_t angle_t = angle;
+
+ if (d == 0f)
+ {
+ x = 0f;
+ y = 0f;
+ z = 0f;
+ w = 0f;
+ }
+ else
+ {
+ real_t s = Mathf.Sin(angle_t * 0.5f) / d;
+
+ x = axis.x * s;
+ y = axis.y * s;
+ z = axis.z * s;
+ w = Mathf.Cos(angle_t * 0.5f);
+ }
+ }
+
+ public static Quat operator *(Quat left, Quat right)
+ {
+ return new Quat
+ (
+ left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y,
+ left.w * right.y + left.y * right.w + left.z * right.x - left.x * right.z,
+ left.w * right.z + left.z * right.w + left.x * right.y - left.y * right.x,
+ left.w * right.w - left.x * right.x - left.y * right.y - left.z * right.z
+ );
+ }
+
+ public static Quat operator +(Quat left, Quat right)
+ {
+ return new Quat(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
+ }
+
+ public static Quat operator -(Quat left, Quat right)
+ {
+ return new Quat(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
+ }
+
+ public static Quat operator -(Quat left)
+ {
+ return new Quat(-left.x, -left.y, -left.z, -left.w);
+ }
+
+ public static Quat operator *(Quat left, Vector3 right)
+ {
+ return new Quat
+ (
+ left.w * right.x + left.y * right.z - left.z * right.y,
+ left.w * right.y + left.z * right.x - left.x * right.z,
+ left.w * right.z + left.x * right.y - left.y * right.x,
+ -left.x * right.x - left.y * right.y - left.z * right.z
+ );
+ }
+
+ public static Quat operator *(Vector3 left, Quat right)
+ {
+ return new Quat
+ (
+ right.w * left.x + right.y * left.z - right.z * left.y,
+ right.w * left.y + right.z * left.x - right.x * left.z,
+ right.w * left.z + right.x * left.y - right.y * left.x,
+ -right.x * left.x - right.y * left.y - right.z * left.z
+ );
+ }
+
+ public static Quat operator *(Quat left, 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 Vector2)
+ {
+ return Equals((Vector2)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Quat other)
+ {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2}, {3})", 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/Managed/Files/RID.cs b/modules/mono/glue/Managed/Files/RID.cs
new file mode 100644
index 0000000000..b862b8cac0
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/RID.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ public partial class RID : IDisposable
+ {
+ private bool disposed = false;
+
+ internal IntPtr ptr;
+
+ internal static IntPtr GetPtr(RID instance)
+ {
+ return instance == null ? IntPtr.Zero : instance.ptr;
+ }
+
+ ~RID()
+ {
+ Dispose(false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual 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));
+ }
+
+ [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/Managed/Files/Rect2.cs b/modules/mono/glue/Managed/Files/Rect2.cs
new file mode 100644
index 0000000000..cb25c267bc
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Rect2.cs
@@ -0,0 +1,256 @@
+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
+{
+ [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 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/Managed/Files/SignalAwaiter.cs b/modules/mono/glue/Managed/Files/SignalAwaiter.cs
new file mode 100644
index 0000000000..9483b6ffb4
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/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/Managed/Files/StringExtensions.cs b/modules/mono/glue/Managed/Files/StringExtensions.cs
new file mode 100644
index 0000000000..21c9be98c1
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/StringExtensions.cs
@@ -0,0 +1,981 @@
+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)) >= 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 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, 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, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int Find(this string instance, string what, int from = 0)
+ {
+ return instance.IndexOf(what, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // <summary>
+ // Find the last occurrence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int FindLast(this string instance, string what)
+ {
+ return instance.LastIndexOf(what, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // <summary>
+ // Find the first occurrence of a substring but search as case-insensitive, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
+ // </summary>
+ public static int FindN(this string instance, string what, int from = 0)
+ {
+ return instance.IndexOf(what, StringComparison.Ordinal);
+ }
+
+ // <summary>
+ // If the string is a path to a file, return the base directory.
+ // </summary>
+ public static string 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, instance.Length);
+ @base = instance.Substring(0, end);
+ }
+ else
+ {
+ if (instance.BeginsWith("/"))
+ {
+ rs = instance.Substring(1, instance.Length);
+ @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, instance.Length);
+ }
+
+ // <summary>
+ // Hash the string and return a 32 bits integer.
+ // </summary>
+ public static int Hash(this string instance)
+ {
+ int index = 0;
+ int hashv = 5381;
+ int c;
+
+ while ((c = 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 (instance[source] != 0 && text[target] != 0)
+ {
+ 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 (instance[source] == 0)
+ 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, 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, 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, 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);
+ 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)
+ {
+ return instance.Substring(from, len);
+ }
+
+ // <summary>
+ // Convert the String (which is a character array) to PoolByteArray (which is an array of bytes). The conversion is speeded up in comparison to to_utf8() with the assumption that all the characters the String contains are only ASCII characters.
+ // </summary>
+ public static byte[] 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/Managed/Files/Transform.cs b/modules/mono/glue/Managed/Files/Transform.cs
new file mode 100644
index 0000000000..e432d5b52c
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Transform.cs
@@ -0,0 +1,191 @@
+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
+{
+ [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 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 zAxis = eye - target;
+
+ zAxis.Normalize();
+
+ Vector3 yAxis = up;
+
+ Vector3 xAxis = yAxis.Cross(zAxis);
+
+ // Recompute Y = Z cross X
+ yAxis = zAxis.Cross(xAxis);
+
+ xAxis.Normalize();
+ yAxis.Normalize();
+
+ basis = Basis.CreateFromAxes(xAxis, yAxis, zAxis);
+
+ origin = eye;
+ }
+
+ public Transform Translated(Vector3 ofs)
+ {
+ return new Transform(basis, new Vector3
+ (
+ origin[0] += basis[0].Dot(ofs),
+ origin[1] += basis[1].Dot(ofs),
+ origin[2] += basis[2].Dot(ofs)
+ ));
+ }
+
+ public Vector3 Xform(Vector3 v)
+ {
+ return new Vector3
+ (
+ basis[0].Dot(v) + origin.x,
+ basis[1].Dot(v) + origin.y,
+ basis[2].Dot(v) + origin.z
+ );
+ }
+
+ public Vector3 XformInv(Vector3 v)
+ {
+ Vector3 vInv = v - origin;
+
+ return new Vector3
+ (
+ basis[0, 0] * vInv.x + basis[1, 0] * vInv.y + basis[2, 0] * vInv.z,
+ basis[0, 1] * vInv.x + basis[1, 1] * vInv.y + basis[2, 1] * vInv.z,
+ basis[0, 2] * vInv.x + basis[1, 2] * vInv.y + basis[2, 2] * vInv.z
+ );
+ }
+
+ // Constants
+ private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero);
+ private static readonly Transform _flipX = new Transform(new Basis(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1)), Vector3.Zero);
+ private static readonly Transform _flipY = new Transform(new Basis(new Vector3(1, 0, 0), new Vector3(0, -1, 0), new Vector3(0, 0, 1)), Vector3.Zero);
+ private static readonly Transform _flipZ = new Transform(new Basis(new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(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 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin)
+ {
+ basis = Basis.CreateFromAxes(xAxis, yAxis, zAxis);
+ 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 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/Managed/Files/Transform2D.cs b/modules/mono/glue/Managed/Files/Transform2D.cs
new file mode 100644
index 0000000000..8d30833066
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Transform2D.cs
@@ -0,0 +1,360 @@
+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
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Transform2D : IEquatable<Transform2D>
+ {
+ public Vector2 x;
+ public Vector2 y;
+ public Vector2 o;
+
+ public Vector2 Origin
+ {
+ get { return o; }
+ }
+
+ public real_t Rotation
+ {
+ get { return Mathf.Atan2(y.x, o.y); }
+ }
+
+ public Vector2 Scale
+ {
+ get { return new Vector2(x.Length(), y.Length()); }
+ }
+
+ public Vector2 this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return o;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ return;
+ case 1:
+ y = value;
+ return;
+ case 2:
+ o = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+
+ public real_t this[int index, int axis]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x[axis];
+ case 1:
+ return y[axis];
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x[axis] = value;
+ return;
+ case 1:
+ y[axis] = value;
+ return;
+ default:
+ throw new IndexOutOfRangeException();
+ }
+ }
+ }
+
+ public Transform2D AffineInverse()
+ {
+ var inv = this;
+
+ real_t det = this[0, 0] * this[1, 1] - this[1, 0] * this[0, 1];
+
+ if (det == 0)
+ {
+ return new Transform2D
+ (
+ float.NaN, float.NaN,
+ float.NaN, float.NaN,
+ float.NaN, float.NaN
+ );
+ }
+
+ real_t idet = 1.0f / det;
+
+ real_t temp = this[0, 0];
+ this[0, 0] = this[1, 1];
+ this[1, 1] = temp;
+
+ this[0] *= new Vector2(idet, -idet);
+ this[1] *= new Vector2(-idet, idet);
+
+ this[2] = BasisXform(-this[2]);
+
+ return inv;
+ }
+
+ 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.o = inv.BasisXform(-inv.o);
+
+ 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.o *= scale;
+ return copy;
+ }
+
+ 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.o += copy.BasisXform(offset);
+ return copy;
+ }
+
+ public Vector2 Xform(Vector2 v)
+ {
+ return new Vector2(Tdotx(v), Tdoty(v)) + o;
+ }
+
+ public Vector2 XformInv(Vector2 v)
+ {
+ Vector2 vInv = v - o;
+ return new Vector2(x.Dot(vInv), y.Dot(vInv));
+ }
+
+ // Constants
+ private static readonly Transform2D _identity = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, 1f), Vector2.Zero);
+ private static readonly Transform2D _flipX = new Transform2D(new Vector2(-1f, 0f), new Vector2(0f, 1f), Vector2.Zero);
+ private static readonly Transform2D _flipY = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, -1f), Vector2.Zero);
+
+ public static Transform2D Identity { get { return _identity; } }
+ public static Transform2D FlipX { get { return _flipX; } }
+ public static Transform2D FlipY { get { return _flipY; } }
+
+ // Constructors
+ public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin)
+ {
+ x = xAxis;
+ y = yAxis;
+ o = origin;
+ }
+
+ 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);
+ o = new Vector2(ox, oy);
+ }
+
+ public Transform2D(real_t rot, Vector2 pos)
+ {
+ real_t cr = Mathf.Cos(rot);
+ real_t sr = Mathf.Sin(rot);
+ x.x = cr;
+ y.y = cr;
+ x.y = -sr;
+ y.x = sr;
+ o = pos;
+ }
+
+ public static Transform2D operator *(Transform2D left, Transform2D right)
+ {
+ left.o = left.Xform(right.o);
+
+ real_t x0, x1, y0, y1;
+
+ x0 = left.Tdotx(right.x);
+ x1 = left.Tdoty(right.x);
+ y0 = left.Tdotx(right.y);
+ y1 = left.Tdoty(right.y);
+
+ left.x.x = x0;
+ left.x.y = x1;
+ left.y.x = y0;
+ left.y.y = y1;
+
+ return left;
+ }
+
+ public static bool operator ==(Transform2D left, Transform2D right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Transform2D left, Transform2D right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Transform2D)
+ {
+ return Equals((Transform2D)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Transform2D other)
+ {
+ return x.Equals(other.x) && y.Equals(other.y) && o.Equals(other.o);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ y.GetHashCode() ^ o.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ x.ToString(),
+ y.ToString(),
+ o.ToString()
+ });
+ }
+
+ public string ToString(string format)
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ x.ToString(format),
+ y.ToString(format),
+ o.ToString(format)
+ });
+ }
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/Vector2.cs b/modules/mono/glue/Managed/Files/Vector2.cs
new file mode 100644
index 0000000000..080b8802ba
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Vector2.cs
@@ -0,0 +1,417 @@
+// 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
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Vector2 : IEquatable<Vector2>
+ {
+ 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 length = x * x + y * y;
+
+ if (length != 0f)
+ {
+ length = Mathf.Sqrt(length);
+ 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(x - to.x, y - to.y);
+ }
+
+ 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 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 Normalized()
+ {
+ var result = this;
+ result.Normalize();
+ return result;
+ }
+
+ 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));
+ }
+
+ public void Set(real_t x, real_t y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+ public void Set(Vector2 v)
+ {
+ x = v.x;
+ y = v.y;
+ }
+
+ 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 bool operator ==(Vector2 left, Vector2 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Vector2 left, Vector2 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public static bool operator <=(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(right.x))
+ {
+ return left.y <= right.y;
+ }
+
+ return left.x <= right.x;
+ }
+
+ public static bool operator >=(Vector2 left, Vector2 right)
+ {
+ if (left.x.Equals(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 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/Managed/Files/Vector3.cs b/modules/mono/glue/Managed/Files/Vector3.cs
new file mode 100644
index 0000000000..6fffe5e4d6
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/Vector3.cs
@@ -0,0 +1,481 @@
+// 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
+{
+ [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 length = Length();
+
+ if (length == 0f)
+ {
+ x = y = z = 0f;
+ }
+ else
+ {
+ x /= length;
+ y /= length;
+ z /= length;
+ }
+ }
+
+ public Vector3 Abs()
+ {
+ return new Vector3(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z));
+ }
+
+ public 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 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 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(
+ new Vector3(x * b.x, x * b.y, x * b.z),
+ new Vector3(y * b.x, y * b.y, y * b.z),
+ new Vector3(z * b.x, z * b.y, z * b.z)
+ );
+ }
+
+ public Vector3 Project(Vector3 onNormal)
+ {
+ return onNormal * (Dot(onNormal) / onNormal.LengthSquared());
+ }
+
+ public Vector3 Reflect(Vector3 n)
+ {
+#if DEBUG
+ if (!n.IsNormalized())
+ throw new ArgumentException(String.Format("{0} is not normalized", n), 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);
+ }
+
+ public void Set(real_t x, real_t y, real_t z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+ public void Set(Vector3 v)
+ {
+ x = v.x;
+ y = v.y;
+ z = v.z;
+ }
+
+ public Vector3 Slerp(Vector3 b, real_t t)
+ {
+ 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 bool operator ==(Vector3 left, Vector3 right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(Vector3 left, Vector3 right)
+ {
+ return !left.Equals(right);
+ }
+
+ public static bool operator <(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z < right.z;
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z > right.z;
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public static bool operator <=(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z <= right.z;
+ return left.y < right.y;
+ }
+
+ return left.x < right.x;
+ }
+
+ public static bool operator >=(Vector3 left, Vector3 right)
+ {
+ if (left.x == right.x)
+ {
+ if (left.y == right.y)
+ return left.z >= right.z;
+ return left.y > right.y;
+ }
+
+ return left.x > right.x;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Vector3)
+ {
+ return Equals((Vector3)obj);
+ }
+
+ return false;
+ }
+
+ public bool Equals(Vector3 other)
+ {
+ return x == other.x && y == other.y && z == other.z;
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return String.Format("({0}, {1}, {2})", new object[]
+ {
+ 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)
+ });
+ }
+ }
+}