Sirikata
|
00001 /* Sirikata Utilities -- Math Library 00002 * Matrix4x4.hpp 00003 * 00004 * Copyright (c) 2009, Daniel Reiter Horn 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions are 00009 * met: 00010 * * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * * Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in 00014 * the documentation and/or other materials provided with the 00015 * distribution. 00016 * * Neither the name of Sirikata nor the names of its contributors may 00017 * be used to endorse or promote products derived from this software 00018 * without specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 00021 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 00022 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 00023 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 00024 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00027 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00028 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00029 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 */ 00032 #ifndef _SIRIKATA_MATRIX4X4_HPP_ 00033 #define _SIRIKATA_MATRIX4X4_HPP_ 00034 00035 #include "Vector3.hpp" 00036 #include "Vector4.hpp" 00037 #include "Quaternion.hpp" 00038 00039 namespace Sirikata { 00040 00041 template <typename scalar> class Matrix4x4 { 00042 public: 00043 typedef Vector3<scalar> Vector3x; 00044 typedef Vector4<scalar> Vector4x; 00045 00046 class COLUMNS{}; 00047 class ROWS{}; 00048 00049 class COLUMN_MAJOR{}; 00050 class ROW_MAJOR{}; 00051 00052 enum Dimension { 00053 X = 0, 00054 Y = 1, 00055 Z = 2, 00056 W = 3 00057 }; 00058 private: 00059 Vector4x mCol[4]; 00060 public: 00061 typedef scalar real; 00062 Matrix4x4(){ 00063 setCol(0,Vector4x::zero()); 00064 setCol(1,Vector4x::zero()); 00065 setCol(2,Vector4x::zero()); 00066 setCol(3,Vector4x::zero()); 00067 } 00068 static const Matrix4x4& zero() { 00069 static Matrix4x4 zero_( 00070 Vector4x::zero(), 00071 Vector4x::zero(), 00072 Vector4x::zero(), 00073 Vector4x::zero(), 00074 COLUMNS() 00075 ); 00076 return zero_; 00077 } 00078 static const Matrix4x4& identity() { 00079 static Matrix4x4 identity (Vector4x::unitX(), 00080 Vector4x::unitY(), 00081 Vector4x::unitZ(), 00082 Vector4x(0, 0, 0, 1), 00083 COLUMNS()); 00084 return identity; 00085 } 00086 // Generate a matrix for swapping two dimensions. 00087 static Matrix4x4 swapDimensions(Dimension old_up, Dimension new_up) { 00088 assert(old_up != W && new_up != W); 00089 if (old_up == new_up) return identity(); 00090 Vector4x dims[3] = { Vector4x::unitX(), Vector4x::unitY(), Vector4x::unitZ() }; 00091 std::swap(dims[old_up], dims[new_up]); 00092 return Matrix4x4( 00093 dims[0], dims[1], dims[2], 00094 Vector4x(0, 0, 0, 1), 00095 COLUMNS() 00096 ); 00097 } 00098 static Matrix4x4 reflection(Dimension across) { 00099 return Matrix4x4( 00100 (across == X ? -1.f : 1.f) * Vector4x::unitX(), 00101 (across == Y ? -1.f : 1.f) * Vector4x::unitY(), 00102 (across == Z ? -1.f : 1.f) * Vector4x::unitZ(), 00103 Vector4x(0, 0, 0, 1), 00104 COLUMNS()); 00105 } 00106 static Matrix4x4 scale(Dimension dim, scalar s) { 00107 return Matrix4x4( 00108 (dim == X ? s : 1.f) * Vector4x::unitX(), 00109 (dim == Y ? s : 1.f) * Vector4x::unitY(), 00110 (dim == Z ? s : 1.f) * Vector4x::unitZ(), 00111 Vector4x(0, 0, 0, 1), 00112 COLUMNS() 00113 ); 00114 } 00115 static Matrix4x4 scale(scalar s) { 00116 return Matrix4x4( 00117 Vector4x::unitX() * s, 00118 Vector4x::unitY() * s, 00119 Vector4x::unitZ() * s, 00120 Vector4x(0, 0, 0, 1), 00121 COLUMNS() 00122 ); 00123 } 00124 static Matrix4x4 translate(const Vector3x& t) { 00125 return Matrix4x4( 00126 Vector4x(Vector3x::unitX(), 0), 00127 Vector4x(Vector3x::unitY(), 0), 00128 Vector4x(Vector3x::unitZ(), 0), 00129 Vector4x(t.x, t.y, t.z, 1), 00130 COLUMNS() 00131 ); 00132 } 00133 static Matrix4x4 rotate(const Quaternion& r) { 00134 return Matrix4x4( 00135 Vector4x(r.xAxis(), 0), 00136 Vector4x(r.yAxis(), 0), 00137 Vector4x(r.zAxis(), 0), 00138 Vector4x(0, 0, 0, 1), 00139 COLUMNS() 00140 ); 00141 } 00142 Matrix4x4(const Vector4x&col1, const Vector4x&col2, const Vector4x&col3, const Vector4x&col4, COLUMNS c){ 00143 setCol(0,col1); 00144 setCol(1,col2); 00145 setCol(2,col3); 00146 setCol(3,col4); 00147 } 00148 Matrix4x4(const Vector4x&row1, const Vector4x&row2, const Vector4x&row3, const Vector4x&row4, ROWS r){ 00149 setRow(0,row1); 00150 setRow(1,row2); 00151 setRow(2,row3); 00152 setRow(3,row4); 00153 } 00154 00155 template<typename T> 00156 Matrix4x4(const T&other, COLUMN_MAJOR c) { 00157 for(int i = 0; i < 4; i++) 00158 setCol(i, Vector4x(other[i][0], other[i][1], other[i][2], other[i][3])); 00159 } 00160 template<typename T> 00161 Matrix4x4(const T&other, ROW_MAJOR r) { 00162 for(int i = 0; i < 4; i++) 00163 setRow(i, Vector4x(other[i][0], other[i][1], other[i][2], other[i][3])); 00164 } 00165 00166 template<typename T> 00167 Matrix4x4(T* other, COLUMN_MAJOR c) { 00168 for(int i = 0; i < 4; i++) 00169 setCol(i, Vector4x(other[i*4+0], other[i*4+1], other[i*4+2], other[i*4+3])); 00170 } template<typename T> 00171 Matrix4x4(T* other, ROW_MAJOR c) { 00172 for(int i = 0; i < 4; i++) 00173 setRow(i, Vector4x(other[i*4+0], other[i*4+1], other[i*4+2], other[i*4+3])); 00174 } 00175 00176 const Vector4x& getCol(unsigned int which) const { 00177 assert(which<4); 00178 return mCol[which]; 00179 } 00180 void setCol(unsigned int which,const Vector4x &col) { 00181 assert(which<4); 00182 mCol[which]=col; 00183 } 00184 Vector4x getRow(unsigned int which) const { 00185 assert(which<4); 00186 return Vector4x(mCol[0][which], 00187 mCol[1][which], 00188 mCol[2][which], 00189 mCol[3][which]); 00190 } 00191 void setRow(unsigned int which, const Vector4x &row) { 00192 assert(which<4); 00193 mCol[0][which]=row[0]; 00194 mCol[1][which]=row[1]; 00195 mCol[2][which]=row[2]; 00196 mCol[3][which]=row[3]; 00197 } 00198 scalar&operator() (unsigned int row, unsigned int column) { 00199 return mCol[column][row]; 00200 } 00201 scalar operator() (unsigned int row, unsigned int column) const{ 00202 return mCol[column][row]; 00203 } 00204 template <typename T> Vector4<T> operator *(const Vector4<T>&other)const { 00205 return mCol[0]*other.x+mCol[1]*other.y+mCol[2]*other.z+mCol[3]*other.w; 00206 } 00207 template <typename T> Vector3<T> operator *(const Vector3<T>&other)const { 00208 Vector4<T> tmp = mCol[0]*other.x+mCol[1]*other.y+mCol[2]*other.z+mCol[3]*1.f; 00209 return Vector3<T>(tmp.x/tmp.w, tmp.y/tmp.w, tmp.z/tmp.w); 00210 } 00211 Matrix4x4 operator *(scalar other)const { 00212 return Matrix4x4(getCol(0)*other,getCol(1)*other,getCol(2)*other,getCol(3)*other,COLUMNS()); 00213 } 00214 Matrix4x4 operator /(scalar other)const { 00215 return Matrix4x4(getCol(0)/other,getCol(1)/other,getCol(2)/other,getCol(3)/other,COLUMNS()); 00216 } 00217 bool operator == (const Matrix4x4&other)const{ 00218 return getCol(0)==other.getCol(0)&&getCol(1)==other.getCol(1)&&getCol(2)==other.getCol(2)&&getCol(3)==other.getCol(3); 00219 } 00220 bool operator != (const Matrix4x4&other)const{ 00221 return getCol(0)!=other.getCol(0) || getCol(1)!=other.getCol(1) || getCol(2)!=other.getCol(2) || getCol(3)!=other.getCol(3); 00222 } 00223 Matrix4x4 operator+ (const Matrix4x4&other)const { 00224 return Matrix4x4(getCol(0)+other.getCol(0), 00225 getCol(1)+other.getCol(1), 00226 getCol(2)+other.getCol(2), 00227 getCol(3)+other.getCol(3), 00228 COLUMNS()); 00229 } 00230 Matrix4x4 operator- (const Matrix4x4&other)const { 00231 return Matrix4x4(getCol(0)-other.getCol(0), 00232 getCol(1)-other.getCol(1), 00233 getCol(2)-other.getCol(2), 00234 getCol(3)-other.getCol(3), 00235 COLUMNS()); 00236 } 00237 Matrix4x4 operator- ()const { 00238 return Matrix4x4(-getCol(0), 00239 -getCol(1), 00240 -getCol(2), 00241 -getCol(3), 00242 COLUMNS()); 00243 } 00244 Matrix4x4& operator+= (const Matrix4x4&other) { 00245 mCol[0]+=other.getCol(0); 00246 mCol[1]+=other.getCol(1); 00247 mCol[2]+=other.getCol(2); 00248 mCol[3]+=other.getCol(3); 00249 return *this; 00250 } 00251 Matrix4x4& operator-= (const Matrix4x4&other) { 00252 mCol[0]-=other.getCol(0); 00253 mCol[1]-=other.getCol(1); 00254 mCol[2]-=other.getCol(2); 00255 mCol[3]-=other.getCol(3); 00256 return *this; 00257 } 00258 Matrix4x4 operator* (const Matrix4x4&other)const { 00259 Vector4<scalar> ocol0=other.getCol(0); 00260 Vector4<scalar> ocol1=other.getCol(1); 00261 Vector4<scalar> ocol2=other.getCol(2); 00262 Vector4<scalar> ocol3=other.getCol(3); 00263 return Matrix4x4(mCol[0]*ocol0.x+mCol[1]*ocol0.y+mCol[2]*ocol0.z+mCol[3]*ocol0.w, 00264 mCol[0]*ocol1.x+mCol[1]*ocol1.y+mCol[2]*ocol1.z+mCol[3]*ocol1.w, 00265 mCol[0]*ocol2.x+mCol[1]*ocol2.y+mCol[2]*ocol2.z+mCol[3]*ocol2.w, 00266 mCol[0]*ocol3.x+mCol[1]*ocol3.y+mCol[2]*ocol3.z+mCol[3]*ocol3.w, 00267 COLUMNS()); 00268 } 00269 Matrix4x4& operator*= (const Matrix4x4&other) { 00270 Vector4<scalar> ocol0=other.getCol(0); 00271 Vector4<scalar> ocol1=other.getCol(1); 00272 Vector4<scalar> ocol2=other.getCol(2); 00273 Vector4<scalar> ocol3=other.getCol(3); 00274 //cannot do this *= inplace 00275 ocol0=mCol[0]*ocol0.x+mCol[1]*ocol0.y+mCol[2]*ocol0.z+mCol[3]*ocol0.w; 00276 ocol1=mCol[0]*ocol1.x+mCol[1]*ocol1.y+mCol[2]*ocol1.z+mCol[3]*ocol1.w; 00277 ocol2=mCol[0]*ocol2.x+mCol[1]*ocol2.y+mCol[2]*ocol2.z+mCol[3]*ocol2.w; 00278 ocol3=mCol[0]*ocol3.x+mCol[1]*ocol3.y+mCol[2]*ocol3.z+mCol[3]*ocol3.w; 00279 //have to copy back 00280 mCol[0]=ocol0; 00281 mCol[1]=ocol1; 00282 mCol[2]=ocol2; 00283 mCol[3]=ocol3; 00284 return *this; 00285 } 00286 Matrix4x4& operator*= (scalar other) { 00287 mCol[0]*=other; 00288 mCol[1]*=other; 00289 mCol[2]*=other; 00290 mCol[3]*=other; 00291 return *this; 00292 } 00293 Matrix4x4& operator/= (scalar other) { 00294 mCol[0]/=other; 00295 mCol[1]/=other; 00296 mCol[2]/=other; 00297 mCol[3]/=other; 00298 return *this; 00299 } 00300 Matrix4x4 transpose() const { 00301 return Matrix4x4(getCol(0), 00302 getCol(1), 00303 getCol(2), 00304 getCol(3), 00305 ROWS()); 00306 } 00307 00308 scalar invert(Matrix4x4& inv) const { 00309 /* Code adapted from an Intel matrix inversion optimization report 00310 (ftp://download.intel.com/design/pentiumiii/sml/24504301.pdf) */ 00311 scalar mat[16]; 00312 scalar dst[16]; 00313 00314 int counter = 0; 00315 for (int i=0; i<4; i++) { 00316 for (int j=0; j<4; j++) { 00317 mat[counter] = mCol[j][i]; 00318 counter++; 00319 } 00320 } 00321 00322 scalar tmp[12]; /* temp array for pairs */ 00323 scalar src[16]; /* array of transpose source matrix */ 00324 scalar det; /* determinant */ 00325 /* transpose matrix */ 00326 for (int i = 0; i < 4; i++) { 00327 src[i] = mat[i*4]; 00328 src[i + 4] = mat[i*4 + 1]; 00329 src[i + 8] = mat[i*4 + 2]; 00330 src[i + 12] = mat[i*4 + 3]; 00331 } 00332 /* calculate pairs for first 8 elements (cofactors) */ 00333 tmp[0] = src[10] * src[15]; 00334 tmp[1] = src[11] * src[14]; 00335 tmp[2] = src[9] * src[15]; 00336 tmp[3] = src[11] * src[13]; 00337 tmp[4] = src[9] * src[14]; 00338 tmp[5] = src[10] * src[13]; 00339 tmp[6] = src[8] * src[15]; 00340 tmp[7] = src[11] * src[12]; 00341 tmp[8] = src[8] * src[14]; 00342 tmp[9] = src[10] * src[12]; 00343 tmp[10] = src[8] * src[13]; 00344 tmp[11] = src[9] * src[12]; 00345 /* calculate first 8 elements (cofactors) */ 00346 dst[0] = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7]; 00347 dst[0] -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7]; 00348 dst[1] = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7]; 00349 dst[1] -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7]; 00350 dst[2] = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7]; 00351 dst[2] -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7]; 00352 dst[3] = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6]; 00353 dst[3] -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6]; 00354 dst[4] = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3]; 00355 dst[4] -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3]; 00356 dst[5] = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3]; 00357 dst[5] -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3]; 00358 dst[6] = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3]; 00359 dst[6] -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3]; 00360 dst[7] = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2]; 00361 dst[7] -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2]; 00362 /* calculate pairs for second 8 elements (cofactors) */ 00363 tmp[0] = src[2]*src[7]; 00364 tmp[1] = src[3]*src[6]; 00365 tmp[2] = src[1]*src[7]; 00366 tmp[3] = src[3]*src[5]; 00367 tmp[4] = src[1]*src[6]; 00368 tmp[5] = src[2]*src[5]; 00369 tmp[6] = src[0]*src[7]; 00370 tmp[7] = src[3]*src[4]; 00371 tmp[8] = src[0]*src[6]; 00372 tmp[9] = src[2]*src[4]; 00373 tmp[10] = src[0]*src[5]; 00374 tmp[11] = src[1]*src[4]; 00375 /* calculate second 8 elements (cofactors) */ 00376 dst[8] = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15]; 00377 dst[8] -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15]; 00378 dst[9] = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15]; 00379 dst[9] -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15]; 00380 dst[10] = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15]; 00381 dst[10]-= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15]; 00382 dst[11] = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14]; 00383 dst[11]-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14]; 00384 dst[12] = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9]; 00385 dst[12]-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10]; 00386 dst[13] = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10]; 00387 dst[13]-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8]; 00388 dst[14] = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8]; 00389 dst[14]-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9]; 00390 dst[15] = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9]; 00391 dst[15]-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8]; 00392 /* calculate determinant */ 00393 det=src[0]*dst[0]+src[1]*dst[1]+src[2]*dst[2]+src[3]*dst[3]; 00394 00395 if (det == 0.0) return 0.0; 00396 00397 /* calculate matrix inverse */ 00398 det = 1/det; 00399 for (int j = 0; j < 16; j++) 00400 dst[j] *= det; 00401 00402 counter = 0; 00403 for (int i=0; i<4; i++) { 00404 for (int j=0; j<4; j++) { 00405 inv(i,j) = dst[counter]; 00406 counter++; 00407 } 00408 } 00409 00410 return det; 00411 } 00412 00413 00414 Matrix3x3<scalar> extract3x3() const { 00415 Vector4x c1 = getCol(0); 00416 Vector4x c2 = getCol(1); 00417 Vector4x c3 = getCol(2); 00418 return Matrix3x3<scalar>( 00419 Vector3<scalar>(c1[0], c1[1], c1[2]), 00420 Vector3<scalar>(c2[0], c2[1], c2[2]), 00421 Vector3<scalar>(c3[0], c3[1], c3[2]), 00422 Sirikata::COLUMNS() 00423 ); 00424 } 00425 std::string toString() const { 00426 std::ostringstream os; 00427 os<<"{ col1:"<<mCol[0]<<" col2:"<<mCol[1]<<" col3:"<<mCol[2]<<" col4:"<<mCol[3]<<'}'; 00428 return os.str(); 00429 } 00430 }; 00431 template<typename scalar> inline std::ostream& operator <<(std::ostream& os, const Matrix4x4<scalar> &rhs) { 00432 os<<"{ col1:"<<rhs.getCol(0)<<" col2:"<<rhs.getCol(1)<<" col3:"<<rhs.getCol(2)<<" col4:"<<rhs.getCol(3)<<'}'; 00433 return os; 00434 } 00435 00436 template <typename T,typename S> Vector4<T> operator *(const Vector4<T>&vec, const Matrix4x4<S>&mat) { 00437 return Vector4<T>( 00438 mat.getCol(0).dot(vec), 00439 mat.getCol(1).dot(vec), 00440 mat.getCol(2).dot(vec), 00441 mat.getCol(3).dot(vec) 00442 ); 00443 } 00444 template <typename T> Matrix4x4<T> operator *(T other, const Matrix4x4<T>&mat) { 00445 return Matrix4x4<T>(mat.getCol(0)*other,mat.getCol(1)*other,mat.getCol(2)*other,mat.getCol(3)*other,COLUMNS()); 00446 } 00447 template <typename T> Matrix4x4<T> operator /(T other, const Matrix4x4<T>&mat) { 00448 return Matrix4x4<T>(other/mat.getCol(0),other/mat.getCol(1),other/mat.getCol(2),other/mat.getCol(3),COLUMNS()); 00449 } 00450 00451 typedef Matrix4x4<float32> Matrix4x4f; 00452 typedef Matrix4x4<float64> Matrix4x4d; 00453 00454 } 00455 #endif // _SIRIKATA_MATRIX4x4_HPP_