using Godot; using System; using System.Runtime.InteropServices; #if GODOT_REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif /// /// Basis25D structure for performing 2.5D transform math. /// Note: All code assumes that Y is UP in 3D, and DOWN in 2D. /// A top-down view has a Y axis component of (0, 0), with a Z axis component of (0, 1). /// For a front side view, Y is (0, -1) and Z is (0, 0). /// Remember that Godot's 2D mode has the Y axis pointing DOWN on the screen. /// [Serializable] [StructLayout(LayoutKind.Sequential)] public struct Basis25D : IEquatable { // Also matrix columns, the directions to move on screen for each unit change in 3D. public Vector2 x; public Vector2 y; public Vector2 z; // Also matrix rows, the parts of each vector that contribute to moving in a screen direction. // Setting a row to zero means no movement in that direction. public Vector3 Row0 { get { return new Vector3(x.x, y.x, z.x); } set { x.x = value.x; y.x = value.y; z.x = value.z; } } public Vector3 Row1 { get { return new Vector3(x.y, y.y, z.y); } set { x.y = value.x; y.y = value.y; z.y = value.z; } } public Vector2 this[int columnIndex] { get { switch (columnIndex) { case 0: return x; case 1: return y; case 2: return z; default: throw new IndexOutOfRangeException(); } } set { switch (columnIndex) { case 0: x = value; return; case 1: y = value; return; case 2: z = value; return; default: throw new IndexOutOfRangeException(); } } } public real_t this[int columnIndex, int rowIndex] { get { return this[columnIndex][rowIndex]; } set { Vector2 v = this[columnIndex]; v[rowIndex] = value; this[columnIndex] = v; } } private static readonly Basis25D _topDown = new Basis25D(1, 0, 0, 0, 0, 1); private static readonly Basis25D _frontSide = new Basis25D(1, 0, 0, -1, 0, 0); private static readonly Basis25D _fortyFive = new Basis25D(1, 0, 0, -0.70710678118f, 0, 0.70710678118f); private static readonly Basis25D _isometric = new Basis25D(0.86602540378f, 0.5f, 0, -1, -0.86602540378f, 0.5f); private static readonly Basis25D _obliqueY = new Basis25D(1, 0, -0.70710678118f, -0.70710678118f, 0, 1); private static readonly Basis25D _obliqueZ = new Basis25D(1, 0, 0, -1, -0.70710678118f, 0.70710678118f); public static Basis25D TopDown { get { return _topDown; } } public static Basis25D FrontSide { get { return _frontSide; } } public static Basis25D FortyFive { get { return _fortyFive; } } public static Basis25D Isometric { get { return _isometric; } } public static Basis25D ObliqueY { get { return _obliqueY; } } public static Basis25D ObliqueZ { get { return _obliqueZ; } } /// /// Creates a Dimetric Basis25D from the angle between the Y axis and the others. /// Dimetric(Tau/3) or Dimetric(2.09439510239) is the same as Isometric. /// Try to keep this number away from a multiple of Tau/4 (or Pi/2) radians. /// /// The angle, in radians, between the Y axis and the X/Z axes. public static Basis25D Dimetric(real_t angle) { real_t sin = Mathf.Sin(angle); real_t cos = Mathf.Cos(angle); return new Basis25D(sin, -cos, 0, -1, -sin, -cos); } // Constructors public Basis25D(Basis25D b) { x = b.x; y = b.y; z = b.z; } public Basis25D(Vector2 xAxis, Vector2 yAxis, Vector2 zAxis) { x = xAxis; y = yAxis; z = zAxis; } public Basis25D(real_t xx, real_t xy, real_t yx, real_t yy, real_t zx, real_t zy) { x = new Vector2(xx, xy); y = new Vector2(yx, yy); z = new Vector2(zx, zy); } public static Basis25D operator *(Basis25D b, real_t s) { b.x *= s; b.y *= s; b.z *= s; return b; } public static Basis25D operator /(Basis25D b, real_t s) { b.x /= s; b.y /= s; b.z /= s; return b; } public static bool operator ==(Basis25D left, Basis25D right) { return left.Equals(right); } public static bool operator !=(Basis25D left, Basis25D right) { return !left.Equals(right); } public override bool Equals(object obj) { if (obj is Basis25D) { return Equals((Basis25D)obj); } return false; } public bool Equals(Basis25D other) { return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z); } public bool IsEqualApprox(Basis25D other) { return x.IsEqualApprox(other.x) && y.IsEqualApprox(other.y) && z.IsEqualApprox(other.z); } public override int GetHashCode() { return y.GetHashCode() ^ x.GetHashCode() ^ z.GetHashCode(); } public override string ToString() { string s = String.Format("({0}, {1}, {2})", new object[] { x.ToString(), y.ToString(), z.ToString() }); return s; } public string ToString(string format) { string s = String.Format("({0}, {1}, {2})", new object[] { x.ToString(format), y.ToString(format), z.ToString(format) }); return s; } }