using System; using System.Runtime.InteropServices; namespace AssetStudio { [StructLayout(LayoutKind.Sequential, Pack = 4)] public struct Matrix4x4 : IEquatable { public float M00; public float M10; public float M20; public float M30; public float M01; public float M11; public float M21; public float M31; public float M02; public float M12; public float M22; public float M32; public float M03; public float M13; public float M23; public float M33; public Matrix4x4(float[] values) { if (values == null) throw new ArgumentNullException(nameof(values)); if (values.Length != 16) throw new ArgumentOutOfRangeException(nameof(values), "There must be sixteen and only sixteen input values for Matrix."); M00 = values[0]; M10 = values[1]; M20 = values[2]; M30 = values[3]; M01 = values[4]; M11 = values[5]; M21 = values[6]; M31 = values[7]; M02 = values[8]; M12 = values[9]; M22 = values[10]; M32 = values[11]; M03 = values[12]; M13 = values[13]; M23 = values[14]; M33 = values[15]; } public float this[int row, int column] { get => this[row + column * 4]; set => this[row + column * 4] = value; } public float this[int index] { get { switch (index) { case 0: return M00; case 1: return M10; case 2: return M20; case 3: return M30; case 4: return M01; case 5: return M11; case 6: return M21; case 7: return M31; case 8: return M02; case 9: return M12; case 10: return M22; case 11: return M32; case 12: return M03; case 13: return M13; case 14: return M23; case 15: return M33; default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid Matrix4x4 index!"); } } set { switch (index) { case 0: M00 = value; break; case 1: M10 = value; break; case 2: M20 = value; break; case 3: M30 = value; break; case 4: M01 = value; break; case 5: M11 = value; break; case 6: M21 = value; break; case 7: M31 = value; break; case 8: M02 = value; break; case 9: M12 = value; break; case 10: M22 = value; break; case 11: M32 = value; break; case 12: M03 = value; break; case 13: M13 = value; break; case 14: M23 = value; break; case 15: M33 = value; break; default: throw new ArgumentOutOfRangeException(nameof(index), "Invalid Matrix4x4 index!"); } } } public override int GetHashCode() { return GetColumn(0).GetHashCode() ^ (GetColumn(1).GetHashCode() << 2) ^ (GetColumn(2).GetHashCode() >> 2) ^ (GetColumn(3).GetHashCode() >> 1); } public override bool Equals(object other) { if (!(other is Matrix4x4)) return false; return Equals((Matrix4x4)other); } public bool Equals(Matrix4x4 other) { return GetColumn(0).Equals(other.GetColumn(0)) && GetColumn(1).Equals(other.GetColumn(1)) && GetColumn(2).Equals(other.GetColumn(2)) && GetColumn(3).Equals(other.GetColumn(3)); } public Vector4 GetColumn(int index) { switch (index) { case 0: return new Vector4(M00, M10, M20, M30); case 1: return new Vector4(M01, M11, M21, M31); case 2: return new Vector4(M02, M12, M22, M32); case 3: return new Vector4(M03, M13, M23, M33); default: throw new IndexOutOfRangeException("Invalid column index!"); } } public Vector4 GetRow(int index) { switch (index) { case 0: return new Vector4(M00, M01, M02, M03); case 1: return new Vector4(M10, M11, M12, M13); case 2: return new Vector4(M20, M21, M22, M23); case 3: return new Vector4(M30, M31, M32, M33); default: throw new IndexOutOfRangeException("Invalid row index!"); } } public static Matrix4x4 operator *(Matrix4x4 lhs, Matrix4x4 rhs) { Matrix4x4 res; res.M00 = lhs.M00 * rhs.M00 + lhs.M01 * rhs.M10 + lhs.M02 * rhs.M20 + lhs.M03 * rhs.M30; res.M01 = lhs.M00 * rhs.M01 + lhs.M01 * rhs.M11 + lhs.M02 * rhs.M21 + lhs.M03 * rhs.M31; res.M02 = lhs.M00 * rhs.M02 + lhs.M01 * rhs.M12 + lhs.M02 * rhs.M22 + lhs.M03 * rhs.M32; res.M03 = lhs.M00 * rhs.M03 + lhs.M01 * rhs.M13 + lhs.M02 * rhs.M23 + lhs.M03 * rhs.M33; res.M10 = lhs.M10 * rhs.M00 + lhs.M11 * rhs.M10 + lhs.M12 * rhs.M20 + lhs.M13 * rhs.M30; res.M11 = lhs.M10 * rhs.M01 + lhs.M11 * rhs.M11 + lhs.M12 * rhs.M21 + lhs.M13 * rhs.M31; res.M12 = lhs.M10 * rhs.M02 + lhs.M11 * rhs.M12 + lhs.M12 * rhs.M22 + lhs.M13 * rhs.M32; res.M13 = lhs.M10 * rhs.M03 + lhs.M11 * rhs.M13 + lhs.M12 * rhs.M23 + lhs.M13 * rhs.M33; res.M20 = lhs.M20 * rhs.M00 + lhs.M21 * rhs.M10 + lhs.M22 * rhs.M20 + lhs.M23 * rhs.M30; res.M21 = lhs.M20 * rhs.M01 + lhs.M21 * rhs.M11 + lhs.M22 * rhs.M21 + lhs.M23 * rhs.M31; res.M22 = lhs.M20 * rhs.M02 + lhs.M21 * rhs.M12 + lhs.M22 * rhs.M22 + lhs.M23 * rhs.M32; res.M23 = lhs.M20 * rhs.M03 + lhs.M21 * rhs.M13 + lhs.M22 * rhs.M23 + lhs.M23 * rhs.M33; res.M30 = lhs.M30 * rhs.M00 + lhs.M31 * rhs.M10 + lhs.M32 * rhs.M20 + lhs.M33 * rhs.M30; res.M31 = lhs.M30 * rhs.M01 + lhs.M31 * rhs.M11 + lhs.M32 * rhs.M21 + lhs.M33 * rhs.M31; res.M32 = lhs.M30 * rhs.M02 + lhs.M31 * rhs.M12 + lhs.M32 * rhs.M22 + lhs.M33 * rhs.M32; res.M33 = lhs.M30 * rhs.M03 + lhs.M31 * rhs.M13 + lhs.M32 * rhs.M23 + lhs.M33 * rhs.M33; return res; } public static bool operator ==(Matrix4x4 lhs, Matrix4x4 rhs) { return lhs.GetColumn(0) == rhs.GetColumn(0) && lhs.GetColumn(1) == rhs.GetColumn(1) && lhs.GetColumn(2) == rhs.GetColumn(2) && lhs.GetColumn(3) == rhs.GetColumn(3); } public static bool operator !=(Matrix4x4 lhs, Matrix4x4 rhs) { return !(lhs == rhs); } public static Matrix4x4 Scale(Vector3 vector) { Matrix4x4 m; m.M00 = vector.X; m.M01 = 0F; m.M02 = 0F; m.M03 = 0F; m.M10 = 0F; m.M11 = vector.Y; m.M12 = 0F; m.M13 = 0F; m.M20 = 0F; m.M21 = 0F; m.M22 = vector.Z; m.M23 = 0F; m.M30 = 0F; m.M31 = 0F; m.M32 = 0F; m.M33 = 1F; return m; } public static Matrix4x4 Translate(Vector3 vector) { Matrix4x4 m; m.M00 = 1F; m.M01 = 0F; m.M02 = 0F; m.M03 = vector.X; m.M10 = 0F; m.M11 = 1F; m.M12 = 0F; m.M13 = vector.Y; m.M20 = 0F; m.M21 = 0F; m.M22 = 1F; m.M23 = vector.Z; m.M30 = 0F; m.M31 = 0F; m.M32 = 0F; m.M33 = 1F; return m; } public static Matrix4x4 Rotate(Quaternion q) { float x = q.X * 2.0F; float y = q.Y * 2.0F; float z = q.Z * 2.0F; float xx = q.X * x; float yy = q.Y * y; float zz = q.Z * z; float xy = q.X * y; float xz = q.X * z; float yz = q.Y * z; float wx = q.W * x; float wy = q.W * y; float wz = q.W * z; Matrix4x4 m; m.M00 = 1.0f - (yy + zz); m.M10 = xy + wz; m.M20 = xz - wy; m.M30 = 0.0F; m.M01 = xy - wz; m.M11 = 1.0f - (xx + zz); m.M21 = yz + wx; m.M31 = 0.0F; m.M02 = xz + wy; m.M12 = yz - wx; m.M22 = 1.0f - (xx + yy); m.M32 = 0.0F; m.M03 = 0.0F; m.M13 = 0.0F; m.M23 = 0.0F; m.M33 = 1.0F; return m; } } }