Sfoglia il codice sorgente

Various improvements to math libraries
- Fixed incorrect euler angle <-> quaternion/matrix conversions
- Made YXZ default euler angle ordering
- Slightly faster implementations of some methods

Marko Pintera 10 anni fa
parent
commit
94a69a20bb

+ 7 - 20
BansheeUtility/Include/BsMatrix3.h

@@ -79,7 +79,7 @@ namespace BansheeEngine
         }
         }
 
 
         /**
         /**
-         * @brief	Construct a matrix from euler angles, XYZ ordering.
+         * @brief	Construct a matrix from euler angles, YXZ ordering.
          * 			
          * 			
 		 * @see		Matrix3::fromEulerAngles
 		 * @see		Matrix3::fromEulerAngles
          */
          */
@@ -247,27 +247,9 @@ namespace BansheeEngine
          * @return	True if unique solution was found, false otherwise.
          * @return	True if unique solution was found, false otherwise.
          * 			
          * 			
 		 * @note	Matrix must be orthonormal.
 		 * @note	Matrix must be orthonormal.
-		 * 			
-		 * 			Since different values will be returned depending in which order are the rotations applied, this method assumes
-		 * 			they are applied in XYZ order. If you need a specific order, use the overloaded "toEulerAngles" method instead.
          */
          */
         bool toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const;
         bool toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const;
 
 
-		/**
-		 * @brief	Extracts Pitch/Yaw/Roll rotations from this matrix.
-		 *
-		 * @param	xAngle	Rotation about x axis. (AKA Pitch)
-		 * @param	yAngle	Rotation about y axis. (AKA Yaw)
-		 * @param	zAngle	Rotation about z axis. (AKA Roll)
-		 * @param	order 	The order in which rotations will be extracted. 
-		 * 					Different values can be retrieved depending on the order.
-		 *
-		 * @return	True if unique solution was found, false otherwise.
-		 * 			
-		 * @note	Matrix must be orthonormal.
-		 */
-		bool toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle, EulerAngleOrder order) const;
-
         /**
         /**
          * @brief	Creates a rotation matrix from the provided Pitch/Yaw/Roll angles.
          * @brief	Creates a rotation matrix from the provided Pitch/Yaw/Roll angles.
          *
          *
@@ -277,7 +259,7 @@ namespace BansheeEngine
          *
          *
          * @note	Matrix must be orthonormal.
          * @note	Matrix must be orthonormal.
 		 * 			Since different values will be produced depending in which order are the rotations applied, this method assumes
 		 * 			Since different values will be produced depending in which order are the rotations applied, this method assumes
-		 * 			they are applied in XYZ order. If you need a specific order, use the overloaded "fromEulerAngles" method instead.
+		 * 			they are applied in YXZ order. If you need a specific order, use the overloaded "fromEulerAngles" method instead.
          */
          */
         void fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle);
         void fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle);
 
 
@@ -296,6 +278,11 @@ namespace BansheeEngine
 
 
         /**
         /**
          * @brief	Eigensolver, matrix must be symmetric.
          * @brief	Eigensolver, matrix must be symmetric.
+		 *
+		 * @note	Eigenvectors are vectors which when transformed by the matrix, only change
+		 *			in magnitude, but not in direction. Eigenvalue is that magnitude. In other words
+		 *			you will get the same result whether you multiply the vector by the matrix or by its
+		 *			eigenvalue.
          */
          */
         void eigenSolveSymmetric(float eigenValues[3], Vector3 eigenVectors[3]) const;
         void eigenSolveSymmetric(float eigenValues[3], Vector3 eigenVectors[3]) const;
 
 

+ 2 - 18
BansheeUtility/Include/BsQuaternion.h

@@ -47,7 +47,7 @@ namespace BansheeEngine
         }
         }
 
 
         /**
         /**
-         * @brief	Construct a quaternion from euler angles, XYZ ordering.
+         * @brief	Construct a quaternion from euler angles, YXZ ordering.
          * 			
          * 			
 		 * @see		Quaternion::fromEulerAngles
 		 * @see		Quaternion::fromEulerAngles
          */
          */
@@ -120,7 +120,7 @@ namespace BansheeEngine
 		 * @param	zAngle	Rotation about z axis. (AKA Roll)
 		 * @param	zAngle	Rotation about z axis. (AKA Roll)
          *
          *
          * @note	Since different values will be produced depending in which order are the rotations applied, this method assumes
          * @note	Since different values will be produced depending in which order are the rotations applied, this method assumes
-		 * 			they are applied in XYZ order. If you need a specific order, use the overloaded "fromEulerAngles" method instead.
+		 * 			they are applied in YXZ order. If you need a specific order, use the overloaded "fromEulerAngles" method instead.
          */
          */
         void fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle);
         void fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle);
 
 
@@ -165,25 +165,9 @@ namespace BansheeEngine
          * @param [out]	zAngle 	Rotation about z axis. (AKA Roll)
          * @param [out]	zAngle 	Rotation about z axis. (AKA Roll)
          *
          *
          * @return	True if unique solution was found, false otherwise.
          * @return	True if unique solution was found, false otherwise.
-         * 			
-		 * @note	Since different values will be returned depending in which order are the rotations applied, this method assumes
-		 * 			they are applied in XYZ order. If you need a specific order, use the overloaded "toEulerAngles" method instead.
          */
          */
         bool toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const;
         bool toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const;
 
 
-		/**
-		 * @brief	Extracts Pitch/Yaw/Roll rotations from this quaternion.
-		 *
-		 * @param [out]	xAngle	Rotation about x axis. (AKA Pitch)
-		 * @param [out]	yAngle	Rotation about y axis. (AKA Yaw)
-		 * @param [out]	zAngle	Rotation about z axis. (AKA Roll)
-		 * @param	order 	The order in which rotations will be extracted. 
-		 * 					Different values can be retrieved depending on the order.
-		 *
-		 * @return	True if unique solution was found, false otherwise.
-		 */
-		bool toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle, EulerAngleOrder order) const;
-
         /**
         /**
          * @brief	Get the local x-axis.
          * @brief	Get the local x-axis.
          */
          */

+ 48 - 71
BansheeUtility/Source/BsMatrix3.cpp

@@ -754,89 +754,59 @@ namespace BansheeEngine
 
 
     bool Matrix3::toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const
     bool Matrix3::toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const
     {
     {
-        xAngle = Radian(Math::asin(m[0][2]));
+        xAngle = -Radian(Math::asin(m[1][2]));
         if (xAngle < Radian(Math::HALF_PI))
         if (xAngle < Radian(Math::HALF_PI))
         {
         {
             if (xAngle > Radian(-Math::HALF_PI))
             if (xAngle > Radian(-Math::HALF_PI))
             {
             {
-                yAngle = Math::atan2(-m[1][2], m[2][2]);
-                zAngle = Math::atan2(-m[0][1], m[0][0]);
+                yAngle = Math::atan2(m[0][2], m[2][2]);
+                zAngle = Math::atan2(m[1][0], m[1][1]);
 
 
                 return true;
                 return true;
             }
             }
             else
             else
             {
             {
-                // WARNING.  Not a unique solution.
-                Radian angle = Math::atan2(m[1][0],m[1][1]);
-                zAngle = Radian(0.0f);  // Any angle works
-                yAngle = zAngle - angle;
+                // Note: Not an unique solution.
+				xAngle = Radian(-Math::HALF_PI);
+				yAngle = Math::atan2(-m[0][1], m[0][0]);
+				zAngle = Radian(0.0f);
 
 
                 return false;
                 return false;
             }
             }
         }
         }
         else
         else
         {
         {
-            // WARNING.  Not a unique solution.
-            Radian angle = Math::atan2(m[1][0],m[1][1]);
-            zAngle = Radian(0.0f);  // Any angle works
-            yAngle = angle - zAngle;
-
+            // Note: Not an unique solution.
+			xAngle = Radian(Math::HALF_PI);
+			yAngle = Math::atan2(m[0][1], m[0][0]);
+            zAngle = Radian(0.0f);
+			
             return false;
             return false;
         }
         }
     }
     }
 
 
-	bool Matrix3::toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle, EulerAngleOrder order) const
-	{
-		const EulerAngleOrderData& l = EA_LOOKUP[(int)order];
-
-		xAngle = Radian(Math::asin(l.sign * m[l.a][l.c]));
-		if (xAngle < Radian(Math::HALF_PI))
-		{
-			if (xAngle > Radian(-Math::HALF_PI))
-			{
-				yAngle = Math::atan2(-l.sign * m[l.b][l.c], m[l.c][l.c]);
-				zAngle = Math::atan2(-l.sign * m[l.a][l.b], m[l.a][l.a]);
-
-				return true;
-			}
-			else
-			{
-				// WARNING.  Not a unique solution.
-				Radian angle = Math::atan2(l.sign * m[l.b][l.a], m[l.b][l.b]);
-				zAngle = Radian(0.0f);  // Any angle works
-				yAngle = zAngle - angle;
-
-				return false;
-			}
-		}
-		else
-		{
-			// WARNING.  Not a unique solution.
-			Radian angle = Math::atan2(l.sign * m[l.b][l.a], m[l.b][l.b]);
-			zAngle = Radian(0.0f);  // Any angle works
-			yAngle = angle - zAngle;
-
-			return false;
-		}
-	}
-
     void Matrix3::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle)
     void Matrix3::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle)
     {
     {
-        float cos, sin;
+		float cx = Math::cos(xAngle);
+		float sx = Math::sin(xAngle);
+
+		float cy = Math::cos(yAngle);
+		float sy = Math::sin(yAngle);
 
 
-        cos = Math::cos(yAngle);
-        sin = Math::sin(yAngle);
-        Matrix3 xMat(1.0f, 0.0f, 0.0f, 0.0f, cos, -sin, 0.0f, sin, cos);
+        float cz = Math::cos(zAngle);
+		float sz = Math::sin(zAngle);
 
 
-        cos = Math::cos(xAngle);
-        sin = Math::sin(xAngle);
-        Matrix3 yMat(cos, 0.0f, sin, 0.0f, 1.0f, 0.0f, -sin, 0.0f, cos);
+		m[0][0] = cy * cz + sx * sy * sz;
+		m[0][1] = cz * sx * sy - cy * sz;
+		m[0][2] = cx * sy;
 
 
-        cos = Math::cos(zAngle);
-        sin = Math::sin(zAngle);
-        Matrix3 zMat(cos,-sin, 0.0f, sin, cos, 0.0f, 0.0f, 0.0f, 1.0f);
+		m[1][0] = cx * sz;
+		m[1][1] = cx * cz;
+		m[1][2] = -sx;
 
 
-        *this = xMat*(yMat*zMat);
+		m[2][0] = -cz * sy + cy * sx * sz;
+		m[2][1] = cy * cz * sx + sy * sz;
+		m[2][2] = cx * cy;
     }
     }
 
 
 	void Matrix3::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order)
 	void Matrix3::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order)
@@ -844,19 +814,26 @@ namespace BansheeEngine
 		const EulerAngleOrderData& l = EA_LOOKUP[(int)order];
 		const EulerAngleOrderData& l = EA_LOOKUP[(int)order];
 
 
 		Matrix3 mats[3];
 		Matrix3 mats[3];
-		float cos, sin;
-
-		cos = Math::cos(yAngle);
-		sin = Math::sin(yAngle);
-		mats[0] = Matrix3(1.0f, 0.0f, 0.0f, 0.0f, cos, -sin, 0.0f, sin, cos);
-
-		cos = Math::cos(xAngle);
-		sin = Math::sin(xAngle);
-		mats[1] = Matrix3(cos, 0.0f, sin, 0.0f, 1.0f, 0.0f, -sin, 0.0f, cos);
-
-		cos = Math::cos(zAngle);
-		sin = Math::sin(zAngle);
-		mats[2] = Matrix3(cos,-sin, 0.0f, sin, cos, 0.0f, 0.0f, 0.0f, 1.0f);
+		float cx = Math::cos(xAngle);
+		float sx = Math::sin(xAngle);
+		mats[0] = Matrix3(
+			1.0f, 0.0f, 0.0f,
+			0.0f, cx, -sx,
+			0.0f, sx, cx);
+
+		float cy = Math::cos(yAngle);
+		float sy = Math::sin(yAngle);
+		mats[1] = Matrix3(
+			cy, 0.0f, sy,
+			0.0f, 1.0f, 0.0f,
+			-sy, 0.0f, cy);
+
+		float cz = Math::cos(zAngle);
+		float sz = Math::sin(zAngle);
+		mats[2] = Matrix3(
+			cz, -sz, 0.0f,
+			sz, cz, 0.0f,
+			0.0f, 0.0f, 1.0f);
 	
 	
 		*this = mats[l.a]*(mats[l.b]*mats[l.c]);
 		*this = mats[l.a]*(mats[l.b]*mats[l.c]);
 	}
 	}

+ 40 - 15
BansheeUtility/Source/BsQuaternion.cpp

@@ -62,10 +62,9 @@ namespace BansheeEngine
 
 
     void Quaternion::fromAxisAngle(const Vector3& axis, const Radian& angle)
     void Quaternion::fromAxisAngle(const Vector3& axis, const Radian& angle)
     {
     {
-        // Assert:  axis[] is unit length
-
         Radian halfAngle (0.5f*angle);
         Radian halfAngle (0.5f*angle);
         float sin = Math::sin(halfAngle);
         float sin = Math::sin(halfAngle);
+
         w = Math::cos(halfAngle);
         w = Math::cos(halfAngle);
         x = sin*axis.x;
         x = sin*axis.x;
         y = sin*axis.y;
         y = sin*axis.y;
@@ -93,16 +92,49 @@ namespace BansheeEngine
 
 
 	void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle)
 	void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle)
 	{
 	{
-		Matrix3 mat;
-		mat.fromEulerAngles(xAngle, yAngle, zAngle);
-		mat.toQuaternion(*this);
+		Radian halfXAngle = xAngle * 0.5f;
+		Radian halfYAngle = yAngle * 0.5f;
+		Radian halfZAngle = zAngle * 0.5f;
+
+		float cx = Math::cos(halfXAngle);
+		float sx = Math::sin(halfXAngle);
+
+		float cy = Math::cos(halfYAngle);
+		float sy = Math::sin(halfYAngle);
+
+		float cz = Math::cos(halfZAngle);
+		float sz = Math::sin(halfZAngle);
+
+		Quaternion quatX(cx, sx, 0.0f, 0.0f);
+		Quaternion quatY(cy, 0.0f, sy, 0.0f);
+		Quaternion quatZ(cz, 0.0f, 0.0f, sz);
+
+		*this = (quatY * quatX) * quatZ;
 	}
 	}
 
 
 	void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order)
 	void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order)
 	{
 	{
-		Matrix3 mat;
-		mat.fromEulerAngles(xAngle, yAngle, zAngle, order);
-		mat.toQuaternion(*this);
+		const EulerAngleOrderData& l = EA_LOOKUP[(int)order];
+
+		Radian halfXAngle = xAngle * 0.5f;
+		Radian halfYAngle = yAngle * 0.5f;
+		Radian halfZAngle = zAngle * 0.5f;
+
+		float cx = Math::cos(halfXAngle);
+		float sx = Math::sin(halfXAngle);
+
+		float cy = Math::cos(halfYAngle);
+		float sy = Math::sin(halfYAngle);
+
+		float cz = Math::cos(halfZAngle);
+		float sz = Math::sin(halfZAngle);
+
+		Quaternion quats[3];
+		quats[0] = Quaternion(cx, sx, 0.0f, 0.0f);
+		quats[1] = Quaternion(cy, 0.0f, sy, 0.0f);
+		quats[2] = Quaternion(cz, 0.0f, 0.0f, sz);
+
+		*this = (quats[l.a] * quats[l.b]) * quats[l.c];
 	}
 	}
 
 
 	void Quaternion::toRotationMatrix(Matrix3& mat) const
 	void Quaternion::toRotationMatrix(Matrix3& mat) const
@@ -177,13 +209,6 @@ namespace BansheeEngine
 		return matRot.toEulerAngles(xAngle, yAngle, zAngle);
 		return matRot.toEulerAngles(xAngle, yAngle, zAngle);
 	}
 	}
 
 
-	bool Quaternion::toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle, EulerAngleOrder order) const
-	{
-		Matrix3 matRot;
-		toRotationMatrix(matRot);
-		return matRot.toEulerAngles(xAngle, yAngle, zAngle, order);
-	}
-
     Vector3 Quaternion::xAxis() const
     Vector3 Quaternion::xAxis() const
     {
     {
         float fTy  = 2.0f*y;
         float fTy  = 2.0f*y;

+ 35 - 0
MBansheeEngine/Math/MathEx.cs

@@ -221,6 +221,41 @@ namespace BansheeEngine
             return (float)Math.Atan2(y, x);
             return (float)Math.Atan2(y, x);
         }
         }
 
 
+        public static float Sin(Radian f)
+        {
+            return (float)Math.Sin(f.Radians);
+        }
+
+        public static float Cos(Radian f)
+        {
+            return (float)Math.Cos(f.Radians);
+        }
+
+        public static float Tan(Radian f)
+        {
+            return (float)Math.Tan(f.Radians);
+        }
+
+        public static float Asin(Radian f)
+        {
+            return (float)Math.Asin(f.Radians);
+        }
+
+        public static float Acos(Radian f)
+        {
+            return (float)Math.Acos(f.Radians);
+        }
+
+        public static float Atan(Radian f)
+        {
+            return (float)Math.Atan(f.Radians);
+        }
+
+        public static float Atan2(Radian y, Radian x)
+        {
+            return (float)Math.Atan2(y.Radians, x.Radians);
+        }
+
         public static float Sqrt(float f)
         public static float Sqrt(float f)
         {
         {
             return (float)Math.Sqrt(f);
             return (float)Math.Sqrt(f);

+ 73 - 29
MBansheeEngine/Math/Matrix3.cs

@@ -326,36 +326,34 @@ namespace BansheeEngine
         /**
         /**
          * @note    Returns angles in degrees.
          * @note    Returns angles in degrees.
          */
          */
-        public Vector3 ToEulerAngles(EulerAngleOrder order = EulerAngleOrder.XYZ)
+        public Vector3 ToEulerAngles()
         {
         {
-            EulerAngleOrderData l = EA_LOOKUP[(int)order];
-
-		    float xAngle = MathEx.Asin(l.sign * this[l.a, l.c]);
+            float xAngle = -MathEx.Asin(this[1, 2]);
 		    if (xAngle < MathEx.HalfPi)
 		    if (xAngle < MathEx.HalfPi)
 		    {
 		    {
 			    if (xAngle > -MathEx.HalfPi)
 			    if (xAngle > -MathEx.HalfPi)
 			    {
 			    {
-				    float yAngle = MathEx.Atan2(-l.sign * this[l.b, l.c], this[l.c, l.c]);
-				    float zAngle = MathEx.Atan2(-l.sign * this[l.a, l.b], this[l.a, l.a]);
+				    float yAngle = MathEx.Atan2(this[0, 2], this[2, 2]);
+				    float zAngle = MathEx.Atan2(this[1, 0], this[1, 1]);
 
 
                     return new Vector3(xAngle * MathEx.Rad2Deg, yAngle * MathEx.Rad2Deg, zAngle * MathEx.Rad2Deg);
                     return new Vector3(xAngle * MathEx.Rad2Deg, yAngle * MathEx.Rad2Deg, zAngle * MathEx.Rad2Deg);
 			    }
 			    }
 			    else
 			    else
 			    {
 			    {
-				    // WARNING.  Not a unique solution.
-				    float angle = MathEx.Atan2(l.sign * this[l.b, l.a], this[l.b, l.b]);
-				    float zAngle = 0.0f;  // Any angle works
-				    float yAngle = zAngle - angle;
-
+				    // Note: Not an unique solution.
+			        xAngle = -MathEx.HalfPi;
+                    float yAngle = MathEx.Atan2(-this[0, 1], this[0, 0]);
+				    float zAngle = 0.0f;
+				    
                     return new Vector3(xAngle * MathEx.Rad2Deg, yAngle * MathEx.Rad2Deg, zAngle * MathEx.Rad2Deg);
                     return new Vector3(xAngle * MathEx.Rad2Deg, yAngle * MathEx.Rad2Deg, zAngle * MathEx.Rad2Deg);
 			    }
 			    }
 		    }
 		    }
 		    else
 		    else
 		    {
 		    {
-			    // WARNING.  Not a unique solution.
-			    float angle = MathEx.Atan2(l.sign * this[l.b, l.a], this[l.b, l.b]);
-                float zAngle = 0.0f; // Any angle works
-			    float yAngle = angle - zAngle;
+			    // Note: Not an unique solution.
+                xAngle = MathEx.HalfPi;
+                float yAngle = MathEx.Atan2(this[0, 1], this[0, 0]);
+                float zAngle = 0.0f; 
 
 
                 return new Vector3(xAngle * MathEx.Rad2Deg, yAngle * MathEx.Rad2Deg, zAngle * MathEx.Rad2Deg);
                 return new Vector3(xAngle * MathEx.Rad2Deg, yAngle * MathEx.Rad2Deg, zAngle * MathEx.Rad2Deg);
 		    }
 		    }
@@ -454,33 +452,79 @@ namespace BansheeEngine
         }
         }
 
 
         public static Matrix3 FromEuler(Vector3 eulerDeg, EulerAngleOrder order)
         public static Matrix3 FromEuler(Vector3 eulerDeg, EulerAngleOrder order)
+        {
+            return FromEuler(new Degree(eulerDeg.x), new Degree(eulerDeg.y), new Degree(eulerDeg.y), order);
+        }
+
+        public static Matrix3 FromEuler(Radian xAngle, Radian yAngle, Radian zAngle, EulerAngleOrder order)
         {
         {
             EulerAngleOrderData l = EA_LOOKUP[(int)order];
             EulerAngleOrderData l = EA_LOOKUP[(int)order];
 
 
 		    Matrix3[] mats = new Matrix3[3];
 		    Matrix3[] mats = new Matrix3[3];
-		    float cos, sin;
 
 
-		    cos = MathEx.Cos(eulerDeg.y * MathEx.Deg2Rad);
-            sin = MathEx.Sin(eulerDeg.y * MathEx.Deg2Rad);
-		    mats[0] = new Matrix3(1.0f, 0.0f, 0.0f, 0.0f, cos, -sin, 0.0f, sin, cos);
-
-            cos = MathEx.Cos(eulerDeg.x * MathEx.Deg2Rad);
-            sin = MathEx.Sin(eulerDeg.x * MathEx.Deg2Rad);
-		    mats[1] = new Matrix3(cos, 0.0f, sin, 0.0f, 1.0f, 0.0f, -sin, 0.0f, cos);
-
-            cos = MathEx.Cos(eulerDeg.z * MathEx.Deg2Rad);
-            sin = MathEx.Sin(eulerDeg.z * MathEx.Deg2Rad);
-		    mats[2] = new Matrix3(cos,-sin, 0.0f, sin, cos, 0.0f, 0.0f, 0.0f, 1.0f);
+            float cx = MathEx.Cos(xAngle);
+            float sx = MathEx.Sin(xAngle);
+		    mats[0] = new Matrix3(
+			    1.0f, 0.0f, 0.0f,
+			    0.0f, cx, -sx,
+			    0.0f, sx, cx);
+
+            float cy = MathEx.Cos(yAngle);
+            float sy = MathEx.Sin(yAngle);
+		    mats[1] = new Matrix3(
+			    cy, 0.0f, sy,
+			    0.0f, 1.0f, 0.0f,
+			    -sy, 0.0f, cy);
+
+            float cz = MathEx.Cos(zAngle);
+            float sz = MathEx.Sin(zAngle);
+		    mats[2] = new Matrix3(
+			    cz, -sz, 0.0f,
+			    sz, cz, 0.0f,
+			    0.0f, 0.0f, 1.0f);
 	
 	
 		    return mats[l.a]*(mats[l.b]*mats[l.c]);
 		    return mats[l.a]*(mats[l.b]*mats[l.c]);
         }
         }
 
 
+        public static Matrix3 FromEuler(Vector3 eulerDeg)
+        {
+            return FromEuler(new Degree(eulerDeg.x), new Degree(eulerDeg.y), new Degree(eulerDeg.y));
+        }
+
+        public static Matrix3 FromEuler(Radian xAngle, Radian yAngle, Radian zAngle)
+        {
+            Matrix3 m = new Matrix3();
+
+		    float cx = MathEx.Cos(xAngle);
+		    float sx = MathEx.Sin(xAngle);
+
+		    float cy = MathEx.Cos(yAngle);
+		    float sy = MathEx.Sin(yAngle);
+
+            float cz = MathEx.Cos(zAngle);
+		    float sz = MathEx.Sin(zAngle);
+
+		    m[0, 0] = cy * cz + sx * sy * sz;
+		    m[0, 1] = cz * sx * sy - cy * sz;
+		    m[0, 2] = cx * sy;
+
+		    m[1, 0] = cx * sz;
+		    m[1, 1] = cx * cz;
+		    m[1, 2] = -sx;
+
+		    m[2, 0] = -cz * sy + cy * sx * sz;
+		    m[2, 1] = cy * cz * sx + sy * sz;
+		    m[2, 2] = cx * cy;
+
+            return m;
+        }
+
         public static Matrix3 FromAxisAngle(Vector3 axis, Degree angle)
         public static Matrix3 FromAxisAngle(Vector3 axis, Degree angle)
         {
         {
             Matrix3 mat;
             Matrix3 mat;
 
 
-            float cos = MathEx.Cos(angle.Radians);
-            float sin = MathEx.Sin(angle.Radians);
+            float cos = MathEx.Cos(angle);
+            float sin = MathEx.Sin(angle);
             float oneMinusCos = 1.0f - cos;
             float oneMinusCos = 1.0f - cos;
             float x2 = axis.x * axis.x;
             float x2 = axis.x * axis.x;
             float y2 = axis.y * axis.y;
             float y2 = axis.y * axis.y;

+ 50 - 11
MBansheeEngine/Math/Quaternion.cs

@@ -125,6 +125,26 @@ namespace BansheeEngine
             }
             }
         }
         }
 
 
+        public Quaternion Inverse
+        {
+            get
+            {
+                Quaternion copy = this;
+                copy.Invert();
+                return copy;
+            }
+        }
+
+        public Quaternion Normalized
+        {
+            get
+            {
+                Quaternion copy = this;
+                copy.Normalize();
+                return copy;
+            }
+        }
+
         public Quaternion(float x, float y, float z, float w)
         public Quaternion(float x, float y, float z, float w)
         {
         {
             this.x = x;
             this.x = x;
@@ -244,7 +264,7 @@ namespace BansheeEngine
             return len;
             return len;
         }
         }
 
 
-        public void Inverse()
+        public void Invert()
         {
         {
             float fNorm = w * w + x * x + y * y + z * z;
             float fNorm = w * w + x * x + y * y + z * z;
             if (fNorm > 0.0f)
             if (fNorm > 0.0f)
@@ -325,10 +345,10 @@ namespace BansheeEngine
             return Slerp(from, to, t);
             return Slerp(from, to, t);
         }
         }
 
 
-        public static Quaternion Inverse(Quaternion rotation)
+        public static Quaternion Invert(Quaternion rotation)
         {
         {
             Quaternion copy = rotation;
             Quaternion copy = rotation;
-            copy.Inverse();
+            copy.Invert();
 
 
             return copy;
             return copy;
         }
         }
@@ -360,10 +380,10 @@ namespace BansheeEngine
         }
         }
 
 
         // Returns angles in degrees
         // Returns angles in degrees
-        public Vector3 ToEuler(EulerAngleOrder order = EulerAngleOrder.XYZ)
+        public Vector3 ToEuler()
         {
         {
             Matrix3 matRot = ToRotationMatrix();
             Matrix3 matRot = ToRotationMatrix();
-            return matRot.ToEulerAngles(order);
+            return matRot.ToEulerAngles();
         }
         }
 
 
         public Matrix3 ToRotationMatrix()
         public Matrix3 ToRotationMatrix()
@@ -426,9 +446,9 @@ namespace BansheeEngine
             return quat;
             return quat;
         }
         }
 
 
-        public static Vector3 ToEuler(Quaternion rotation, EulerAngleOrder order = EulerAngleOrder.XYZ)
+        public static Vector3 ToEuler(Quaternion rotation)
         {
         {
-            return rotation.ToEuler(order);
+            return rotation.ToEuler();
         }
         }
 
 
         public static void ToAxisAngle(Quaternion rotation, out Vector3 axis, out Degree angleDeg)
         public static void ToAxisAngle(Quaternion rotation, out Vector3 axis, out Degree angleDeg)
@@ -499,16 +519,35 @@ namespace BansheeEngine
             return quat;
             return quat;
         }
         }
 
 
-        public static Quaternion FromEuler(float xDeg, float yDeg, float zDeg, EulerAngleOrder order = EulerAngleOrder.XYZ)
+        public static Quaternion FromEuler(Degree xDeg, Degree yDeg, Degree zDeg, EulerAngleOrder order = EulerAngleOrder.YXZ)
         {
         {
-            Matrix3 mat = Matrix3.FromEuler(new Vector3(xDeg, yDeg, zDeg), order);
-            return mat.ToQuaternion();
+		    EulerAngleOrderData l = EA_LOOKUP[(int)order];
+
+		    Radian halfXAngle = xDeg * 0.5f;
+		    Radian halfYAngle = yDeg * 0.5f;
+		    Radian halfZAngle = zDeg * 0.5f;
+
+		    float cx = MathEx.Cos(halfXAngle);
+		    float sx = MathEx.Sin(halfXAngle);
+
+		    float cy = MathEx.Cos(halfYAngle);
+		    float sy = MathEx.Sin(halfYAngle);
+
+		    float cz = MathEx.Cos(halfZAngle);
+		    float sz = MathEx.Sin(halfZAngle);
+
+		    Quaternion[] quats = new Quaternion[3];
+		    quats[0] = new Quaternion(cx, sx, 0.0f, 0.0f);
+		    quats[1] = new Quaternion(cy, 0.0f, sy, 0.0f);
+		    quats[2] = new Quaternion(cz, 0.0f, 0.0f, sz);
+
+		    return (quats[l.a] * quats[l.b]) * quats[l.c];
         }
         }
 
 
         /**
         /**
          * @note Angles in degrees.
          * @note Angles in degrees.
          */
          */
-        public static Quaternion FromEuler(Vector3 euler, EulerAngleOrder order = EulerAngleOrder.XYZ)
+        public static Quaternion FromEuler(Vector3 euler, EulerAngleOrder order = EulerAngleOrder.YXZ)
         {
         {
             return FromEuler(euler.x, euler.y, euler.z, order);
             return FromEuler(euler.x, euler.y, euler.z, order);
         }
         }

+ 22 - 2
TODO.txt

@@ -56,12 +56,24 @@ Code quality improvements:
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Polish stage 1
 Polish stage 1
 
 
+Handles:
+Move plane handles could be more precise
+Once rotated further rotations seem to be going in wrong direction and gizmo is messed up
+Rotations seems to be going in the wrong direction
+Rotations around center incorrectly move and rotate the rotation gizmos
+Free rotation handle doesn't seem to be implemented
+Investigate rotation local/global (also move, I don't think its implemented properly, I seem to be modifying only Position)
+Investigate scale
+Check multi-select move/Rotate/scale
+
+There's a large hang when doing certain operations like selecting a mesh in scene, or switching from center to pivot mode
+Crash on shutdown in mono_gchandle_free
 When selecting an gizmo icon the selection seems delayed and its gizmos flash for a frame before hiding (Can't reproduce atm but I saw it)
 When selecting an gizmo icon the selection seems delayed and its gizmos flash for a frame before hiding (Can't reproduce atm but I saw it)
 Decent looking default layout
 Decent looking default layout
+ProjectLibrary seems to import some files on every start-up
 
 
 Fix handles
 Fix handles
  - Some handle functionality is unfinished
  - Some handle functionality is unfinished
- - Handles look too large when scene view is enlarged
  - Moving around XZ plane seems to be wrong (it doesn't move as fast as the mouse)
  - Moving around XZ plane seems to be wrong (it doesn't move as fast as the mouse)
 
 
 SceneTreeView
 SceneTreeView
@@ -89,10 +101,19 @@ When building game make sure to go over texture resources and ensure they are sa
 as we don't want to do format conversion at runtime (Not cruical, but it should be done eventually)
 as we don't want to do format conversion at runtime (Not cruical, but it should be done eventually)
  - This should something similar to Unity where when changing the platform all resources get reimported
  - This should something similar to Unity where when changing the platform all resources get reimported
 
 
+Later:
+ - Save the default editor layout somewhere and make sure its used on initial startup when no layout exists
+
+Will need a status bar:
+ - Displays last error message
+ - Opens up console on click
+ - Indicator when compiling
+
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Project window
 Project window
 
 
 Later:
 Later:
+ - Might need to improve search (need to test). Do multiple search keywords work properly?
  - Consider delaying search until user stops pressing keys (so not to have thousands of search results in the initial stages)
  - Consider delaying search until user stops pressing keys (so not to have thousands of search results in the initial stages)
  - Save & restore scroll position when Refresh happens
  - Save & restore scroll position when Refresh happens
 
 
@@ -130,7 +151,6 @@ Simple stuff
 Handles
 Handles
 
 
 When scaling using center make sure to offset the object before scale
 When scaling using center make sure to offset the object before scale
-Handles should probably not having shading, or have better shading.
 
 
 Rotate handle:
 Rotate handle:
  - How to handle local/global with rotate handle?
  - How to handle local/global with rotate handle?