2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/public-api/math/matrix.h>
23 #include <cstdint> // uint32_t
24 #include <cstring> // memcpy
28 #include <dali/public-api/common/dali-common.h>
29 #include <dali/public-api/math/vector3.h>
30 #include <dali/public-api/math/vector4.h>
31 #include <dali/public-api/math/quaternion.h>
32 #include <dali/public-api/math/math-utils.h>
33 #include <dali/internal/render/common/performance-monitor.h>
37 const float ROTATION_EPSILON = 0.003f; // Deliberately large
39 const uint32_t NUM_BYTES_IN_ROW_OF_3( 3 * sizeof( float ) );
40 const uint32_t NUM_BYTES_IN_ROW( 4 * sizeof( float ) );
41 const uint32_t NUM_BYTES_IN_MATRIX( 16 * sizeof( float ) );
42 const uint32_t ROW1_OFFSET( 4 );
43 const uint32_t ROW2_OFFSET( 8 );
44 const uint32_t ROW3_OFFSET( 12 );
47 * Helper to convert to Quaternion to float16 array
49 void Convert( float*& m, const Dali::Quaternion& rotation )
51 const float xx = rotation.mVector.x * rotation.mVector.x;
52 const float yy = rotation.mVector.y * rotation.mVector.y;
53 const float zz = rotation.mVector.z * rotation.mVector.z;
54 const float xy = rotation.mVector.x * rotation.mVector.y;
55 const float xz = rotation.mVector.x * rotation.mVector.z;
56 const float wx = rotation.mVector.w * rotation.mVector.x;
57 const float wy = rotation.mVector.w * rotation.mVector.y;
58 const float wz = rotation.mVector.w * rotation.mVector.z;
59 const float yz = rotation.mVector.y * rotation.mVector.z;
61 m[0] = 1.0f - 2.0f * (yy + zz);
62 m[1] = 2.0f * (xy + wz);
63 m[2] = 2.0f * (xz - wy);
66 m[4] = 2.0f * (xy - wz);
67 m[5] = 1.0f - 2.0f * (xx + zz);
68 m[6] = 2.0f * (yz + wx);
71 m[8] = 2.0f * (xz + wy);
72 m[9] = 2.0f * (yz - wx);
73 m[10]= 1.0f - 2.0f * (xx + yy);
86 using Internal::PerformanceMonitor;
88 const float identityArray[] = {1.0f, 0.0f, 0.0f, 0.0f,
89 0.0f, 1.0f, 0.0f, 0.0f,
90 0.0f, 0.0f, 1.0f, 0.0f,
91 0.0f, 0.0f, 0.0f, 1.0f};
93 const Matrix Matrix::IDENTITY(identityArray);
97 memset( mMatrix, 0, NUM_BYTES_IN_MATRIX );
100 Matrix::Matrix( bool initialize )
104 memset( mMatrix, 0, NUM_BYTES_IN_MATRIX );
108 Matrix::Matrix(const float* array)
110 memcpy( mMatrix, array, NUM_BYTES_IN_MATRIX );
113 Matrix::Matrix( const Quaternion& rotation )
115 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,18);
117 float* matrixPtr = &mMatrix[0];
118 Convert( matrixPtr, rotation );
121 Matrix::Matrix( const Matrix& matrix )
123 memcpy( mMatrix, matrix.mMatrix, NUM_BYTES_IN_MATRIX );
126 Matrix& Matrix::operator=( const Matrix& matrix )
128 // no point copying if self assigning
129 if( this != &matrix )
131 memcpy( mMatrix, matrix.mMatrix, NUM_BYTES_IN_MATRIX );
136 Matrix::Matrix( Matrix&& matrix )
138 memcpy( mMatrix, matrix.mMatrix, NUM_BYTES_IN_MATRIX );
141 Matrix& Matrix::operator=( Matrix&& matrix )
143 if( this != &matrix )
145 memcpy( mMatrix, matrix.mMatrix, NUM_BYTES_IN_MATRIX );
150 void Matrix::InvertTransform(Matrix& result) const
152 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,12);
154 float* m1 = result.AsFloat();
156 DALI_ASSERT_ALWAYS( EqualsZero( mMatrix[3] ) && EqualsZero( mMatrix[7] ) && EqualsZero( mMatrix[11] ) && Equals( mMatrix[15], 1.0f ) && "Must be a transform matrix" );
170 m1[10] = mMatrix[10];
173 m1[12] = -( ( mMatrix[0] * mMatrix[12] ) + ( mMatrix[1] * mMatrix[13] ) + ( mMatrix[2] * mMatrix[14] ) + ( mMatrix[3] * mMatrix[15] ) );
174 m1[13] = -( ( mMatrix[4] * mMatrix[12] ) + ( mMatrix[5] * mMatrix[13] ) + ( mMatrix[6] * mMatrix[14] ) + ( mMatrix[7] * mMatrix[15] ) );
175 m1[14] = -( ( mMatrix[8] * mMatrix[12] ) + ( mMatrix[9] * mMatrix[13] ) + ( mMatrix[10] * mMatrix[14] ) + ( mMatrix[11] * mMatrix[15] ) );
179 static bool InvertMatrix(const float* m, float* out)
183 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,192); // 12 x 16 multiples
185 inv[0] = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15] + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
186 inv[4] = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15] - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
187 inv[8] = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15] + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
188 inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14] - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
189 inv[1] = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15] - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
190 inv[5] = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15] + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
191 inv[9] = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15] - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
192 inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14] + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
193 inv[2] = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15] + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
194 inv[6] = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15] - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
195 inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15] + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
196 inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14] - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
197 inv[3] = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11] - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
198 inv[7] = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11] + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
199 inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11] - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
200 inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10] + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
202 float det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
204 // In the case where the determinant is exactly zero, the matrix is non-invertible
205 if ( EqualsZero( det ) )
212 for( int32_t i = 0; i < 16; i++)
214 out[i] = inv[i] * det;
220 bool Matrix::Invert()
224 return InvertMatrix(temp.AsFloat(), mMatrix);
227 void Matrix::Transpose()
229 float temp = mMatrix[1];
230 mMatrix[1] = mMatrix[4];
234 mMatrix[2] = mMatrix[8];
238 mMatrix[3] = mMatrix[12];
242 mMatrix[6] = mMatrix[9];
246 mMatrix[7] = mMatrix[13];
250 mMatrix[11] = mMatrix[14];
254 void Matrix::SetIdentity()
256 memcpy( mMatrix, identityArray, NUM_BYTES_IN_MATRIX );
259 void Matrix::SetIdentityAndScale( const Vector3& scale )
261 // initialize to zeros
262 memset( mMatrix, 0, NUM_BYTES_IN_MATRIX );
264 // just apply scale on the diagonal
265 mMatrix[0] = scale.x;
266 mMatrix[5] = scale.y;
267 mMatrix[10] = scale.z;
271 void Matrix::SetTranslation(const Vector4& translation)
273 memcpy( mMatrix + ROW3_OFFSET, &translation, NUM_BYTES_IN_ROW );
275 void Matrix::SetTranslation(const Vector3& other)
277 memcpy( mMatrix + ROW3_OFFSET, &other, NUM_BYTES_IN_ROW_OF_3 );
281 void Matrix::Multiply( Matrix& result, const Matrix& lhs, const Matrix& rhs )
283 MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
284 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,64); // 64 = 16*4
286 float* temp = result.AsFloat();
287 const float* rhsPtr = rhs.AsFloat();
288 const float* lhsPtr = lhs.AsFloat();
292 for( int32_t i=0; i < 4; i++ )
294 // i<<2 gives the first vector / column
296 int32_t loc1 = loc + 1;
297 int32_t loc2 = loc + 2;
298 int32_t loc3 = loc + 3;
299 float value0 = lhsPtr[loc];
300 float value1 = lhsPtr[loc1];
301 float value2 = lhsPtr[loc2];
302 float value3 = lhsPtr[loc3];
303 temp[loc] = (value0 * rhsPtr[0]) +
304 (value1 * rhsPtr[4]) +
305 (value2 * rhsPtr[8]) +
306 (value3 * rhsPtr[12]);
308 temp[loc1] = (value0 * rhsPtr[1]) +
309 (value1 * rhsPtr[5]) +
310 (value2 * rhsPtr[9]) +
311 (value3 * rhsPtr[13]);
313 temp[loc2] = (value0 * rhsPtr[2]) +
314 (value1 * rhsPtr[6]) +
315 (value2 * rhsPtr[10])+
316 (value3 * rhsPtr[14]);
318 temp[loc3] = (value0 * rhsPtr[3]) +
319 (value1 * rhsPtr[7]) +
320 (value2 * rhsPtr[11])+
321 (value3 * rhsPtr[15]);
326 // 64 32bit registers,
328 // d = 64 bit double-word d0 -d31
329 // q =128 bit quad-word q0 -q15 (enough to handle a column of 4 floats in a matrix)
330 // e.g. q0 = d0 and d1
332 // load and stores interleaved as NEON can load and store while calculating
333 asm volatile ( "VLDM %1, {q0-q3} \n\t" // load matrix 1 (lhsPtr) q[0..q3]
334 "VLDM %0, {q8-q11} \n\t" // load matrix 2 (rhsPtr) q[q8-q11]
335 "VMUL.F32 q12, q8, d0[0] \n\t" // column 0 = rhsPtr[0..3] * lhsPtr[0..3]
336 "VMUL.F32 q13, q8, d2[0] \n\t" // column 1 = rhsPtr[0..3] * lhsPtr[4..7]
337 "VMUL.F32 q14, q8, d4[0] \n\t" // column 2 = rhsPtr[0..3] * lhsPtr[8..11]
338 "VMUL.F32 q15, q8, d6[0] \n\t" // column 3 = rhsPtr[0..3] * lhsPtr[12..15]
340 "VMLA.F32 q12, q9, d0[1] \n\t" // column 0 += rhsPtr[4..7] * lhsPtr[0..3]
341 "VMLA.F32 q13, q9, d2[1] \n\t" // column 1 += rhsPtr[4..7] * lhsPtr[4..7]
342 "VMLA.F32 q14, q9, d4[1] \n\t" // column 2 += rhsPtr[4..7] * lhsPtr[8..11]
343 "VMLA.F32 q15, q9, d6[1] \n\t" // column 3 += rhsPtr[4..7] * lhsPtr[12..15]
345 "VMLA.F32 q12, q10, d1[0] \n\t" // column 0 += rhsPtr[8..11] * lhsPtr[0..3]
346 "VMLA.F32 q13, q10, d3[0] \n\t" // column 1 += rhsPtr[8..11] * lhsPtr[4..7]
347 "VMLA.F32 q14, q10, d5[0] \n\t" // column 2 += rhsPtr[8..11] * lhsPtr[8..11]
348 "VMLA.F32 q15, q10, d7[0] \n\t" // column 3 += rhsPtr[8..11] * lhsPtr[12..15]
350 "VMLA.F32 q12, q11, d1[1] \n\t" // column 0 += rhsPtr[12..15] * lhsPtr[0..3]
351 "VMLA.F32 q13, q11, d3[1] \n\t" // column 1 += rhsPtr[12..15] * lhsPtr[4..7]
352 "VMLA.F32 q14, q11, d5[1] \n\t" // column 2 += rhsPtr[12..15] * lhsPtr[8..11]
353 "VMLA.F32 q15, q11, d7[1] \n\t" // column 3 += rhsPtr[12..15] * lhsPtr[12..15]
354 "VSTM %2, {q12-q15} \n\t" // store entire output matrix.
355 : "+r"(rhsPtr), "+r"(lhsPtr), "+r"(temp)
357 : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", "memory" );
362 void Matrix::Multiply( Matrix& result, const Matrix& lhs, const Quaternion& rhs )
364 MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
365 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,54); // 54 = 36+18
368 float* rhsPtr = &matrix[0];
369 Convert( rhsPtr, rhs );
371 // quaternion contains just rotation so it really only needs 3x3 matrix
373 float* temp = result.AsFloat();
374 const float* lhsPtr = lhs.AsFloat();
378 for( int32_t i=0; i < 4; i++ )
380 // i<<2 gives the first vector / column
382 int32_t loc1 = loc + 1;
383 int32_t loc2 = loc + 2;
384 int32_t loc3 = loc + 3;
385 float value0 = lhsPtr[loc];
386 float value1 = lhsPtr[loc1];
387 float value2 = lhsPtr[loc2];
388 float value3 = lhsPtr[loc3];
389 temp[loc] = (value0 * rhsPtr[0]) +
390 (value1 * rhsPtr[4]) +
391 (value2 * rhsPtr[8]) +
392 (0.0f); //value3 * rhsPtr[12] is 0.0f
394 temp[loc1] = (value0 * rhsPtr[1]) +
395 (value1 * rhsPtr[5]) +
396 (value2 * rhsPtr[9]) +
397 (0.0f); //value3 * rhsPtr[13] is 0.0f
399 temp[loc2] = (value0 * rhsPtr[2]) +
400 (value1 * rhsPtr[6]) +
401 (value2 * rhsPtr[10])+
402 (0.0f); //value3 * rhsPtr[14] is 0.0f
404 temp[loc3] = (0.0f) + //value0 * rhsPtr[3] is 0.0f
405 (0.0f) + //value1 * rhsPtr[7] is 0.0f
406 (0.0f) + //value2 * rhsPtr[11] is 0.0f
407 (value3); // rhsPtr[15] is 1.0f
412 // 64 32bit registers,
414 // d = 64 bit double-word d0 -d31
415 // q =128 bit quad-word q0 -q15 (enough to handle a column of 4 floats in a matrix)
416 // e.g. q0 = d0 and d1
417 // load and stores interleaved as NEON can load and store while calculating
418 asm volatile ( "VLDM %1, {q4-q6} \n\t" // load matrix 1 (lhsPtr)
419 "VLD1.F32 {q7}, [%2]! \n\t" // load matrix 2 (rhsPtr) [0..3]
420 "VMUL.F32 q0, q7, d8[0] \n\t" // column 0 = rhsPtr[0..3] * lhsPtr[0..3]
421 "VMUL.F32 q1, q7, d10[0] \n\t" // column 1 = rhsPtr[0..3] * lhsPtr[4..7]
422 "VMUL.F32 q2, q7, d12[0] \n\t" // column 2 = rhsPtr[0..3] * lhsPtr[8..11]
423 "VLD1.F32 {q7}, [%2]! \n\t" // load matrix 2 (rhsPtr) [4..7]
424 "VMLA.F32 q0, q7, d8[1] \n\t" // column 0+= rhsPtr[4..7] * lhsPtr[0..3]
425 "VMLA.F32 q1, q7, d10[1] \n\t" // column 1+= rhsPtr[4..7] * lhsPtr[4..7]
426 "VMLA.F32 q2, q7, d12[1] \n\t" // column 2+= rhsPtr[4..7] * lhsPtr[8..11]
427 "VLD1.F32 {q7}, [%2]! \n\t" // load matrix 2 (rhsPtr) [8..11]
428 "VMLA.F32 q0, q7, d9[0] \n\t" // column 0+= rhsPtr[8..11] * lhsPtr[0..3]
429 "VMLA.F32 q1, q7, d11[0] \n\t" // column 1+= rhsPtr[8..11] * lhsPtr[4..7]
430 "VMLA.F32 q2, q7, d13[0] \n\t" // column 2+= rhsPtr[8..11] * lhsPtr[8..11]
431 "VSTM %0, {q0-q2} \n\t" // store entire output matrix.
433 : "r"(temp), "r"(lhsPtr), "r" (rhsPtr)
434 : "%r0", "%q0", "%q1", "%q2", "%q4", "%q5", "%q6", "%q7", "memory" );
443 Vector4 Matrix::operator*(const Vector4& rhs) const
445 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,16);
451 temp.x = rhs.x * mMatrix[0] + rhs.y * mMatrix[4] + rhs.z * mMatrix[8] + rhs.w * mMatrix[12];
452 temp.y = rhs.x * mMatrix[1] + rhs.y * mMatrix[5] + rhs.z * mMatrix[9] + rhs.w * mMatrix[13];
453 temp.z = rhs.x * mMatrix[2] + rhs.y * mMatrix[6] + rhs.z * mMatrix[10] + rhs.w * mMatrix[14];
454 temp.w = rhs.x * mMatrix[3] + rhs.y * mMatrix[7] + rhs.z * mMatrix[11] + rhs.w * mMatrix[15];
458 // 64 32bit registers,
460 // d = 64 bit double-word d0 -d31
461 // q =128 bit quad-word q0 -q15 (enough to handle a column of 4 floats in a matrix)
462 // e.g. q0 = d0 and d1
463 // load and stores interleaved as NEON can load and store while calculating
464 asm volatile ( "VLD1.F32 {q0}, [%1] \n\t" //q0 = rhs
465 "VLD1.F32 {q9}, [%0]! \n\t"
466 "VMUL.F32 q10, q9, d0[0] \n\t"
467 "VLD1.F32 {q9}, [%0]! \n\t"
468 "VMLA.F32 q10, q9, d0[1] \n\t" //q10 = mMatrix[0..3] * rhs + mMatrix[4..7] * rhs
469 "VLD1.F32 {q9}, [%0]! \n\t"
470 "VMUL.F32 q11, q9, d1[0] \n\t"
471 "VLD1.F32 {q9}, [%0]! \n\t"
472 "VMLA.F32 q11, q9, d1[1] \n\t" //q11 = mMatrix[8..11] * rhs + mMatrix[12..15] * rhs
473 "VADD.F32 q10, q10, q11 \n\t"
474 "VST1.F32 {q10},[%2] \n\t" //temp = q10 + q11
476 : "r"(mMatrix), "r"(&rhs), "r"(&temp)
477 : "q0", "q9", "q10", "q11", "memory" );
482 bool Matrix::operator==(const Matrix& rhs) const
485 ( fabsf( mMatrix[0] - rhs.mMatrix[0] ) <= GetRangedEpsilon( mMatrix[0], rhs.mMatrix[0] ) ) &&
486 ( fabsf( mMatrix[1] - rhs.mMatrix[1] ) <= GetRangedEpsilon( mMatrix[1], rhs.mMatrix[1] ) ) &&
487 ( fabsf( mMatrix[2] - rhs.mMatrix[2] ) <= GetRangedEpsilon( mMatrix[2], rhs.mMatrix[2] ) ) &&
488 ( fabsf( mMatrix[3] - rhs.mMatrix[3] ) <= GetRangedEpsilon( mMatrix[3], rhs.mMatrix[3] ) ) &&
489 ( fabsf( mMatrix[4] - rhs.mMatrix[4] ) <= GetRangedEpsilon( mMatrix[4], rhs.mMatrix[4] ) ) &&
490 ( fabsf( mMatrix[5] - rhs.mMatrix[5] ) <= GetRangedEpsilon( mMatrix[5], rhs.mMatrix[5] ) ) &&
491 ( fabsf( mMatrix[6] - rhs.mMatrix[6] ) <= GetRangedEpsilon( mMatrix[6], rhs.mMatrix[6] ) ) &&
492 ( fabsf( mMatrix[7] - rhs.mMatrix[7] ) <= GetRangedEpsilon( mMatrix[7], rhs.mMatrix[7] ) ) &&
493 ( fabsf( mMatrix[8] - rhs.mMatrix[8] ) <= GetRangedEpsilon( mMatrix[8], rhs.mMatrix[8] ) ) &&
494 ( fabsf( mMatrix[9] - rhs.mMatrix[9] ) <= GetRangedEpsilon( mMatrix[9], rhs.mMatrix[9] ) ) &&
495 ( fabsf( mMatrix[10] - rhs.mMatrix[10] ) <= GetRangedEpsilon( mMatrix[10], rhs.mMatrix[10] ) ) &&
496 ( fabsf( mMatrix[11] - rhs.mMatrix[11] ) <= GetRangedEpsilon( mMatrix[11], rhs.mMatrix[11] ) ) &&
497 ( fabsf( mMatrix[12] - rhs.mMatrix[12] ) <= GetRangedEpsilon( mMatrix[12], rhs.mMatrix[12] ) ) &&
498 ( fabsf( mMatrix[13] - rhs.mMatrix[13] ) <= GetRangedEpsilon( mMatrix[13], rhs.mMatrix[13] ) ) &&
499 ( fabsf( mMatrix[14] - rhs.mMatrix[14] ) <= GetRangedEpsilon( mMatrix[14], rhs.mMatrix[14] ) ) &&
500 ( fabsf( mMatrix[15] - rhs.mMatrix[15] ) <= GetRangedEpsilon( mMatrix[15], rhs.mMatrix[15] ) ) );
503 bool Matrix::operator!=(const Matrix& rhs) const
513 void Matrix::OrthoNormalize()
515 Vector4 vector0(GetXAxis());
516 Vector4 vector1(GetYAxis());
517 Vector4 vector2(GetZAxis());
521 vector2 = vector0.Cross( vector1 );
522 vector1 = vector2.Cross( vector0 );
524 memcpy( mMatrix, &vector0, NUM_BYTES_IN_ROW );
525 memcpy( mMatrix + ROW1_OFFSET, &vector1, NUM_BYTES_IN_ROW );
526 memcpy( mMatrix + ROW2_OFFSET, &vector2, NUM_BYTES_IN_ROW );
529 Vector3 Matrix::GetXAxis() const
531 return Vector3(mMatrix[0], mMatrix[1], mMatrix[2]);
534 Vector3 Matrix::GetYAxis() const
536 return Vector3(mMatrix[4], mMatrix[5], mMatrix[6]);
539 Vector3 Matrix::GetZAxis() const
541 return Vector3(mMatrix[8], mMatrix[9], mMatrix[10]);
544 void Matrix::SetXAxis(const Vector3& axis)
551 void Matrix::SetYAxis(const Vector3& axis)
558 void Matrix::SetZAxis(const Vector3& axis)
562 mMatrix[10] = axis.z;
565 void Matrix::SetTransformComponents(const Vector3& scale,
566 const Quaternion& rotation,
567 const Vector3& translation )
569 if( rotation.IsIdentity() )
571 mMatrix[0] = scale.x;
577 mMatrix[5] = scale.y;
583 mMatrix[10]= scale.z;
588 MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
589 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,27); // 27 = 9+18
591 const float xx = rotation.mVector.x * rotation.mVector.x;
592 const float yy = rotation.mVector.y * rotation.mVector.y;
593 const float zz = rotation.mVector.z * rotation.mVector.z;
594 const float xy = rotation.mVector.x * rotation.mVector.y;
595 const float xz = rotation.mVector.x * rotation.mVector.z;
596 const float wx = rotation.mVector.w * rotation.mVector.x;
597 const float wy = rotation.mVector.w * rotation.mVector.y;
598 const float wz = rotation.mVector.w * rotation.mVector.z;
599 const float yz = rotation.mVector.y * rotation.mVector.z;
601 mMatrix[0] = (scale.x * (1.0f - 2.0f * (yy + zz)));
602 mMatrix[1] = (scale.x * ( 2.0f * (xy + wz)));
603 mMatrix[2] = (scale.x * ( 2.0f * (xz - wy)));
606 mMatrix[4] = (scale.y * ( 2.0f * (xy - wz)));
607 mMatrix[5] = (scale.y * (1.0f - 2.0f * (xx + zz)));
608 mMatrix[6] = (scale.y * ( 2.0f * (yz + wx)));
611 mMatrix[8] = (scale.z * ( 2.0f * (xz + wy)));
612 mMatrix[9] = (scale.z * ( 2.0f * (yz - wx)));
613 mMatrix[10]= (scale.z * (1.0f - 2.0f * (xx + yy)));
617 mMatrix[12] = translation.x;
618 mMatrix[13] = translation.y;
619 mMatrix[14] = translation.z;
623 void Matrix::SetInverseTransformComponents(const Vector3& scale,
624 const Quaternion& rotation,
625 const Vector3& translation )
627 Vector3 inverseTranslation = -translation;
628 Vector3 inverseScale( 1.0f/scale.x, 1.0f/scale.y, 1.0f/scale.z);
629 Quaternion inverseRotation(rotation);
630 bool isRotated = ! inverseRotation.IsIdentity();
632 // Order of application is translation, rotation, scale.
633 // Ensure translation is relative to scale & rotation:
637 inverseRotation.Invert();
638 inverseTranslation = inverseRotation.Rotate(inverseTranslation);
641 inverseTranslation *= inverseScale;
645 MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
646 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,27); // 27 = 9+18
648 const float xx = inverseRotation.mVector.x * inverseRotation.mVector.x;
649 const float yy = inverseRotation.mVector.y * inverseRotation.mVector.y;
650 const float zz = inverseRotation.mVector.z * inverseRotation.mVector.z;
651 const float xy = inverseRotation.mVector.x * inverseRotation.mVector.y;
652 const float xz = inverseRotation.mVector.x * inverseRotation.mVector.z;
653 const float wx = inverseRotation.mVector.w * inverseRotation.mVector.x;
654 const float wy = inverseRotation.mVector.w * inverseRotation.mVector.y;
655 const float wz = inverseRotation.mVector.w * inverseRotation.mVector.z;
656 const float yz = inverseRotation.mVector.y * inverseRotation.mVector.z;
658 mMatrix[0] = (inverseScale.x * (1.0f - 2.0f * (yy + zz)));
659 mMatrix[1] = (inverseScale.y * (2.0f * (xy + wz)));
660 mMatrix[2] = (inverseScale.z * (2.0f * (xz - wy)));
663 mMatrix[4] = (inverseScale.x * (2.0f * (xy - wz)));
664 mMatrix[5] = (inverseScale.y * (1.0f - 2.0f * (xx + zz)));
665 mMatrix[6] = (inverseScale.z * (2.0f * (yz + wx)));
668 mMatrix[8] = (inverseScale.x * (2.0f * (xz + wy)));
669 mMatrix[9] = (inverseScale.y * (2.0f * (yz - wx)));
670 mMatrix[10]= (inverseScale.z * (1.0f - 2.0f * (xx + yy)));
675 mMatrix[0] = inverseScale.x;
681 mMatrix[5] = inverseScale.y;
687 mMatrix[10]= inverseScale.z;
692 mMatrix[12] = inverseTranslation.x;
693 mMatrix[13] = inverseTranslation.y;
694 mMatrix[14] = inverseTranslation.z;
698 void Matrix::SetInverseTransformComponents(const Vector3& xAxis,
699 const Vector3& yAxis,
700 const Vector3& zAxis,
701 const Vector3& translation )
703 // x, y, z axis parameters represent a orthonormal basis with no scaling, i.e. a rotation matrix.
704 // Invert rotation by transposing in place
706 // Order of application is translation, rotation
708 mMatrix[0] = xAxis.x;
709 mMatrix[1] = yAxis.x;
710 mMatrix[2] = zAxis.x;
713 mMatrix[4] = xAxis.y;
714 mMatrix[5] = yAxis.y;
715 mMatrix[6] = zAxis.y;
718 mMatrix[8] = xAxis.z;
719 mMatrix[9] = yAxis.z;
720 mMatrix[10] = zAxis.z;
727 // Ensure translation is relative to scale & rotation:
729 Vector4 inverseTranslation( -translation.x, -translation.y, -translation.z, 1.0f);
730 inverseTranslation = *this * inverseTranslation; // Rotate inverse translation
731 inverseTranslation.w = 1.0f;
732 SetTranslation(inverseTranslation);
736 void Matrix::GetTransformComponents(Vector3& position,
737 Quaternion& rotation,
738 Vector3& scale) const
740 position = GetTranslation3();
742 // Derive scale from axis lengths.
743 Vector3 theScale(GetXAxis().Length(), GetYAxis().Length(), GetZAxis().Length());
746 if( ! ( fabs(theScale.x - Vector3::ONE.x) < ROTATION_EPSILON &&
747 fabs(theScale.y - Vector3::ONE.y) < ROTATION_EPSILON &&
748 fabs(theScale.z - Vector3::ONE.z) < ROTATION_EPSILON ) )
750 MATH_INCREASE_COUNTER(PerformanceMonitor::MATRIX_MULTIPLYS);
751 MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,9);
753 // Non-identity scale is embedded into rotation matrix. Remove it first:
755 Vector3 inverseScale(1.0f/theScale.x, 1.0f/theScale.y, 1.0f/theScale.z);
756 m.mMatrix[0] *= inverseScale.x;
757 m.mMatrix[1] *= inverseScale.x;
758 m.mMatrix[2] *= inverseScale.x;
759 m.mMatrix[4] *= inverseScale.y;
760 m.mMatrix[5] *= inverseScale.y;
761 m.mMatrix[6] *= inverseScale.y;
762 m.mMatrix[8] *= inverseScale.z;
763 m.mMatrix[9] *= inverseScale.z;
764 m.mMatrix[10] *= inverseScale.z;
766 Quaternion theRotation(m);
768 // If the imaginary components are close to zero, then use null quaternion instead.
769 if( fabs(theRotation.mVector.x) < ROTATION_EPSILON &&
770 fabs(theRotation.mVector.y) < ROTATION_EPSILON &&
771 fabs(theRotation.mVector.z) < ROTATION_EPSILON )
773 theRotation = Quaternion();
775 rotation = theRotation;
779 Quaternion theRotation(*this);
781 // If the imaginary components are close to zero, then use null quaternion instead.
782 if( fabs(theRotation.mVector.x) < ROTATION_EPSILON &&
783 fabs(theRotation.mVector.y) < ROTATION_EPSILON &&
784 fabs(theRotation.mVector.z) < ROTATION_EPSILON )
786 theRotation = Quaternion();
788 rotation = theRotation;
794 std::ostream& operator<< (std::ostream& o, const Matrix& matrix)
796 return o << "[ " << matrix.mMatrix[0] << ", " << matrix.mMatrix[1] << ", " << matrix.mMatrix[2] << ", " << matrix.mMatrix[3] << ", "
797 << matrix.mMatrix[4] << ", " << matrix.mMatrix[5] << ", " << matrix.mMatrix[6] << ", " << matrix.mMatrix[7] << ", "
798 << matrix.mMatrix[8] << ", " << matrix.mMatrix[9] << ", " << matrix.mMatrix[10] << ", " << matrix.mMatrix[11] << ", "
799 << matrix.mMatrix[12] << ", " << matrix.mMatrix[13] << ", " << matrix.mMatrix[14] << ", " << matrix.mMatrix[15] << " ]";