vrshoot

view libs/assimp/assimp/matrix4x4.inl @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
42 /** @file aiMatrix4x4t<TReal>.inl
43 * @brief Inline implementation of the 4x4 matrix operators
44 */
45 #ifndef AI_MATRIX4x4_INL_INC
46 #define AI_MATRIX4x4_INL_INC
48 #ifdef __cplusplus
50 #include "matrix4x4.h"
51 #include "matrix3x3.h"
52 #include "quaternion.h"
54 #include <algorithm>
55 #include <limits>
56 #include <math.h>
58 // ----------------------------------------------------------------------------------------
59 template <typename TReal>
60 aiMatrix4x4t<TReal> ::aiMatrix4x4t () :
61 a1(1.0f), a2(), a3(), a4(),
62 b1(), b2(1.0f), b3(), b4(),
63 c1(), c2(), c3(1.0f), c4(),
64 d1(), d2(), d3(), d4(1.0f)
65 {
67 }
69 // ----------------------------------------------------------------------------------------
70 template <typename TReal>
71 aiMatrix4x4t<TReal> ::aiMatrix4x4t (TReal _a1, TReal _a2, TReal _a3, TReal _a4,
72 TReal _b1, TReal _b2, TReal _b3, TReal _b4,
73 TReal _c1, TReal _c2, TReal _c3, TReal _c4,
74 TReal _d1, TReal _d2, TReal _d3, TReal _d4) :
75 a1(_a1), a2(_a2), a3(_a3), a4(_a4),
76 b1(_b1), b2(_b2), b3(_b3), b4(_b4),
77 c1(_c1), c2(_c2), c3(_c3), c4(_c4),
78 d1(_d1), d2(_d2), d3(_d3), d4(_d4)
79 {
81 }
83 // ------------------------------------------------------------------------------------------------
84 template <typename TReal>
85 template <typename TOther>
86 aiMatrix4x4t<TReal>::operator aiMatrix4x4t<TOther> () const
87 {
88 return aiMatrix4x4t<TOther>(static_cast<TOther>(a1),static_cast<TOther>(a2),static_cast<TOther>(a3),static_cast<TOther>(a4),
89 static_cast<TOther>(b1),static_cast<TOther>(b2),static_cast<TOther>(b3),static_cast<TOther>(b4),
90 static_cast<TOther>(c1),static_cast<TOther>(c2),static_cast<TOther>(c3),static_cast<TOther>(c4),
91 static_cast<TOther>(d1),static_cast<TOther>(d2),static_cast<TOther>(d3),static_cast<TOther>(d4));
92 }
95 // ----------------------------------------------------------------------------------------
96 template <typename TReal>
97 inline aiMatrix4x4t<TReal>::aiMatrix4x4t (const aiMatrix3x3t<TReal>& m)
98 {
99 a1 = m.a1; a2 = m.a2; a3 = m.a3; a4 = static_cast<TReal>(0.0);
100 b1 = m.b1; b2 = m.b2; b3 = m.b3; b4 = static_cast<TReal>(0.0);
101 c1 = m.c1; c2 = m.c2; c3 = m.c3; c4 = static_cast<TReal>(0.0);
102 d1 = static_cast<TReal>(0.0); d2 = static_cast<TReal>(0.0); d3 = static_cast<TReal>(0.0); d4 = static_cast<TReal>(1.0);
103 }
105 // ----------------------------------------------------------------------------------------
106 template <typename TReal>
107 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::operator *= (const aiMatrix4x4t<TReal>& m)
108 {
109 *this = aiMatrix4x4t<TReal>(
110 m.a1 * a1 + m.b1 * a2 + m.c1 * a3 + m.d1 * a4,
111 m.a2 * a1 + m.b2 * a2 + m.c2 * a3 + m.d2 * a4,
112 m.a3 * a1 + m.b3 * a2 + m.c3 * a3 + m.d3 * a4,
113 m.a4 * a1 + m.b4 * a2 + m.c4 * a3 + m.d4 * a4,
114 m.a1 * b1 + m.b1 * b2 + m.c1 * b3 + m.d1 * b4,
115 m.a2 * b1 + m.b2 * b2 + m.c2 * b3 + m.d2 * b4,
116 m.a3 * b1 + m.b3 * b2 + m.c3 * b3 + m.d3 * b4,
117 m.a4 * b1 + m.b4 * b2 + m.c4 * b3 + m.d4 * b4,
118 m.a1 * c1 + m.b1 * c2 + m.c1 * c3 + m.d1 * c4,
119 m.a2 * c1 + m.b2 * c2 + m.c2 * c3 + m.d2 * c4,
120 m.a3 * c1 + m.b3 * c2 + m.c3 * c3 + m.d3 * c4,
121 m.a4 * c1 + m.b4 * c2 + m.c4 * c3 + m.d4 * c4,
122 m.a1 * d1 + m.b1 * d2 + m.c1 * d3 + m.d1 * d4,
123 m.a2 * d1 + m.b2 * d2 + m.c2 * d3 + m.d2 * d4,
124 m.a3 * d1 + m.b3 * d2 + m.c3 * d3 + m.d3 * d4,
125 m.a4 * d1 + m.b4 * d2 + m.c4 * d3 + m.d4 * d4);
126 return *this;
127 }
129 // ----------------------------------------------------------------------------------------
130 template <typename TReal>
131 inline aiMatrix4x4t<TReal> aiMatrix4x4t<TReal>::operator* (const aiMatrix4x4t<TReal>& m) const
132 {
133 aiMatrix4x4t<TReal> temp( *this);
134 temp *= m;
135 return temp;
136 }
139 // ----------------------------------------------------------------------------------------
140 template <typename TReal>
141 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Transpose()
142 {
143 // (TReal&) don't remove, GCC complains cause of packed fields
144 std::swap( (TReal&)b1, (TReal&)a2);
145 std::swap( (TReal&)c1, (TReal&)a3);
146 std::swap( (TReal&)c2, (TReal&)b3);
147 std::swap( (TReal&)d1, (TReal&)a4);
148 std::swap( (TReal&)d2, (TReal&)b4);
149 std::swap( (TReal&)d3, (TReal&)c4);
150 return *this;
151 }
154 // ----------------------------------------------------------------------------------------
155 template <typename TReal>
156 inline TReal aiMatrix4x4t<TReal>::Determinant() const
157 {
158 return a1*b2*c3*d4 - a1*b2*c4*d3 + a1*b3*c4*d2 - a1*b3*c2*d4
159 + a1*b4*c2*d3 - a1*b4*c3*d2 - a2*b3*c4*d1 + a2*b3*c1*d4
160 - a2*b4*c1*d3 + a2*b4*c3*d1 - a2*b1*c3*d4 + a2*b1*c4*d3
161 + a3*b4*c1*d2 - a3*b4*c2*d1 + a3*b1*c2*d4 - a3*b1*c4*d2
162 + a3*b2*c4*d1 - a3*b2*c1*d4 - a4*b1*c2*d3 + a4*b1*c3*d2
163 - a4*b2*c3*d1 + a4*b2*c1*d3 - a4*b3*c1*d2 + a4*b3*c2*d1;
164 }
166 // ----------------------------------------------------------------------------------------
167 template <typename TReal>
168 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Inverse()
169 {
170 // Compute the reciprocal determinant
171 const TReal det = Determinant();
172 if(det == static_cast<TReal>(0.0))
173 {
174 // Matrix not invertible. Setting all elements to nan is not really
175 // correct in a mathematical sense but it is easy to debug for the
176 // programmer.
177 const TReal nan = std::numeric_limits<TReal>::quiet_NaN();
178 *this = aiMatrix4x4t<TReal>(
179 nan,nan,nan,nan,
180 nan,nan,nan,nan,
181 nan,nan,nan,nan,
182 nan,nan,nan,nan);
184 return *this;
185 }
187 const TReal invdet = static_cast<TReal>(1.0) / det;
189 aiMatrix4x4t<TReal> res;
190 res.a1 = invdet * (b2 * (c3 * d4 - c4 * d3) + b3 * (c4 * d2 - c2 * d4) + b4 * (c2 * d3 - c3 * d2));
191 res.a2 = -invdet * (a2 * (c3 * d4 - c4 * d3) + a3 * (c4 * d2 - c2 * d4) + a4 * (c2 * d3 - c3 * d2));
192 res.a3 = invdet * (a2 * (b3 * d4 - b4 * d3) + a3 * (b4 * d2 - b2 * d4) + a4 * (b2 * d3 - b3 * d2));
193 res.a4 = -invdet * (a2 * (b3 * c4 - b4 * c3) + a3 * (b4 * c2 - b2 * c4) + a4 * (b2 * c3 - b3 * c2));
194 res.b1 = -invdet * (b1 * (c3 * d4 - c4 * d3) + b3 * (c4 * d1 - c1 * d4) + b4 * (c1 * d3 - c3 * d1));
195 res.b2 = invdet * (a1 * (c3 * d4 - c4 * d3) + a3 * (c4 * d1 - c1 * d4) + a4 * (c1 * d3 - c3 * d1));
196 res.b3 = -invdet * (a1 * (b3 * d4 - b4 * d3) + a3 * (b4 * d1 - b1 * d4) + a4 * (b1 * d3 - b3 * d1));
197 res.b4 = invdet * (a1 * (b3 * c4 - b4 * c3) + a3 * (b4 * c1 - b1 * c4) + a4 * (b1 * c3 - b3 * c1));
198 res.c1 = invdet * (b1 * (c2 * d4 - c4 * d2) + b2 * (c4 * d1 - c1 * d4) + b4 * (c1 * d2 - c2 * d1));
199 res.c2 = -invdet * (a1 * (c2 * d4 - c4 * d2) + a2 * (c4 * d1 - c1 * d4) + a4 * (c1 * d2 - c2 * d1));
200 res.c3 = invdet * (a1 * (b2 * d4 - b4 * d2) + a2 * (b4 * d1 - b1 * d4) + a4 * (b1 * d2 - b2 * d1));
201 res.c4 = -invdet * (a1 * (b2 * c4 - b4 * c2) + a2 * (b4 * c1 - b1 * c4) + a4 * (b1 * c2 - b2 * c1));
202 res.d1 = -invdet * (b1 * (c2 * d3 - c3 * d2) + b2 * (c3 * d1 - c1 * d3) + b3 * (c1 * d2 - c2 * d1));
203 res.d2 = invdet * (a1 * (c2 * d3 - c3 * d2) + a2 * (c3 * d1 - c1 * d3) + a3 * (c1 * d2 - c2 * d1));
204 res.d3 = -invdet * (a1 * (b2 * d3 - b3 * d2) + a2 * (b3 * d1 - b1 * d3) + a3 * (b1 * d2 - b2 * d1));
205 res.d4 = invdet * (a1 * (b2 * c3 - b3 * c2) + a2 * (b3 * c1 - b1 * c3) + a3 * (b1 * c2 - b2 * c1));
206 *this = res;
208 return *this;
209 }
211 // ----------------------------------------------------------------------------------------
212 template <typename TReal>
213 inline TReal* aiMatrix4x4t<TReal>::operator[](unsigned int p_iIndex)
214 {
215 // XXX this is UB. Has been for years. The fact that it works now does not make it better.
216 return &this->a1 + p_iIndex * 4;
217 }
219 // ----------------------------------------------------------------------------------------
220 template <typename TReal>
221 inline const TReal* aiMatrix4x4t<TReal>::operator[](unsigned int p_iIndex) const
222 {
223 // XXX same
224 return &this->a1 + p_iIndex * 4;
225 }
227 // ----------------------------------------------------------------------------------------
228 template <typename TReal>
229 inline bool aiMatrix4x4t<TReal>::operator== (const aiMatrix4x4t<TReal> m) const
230 {
231 return (a1 == m.a1 && a2 == m.a2 && a3 == m.a3 && a4 == m.a4 &&
232 b1 == m.b1 && b2 == m.b2 && b3 == m.b3 && b4 == m.b4 &&
233 c1 == m.c1 && c2 == m.c2 && c3 == m.c3 && c4 == m.c4 &&
234 d1 == m.d1 && d2 == m.d2 && d3 == m.d3 && d4 == m.d4);
235 }
237 // ----------------------------------------------------------------------------------------
238 template <typename TReal>
239 inline bool aiMatrix4x4t<TReal>::operator!= (const aiMatrix4x4t<TReal> m) const
240 {
241 return !(*this == m);
242 }
244 // ----------------------------------------------------------------------------------------
245 template <typename TReal>
246 inline void aiMatrix4x4t<TReal>::Decompose (aiVector3t<TReal>& scaling, aiQuaterniont<TReal>& rotation,
247 aiVector3t<TReal>& position) const
248 {
249 const aiMatrix4x4t<TReal>& _this = *this;
251 // extract translation
252 position.x = _this[0][3];
253 position.y = _this[1][3];
254 position.z = _this[2][3];
256 // extract the rows of the matrix
257 aiVector3t<TReal> vRows[3] = {
258 aiVector3t<TReal>(_this[0][0],_this[1][0],_this[2][0]),
259 aiVector3t<TReal>(_this[0][1],_this[1][1],_this[2][1]),
260 aiVector3t<TReal>(_this[0][2],_this[1][2],_this[2][2])
261 };
263 // extract the scaling factors
264 scaling.x = vRows[0].Length();
265 scaling.y = vRows[1].Length();
266 scaling.z = vRows[2].Length();
268 // and the sign of the scaling
269 if (Determinant() < 0) {
270 scaling.x = -scaling.x;
271 scaling.y = -scaling.y;
272 scaling.z = -scaling.z;
273 }
275 // and remove all scaling from the matrix
276 if(scaling.x)
277 {
278 vRows[0] /= scaling.x;
279 }
280 if(scaling.y)
281 {
282 vRows[1] /= scaling.y;
283 }
284 if(scaling.z)
285 {
286 vRows[2] /= scaling.z;
287 }
289 // build a 3x3 rotation matrix
290 aiMatrix3x3t<TReal> m(vRows[0].x,vRows[1].x,vRows[2].x,
291 vRows[0].y,vRows[1].y,vRows[2].y,
292 vRows[0].z,vRows[1].z,vRows[2].z);
294 // and generate the rotation quaternion from it
295 rotation = aiQuaterniont<TReal>(m);
296 }
298 // ----------------------------------------------------------------------------------------
299 template <typename TReal>
300 inline void aiMatrix4x4t<TReal>::DecomposeNoScaling (aiQuaterniont<TReal>& rotation,
301 aiVector3t<TReal>& position) const
302 {
303 const aiMatrix4x4t<TReal>& _this = *this;
305 // extract translation
306 position.x = _this[0][3];
307 position.y = _this[1][3];
308 position.z = _this[2][3];
310 // extract rotation
311 rotation = aiQuaterniont<TReal>((aiMatrix3x3t<TReal>)_this);
312 }
314 // ----------------------------------------------------------------------------------------
315 template <typename TReal>
316 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::FromEulerAnglesXYZ(const aiVector3t<TReal>& blubb)
317 {
318 return FromEulerAnglesXYZ(blubb.x,blubb.y,blubb.z);
319 }
321 // ----------------------------------------------------------------------------------------
322 template <typename TReal>
323 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::FromEulerAnglesXYZ(TReal x, TReal y, TReal z)
324 {
325 aiMatrix4x4t<TReal>& _this = *this;
327 TReal cr = cos( x );
328 TReal sr = sin( x );
329 TReal cp = cos( y );
330 TReal sp = sin( y );
331 TReal cy = cos( z );
332 TReal sy = sin( z );
334 _this.a1 = cp*cy ;
335 _this.a2 = cp*sy;
336 _this.a3 = -sp ;
338 TReal srsp = sr*sp;
339 TReal crsp = cr*sp;
341 _this.b1 = srsp*cy-cr*sy ;
342 _this.b2 = srsp*sy+cr*cy ;
343 _this.b3 = sr*cp ;
345 _this.c1 = crsp*cy+sr*sy ;
346 _this.c2 = crsp*sy-sr*cy ;
347 _this.c3 = cr*cp ;
349 return *this;
350 }
352 // ----------------------------------------------------------------------------------------
353 template <typename TReal>
354 inline bool aiMatrix4x4t<TReal>::IsIdentity() const
355 {
356 // Use a small epsilon to solve floating-point inaccuracies
357 const static TReal epsilon = 10e-3f;
359 return (a2 <= epsilon && a2 >= -epsilon &&
360 a3 <= epsilon && a3 >= -epsilon &&
361 a4 <= epsilon && a4 >= -epsilon &&
362 b1 <= epsilon && b1 >= -epsilon &&
363 b3 <= epsilon && b3 >= -epsilon &&
364 b4 <= epsilon && b4 >= -epsilon &&
365 c1 <= epsilon && c1 >= -epsilon &&
366 c2 <= epsilon && c2 >= -epsilon &&
367 c4 <= epsilon && c4 >= -epsilon &&
368 d1 <= epsilon && d1 >= -epsilon &&
369 d2 <= epsilon && d2 >= -epsilon &&
370 d3 <= epsilon && d3 >= -epsilon &&
371 a1 <= 1.f+epsilon && a1 >= 1.f-epsilon &&
372 b2 <= 1.f+epsilon && b2 >= 1.f-epsilon &&
373 c3 <= 1.f+epsilon && c3 >= 1.f-epsilon &&
374 d4 <= 1.f+epsilon && d4 >= 1.f-epsilon);
375 }
377 // ----------------------------------------------------------------------------------------
378 template <typename TReal>
379 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::RotationX(TReal a, aiMatrix4x4t<TReal>& out)
380 {
381 /*
382 | 1 0 0 0 |
383 M = | 0 cos(A) -sin(A) 0 |
384 | 0 sin(A) cos(A) 0 |
385 | 0 0 0 1 | */
386 out = aiMatrix4x4t<TReal>();
387 out.b2 = out.c3 = cos(a);
388 out.b3 = -(out.c2 = sin(a));
389 return out;
390 }
392 // ----------------------------------------------------------------------------------------
393 template <typename TReal>
394 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::RotationY(TReal a, aiMatrix4x4t<TReal>& out)
395 {
396 /*
397 | cos(A) 0 sin(A) 0 |
398 M = | 0 1 0 0 |
399 | -sin(A) 0 cos(A) 0 |
400 | 0 0 0 1 |
401 */
402 out = aiMatrix4x4t<TReal>();
403 out.a1 = out.c3 = cos(a);
404 out.c1 = -(out.a3 = sin(a));
405 return out;
406 }
408 // ----------------------------------------------------------------------------------------
409 template <typename TReal>
410 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::RotationZ(TReal a, aiMatrix4x4t<TReal>& out)
411 {
412 /*
413 | cos(A) -sin(A) 0 0 |
414 M = | sin(A) cos(A) 0 0 |
415 | 0 0 1 0 |
416 | 0 0 0 1 | */
417 out = aiMatrix4x4t<TReal>();
418 out.a1 = out.b2 = cos(a);
419 out.a2 = -(out.b1 = sin(a));
420 return out;
421 }
423 // ----------------------------------------------------------------------------------------
424 // Returns a rotation matrix for a rotation around an arbitrary axis.
425 template <typename TReal>
426 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Rotation( TReal a, const aiVector3t<TReal>& axis, aiMatrix4x4t<TReal>& out)
427 {
428 TReal c = cos( a), s = sin( a), t = 1 - c;
429 TReal x = axis.x, y = axis.y, z = axis.z;
431 // Many thanks to MathWorld and Wikipedia
432 out.a1 = t*x*x + c; out.a2 = t*x*y - s*z; out.a3 = t*x*z + s*y;
433 out.b1 = t*x*y + s*z; out.b2 = t*y*y + c; out.b3 = t*y*z - s*x;
434 out.c1 = t*x*z - s*y; out.c2 = t*y*z + s*x; out.c3 = t*z*z + c;
435 out.a4 = out.b4 = out.c4 = static_cast<TReal>(0.0);
436 out.d1 = out.d2 = out.d3 = static_cast<TReal>(0.0);
437 out.d4 = static_cast<TReal>(1.0);
439 return out;
440 }
442 // ----------------------------------------------------------------------------------------
443 template <typename TReal>
444 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Translation( const aiVector3t<TReal>& v, aiMatrix4x4t<TReal>& out)
445 {
446 out = aiMatrix4x4t<TReal>();
447 out.a4 = v.x;
448 out.b4 = v.y;
449 out.c4 = v.z;
450 return out;
451 }
453 // ----------------------------------------------------------------------------------------
454 template <typename TReal>
455 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::Scaling( const aiVector3t<TReal>& v, aiMatrix4x4t<TReal>& out)
456 {
457 out = aiMatrix4x4t<TReal>();
458 out.a1 = v.x;
459 out.b2 = v.y;
460 out.c3 = v.z;
461 return out;
462 }
464 // ----------------------------------------------------------------------------------------
465 /** A function for creating a rotation matrix that rotates a vector called
466 * "from" into another vector called "to".
467 * Input : from[3], to[3] which both must be *normalized* non-zero vectors
468 * Output: mtx[3][3] -- a 3x3 matrix in colum-major form
469 * Authors: Tomas Möller, John Hughes
470 * "Efficiently Building a Matrix to Rotate One Vector to Another"
471 * Journal of Graphics Tools, 4(4):1-4, 1999
472 */
473 // ----------------------------------------------------------------------------------------
474 template <typename TReal>
475 inline aiMatrix4x4t<TReal>& aiMatrix4x4t<TReal>::FromToMatrix(const aiVector3t<TReal>& from,
476 const aiVector3t<TReal>& to, aiMatrix4x4t<TReal>& mtx)
477 {
478 aiMatrix3x3t<TReal> m3;
479 aiMatrix3x3t<TReal>::FromToMatrix(from,to,m3);
480 mtx = aiMatrix4x4t<TReal>(m3);
481 return mtx;
482 }
484 #endif // __cplusplus
485 #endif // AI_MATRIX4x4_INL_INC