DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Matrix.h (57756B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #ifndef __MATH_MATRIX_H__
     30 #define __MATH_MATRIX_H__
     31 
     32 /*
     33 ===============================================================================
     34 
     35   Matrix classes, all matrices are row-major except idMat3
     36 
     37 ===============================================================================
     38 */
     39 
     40 #define MATRIX_INVERSE_EPSILON		1e-14
     41 #define MATRIX_EPSILON				1e-6
     42 
     43 class idAngles;
     44 class idQuat;
     45 class idCQuat;
     46 class idRotation;
     47 class idMat4;
     48 
     49 //===============================================================
     50 //
     51 //	idMat2 - 2x2 matrix
     52 //
     53 //===============================================================
     54 
     55 class idMat2 {
     56 public:
     57 					idMat2();
     58 					explicit idMat2( const idVec2 &x, const idVec2 &y );
     59 					explicit idMat2( const float xx, const float xy, const float yx, const float yy );
     60 					explicit idMat2( const float src[ 2 ][ 2 ] );
     61 
     62 	const idVec2 &	operator[]( int index ) const;
     63 	idVec2 &		operator[]( int index );
     64 	idMat2			operator-() const;
     65 	idMat2			operator*( const float a ) const;
     66 	idVec2			operator*( const idVec2 &vec ) const;
     67 	idMat2			operator*( const idMat2 &a ) const;
     68 	idMat2			operator+( const idMat2 &a ) const;
     69 	idMat2			operator-( const idMat2 &a ) const;
     70 	idMat2 &		operator*=( const float a );
     71 	idMat2 &		operator*=( const idMat2 &a );
     72 	idMat2 &		operator+=( const idMat2 &a );
     73 	idMat2 &		operator-=( const idMat2 &a );
     74 
     75 	friend idMat2	operator*( const float a, const idMat2 &mat );
     76 	friend idVec2	operator*( const idVec2 &vec, const idMat2 &mat );
     77 	friend idVec2 &	operator*=( idVec2 &vec, const idMat2 &mat );
     78 
     79 	bool			Compare( const idMat2 &a ) const;						// exact compare, no epsilon
     80 	bool			Compare( const idMat2 &a, const float epsilon ) const;	// compare with epsilon
     81 	bool			operator==( const idMat2 &a ) const;					// exact compare, no epsilon
     82 	bool			operator!=( const idMat2 &a ) const;					// exact compare, no epsilon
     83 
     84 	void			Zero();
     85 	void			Identity();
     86 	bool			IsIdentity( const float epsilon = MATRIX_EPSILON ) const;
     87 	bool			IsSymmetric( const float epsilon = MATRIX_EPSILON ) const;
     88 	bool			IsDiagonal( const float epsilon = MATRIX_EPSILON ) const;
     89 
     90 	float			Trace() const;
     91 	float			Determinant() const;
     92 	idMat2			Transpose() const;	// returns transpose
     93 	idMat2 &		TransposeSelf();
     94 	idMat2			Inverse() const;		// returns the inverse ( m * m.Inverse() = identity )
     95 	bool			InverseSelf();		// returns false if determinant is zero
     96 	idMat2			InverseFast() const;	// returns the inverse ( m * m.Inverse() = identity )
     97 	bool			InverseFastSelf();	// returns false if determinant is zero
     98 
     99 	int				GetDimension() const;
    100 
    101 	const float *	ToFloatPtr() const;
    102 	float *			ToFloatPtr();
    103 	const char *	ToString( int precision = 2 ) const;
    104 
    105 private:
    106 	idVec2			mat[ 2 ];
    107 };
    108 
    109 extern idMat2 mat2_zero;
    110 extern idMat2 mat2_identity;
    111 #define mat2_default	mat2_identity
    112 
    113 ID_INLINE idMat2::idMat2() {
    114 }
    115 
    116 ID_INLINE idMat2::idMat2( const idVec2 &x, const idVec2 &y ) {
    117 	mat[ 0 ].x = x.x; mat[ 0 ].y = x.y;
    118 	mat[ 1 ].x = y.x; mat[ 1 ].y = y.y;
    119 }
    120 
    121 ID_INLINE idMat2::idMat2( const float xx, const float xy, const float yx, const float yy ) {
    122 	mat[ 0 ].x = xx; mat[ 0 ].y = xy;
    123 	mat[ 1 ].x = yx; mat[ 1 ].y = yy;
    124 }
    125 
    126 ID_INLINE idMat2::idMat2( const float src[ 2 ][ 2 ] ) {
    127 	memcpy( mat, src, 2 * 2 * sizeof( float ) );
    128 }
    129 
    130 ID_INLINE const idVec2 &idMat2::operator[]( int index ) const {
    131 	//assert( ( index >= 0 ) && ( index < 2 ) );
    132 	return mat[ index ];
    133 }
    134 
    135 ID_INLINE idVec2 &idMat2::operator[]( int index ) {
    136 	//assert( ( index >= 0 ) && ( index < 2 ) );
    137 	return mat[ index ];
    138 }
    139 
    140 ID_INLINE idMat2 idMat2::operator-() const {
    141 	return idMat2(	-mat[0][0], -mat[0][1],
    142 					-mat[1][0], -mat[1][1] );
    143 }
    144 
    145 ID_INLINE idVec2 idMat2::operator*( const idVec2 &vec ) const {
    146 	return idVec2(
    147 		mat[ 0 ].x * vec.x + mat[ 0 ].y * vec.y,
    148 		mat[ 1 ].x * vec.x + mat[ 1 ].y * vec.y );
    149 }
    150 
    151 ID_INLINE idMat2 idMat2::operator*( const idMat2 &a ) const {
    152 	return idMat2(
    153 		mat[0].x * a[0].x + mat[0].y * a[1].x,
    154 		mat[0].x * a[0].y + mat[0].y * a[1].y,
    155 		mat[1].x * a[0].x + mat[1].y * a[1].x,
    156 		mat[1].x * a[0].y + mat[1].y * a[1].y );
    157 }
    158 
    159 ID_INLINE idMat2 idMat2::operator*( const float a ) const {
    160 	return idMat2(
    161 		mat[0].x * a, mat[0].y * a, 
    162 		mat[1].x * a, mat[1].y * a );
    163 }
    164 
    165 ID_INLINE idMat2 idMat2::operator+( const idMat2 &a ) const {
    166 	return idMat2(
    167 		mat[0].x + a[0].x, mat[0].y + a[0].y, 
    168 		mat[1].x + a[1].x, mat[1].y + a[1].y );
    169 }
    170     
    171 ID_INLINE idMat2 idMat2::operator-( const idMat2 &a ) const {
    172 	return idMat2(
    173 		mat[0].x - a[0].x, mat[0].y - a[0].y,
    174 		mat[1].x - a[1].x, mat[1].y - a[1].y );
    175 }
    176 
    177 ID_INLINE idMat2 &idMat2::operator*=( const float a ) {
    178 	mat[0].x *= a; mat[0].y *= a;
    179 	mat[1].x *= a; mat[1].y *= a;
    180 
    181     return *this;
    182 }
    183 
    184 ID_INLINE idMat2 &idMat2::operator*=( const idMat2 &a ) {
    185 	float x, y;
    186 	x = mat[0].x; y = mat[0].y;
    187 	mat[0].x = x * a[0].x + y * a[1].x;
    188 	mat[0].y = x * a[0].y + y * a[1].y;
    189 	x = mat[1].x; y = mat[1].y;
    190 	mat[1].x = x * a[0].x + y * a[1].x;
    191 	mat[1].y = x * a[0].y + y * a[1].y;
    192 	return *this;
    193 }
    194 
    195 ID_INLINE idMat2 &idMat2::operator+=( const idMat2 &a ) {
    196 	mat[0].x += a[0].x; mat[0].y += a[0].y;
    197 	mat[1].x += a[1].x; mat[1].y += a[1].y;
    198 
    199     return *this;
    200 }
    201 
    202 ID_INLINE idMat2 &idMat2::operator-=( const idMat2 &a ) {
    203 	mat[0].x -= a[0].x; mat[0].y -= a[0].y;
    204 	mat[1].x -= a[1].x; mat[1].y -= a[1].y;
    205 
    206     return *this;
    207 }
    208 
    209 ID_INLINE idVec2 operator*( const idVec2 &vec, const idMat2 &mat ) {
    210 	return mat * vec;
    211 }
    212 
    213 ID_INLINE idMat2 operator*( const float a, idMat2 const &mat ) {
    214 	return mat * a;
    215 }
    216 
    217 ID_INLINE idVec2 &operator*=( idVec2 &vec, const idMat2 &mat ) {
    218 	vec = mat * vec;
    219 	return vec;
    220 }
    221 
    222 ID_INLINE bool idMat2::Compare( const idMat2 &a ) const {
    223 	if ( mat[0].Compare( a[0] ) &&
    224 		mat[1].Compare( a[1] ) ) {
    225 		return true;
    226 	}
    227 	return false;
    228 }
    229 
    230 ID_INLINE bool idMat2::Compare( const idMat2 &a, const float epsilon ) const {
    231 	if ( mat[0].Compare( a[0], epsilon ) &&
    232 		mat[1].Compare( a[1], epsilon ) ) {
    233 		return true;
    234 	}
    235 	return false;
    236 }
    237 
    238 ID_INLINE bool idMat2::operator==( const idMat2 &a ) const {
    239 	return Compare( a );
    240 }
    241 
    242 ID_INLINE bool idMat2::operator!=( const idMat2 &a ) const {
    243 	return !Compare( a );
    244 }
    245 
    246 ID_INLINE void idMat2::Zero() {
    247 	mat[0].Zero();
    248 	mat[1].Zero();
    249 }
    250 
    251 ID_INLINE void idMat2::Identity() {
    252 	*this = mat2_identity;
    253 }
    254 
    255 ID_INLINE bool idMat2::IsIdentity( const float epsilon ) const {
    256 	return Compare( mat2_identity, epsilon );
    257 }
    258 
    259 ID_INLINE bool idMat2::IsSymmetric( const float epsilon ) const {
    260 	return ( idMath::Fabs( mat[0][1] - mat[1][0] ) < epsilon );
    261 }
    262 
    263 ID_INLINE bool idMat2::IsDiagonal( const float epsilon ) const {
    264 	if ( idMath::Fabs( mat[0][1] ) > epsilon ||
    265 		idMath::Fabs( mat[1][0] ) > epsilon ) {
    266 		return false;
    267 	}
    268 	return true;
    269 }
    270 
    271 ID_INLINE float idMat2::Trace() const {
    272 	return ( mat[0][0] + mat[1][1] );
    273 }
    274 
    275 ID_INLINE float idMat2::Determinant() const {
    276 	return mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0];
    277 }
    278 
    279 ID_INLINE idMat2 idMat2::Transpose() const {
    280 	return idMat2(	mat[0][0], mat[1][0],
    281 					mat[0][1], mat[1][1] );
    282 }
    283 
    284 ID_INLINE idMat2 &idMat2::TransposeSelf() {
    285 	float tmp;
    286 
    287 	tmp = mat[0][1];
    288 	mat[0][1] = mat[1][0];
    289 	mat[1][0] = tmp;
    290 
    291 	return *this;
    292 }
    293 
    294 ID_INLINE idMat2 idMat2::Inverse() const {
    295 	idMat2 invMat;
    296 
    297 	invMat = *this;
    298 	verify( invMat.InverseSelf() );
    299 	return invMat;
    300 }
    301 
    302 ID_INLINE idMat2 idMat2::InverseFast() const {
    303 	idMat2 invMat;
    304 
    305 	invMat = *this;
    306 	verify( invMat.InverseFastSelf() );
    307 	return invMat;
    308 }
    309 
    310 ID_INLINE int idMat2::GetDimension() const {
    311 	return 4;
    312 }
    313 
    314 ID_INLINE const float *idMat2::ToFloatPtr() const {
    315 	return mat[0].ToFloatPtr();
    316 }
    317 
    318 ID_INLINE float *idMat2::ToFloatPtr() {
    319 	return mat[0].ToFloatPtr();
    320 }
    321 
    322 
    323 //===============================================================
    324 //
    325 //	idMat3 - 3x3 matrix
    326 //
    327 //	NOTE:	matrix is column-major
    328 //
    329 //===============================================================
    330 
    331 class idMat3 {
    332 public:
    333 					idMat3();
    334 					explicit idMat3( const idVec3 &x, const idVec3 &y, const idVec3 &z );
    335 					explicit idMat3( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz );
    336 					explicit idMat3( const float src[ 3 ][ 3 ] );
    337 
    338 	const idVec3 &	operator[]( int index ) const;
    339 	idVec3 &		operator[]( int index );
    340 	idMat3			operator-() const;
    341 	idMat3			operator*( const float a ) const;
    342 	idVec3			operator*( const idVec3 &vec ) const;
    343 	idMat3			operator*( const idMat3 &a ) const;
    344 	idMat3			operator+( const idMat3 &a ) const;
    345 	idMat3			operator-( const idMat3 &a ) const;
    346 	idMat3 &		operator*=( const float a );
    347 	idMat3 &		operator*=( const idMat3 &a );
    348 	idMat3 &		operator+=( const idMat3 &a );
    349 	idMat3 &		operator-=( const idMat3 &a );
    350 
    351 	friend idMat3	operator*( const float a, const idMat3 &mat );
    352 	friend idVec3	operator*( const idVec3 &vec, const idMat3 &mat );
    353 	friend idVec3 &	operator*=( idVec3 &vec, const idMat3 &mat );
    354 
    355 	bool			Compare( const idMat3 &a ) const;						// exact compare, no epsilon
    356 	bool			Compare( const idMat3 &a, const float epsilon ) const;	// compare with epsilon
    357 	bool			operator==( const idMat3 &a ) const;					// exact compare, no epsilon
    358 	bool			operator!=( const idMat3 &a ) const;					// exact compare, no epsilon
    359 
    360 	void			Zero();
    361 	void			Identity();
    362 	bool			IsIdentity( const float epsilon = MATRIX_EPSILON ) const;
    363 	bool			IsSymmetric( const float epsilon = MATRIX_EPSILON ) const;
    364 	bool			IsDiagonal( const float epsilon = MATRIX_EPSILON ) const;
    365 	bool			IsRotated() const;
    366 
    367 	void			ProjectVector( const idVec3 &src, idVec3 &dst ) const;
    368 	void			UnprojectVector( const idVec3 &src, idVec3 &dst ) const;
    369 
    370 	bool			FixDegeneracies();	// fix degenerate axial cases
    371 	bool			FixDenormals();		// change tiny numbers to zero
    372 
    373 	float			Trace() const;
    374 	float			Determinant() const;
    375 	idMat3			OrthoNormalize() const;
    376 	idMat3 &		OrthoNormalizeSelf();
    377 	idMat3			Transpose() const;	// returns transpose
    378 	idMat3 &		TransposeSelf();
    379 	idMat3			Inverse() const;		// returns the inverse ( m * m.Inverse() = identity )
    380 	bool			InverseSelf();		// returns false if determinant is zero
    381 	idMat3			InverseFast() const;	// returns the inverse ( m * m.Inverse() = identity )
    382 	bool			InverseFastSelf();	// returns false if determinant is zero
    383 	idMat3			TransposeMultiply( const idMat3 &b ) const;
    384 
    385 	idMat3			InertiaTranslate( const float mass, const idVec3 &centerOfMass, const idVec3 &translation ) const;
    386 	idMat3 &		InertiaTranslateSelf( const float mass, const idVec3 &centerOfMass, const idVec3 &translation );
    387 	idMat3			InertiaRotate( const idMat3 &rotation ) const;
    388 	idMat3 &		InertiaRotateSelf( const idMat3 &rotation );
    389 
    390 	int				GetDimension() const;
    391 
    392 	idAngles		ToAngles() const;
    393 	idQuat			ToQuat() const;
    394 	idCQuat			ToCQuat() const;
    395 	idRotation		ToRotation() const;
    396 	idMat4			ToMat4() const;
    397 	idVec3			ToAngularVelocity() const;
    398 	const float *	ToFloatPtr() const;
    399 	float *			ToFloatPtr();
    400 	const char *	ToString( int precision = 2 ) const;
    401 
    402 	friend void		TransposeMultiply( const idMat3 &inv, const idMat3 &b, idMat3 &dst );
    403 	friend idMat3	SkewSymmetric( idVec3 const &src );
    404 
    405 private:
    406 	idVec3			mat[ 3 ];
    407 };
    408 
    409 extern idMat3 mat3_zero;
    410 extern idMat3 mat3_identity;
    411 #define mat3_default	mat3_identity
    412 
    413 ID_INLINE idMat3::idMat3() {
    414 }
    415 
    416 ID_INLINE idMat3::idMat3( const idVec3 &x, const idVec3 &y, const idVec3 &z ) {
    417 	mat[ 0 ].x = x.x; mat[ 0 ].y = x.y; mat[ 0 ].z = x.z;
    418 	mat[ 1 ].x = y.x; mat[ 1 ].y = y.y; mat[ 1 ].z = y.z;
    419 	mat[ 2 ].x = z.x; mat[ 2 ].y = z.y; mat[ 2 ].z = z.z;
    420 }
    421 
    422 ID_INLINE idMat3::idMat3( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz ) {
    423 	mat[ 0 ].x = xx; mat[ 0 ].y = xy; mat[ 0 ].z = xz;
    424 	mat[ 1 ].x = yx; mat[ 1 ].y = yy; mat[ 1 ].z = yz;
    425 	mat[ 2 ].x = zx; mat[ 2 ].y = zy; mat[ 2 ].z = zz;
    426 }
    427 
    428 ID_INLINE idMat3::idMat3( const float src[ 3 ][ 3 ] ) {
    429 	memcpy( mat, src, 3 * 3 * sizeof( float ) );
    430 }
    431 
    432 ID_INLINE const idVec3 &idMat3::operator[]( int index ) const {
    433 	//assert( ( index >= 0 ) && ( index < 3 ) );
    434 	return mat[ index ];
    435 }
    436 
    437 ID_INLINE idVec3 &idMat3::operator[]( int index ) {
    438 	//assert( ( index >= 0 ) && ( index < 3 ) );
    439 	return mat[ index ];
    440 }
    441 
    442 ID_INLINE idMat3 idMat3::operator-() const {
    443 	return idMat3(	-mat[0][0], -mat[0][1], -mat[0][2],
    444 					-mat[1][0], -mat[1][1], -mat[1][2],
    445 					-mat[2][0], -mat[2][1], -mat[2][2] );
    446 }
    447 
    448 ID_INLINE idVec3 idMat3::operator*( const idVec3 &vec ) const {
    449 	return idVec3(
    450 		mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z,
    451 		mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z,
    452 		mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z );
    453 }
    454 
    455 ID_INLINE idMat3 idMat3::operator*( const idMat3 &a ) const {
    456 	int i, j;
    457 	const float *m1Ptr, *m2Ptr;
    458 	float *dstPtr;
    459 	idMat3 dst;
    460 
    461 	m1Ptr = reinterpret_cast<const float *>(this);
    462 	m2Ptr = reinterpret_cast<const float *>(&a);
    463 	dstPtr = reinterpret_cast<float *>(&dst);
    464 
    465 	for ( i = 0; i < 3; i++ ) {
    466 		for ( j = 0; j < 3; j++ ) {
    467 			*dstPtr = m1Ptr[0] * m2Ptr[ 0 * 3 + j ]
    468 					+ m1Ptr[1] * m2Ptr[ 1 * 3 + j ]
    469 					+ m1Ptr[2] * m2Ptr[ 2 * 3 + j ];
    470 			dstPtr++;
    471 		}
    472 		m1Ptr += 3;
    473 	}
    474 	return dst;
    475 }
    476 
    477 ID_INLINE idMat3 idMat3::operator*( const float a ) const {
    478 	return idMat3(
    479 		mat[0].x * a, mat[0].y * a, mat[0].z * a,
    480 		mat[1].x * a, mat[1].y * a, mat[1].z * a,
    481 		mat[2].x * a, mat[2].y * a, mat[2].z * a );
    482 }
    483 
    484 ID_INLINE idMat3 idMat3::operator+( const idMat3 &a ) const {
    485 	return idMat3(
    486 		mat[0].x + a[0].x, mat[0].y + a[0].y, mat[0].z + a[0].z,
    487 		mat[1].x + a[1].x, mat[1].y + a[1].y, mat[1].z + a[1].z,
    488 		mat[2].x + a[2].x, mat[2].y + a[2].y, mat[2].z + a[2].z );
    489 }
    490     
    491 ID_INLINE idMat3 idMat3::operator-( const idMat3 &a ) const {
    492 	return idMat3(
    493 		mat[0].x - a[0].x, mat[0].y - a[0].y, mat[0].z - a[0].z,
    494 		mat[1].x - a[1].x, mat[1].y - a[1].y, mat[1].z - a[1].z,
    495 		mat[2].x - a[2].x, mat[2].y - a[2].y, mat[2].z - a[2].z );
    496 }
    497 
    498 ID_INLINE idMat3 &idMat3::operator*=( const float a ) {
    499 	mat[0].x *= a; mat[0].y *= a; mat[0].z *= a;
    500 	mat[1].x *= a; mat[1].y *= a; mat[1].z *= a; 
    501 	mat[2].x *= a; mat[2].y *= a; mat[2].z *= a;
    502 
    503     return *this;
    504 }
    505 
    506 ID_INLINE idMat3 &idMat3::operator*=( const idMat3 &a ) {
    507 	int i, j;
    508 	const float *m2Ptr;
    509 	float *m1Ptr, dst[3];
    510 
    511 	m1Ptr = reinterpret_cast<float *>(this);
    512 	m2Ptr = reinterpret_cast<const float *>(&a);
    513 
    514 	for ( i = 0; i < 3; i++ ) {
    515 		for ( j = 0; j < 3; j++ ) {
    516 			dst[j]  = m1Ptr[0] * m2Ptr[ 0 * 3 + j ]
    517 					+ m1Ptr[1] * m2Ptr[ 1 * 3 + j ]
    518 					+ m1Ptr[2] * m2Ptr[ 2 * 3 + j ];
    519 		}
    520 		m1Ptr[0] = dst[0]; m1Ptr[1] = dst[1]; m1Ptr[2] = dst[2];
    521 		m1Ptr += 3;
    522 	}
    523 	return *this;
    524 }
    525 
    526 ID_INLINE idMat3 &idMat3::operator+=( const idMat3 &a ) {
    527 	mat[0].x += a[0].x; mat[0].y += a[0].y; mat[0].z += a[0].z;
    528 	mat[1].x += a[1].x; mat[1].y += a[1].y; mat[1].z += a[1].z;
    529 	mat[2].x += a[2].x; mat[2].y += a[2].y; mat[2].z += a[2].z;
    530 
    531     return *this;
    532 }
    533 
    534 ID_INLINE idMat3 &idMat3::operator-=( const idMat3 &a ) {
    535 	mat[0].x -= a[0].x; mat[0].y -= a[0].y; mat[0].z -= a[0].z;
    536 	mat[1].x -= a[1].x; mat[1].y -= a[1].y; mat[1].z -= a[1].z;
    537 	mat[2].x -= a[2].x; mat[2].y -= a[2].y; mat[2].z -= a[2].z;
    538 
    539     return *this;
    540 }
    541 
    542 ID_INLINE idVec3 operator*( const idVec3 &vec, const idMat3 &mat ) {
    543 	return mat * vec;
    544 }
    545 
    546 ID_INLINE idMat3 operator*( const float a, const idMat3 &mat ) {
    547 	return mat * a;
    548 }
    549 
    550 ID_INLINE idVec3 &operator*=( idVec3 &vec, const idMat3 &mat ) {
    551 	float x = mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z;
    552 	float y = mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z;
    553 	vec.z = mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z;
    554 	vec.x = x;
    555 	vec.y = y;
    556 	return vec;
    557 }
    558 
    559 ID_INLINE bool idMat3::Compare( const idMat3 &a ) const {
    560 	if ( mat[0].Compare( a[0] ) &&
    561 		mat[1].Compare( a[1] ) &&
    562 		mat[2].Compare( a[2] ) ) {
    563 		return true;
    564 	}
    565 	return false;
    566 }
    567 
    568 ID_INLINE bool idMat3::Compare( const idMat3 &a, const float epsilon ) const {
    569 	if ( mat[0].Compare( a[0], epsilon ) &&
    570 		mat[1].Compare( a[1], epsilon ) &&
    571 		mat[2].Compare( a[2], epsilon ) ) {
    572 		return true;
    573 	}
    574 	return false;
    575 }
    576 
    577 ID_INLINE bool idMat3::operator==( const idMat3 &a ) const {
    578 	return Compare( a );
    579 }
    580 
    581 ID_INLINE bool idMat3::operator!=( const idMat3 &a ) const {
    582 	return !Compare( a );
    583 }
    584 
    585 ID_INLINE void idMat3::Zero() {
    586 	memset( mat, 0, sizeof( idMat3 ) );
    587 }
    588 
    589 ID_INLINE void idMat3::Identity() {
    590 	*this = mat3_identity;
    591 }
    592 
    593 ID_INLINE bool idMat3::IsIdentity( const float epsilon ) const {
    594 	return Compare( mat3_identity, epsilon );
    595 }
    596 
    597 ID_INLINE bool idMat3::IsSymmetric( const float epsilon ) const {
    598 	if ( idMath::Fabs( mat[0][1] - mat[1][0] ) > epsilon ) {
    599 		return false;
    600 	}
    601 	if ( idMath::Fabs( mat[0][2] - mat[2][0] ) > epsilon ) {
    602 		return false;
    603 	}
    604 	if ( idMath::Fabs( mat[1][2] - mat[2][1] ) > epsilon ) {
    605 		return false;
    606 	}
    607 	return true;
    608 }
    609 
    610 ID_INLINE bool idMat3::IsDiagonal( const float epsilon ) const {
    611 	if ( idMath::Fabs( mat[0][1] ) > epsilon ||
    612 		idMath::Fabs( mat[0][2] ) > epsilon ||
    613 		idMath::Fabs( mat[1][0] ) > epsilon ||
    614 		idMath::Fabs( mat[1][2] ) > epsilon ||
    615 		idMath::Fabs( mat[2][0] ) > epsilon ||
    616 		idMath::Fabs( mat[2][1] ) > epsilon ) {
    617 		return false;
    618 	}
    619 	return true;
    620 }
    621 
    622 ID_INLINE bool idMat3::IsRotated() const {
    623 	return !Compare( mat3_identity );
    624 }
    625 
    626 ID_INLINE void idMat3::ProjectVector( const idVec3 &src, idVec3 &dst ) const {
    627 	dst.x = src * mat[ 0 ];
    628 	dst.y = src * mat[ 1 ];
    629 	dst.z = src * mat[ 2 ];
    630 }
    631 
    632 ID_INLINE void idMat3::UnprojectVector( const idVec3 &src, idVec3 &dst ) const {
    633 	dst = mat[ 0 ] * src.x + mat[ 1 ] * src.y + mat[ 2 ] * src.z;
    634 }
    635 
    636 ID_INLINE bool idMat3::FixDegeneracies() {
    637 	bool r = mat[0].FixDegenerateNormal();
    638 	r |= mat[1].FixDegenerateNormal();
    639 	r |= mat[2].FixDegenerateNormal();
    640 	return r;
    641 }
    642 
    643 ID_INLINE bool idMat3::FixDenormals() {
    644 	bool r = mat[0].FixDenormals();
    645 	r |= mat[1].FixDenormals();
    646 	r |= mat[2].FixDenormals();
    647 	return r;
    648 }
    649 
    650 ID_INLINE float idMat3::Trace() const {
    651 	return ( mat[0][0] + mat[1][1] + mat[2][2] );
    652 }
    653 
    654 ID_INLINE idMat3 idMat3::OrthoNormalize() const {
    655 	idMat3 ortho;
    656 
    657 	ortho = *this;
    658 	ortho[ 0 ].Normalize();
    659 	ortho[ 2 ].Cross( mat[ 0 ], mat[ 1 ] );
    660 	ortho[ 2 ].Normalize();
    661 	ortho[ 1 ].Cross( mat[ 2 ], mat[ 0 ] );
    662 	ortho[ 1 ].Normalize();
    663 	return ortho;
    664 }
    665 
    666 ID_INLINE idMat3 &idMat3::OrthoNormalizeSelf() {
    667 	mat[ 0 ].Normalize();
    668 	mat[ 2 ].Cross( mat[ 0 ], mat[ 1 ] );
    669 	mat[ 2 ].Normalize();
    670 	mat[ 1 ].Cross( mat[ 2 ], mat[ 0 ] );
    671 	mat[ 1 ].Normalize();
    672 	return *this;
    673 }
    674 
    675 ID_INLINE idMat3 idMat3::Transpose() const {
    676 	return idMat3(	mat[0][0], mat[1][0], mat[2][0],
    677 					mat[0][1], mat[1][1], mat[2][1],
    678 					mat[0][2], mat[1][2], mat[2][2] );
    679 }
    680 
    681 ID_INLINE idMat3 &idMat3::TransposeSelf() {
    682 	float tmp0, tmp1, tmp2;
    683 
    684 	tmp0 = mat[0][1];
    685 	mat[0][1] = mat[1][0];
    686 	mat[1][0] = tmp0;
    687 	tmp1 = mat[0][2];
    688 	mat[0][2] = mat[2][0];
    689 	mat[2][0] = tmp1;
    690 	tmp2 = mat[1][2];
    691 	mat[1][2] = mat[2][1];
    692 	mat[2][1] = tmp2;
    693 
    694 	return *this;
    695 }
    696 
    697 ID_INLINE idMat3 idMat3::Inverse() const {
    698 	idMat3 invMat;
    699 
    700 	invMat = *this;
    701 	verify( invMat.InverseSelf() );
    702 	return invMat;
    703 }
    704 
    705 ID_INLINE idMat3 idMat3::InverseFast() const {
    706 	idMat3 invMat;
    707 
    708 	invMat = *this;
    709 	verify( invMat.InverseFastSelf() );
    710 	return invMat;
    711 }
    712 
    713 ID_INLINE idMat3 idMat3::TransposeMultiply( const idMat3 &b ) const {
    714 	return idMat3(	mat[0].x * b[0].x + mat[1].x * b[1].x + mat[2].x * b[2].x,
    715 					mat[0].x * b[0].y + mat[1].x * b[1].y + mat[2].x * b[2].y,
    716 					mat[0].x * b[0].z + mat[1].x * b[1].z + mat[2].x * b[2].z,
    717 					mat[0].y * b[0].x + mat[1].y * b[1].x + mat[2].y * b[2].x,
    718 					mat[0].y * b[0].y + mat[1].y * b[1].y + mat[2].y * b[2].y,
    719 					mat[0].y * b[0].z + mat[1].y * b[1].z + mat[2].y * b[2].z,
    720 					mat[0].z * b[0].x + mat[1].z * b[1].x + mat[2].z * b[2].x,
    721 					mat[0].z * b[0].y + mat[1].z * b[1].y + mat[2].z * b[2].y,
    722 					mat[0].z * b[0].z + mat[1].z * b[1].z + mat[2].z * b[2].z );
    723 }
    724 
    725 ID_INLINE void TransposeMultiply( const idMat3 &transpose, const idMat3 &b, idMat3 &dst ) {
    726 	dst[0].x = transpose[0].x * b[0].x + transpose[1].x * b[1].x + transpose[2].x * b[2].x;
    727 	dst[0].y = transpose[0].x * b[0].y + transpose[1].x * b[1].y + transpose[2].x * b[2].y;
    728 	dst[0].z = transpose[0].x * b[0].z + transpose[1].x * b[1].z + transpose[2].x * b[2].z;
    729 	dst[1].x = transpose[0].y * b[0].x + transpose[1].y * b[1].x + transpose[2].y * b[2].x;
    730 	dst[1].y = transpose[0].y * b[0].y + transpose[1].y * b[1].y + transpose[2].y * b[2].y;
    731 	dst[1].z = transpose[0].y * b[0].z + transpose[1].y * b[1].z + transpose[2].y * b[2].z;
    732 	dst[2].x = transpose[0].z * b[0].x + transpose[1].z * b[1].x + transpose[2].z * b[2].x;
    733 	dst[2].y = transpose[0].z * b[0].y + transpose[1].z * b[1].y + transpose[2].z * b[2].y;
    734 	dst[2].z = transpose[0].z * b[0].z + transpose[1].z * b[1].z + transpose[2].z * b[2].z;
    735 }
    736 
    737 ID_INLINE idMat3 SkewSymmetric( idVec3 const &src ) {
    738 	return idMat3( 0.0f, -src.z,  src.y, src.z,   0.0f, -src.x, -src.y,  src.x,   0.0f );
    739 }
    740 
    741 ID_INLINE int idMat3::GetDimension() const {
    742 	return 9;
    743 }
    744 
    745 ID_INLINE const float *idMat3::ToFloatPtr() const {
    746 	return mat[0].ToFloatPtr();
    747 }
    748 
    749 ID_INLINE float *idMat3::ToFloatPtr() {
    750 	return mat[0].ToFloatPtr();
    751 }
    752 
    753 
    754 //===============================================================
    755 //
    756 //	idMat4 - 4x4 matrix
    757 //
    758 //===============================================================
    759 
    760 class idMat4 {
    761 public:
    762 					idMat4();
    763 					explicit idMat4( const idVec4 &x, const idVec4 &y, const idVec4 &z, const idVec4 &w );
    764 					explicit idMat4(const float xx, const float xy, const float xz, const float xw,
    765 									const float yx, const float yy, const float yz, const float yw,
    766 									const float zx, const float zy, const float zz, const float zw,
    767 									const float wx, const float wy, const float wz, const float ww );
    768 					explicit idMat4( const idMat3 &rotation, const idVec3 &translation );
    769 					explicit idMat4( const float src[ 4 ][ 4 ] );
    770 
    771 	const idVec4 &	operator[]( int index ) const;
    772 	idVec4 &		operator[]( int index );
    773 	idMat4			operator*( const float a ) const;
    774 	idVec4			operator*( const idVec4 &vec ) const;
    775 	idVec3			operator*( const idVec3 &vec ) const;
    776 	idMat4			operator*( const idMat4 &a ) const;
    777 	idMat4			operator+( const idMat4 &a ) const;
    778 	idMat4			operator-( const idMat4 &a ) const;
    779 	idMat4 &		operator*=( const float a );
    780 	idMat4 &		operator*=( const idMat4 &a );
    781 	idMat4 &		operator+=( const idMat4 &a );
    782 	idMat4 &		operator-=( const idMat4 &a );
    783 
    784 	friend idMat4	operator*( const float a, const idMat4 &mat );
    785 	friend idVec4	operator*( const idVec4 &vec, const idMat4 &mat );
    786 	friend idVec3	operator*( const idVec3 &vec, const idMat4 &mat );
    787 	friend idVec4 &	operator*=( idVec4 &vec, const idMat4 &mat );
    788 	friend idVec3 &	operator*=( idVec3 &vec, const idMat4 &mat );
    789 
    790 	bool			Compare( const idMat4 &a ) const;						// exact compare, no epsilon
    791 	bool			Compare( const idMat4 &a, const float epsilon ) const;	// compare with epsilon
    792 	bool			operator==( const idMat4 &a ) const;					// exact compare, no epsilon
    793 	bool			operator!=( const idMat4 &a ) const;					// exact compare, no epsilon
    794 
    795 	void			Zero();
    796 	void			Identity();
    797 	bool			IsIdentity( const float epsilon = MATRIX_EPSILON ) const;
    798 	bool			IsSymmetric( const float epsilon = MATRIX_EPSILON ) const;
    799 	bool			IsDiagonal( const float epsilon = MATRIX_EPSILON ) const;
    800 	bool			IsRotated() const;
    801 
    802 	void			ProjectVector( const idVec4 &src, idVec4 &dst ) const;
    803 	void			UnprojectVector( const idVec4 &src, idVec4 &dst ) const;
    804 
    805 	float			Trace() const;
    806 	float			Determinant() const;
    807 	idMat4			Transpose() const;	// returns transpose
    808 	idMat4 &		TransposeSelf();
    809 	idMat4			Inverse() const;		// returns the inverse ( m * m.Inverse() = identity )
    810 	bool			InverseSelf();		// returns false if determinant is zero
    811 	idMat4			InverseFast() const;	// returns the inverse ( m * m.Inverse() = identity )
    812 	bool			InverseFastSelf();	// returns false if determinant is zero
    813 	idMat4			TransposeMultiply( const idMat4 &b ) const;
    814 
    815 	int				GetDimension() const;
    816 
    817 	const float *	ToFloatPtr() const;
    818 	float *			ToFloatPtr();
    819 	const char *	ToString( int precision = 2 ) const;
    820 
    821 private:
    822 	idVec4			mat[ 4 ];
    823 };
    824 
    825 extern idMat4 mat4_zero;
    826 extern idMat4 mat4_identity;
    827 #define mat4_default	mat4_identity
    828 
    829 ID_INLINE idMat4::idMat4() {
    830 }
    831 
    832 ID_INLINE idMat4::idMat4( const idVec4 &x, const idVec4 &y, const idVec4 &z, const idVec4 &w ) {
    833 	mat[ 0 ] = x;
    834 	mat[ 1 ] = y;
    835 	mat[ 2 ] = z;
    836 	mat[ 3 ] = w;
    837 }
    838 
    839 ID_INLINE idMat4::idMat4( const float xx, const float xy, const float xz, const float xw,
    840 							const float yx, const float yy, const float yz, const float yw,
    841 							const float zx, const float zy, const float zz, const float zw,
    842 							const float wx, const float wy, const float wz, const float ww ) {
    843 	mat[0][0] = xx; mat[0][1] = xy; mat[0][2] = xz; mat[0][3] = xw;
    844 	mat[1][0] = yx; mat[1][1] = yy; mat[1][2] = yz; mat[1][3] = yw;
    845 	mat[2][0] = zx; mat[2][1] = zy; mat[2][2] = zz; mat[2][3] = zw;
    846 	mat[3][0] = wx; mat[3][1] = wy; mat[3][2] = wz; mat[3][3] = ww;
    847 }
    848 
    849 ID_INLINE idMat4::idMat4( const idMat3 &rotation, const idVec3 &translation ) {
    850 	// NOTE: idMat3 is transposed because it is column-major
    851 	mat[ 0 ][ 0 ] = rotation[0][0];
    852 	mat[ 0 ][ 1 ] = rotation[1][0];
    853 	mat[ 0 ][ 2 ] = rotation[2][0];
    854 	mat[ 0 ][ 3 ] = translation[0];
    855 	mat[ 1 ][ 0 ] = rotation[0][1];
    856 	mat[ 1 ][ 1 ] = rotation[1][1];
    857 	mat[ 1 ][ 2 ] = rotation[2][1];
    858 	mat[ 1 ][ 3 ] = translation[1];
    859 	mat[ 2 ][ 0 ] = rotation[0][2];
    860 	mat[ 2 ][ 1 ] = rotation[1][2];
    861 	mat[ 2 ][ 2 ] = rotation[2][2];
    862 	mat[ 2 ][ 3 ] = translation[2];
    863 	mat[ 3 ][ 0 ] = 0.0f;
    864 	mat[ 3 ][ 1 ] = 0.0f;
    865 	mat[ 3 ][ 2 ] = 0.0f;
    866 	mat[ 3 ][ 3 ] = 1.0f;
    867 }
    868 
    869 ID_INLINE idMat4::idMat4( const float src[ 4 ][ 4 ] ) {
    870 	memcpy( mat, src, 4 * 4 * sizeof( float ) );
    871 }
    872 
    873 ID_INLINE const idVec4 &idMat4::operator[]( int index ) const {
    874 	//assert( ( index >= 0 ) && ( index < 4 ) );
    875 	return mat[ index ];
    876 }
    877 
    878 ID_INLINE idVec4 &idMat4::operator[]( int index ) {
    879 	//assert( ( index >= 0 ) && ( index < 4 ) );
    880 	return mat[ index ];
    881 }
    882 
    883 ID_INLINE idMat4 idMat4::operator*( const float a ) const {
    884 	return idMat4(
    885 		mat[0].x * a, mat[0].y * a, mat[0].z * a, mat[0].w * a,
    886 		mat[1].x * a, mat[1].y * a, mat[1].z * a, mat[1].w * a,
    887 		mat[2].x * a, mat[2].y * a, mat[2].z * a, mat[2].w * a,
    888 		mat[3].x * a, mat[3].y * a, mat[3].z * a, mat[3].w * a );
    889 }
    890 
    891 ID_INLINE idVec4 idMat4::operator*( const idVec4 &vec ) const {
    892 	return idVec4(
    893 		mat[ 0 ].x * vec.x + mat[ 0 ].y * vec.y + mat[ 0 ].z * vec.z + mat[ 0 ].w * vec.w,
    894 		mat[ 1 ].x * vec.x + mat[ 1 ].y * vec.y + mat[ 1 ].z * vec.z + mat[ 1 ].w * vec.w,
    895 		mat[ 2 ].x * vec.x + mat[ 2 ].y * vec.y + mat[ 2 ].z * vec.z + mat[ 2 ].w * vec.w,
    896 		mat[ 3 ].x * vec.x + mat[ 3 ].y * vec.y + mat[ 3 ].z * vec.z + mat[ 3 ].w * vec.w );
    897 }
    898 
    899 ID_INLINE idVec3 idMat4::operator*( const idVec3 &vec ) const {
    900 	float s = mat[ 3 ].x * vec.x + mat[ 3 ].y * vec.y + mat[ 3 ].z * vec.z + mat[ 3 ].w;
    901 	if ( s == 0.0f ) {
    902 		return idVec3( 0.0f, 0.0f, 0.0f );
    903 	}
    904 	if ( s == 1.0f ) {
    905 		return idVec3(
    906 			mat[ 0 ].x * vec.x + mat[ 0 ].y * vec.y + mat[ 0 ].z * vec.z + mat[ 0 ].w,
    907 			mat[ 1 ].x * vec.x + mat[ 1 ].y * vec.y + mat[ 1 ].z * vec.z + mat[ 1 ].w,
    908 			mat[ 2 ].x * vec.x + mat[ 2 ].y * vec.y + mat[ 2 ].z * vec.z + mat[ 2 ].w );
    909 	}
    910 	else {
    911 		float invS = 1.0f / s;
    912 		return idVec3(
    913 			(mat[ 0 ].x * vec.x + mat[ 0 ].y * vec.y + mat[ 0 ].z * vec.z + mat[ 0 ].w) * invS,
    914 			(mat[ 1 ].x * vec.x + mat[ 1 ].y * vec.y + mat[ 1 ].z * vec.z + mat[ 1 ].w) * invS,
    915 			(mat[ 2 ].x * vec.x + mat[ 2 ].y * vec.y + mat[ 2 ].z * vec.z + mat[ 2 ].w) * invS );
    916 	}
    917 }
    918 
    919 ID_INLINE idMat4 idMat4::operator*( const idMat4 &a ) const {
    920 	int i, j;
    921 	const float *m1Ptr, *m2Ptr;
    922 	float *dstPtr;
    923 	idMat4 dst;
    924 
    925 	m1Ptr = reinterpret_cast<const float *>(this);
    926 	m2Ptr = reinterpret_cast<const float *>(&a);
    927 	dstPtr = reinterpret_cast<float *>(&dst);
    928 
    929 	for ( i = 0; i < 4; i++ ) {
    930 		for ( j = 0; j < 4; j++ ) {
    931 			*dstPtr = m1Ptr[0] * m2Ptr[ 0 * 4 + j ]
    932 					+ m1Ptr[1] * m2Ptr[ 1 * 4 + j ]
    933 					+ m1Ptr[2] * m2Ptr[ 2 * 4 + j ]
    934 					+ m1Ptr[3] * m2Ptr[ 3 * 4 + j ];
    935 			dstPtr++;
    936 		}
    937 		m1Ptr += 4;
    938 	}
    939 	return dst;
    940 }
    941 
    942 ID_INLINE idMat4 idMat4::operator+( const idMat4 &a ) const {
    943 	return idMat4( 
    944 		mat[0].x + a[0].x, mat[0].y + a[0].y, mat[0].z + a[0].z, mat[0].w + a[0].w,
    945 		mat[1].x + a[1].x, mat[1].y + a[1].y, mat[1].z + a[1].z, mat[1].w + a[1].w,
    946 		mat[2].x + a[2].x, mat[2].y + a[2].y, mat[2].z + a[2].z, mat[2].w + a[2].w,
    947 		mat[3].x + a[3].x, mat[3].y + a[3].y, mat[3].z + a[3].z, mat[3].w + a[3].w );
    948 }
    949     
    950 ID_INLINE idMat4 idMat4::operator-( const idMat4 &a ) const {
    951 	return idMat4( 
    952 		mat[0].x - a[0].x, mat[0].y - a[0].y, mat[0].z - a[0].z, mat[0].w - a[0].w,
    953 		mat[1].x - a[1].x, mat[1].y - a[1].y, mat[1].z - a[1].z, mat[1].w - a[1].w,
    954 		mat[2].x - a[2].x, mat[2].y - a[2].y, mat[2].z - a[2].z, mat[2].w - a[2].w,
    955 		mat[3].x - a[3].x, mat[3].y - a[3].y, mat[3].z - a[3].z, mat[3].w - a[3].w );
    956 }
    957 
    958 ID_INLINE idMat4 &idMat4::operator*=( const float a ) {
    959 	mat[0].x *= a; mat[0].y *= a; mat[0].z *= a; mat[0].w *= a;
    960 	mat[1].x *= a; mat[1].y *= a; mat[1].z *= a; mat[1].w *= a;
    961 	mat[2].x *= a; mat[2].y *= a; mat[2].z *= a; mat[2].w *= a;
    962 	mat[3].x *= a; mat[3].y *= a; mat[3].z *= a; mat[3].w *= a;
    963     return *this;
    964 }
    965 
    966 ID_INLINE idMat4 &idMat4::operator*=( const idMat4 &a ) {
    967 	*this = (*this) * a;
    968 	return *this;
    969 }
    970 
    971 ID_INLINE idMat4 &idMat4::operator+=( const idMat4 &a ) {
    972 	mat[0].x += a[0].x; mat[0].y += a[0].y; mat[0].z += a[0].z; mat[0].w += a[0].w;
    973 	mat[1].x += a[1].x; mat[1].y += a[1].y; mat[1].z += a[1].z; mat[1].w += a[1].w;
    974 	mat[2].x += a[2].x; mat[2].y += a[2].y; mat[2].z += a[2].z; mat[2].w += a[2].w;
    975 	mat[3].x += a[3].x; mat[3].y += a[3].y; mat[3].z += a[3].z; mat[3].w += a[3].w;
    976     return *this;
    977 }
    978 
    979 ID_INLINE idMat4 &idMat4::operator-=( const idMat4 &a ) {
    980 	mat[0].x -= a[0].x; mat[0].y -= a[0].y; mat[0].z -= a[0].z; mat[0].w -= a[0].w;
    981 	mat[1].x -= a[1].x; mat[1].y -= a[1].y; mat[1].z -= a[1].z; mat[1].w -= a[1].w;
    982 	mat[2].x -= a[2].x; mat[2].y -= a[2].y; mat[2].z -= a[2].z; mat[2].w -= a[2].w;
    983 	mat[3].x -= a[3].x; mat[3].y -= a[3].y; mat[3].z -= a[3].z; mat[3].w -= a[3].w;
    984     return *this;
    985 }
    986 
    987 ID_INLINE idMat4 operator*( const float a, const idMat4 &mat ) {
    988 	return mat * a;
    989 }
    990 
    991 ID_INLINE idVec4 operator*( const idVec4 &vec, const idMat4 &mat ) {
    992 	return mat * vec;
    993 }
    994 
    995 ID_INLINE idVec3 operator*( const idVec3 &vec, const idMat4 &mat ) {
    996 	return mat * vec;
    997 }
    998 
    999 ID_INLINE idVec4 &operator*=( idVec4 &vec, const idMat4 &mat ) {
   1000 	vec = mat * vec;
   1001 	return vec;
   1002 }
   1003 
   1004 ID_INLINE idVec3 &operator*=( idVec3 &vec, const idMat4 &mat ) {
   1005 	vec = mat * vec;
   1006 	return vec;
   1007 }
   1008 
   1009 ID_INLINE bool idMat4::Compare( const idMat4 &a ) const {
   1010 	dword i;
   1011 	const float *ptr1, *ptr2;
   1012 
   1013 	ptr1 = reinterpret_cast<const float *>(mat);
   1014 	ptr2 = reinterpret_cast<const float *>(a.mat);
   1015 	for ( i = 0; i < 4*4; i++ ) {
   1016 		if ( ptr1[i] != ptr2[i] ) {
   1017 			return false;
   1018 		}
   1019 	}
   1020 	return true;
   1021 }
   1022 
   1023 ID_INLINE bool idMat4::Compare( const idMat4 &a, const float epsilon ) const {
   1024 	dword i;
   1025 	const float *ptr1, *ptr2;
   1026 
   1027 	ptr1 = reinterpret_cast<const float *>(mat);
   1028 	ptr2 = reinterpret_cast<const float *>(a.mat);
   1029 	for ( i = 0; i < 4*4; i++ ) {
   1030 		if ( idMath::Fabs( ptr1[i] - ptr2[i] ) > epsilon ) {
   1031 			return false;
   1032 		}
   1033 	}
   1034 	return true;
   1035 }
   1036 
   1037 ID_INLINE bool idMat4::operator==( const idMat4 &a ) const {
   1038 	return Compare( a );
   1039 }
   1040 
   1041 ID_INLINE bool idMat4::operator!=( const idMat4 &a ) const {
   1042 	return !Compare( a );
   1043 }
   1044 
   1045 ID_INLINE void idMat4::Zero() {
   1046 	memset( mat, 0, sizeof( idMat4 ) );
   1047 }
   1048 
   1049 ID_INLINE void idMat4::Identity() {
   1050 	*this = mat4_identity;
   1051 }
   1052 
   1053 ID_INLINE bool idMat4::IsIdentity( const float epsilon ) const {
   1054 	return Compare( mat4_identity, epsilon );
   1055 }
   1056 
   1057 ID_INLINE bool idMat4::IsSymmetric( const float epsilon ) const {
   1058 	for ( int i = 1; i < 4; i++ ) {
   1059 		for ( int j = 0; j < i; j++ ) {
   1060 			if ( idMath::Fabs( mat[i][j] - mat[j][i] ) > epsilon ) {
   1061 				return false;
   1062 			}
   1063 		}
   1064 	}
   1065 	return true;
   1066 }
   1067 
   1068 ID_INLINE bool idMat4::IsDiagonal( const float epsilon ) const {
   1069 	for ( int i = 0; i < 4; i++ ) {
   1070 		for ( int j = 0; j < 4; j++ ) {
   1071 			if ( i != j && idMath::Fabs( mat[i][j] ) > epsilon ) {
   1072 				return false;
   1073 			}
   1074 		}
   1075 	}
   1076 	return true;
   1077 }
   1078 
   1079 ID_INLINE bool idMat4::IsRotated() const {
   1080 	if ( !mat[ 0 ][ 1 ] && !mat[ 0 ][ 2 ] &&
   1081 		!mat[ 1 ][ 0 ] && !mat[ 1 ][ 2 ] &&
   1082 		!mat[ 2 ][ 0 ] && !mat[ 2 ][ 1 ] ) {
   1083 		return false;
   1084 	}
   1085 	return true;
   1086 }
   1087 
   1088 ID_INLINE void idMat4::ProjectVector( const idVec4 &src, idVec4 &dst ) const {
   1089 	dst.x = src * mat[ 0 ];
   1090 	dst.y = src * mat[ 1 ];
   1091 	dst.z = src * mat[ 2 ];
   1092 	dst.w = src * mat[ 3 ];
   1093 }
   1094 
   1095 ID_INLINE void idMat4::UnprojectVector( const idVec4 &src, idVec4 &dst ) const {
   1096 	dst = mat[ 0 ] * src.x + mat[ 1 ] * src.y + mat[ 2 ] * src.z + mat[ 3 ] * src.w;
   1097 }
   1098 
   1099 ID_INLINE float idMat4::Trace() const {
   1100 	return ( mat[0][0] + mat[1][1] + mat[2][2] + mat[3][3] );
   1101 }
   1102 
   1103 ID_INLINE idMat4 idMat4::Inverse() const {
   1104 	idMat4 invMat;
   1105 
   1106 	invMat = *this;
   1107 	verify( invMat.InverseSelf() );
   1108 	return invMat;
   1109 }
   1110 
   1111 ID_INLINE idMat4 idMat4::InverseFast() const {
   1112 	idMat4 invMat;
   1113 
   1114 	invMat = *this;
   1115 	verify( invMat.InverseFastSelf() );
   1116 	return invMat;
   1117 }
   1118 
   1119 ID_INLINE idMat4 idMat3::ToMat4() const {
   1120 	// NOTE: idMat3 is transposed because it is column-major
   1121 	return idMat4(	mat[0][0],	mat[1][0],	mat[2][0],	0.0f,
   1122 					mat[0][1],	mat[1][1],	mat[2][1],	0.0f,
   1123 					mat[0][2],	mat[1][2],	mat[2][2],	0.0f,
   1124 					0.0f,		0.0f,		0.0f,		1.0f );
   1125 }
   1126 
   1127 ID_INLINE int idMat4::GetDimension() const {
   1128 	return 16;
   1129 }
   1130 
   1131 ID_INLINE const float *idMat4::ToFloatPtr() const {
   1132 	return mat[0].ToFloatPtr();
   1133 }
   1134 
   1135 ID_INLINE float *idMat4::ToFloatPtr() {
   1136 	return mat[0].ToFloatPtr();
   1137 }
   1138 
   1139 
   1140 //===============================================================
   1141 //
   1142 //	idMat5 - 5x5 matrix
   1143 //
   1144 //===============================================================
   1145 
   1146 class idMat5 {
   1147 public:
   1148 					idMat5();
   1149 					explicit idMat5( const idVec5 &v0, const idVec5 &v1, const idVec5 &v2, const idVec5 &v3, const idVec5 &v4 );
   1150 					explicit idMat5( const float src[ 5 ][ 5 ] );
   1151 
   1152 	const idVec5 &	operator[]( int index ) const;
   1153 	idVec5 &		operator[]( int index );
   1154 	idMat5			operator*( const float a ) const;
   1155 	idVec5			operator*( const idVec5 &vec ) const;
   1156 	idMat5			operator*( const idMat5 &a ) const;
   1157 	idMat5			operator+( const idMat5 &a ) const;
   1158 	idMat5			operator-( const idMat5 &a ) const;
   1159 	idMat5 &		operator*=( const float a );
   1160 	idMat5 &		operator*=( const idMat5 &a );
   1161 	idMat5 &		operator+=( const idMat5 &a );
   1162 	idMat5 &		operator-=( const idMat5 &a );
   1163 
   1164 	friend idMat5	operator*( const float a, const idMat5 &mat );
   1165 	friend idVec5	operator*( const idVec5 &vec, const idMat5 &mat );
   1166 	friend idVec5 &	operator*=( idVec5 &vec, const idMat5 &mat );
   1167 
   1168 	bool			Compare( const idMat5 &a ) const;						// exact compare, no epsilon
   1169 	bool			Compare( const idMat5 &a, const float epsilon ) const;	// compare with epsilon
   1170 	bool			operator==( const idMat5 &a ) const;					// exact compare, no epsilon
   1171 	bool			operator!=( const idMat5 &a ) const;					// exact compare, no epsilon
   1172 
   1173 	void			Zero();
   1174 	void			Identity();
   1175 	bool			IsIdentity( const float epsilon = MATRIX_EPSILON ) const;
   1176 	bool			IsSymmetric( const float epsilon = MATRIX_EPSILON ) const;
   1177 	bool			IsDiagonal( const float epsilon = MATRIX_EPSILON ) const;
   1178 
   1179 	float			Trace() const;
   1180 	float			Determinant() const;
   1181 	idMat5			Transpose() const;	// returns transpose
   1182 	idMat5 &		TransposeSelf();
   1183 	idMat5			Inverse() const;		// returns the inverse ( m * m.Inverse() = identity )
   1184 	bool			InverseSelf();		// returns false if determinant is zero
   1185 	idMat5			InverseFast() const;	// returns the inverse ( m * m.Inverse() = identity )
   1186 	bool			InverseFastSelf();	// returns false if determinant is zero
   1187 
   1188 	int				GetDimension() const;
   1189 
   1190 	const float *	ToFloatPtr() const;
   1191 	float *			ToFloatPtr();
   1192 	const char *	ToString( int precision = 2 ) const;
   1193 
   1194 private:
   1195 	idVec5			mat[ 5 ];
   1196 };
   1197 
   1198 extern idMat5 mat5_zero;
   1199 extern idMat5 mat5_identity;
   1200 #define mat5_default	mat5_identity
   1201 
   1202 ID_INLINE idMat5::idMat5() {
   1203 }
   1204 
   1205 ID_INLINE idMat5::idMat5( const float src[ 5 ][ 5 ] ) {
   1206 	memcpy( mat, src, 5 * 5 * sizeof( float ) );
   1207 }
   1208 
   1209 ID_INLINE idMat5::idMat5( const idVec5 &v0, const idVec5 &v1, const idVec5 &v2, const idVec5 &v3, const idVec5 &v4 ) {
   1210 	mat[0] = v0;
   1211 	mat[1] = v1;
   1212 	mat[2] = v2;
   1213 	mat[3] = v3;
   1214 	mat[4] = v4;
   1215 }
   1216 
   1217 ID_INLINE const idVec5 &idMat5::operator[]( int index ) const {
   1218 	//assert( ( index >= 0 ) && ( index < 5 ) );
   1219 	return mat[ index ];
   1220 }
   1221 
   1222 ID_INLINE idVec5 &idMat5::operator[]( int index ) {
   1223 	//assert( ( index >= 0 ) && ( index < 5 ) );
   1224 	return mat[ index ];
   1225 }
   1226 
   1227 ID_INLINE idMat5 idMat5::operator*( const idMat5 &a ) const {
   1228 	int i, j;
   1229 	const float *m1Ptr, *m2Ptr;
   1230 	float *dstPtr;
   1231 	idMat5 dst;
   1232 
   1233 	m1Ptr = reinterpret_cast<const float *>(this);
   1234 	m2Ptr = reinterpret_cast<const float *>(&a);
   1235 	dstPtr = reinterpret_cast<float *>(&dst);
   1236 
   1237 	for ( i = 0; i < 5; i++ ) {
   1238 		for ( j = 0; j < 5; j++ ) {
   1239 			*dstPtr = m1Ptr[0] * m2Ptr[ 0 * 5 + j ]
   1240 					+ m1Ptr[1] * m2Ptr[ 1 * 5 + j ]
   1241 					+ m1Ptr[2] * m2Ptr[ 2 * 5 + j ]
   1242 					+ m1Ptr[3] * m2Ptr[ 3 * 5 + j ]
   1243 					+ m1Ptr[4] * m2Ptr[ 4 * 5 + j ];
   1244 			dstPtr++;
   1245 		}
   1246 		m1Ptr += 5;
   1247 	}
   1248 	return dst;
   1249 }
   1250 
   1251 ID_INLINE idMat5 idMat5::operator*( const float a ) const {
   1252 	return idMat5(
   1253 		idVec5( mat[0][0] * a, mat[0][1] * a, mat[0][2] * a, mat[0][3] * a, mat[0][4] * a ),
   1254 		idVec5( mat[1][0] * a, mat[1][1] * a, mat[1][2] * a, mat[1][3] * a, mat[1][4] * a ),
   1255 		idVec5( mat[2][0] * a, mat[2][1] * a, mat[2][2] * a, mat[2][3] * a, mat[2][4] * a ),
   1256 		idVec5( mat[3][0] * a, mat[3][1] * a, mat[3][2] * a, mat[3][3] * a, mat[3][4] * a ),
   1257 		idVec5( mat[4][0] * a, mat[4][1] * a, mat[4][2] * a, mat[4][3] * a, mat[4][4] * a ) );
   1258 }
   1259 
   1260 ID_INLINE idVec5 idMat5::operator*( const idVec5 &vec ) const {
   1261 	return idVec5(
   1262 		mat[0][0] * vec[0] + mat[0][1] * vec[1] + mat[0][2] * vec[2] + mat[0][3] * vec[3] + mat[0][4] * vec[4],
   1263 		mat[1][0] * vec[0] + mat[1][1] * vec[1] + mat[1][2] * vec[2] + mat[1][3] * vec[3] + mat[1][4] * vec[4],
   1264 		mat[2][0] * vec[0] + mat[2][1] * vec[1] + mat[2][2] * vec[2] + mat[2][3] * vec[3] + mat[2][4] * vec[4],
   1265 		mat[3][0] * vec[0] + mat[3][1] * vec[1] + mat[3][2] * vec[2] + mat[3][3] * vec[3] + mat[3][4] * vec[4],
   1266 		mat[4][0] * vec[0] + mat[4][1] * vec[1] + mat[4][2] * vec[2] + mat[4][3] * vec[3] + mat[4][4] * vec[4] );
   1267 }
   1268 
   1269 ID_INLINE idMat5 idMat5::operator+( const idMat5 &a ) const {
   1270 	return idMat5(
   1271 		idVec5( mat[0][0] + a[0][0], mat[0][1] + a[0][1], mat[0][2] + a[0][2], mat[0][3] + a[0][3], mat[0][4] + a[0][4] ),
   1272 		idVec5( mat[1][0] + a[1][0], mat[1][1] + a[1][1], mat[1][2] + a[1][2], mat[1][3] + a[1][3], mat[1][4] + a[1][4] ),
   1273 		idVec5( mat[2][0] + a[2][0], mat[2][1] + a[2][1], mat[2][2] + a[2][2], mat[2][3] + a[2][3], mat[2][4] + a[2][4] ),
   1274 		idVec5( mat[3][0] + a[3][0], mat[3][1] + a[3][1], mat[3][2] + a[3][2], mat[3][3] + a[3][3], mat[3][4] + a[3][4] ),
   1275 		idVec5( mat[4][0] + a[4][0], mat[4][1] + a[4][1], mat[4][2] + a[4][2], mat[4][3] + a[4][3], mat[4][4] + a[4][4] ) );
   1276 }
   1277 
   1278 ID_INLINE idMat5 idMat5::operator-( const idMat5 &a ) const {
   1279 	return idMat5(
   1280 		idVec5( mat[0][0] - a[0][0], mat[0][1] - a[0][1], mat[0][2] - a[0][2], mat[0][3] - a[0][3], mat[0][4] - a[0][4] ),
   1281 		idVec5( mat[1][0] - a[1][0], mat[1][1] - a[1][1], mat[1][2] - a[1][2], mat[1][3] - a[1][3], mat[1][4] - a[1][4] ),
   1282 		idVec5( mat[2][0] - a[2][0], mat[2][1] - a[2][1], mat[2][2] - a[2][2], mat[2][3] - a[2][3], mat[2][4] - a[2][4] ),
   1283 		idVec5( mat[3][0] - a[3][0], mat[3][1] - a[3][1], mat[3][2] - a[3][2], mat[3][3] - a[3][3], mat[3][4] - a[3][4] ),
   1284 		idVec5( mat[4][0] - a[4][0], mat[4][1] - a[4][1], mat[4][2] - a[4][2], mat[4][3] - a[4][3], mat[4][4] - a[4][4] ) );
   1285 }
   1286 
   1287 ID_INLINE idMat5 &idMat5::operator*=( const float a ) {
   1288 	mat[0][0] *= a; mat[0][1] *= a; mat[0][2] *= a; mat[0][3] *= a; mat[0][4] *= a;
   1289 	mat[1][0] *= a; mat[1][1] *= a; mat[1][2] *= a; mat[1][3] *= a; mat[1][4] *= a;
   1290 	mat[2][0] *= a; mat[2][1] *= a; mat[2][2] *= a; mat[2][3] *= a; mat[2][4] *= a;
   1291 	mat[3][0] *= a; mat[3][1] *= a; mat[3][2] *= a; mat[3][3] *= a; mat[3][4] *= a;
   1292 	mat[4][0] *= a; mat[4][1] *= a; mat[4][2] *= a; mat[4][3] *= a; mat[4][4] *= a;
   1293 	return *this;
   1294 }
   1295 
   1296 ID_INLINE idMat5 &idMat5::operator*=( const idMat5 &a ) {
   1297 	*this = *this * a;
   1298 	return *this;
   1299 }
   1300 
   1301 ID_INLINE idMat5 &idMat5::operator+=( const idMat5 &a ) {
   1302 	mat[0][0] += a[0][0]; mat[0][1] += a[0][1]; mat[0][2] += a[0][2]; mat[0][3] += a[0][3]; mat[0][4] += a[0][4];
   1303 	mat[1][0] += a[1][0]; mat[1][1] += a[1][1]; mat[1][2] += a[1][2]; mat[1][3] += a[1][3]; mat[1][4] += a[1][4];
   1304 	mat[2][0] += a[2][0]; mat[2][1] += a[2][1]; mat[2][2] += a[2][2]; mat[2][3] += a[2][3]; mat[2][4] += a[2][4];
   1305 	mat[3][0] += a[3][0]; mat[3][1] += a[3][1]; mat[3][2] += a[3][2]; mat[3][3] += a[3][3]; mat[3][4] += a[3][4];
   1306 	mat[4][0] += a[4][0]; mat[4][1] += a[4][1]; mat[4][2] += a[4][2]; mat[4][3] += a[4][3]; mat[4][4] += a[4][4];
   1307 	return *this;
   1308 }
   1309 
   1310 ID_INLINE idMat5 &idMat5::operator-=( const idMat5 &a ) {
   1311 	mat[0][0] -= a[0][0]; mat[0][1] -= a[0][1]; mat[0][2] -= a[0][2]; mat[0][3] -= a[0][3]; mat[0][4] -= a[0][4];
   1312 	mat[1][0] -= a[1][0]; mat[1][1] -= a[1][1]; mat[1][2] -= a[1][2]; mat[1][3] -= a[1][3]; mat[1][4] -= a[1][4];
   1313 	mat[2][0] -= a[2][0]; mat[2][1] -= a[2][1]; mat[2][2] -= a[2][2]; mat[2][3] -= a[2][3]; mat[2][4] -= a[2][4];
   1314 	mat[3][0] -= a[3][0]; mat[3][1] -= a[3][1]; mat[3][2] -= a[3][2]; mat[3][3] -= a[3][3]; mat[3][4] -= a[3][4];
   1315 	mat[4][0] -= a[4][0]; mat[4][1] -= a[4][1]; mat[4][2] -= a[4][2]; mat[4][3] -= a[4][3]; mat[4][4] -= a[4][4];
   1316 	return *this;
   1317 }
   1318 
   1319 ID_INLINE idVec5 operator*( const idVec5 &vec, const idMat5 &mat ) {
   1320 	return mat * vec;
   1321 }
   1322 
   1323 ID_INLINE idMat5 operator*( const float a, idMat5 const &mat ) {
   1324 	return mat * a;
   1325 }
   1326 
   1327 ID_INLINE idVec5 &operator*=( idVec5 &vec, const idMat5 &mat ) {
   1328 	vec = mat * vec;
   1329 	return vec;
   1330 }
   1331 
   1332 ID_INLINE bool idMat5::Compare( const idMat5 &a ) const {
   1333 	dword i;
   1334 	const float *ptr1, *ptr2;
   1335 
   1336 	ptr1 = reinterpret_cast<const float *>(mat);
   1337 	ptr2 = reinterpret_cast<const float *>(a.mat);
   1338 	for ( i = 0; i < 5*5; i++ ) {
   1339 		if ( ptr1[i] != ptr2[i] ) {
   1340 			return false;
   1341 		}
   1342 	}
   1343 	return true;
   1344 }
   1345 
   1346 ID_INLINE bool idMat5::Compare( const idMat5 &a, const float epsilon ) const {
   1347 	dword i;
   1348 	const float *ptr1, *ptr2;
   1349 
   1350 	ptr1 = reinterpret_cast<const float *>(mat);
   1351 	ptr2 = reinterpret_cast<const float *>(a.mat);
   1352 	for ( i = 0; i < 5*5; i++ ) {
   1353 		if ( idMath::Fabs( ptr1[i] - ptr2[i] ) > epsilon ) {
   1354 			return false;
   1355 		}
   1356 	}
   1357 	return true;
   1358 }
   1359 
   1360 ID_INLINE bool idMat5::operator==( const idMat5 &a ) const {
   1361 	return Compare( a );
   1362 }
   1363 
   1364 ID_INLINE bool idMat5::operator!=( const idMat5 &a ) const {
   1365 	return !Compare( a );
   1366 }
   1367 
   1368 ID_INLINE void idMat5::Zero() {
   1369 	memset( mat, 0, sizeof( idMat5 ) );
   1370 }
   1371 
   1372 ID_INLINE void idMat5::Identity() {
   1373 	*this = mat5_identity;
   1374 }
   1375 
   1376 ID_INLINE bool idMat5::IsIdentity( const float epsilon ) const {
   1377 	return Compare( mat5_identity, epsilon );
   1378 }
   1379 
   1380 ID_INLINE bool idMat5::IsSymmetric( const float epsilon ) const {
   1381 	for ( int i = 1; i < 5; i++ ) {
   1382 		for ( int j = 0; j < i; j++ ) {
   1383 			if ( idMath::Fabs( mat[i][j] - mat[j][i] ) > epsilon ) {
   1384 				return false;
   1385 			}
   1386 		}
   1387 	}
   1388 	return true;
   1389 }
   1390 
   1391 ID_INLINE bool idMat5::IsDiagonal( const float epsilon ) const {
   1392 	for ( int i = 0; i < 5; i++ ) {
   1393 		for ( int j = 0; j < 5; j++ ) {
   1394 			if ( i != j && idMath::Fabs( mat[i][j] ) > epsilon ) {
   1395 				return false;
   1396 			}
   1397 		}
   1398 	}
   1399 	return true;
   1400 }
   1401 
   1402 ID_INLINE float idMat5::Trace() const {
   1403 	return ( mat[0][0] + mat[1][1] + mat[2][2] + mat[3][3] + mat[4][4] );
   1404 }
   1405 
   1406 ID_INLINE idMat5 idMat5::Inverse() const {
   1407 	idMat5 invMat;
   1408 
   1409 	invMat = *this;
   1410 	verify( invMat.InverseSelf() );
   1411 	return invMat;
   1412 }
   1413 
   1414 ID_INLINE idMat5 idMat5::InverseFast() const {
   1415 	idMat5 invMat;
   1416 
   1417 	invMat = *this;
   1418 	verify( invMat.InverseFastSelf() );
   1419 	return invMat;
   1420 }
   1421 
   1422 ID_INLINE int idMat5::GetDimension() const {
   1423 	return 25;
   1424 }
   1425 
   1426 ID_INLINE const float *idMat5::ToFloatPtr() const {
   1427 	return mat[0].ToFloatPtr();
   1428 }
   1429 
   1430 ID_INLINE float *idMat5::ToFloatPtr() {
   1431 	return mat[0].ToFloatPtr();
   1432 }
   1433 
   1434 
   1435 //===============================================================
   1436 //
   1437 //	idMat6 - 6x6 matrix
   1438 //
   1439 //===============================================================
   1440 
   1441 class idMat6 {
   1442 public:
   1443 					idMat6();
   1444 					explicit idMat6( const idVec6 &v0, const idVec6 &v1, const idVec6 &v2, const idVec6 &v3, const idVec6 &v4, const idVec6 &v5 );
   1445 					explicit idMat6( const idMat3 &m0, const idMat3 &m1, const idMat3 &m2, const idMat3 &m3 );
   1446 					explicit idMat6( const float src[ 6 ][ 6 ] );
   1447 
   1448 	const idVec6 &	operator[]( int index ) const;
   1449 	idVec6 &		operator[]( int index );
   1450 	idMat6			operator*( const float a ) const;
   1451 	idVec6			operator*( const idVec6 &vec ) const;
   1452 	idMat6			operator*( const idMat6 &a ) const;
   1453 	idMat6			operator+( const idMat6 &a ) const;
   1454 	idMat6			operator-( const idMat6 &a ) const;
   1455 	idMat6 &		operator*=( const float a );
   1456 	idMat6 &		operator*=( const idMat6 &a );
   1457 	idMat6 &		operator+=( const idMat6 &a );
   1458 	idMat6 &		operator-=( const idMat6 &a );
   1459 
   1460 	friend idMat6	operator*( const float a, const idMat6 &mat );
   1461 	friend idVec6	operator*( const idVec6 &vec, const idMat6 &mat );
   1462 	friend idVec6 &	operator*=( idVec6 &vec, const idMat6 &mat );
   1463 
   1464 	bool			Compare( const idMat6 &a ) const;						// exact compare, no epsilon
   1465 	bool			Compare( const idMat6 &a, const float epsilon ) const;	// compare with epsilon
   1466 	bool			operator==( const idMat6 &a ) const;					// exact compare, no epsilon
   1467 	bool			operator!=( const idMat6 &a ) const;					// exact compare, no epsilon
   1468 
   1469 	void			Zero();
   1470 	void			Identity();
   1471 	bool			IsIdentity( const float epsilon = MATRIX_EPSILON ) const;
   1472 	bool			IsSymmetric( const float epsilon = MATRIX_EPSILON ) const;
   1473 	bool			IsDiagonal( const float epsilon = MATRIX_EPSILON ) const;
   1474 
   1475 	idMat3			SubMat3( int n ) const;
   1476 	float			Trace() const;
   1477 	float			Determinant() const;
   1478 	idMat6			Transpose() const;	// returns transpose
   1479 	idMat6 &		TransposeSelf();
   1480 	idMat6			Inverse() const;		// returns the inverse ( m * m.Inverse() = identity )
   1481 	bool			InverseSelf();		// returns false if determinant is zero
   1482 	idMat6			InverseFast() const;	// returns the inverse ( m * m.Inverse() = identity )
   1483 	bool			InverseFastSelf();	// returns false if determinant is zero
   1484 
   1485 	int				GetDimension() const;
   1486 
   1487 	const float *	ToFloatPtr() const;
   1488 	float *			ToFloatPtr();
   1489 	const char *	ToString( int precision = 2 ) const;
   1490 
   1491 private:
   1492 	idVec6			mat[ 6 ];
   1493 };
   1494 
   1495 extern idMat6 mat6_zero;
   1496 extern idMat6 mat6_identity;
   1497 #define mat6_default	mat6_identity
   1498 
   1499 ID_INLINE idMat6::idMat6() {
   1500 }
   1501 
   1502 ID_INLINE idMat6::idMat6( const idMat3 &m0, const idMat3 &m1, const idMat3 &m2, const idMat3 &m3 ) {
   1503 	mat[0] = idVec6( m0[0][0], m0[0][1], m0[0][2], m1[0][0], m1[0][1], m1[0][2] );
   1504 	mat[1] = idVec6( m0[1][0], m0[1][1], m0[1][2], m1[1][0], m1[1][1], m1[1][2] );
   1505 	mat[2] = idVec6( m0[2][0], m0[2][1], m0[2][2], m1[2][0], m1[2][1], m1[2][2] );
   1506 	mat[3] = idVec6( m2[0][0], m2[0][1], m2[0][2], m3[0][0], m3[0][1], m3[0][2] );
   1507 	mat[4] = idVec6( m2[1][0], m2[1][1], m2[1][2], m3[1][0], m3[1][1], m3[1][2] );
   1508 	mat[5] = idVec6( m2[2][0], m2[2][1], m2[2][2], m3[2][0], m3[2][1], m3[2][2] );
   1509 }
   1510 
   1511 ID_INLINE idMat6::idMat6( const idVec6 &v0, const idVec6 &v1, const idVec6 &v2, const idVec6 &v3, const idVec6 &v4, const idVec6 &v5 ) {
   1512 	mat[0] = v0;
   1513 	mat[1] = v1;
   1514 	mat[2] = v2;
   1515 	mat[3] = v3;
   1516 	mat[4] = v4;
   1517 	mat[5] = v5;
   1518 }
   1519 
   1520 ID_INLINE idMat6::idMat6( const float src[ 6 ][ 6 ] ) {
   1521 	memcpy( mat, src, 6 * 6 * sizeof( float ) );
   1522 }
   1523 
   1524 ID_INLINE const idVec6 &idMat6::operator[]( int index ) const {
   1525 	//assert( ( index >= 0 ) && ( index < 6 ) );
   1526 	return mat[ index ];
   1527 }
   1528 
   1529 ID_INLINE idVec6 &idMat6::operator[]( int index ) {
   1530 	//assert( ( index >= 0 ) && ( index < 6 ) );
   1531 	return mat[ index ];
   1532 }
   1533 
   1534 ID_INLINE idMat6 idMat6::operator*( const idMat6 &a ) const {
   1535 	int i, j;
   1536 	const float *m1Ptr, *m2Ptr;
   1537 	float *dstPtr;
   1538 	idMat6 dst;
   1539 
   1540 	m1Ptr = reinterpret_cast<const float *>(this);
   1541 	m2Ptr = reinterpret_cast<const float *>(&a);
   1542 	dstPtr = reinterpret_cast<float *>(&dst);
   1543 
   1544 	for ( i = 0; i < 6; i++ ) {
   1545 		for ( j = 0; j < 6; j++ ) {
   1546 			*dstPtr = m1Ptr[0] * m2Ptr[ 0 * 6 + j ]
   1547 					+ m1Ptr[1] * m2Ptr[ 1 * 6 + j ]
   1548 					+ m1Ptr[2] * m2Ptr[ 2 * 6 + j ]
   1549 					+ m1Ptr[3] * m2Ptr[ 3 * 6 + j ]
   1550 					+ m1Ptr[4] * m2Ptr[ 4 * 6 + j ]
   1551 					+ m1Ptr[5] * m2Ptr[ 5 * 6 + j ];
   1552 			dstPtr++;
   1553 		}
   1554 		m1Ptr += 6;
   1555 	}
   1556 	return dst;
   1557 }
   1558 
   1559 ID_INLINE idMat6 idMat6::operator*( const float a ) const {
   1560 	return idMat6(
   1561 		idVec6( mat[0][0] * a, mat[0][1] * a, mat[0][2] * a, mat[0][3] * a, mat[0][4] * a, mat[0][5] * a ),
   1562 		idVec6( mat[1][0] * a, mat[1][1] * a, mat[1][2] * a, mat[1][3] * a, mat[1][4] * a, mat[1][5] * a ),
   1563 		idVec6( mat[2][0] * a, mat[2][1] * a, mat[2][2] * a, mat[2][3] * a, mat[2][4] * a, mat[2][5] * a ),
   1564 		idVec6( mat[3][0] * a, mat[3][1] * a, mat[3][2] * a, mat[3][3] * a, mat[3][4] * a, mat[3][5] * a ),
   1565 		idVec6( mat[4][0] * a, mat[4][1] * a, mat[4][2] * a, mat[4][3] * a, mat[4][4] * a, mat[4][5] * a ),
   1566 		idVec6( mat[5][0] * a, mat[5][1] * a, mat[5][2] * a, mat[5][3] * a, mat[5][4] * a, mat[5][5] * a ) );
   1567 }
   1568 
   1569 ID_INLINE idVec6 idMat6::operator*( const idVec6 &vec ) const {
   1570 	return idVec6(
   1571 		mat[0][0] * vec[0] + mat[0][1] * vec[1] + mat[0][2] * vec[2] + mat[0][3] * vec[3] + mat[0][4] * vec[4] + mat[0][5] * vec[5],
   1572 		mat[1][0] * vec[0] + mat[1][1] * vec[1] + mat[1][2] * vec[2] + mat[1][3] * vec[3] + mat[1][4] * vec[4] + mat[1][5] * vec[5],
   1573 		mat[2][0] * vec[0] + mat[2][1] * vec[1] + mat[2][2] * vec[2] + mat[2][3] * vec[3] + mat[2][4] * vec[4] + mat[2][5] * vec[5],
   1574 		mat[3][0] * vec[0] + mat[3][1] * vec[1] + mat[3][2] * vec[2] + mat[3][3] * vec[3] + mat[3][4] * vec[4] + mat[3][5] * vec[5],
   1575 		mat[4][0] * vec[0] + mat[4][1] * vec[1] + mat[4][2] * vec[2] + mat[4][3] * vec[3] + mat[4][4] * vec[4] + mat[4][5] * vec[5],
   1576 		mat[5][0] * vec[0] + mat[5][1] * vec[1] + mat[5][2] * vec[2] + mat[5][3] * vec[3] + mat[5][4] * vec[4] + mat[5][5] * vec[5] );
   1577 }
   1578 
   1579 ID_INLINE idMat6 idMat6::operator+( const idMat6 &a ) const {
   1580 	return idMat6(
   1581 		idVec6( mat[0][0] + a[0][0], mat[0][1] + a[0][1], mat[0][2] + a[0][2], mat[0][3] + a[0][3], mat[0][4] + a[0][4], mat[0][5] + a[0][5] ),
   1582 		idVec6( mat[1][0] + a[1][0], mat[1][1] + a[1][1], mat[1][2] + a[1][2], mat[1][3] + a[1][3], mat[1][4] + a[1][4], mat[1][5] + a[1][5] ),
   1583 		idVec6( mat[2][0] + a[2][0], mat[2][1] + a[2][1], mat[2][2] + a[2][2], mat[2][3] + a[2][3], mat[2][4] + a[2][4], mat[2][5] + a[2][5] ),
   1584 		idVec6( mat[3][0] + a[3][0], mat[3][1] + a[3][1], mat[3][2] + a[3][2], mat[3][3] + a[3][3], mat[3][4] + a[3][4], mat[3][5] + a[3][5] ),
   1585 		idVec6( mat[4][0] + a[4][0], mat[4][1] + a[4][1], mat[4][2] + a[4][2], mat[4][3] + a[4][3], mat[4][4] + a[4][4], mat[4][5] + a[4][5] ),
   1586 		idVec6( mat[5][0] + a[5][0], mat[5][1] + a[5][1], mat[5][2] + a[5][2], mat[5][3] + a[5][3], mat[5][4] + a[5][4], mat[5][5] + a[5][5] ) );
   1587 }
   1588 
   1589 ID_INLINE idMat6 idMat6::operator-( const idMat6 &a ) const {
   1590 	return idMat6(
   1591 		idVec6( mat[0][0] - a[0][0], mat[0][1] - a[0][1], mat[0][2] - a[0][2], mat[0][3] - a[0][3], mat[0][4] - a[0][4], mat[0][5] - a[0][5] ),
   1592 		idVec6( mat[1][0] - a[1][0], mat[1][1] - a[1][1], mat[1][2] - a[1][2], mat[1][3] - a[1][3], mat[1][4] - a[1][4], mat[1][5] - a[1][5] ),
   1593 		idVec6( mat[2][0] - a[2][0], mat[2][1] - a[2][1], mat[2][2] - a[2][2], mat[2][3] - a[2][3], mat[2][4] - a[2][4], mat[2][5] - a[2][5] ),
   1594 		idVec6( mat[3][0] - a[3][0], mat[3][1] - a[3][1], mat[3][2] - a[3][2], mat[3][3] - a[3][3], mat[3][4] - a[3][4], mat[3][5] - a[3][5] ),
   1595 		idVec6( mat[4][0] - a[4][0], mat[4][1] - a[4][1], mat[4][2] - a[4][2], mat[4][3] - a[4][3], mat[4][4] - a[4][4], mat[4][5] - a[4][5] ),
   1596 		idVec6( mat[5][0] - a[5][0], mat[5][1] - a[5][1], mat[5][2] - a[5][2], mat[5][3] - a[5][3], mat[5][4] - a[5][4], mat[5][5] - a[5][5] ) );
   1597 }
   1598 
   1599 ID_INLINE idMat6 &idMat6::operator*=( const float a ) {
   1600 	mat[0][0] *= a; mat[0][1] *= a; mat[0][2] *= a; mat[0][3] *= a; mat[0][4] *= a; mat[0][5] *= a;
   1601 	mat[1][0] *= a; mat[1][1] *= a; mat[1][2] *= a; mat[1][3] *= a; mat[1][4] *= a; mat[1][5] *= a;
   1602 	mat[2][0] *= a; mat[2][1] *= a; mat[2][2] *= a; mat[2][3] *= a; mat[2][4] *= a; mat[2][5] *= a;
   1603 	mat[3][0] *= a; mat[3][1] *= a; mat[3][2] *= a; mat[3][3] *= a; mat[3][4] *= a; mat[3][5] *= a;
   1604 	mat[4][0] *= a; mat[4][1] *= a; mat[4][2] *= a; mat[4][3] *= a; mat[4][4] *= a; mat[4][5] *= a;
   1605 	mat[5][0] *= a; mat[5][1] *= a; mat[5][2] *= a; mat[5][3] *= a; mat[5][4] *= a; mat[5][5] *= a;
   1606 	return *this;
   1607 }
   1608 
   1609 ID_INLINE idMat6 &idMat6::operator*=( const idMat6 &a ) {
   1610 	*this = *this * a;
   1611 	return *this;
   1612 }
   1613 
   1614 ID_INLINE idMat6 &idMat6::operator+=( const idMat6 &a ) {
   1615 	mat[0][0] += a[0][0]; mat[0][1] += a[0][1]; mat[0][2] += a[0][2]; mat[0][3] += a[0][3]; mat[0][4] += a[0][4]; mat[0][5] += a[0][5];
   1616 	mat[1][0] += a[1][0]; mat[1][1] += a[1][1]; mat[1][2] += a[1][2]; mat[1][3] += a[1][3]; mat[1][4] += a[1][4]; mat[1][5] += a[1][5];
   1617 	mat[2][0] += a[2][0]; mat[2][1] += a[2][1]; mat[2][2] += a[2][2]; mat[2][3] += a[2][3]; mat[2][4] += a[2][4]; mat[2][5] += a[2][5];
   1618 	mat[3][0] += a[3][0]; mat[3][1] += a[3][1]; mat[3][2] += a[3][2]; mat[3][3] += a[3][3]; mat[3][4] += a[3][4]; mat[3][5] += a[3][5];
   1619 	mat[4][0] += a[4][0]; mat[4][1] += a[4][1]; mat[4][2] += a[4][2]; mat[4][3] += a[4][3]; mat[4][4] += a[4][4]; mat[4][5] += a[4][5];
   1620 	mat[5][0] += a[5][0]; mat[5][1] += a[5][1]; mat[5][2] += a[5][2]; mat[5][3] += a[5][3]; mat[5][4] += a[5][4]; mat[5][5] += a[5][5];
   1621 	return *this;
   1622 }
   1623 
   1624 ID_INLINE idMat6 &idMat6::operator-=( const idMat6 &a ) {
   1625 	mat[0][0] -= a[0][0]; mat[0][1] -= a[0][1]; mat[0][2] -= a[0][2]; mat[0][3] -= a[0][3]; mat[0][4] -= a[0][4]; mat[0][5] -= a[0][5];
   1626 	mat[1][0] -= a[1][0]; mat[1][1] -= a[1][1]; mat[1][2] -= a[1][2]; mat[1][3] -= a[1][3]; mat[1][4] -= a[1][4]; mat[1][5] -= a[1][5];
   1627 	mat[2][0] -= a[2][0]; mat[2][1] -= a[2][1]; mat[2][2] -= a[2][2]; mat[2][3] -= a[2][3]; mat[2][4] -= a[2][4]; mat[2][5] -= a[2][5];
   1628 	mat[3][0] -= a[3][0]; mat[3][1] -= a[3][1]; mat[3][2] -= a[3][2]; mat[3][3] -= a[3][3]; mat[3][4] -= a[3][4]; mat[3][5] -= a[3][5];
   1629 	mat[4][0] -= a[4][0]; mat[4][1] -= a[4][1]; mat[4][2] -= a[4][2]; mat[4][3] -= a[4][3]; mat[4][4] -= a[4][4]; mat[4][5] -= a[4][5];
   1630 	mat[5][0] -= a[5][0]; mat[5][1] -= a[5][1]; mat[5][2] -= a[5][2]; mat[5][3] -= a[5][3]; mat[5][4] -= a[5][4]; mat[5][5] -= a[5][5];
   1631 	return *this;
   1632 }
   1633 
   1634 ID_INLINE idVec6 operator*( const idVec6 &vec, const idMat6 &mat ) {
   1635 	return mat * vec;
   1636 }
   1637 
   1638 ID_INLINE idMat6 operator*( const float a, idMat6 const &mat ) {
   1639 	return mat * a;
   1640 }
   1641 
   1642 ID_INLINE idVec6 &operator*=( idVec6 &vec, const idMat6 &mat ) {
   1643 	vec = mat * vec;
   1644 	return vec;
   1645 }
   1646 
   1647 ID_INLINE bool idMat6::Compare( const idMat6 &a ) const {
   1648 	dword i;
   1649 	const float *ptr1, *ptr2;
   1650 
   1651 	ptr1 = reinterpret_cast<const float *>(mat);
   1652 	ptr2 = reinterpret_cast<const float *>(a.mat);
   1653 	for ( i = 0; i < 6*6; i++ ) {
   1654 		if ( ptr1[i] != ptr2[i] ) {
   1655 			return false;
   1656 		}
   1657 	}
   1658 	return true;
   1659 }
   1660 
   1661 ID_INLINE bool idMat6::Compare( const idMat6 &a, const float epsilon ) const {
   1662 	dword i;
   1663 	const float *ptr1, *ptr2;
   1664 
   1665 	ptr1 = reinterpret_cast<const float *>(mat);
   1666 	ptr2 = reinterpret_cast<const float *>(a.mat);
   1667 	for ( i = 0; i < 6*6; i++ ) {
   1668 		if ( idMath::Fabs( ptr1[i] - ptr2[i] ) > epsilon ) {
   1669 			return false;
   1670 		}
   1671 	}
   1672 	return true;
   1673 }
   1674 
   1675 ID_INLINE bool idMat6::operator==( const idMat6 &a ) const {
   1676 	return Compare( a );
   1677 }
   1678 
   1679 ID_INLINE bool idMat6::operator!=( const idMat6 &a ) const {
   1680 	return !Compare( a );
   1681 }
   1682 
   1683 ID_INLINE void idMat6::Zero() {
   1684 	memset( mat, 0, sizeof( idMat6 ) );
   1685 }
   1686 
   1687 ID_INLINE void idMat6::Identity() {
   1688 	*this = mat6_identity;
   1689 }
   1690 
   1691 ID_INLINE bool idMat6::IsIdentity( const float epsilon ) const {
   1692 	return Compare( mat6_identity, epsilon );
   1693 }
   1694 
   1695 ID_INLINE bool idMat6::IsSymmetric( const float epsilon ) const {
   1696 	for ( int i = 1; i < 6; i++ ) {
   1697 		for ( int j = 0; j < i; j++ ) {
   1698 			if ( idMath::Fabs( mat[i][j] - mat[j][i] ) > epsilon ) {
   1699 				return false;
   1700 			}
   1701 		}
   1702 	}
   1703 	return true;
   1704 }
   1705 
   1706 ID_INLINE bool idMat6::IsDiagonal( const float epsilon ) const {
   1707 	for ( int i = 0; i < 6; i++ ) {
   1708 		for ( int j = 0; j < 6; j++ ) {
   1709 			if ( i != j && idMath::Fabs( mat[i][j] ) > epsilon ) {
   1710 				return false;
   1711 			}
   1712 		}
   1713 	}
   1714 	return true;
   1715 }
   1716 
   1717 ID_INLINE idMat3 idMat6::SubMat3( int n ) const {
   1718 	assert( n >= 0 && n < 4 );
   1719 	int b0 = ((n & 2) >> 1) * 3;
   1720 	int b1 = (n & 1) * 3;
   1721 	return idMat3(
   1722 		mat[b0 + 0][b1 + 0], mat[b0 + 0][b1 + 1], mat[b0 + 0][b1 + 2],
   1723 		mat[b0 + 1][b1 + 0], mat[b0 + 1][b1 + 1], mat[b0 + 1][b1 + 2],
   1724 		mat[b0 + 2][b1 + 0], mat[b0 + 2][b1 + 1], mat[b0 + 2][b1 + 2] );
   1725 }
   1726 
   1727 ID_INLINE float idMat6::Trace() const {
   1728 	return ( mat[0][0] + mat[1][1] + mat[2][2] + mat[3][3] + mat[4][4] + mat[5][5] );
   1729 }
   1730 
   1731 ID_INLINE idMat6 idMat6::Inverse() const {
   1732 	idMat6 invMat;
   1733 
   1734 	invMat = *this;
   1735 	verify( invMat.InverseSelf() );
   1736 	return invMat;
   1737 }
   1738 
   1739 ID_INLINE idMat6 idMat6::InverseFast() const {
   1740 	idMat6 invMat;
   1741 
   1742 	invMat = *this;
   1743 	verify( invMat.InverseFastSelf() );
   1744 	return invMat;
   1745 }
   1746 
   1747 ID_INLINE int idMat6::GetDimension() const {
   1748 	return 36;
   1749 }
   1750 
   1751 ID_INLINE const float *idMat6::ToFloatPtr() const {
   1752 	return mat[0].ToFloatPtr();
   1753 }
   1754 
   1755 ID_INLINE float *idMat6::ToFloatPtr() {
   1756 	return mat[0].ToFloatPtr();
   1757 }
   1758 
   1759 #endif /* !__MATH_MATRIX_H__ */