|  |  | @ -2552,65 +2552,91 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q) | 
		
	
		
			
			|  |  |  | return result; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Decompose a transformation matrix into its rotational, translational and scaling components | 
		
	
		
			
			|  |  |  | // Decompose a transformation matrix into its rotational, translational and scaling components and remove shear | 
		
	
		
			
			|  |  |  | RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | // Extract translation. | 
		
	
		
			
			|  |  |  | float eps = 1e-9; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Extract Translation | 
		
	
		
			
			|  |  |  | translation->x = mat.m12; | 
		
	
		
			
			|  |  |  | translation->y = mat.m13; | 
		
	
		
			
			|  |  |  | translation->z = mat.m14; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Extract upper-left for determinant computation | 
		
	
		
			
			|  |  |  | const float a = mat.m0; | 
		
	
		
			
			|  |  |  | const float b = mat.m4; | 
		
	
		
			
			|  |  |  | const float c = mat.m8; | 
		
	
		
			
			|  |  |  | const float d = mat.m1; | 
		
	
		
			
			|  |  |  | const float e = mat.m5; | 
		
	
		
			
			|  |  |  | const float f = mat.m9; | 
		
	
		
			
			|  |  |  | const float g = mat.m2; | 
		
	
		
			
			|  |  |  | const float h = mat.m6; | 
		
	
		
			
			|  |  |  | const float i = mat.m10; | 
		
	
		
			
			|  |  |  | const float A = e*i - f*h; | 
		
	
		
			
			|  |  |  | const float B = f*g - d*i; | 
		
	
		
			
			|  |  |  | const float C = d*h - e*g; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Extract scale | 
		
	
		
			
			|  |  |  | const float det = a*A + b*B + c*C; | 
		
	
		
			
			|  |  |  | Vector3 abc = { a, b, c }; | 
		
	
		
			
			|  |  |  | Vector3 def = { d, e, f }; | 
		
	
		
			
			|  |  |  | Vector3 ghi = { g, h, i }; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | float scalex = Vector3Length(abc); | 
		
	
		
			
			|  |  |  | float scaley = Vector3Length(def); | 
		
	
		
			
			|  |  |  | float scalez = Vector3Length(ghi); | 
		
	
		
			
			|  |  |  | Vector3 s = { scalex, scaley, scalez }; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if (det < 0) s = Vector3Negate(s); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | *scale = s; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Remove scale from the matrix if it is not close to zero | 
		
	
		
			
			|  |  |  | Matrix clone = mat; | 
		
	
		
			
			|  |  |  | if (!FloatEquals(det, 0)) | 
		
	
		
			
			|  |  |  | // Matrix Columns - Rotation will be extracted into here. | 
		
	
		
			
			|  |  |  | Vector3 matColumns[3] = { { mat.m0, mat.m4, mat.m8 }, | 
		
	
		
			
			|  |  |  | { mat.m1, mat.m5, mat.m9 }, | 
		
	
		
			
			|  |  |  | { mat.m2, mat.m6, mat.m10 } }; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Shear Parameters XY, XZ, and YZ (extract and ignored) | 
		
	
		
			
			|  |  |  | float shear[3] = { 0 }; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Normalized Scale Parameters | 
		
	
		
			
			|  |  |  | Vector3 scl = { 0 }; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Max-Normalizing helps numerical stability | 
		
	
		
			
			|  |  |  | float stabilizer = eps; | 
		
	
		
			
			|  |  |  | for (int i = 0; i < 3; i++) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x)); | 
		
	
		
			
			|  |  |  | stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y)); | 
		
	
		
			
			|  |  |  | stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z)); | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer); | 
		
	
		
			
			|  |  |  | matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer); | 
		
	
		
			
			|  |  |  | matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // X Scale | 
		
	
		
			
			|  |  |  | scl.x = Vector3Length(matColumns[0]); | 
		
	
		
			
			|  |  |  | if (scl.x > eps) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | clone.m0 /= s.x; | 
		
	
		
			
			|  |  |  | clone.m4 /= s.x; | 
		
	
		
			
			|  |  |  | clone.m8 /= s.x; | 
		
	
		
			
			|  |  |  | clone.m1 /= s.y; | 
		
	
		
			
			|  |  |  | clone.m5 /= s.y; | 
		
	
		
			
			|  |  |  | clone.m9 /= s.y; | 
		
	
		
			
			|  |  |  | clone.m2 /= s.z; | 
		
	
		
			
			|  |  |  | clone.m6 /= s.z; | 
		
	
		
			
			|  |  |  | clone.m10 /= s.z; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Extract rotation | 
		
	
		
			
			|  |  |  | *rotation = QuaternionFromMatrix(clone); | 
		
	
		
			
			|  |  |  | matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | else | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Compute XY shear and make col2 orthogonal | 
		
	
		
			
			|  |  |  | shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]); | 
		
	
		
			
			|  |  |  | matColumns[1] = Vector3Subtract(matColumns[1], Vector3Scale(matColumns[0], shear[0])); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Y Scale | 
		
	
		
			
			|  |  |  | scl.y = Vector3Length(matColumns[1]); | 
		
	
		
			
			|  |  |  | if (scl.y > eps) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | // Set to identity if close to zero | 
		
	
		
			
			|  |  |  | *rotation = QuaternionIdentity(); | 
		
	
		
			
			|  |  |  | matColumns[1] = Vector3Scale(matColumns[1], 1.0f / scl.y); | 
		
	
		
			
			|  |  |  | n">shear[0] /= scl.y; // Correct XY shear | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Compute XZ and YZ shears and make col3 orthogonal | 
		
	
		
			
			|  |  |  | shear[1] = Vector3DotProduct(matColumns[0], matColumns[2]); | 
		
	
		
			
			|  |  |  | matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[0], shear[1])); | 
		
	
		
			
			|  |  |  | shear[2] = Vector3DotProduct(matColumns[1], matColumns[2]); | 
		
	
		
			
			|  |  |  | matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[1], shear[2])); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Z Scale | 
		
	
		
			
			|  |  |  | scl.z = Vector3Length(matColumns[2]); | 
		
	
		
			
			|  |  |  | if (scl.z > eps) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | matColumns[2] = Vector3Scale(matColumns[2], 1.0f / scl.z); | 
		
	
		
			
			|  |  |  | shear[1] /= scl.z; // Correct XZ shear | 
		
	
		
			
			|  |  |  | shear[2] /= scl.z; // Correct YZ shear | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1. | 
		
	
		
			
			|  |  |  | if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | scl = Vector3Negate(scl); | 
		
	
		
			
			|  |  |  | matColumns[0] = Vector3Negate(matColumns[0]); | 
		
	
		
			
			|  |  |  | matColumns[1] = Vector3Negate(matColumns[1]); | 
		
	
		
			
			|  |  |  | matColumns[2] = Vector3Negate(matColumns[2]); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Set Scale | 
		
	
		
			
			|  |  |  | *scale = Vector3Scale(scl, stabilizer); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Extract Rotation | 
		
	
		
			
			|  |  |  | Matrix rotationMatrix = { matColumns[0].x, matColumns[0].y, matColumns[0].z, 0, | 
		
	
		
			
			|  |  |  | matColumns[1].x, matColumns[1].y, matColumns[1].z, 0, | 
		
	
		
			
			|  |  |  | matColumns[2].x, matColumns[2].y, matColumns[2].z, 0, | 
		
	
		
			
			|  |  |  | 0, 0, 0, 1 }; | 
		
	
		
			
			|  |  |  | *rotation = QuaternionFromMatrix(rotationMatrix); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | #if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS) | 
		
	
	
		
			
				|  |  |  |