diff options
Diffstat (limited to 'modules/mono/glue/Managed')
44 files changed, 7354 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..33b2b46712 --- /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..d5a35d7ae0 --- /dev/null +++ b/modules/mono/glue/Managed/Files/Array.cs @@ -0,0 +1,349 @@ +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 this[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 object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_SetAt(IntPtr ptr, int index, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Array_Count(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static 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); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass); + } + + public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T> + { + Array objectArray; + + internal static int elemTypeEncoding; + internal static IntPtr elemTypeClass; + + static Array() + { + Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass); + } + + public Array() + { + objectArray = new Array(); + } + + public Array(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)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); + } + 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)this[i]; + arrayIndex++; + } + } + + public IEnumerator<T> GetEnumerator() + { + int count = objectArray.Count; + + for (int i = 0; i < count; i++) + { + yield return (T)this[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..2398e10135 --- /dev/null +++ b/modules/mono/glue/Managed/Files/Attributes/RPCAttributes.cs @@ -0,0 +1,28 @@ +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 PuppetAttribute : 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 PuppetSyncAttribute : 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..54d2813abf --- /dev/null +++ b/modules/mono/glue/Managed/Files/Basis.cs @@ -0,0 +1,610 @@ +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) + ); + } + + internal Quat RotationQuat() + { + Basis orthonormalizedBasis = Orthonormalized(); + real_t det = orthonormalizedBasis.Determinant(); + if (det < 0) + { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + orthonormalizedBasis = orthonormalizedBasis.Scaled(Vector3.NegOne); + } + + return orthonormalizedBasis.Quat(); + } + + internal void SetQuantScale(Quat quat, Vector3 scale) + { + SetDiagonal(scale); + Rotate(quat); + } + + private void Rotate(Quat quat) + { + this *= new Basis(quat); + } + + private void SetDiagonal(Vector3 diagonal) + { + _x = new Vector3(diagonal.x, 0, 0); + _y = new Vector3(0, diagonal.y, 0); + _z = new Vector3(0, 0, diagonal.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..fc5bb010a9 --- /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..7695f03cd6 --- /dev/null +++ b/modules/mono/glue/Managed/Files/Dictionary.cs @@ -0,0 +1,417 @@ +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 object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Dictionary_Keys(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static IntPtr godot_icall_Dictionary_Values(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Dictionary_Count(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Clear(IntPtr ptr); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass); + } + + public class Dictionary<TKey, TValue> : + IDictionary<TKey, TValue>, + ICollection<KeyValuePair<TKey, TValue>>, + IEnumerable<KeyValuePair<TKey, TValue>> + { + Dictionary objectDict; + + internal static int valTypeEncoding; + internal static IntPtr valTypeClass; + + static Dictionary() + { + Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass); + } + + public Dictionary() + { + objectDict = new Dictionary(); + } + + public Dictionary(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)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); + } + set + { + objectDict[key] = value; + } + } + + public ICollection<TKey> Keys + { + get + { + IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(objectDict.GetPtr()); + return new Array<TKey>(new ArraySafeHandle(handle)); + } + } + + public ICollection<TValue> Values + { + get + { + IntPtr handle = Dictionary.godot_icall_Dictionary_Values(objectDict.GetPtr()); + return new Array<TValue>(new ArraySafeHandle(handle)); + } + } + + public 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 = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass); + 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..366d89b1c2 --- /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 : class + { + return (T)(object)GetNode(path); + } + + public T GetNodeOrNull<T>(NodePath path) where T : class + { + return GetNode(path) as T; + } + + public T GetChild<T>(int idx) where T : class + { + return (T)(object)GetChild(idx); + } + + public T GetChildOrNull<T>(int idx) where T : class + { + return GetChild(idx) as T; + } + + public T GetOwner<T>() where T : class + { + return (T)(object)GetOwner(); + } + + public T GetOwnerOrNull<T>() where T : class + { + return GetOwner() as T; + } + + public T GetParent<T>() where T : class + { + return (T)(object)GetParent(); + } + + public T GetParentOrNull<T>() where T : class + { + return GetParent() as T; + } + } +} diff --git a/modules/mono/glue/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..684d160b57 --- /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 : class + { + return (T)(object)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..75a35a9eea --- /dev/null +++ b/modules/mono/glue/Managed/Files/GD.cs @@ -0,0 +1,258 @@ +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 : class + { + return ResourceLoader.Load<T>(path); + } + + public static void PushError(string message) + { + godot_icall_GD_pusherror(message); + } + + public static void PushWarning(string message) + { + godot_icall_GD_pushwarning(message); + } + + public static void Print(params object[] what) + { + godot_icall_GD_print(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); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_GD_pusherror(string type); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_GD_pushwarning(string type); + } +} diff --git a/modules/mono/glue/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..dcab3c1ffc --- /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..2ef02cc288 --- /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..f11cd490a9 --- /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..fd1ac01083 --- /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..888f300347 --- /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..c194facd0b --- /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..687ed8f011 --- /dev/null +++ b/modules/mono/glue/Managed/Files/Transform.cs @@ -0,0 +1,210 @@ +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 InterpolateWith(Transform transform, real_t c) + { + /* not sure if very "efficient" but good enough? */ + + Vector3 sourceScale = basis.Scale; + Quat sourceRotation = basis.RotationQuat(); + Vector3 sourceLocation = origin; + + Vector3 destinationScale = transform.basis.Scale; + Quat destinationRotation = transform.basis.RotationQuat(); + Vector3 destinationLocation = transform.origin; + + var interpolated = new Transform(); + interpolated.basis.SetQuantScale(sourceRotation.Slerp(destinationRotation, c).Normalized(), sourceScale.LinearInterpolate(destinationScale, c)); + interpolated.origin = sourceLocation.LinearInterpolate(destinationLocation, c); + + return interpolated; + } + + public Transform Inverse() + { + Basis basisTr = basis.Transposed(); + return new Transform(basisTr, basisTr.Xform(-origin)); + } + + public Transform LookingAt(Vector3 target, Vector3 up) + { + var t = this; + t.SetLookAt(origin, target, up); + return t; + } + + public Transform Orthonormalized() + { + return new Transform(basis.Orthonormalized(), origin); + } + + public Transform Rotated(Vector3 axis, real_t phi) + { + return new Transform(new Basis(axis, phi), new Vector3()) * this; + } + + public Transform Scaled(Vector3 scale) + { + return new Transform(basis.Scaled(scale), origin * scale); + } + + public void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) + { + // Make rotation matrix + // Z vector + Vector3 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..c9e5b560b2 --- /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..ce41886bfc --- /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..8e62ec778d --- /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) + }); + } + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/Enums.cs b/modules/mono/glue/Managed/IgnoredFiles/Enums.cs new file mode 100644 index 0000000000..05f1abcf93 --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/Enums.cs @@ -0,0 +1,21 @@ + +namespace Godot +{ + public enum Margin + { + Left = 0, + Top = 1, + Right = 2, + Bottom = 3 + } + + public enum Error + { + Ok = 0 + } + + public enum PropertyHint + { + None = 0 + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/FuncRef.cs b/modules/mono/glue/Managed/IgnoredFiles/FuncRef.cs new file mode 100644 index 0000000000..83504fe49f --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/FuncRef.cs @@ -0,0 +1,17 @@ +using System; + +namespace Godot +{ + public partial class FuncRef + { + public void SetInstance(Object instance) + { + throw new NotImplementedException(); + } + + public void SetFunction(string name) + { + throw new NotImplementedException(); + } + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/Node.cs b/modules/mono/glue/Managed/IgnoredFiles/Node.cs new file mode 100644 index 0000000000..99ba0f827a --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/Node.cs @@ -0,0 +1,28 @@ + +using System; + +namespace Godot +{ + public partial class Node + { + public Node GetChild(int idx) + { + throw new NotImplementedException(); + } + + public Node GetNode(NodePath path) + { + throw new NotImplementedException(); + } + + public Node GetOwner() + { + throw new NotImplementedException(); + } + + public Node GetParent() + { + throw new NotImplementedException(); + } + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/Resource.cs b/modules/mono/glue/Managed/IgnoredFiles/Resource.cs new file mode 100644 index 0000000000..cc0a5555b1 --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/Resource.cs @@ -0,0 +1,7 @@ +namespace Godot +{ + public partial class Resource + { + + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/ResourceLoader.cs b/modules/mono/glue/Managed/IgnoredFiles/ResourceLoader.cs new file mode 100644 index 0000000000..6461d35146 --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/ResourceLoader.cs @@ -0,0 +1,12 @@ +using System; + +namespace Godot +{ + public partial class ResourceLoader + { + public static Resource Load(string path, string typeHint = "", bool pNoCache = false) + { + throw new NotImplementedException(); + } + } +} diff --git a/modules/mono/glue/Managed/IgnoredFiles/WeakRef.cs b/modules/mono/glue/Managed/IgnoredFiles/WeakRef.cs new file mode 100644 index 0000000000..1498b7836b --- /dev/null +++ b/modules/mono/glue/Managed/IgnoredFiles/WeakRef.cs @@ -0,0 +1,7 @@ +namespace Godot +{ + public partial class WeakRef + { + + } +} diff --git a/modules/mono/glue/Managed/Managed.csproj b/modules/mono/glue/Managed/Managed.csproj new file mode 100644 index 0000000000..1f82dde5e7 --- /dev/null +++ b/modules/mono/glue/Managed/Managed.csproj @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">x86</Platform> + <ProjectGuid>{DAA3DEF8-5112-407C-A5E5-6C608CF5F955}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>Managed</RootNamespace> + <AssemblyName>Managed</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ExternalConsole>true</ExternalConsole> + <PlatformTarget>x86</PlatformTarget> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ExternalConsole>true</ExternalConsole> + <PlatformTarget>x86</PlatformTarget> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Files\**\*.cs" /> + <Compile Include="IgnoredFiles\**\*.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> +</Project> diff --git a/modules/mono/glue/Managed/Managed.sln b/modules/mono/glue/Managed/Managed.sln new file mode 100644 index 0000000000..61ddde0fb7 --- /dev/null +++ b/modules/mono/glue/Managed/Managed.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managed", "Managed.csproj", "{DAA3DEF8-5112-407C-A5E5-6C608CF5F955}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DAA3DEF8-5112-407C-A5E5-6C608CF5F955}.Debug|x86.ActiveCfg = Debug|x86 + {DAA3DEF8-5112-407C-A5E5-6C608CF5F955}.Debug|x86.Build.0 = Debug|x86 + {DAA3DEF8-5112-407C-A5E5-6C608CF5F955}.Release|x86.ActiveCfg = Release|x86 + {DAA3DEF8-5112-407C-A5E5-6C608CF5F955}.Release|x86.Build.0 = Release|x86 + EndGlobalSection +EndGlobal diff --git a/modules/mono/glue/Managed/Properties/AssemblyInfo.cs b/modules/mono/glue/Managed/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..77b3774e81 --- /dev/null +++ b/modules/mono/glue/Managed/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Managed")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] diff --git a/modules/mono/glue/Managed/README.md b/modules/mono/glue/Managed/README.md new file mode 100644 index 0000000000..65e63cae37 --- /dev/null +++ b/modules/mono/glue/Managed/README.md @@ -0,0 +1,5 @@ +The directory `Files` contains C# files from the core assembly project that are not part of the generated API. Any file with the `.cs` extension in this directory will be added to the core assembly project. + +A dummy solution and project is provided to get tooling help while editing these files, like code completion and name refactoring. + +The directory `IgnoredFiles` contains C# files that are needed to build the dummy project but must not be added to the core assembly project. They contain placeholders for the declarations that are part of the generated API. |