diff options
Diffstat (limited to 'libraries/irrlicht-1.8.1/include/matrix4.h')
-rw-r--r-- | libraries/irrlicht-1.8.1/include/matrix4.h | 2242 |
1 files changed, 0 insertions, 2242 deletions
diff --git a/libraries/irrlicht-1.8.1/include/matrix4.h b/libraries/irrlicht-1.8.1/include/matrix4.h deleted file mode 100644 index df1e4ea..0000000 --- a/libraries/irrlicht-1.8.1/include/matrix4.h +++ /dev/null | |||
@@ -1,2242 +0,0 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #ifndef __IRR_MATRIX_H_INCLUDED__ | ||
6 | #define __IRR_MATRIX_H_INCLUDED__ | ||
7 | |||
8 | #include "irrMath.h" | ||
9 | #include "vector3d.h" | ||
10 | #include "vector2d.h" | ||
11 | #include "plane3d.h" | ||
12 | #include "aabbox3d.h" | ||
13 | #include "rect.h" | ||
14 | #include "irrString.h" | ||
15 | |||
16 | // enable this to keep track of changes to the matrix | ||
17 | // and make simpler identity check for seldomly changing matrices | ||
18 | // otherwise identity check will always compare the elements | ||
19 | //#define USE_MATRIX_TEST | ||
20 | |||
21 | // this is only for debugging purposes | ||
22 | //#define USE_MATRIX_TEST_DEBUG | ||
23 | |||
24 | #if defined( USE_MATRIX_TEST_DEBUG ) | ||
25 | |||
26 | struct MatrixTest | ||
27 | { | ||
28 | MatrixTest () : ID(0), Calls(0) {} | ||
29 | char buf[256]; | ||
30 | int Calls; | ||
31 | int ID; | ||
32 | }; | ||
33 | static MatrixTest MTest; | ||
34 | |||
35 | #endif | ||
36 | |||
37 | namespace irr | ||
38 | { | ||
39 | namespace core | ||
40 | { | ||
41 | |||
42 | //! 4x4 matrix. Mostly used as transformation matrix for 3d calculations. | ||
43 | /** The matrix is a D3D style matrix, row major with translations in the 4th row. */ | ||
44 | template <class T> | ||
45 | class CMatrix4 | ||
46 | { | ||
47 | public: | ||
48 | |||
49 | //! Constructor Flags | ||
50 | enum eConstructor | ||
51 | { | ||
52 | EM4CONST_NOTHING = 0, | ||
53 | EM4CONST_COPY, | ||
54 | EM4CONST_IDENTITY, | ||
55 | EM4CONST_TRANSPOSED, | ||
56 | EM4CONST_INVERSE, | ||
57 | EM4CONST_INVERSE_TRANSPOSED | ||
58 | }; | ||
59 | |||
60 | //! Default constructor | ||
61 | /** \param constructor Choose the initialization style */ | ||
62 | CMatrix4( eConstructor constructor = EM4CONST_IDENTITY ); | ||
63 | //! Copy constructor | ||
64 | /** \param other Other matrix to copy from | ||
65 | \param constructor Choose the initialization style */ | ||
66 | CMatrix4(const CMatrix4<T>& other, eConstructor constructor = EM4CONST_COPY); | ||
67 | |||
68 | //! Simple operator for directly accessing every element of the matrix. | ||
69 | T& operator()(const s32 row, const s32 col) | ||
70 | { | ||
71 | #if defined ( USE_MATRIX_TEST ) | ||
72 | definitelyIdentityMatrix=false; | ||
73 | #endif | ||
74 | return M[ row * 4 + col ]; | ||
75 | } | ||
76 | |||
77 | //! Simple operator for directly accessing every element of the matrix. | ||
78 | const T& operator()(const s32 row, const s32 col) const { return M[row * 4 + col]; } | ||
79 | |||
80 | //! Simple operator for linearly accessing every element of the matrix. | ||
81 | T& operator[](u32 index) | ||
82 | { | ||
83 | #if defined ( USE_MATRIX_TEST ) | ||
84 | definitelyIdentityMatrix=false; | ||
85 | #endif | ||
86 | return M[index]; | ||
87 | } | ||
88 | |||
89 | //! Simple operator for linearly accessing every element of the matrix. | ||
90 | const T& operator[](u32 index) const { return M[index]; } | ||
91 | |||
92 | //! Sets this matrix equal to the other matrix. | ||
93 | inline CMatrix4<T>& operator=(const CMatrix4<T> &other); | ||
94 | |||
95 | //! Sets all elements of this matrix to the value. | ||
96 | inline CMatrix4<T>& operator=(const T& scalar); | ||
97 | |||
98 | //! Returns pointer to internal array | ||
99 | const T* pointer() const { return M; } | ||
100 | T* pointer() | ||
101 | { | ||
102 | #if defined ( USE_MATRIX_TEST ) | ||
103 | definitelyIdentityMatrix=false; | ||
104 | #endif | ||
105 | return M; | ||
106 | } | ||
107 | |||
108 | //! Returns true if other matrix is equal to this matrix. | ||
109 | bool operator==(const CMatrix4<T> &other) const; | ||
110 | |||
111 | //! Returns true if other matrix is not equal to this matrix. | ||
112 | bool operator!=(const CMatrix4<T> &other) const; | ||
113 | |||
114 | //! Add another matrix. | ||
115 | CMatrix4<T> operator+(const CMatrix4<T>& other) const; | ||
116 | |||
117 | //! Add another matrix. | ||
118 | CMatrix4<T>& operator+=(const CMatrix4<T>& other); | ||
119 | |||
120 | //! Subtract another matrix. | ||
121 | CMatrix4<T> operator-(const CMatrix4<T>& other) const; | ||
122 | |||
123 | //! Subtract another matrix. | ||
124 | CMatrix4<T>& operator-=(const CMatrix4<T>& other); | ||
125 | |||
126 | //! set this matrix to the product of two matrices | ||
127 | /** Calculate b*a */ | ||
128 | inline CMatrix4<T>& setbyproduct(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b ); | ||
129 | |||
130 | //! Set this matrix to the product of two matrices | ||
131 | /** Calculate b*a, no optimization used, | ||
132 | use it if you know you never have a identity matrix */ | ||
133 | CMatrix4<T>& setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b ); | ||
134 | |||
135 | //! Multiply by another matrix. | ||
136 | /** Calculate other*this */ | ||
137 | CMatrix4<T> operator*(const CMatrix4<T>& other) const; | ||
138 | |||
139 | //! Multiply by another matrix. | ||
140 | /** Calculate and return other*this */ | ||
141 | CMatrix4<T>& operator*=(const CMatrix4<T>& other); | ||
142 | |||
143 | //! Multiply by scalar. | ||
144 | CMatrix4<T> operator*(const T& scalar) const; | ||
145 | |||
146 | //! Multiply by scalar. | ||
147 | CMatrix4<T>& operator*=(const T& scalar); | ||
148 | |||
149 | //! Set matrix to identity. | ||
150 | inline CMatrix4<T>& makeIdentity(); | ||
151 | |||
152 | //! Returns true if the matrix is the identity matrix | ||
153 | inline bool isIdentity() const; | ||
154 | |||
155 | //! Returns true if the matrix is orthogonal | ||
156 | inline bool isOrthogonal() const; | ||
157 | |||
158 | //! Returns true if the matrix is the identity matrix | ||
159 | bool isIdentity_integer_base () const; | ||
160 | |||
161 | //! Set the translation of the current matrix. Will erase any previous values. | ||
162 | CMatrix4<T>& setTranslation( const vector3d<T>& translation ); | ||
163 | |||
164 | //! Gets the current translation | ||
165 | vector3d<T> getTranslation() const; | ||
166 | |||
167 | //! Set the inverse translation of the current matrix. Will erase any previous values. | ||
168 | CMatrix4<T>& setInverseTranslation( const vector3d<T>& translation ); | ||
169 | |||
170 | //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. | ||
171 | inline CMatrix4<T>& setRotationRadians( const vector3d<T>& rotation ); | ||
172 | |||
173 | //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. | ||
174 | CMatrix4<T>& setRotationDegrees( const vector3d<T>& rotation ); | ||
175 | |||
176 | //! Returns the rotation, as set by setRotation(). | ||
177 | /** This code was orginally written by by Chev. */ | ||
178 | core::vector3d<T> getRotationDegrees() const; | ||
179 | |||
180 | //! Make an inverted rotation matrix from Euler angles. | ||
181 | /** The 4th row and column are unmodified. */ | ||
182 | inline CMatrix4<T>& setInverseRotationRadians( const vector3d<T>& rotation ); | ||
183 | |||
184 | //! Make an inverted rotation matrix from Euler angles. | ||
185 | /** The 4th row and column are unmodified. */ | ||
186 | inline CMatrix4<T>& setInverseRotationDegrees( const vector3d<T>& rotation ); | ||
187 | |||
188 | //! Make a rotation matrix from angle and axis, assuming left handed rotation. | ||
189 | /** The 4th row and column are unmodified. */ | ||
190 | inline CMatrix4<T>& setRotationAxisRadians(const T& angle, const vector3d<T>& axis); | ||
191 | |||
192 | //! Set Scale | ||
193 | CMatrix4<T>& setScale( const vector3d<T>& scale ); | ||
194 | |||
195 | //! Set Scale | ||
196 | CMatrix4<T>& setScale( const T scale ) { return setScale(core::vector3d<T>(scale,scale,scale)); } | ||
197 | |||
198 | //! Get Scale | ||
199 | core::vector3d<T> getScale() const; | ||
200 | |||
201 | //! Translate a vector by the inverse of the translation part of this matrix. | ||
202 | void inverseTranslateVect( vector3df& vect ) const; | ||
203 | |||
204 | //! Rotate a vector by the inverse of the rotation part of this matrix. | ||
205 | void inverseRotateVect( vector3df& vect ) const; | ||
206 | |||
207 | //! Rotate a vector by the rotation part of this matrix. | ||
208 | void rotateVect( vector3df& vect ) const; | ||
209 | |||
210 | //! An alternate transform vector method, writing into a second vector | ||
211 | void rotateVect(core::vector3df& out, const core::vector3df& in) const; | ||
212 | |||
213 | //! An alternate transform vector method, writing into an array of 3 floats | ||
214 | void rotateVect(T *out,const core::vector3df &in) const; | ||
215 | |||
216 | //! Transforms the vector by this matrix | ||
217 | void transformVect( vector3df& vect) const; | ||
218 | |||
219 | //! Transforms input vector by this matrix and stores result in output vector | ||
220 | void transformVect( vector3df& out, const vector3df& in ) const; | ||
221 | |||
222 | //! An alternate transform vector method, writing into an array of 4 floats | ||
223 | void transformVect(T *out,const core::vector3df &in) const; | ||
224 | |||
225 | //! An alternate transform vector method, reading from and writing to an array of 3 floats | ||
226 | void transformVec3(T *out, const T * in) const; | ||
227 | |||
228 | //! Translate a vector by the translation part of this matrix. | ||
229 | void translateVect( vector3df& vect ) const; | ||
230 | |||
231 | //! Transforms a plane by this matrix | ||
232 | void transformPlane( core::plane3d<f32> &plane) const; | ||
233 | |||
234 | //! Transforms a plane by this matrix | ||
235 | void transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const; | ||
236 | |||
237 | //! Transforms a axis aligned bounding box | ||
238 | /** The result box of this operation may not be accurate at all. For | ||
239 | correct results, use transformBoxEx() */ | ||
240 | void transformBox(core::aabbox3d<f32>& box) const; | ||
241 | |||
242 | //! Transforms a axis aligned bounding box | ||
243 | /** The result box of this operation should by accurate, but this operation | ||
244 | is slower than transformBox(). */ | ||
245 | void transformBoxEx(core::aabbox3d<f32>& box) const; | ||
246 | |||
247 | //! Multiplies this matrix by a 1x4 matrix | ||
248 | void multiplyWith1x4Matrix(T* matrix) const; | ||
249 | |||
250 | //! Calculates inverse of matrix. Slow. | ||
251 | /** \return Returns false if there is no inverse matrix.*/ | ||
252 | bool makeInverse(); | ||
253 | |||
254 | |||
255 | //! Inverts a primitive matrix which only contains a translation and a rotation | ||
256 | /** \param out: where result matrix is written to. */ | ||
257 | bool getInversePrimitive ( CMatrix4<T>& out ) const; | ||
258 | |||
259 | //! Gets the inversed matrix of this one | ||
260 | /** \param out: where result matrix is written to. | ||
261 | \return Returns false if there is no inverse matrix. */ | ||
262 | bool getInverse(CMatrix4<T>& out) const; | ||
263 | |||
264 | //! Builds a right-handed perspective projection matrix based on a field of view | ||
265 | CMatrix4<T>& buildProjectionMatrixPerspectiveFovRH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar); | ||
266 | |||
267 | //! Builds a left-handed perspective projection matrix based on a field of view | ||
268 | CMatrix4<T>& buildProjectionMatrixPerspectiveFovLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar); | ||
269 | |||
270 | //! Builds a left-handed perspective projection matrix based on a field of view, with far plane at infinity | ||
271 | CMatrix4<T>& buildProjectionMatrixPerspectiveFovInfinityLH(f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon=0); | ||
272 | |||
273 | //! Builds a right-handed perspective projection matrix. | ||
274 | CMatrix4<T>& buildProjectionMatrixPerspectiveRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); | ||
275 | |||
276 | //! Builds a left-handed perspective projection matrix. | ||
277 | CMatrix4<T>& buildProjectionMatrixPerspectiveLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); | ||
278 | |||
279 | //! Builds a left-handed orthogonal projection matrix. | ||
280 | CMatrix4<T>& buildProjectionMatrixOrthoLH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); | ||
281 | |||
282 | //! Builds a right-handed orthogonal projection matrix. | ||
283 | CMatrix4<T>& buildProjectionMatrixOrthoRH(f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar); | ||
284 | |||
285 | //! Builds a left-handed look-at matrix. | ||
286 | CMatrix4<T>& buildCameraLookAtMatrixLH( | ||
287 | const vector3df& position, | ||
288 | const vector3df& target, | ||
289 | const vector3df& upVector); | ||
290 | |||
291 | //! Builds a right-handed look-at matrix. | ||
292 | CMatrix4<T>& buildCameraLookAtMatrixRH( | ||
293 | const vector3df& position, | ||
294 | const vector3df& target, | ||
295 | const vector3df& upVector); | ||
296 | |||
297 | //! Builds a matrix that flattens geometry into a plane. | ||
298 | /** \param light: light source | ||
299 | \param plane: plane into which the geometry if flattened into | ||
300 | \param point: value between 0 and 1, describing the light source. | ||
301 | If this is 1, it is a point light, if it is 0, it is a directional light. */ | ||
302 | CMatrix4<T>& buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point=1.0f); | ||
303 | |||
304 | //! Builds a matrix which transforms a normalized Device Coordinate to Device Coordinates. | ||
305 | /** Used to scale <-1,-1><1,1> to viewport, for example from <-1,-1> <1,1> to the viewport <0,0><0,640> */ | ||
306 | CMatrix4<T>& buildNDCToDCMatrix( const core::rect<s32>& area, f32 zScale); | ||
307 | |||
308 | //! Creates a new matrix as interpolated matrix from two other ones. | ||
309 | /** \param b: other matrix to interpolate with | ||
310 | \param time: Must be a value between 0 and 1. */ | ||
311 | CMatrix4<T> interpolate(const core::CMatrix4<T>& b, f32 time) const; | ||
312 | |||
313 | //! Gets transposed matrix | ||
314 | CMatrix4<T> getTransposed() const; | ||
315 | |||
316 | //! Gets transposed matrix | ||
317 | inline void getTransposed( CMatrix4<T>& dest ) const; | ||
318 | |||
319 | //! Builds a matrix that rotates from one vector to another | ||
320 | /** \param from: vector to rotate from | ||
321 | \param to: vector to rotate to | ||
322 | */ | ||
323 | CMatrix4<T>& buildRotateFromTo(const core::vector3df& from, const core::vector3df& to); | ||
324 | |||
325 | //! Builds a combined matrix which translates to a center before rotation and translates from origin afterwards | ||
326 | /** \param center Position to rotate around | ||
327 | \param translate Translation applied after the rotation | ||
328 | */ | ||
329 | void setRotationCenter(const core::vector3df& center, const core::vector3df& translate); | ||
330 | |||
331 | //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis | ||
332 | /** \param camPos: viewer position in world coo | ||
333 | \param center: object position in world-coo and rotation pivot | ||
334 | \param translation: object final translation from center | ||
335 | \param axis: axis to rotate about | ||
336 | \param from: source vector to rotate from | ||
337 | */ | ||
338 | void buildAxisAlignedBillboard(const core::vector3df& camPos, | ||
339 | const core::vector3df& center, | ||
340 | const core::vector3df& translation, | ||
341 | const core::vector3df& axis, | ||
342 | const core::vector3df& from); | ||
343 | |||
344 | /* | ||
345 | construct 2D Texture transformations | ||
346 | rotate about center, scale, and transform. | ||
347 | */ | ||
348 | //! Set to a texture transformation matrix with the given parameters. | ||
349 | CMatrix4<T>& buildTextureTransform( f32 rotateRad, | ||
350 | const core::vector2df &rotatecenter, | ||
351 | const core::vector2df &translate, | ||
352 | const core::vector2df &scale); | ||
353 | |||
354 | //! Set texture transformation rotation | ||
355 | /** Rotate about z axis, recenter at (0.5,0.5). | ||
356 | Doesn't clear other elements than those affected | ||
357 | \param radAngle Angle in radians | ||
358 | \return Altered matrix */ | ||
359 | CMatrix4<T>& setTextureRotationCenter( f32 radAngle ); | ||
360 | |||
361 | //! Set texture transformation translation | ||
362 | /** Doesn't clear other elements than those affected. | ||
363 | \param x Offset on x axis | ||
364 | \param y Offset on y axis | ||
365 | \return Altered matrix */ | ||
366 | CMatrix4<T>& setTextureTranslate( f32 x, f32 y ); | ||
367 | |||
368 | //! Set texture transformation translation, using a transposed representation | ||
369 | /** Doesn't clear other elements than those affected. | ||
370 | \param x Offset on x axis | ||
371 | \param y Offset on y axis | ||
372 | \return Altered matrix */ | ||
373 | CMatrix4<T>& setTextureTranslateTransposed( f32 x, f32 y ); | ||
374 | |||
375 | //! Set texture transformation scale | ||
376 | /** Doesn't clear other elements than those affected. | ||
377 | \param sx Scale factor on x axis | ||
378 | \param sy Scale factor on y axis | ||
379 | \return Altered matrix. */ | ||
380 | CMatrix4<T>& setTextureScale( f32 sx, f32 sy ); | ||
381 | |||
382 | //! Set texture transformation scale, and recenter at (0.5,0.5) | ||
383 | /** Doesn't clear other elements than those affected. | ||
384 | \param sx Scale factor on x axis | ||
385 | \param sy Scale factor on y axis | ||
386 | \return Altered matrix. */ | ||
387 | CMatrix4<T>& setTextureScaleCenter( f32 sx, f32 sy ); | ||
388 | |||
389 | //! Sets all matrix data members at once | ||
390 | CMatrix4<T>& setM(const T* data); | ||
391 | |||
392 | //! Sets if the matrix is definitely identity matrix | ||
393 | void setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix); | ||
394 | |||
395 | //! Gets if the matrix is definitely identity matrix | ||
396 | bool getDefinitelyIdentityMatrix() const; | ||
397 | |||
398 | //! Compare two matrices using the equal method | ||
399 | bool equals(const core::CMatrix4<T>& other, const T tolerance=(T)ROUNDING_ERROR_f64) const; | ||
400 | |||
401 | private: | ||
402 | //! Matrix data, stored in row-major order | ||
403 | T M[16]; | ||
404 | #if defined ( USE_MATRIX_TEST ) | ||
405 | //! Flag is this matrix is identity matrix | ||
406 | mutable u32 definitelyIdentityMatrix; | ||
407 | #endif | ||
408 | #if defined ( USE_MATRIX_TEST_DEBUG ) | ||
409 | u32 id; | ||
410 | mutable u32 calls; | ||
411 | #endif | ||
412 | |||
413 | }; | ||
414 | |||
415 | // Default constructor | ||
416 | template <class T> | ||
417 | inline CMatrix4<T>::CMatrix4( eConstructor constructor ) | ||
418 | #if defined ( USE_MATRIX_TEST ) | ||
419 | : definitelyIdentityMatrix(BIT_UNTESTED) | ||
420 | #endif | ||
421 | #if defined ( USE_MATRIX_TEST_DEBUG ) | ||
422 | ,id ( MTest.ID++), calls ( 0 ) | ||
423 | #endif | ||
424 | { | ||
425 | switch ( constructor ) | ||
426 | { | ||
427 | case EM4CONST_NOTHING: | ||
428 | case EM4CONST_COPY: | ||
429 | break; | ||
430 | case EM4CONST_IDENTITY: | ||
431 | case EM4CONST_INVERSE: | ||
432 | default: | ||
433 | makeIdentity(); | ||
434 | break; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | // Copy constructor | ||
439 | template <class T> | ||
440 | inline CMatrix4<T>::CMatrix4( const CMatrix4<T>& other, eConstructor constructor) | ||
441 | #if defined ( USE_MATRIX_TEST ) | ||
442 | : definitelyIdentityMatrix(BIT_UNTESTED) | ||
443 | #endif | ||
444 | #if defined ( USE_MATRIX_TEST_DEBUG ) | ||
445 | ,id ( MTest.ID++), calls ( 0 ) | ||
446 | #endif | ||
447 | { | ||
448 | switch ( constructor ) | ||
449 | { | ||
450 | case EM4CONST_IDENTITY: | ||
451 | makeIdentity(); | ||
452 | break; | ||
453 | case EM4CONST_NOTHING: | ||
454 | break; | ||
455 | case EM4CONST_COPY: | ||
456 | *this = other; | ||
457 | break; | ||
458 | case EM4CONST_TRANSPOSED: | ||
459 | other.getTransposed(*this); | ||
460 | break; | ||
461 | case EM4CONST_INVERSE: | ||
462 | if (!other.getInverse(*this)) | ||
463 | memset(M, 0, 16*sizeof(T)); | ||
464 | break; | ||
465 | case EM4CONST_INVERSE_TRANSPOSED: | ||
466 | if (!other.getInverse(*this)) | ||
467 | memset(M, 0, 16*sizeof(T)); | ||
468 | else | ||
469 | *this=getTransposed(); | ||
470 | break; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | //! Add another matrix. | ||
475 | template <class T> | ||
476 | inline CMatrix4<T> CMatrix4<T>::operator+(const CMatrix4<T>& other) const | ||
477 | { | ||
478 | CMatrix4<T> temp ( EM4CONST_NOTHING ); | ||
479 | |||
480 | temp[0] = M[0]+other[0]; | ||
481 | temp[1] = M[1]+other[1]; | ||
482 | temp[2] = M[2]+other[2]; | ||
483 | temp[3] = M[3]+other[3]; | ||
484 | temp[4] = M[4]+other[4]; | ||
485 | temp[5] = M[5]+other[5]; | ||
486 | temp[6] = M[6]+other[6]; | ||
487 | temp[7] = M[7]+other[7]; | ||
488 | temp[8] = M[8]+other[8]; | ||
489 | temp[9] = M[9]+other[9]; | ||
490 | temp[10] = M[10]+other[10]; | ||
491 | temp[11] = M[11]+other[11]; | ||
492 | temp[12] = M[12]+other[12]; | ||
493 | temp[13] = M[13]+other[13]; | ||
494 | temp[14] = M[14]+other[14]; | ||
495 | temp[15] = M[15]+other[15]; | ||
496 | |||
497 | return temp; | ||
498 | } | ||
499 | |||
500 | //! Add another matrix. | ||
501 | template <class T> | ||
502 | inline CMatrix4<T>& CMatrix4<T>::operator+=(const CMatrix4<T>& other) | ||
503 | { | ||
504 | M[0]+=other[0]; | ||
505 | M[1]+=other[1]; | ||
506 | M[2]+=other[2]; | ||
507 | M[3]+=other[3]; | ||
508 | M[4]+=other[4]; | ||
509 | M[5]+=other[5]; | ||
510 | M[6]+=other[6]; | ||
511 | M[7]+=other[7]; | ||
512 | M[8]+=other[8]; | ||
513 | M[9]+=other[9]; | ||
514 | M[10]+=other[10]; | ||
515 | M[11]+=other[11]; | ||
516 | M[12]+=other[12]; | ||
517 | M[13]+=other[13]; | ||
518 | M[14]+=other[14]; | ||
519 | M[15]+=other[15]; | ||
520 | |||
521 | return *this; | ||
522 | } | ||
523 | |||
524 | //! Subtract another matrix. | ||
525 | template <class T> | ||
526 | inline CMatrix4<T> CMatrix4<T>::operator-(const CMatrix4<T>& other) const | ||
527 | { | ||
528 | CMatrix4<T> temp ( EM4CONST_NOTHING ); | ||
529 | |||
530 | temp[0] = M[0]-other[0]; | ||
531 | temp[1] = M[1]-other[1]; | ||
532 | temp[2] = M[2]-other[2]; | ||
533 | temp[3] = M[3]-other[3]; | ||
534 | temp[4] = M[4]-other[4]; | ||
535 | temp[5] = M[5]-other[5]; | ||
536 | temp[6] = M[6]-other[6]; | ||
537 | temp[7] = M[7]-other[7]; | ||
538 | temp[8] = M[8]-other[8]; | ||
539 | temp[9] = M[9]-other[9]; | ||
540 | temp[10] = M[10]-other[10]; | ||
541 | temp[11] = M[11]-other[11]; | ||
542 | temp[12] = M[12]-other[12]; | ||
543 | temp[13] = M[13]-other[13]; | ||
544 | temp[14] = M[14]-other[14]; | ||
545 | temp[15] = M[15]-other[15]; | ||
546 | |||
547 | return temp; | ||
548 | } | ||
549 | |||
550 | //! Subtract another matrix. | ||
551 | template <class T> | ||
552 | inline CMatrix4<T>& CMatrix4<T>::operator-=(const CMatrix4<T>& other) | ||
553 | { | ||
554 | M[0]-=other[0]; | ||
555 | M[1]-=other[1]; | ||
556 | M[2]-=other[2]; | ||
557 | M[3]-=other[3]; | ||
558 | M[4]-=other[4]; | ||
559 | M[5]-=other[5]; | ||
560 | M[6]-=other[6]; | ||
561 | M[7]-=other[7]; | ||
562 | M[8]-=other[8]; | ||
563 | M[9]-=other[9]; | ||
564 | M[10]-=other[10]; | ||
565 | M[11]-=other[11]; | ||
566 | M[12]-=other[12]; | ||
567 | M[13]-=other[13]; | ||
568 | M[14]-=other[14]; | ||
569 | M[15]-=other[15]; | ||
570 | |||
571 | return *this; | ||
572 | } | ||
573 | |||
574 | //! Multiply by scalar. | ||
575 | template <class T> | ||
576 | inline CMatrix4<T> CMatrix4<T>::operator*(const T& scalar) const | ||
577 | { | ||
578 | CMatrix4<T> temp ( EM4CONST_NOTHING ); | ||
579 | |||
580 | temp[0] = M[0]*scalar; | ||
581 | temp[1] = M[1]*scalar; | ||
582 | temp[2] = M[2]*scalar; | ||
583 | temp[3] = M[3]*scalar; | ||
584 | temp[4] = M[4]*scalar; | ||
585 | temp[5] = M[5]*scalar; | ||
586 | temp[6] = M[6]*scalar; | ||
587 | temp[7] = M[7]*scalar; | ||
588 | temp[8] = M[8]*scalar; | ||
589 | temp[9] = M[9]*scalar; | ||
590 | temp[10] = M[10]*scalar; | ||
591 | temp[11] = M[11]*scalar; | ||
592 | temp[12] = M[12]*scalar; | ||
593 | temp[13] = M[13]*scalar; | ||
594 | temp[14] = M[14]*scalar; | ||
595 | temp[15] = M[15]*scalar; | ||
596 | |||
597 | return temp; | ||
598 | } | ||
599 | |||
600 | //! Multiply by scalar. | ||
601 | template <class T> | ||
602 | inline CMatrix4<T>& CMatrix4<T>::operator*=(const T& scalar) | ||
603 | { | ||
604 | M[0]*=scalar; | ||
605 | M[1]*=scalar; | ||
606 | M[2]*=scalar; | ||
607 | M[3]*=scalar; | ||
608 | M[4]*=scalar; | ||
609 | M[5]*=scalar; | ||
610 | M[6]*=scalar; | ||
611 | M[7]*=scalar; | ||
612 | M[8]*=scalar; | ||
613 | M[9]*=scalar; | ||
614 | M[10]*=scalar; | ||
615 | M[11]*=scalar; | ||
616 | M[12]*=scalar; | ||
617 | M[13]*=scalar; | ||
618 | M[14]*=scalar; | ||
619 | M[15]*=scalar; | ||
620 | |||
621 | return *this; | ||
622 | } | ||
623 | |||
624 | //! Multiply by another matrix. | ||
625 | template <class T> | ||
626 | inline CMatrix4<T>& CMatrix4<T>::operator*=(const CMatrix4<T>& other) | ||
627 | { | ||
628 | #if defined ( USE_MATRIX_TEST ) | ||
629 | // do checks on your own in order to avoid copy creation | ||
630 | if ( !other.isIdentity() ) | ||
631 | { | ||
632 | if ( this->isIdentity() ) | ||
633 | { | ||
634 | return (*this = other); | ||
635 | } | ||
636 | else | ||
637 | { | ||
638 | CMatrix4<T> temp ( *this ); | ||
639 | return setbyproduct_nocheck( temp, other ); | ||
640 | } | ||
641 | } | ||
642 | return *this; | ||
643 | #else | ||
644 | CMatrix4<T> temp ( *this ); | ||
645 | return setbyproduct_nocheck( temp, other ); | ||
646 | #endif | ||
647 | } | ||
648 | |||
649 | //! multiply by another matrix | ||
650 | // set this matrix to the product of two other matrices | ||
651 | // goal is to reduce stack use and copy | ||
652 | template <class T> | ||
653 | inline CMatrix4<T>& CMatrix4<T>::setbyproduct_nocheck(const CMatrix4<T>& other_a,const CMatrix4<T>& other_b ) | ||
654 | { | ||
655 | const T *m1 = other_a.M; | ||
656 | const T *m2 = other_b.M; | ||
657 | |||
658 | M[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; | ||
659 | M[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; | ||
660 | M[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; | ||
661 | M[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3]; | ||
662 | |||
663 | M[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7]; | ||
664 | M[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7]; | ||
665 | M[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7]; | ||
666 | M[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7]; | ||
667 | |||
668 | M[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11]; | ||
669 | M[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11]; | ||
670 | M[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11]; | ||
671 | M[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11]; | ||
672 | |||
673 | M[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15]; | ||
674 | M[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15]; | ||
675 | M[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15]; | ||
676 | M[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; | ||
677 | #if defined ( USE_MATRIX_TEST ) | ||
678 | definitelyIdentityMatrix=false; | ||
679 | #endif | ||
680 | return *this; | ||
681 | } | ||
682 | |||
683 | |||
684 | //! multiply by another matrix | ||
685 | // set this matrix to the product of two other matrices | ||
686 | // goal is to reduce stack use and copy | ||
687 | template <class T> | ||
688 | inline CMatrix4<T>& CMatrix4<T>::setbyproduct(const CMatrix4<T>& other_a, const CMatrix4<T>& other_b ) | ||
689 | { | ||
690 | #if defined ( USE_MATRIX_TEST ) | ||
691 | if ( other_a.isIdentity () ) | ||
692 | return (*this = other_b); | ||
693 | else | ||
694 | if ( other_b.isIdentity () ) | ||
695 | return (*this = other_a); | ||
696 | else | ||
697 | return setbyproduct_nocheck(other_a,other_b); | ||
698 | #else | ||
699 | return setbyproduct_nocheck(other_a,other_b); | ||
700 | #endif | ||
701 | } | ||
702 | |||
703 | //! multiply by another matrix | ||
704 | template <class T> | ||
705 | inline CMatrix4<T> CMatrix4<T>::operator*(const CMatrix4<T>& m2) const | ||
706 | { | ||
707 | #if defined ( USE_MATRIX_TEST ) | ||
708 | // Testing purpose.. | ||
709 | if ( this->isIdentity() ) | ||
710 | return m2; | ||
711 | if ( m2.isIdentity() ) | ||
712 | return *this; | ||
713 | #endif | ||
714 | |||
715 | CMatrix4<T> m3 ( EM4CONST_NOTHING ); | ||
716 | |||
717 | const T *m1 = M; | ||
718 | |||
719 | m3[0] = m1[0]*m2[0] + m1[4]*m2[1] + m1[8]*m2[2] + m1[12]*m2[3]; | ||
720 | m3[1] = m1[1]*m2[0] + m1[5]*m2[1] + m1[9]*m2[2] + m1[13]*m2[3]; | ||
721 | m3[2] = m1[2]*m2[0] + m1[6]*m2[1] + m1[10]*m2[2] + m1[14]*m2[3]; | ||
722 | m3[3] = m1[3]*m2[0] + m1[7]*m2[1] + m1[11]*m2[2] + m1[15]*m2[3]; | ||
723 | |||
724 | m3[4] = m1[0]*m2[4] + m1[4]*m2[5] + m1[8]*m2[6] + m1[12]*m2[7]; | ||
725 | m3[5] = m1[1]*m2[4] + m1[5]*m2[5] + m1[9]*m2[6] + m1[13]*m2[7]; | ||
726 | m3[6] = m1[2]*m2[4] + m1[6]*m2[5] + m1[10]*m2[6] + m1[14]*m2[7]; | ||
727 | m3[7] = m1[3]*m2[4] + m1[7]*m2[5] + m1[11]*m2[6] + m1[15]*m2[7]; | ||
728 | |||
729 | m3[8] = m1[0]*m2[8] + m1[4]*m2[9] + m1[8]*m2[10] + m1[12]*m2[11]; | ||
730 | m3[9] = m1[1]*m2[8] + m1[5]*m2[9] + m1[9]*m2[10] + m1[13]*m2[11]; | ||
731 | m3[10] = m1[2]*m2[8] + m1[6]*m2[9] + m1[10]*m2[10] + m1[14]*m2[11]; | ||
732 | m3[11] = m1[3]*m2[8] + m1[7]*m2[9] + m1[11]*m2[10] + m1[15]*m2[11]; | ||
733 | |||
734 | m3[12] = m1[0]*m2[12] + m1[4]*m2[13] + m1[8]*m2[14] + m1[12]*m2[15]; | ||
735 | m3[13] = m1[1]*m2[12] + m1[5]*m2[13] + m1[9]*m2[14] + m1[13]*m2[15]; | ||
736 | m3[14] = m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15]; | ||
737 | m3[15] = m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15]; | ||
738 | return m3; | ||
739 | } | ||
740 | |||
741 | |||
742 | |||
743 | template <class T> | ||
744 | inline vector3d<T> CMatrix4<T>::getTranslation() const | ||
745 | { | ||
746 | return vector3d<T>(M[12], M[13], M[14]); | ||
747 | } | ||
748 | |||
749 | |||
750 | template <class T> | ||
751 | inline CMatrix4<T>& CMatrix4<T>::setTranslation( const vector3d<T>& translation ) | ||
752 | { | ||
753 | M[12] = translation.X; | ||
754 | M[13] = translation.Y; | ||
755 | M[14] = translation.Z; | ||
756 | #if defined ( USE_MATRIX_TEST ) | ||
757 | definitelyIdentityMatrix=false; | ||
758 | #endif | ||
759 | return *this; | ||
760 | } | ||
761 | |||
762 | template <class T> | ||
763 | inline CMatrix4<T>& CMatrix4<T>::setInverseTranslation( const vector3d<T>& translation ) | ||
764 | { | ||
765 | M[12] = -translation.X; | ||
766 | M[13] = -translation.Y; | ||
767 | M[14] = -translation.Z; | ||
768 | #if defined ( USE_MATRIX_TEST ) | ||
769 | definitelyIdentityMatrix=false; | ||
770 | #endif | ||
771 | return *this; | ||
772 | } | ||
773 | |||
774 | template <class T> | ||
775 | inline CMatrix4<T>& CMatrix4<T>::setScale( const vector3d<T>& scale ) | ||
776 | { | ||
777 | M[0] = scale.X; | ||
778 | M[5] = scale.Y; | ||
779 | M[10] = scale.Z; | ||
780 | #if defined ( USE_MATRIX_TEST ) | ||
781 | definitelyIdentityMatrix=false; | ||
782 | #endif | ||
783 | return *this; | ||
784 | } | ||
785 | |||
786 | //! Returns the absolute values of the scales of the matrix. | ||
787 | /** | ||
788 | Note that this returns the absolute (positive) values unless only scale is set. | ||
789 | Unfortunately it does not appear to be possible to extract any original negative | ||
790 | values. The best that we could do would be to arbitrarily make one scale | ||
791 | negative if one or three of them were negative. | ||
792 | FIXME - return the original values. | ||
793 | */ | ||
794 | template <class T> | ||
795 | inline vector3d<T> CMatrix4<T>::getScale() const | ||
796 | { | ||
797 | // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices | ||
798 | |||
799 | // Deal with the 0 rotation case first | ||
800 | // Prior to Irrlicht 1.6, we always returned this value. | ||
801 | if(core::iszero(M[1]) && core::iszero(M[2]) && | ||
802 | core::iszero(M[4]) && core::iszero(M[6]) && | ||
803 | core::iszero(M[8]) && core::iszero(M[9])) | ||
804 | return vector3d<T>(M[0], M[5], M[10]); | ||
805 | |||
806 | // We have to do the full calculation. | ||
807 | return vector3d<T>(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]), | ||
808 | sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]), | ||
809 | sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10])); | ||
810 | } | ||
811 | |||
812 | template <class T> | ||
813 | inline CMatrix4<T>& CMatrix4<T>::setRotationDegrees( const vector3d<T>& rotation ) | ||
814 | { | ||
815 | return setRotationRadians( rotation * core::DEGTORAD ); | ||
816 | } | ||
817 | |||
818 | template <class T> | ||
819 | inline CMatrix4<T>& CMatrix4<T>::setInverseRotationDegrees( const vector3d<T>& rotation ) | ||
820 | { | ||
821 | return setInverseRotationRadians( rotation * core::DEGTORAD ); | ||
822 | } | ||
823 | |||
824 | template <class T> | ||
825 | inline CMatrix4<T>& CMatrix4<T>::setRotationRadians( const vector3d<T>& rotation ) | ||
826 | { | ||
827 | const f64 cr = cos( rotation.X ); | ||
828 | const f64 sr = sin( rotation.X ); | ||
829 | const f64 cp = cos( rotation.Y ); | ||
830 | const f64 sp = sin( rotation.Y ); | ||
831 | const f64 cy = cos( rotation.Z ); | ||
832 | const f64 sy = sin( rotation.Z ); | ||
833 | |||
834 | M[0] = (T)( cp*cy ); | ||
835 | M[1] = (T)( cp*sy ); | ||
836 | M[2] = (T)( -sp ); | ||
837 | |||
838 | const f64 srsp = sr*sp; | ||
839 | const f64 crsp = cr*sp; | ||
840 | |||
841 | M[4] = (T)( srsp*cy-cr*sy ); | ||
842 | M[5] = (T)( srsp*sy+cr*cy ); | ||
843 | M[6] = (T)( sr*cp ); | ||
844 | |||
845 | M[8] = (T)( crsp*cy+sr*sy ); | ||
846 | M[9] = (T)( crsp*sy-sr*cy ); | ||
847 | M[10] = (T)( cr*cp ); | ||
848 | #if defined ( USE_MATRIX_TEST ) | ||
849 | definitelyIdentityMatrix=false; | ||
850 | #endif | ||
851 | return *this; | ||
852 | } | ||
853 | |||
854 | |||
855 | //! Returns a rotation that is equivalent to that set by setRotationDegrees(). | ||
856 | /** This code was sent in by Chev. Note that it does not necessarily return | ||
857 | the *same* Euler angles as those set by setRotationDegrees(), but the rotation will | ||
858 | be equivalent, i.e. will have the same result when used to rotate a vector or node. */ | ||
859 | template <class T> | ||
860 | inline core::vector3d<T> CMatrix4<T>::getRotationDegrees() const | ||
861 | { | ||
862 | const CMatrix4<T> &mat = *this; | ||
863 | core::vector3d<T> scale = getScale(); | ||
864 | // we need to check for negative scale on to axes, which would bring up wrong results | ||
865 | if (scale.Y<0 && scale.Z<0) | ||
866 | { | ||
867 | scale.Y =-scale.Y; | ||
868 | scale.Z =-scale.Z; | ||
869 | } | ||
870 | else if (scale.X<0 && scale.Z<0) | ||
871 | { | ||
872 | scale.X =-scale.X; | ||
873 | scale.Z =-scale.Z; | ||
874 | } | ||
875 | else if (scale.X<0 && scale.Y<0) | ||
876 | { | ||
877 | scale.X =-scale.X; | ||
878 | scale.Y =-scale.Y; | ||
879 | } | ||
880 | const core::vector3d<f64> invScale(core::reciprocal(scale.X),core::reciprocal(scale.Y),core::reciprocal(scale.Z)); | ||
881 | |||
882 | f64 Y = -asin(core::clamp(mat[2]*invScale.X, -1.0, 1.0)); | ||
883 | const f64 C = cos(Y); | ||
884 | Y *= RADTODEG64; | ||
885 | |||
886 | f64 rotx, roty, X, Z; | ||
887 | |||
888 | if (!core::iszero(C)) | ||
889 | { | ||
890 | const f64 invC = core::reciprocal(C); | ||
891 | rotx = mat[10] * invC * invScale.Z; | ||
892 | roty = mat[6] * invC * invScale.Y; | ||
893 | X = atan2( roty, rotx ) * RADTODEG64; | ||
894 | rotx = mat[0] * invC * invScale.X; | ||
895 | roty = mat[1] * invC * invScale.X; | ||
896 | Z = atan2( roty, rotx ) * RADTODEG64; | ||
897 | } | ||
898 | else | ||
899 | { | ||
900 | X = 0.0; | ||
901 | rotx = mat[5] * invScale.Y; | ||
902 | roty = -mat[4] * invScale.Y; | ||
903 | Z = atan2( roty, rotx ) * RADTODEG64; | ||
904 | } | ||
905 | |||
906 | // fix values that get below zero | ||
907 | if (X < 0.0) X += 360.0; | ||
908 | if (Y < 0.0) Y += 360.0; | ||
909 | if (Z < 0.0) Z += 360.0; | ||
910 | |||
911 | return vector3d<T>((T)X,(T)Y,(T)Z); | ||
912 | } | ||
913 | |||
914 | |||
915 | //! Sets matrix to rotation matrix of inverse angles given as parameters | ||
916 | template <class T> | ||
917 | inline CMatrix4<T>& CMatrix4<T>::setInverseRotationRadians( const vector3d<T>& rotation ) | ||
918 | { | ||
919 | f64 cr = cos( rotation.X ); | ||
920 | f64 sr = sin( rotation.X ); | ||
921 | f64 cp = cos( rotation.Y ); | ||
922 | f64 sp = sin( rotation.Y ); | ||
923 | f64 cy = cos( rotation.Z ); | ||
924 | f64 sy = sin( rotation.Z ); | ||
925 | |||
926 | M[0] = (T)( cp*cy ); | ||
927 | M[4] = (T)( cp*sy ); | ||
928 | M[8] = (T)( -sp ); | ||
929 | |||
930 | f64 srsp = sr*sp; | ||
931 | f64 crsp = cr*sp; | ||
932 | |||
933 | M[1] = (T)( srsp*cy-cr*sy ); | ||
934 | M[5] = (T)( srsp*sy+cr*cy ); | ||
935 | M[9] = (T)( sr*cp ); | ||
936 | |||
937 | M[2] = (T)( crsp*cy+sr*sy ); | ||
938 | M[6] = (T)( crsp*sy-sr*cy ); | ||
939 | M[10] = (T)( cr*cp ); | ||
940 | #if defined ( USE_MATRIX_TEST ) | ||
941 | definitelyIdentityMatrix=false; | ||
942 | #endif | ||
943 | return *this; | ||
944 | } | ||
945 | |||
946 | //! Sets matrix to rotation matrix defined by axis and angle, assuming LH rotation | ||
947 | template <class T> | ||
948 | inline CMatrix4<T>& CMatrix4<T>::setRotationAxisRadians( const T& angle, const vector3d<T>& axis ) | ||
949 | { | ||
950 | const f64 c = cos(angle); | ||
951 | const f64 s = sin(angle); | ||
952 | const f64 t = 1.0 - c; | ||
953 | |||
954 | const f64 tx = t * axis.X; | ||
955 | const f64 ty = t * axis.Y; | ||
956 | const f64 tz = t * axis.Z; | ||
957 | |||
958 | const f64 sx = s * axis.X; | ||
959 | const f64 sy = s * axis.Y; | ||
960 | const f64 sz = s * axis.Z; | ||
961 | |||
962 | M[0] = (T)(tx * axis.X + c); | ||
963 | M[1] = (T)(tx * axis.Y + sz); | ||
964 | M[2] = (T)(tx * axis.Z - sy); | ||
965 | |||
966 | M[4] = (T)(ty * axis.X - sz); | ||
967 | M[5] = (T)(ty * axis.Y + c); | ||
968 | M[6] = (T)(ty * axis.Z + sx); | ||
969 | |||
970 | M[8] = (T)(tz * axis.X + sy); | ||
971 | M[9] = (T)(tz * axis.Y - sx); | ||
972 | M[10] = (T)(tz * axis.Z + c); | ||
973 | |||
974 | #if defined ( USE_MATRIX_TEST ) | ||
975 | definitelyIdentityMatrix=false; | ||
976 | #endif | ||
977 | return *this; | ||
978 | } | ||
979 | |||
980 | |||
981 | /*! | ||
982 | */ | ||
983 | template <class T> | ||
984 | inline CMatrix4<T>& CMatrix4<T>::makeIdentity() | ||
985 | { | ||
986 | memset(M, 0, 16*sizeof(T)); | ||
987 | M[0] = M[5] = M[10] = M[15] = (T)1; | ||
988 | #if defined ( USE_MATRIX_TEST ) | ||
989 | definitelyIdentityMatrix=true; | ||
990 | #endif | ||
991 | return *this; | ||
992 | } | ||
993 | |||
994 | |||
995 | /* | ||
996 | check identity with epsilon | ||
997 | solve floating range problems.. | ||
998 | */ | ||
999 | template <class T> | ||
1000 | inline bool CMatrix4<T>::isIdentity() const | ||
1001 | { | ||
1002 | #if defined ( USE_MATRIX_TEST ) | ||
1003 | if (definitelyIdentityMatrix) | ||
1004 | return true; | ||
1005 | #endif | ||
1006 | if (!core::equals( M[12], (T)0 ) || !core::equals( M[13], (T)0 ) || !core::equals( M[14], (T)0 ) || !core::equals( M[15], (T)1 )) | ||
1007 | return false; | ||
1008 | |||
1009 | if (!core::equals( M[ 0], (T)1 ) || !core::equals( M[ 1], (T)0 ) || !core::equals( M[ 2], (T)0 ) || !core::equals( M[ 3], (T)0 )) | ||
1010 | return false; | ||
1011 | |||
1012 | if (!core::equals( M[ 4], (T)0 ) || !core::equals( M[ 5], (T)1 ) || !core::equals( M[ 6], (T)0 ) || !core::equals( M[ 7], (T)0 )) | ||
1013 | return false; | ||
1014 | |||
1015 | if (!core::equals( M[ 8], (T)0 ) || !core::equals( M[ 9], (T)0 ) || !core::equals( M[10], (T)1 ) || !core::equals( M[11], (T)0 )) | ||
1016 | return false; | ||
1017 | /* | ||
1018 | if (!core::equals( M[ 0], (T)1 ) || | ||
1019 | !core::equals( M[ 5], (T)1 ) || | ||
1020 | !core::equals( M[10], (T)1 ) || | ||
1021 | !core::equals( M[15], (T)1 )) | ||
1022 | return false; | ||
1023 | |||
1024 | for (s32 i=0; i<4; ++i) | ||
1025 | for (s32 j=0; j<4; ++j) | ||
1026 | if ((j != i) && (!iszero((*this)(i,j)))) | ||
1027 | return false; | ||
1028 | */ | ||
1029 | #if defined ( USE_MATRIX_TEST ) | ||
1030 | definitelyIdentityMatrix=true; | ||
1031 | #endif | ||
1032 | return true; | ||
1033 | } | ||
1034 | |||
1035 | |||
1036 | /* Check orthogonality of matrix. */ | ||
1037 | template <class T> | ||
1038 | inline bool CMatrix4<T>::isOrthogonal() const | ||
1039 | { | ||
1040 | T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ]; | ||
1041 | if (!iszero(dp)) | ||
1042 | return false; | ||
1043 | dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11]; | ||
1044 | if (!iszero(dp)) | ||
1045 | return false; | ||
1046 | dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15]; | ||
1047 | if (!iszero(dp)) | ||
1048 | return false; | ||
1049 | dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11]; | ||
1050 | if (!iszero(dp)) | ||
1051 | return false; | ||
1052 | dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15]; | ||
1053 | if (!iszero(dp)) | ||
1054 | return false; | ||
1055 | dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15]; | ||
1056 | return (iszero(dp)); | ||
1057 | } | ||
1058 | |||
1059 | |||
1060 | /* | ||
1061 | doesn't solve floating range problems.. | ||
1062 | but takes care on +/- 0 on translation because we are changing it.. | ||
1063 | reducing floating point branches | ||
1064 | but it needs the floats in memory.. | ||
1065 | */ | ||
1066 | template <class T> | ||
1067 | inline bool CMatrix4<T>::isIdentity_integer_base() const | ||
1068 | { | ||
1069 | #if defined ( USE_MATRIX_TEST ) | ||
1070 | if (definitelyIdentityMatrix) | ||
1071 | return true; | ||
1072 | #endif | ||
1073 | if(IR(M[0])!=F32_VALUE_1) return false; | ||
1074 | if(IR(M[1])!=0) return false; | ||
1075 | if(IR(M[2])!=0) return false; | ||
1076 | if(IR(M[3])!=0) return false; | ||
1077 | |||
1078 | if(IR(M[4])!=0) return false; | ||
1079 | if(IR(M[5])!=F32_VALUE_1) return false; | ||
1080 | if(IR(M[6])!=0) return false; | ||
1081 | if(IR(M[7])!=0) return false; | ||
1082 | |||
1083 | if(IR(M[8])!=0) return false; | ||
1084 | if(IR(M[9])!=0) return false; | ||
1085 | if(IR(M[10])!=F32_VALUE_1) return false; | ||
1086 | if(IR(M[11])!=0) return false; | ||
1087 | |||
1088 | if(IR(M[12])!=0) return false; | ||
1089 | if(IR(M[13])!=0) return false; | ||
1090 | if(IR(M[13])!=0) return false; | ||
1091 | if(IR(M[15])!=F32_VALUE_1) return false; | ||
1092 | |||
1093 | #if defined ( USE_MATRIX_TEST ) | ||
1094 | definitelyIdentityMatrix=true; | ||
1095 | #endif | ||
1096 | return true; | ||
1097 | } | ||
1098 | |||
1099 | |||
1100 | template <class T> | ||
1101 | inline void CMatrix4<T>::rotateVect( vector3df& vect ) const | ||
1102 | { | ||
1103 | vector3df tmp = vect; | ||
1104 | vect.X = tmp.X*M[0] + tmp.Y*M[4] + tmp.Z*M[8]; | ||
1105 | vect.Y = tmp.X*M[1] + tmp.Y*M[5] + tmp.Z*M[9]; | ||
1106 | vect.Z = tmp.X*M[2] + tmp.Y*M[6] + tmp.Z*M[10]; | ||
1107 | } | ||
1108 | |||
1109 | //! An alternate transform vector method, writing into a second vector | ||
1110 | template <class T> | ||
1111 | inline void CMatrix4<T>::rotateVect(core::vector3df& out, const core::vector3df& in) const | ||
1112 | { | ||
1113 | out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8]; | ||
1114 | out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9]; | ||
1115 | out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10]; | ||
1116 | } | ||
1117 | |||
1118 | //! An alternate transform vector method, writing into an array of 3 floats | ||
1119 | template <class T> | ||
1120 | inline void CMatrix4<T>::rotateVect(T *out, const core::vector3df& in) const | ||
1121 | { | ||
1122 | out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8]; | ||
1123 | out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9]; | ||
1124 | out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10]; | ||
1125 | } | ||
1126 | |||
1127 | template <class T> | ||
1128 | inline void CMatrix4<T>::inverseRotateVect( vector3df& vect ) const | ||
1129 | { | ||
1130 | vector3df tmp = vect; | ||
1131 | vect.X = tmp.X*M[0] + tmp.Y*M[1] + tmp.Z*M[2]; | ||
1132 | vect.Y = tmp.X*M[4] + tmp.Y*M[5] + tmp.Z*M[6]; | ||
1133 | vect.Z = tmp.X*M[8] + tmp.Y*M[9] + tmp.Z*M[10]; | ||
1134 | } | ||
1135 | |||
1136 | template <class T> | ||
1137 | inline void CMatrix4<T>::transformVect( vector3df& vect) const | ||
1138 | { | ||
1139 | f32 vector[3]; | ||
1140 | |||
1141 | vector[0] = vect.X*M[0] + vect.Y*M[4] + vect.Z*M[8] + M[12]; | ||
1142 | vector[1] = vect.X*M[1] + vect.Y*M[5] + vect.Z*M[9] + M[13]; | ||
1143 | vector[2] = vect.X*M[2] + vect.Y*M[6] + vect.Z*M[10] + M[14]; | ||
1144 | |||
1145 | vect.X = vector[0]; | ||
1146 | vect.Y = vector[1]; | ||
1147 | vect.Z = vector[2]; | ||
1148 | } | ||
1149 | |||
1150 | template <class T> | ||
1151 | inline void CMatrix4<T>::transformVect( vector3df& out, const vector3df& in) const | ||
1152 | { | ||
1153 | out.X = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12]; | ||
1154 | out.Y = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13]; | ||
1155 | out.Z = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14]; | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | template <class T> | ||
1160 | inline void CMatrix4<T>::transformVect(T *out, const core::vector3df &in) const | ||
1161 | { | ||
1162 | out[0] = in.X*M[0] + in.Y*M[4] + in.Z*M[8] + M[12]; | ||
1163 | out[1] = in.X*M[1] + in.Y*M[5] + in.Z*M[9] + M[13]; | ||
1164 | out[2] = in.X*M[2] + in.Y*M[6] + in.Z*M[10] + M[14]; | ||
1165 | out[3] = in.X*M[3] + in.Y*M[7] + in.Z*M[11] + M[15]; | ||
1166 | } | ||
1167 | |||
1168 | template <class T> | ||
1169 | inline void CMatrix4<T>::transformVec3(T *out, const T * in) const | ||
1170 | { | ||
1171 | out[0] = in[0]*M[0] + in[1]*M[4] + in[2]*M[8] + M[12]; | ||
1172 | out[1] = in[0]*M[1] + in[1]*M[5] + in[2]*M[9] + M[13]; | ||
1173 | out[2] = in[0]*M[2] + in[1]*M[6] + in[2]*M[10] + M[14]; | ||
1174 | } | ||
1175 | |||
1176 | |||
1177 | //! Transforms a plane by this matrix | ||
1178 | template <class T> | ||
1179 | inline void CMatrix4<T>::transformPlane( core::plane3d<f32> &plane) const | ||
1180 | { | ||
1181 | vector3df member; | ||
1182 | // Transform the plane member point, i.e. rotate, translate and scale it. | ||
1183 | transformVect(member, plane.getMemberPoint()); | ||
1184 | |||
1185 | // Transform the normal by the transposed inverse of the matrix | ||
1186 | CMatrix4<T> transposedInverse(*this, EM4CONST_INVERSE_TRANSPOSED); | ||
1187 | vector3df normal = plane.Normal; | ||
1188 | transposedInverse.transformVect(normal); | ||
1189 | |||
1190 | plane.setPlane(member, normal); | ||
1191 | } | ||
1192 | |||
1193 | //! Transforms a plane by this matrix | ||
1194 | template <class T> | ||
1195 | inline void CMatrix4<T>::transformPlane( const core::plane3d<f32> &in, core::plane3d<f32> &out) const | ||
1196 | { | ||
1197 | out = in; | ||
1198 | transformPlane( out ); | ||
1199 | } | ||
1200 | |||
1201 | //! Transforms a axis aligned bounding box | ||
1202 | template <class T> | ||
1203 | inline void CMatrix4<T>::transformBox(core::aabbox3d<f32>& box) const | ||
1204 | { | ||
1205 | #if defined ( USE_MATRIX_TEST ) | ||
1206 | if (isIdentity()) | ||
1207 | return; | ||
1208 | #endif | ||
1209 | |||
1210 | transformVect(box.MinEdge); | ||
1211 | transformVect(box.MaxEdge); | ||
1212 | box.repair(); | ||
1213 | } | ||
1214 | |||
1215 | //! Transforms a axis aligned bounding box more accurately than transformBox() | ||
1216 | template <class T> | ||
1217 | inline void CMatrix4<T>::transformBoxEx(core::aabbox3d<f32>& box) const | ||
1218 | { | ||
1219 | #if defined ( USE_MATRIX_TEST ) | ||
1220 | if (isIdentity()) | ||
1221 | return; | ||
1222 | #endif | ||
1223 | |||
1224 | const f32 Amin[3] = {box.MinEdge.X, box.MinEdge.Y, box.MinEdge.Z}; | ||
1225 | const f32 Amax[3] = {box.MaxEdge.X, box.MaxEdge.Y, box.MaxEdge.Z}; | ||
1226 | |||
1227 | f32 Bmin[3]; | ||
1228 | f32 Bmax[3]; | ||
1229 | |||
1230 | Bmin[0] = Bmax[0] = M[12]; | ||
1231 | Bmin[1] = Bmax[1] = M[13]; | ||
1232 | Bmin[2] = Bmax[2] = M[14]; | ||
1233 | |||
1234 | const CMatrix4<T> &m = *this; | ||
1235 | |||
1236 | for (u32 i = 0; i < 3; ++i) | ||
1237 | { | ||
1238 | for (u32 j = 0; j < 3; ++j) | ||
1239 | { | ||
1240 | const f32 a = m(j,i) * Amin[j]; | ||
1241 | const f32 b = m(j,i) * Amax[j]; | ||
1242 | |||
1243 | if (a < b) | ||
1244 | { | ||
1245 | Bmin[i] += a; | ||
1246 | Bmax[i] += b; | ||
1247 | } | ||
1248 | else | ||
1249 | { | ||
1250 | Bmin[i] += b; | ||
1251 | Bmax[i] += a; | ||
1252 | } | ||
1253 | } | ||
1254 | } | ||
1255 | |||
1256 | box.MinEdge.X = Bmin[0]; | ||
1257 | box.MinEdge.Y = Bmin[1]; | ||
1258 | box.MinEdge.Z = Bmin[2]; | ||
1259 | |||
1260 | box.MaxEdge.X = Bmax[0]; | ||
1261 | box.MaxEdge.Y = Bmax[1]; | ||
1262 | box.MaxEdge.Z = Bmax[2]; | ||
1263 | } | ||
1264 | |||
1265 | |||
1266 | //! Multiplies this matrix by a 1x4 matrix | ||
1267 | template <class T> | ||
1268 | inline void CMatrix4<T>::multiplyWith1x4Matrix(T* matrix) const | ||
1269 | { | ||
1270 | /* | ||
1271 | 0 1 2 3 | ||
1272 | 4 5 6 7 | ||
1273 | 8 9 10 11 | ||
1274 | 12 13 14 15 | ||
1275 | */ | ||
1276 | |||
1277 | T mat[4]; | ||
1278 | mat[0] = matrix[0]; | ||
1279 | mat[1] = matrix[1]; | ||
1280 | mat[2] = matrix[2]; | ||
1281 | mat[3] = matrix[3]; | ||
1282 | |||
1283 | matrix[0] = M[0]*mat[0] + M[4]*mat[1] + M[8]*mat[2] + M[12]*mat[3]; | ||
1284 | matrix[1] = M[1]*mat[0] + M[5]*mat[1] + M[9]*mat[2] + M[13]*mat[3]; | ||
1285 | matrix[2] = M[2]*mat[0] + M[6]*mat[1] + M[10]*mat[2] + M[14]*mat[3]; | ||
1286 | matrix[3] = M[3]*mat[0] + M[7]*mat[1] + M[11]*mat[2] + M[15]*mat[3]; | ||
1287 | } | ||
1288 | |||
1289 | template <class T> | ||
1290 | inline void CMatrix4<T>::inverseTranslateVect( vector3df& vect ) const | ||
1291 | { | ||
1292 | vect.X = vect.X-M[12]; | ||
1293 | vect.Y = vect.Y-M[13]; | ||
1294 | vect.Z = vect.Z-M[14]; | ||
1295 | } | ||
1296 | |||
1297 | template <class T> | ||
1298 | inline void CMatrix4<T>::translateVect( vector3df& vect ) const | ||
1299 | { | ||
1300 | vect.X = vect.X+M[12]; | ||
1301 | vect.Y = vect.Y+M[13]; | ||
1302 | vect.Z = vect.Z+M[14]; | ||
1303 | } | ||
1304 | |||
1305 | |||
1306 | template <class T> | ||
1307 | inline bool CMatrix4<T>::getInverse(CMatrix4<T>& out) const | ||
1308 | { | ||
1309 | /// Calculates the inverse of this Matrix | ||
1310 | /// The inverse is calculated using Cramers rule. | ||
1311 | /// If no inverse exists then 'false' is returned. | ||
1312 | |||
1313 | #if defined ( USE_MATRIX_TEST ) | ||
1314 | if ( this->isIdentity() ) | ||
1315 | { | ||
1316 | out=*this; | ||
1317 | return true; | ||
1318 | } | ||
1319 | #endif | ||
1320 | const CMatrix4<T> &m = *this; | ||
1321 | |||
1322 | f32 d = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) - | ||
1323 | (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) + | ||
1324 | (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)) + | ||
1325 | (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) - | ||
1326 | (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) + | ||
1327 | (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)); | ||
1328 | |||
1329 | if( core::iszero ( d, FLT_MIN ) ) | ||
1330 | return false; | ||
1331 | |||
1332 | d = core::reciprocal ( d ); | ||
1333 | |||
1334 | out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) + | ||
1335 | m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) + | ||
1336 | m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1))); | ||
1337 | out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) + | ||
1338 | m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) + | ||
1339 | m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1))); | ||
1340 | out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) + | ||
1341 | m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) + | ||
1342 | m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1))); | ||
1343 | out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) + | ||
1344 | m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) + | ||
1345 | m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2))); | ||
1346 | out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) + | ||
1347 | m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) + | ||
1348 | m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3))); | ||
1349 | out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) + | ||
1350 | m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) + | ||
1351 | m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3))); | ||
1352 | out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) + | ||
1353 | m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) + | ||
1354 | m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3))); | ||
1355 | out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) + | ||
1356 | m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) + | ||
1357 | m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2))); | ||
1358 | out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) + | ||
1359 | m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) + | ||
1360 | m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3))); | ||
1361 | out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) + | ||
1362 | m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) + | ||
1363 | m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3))); | ||
1364 | out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) + | ||
1365 | m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) + | ||
1366 | m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3))); | ||
1367 | out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) + | ||
1368 | m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) + | ||
1369 | m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0))); | ||
1370 | out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) + | ||
1371 | m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) + | ||
1372 | m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1))); | ||
1373 | out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) + | ||
1374 | m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) + | ||
1375 | m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1))); | ||
1376 | out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) + | ||
1377 | m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) + | ||
1378 | m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1))); | ||
1379 | out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) + | ||
1380 | m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) + | ||
1381 | m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))); | ||
1382 | |||
1383 | #if defined ( USE_MATRIX_TEST ) | ||
1384 | out.definitelyIdentityMatrix = definitelyIdentityMatrix; | ||
1385 | #endif | ||
1386 | return true; | ||
1387 | } | ||
1388 | |||
1389 | |||
1390 | //! Inverts a primitive matrix which only contains a translation and a rotation | ||
1391 | //! \param out: where result matrix is written to. | ||
1392 | template <class T> | ||
1393 | inline bool CMatrix4<T>::getInversePrimitive ( CMatrix4<T>& out ) const | ||
1394 | { | ||
1395 | out.M[0 ] = M[0]; | ||
1396 | out.M[1 ] = M[4]; | ||
1397 | out.M[2 ] = M[8]; | ||
1398 | out.M[3 ] = 0; | ||
1399 | |||
1400 | out.M[4 ] = M[1]; | ||
1401 | out.M[5 ] = M[5]; | ||
1402 | out.M[6 ] = M[9]; | ||
1403 | out.M[7 ] = 0; | ||
1404 | |||
1405 | out.M[8 ] = M[2]; | ||
1406 | out.M[9 ] = M[6]; | ||
1407 | out.M[10] = M[10]; | ||
1408 | out.M[11] = 0; | ||
1409 | |||
1410 | out.M[12] = (T)-(M[12]*M[0] + M[13]*M[1] + M[14]*M[2]); | ||
1411 | out.M[13] = (T)-(M[12]*M[4] + M[13]*M[5] + M[14]*M[6]); | ||
1412 | out.M[14] = (T)-(M[12]*M[8] + M[13]*M[9] + M[14]*M[10]); | ||
1413 | out.M[15] = 1; | ||
1414 | |||
1415 | #if defined ( USE_MATRIX_TEST ) | ||
1416 | out.definitelyIdentityMatrix = definitelyIdentityMatrix; | ||
1417 | #endif | ||
1418 | return true; | ||
1419 | } | ||
1420 | |||
1421 | /*! | ||
1422 | */ | ||
1423 | template <class T> | ||
1424 | inline bool CMatrix4<T>::makeInverse() | ||
1425 | { | ||
1426 | #if defined ( USE_MATRIX_TEST ) | ||
1427 | if (definitelyIdentityMatrix) | ||
1428 | return true; | ||
1429 | #endif | ||
1430 | CMatrix4<T> temp ( EM4CONST_NOTHING ); | ||
1431 | |||
1432 | if (getInverse(temp)) | ||
1433 | { | ||
1434 | *this = temp; | ||
1435 | return true; | ||
1436 | } | ||
1437 | |||
1438 | return false; | ||
1439 | } | ||
1440 | |||
1441 | |||
1442 | template <class T> | ||
1443 | inline CMatrix4<T>& CMatrix4<T>::operator=(const CMatrix4<T> &other) | ||
1444 | { | ||
1445 | if (this==&other) | ||
1446 | return *this; | ||
1447 | memcpy(M, other.M, 16*sizeof(T)); | ||
1448 | #if defined ( USE_MATRIX_TEST ) | ||
1449 | definitelyIdentityMatrix=other.definitelyIdentityMatrix; | ||
1450 | #endif | ||
1451 | return *this; | ||
1452 | } | ||
1453 | |||
1454 | |||
1455 | template <class T> | ||
1456 | inline CMatrix4<T>& CMatrix4<T>::operator=(const T& scalar) | ||
1457 | { | ||
1458 | for (s32 i = 0; i < 16; ++i) | ||
1459 | M[i]=scalar; | ||
1460 | |||
1461 | #if defined ( USE_MATRIX_TEST ) | ||
1462 | definitelyIdentityMatrix=false; | ||
1463 | #endif | ||
1464 | return *this; | ||
1465 | } | ||
1466 | |||
1467 | |||
1468 | template <class T> | ||
1469 | inline bool CMatrix4<T>::operator==(const CMatrix4<T> &other) const | ||
1470 | { | ||
1471 | #if defined ( USE_MATRIX_TEST ) | ||
1472 | if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) | ||
1473 | return true; | ||
1474 | #endif | ||
1475 | for (s32 i = 0; i < 16; ++i) | ||
1476 | if (M[i] != other.M[i]) | ||
1477 | return false; | ||
1478 | |||
1479 | return true; | ||
1480 | } | ||
1481 | |||
1482 | |||
1483 | template <class T> | ||
1484 | inline bool CMatrix4<T>::operator!=(const CMatrix4<T> &other) const | ||
1485 | { | ||
1486 | return !(*this == other); | ||
1487 | } | ||
1488 | |||
1489 | |||
1490 | // Builds a right-handed perspective projection matrix based on a field of view | ||
1491 | template <class T> | ||
1492 | inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovRH( | ||
1493 | f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar) | ||
1494 | { | ||
1495 | const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); | ||
1496 | _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero | ||
1497 | const T w = static_cast<T>(h / aspectRatio); | ||
1498 | |||
1499 | _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero | ||
1500 | M[0] = w; | ||
1501 | M[1] = 0; | ||
1502 | M[2] = 0; | ||
1503 | M[3] = 0; | ||
1504 | |||
1505 | M[4] = 0; | ||
1506 | M[5] = (T)h; | ||
1507 | M[6] = 0; | ||
1508 | M[7] = 0; | ||
1509 | |||
1510 | M[8] = 0; | ||
1511 | M[9] = 0; | ||
1512 | M[10] = (T)(zFar/(zNear-zFar)); // DirectX version | ||
1513 | // M[10] = (T)(zFar+zNear/(zNear-zFar)); // OpenGL version | ||
1514 | M[11] = -1; | ||
1515 | |||
1516 | M[12] = 0; | ||
1517 | M[13] = 0; | ||
1518 | M[14] = (T)(zNear*zFar/(zNear-zFar)); // DirectX version | ||
1519 | // M[14] = (T)(2.0f*zNear*zFar/(zNear-zFar)); // OpenGL version | ||
1520 | M[15] = 0; | ||
1521 | |||
1522 | #if defined ( USE_MATRIX_TEST ) | ||
1523 | definitelyIdentityMatrix=false; | ||
1524 | #endif | ||
1525 | return *this; | ||
1526 | } | ||
1527 | |||
1528 | |||
1529 | // Builds a left-handed perspective projection matrix based on a field of view | ||
1530 | template <class T> | ||
1531 | inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovLH( | ||
1532 | f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 zFar) | ||
1533 | { | ||
1534 | const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); | ||
1535 | _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero | ||
1536 | const T w = static_cast<T>(h / aspectRatio); | ||
1537 | |||
1538 | _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero | ||
1539 | M[0] = w; | ||
1540 | M[1] = 0; | ||
1541 | M[2] = 0; | ||
1542 | M[3] = 0; | ||
1543 | |||
1544 | M[4] = 0; | ||
1545 | M[5] = (T)h; | ||
1546 | M[6] = 0; | ||
1547 | M[7] = 0; | ||
1548 | |||
1549 | M[8] = 0; | ||
1550 | M[9] = 0; | ||
1551 | M[10] = (T)(zFar/(zFar-zNear)); | ||
1552 | M[11] = 1; | ||
1553 | |||
1554 | M[12] = 0; | ||
1555 | M[13] = 0; | ||
1556 | M[14] = (T)(-zNear*zFar/(zFar-zNear)); | ||
1557 | M[15] = 0; | ||
1558 | |||
1559 | #if defined ( USE_MATRIX_TEST ) | ||
1560 | definitelyIdentityMatrix=false; | ||
1561 | #endif | ||
1562 | return *this; | ||
1563 | } | ||
1564 | |||
1565 | |||
1566 | // Builds a left-handed perspective projection matrix based on a field of view, with far plane culling at infinity | ||
1567 | template <class T> | ||
1568 | inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveFovInfinityLH( | ||
1569 | f32 fieldOfViewRadians, f32 aspectRatio, f32 zNear, f32 epsilon) | ||
1570 | { | ||
1571 | const f64 h = reciprocal(tan(fieldOfViewRadians*0.5)); | ||
1572 | _IRR_DEBUG_BREAK_IF(aspectRatio==0.f); //divide by zero | ||
1573 | const T w = static_cast<T>(h / aspectRatio); | ||
1574 | |||
1575 | M[0] = w; | ||
1576 | M[1] = 0; | ||
1577 | M[2] = 0; | ||
1578 | M[3] = 0; | ||
1579 | |||
1580 | M[4] = 0; | ||
1581 | M[5] = (T)h; | ||
1582 | M[6] = 0; | ||
1583 | M[7] = 0; | ||
1584 | |||
1585 | M[8] = 0; | ||
1586 | M[9] = 0; | ||
1587 | M[10] = (T)(1.f-epsilon); | ||
1588 | M[11] = 1; | ||
1589 | |||
1590 | M[12] = 0; | ||
1591 | M[13] = 0; | ||
1592 | M[14] = (T)(zNear*(epsilon-1.f)); | ||
1593 | M[15] = 0; | ||
1594 | |||
1595 | #if defined ( USE_MATRIX_TEST ) | ||
1596 | definitelyIdentityMatrix=false; | ||
1597 | #endif | ||
1598 | return *this; | ||
1599 | } | ||
1600 | |||
1601 | |||
1602 | // Builds a left-handed orthogonal projection matrix. | ||
1603 | template <class T> | ||
1604 | inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoLH( | ||
1605 | f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) | ||
1606 | { | ||
1607 | _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero | ||
1608 | _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero | ||
1609 | _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero | ||
1610 | M[0] = (T)(2/widthOfViewVolume); | ||
1611 | M[1] = 0; | ||
1612 | M[2] = 0; | ||
1613 | M[3] = 0; | ||
1614 | |||
1615 | M[4] = 0; | ||
1616 | M[5] = (T)(2/heightOfViewVolume); | ||
1617 | M[6] = 0; | ||
1618 | M[7] = 0; | ||
1619 | |||
1620 | M[8] = 0; | ||
1621 | M[9] = 0; | ||
1622 | M[10] = (T)(1/(zFar-zNear)); | ||
1623 | M[11] = 0; | ||
1624 | |||
1625 | M[12] = 0; | ||
1626 | M[13] = 0; | ||
1627 | M[14] = (T)(zNear/(zNear-zFar)); | ||
1628 | M[15] = 1; | ||
1629 | |||
1630 | #if defined ( USE_MATRIX_TEST ) | ||
1631 | definitelyIdentityMatrix=false; | ||
1632 | #endif | ||
1633 | return *this; | ||
1634 | } | ||
1635 | |||
1636 | |||
1637 | // Builds a right-handed orthogonal projection matrix. | ||
1638 | template <class T> | ||
1639 | inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixOrthoRH( | ||
1640 | f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) | ||
1641 | { | ||
1642 | _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero | ||
1643 | _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero | ||
1644 | _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero | ||
1645 | M[0] = (T)(2/widthOfViewVolume); | ||
1646 | M[1] = 0; | ||
1647 | M[2] = 0; | ||
1648 | M[3] = 0; | ||
1649 | |||
1650 | M[4] = 0; | ||
1651 | M[5] = (T)(2/heightOfViewVolume); | ||
1652 | M[6] = 0; | ||
1653 | M[7] = 0; | ||
1654 | |||
1655 | M[8] = 0; | ||
1656 | M[9] = 0; | ||
1657 | M[10] = (T)(1/(zNear-zFar)); | ||
1658 | M[11] = 0; | ||
1659 | |||
1660 | M[12] = 0; | ||
1661 | M[13] = 0; | ||
1662 | M[14] = (T)(zNear/(zNear-zFar)); | ||
1663 | M[15] = 1; | ||
1664 | |||
1665 | #if defined ( USE_MATRIX_TEST ) | ||
1666 | definitelyIdentityMatrix=false; | ||
1667 | #endif | ||
1668 | return *this; | ||
1669 | } | ||
1670 | |||
1671 | |||
1672 | // Builds a right-handed perspective projection matrix. | ||
1673 | template <class T> | ||
1674 | inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveRH( | ||
1675 | f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) | ||
1676 | { | ||
1677 | _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero | ||
1678 | _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero | ||
1679 | _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero | ||
1680 | M[0] = (T)(2*zNear/widthOfViewVolume); | ||
1681 | M[1] = 0; | ||
1682 | M[2] = 0; | ||
1683 | M[3] = 0; | ||
1684 | |||
1685 | M[4] = 0; | ||
1686 | M[5] = (T)(2*zNear/heightOfViewVolume); | ||
1687 | M[6] = 0; | ||
1688 | M[7] = 0; | ||
1689 | |||
1690 | M[8] = 0; | ||
1691 | M[9] = 0; | ||
1692 | M[10] = (T)(zFar/(zNear-zFar)); | ||
1693 | M[11] = -1; | ||
1694 | |||
1695 | M[12] = 0; | ||
1696 | M[13] = 0; | ||
1697 | M[14] = (T)(zNear*zFar/(zNear-zFar)); | ||
1698 | M[15] = 0; | ||
1699 | |||
1700 | #if defined ( USE_MATRIX_TEST ) | ||
1701 | definitelyIdentityMatrix=false; | ||
1702 | #endif | ||
1703 | return *this; | ||
1704 | } | ||
1705 | |||
1706 | |||
1707 | // Builds a left-handed perspective projection matrix. | ||
1708 | template <class T> | ||
1709 | inline CMatrix4<T>& CMatrix4<T>::buildProjectionMatrixPerspectiveLH( | ||
1710 | f32 widthOfViewVolume, f32 heightOfViewVolume, f32 zNear, f32 zFar) | ||
1711 | { | ||
1712 | _IRR_DEBUG_BREAK_IF(widthOfViewVolume==0.f); //divide by zero | ||
1713 | _IRR_DEBUG_BREAK_IF(heightOfViewVolume==0.f); //divide by zero | ||
1714 | _IRR_DEBUG_BREAK_IF(zNear==zFar); //divide by zero | ||
1715 | M[0] = (T)(2*zNear/widthOfViewVolume); | ||
1716 | M[1] = 0; | ||
1717 | M[2] = 0; | ||
1718 | M[3] = 0; | ||
1719 | |||
1720 | M[4] = 0; | ||
1721 | M[5] = (T)(2*zNear/heightOfViewVolume); | ||
1722 | M[6] = 0; | ||
1723 | M[7] = 0; | ||
1724 | |||
1725 | M[8] = 0; | ||
1726 | M[9] = 0; | ||
1727 | M[10] = (T)(zFar/(zFar-zNear)); | ||
1728 | M[11] = 1; | ||
1729 | |||
1730 | M[12] = 0; | ||
1731 | M[13] = 0; | ||
1732 | M[14] = (T)(zNear*zFar/(zNear-zFar)); | ||
1733 | M[15] = 0; | ||
1734 | #if defined ( USE_MATRIX_TEST ) | ||
1735 | definitelyIdentityMatrix=false; | ||
1736 | #endif | ||
1737 | return *this; | ||
1738 | } | ||
1739 | |||
1740 | |||
1741 | // Builds a matrix that flattens geometry into a plane. | ||
1742 | template <class T> | ||
1743 | inline CMatrix4<T>& CMatrix4<T>::buildShadowMatrix(const core::vector3df& light, core::plane3df plane, f32 point) | ||
1744 | { | ||
1745 | plane.Normal.normalize(); | ||
1746 | const f32 d = plane.Normal.dotProduct(light); | ||
1747 | |||
1748 | M[ 0] = (T)(-plane.Normal.X * light.X + d); | ||
1749 | M[ 1] = (T)(-plane.Normal.X * light.Y); | ||
1750 | M[ 2] = (T)(-plane.Normal.X * light.Z); | ||
1751 | M[ 3] = (T)(-plane.Normal.X * point); | ||
1752 | |||
1753 | M[ 4] = (T)(-plane.Normal.Y * light.X); | ||
1754 | M[ 5] = (T)(-plane.Normal.Y * light.Y + d); | ||
1755 | M[ 6] = (T)(-plane.Normal.Y * light.Z); | ||
1756 | M[ 7] = (T)(-plane.Normal.Y * point); | ||
1757 | |||
1758 | M[ 8] = (T)(-plane.Normal.Z * light.X); | ||
1759 | M[ 9] = (T)(-plane.Normal.Z * light.Y); | ||
1760 | M[10] = (T)(-plane.Normal.Z * light.Z + d); | ||
1761 | M[11] = (T)(-plane.Normal.Z * point); | ||
1762 | |||
1763 | M[12] = (T)(-plane.D * light.X); | ||
1764 | M[13] = (T)(-plane.D * light.Y); | ||
1765 | M[14] = (T)(-plane.D * light.Z); | ||
1766 | M[15] = (T)(-plane.D * point + d); | ||
1767 | #if defined ( USE_MATRIX_TEST ) | ||
1768 | definitelyIdentityMatrix=false; | ||
1769 | #endif | ||
1770 | return *this; | ||
1771 | } | ||
1772 | |||
1773 | // Builds a left-handed look-at matrix. | ||
1774 | template <class T> | ||
1775 | inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixLH( | ||
1776 | const vector3df& position, | ||
1777 | const vector3df& target, | ||
1778 | const vector3df& upVector) | ||
1779 | { | ||
1780 | vector3df zaxis = target - position; | ||
1781 | zaxis.normalize(); | ||
1782 | |||
1783 | vector3df xaxis = upVector.crossProduct(zaxis); | ||
1784 | xaxis.normalize(); | ||
1785 | |||
1786 | vector3df yaxis = zaxis.crossProduct(xaxis); | ||
1787 | |||
1788 | M[0] = (T)xaxis.X; | ||
1789 | M[1] = (T)yaxis.X; | ||
1790 | M[2] = (T)zaxis.X; | ||
1791 | M[3] = 0; | ||
1792 | |||
1793 | M[4] = (T)xaxis.Y; | ||
1794 | M[5] = (T)yaxis.Y; | ||
1795 | M[6] = (T)zaxis.Y; | ||
1796 | M[7] = 0; | ||
1797 | |||
1798 | M[8] = (T)xaxis.Z; | ||
1799 | M[9] = (T)yaxis.Z; | ||
1800 | M[10] = (T)zaxis.Z; | ||
1801 | M[11] = 0; | ||
1802 | |||
1803 | M[12] = (T)-xaxis.dotProduct(position); | ||
1804 | M[13] = (T)-yaxis.dotProduct(position); | ||
1805 | M[14] = (T)-zaxis.dotProduct(position); | ||
1806 | M[15] = 1; | ||
1807 | #if defined ( USE_MATRIX_TEST ) | ||
1808 | definitelyIdentityMatrix=false; | ||
1809 | #endif | ||
1810 | return *this; | ||
1811 | } | ||
1812 | |||
1813 | |||
1814 | // Builds a right-handed look-at matrix. | ||
1815 | template <class T> | ||
1816 | inline CMatrix4<T>& CMatrix4<T>::buildCameraLookAtMatrixRH( | ||
1817 | const vector3df& position, | ||
1818 | const vector3df& target, | ||
1819 | const vector3df& upVector) | ||
1820 | { | ||
1821 | vector3df zaxis = position - target; | ||
1822 | zaxis.normalize(); | ||
1823 | |||
1824 | vector3df xaxis = upVector.crossProduct(zaxis); | ||
1825 | xaxis.normalize(); | ||
1826 | |||
1827 | vector3df yaxis = zaxis.crossProduct(xaxis); | ||
1828 | |||
1829 | M[0] = (T)xaxis.X; | ||
1830 | M[1] = (T)yaxis.X; | ||
1831 | M[2] = (T)zaxis.X; | ||
1832 | M[3] = 0; | ||
1833 | |||
1834 | M[4] = (T)xaxis.Y; | ||
1835 | M[5] = (T)yaxis.Y; | ||
1836 | M[6] = (T)zaxis.Y; | ||
1837 | M[7] = 0; | ||
1838 | |||
1839 | M[8] = (T)xaxis.Z; | ||
1840 | M[9] = (T)yaxis.Z; | ||
1841 | M[10] = (T)zaxis.Z; | ||
1842 | M[11] = 0; | ||
1843 | |||
1844 | M[12] = (T)-xaxis.dotProduct(position); | ||
1845 | M[13] = (T)-yaxis.dotProduct(position); | ||
1846 | M[14] = (T)-zaxis.dotProduct(position); | ||
1847 | M[15] = 1; | ||
1848 | #if defined ( USE_MATRIX_TEST ) | ||
1849 | definitelyIdentityMatrix=false; | ||
1850 | #endif | ||
1851 | return *this; | ||
1852 | } | ||
1853 | |||
1854 | |||
1855 | // creates a new matrix as interpolated matrix from this and the passed one. | ||
1856 | template <class T> | ||
1857 | inline CMatrix4<T> CMatrix4<T>::interpolate(const core::CMatrix4<T>& b, f32 time) const | ||
1858 | { | ||
1859 | CMatrix4<T> mat ( EM4CONST_NOTHING ); | ||
1860 | |||
1861 | for (u32 i=0; i < 16; i += 4) | ||
1862 | { | ||
1863 | mat.M[i+0] = (T)(M[i+0] + ( b.M[i+0] - M[i+0] ) * time); | ||
1864 | mat.M[i+1] = (T)(M[i+1] + ( b.M[i+1] - M[i+1] ) * time); | ||
1865 | mat.M[i+2] = (T)(M[i+2] + ( b.M[i+2] - M[i+2] ) * time); | ||
1866 | mat.M[i+3] = (T)(M[i+3] + ( b.M[i+3] - M[i+3] ) * time); | ||
1867 | } | ||
1868 | return mat; | ||
1869 | } | ||
1870 | |||
1871 | |||
1872 | // returns transposed matrix | ||
1873 | template <class T> | ||
1874 | inline CMatrix4<T> CMatrix4<T>::getTransposed() const | ||
1875 | { | ||
1876 | CMatrix4<T> t ( EM4CONST_NOTHING ); | ||
1877 | getTransposed ( t ); | ||
1878 | return t; | ||
1879 | } | ||
1880 | |||
1881 | |||
1882 | // returns transposed matrix | ||
1883 | template <class T> | ||
1884 | inline void CMatrix4<T>::getTransposed( CMatrix4<T>& o ) const | ||
1885 | { | ||
1886 | o[ 0] = M[ 0]; | ||
1887 | o[ 1] = M[ 4]; | ||
1888 | o[ 2] = M[ 8]; | ||
1889 | o[ 3] = M[12]; | ||
1890 | |||
1891 | o[ 4] = M[ 1]; | ||
1892 | o[ 5] = M[ 5]; | ||
1893 | o[ 6] = M[ 9]; | ||
1894 | o[ 7] = M[13]; | ||
1895 | |||
1896 | o[ 8] = M[ 2]; | ||
1897 | o[ 9] = M[ 6]; | ||
1898 | o[10] = M[10]; | ||
1899 | o[11] = M[14]; | ||
1900 | |||
1901 | o[12] = M[ 3]; | ||
1902 | o[13] = M[ 7]; | ||
1903 | o[14] = M[11]; | ||
1904 | o[15] = M[15]; | ||
1905 | #if defined ( USE_MATRIX_TEST ) | ||
1906 | o.definitelyIdentityMatrix=definitelyIdentityMatrix; | ||
1907 | #endif | ||
1908 | } | ||
1909 | |||
1910 | |||
1911 | // used to scale <-1,-1><1,1> to viewport | ||
1912 | template <class T> | ||
1913 | inline CMatrix4<T>& CMatrix4<T>::buildNDCToDCMatrix( const core::rect<s32>& viewport, f32 zScale) | ||
1914 | { | ||
1915 | const f32 scaleX = (viewport.getWidth() - 0.75f ) * 0.5f; | ||
1916 | const f32 scaleY = -(viewport.getHeight() - 0.75f ) * 0.5f; | ||
1917 | |||
1918 | const f32 dx = -0.5f + ( (viewport.UpperLeftCorner.X + viewport.LowerRightCorner.X ) * 0.5f ); | ||
1919 | const f32 dy = -0.5f + ( (viewport.UpperLeftCorner.Y + viewport.LowerRightCorner.Y ) * 0.5f ); | ||
1920 | |||
1921 | makeIdentity(); | ||
1922 | M[12] = (T)dx; | ||
1923 | M[13] = (T)dy; | ||
1924 | return setScale(core::vector3d<T>((T)scaleX, (T)scaleY, (T)zScale)); | ||
1925 | } | ||
1926 | |||
1927 | //! Builds a matrix that rotates from one vector to another | ||
1928 | /** \param from: vector to rotate from | ||
1929 | \param to: vector to rotate to | ||
1930 | |||
1931 | http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToMatrix/index.htm | ||
1932 | */ | ||
1933 | template <class T> | ||
1934 | inline CMatrix4<T>& CMatrix4<T>::buildRotateFromTo(const core::vector3df& from, const core::vector3df& to) | ||
1935 | { | ||
1936 | // unit vectors | ||
1937 | core::vector3df f(from); | ||
1938 | core::vector3df t(to); | ||
1939 | f.normalize(); | ||
1940 | t.normalize(); | ||
1941 | |||
1942 | // axis multiplication by sin | ||
1943 | core::vector3df vs(t.crossProduct(f)); | ||
1944 | |||
1945 | // axis of rotation | ||
1946 | core::vector3df v(vs); | ||
1947 | v.normalize(); | ||
1948 | |||
1949 | // cosinus angle | ||
1950 | T ca = f.dotProduct(t); | ||
1951 | |||
1952 | core::vector3df vt(v * (1 - ca)); | ||
1953 | |||
1954 | M[0] = vt.X * v.X + ca; | ||
1955 | M[5] = vt.Y * v.Y + ca; | ||
1956 | M[10] = vt.Z * v.Z + ca; | ||
1957 | |||
1958 | vt.X *= v.Y; | ||
1959 | vt.Z *= v.X; | ||
1960 | vt.Y *= v.Z; | ||
1961 | |||
1962 | M[1] = vt.X - vs.Z; | ||
1963 | M[2] = vt.Z + vs.Y; | ||
1964 | M[3] = 0; | ||
1965 | |||
1966 | M[4] = vt.X + vs.Z; | ||
1967 | M[6] = vt.Y - vs.X; | ||
1968 | M[7] = 0; | ||
1969 | |||
1970 | M[8] = vt.Z - vs.Y; | ||
1971 | M[9] = vt.Y + vs.X; | ||
1972 | M[11] = 0; | ||
1973 | |||
1974 | M[12] = 0; | ||
1975 | M[13] = 0; | ||
1976 | M[14] = 0; | ||
1977 | M[15] = 1; | ||
1978 | |||
1979 | return *this; | ||
1980 | } | ||
1981 | |||
1982 | //! Builds a matrix which rotates a source vector to a look vector over an arbitrary axis | ||
1983 | /** \param camPos: viewer position in world coord | ||
1984 | \param center: object position in world-coord, rotation pivot | ||
1985 | \param translation: object final translation from center | ||
1986 | \param axis: axis to rotate about | ||
1987 | \param from: source vector to rotate from | ||
1988 | */ | ||
1989 | template <class T> | ||
1990 | inline void CMatrix4<T>::buildAxisAlignedBillboard( | ||
1991 | const core::vector3df& camPos, | ||
1992 | const core::vector3df& center, | ||
1993 | const core::vector3df& translation, | ||
1994 | const core::vector3df& axis, | ||
1995 | const core::vector3df& from) | ||
1996 | { | ||
1997 | // axis of rotation | ||
1998 | core::vector3df up = axis; | ||
1999 | up.normalize(); | ||
2000 | const core::vector3df forward = (camPos - center).normalize(); | ||
2001 | const core::vector3df right = up.crossProduct(forward).normalize(); | ||
2002 | |||
2003 | // correct look vector | ||
2004 | const core::vector3df look = right.crossProduct(up); | ||
2005 | |||
2006 | // rotate from to | ||
2007 | // axis multiplication by sin | ||
2008 | const core::vector3df vs = look.crossProduct(from); | ||
2009 | |||
2010 | // cosinus angle | ||
2011 | const f32 ca = from.dotProduct(look); | ||
2012 | |||
2013 | core::vector3df vt(up * (1.f - ca)); | ||
2014 | |||
2015 | M[0] = static_cast<T>(vt.X * up.X + ca); | ||
2016 | M[5] = static_cast<T>(vt.Y * up.Y + ca); | ||
2017 | M[10] = static_cast<T>(vt.Z * up.Z + ca); | ||
2018 | |||
2019 | vt.X *= up.Y; | ||
2020 | vt.Z *= up.X; | ||
2021 | vt.Y *= up.Z; | ||
2022 | |||
2023 | M[1] = static_cast<T>(vt.X - vs.Z); | ||
2024 | M[2] = static_cast<T>(vt.Z + vs.Y); | ||
2025 | M[3] = 0; | ||
2026 | |||
2027 | M[4] = static_cast<T>(vt.X + vs.Z); | ||
2028 | M[6] = static_cast<T>(vt.Y - vs.X); | ||
2029 | M[7] = 0; | ||
2030 | |||
2031 | M[8] = static_cast<T>(vt.Z - vs.Y); | ||
2032 | M[9] = static_cast<T>(vt.Y + vs.X); | ||
2033 | M[11] = 0; | ||
2034 | |||
2035 | setRotationCenter(center, translation); | ||
2036 | } | ||
2037 | |||
2038 | |||
2039 | //! Builds a combined matrix which translate to a center before rotation and translate afterwards | ||
2040 | template <class T> | ||
2041 | inline void CMatrix4<T>::setRotationCenter(const core::vector3df& center, const core::vector3df& translation) | ||
2042 | { | ||
2043 | M[12] = -M[0]*center.X - M[4]*center.Y - M[8]*center.Z + (center.X - translation.X ); | ||
2044 | M[13] = -M[1]*center.X - M[5]*center.Y - M[9]*center.Z + (center.Y - translation.Y ); | ||
2045 | M[14] = -M[2]*center.X - M[6]*center.Y - M[10]*center.Z + (center.Z - translation.Z ); | ||
2046 | M[15] = (T) 1.0; | ||
2047 | #if defined ( USE_MATRIX_TEST ) | ||
2048 | definitelyIdentityMatrix=false; | ||
2049 | #endif | ||
2050 | } | ||
2051 | |||
2052 | /*! | ||
2053 | Generate texture coordinates as linear functions so that: | ||
2054 | u = Ux*x + Uy*y + Uz*z + Uw | ||
2055 | v = Vx*x + Vy*y + Vz*z + Vw | ||
2056 | The matrix M for this case is: | ||
2057 | Ux Vx 0 0 | ||
2058 | Uy Vy 0 0 | ||
2059 | Uz Vz 0 0 | ||
2060 | Uw Vw 0 0 | ||
2061 | */ | ||
2062 | |||
2063 | |||
2064 | template <class T> | ||
2065 | inline CMatrix4<T>& CMatrix4<T>::buildTextureTransform( f32 rotateRad, | ||
2066 | const core::vector2df &rotatecenter, | ||
2067 | const core::vector2df &translate, | ||
2068 | const core::vector2df &scale) | ||
2069 | { | ||
2070 | const f32 c = cosf(rotateRad); | ||
2071 | const f32 s = sinf(rotateRad); | ||
2072 | |||
2073 | M[0] = (T)(c * scale.X); | ||
2074 | M[1] = (T)(s * scale.Y); | ||
2075 | M[2] = 0; | ||
2076 | M[3] = 0; | ||
2077 | |||
2078 | M[4] = (T)(-s * scale.X); | ||
2079 | M[5] = (T)(c * scale.Y); | ||
2080 | M[6] = 0; | ||
2081 | M[7] = 0; | ||
2082 | |||
2083 | M[8] = (T)(c * scale.X * rotatecenter.X + -s * rotatecenter.Y + translate.X); | ||
2084 | M[9] = (T)(s * scale.Y * rotatecenter.X + c * rotatecenter.Y + translate.Y); | ||
2085 | M[10] = 1; | ||
2086 | M[11] = 0; | ||
2087 | |||
2088 | M[12] = 0; | ||
2089 | M[13] = 0; | ||
2090 | M[14] = 0; | ||
2091 | M[15] = 1; | ||
2092 | #if defined ( USE_MATRIX_TEST ) | ||
2093 | definitelyIdentityMatrix=false; | ||
2094 | #endif | ||
2095 | return *this; | ||
2096 | } | ||
2097 | |||
2098 | |||
2099 | // rotate about z axis, center ( 0.5, 0.5 ) | ||
2100 | template <class T> | ||
2101 | inline CMatrix4<T>& CMatrix4<T>::setTextureRotationCenter( f32 rotateRad ) | ||
2102 | { | ||
2103 | const f32 c = cosf(rotateRad); | ||
2104 | const f32 s = sinf(rotateRad); | ||
2105 | M[0] = (T)c; | ||
2106 | M[1] = (T)s; | ||
2107 | |||
2108 | M[4] = (T)-s; | ||
2109 | M[5] = (T)c; | ||
2110 | |||
2111 | M[8] = (T)(0.5f * ( s - c) + 0.5f); | ||
2112 | M[9] = (T)(-0.5f * ( s + c) + 0.5f); | ||
2113 | |||
2114 | #if defined ( USE_MATRIX_TEST ) | ||
2115 | definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad==0.0f); | ||
2116 | #endif | ||
2117 | return *this; | ||
2118 | } | ||
2119 | |||
2120 | |||
2121 | template <class T> | ||
2122 | inline CMatrix4<T>& CMatrix4<T>::setTextureTranslate ( f32 x, f32 y ) | ||
2123 | { | ||
2124 | M[8] = (T)x; | ||
2125 | M[9] = (T)y; | ||
2126 | |||
2127 | #if defined ( USE_MATRIX_TEST ) | ||
2128 | definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f); | ||
2129 | #endif | ||
2130 | return *this; | ||
2131 | } | ||
2132 | |||
2133 | |||
2134 | template <class T> | ||
2135 | inline CMatrix4<T>& CMatrix4<T>::setTextureTranslateTransposed ( f32 x, f32 y ) | ||
2136 | { | ||
2137 | M[2] = (T)x; | ||
2138 | M[6] = (T)y; | ||
2139 | |||
2140 | #if defined ( USE_MATRIX_TEST ) | ||
2141 | definitelyIdentityMatrix = definitelyIdentityMatrix && (x==0.0f) && (y==0.0f) ; | ||
2142 | #endif | ||
2143 | return *this; | ||
2144 | } | ||
2145 | |||
2146 | template <class T> | ||
2147 | inline CMatrix4<T>& CMatrix4<T>::setTextureScale ( f32 sx, f32 sy ) | ||
2148 | { | ||
2149 | M[0] = (T)sx; | ||
2150 | M[5] = (T)sy; | ||
2151 | #if defined ( USE_MATRIX_TEST ) | ||
2152 | definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f); | ||
2153 | #endif | ||
2154 | return *this; | ||
2155 | } | ||
2156 | |||
2157 | |||
2158 | template <class T> | ||
2159 | inline CMatrix4<T>& CMatrix4<T>::setTextureScaleCenter( f32 sx, f32 sy ) | ||
2160 | { | ||
2161 | M[0] = (T)sx; | ||
2162 | M[5] = (T)sy; | ||
2163 | M[8] = (T)(0.5f - 0.5f * sx); | ||
2164 | M[9] = (T)(0.5f - 0.5f * sy); | ||
2165 | |||
2166 | #if defined ( USE_MATRIX_TEST ) | ||
2167 | definitelyIdentityMatrix = definitelyIdentityMatrix && (sx==1.0f) && (sy==1.0f); | ||
2168 | #endif | ||
2169 | return *this; | ||
2170 | } | ||
2171 | |||
2172 | |||
2173 | // sets all matrix data members at once | ||
2174 | template <class T> | ||
2175 | inline CMatrix4<T>& CMatrix4<T>::setM(const T* data) | ||
2176 | { | ||
2177 | memcpy(M,data, 16*sizeof(T)); | ||
2178 | |||
2179 | #if defined ( USE_MATRIX_TEST ) | ||
2180 | definitelyIdentityMatrix=false; | ||
2181 | #endif | ||
2182 | return *this; | ||
2183 | } | ||
2184 | |||
2185 | |||
2186 | // sets if the matrix is definitely identity matrix | ||
2187 | template <class T> | ||
2188 | inline void CMatrix4<T>::setDefinitelyIdentityMatrix( bool isDefinitelyIdentityMatrix) | ||
2189 | { | ||
2190 | #if defined ( USE_MATRIX_TEST ) | ||
2191 | definitelyIdentityMatrix = isDefinitelyIdentityMatrix; | ||
2192 | #endif | ||
2193 | } | ||
2194 | |||
2195 | |||
2196 | // gets if the matrix is definitely identity matrix | ||
2197 | template <class T> | ||
2198 | inline bool CMatrix4<T>::getDefinitelyIdentityMatrix() const | ||
2199 | { | ||
2200 | #if defined ( USE_MATRIX_TEST ) | ||
2201 | return definitelyIdentityMatrix; | ||
2202 | #else | ||
2203 | return false; | ||
2204 | #endif | ||
2205 | } | ||
2206 | |||
2207 | |||
2208 | //! Compare two matrices using the equal method | ||
2209 | template <class T> | ||
2210 | inline bool CMatrix4<T>::equals(const core::CMatrix4<T>& other, const T tolerance) const | ||
2211 | { | ||
2212 | #if defined ( USE_MATRIX_TEST ) | ||
2213 | if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) | ||
2214 | return true; | ||
2215 | #endif | ||
2216 | for (s32 i = 0; i < 16; ++i) | ||
2217 | if (!core::equals(M[i],other.M[i], tolerance)) | ||
2218 | return false; | ||
2219 | |||
2220 | return true; | ||
2221 | } | ||
2222 | |||
2223 | |||
2224 | // Multiply by scalar. | ||
2225 | template <class T> | ||
2226 | inline CMatrix4<T> operator*(const T scalar, const CMatrix4<T>& mat) | ||
2227 | { | ||
2228 | return mat*scalar; | ||
2229 | } | ||
2230 | |||
2231 | |||
2232 | //! Typedef for f32 matrix | ||
2233 | typedef CMatrix4<f32> matrix4; | ||
2234 | |||
2235 | //! global const identity matrix | ||
2236 | IRRLICHT_API extern const matrix4 IdentityMatrix; | ||
2237 | |||
2238 | } // end namespace core | ||
2239 | } // end namespace irr | ||
2240 | |||
2241 | #endif | ||
2242 | |||