[Mono] Add Vector2i, Vector3i, and Rect2i

These have conversion operators between their non-integer equivalents. Vector2i to Vector2 is implicit, while Vector2 to Vector2i is explicit. All conversion code is done in the integer files, so Vector2.cs contains no reference to Vector2i etc.
This commit is contained in:
Aaron Franke 2020-03-17 18:03:04 -04:00
parent 989a223c5a
commit 22ba912d90
No known key found for this signature in database
GPG key ID: 40A1750B977E56BF
6 changed files with 1069 additions and 22 deletions

View file

@ -0,0 +1,262 @@
using System;
using System.Runtime.InteropServices;
namespace Godot
{
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Rect2i : IEquatable<Rect2i>
{
private Vector2i _position;
private Vector2i _size;
public Vector2i Position
{
get { return _position; }
set { _position = value; }
}
public Vector2i Size
{
get { return _size; }
set { _size = value; }
}
public Vector2i End
{
get { return _position + _size; }
set { _size = value - _position; }
}
public int Area
{
get { return GetArea(); }
}
public Rect2i Abs()
{
Vector2i end = End;
Vector2i topLeft = new Vector2i(Mathf.Min(_position.x, end.x), Mathf.Min(_position.y, end.y));
return new Rect2i(topLeft, _size.Abs());
}
public Rect2i Clip(Rect2i b)
{
var newRect = b;
if (!Intersects(newRect))
return new Rect2i();
newRect._position.x = Mathf.Max(b._position.x, _position.x);
newRect._position.y = Mathf.Max(b._position.y, _position.y);
Vector2i bEnd = b._position + b._size;
Vector2i 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(Rect2i 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 Rect2i Expand(Vector2i to)
{
var expanded = this;
Vector2i begin = expanded._position;
Vector2i 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 int GetArea()
{
return _size.x * _size.y;
}
public Rect2i Grow(int 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 Rect2i GrowIndividual(int left, int top, int right, int 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 Rect2i GrowMargin(Margin margin, int 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(Vector2i 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(Rect2i 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 Rect2i Merge(Rect2i b)
{
Rect2i 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 Rect2i(Vector2i position, Vector2i size)
{
_position = position;
_size = size;
}
public Rect2i(Vector2i position, int width, int height)
{
_position = position;
_size = new Vector2i(width, height);
}
public Rect2i(int x, int y, Vector2i size)
{
_position = new Vector2i(x, y);
_size = size;
}
public Rect2i(int x, int y, int width, int height)
{
_position = new Vector2i(x, y);
_size = new Vector2i(width, height);
}
public static bool operator ==(Rect2i left, Rect2i right)
{
return left.Equals(right);
}
public static bool operator !=(Rect2i left, Rect2i right)
{
return !left.Equals(right);
}
public static implicit operator Rect2(Rect2i value)
{
return new Rect2(value._position, value._size);
}
public static explicit operator Rect2i(Rect2 value)
{
return new Rect2i((Vector2i)value.Position, (Vector2i)value.Size);
}
public override bool Equals(object obj)
{
if (obj is Rect2i)
{
return Equals((Rect2i)obj);
}
return false;
}
public bool Equals(Rect2i 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)
});
}
}
}

View file

@ -76,11 +76,6 @@ namespace Godot
}
}
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));
@ -130,6 +125,11 @@ namespace Godot
return v;
}
public real_t Cross(Vector2 b)
{
return x * b.y - y * b.x;
}
public Vector2 CubicInterpolate(Vector2 b, Vector2 preA, Vector2 postB, real_t t)
{
var p0 = preA;
@ -234,7 +234,7 @@ namespace Godot
public Vector2 Reflect(Vector2 n)
{
return 2.0f * n * Dot(n) - this;
return 2 * Dot(n) * n - this;
}
public Vector2 Rotated(real_t phi)
@ -352,18 +352,18 @@ namespace Godot
return left;
}
public static Vector2 operator /(Vector2 vec, real_t scale)
public static Vector2 operator /(Vector2 vec, real_t divisor)
{
vec.x /= scale;
vec.y /= scale;
vec.x /= divisor;
vec.y /= divisor;
return vec;
}
public static Vector2 operator /(Vector2 left, Vector2 right)
public static Vector2 operator /(Vector2 vec, Vector2 divisorv)
{
left.x /= right.x;
left.y /= right.y;
return left;
vec.x /= divisorv.x;
vec.y /= divisorv.y;
return vec;
}
public static Vector2 operator %(Vector2 vec, real_t divisor)

View file

@ -0,0 +1,380 @@
using System;
using System.Runtime.InteropServices;
#if REAL_T_IS_DOUBLE
using real_t = System.Double;
#else
using real_t = System.Single;
#endif
namespace Godot
{
/// <summary>
/// 2-element structure that can be used to represent 2D grid coordinates or pairs of integers.
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Vector2i : IEquatable<Vector2i>
{
public enum Axis
{
X = 0,
Y
}
public int x;
public int y;
public int 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();
}
}
}
public Vector2i Abs()
{
return new Vector2i(Mathf.Abs(x), Mathf.Abs(y));
}
public real_t Angle()
{
return Mathf.Atan2(y, x);
}
public real_t AngleTo(Vector2i to)
{
return Mathf.Atan2(Cross(to), Dot(to));
}
public real_t AngleToPoint(Vector2i to)
{
return Mathf.Atan2(y - to.y, x - to.x);
}
public real_t Aspect()
{
return x / (real_t)y;
}
public Vector2i Bounce(Vector2i n)
{
return -Reflect(n);
}
public int Cross(Vector2i b)
{
return x * b.y - y * b.x;
}
public int DistanceSquaredTo(Vector2i b)
{
return (b - this).LengthSquared();
}
public real_t DistanceTo(Vector2i b)
{
return (b - this).Length();
}
public int Dot(Vector2i b)
{
return x * b.x + y * b.y;
}
public real_t Length()
{
int x2 = x * x;
int y2 = y * y;
return Mathf.Sqrt(x2 + y2);
}
public int LengthSquared()
{
int x2 = x * x;
int y2 = y * y;
return x2 + y2;
}
public Axis MaxAxis()
{
return x < y ? Axis.Y : Axis.X;
}
public Axis MinAxis()
{
return x > y ? Axis.Y : Axis.X;
}
public Vector2i PosMod(int mod)
{
Vector2i v = this;
v.x = Mathf.PosMod(v.x, mod);
v.y = Mathf.PosMod(v.y, mod);
return v;
}
public Vector2i PosMod(Vector2i modv)
{
Vector2i v = this;
v.x = Mathf.PosMod(v.x, modv.x);
v.y = Mathf.PosMod(v.y, modv.y);
return v;
}
public Vector2i Reflect(Vector2i n)
{
return 2 * Dot(n) * n - this;
}
public Vector2i Sign()
{
Vector2i v = this;
v.x = Mathf.Sign(v.x);
v.y = Mathf.Sign(v.y);
return v;
}
public Vector2i Tangent()
{
return new Vector2i(y, -x);
}
// Constants
private static readonly Vector2i _zero = new Vector2i(0, 0);
private static readonly Vector2i _one = new Vector2i(1, 1);
private static readonly Vector2i _up = new Vector2i(0, -1);
private static readonly Vector2i _down = new Vector2i(0, 1);
private static readonly Vector2i _right = new Vector2i(1, 0);
private static readonly Vector2i _left = new Vector2i(-1, 0);
public static Vector2i Zero { get { return _zero; } }
public static Vector2i One { get { return _one; } }
public static Vector2i Up { get { return _up; } }
public static Vector2i Down { get { return _down; } }
public static Vector2i Right { get { return _right; } }
public static Vector2i Left { get { return _left; } }
// Constructors
public Vector2i(int x, int y)
{
this.x = x;
this.y = y;
}
public Vector2i(Vector2i vi)
{
this.x = vi.x;
this.y = vi.y;
}
public Vector2i(Vector2 v)
{
this.x = Mathf.RoundToInt(v.x);
this.y = Mathf.RoundToInt(v.y);
}
public static Vector2i operator +(Vector2i left, Vector2i right)
{
left.x += right.x;
left.y += right.y;
return left;
}
public static Vector2i operator -(Vector2i left, Vector2i right)
{
left.x -= right.x;
left.y -= right.y;
return left;
}
public static Vector2i operator -(Vector2i vec)
{
vec.x = -vec.x;
vec.y = -vec.y;
return vec;
}
public static Vector2i operator *(Vector2i vec, int scale)
{
vec.x *= scale;
vec.y *= scale;
return vec;
}
public static Vector2i operator *(int scale, Vector2i vec)
{
vec.x *= scale;
vec.y *= scale;
return vec;
}
public static Vector2i operator *(Vector2i left, Vector2i right)
{
left.x *= right.x;
left.y *= right.y;
return left;
}
public static Vector2i operator /(Vector2i vec, int divisor)
{
vec.x /= divisor;
vec.y /= divisor;
return vec;
}
public static Vector2i operator /(Vector2i vec, Vector2i divisorv)
{
vec.x /= divisorv.x;
vec.y /= divisorv.y;
return vec;
}
public static Vector2i operator %(Vector2i vec, int divisor)
{
vec.x %= divisor;
vec.y %= divisor;
return vec;
}
public static Vector2i operator %(Vector2i vec, Vector2i divisorv)
{
vec.x %= divisorv.x;
vec.y %= divisorv.y;
return vec;
}
public static Vector2i operator &(Vector2i vec, int and)
{
vec.x &= and;
vec.y &= and;
return vec;
}
public static Vector2i operator &(Vector2i vec, Vector2i andv)
{
vec.x &= andv.x;
vec.y &= andv.y;
return vec;
}
public static bool operator ==(Vector2i left, Vector2i right)
{
return left.Equals(right);
}
public static bool operator !=(Vector2i left, Vector2i right)
{
return !left.Equals(right);
}
public static bool operator <(Vector2i left, Vector2i right)
{
if (left.x.Equals(right.x))
{
return left.y < right.y;
}
return left.x < right.x;
}
public static bool operator >(Vector2i left, Vector2i right)
{
if (left.x.Equals(right.x))
{
return left.y > right.y;
}
return left.x > right.x;
}
public static bool operator <=(Vector2i left, Vector2i right)
{
if (left.x.Equals(right.x))
{
return left.y <= right.y;
}
return left.x <= right.x;
}
public static bool operator >=(Vector2i left, Vector2i right)
{
if (left.x.Equals(right.x))
{
return left.y >= right.y;
}
return left.x >= right.x;
}
public static implicit operator Vector2(Vector2i value)
{
return new Vector2(value.x, value.y);
}
public static explicit operator Vector2i(Vector2 value)
{
return new Vector2i(value);
}
public override bool Equals(object obj)
{
if (obj is Vector2i)
{
return Equals((Vector2i)obj);
}
return false;
}
public bool Equals(Vector2i other)
{
return x == other.x && y == other.y;
}
public override int GetHashCode()
{
return y.GetHashCode() ^ x.GetHashCode();
}
public override string ToString()
{
return String.Format("({0}, {1})", new object[]
{
this.x.ToString(),
this.y.ToString()
});
}
public string ToString(string format)
{
return String.Format("({0}, {1})", new object[]
{
this.x.ToString(format),
this.y.ToString(format)
});
}
}
}

View file

@ -400,20 +400,20 @@ namespace Godot
return left;
}
public static Vector3 operator /(Vector3 vec, real_t scale)
public static Vector3 operator /(Vector3 vec, real_t divisor)
{
vec.x /= scale;
vec.y /= scale;
vec.z /= scale;
vec.x /= divisor;
vec.y /= divisor;
vec.z /= divisor;
return vec;
}
public static Vector3 operator /(Vector3 left, Vector3 right)
public static Vector3 operator /(Vector3 vec, Vector3 divisorv)
{
left.x /= right.x;
left.y /= right.y;
left.z /= right.z;
return left;
vec.x /= divisorv.x;
vec.y /= divisorv.y;
vec.z /= divisorv.z;
return vec;
}
public static Vector3 operator %(Vector3 vec, real_t divisor)

View file

@ -0,0 +1,402 @@
using System;
using System.Runtime.InteropServices;
#if REAL_T_IS_DOUBLE
using real_t = System.Double;
#else
using real_t = System.Single;
#endif
namespace Godot
{
/// <summary>
/// 3-element structure that can be used to represent 3D grid coordinates or sets of integers.
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct Vector3i : IEquatable<Vector3i>
{
public enum Axis
{
X = 0,
Y,
Z
}
public int x;
public int y;
public int z;
public int 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 Vector3i Abs()
{
Vector3i v = this;
if (v.x < 0)
{
v.x = -v.x;
}
if (v.y < 0)
{
v.y = -v.y;
}
if (v.z < 0)
{
v.z = -v.z;
}
return v;
}
public int DistanceSquaredTo(Vector3i b)
{
return (b - this).LengthSquared();
}
public real_t DistanceTo(Vector3i b)
{
return (b - this).Length();
}
public int Dot(Vector3i b)
{
return x * b.x + y * b.y + z * b.z;
}
public real_t Length()
{
int x2 = x * x;
int y2 = y * y;
int z2 = z * z;
return Mathf.Sqrt(x2 + y2 + z2);
}
public int LengthSquared()
{
int x2 = x * x;
int y2 = y * y;
int z2 = z * z;
return x2 + y2 + z2;
}
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 Vector3i PosMod(int mod)
{
Vector3i v = this;
v.x = Mathf.PosMod(v.x, mod);
v.y = Mathf.PosMod(v.y, mod);
v.z = Mathf.PosMod(v.z, mod);
return v;
}
public Vector3i PosMod(Vector3i modv)
{
Vector3i v = this;
v.x = Mathf.PosMod(v.x, modv.x);
v.y = Mathf.PosMod(v.y, modv.y);
v.z = Mathf.PosMod(v.z, modv.z);
return v;
}
public Vector3i Sign()
{
Vector3i v = this;
v.x = Mathf.Sign(v.x);
v.y = Mathf.Sign(v.y);
v.z = Mathf.Sign(v.z);
return v;
}
// Constants
private static readonly Vector3i _zero = new Vector3i(0, 0, 0);
private static readonly Vector3i _one = new Vector3i(1, 1, 1);
private static readonly Vector3i _up = new Vector3i(0, 1, 0);
private static readonly Vector3i _down = new Vector3i(0, -1, 0);
private static readonly Vector3i _right = new Vector3i(1, 0, 0);
private static readonly Vector3i _left = new Vector3i(-1, 0, 0);
private static readonly Vector3i _forward = new Vector3i(0, 0, -1);
private static readonly Vector3i _back = new Vector3i(0, 0, 1);
public static Vector3i Zero { get { return _zero; } }
public static Vector3i One { get { return _one; } }
public static Vector3i Up { get { return _up; } }
public static Vector3i Down { get { return _down; } }
public static Vector3i Right { get { return _right; } }
public static Vector3i Left { get { return _left; } }
public static Vector3i Forward { get { return _forward; } }
public static Vector3i Back { get { return _back; } }
// Constructors
public Vector3i(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
public Vector3i(Vector3i vi)
{
this.x = vi.x;
this.y = vi.y;
this.z = vi.z;
}
public Vector3i(Vector3 v)
{
this.x = Mathf.RoundToInt(v.x);
this.y = Mathf.RoundToInt(v.y);
this.z = Mathf.RoundToInt(v.z);
}
public static Vector3i operator +(Vector3i left, Vector3i right)
{
left.x += right.x;
left.y += right.y;
left.z += right.z;
return left;
}
public static Vector3i operator -(Vector3i left, Vector3i right)
{
left.x -= right.x;
left.y -= right.y;
left.z -= right.z;
return left;
}
public static Vector3i operator -(Vector3i vec)
{
vec.x = -vec.x;
vec.y = -vec.y;
vec.z = -vec.z;
return vec;
}
public static Vector3i operator *(Vector3i vec, int scale)
{
vec.x *= scale;
vec.y *= scale;
vec.z *= scale;
return vec;
}
public static Vector3i operator *(int scale, Vector3i vec)
{
vec.x *= scale;
vec.y *= scale;
vec.z *= scale;
return vec;
}
public static Vector3i operator *(Vector3i left, Vector3i right)
{
left.x *= right.x;
left.y *= right.y;
left.z *= right.z;
return left;
}
public static Vector3i operator /(Vector3i vec, int divisor)
{
vec.x /= divisor;
vec.y /= divisor;
vec.z /= divisor;
return vec;
}
public static Vector3i operator /(Vector3i vec, Vector3i divisorv)
{
vec.x /= divisorv.x;
vec.y /= divisorv.y;
vec.z /= divisorv.z;
return vec;
}
public static Vector3i operator %(Vector3i vec, int divisor)
{
vec.x %= divisor;
vec.y %= divisor;
vec.z %= divisor;
return vec;
}
public static Vector3i operator %(Vector3i vec, Vector3i divisorv)
{
vec.x %= divisorv.x;
vec.y %= divisorv.y;
vec.z %= divisorv.z;
return vec;
}
public static Vector3i operator &(Vector3i vec, int and)
{
vec.x &= and;
vec.y &= and;
vec.z &= and;
return vec;
}
public static Vector3i operator &(Vector3i vec, Vector3i andv)
{
vec.x &= andv.x;
vec.y &= andv.y;
vec.z &= andv.z;
return vec;
}
public static bool operator ==(Vector3i left, Vector3i right)
{
return left.Equals(right);
}
public static bool operator !=(Vector3i left, Vector3i right)
{
return !left.Equals(right);
}
public static bool operator <(Vector3i left, Vector3i right)
{
if (left.x == right.x)
{
if (left.y == right.y)
return left.z < right.z;
else
return left.y < right.y;
}
return left.x < right.x;
}
public static bool operator >(Vector3i left, Vector3i right)
{
if (left.x == right.x)
{
if (left.y == right.y)
return left.z > right.z;
else
return left.y > right.y;
}
return left.x > right.x;
}
public static bool operator <=(Vector3i left, Vector3i right)
{
if (left.x == right.x)
{
if (left.y == right.y)
return left.z <= right.z;
else
return left.y < right.y;
}
return left.x < right.x;
}
public static bool operator >=(Vector3i left, Vector3i right)
{
if (left.x == right.x)
{
if (left.y == right.y)
return left.z >= right.z;
else
return left.y > right.y;
}
return left.x > right.x;
}
public static implicit operator Vector3(Vector3i value)
{
return new Vector3(value.x, value.y, value.z);
}
public static explicit operator Vector3i(Vector3 value)
{
return new Vector3i(value);
}
public override bool Equals(object obj)
{
if (obj is Vector3i)
{
return Equals((Vector3i)obj);
}
return false;
}
public bool Equals(Vector3i other)
{
return x == other.x && y == other.y && z == other.z;
}
public override int GetHashCode()
{
return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode();
}
public override string ToString()
{
return String.Format("({0}, {1}, {2})", new object[]
{
this.x.ToString(),
this.y.ToString(),
this.z.ToString()
});
}
public string ToString(string format)
{
return String.Format("({0}, {1}, {2})", new object[]
{
this.x.ToString(format),
this.y.ToString(format),
this.z.ToString(format)
});
}
}
}

View file

@ -67,6 +67,7 @@
<Compile Include="Core\Plane.cs" />
<Compile Include="Core\Quat.cs" />
<Compile Include="Core\Rect2.cs" />
<Compile Include="Core\Rect2i.cs" />
<Compile Include="Core\RID.cs" />
<Compile Include="Core\SignalInfo.cs" />
<Compile Include="Core\SignalAwaiter.cs" />
@ -75,7 +76,9 @@
<Compile Include="Core\Transform.cs" />
<Compile Include="Core\Transform2D.cs" />
<Compile Include="Core\Vector2.cs" />
<Compile Include="Core\Vector2i.cs" />
<Compile Include="Core\Vector3.cs" />
<Compile Include="Core\Vector3i.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<!--