// Copyright (C) 1996 Keith Whitwell. // This file may only be copied under the terms of the GNU Library General // Public License - see the file COPYING in the lib3d distribution. #include #include #include float Matrix34::identity[3][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 } }; float Matrix4::identity[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; void Matrix34::setIdentity() { memcpy(v, identity, sizeof(v)); } void Matrix4::setIdentity() { memcpy(v, identity, sizeof(v)); } void Matrix4::mul( const Matrix4 &a, const Matrix4 &b) { for(int i=0; i<4; i++) { for(int j=0; j<4; j++) { v[j][i] = (a.v[0][i] * b.v[j][0] + a.v[1][i] * b.v[j][1] + a.v[2][i] * b.v[j][2] + a.v[3][i] * b.v[j][3]); } } } void Matrix4::premul( const Matrix4 &a ) { float t[4][4]; for(int i=0; i<4; i++) { for(int j=0; j<4; j++) { t[j][i] = (a.v[0][i] * v[j][0] + a.v[1][i] * v[j][1] + a.v[2][i] * v[j][2] + a.v[3][i] * v[j][3]); } } memcpy(v,t,sizeof(t)); } void Matrix4::mul( const Matrix34 &a, const Matrix4 &b) { v[0][0]=(a.v[0][0]*b.v[0][0] + a.v[0][1]*b.v[1][0] + a.v[0][2]*b.v[2][0] + a.v[0][3]*b.v[3][0]); v[0][1]=(a.v[0][0]*b.v[0][1] + a.v[0][1]*b.v[1][1] + a.v[0][2]*b.v[2][1] + a.v[0][3]*b.v[3][1]); v[0][2]=(a.v[0][0]*b.v[0][2] + a.v[0][1]*b.v[1][2] + a.v[0][2]*b.v[2][2] + a.v[0][3]*b.v[3][2]); v[0][3]=(a.v[0][0]*b.v[0][3] + a.v[0][1]*b.v[1][3] + a.v[0][2]*b.v[2][3] + a.v[0][3]*b.v[3][3]); v[1][0]=(a.v[1][0]*b.v[0][0] + a.v[1][1]*b.v[1][0] + a.v[1][2]*b.v[2][0] + a.v[1][3]*b.v[3][0]); v[1][1]=(a.v[1][0]*b.v[0][1] + a.v[1][1]*b.v[1][1] + a.v[1][2]*b.v[2][1] + a.v[1][3]*b.v[3][1]); v[1][2]=(a.v[1][0]*b.v[0][2] + a.v[1][1]*b.v[1][2] + a.v[1][2]*b.v[2][2] + a.v[1][3]*b.v[3][2]); v[1][3]=(a.v[1][0]*b.v[0][3] + a.v[1][1]*b.v[1][3] + a.v[1][2]*b.v[2][3] + a.v[1][3]*b.v[3][3]); v[2][0]=(a.v[2][0]*b.v[0][0] + a.v[2][1]*b.v[1][0] + a.v[2][2]*b.v[2][0] + a.v[2][3]*b.v[3][0]); v[2][1]=(a.v[2][0]*b.v[0][1] + a.v[2][1]*b.v[1][1] + a.v[2][2]*b.v[2][1] + a.v[2][3]*b.v[3][1]); v[2][2]=(a.v[2][0]*b.v[0][2] + a.v[2][1]*b.v[1][2] + a.v[2][2]*b.v[2][2] + a.v[2][3]*b.v[3][2]); v[2][3]=(a.v[2][0]*b.v[0][3] + a.v[2][1]*b.v[1][3] + a.v[2][2]*b.v[2][3] + a.v[2][3]*b.v[3][3]); v[3][0]=b.v[3][0]; v[3][1]=b.v[3][1]; v[3][2]=b.v[3][2]; v[3][3]=b.v[3][3]; } void Matrix4::mul( const Matrix4 &a, const Matrix34 &b) { v[0][0]=(a.v[0][0]*b.v[0][0] + a.v[0][1]*b.v[1][0] + a.v[0][2]*b.v[2][0]); v[0][1]=(a.v[0][0]*b.v[0][1] + a.v[0][1]*b.v[1][1] + a.v[0][2]*b.v[2][1]); v[0][2]=(a.v[0][0]*b.v[0][2] + a.v[0][1]*b.v[1][2] + a.v[0][2]*b.v[2][2]); v[0][3]=(a.v[0][0]*b.v[0][3] + a.v[0][1]*b.v[1][3] + a.v[0][2]*b.v[2][3] + a.v[0][3]); v[1][0]=(a.v[1][0]*b.v[0][0] + a.v[1][1]*b.v[1][0] + a.v[1][2]*b.v[2][0]); v[1][1]=(a.v[1][0]*b.v[0][1] + a.v[1][1]*b.v[1][1] + a.v[1][2]*b.v[2][1]); v[1][2]=(a.v[1][0]*b.v[0][2] + a.v[1][1]*b.v[1][2] + a.v[1][2]*b.v[2][2]); v[1][3]=(a.v[1][0]*b.v[0][3] + a.v[1][1]*b.v[1][3] + a.v[1][2]*b.v[2][3] + a.v[1][3]); v[2][0]=(a.v[2][0]*b.v[0][0] + a.v[2][1]*b.v[1][0] + a.v[2][2]*b.v[2][0]); v[2][1]=(a.v[2][0]*b.v[0][1] + a.v[2][1]*b.v[1][1] + a.v[2][2]*b.v[2][1]); v[2][2]=(a.v[2][0]*b.v[0][2] + a.v[2][1]*b.v[1][2] + a.v[2][2]*b.v[2][2]); v[2][3]=(a.v[2][0]*b.v[0][3] + a.v[2][1]*b.v[1][3] + a.v[2][2]*b.v[2][3] + a.v[2][3]); v[3][0]=(a.v[3][0]*b.v[0][0] + a.v[3][1]*b.v[1][0] + a.v[3][2]*b.v[2][0]); v[3][1]=(a.v[3][0]*b.v[0][1] + a.v[3][1]*b.v[1][1] + a.v[3][2]*b.v[2][1]); v[3][2]=(a.v[3][0]*b.v[0][2] + a.v[3][1]*b.v[1][2] + a.v[3][2]*b.v[2][2]); v[3][3]=(a.v[3][0]*b.v[0][3] + a.v[3][1]*b.v[1][3] + a.v[3][2]*b.v[2][3] + a.v[3][3]); } void Matrix34::mul( const Matrix34 &a, const Matrix34 &b) { v[0][0]=a.v[0][0]*b.v[0][0]+a.v[0][1]*b.v[1][0]+a.v[0][2]*b.v[2][0]; v[0][1]=a.v[0][0]*b.v[0][1]+a.v[0][1]*b.v[1][1]+a.v[0][2]*b.v[2][1]; v[0][2]=a.v[0][0]*b.v[0][2]+a.v[0][1]*b.v[1][2]+a.v[0][2]*b.v[2][2]; v[0][3]=a.v[0][0]*b.v[0][3]+a.v[0][1]*b.v[1][3]+a.v[0][2]*b.v[2][3] +a.v[0][3]; v[1][0]=a.v[1][0]*b.v[0][0]+a.v[1][1]*b.v[1][0]+a.v[1][2]*b.v[2][0]; v[1][1]=a.v[1][0]*b.v[0][1]+a.v[1][1]*b.v[1][1]+a.v[1][2]*b.v[2][1]; v[1][2]=a.v[1][0]*b.v[0][2]+a.v[1][1]*b.v[1][2]+a.v[1][2]*b.v[2][2]; v[1][3]=a.v[1][0]*b.v[0][3]+a.v[1][1]*b.v[1][3]+a.v[1][2]*b.v[2][3] +a.v[1][3]; v[2][0]=a.v[2][0]*b.v[0][0]+a.v[2][1]*b.v[1][0]+a.v[2][2]*b.v[2][0]; v[2][1]=a.v[2][0]*b.v[0][1]+a.v[2][1]*b.v[1][1]+a.v[2][2]*b.v[2][1]; v[2][2]=a.v[2][0]*b.v[0][2]+a.v[2][1]*b.v[1][2]+a.v[2][2]*b.v[2][2]; v[2][3]=a.v[2][0]*b.v[0][3]+a.v[2][1]*b.v[1][3]+a.v[2][2]*b.v[2][3] +a.v[2][3]; } void Matrix34::premul( const Matrix34 &a ) { float t[3][4]; t[0][0]=a.v[0][0]*v[0][0]+a.v[0][1]*v[1][0]+a.v[0][2]*v[2][0]; t[0][1]=a.v[0][0]*v[0][1]+a.v[0][1]*v[1][1]+a.v[0][2]*v[2][1]; t[0][2]=a.v[0][0]*v[0][2]+a.v[0][1]*v[1][2]+a.v[0][2]*v[2][2]; t[0][3]=a.v[0][0]*v[0][3]+a.v[0][1]*v[1][3]+a.v[0][2]*v[2][3]+a.v[0][3]; t[1][0]=a.v[1][0]*v[0][0]+a.v[1][1]*v[1][0]+a.v[1][2]*v[2][0]; t[1][1]=a.v[1][0]*v[0][1]+a.v[1][1]*v[1][1]+a.v[1][2]*v[2][1]; t[1][2]=a.v[1][0]*v[0][2]+a.v[1][1]*v[1][2]+a.v[1][2]*v[2][2]; t[1][3]=a.v[1][0]*v[0][3]+a.v[1][1]*v[1][3]+a.v[1][2]*v[2][3]+a.v[1][3]; t[2][0]=a.v[2][0]*v[0][0]+a.v[2][1]*v[1][0]+a.v[2][2]*v[2][0]; t[2][1]=a.v[2][0]*v[0][1]+a.v[2][1]*v[1][1]+a.v[2][2]*v[2][1]; t[2][2]=a.v[2][0]*v[0][2]+a.v[2][1]*v[1][2]+a.v[2][2]*v[2][2]; t[2][3]=a.v[2][0]*v[0][3]+a.v[2][1]*v[1][3]+a.v[2][2]*v[2][3]+a.v[2][3]; memcpy(v,t,sizeof(t)); } void Matrix34::postmul( const Matrix34 &a ) { float t[3][4]; t[0][0]=v[0][0]*a.v[0][0]+v[0][1]*a.v[1][0]+v[0][2]*a.v[2][0]; t[0][1]=v[0][0]*a.v[0][1]+v[0][1]*a.v[1][1]+v[0][2]*a.v[2][1]; t[0][2]=v[0][0]*a.v[0][2]+v[0][1]*a.v[1][2]+v[0][2]*a.v[2][2]; t[0][3]=v[0][0]*a.v[0][3]+v[0][1]*a.v[1][3]+v[0][2]*a.v[2][3]+v[0][3]; t[1][0]=v[1][0]*a.v[0][0]+v[1][1]*a.v[1][0]+v[1][2]*a.v[2][0]; t[1][1]=v[1][0]*a.v[0][1]+v[1][1]*a.v[1][1]+v[1][2]*a.v[2][1]; t[1][2]=v[1][0]*a.v[0][2]+v[1][1]*a.v[1][2]+v[1][2]*a.v[2][2]; t[1][3]=v[1][0]*a.v[0][3]+v[1][1]*a.v[1][3]+v[1][2]*a.v[2][3]+v[1][3]; t[2][0]=v[2][0]*a.v[0][0]+v[2][1]*a.v[1][0]+v[2][2]*a.v[2][0]; t[2][1]=v[2][0]*a.v[0][1]+v[2][1]*a.v[1][1]+v[2][2]*a.v[2][1]; t[2][2]=v[2][0]*a.v[0][2]+v[2][1]*a.v[1][2]+v[2][2]*a.v[2][2]; t[2][3]=v[2][0]*a.v[0][3]+v[2][1]*a.v[1][3]+v[2][2]*a.v[2][3]+v[2][3]; memcpy(v,t,sizeof(t)); } void Matrix34::setTranslation( float x, float y, float z ) { setIdentity(); v[0][3] = x; v[1][3] = y; v[2][3] = z; } void Matrix34::setScale( float x, float y, float z ) { setIdentity(); v[0][0] = x; v[1][1] = y; v[2][2] = z; } void Matrix4::setTranslation( float x, float y, float z ) { setIdentity(); v[0][3] = x; v[1][3] = y; v[2][3] = z; } void Matrix4::setScale( float x, float y, float z ) { setIdentity(); v[0][0] = x; v[1][1] = y; v[2][2] = z; } inline float cot( float x ) { return cos(x)/sin(x); } // Note that the position of the near plane in this cvv is variable and // must be remembered. The far plane is fixed at Z = 1. // dimension is the size of the square at the near plane which will be // visible. This transformation should always be mapped onto a // square device window. float Matrix34::setToCvv(float near, float far, float dimension) { float h = dimension / 2; setIdentity(); v[0][0] = near/(h*far); v[1][1] = near/(h*far); v[2][2] = 1/far; return near * v[2][2]; // Position of the near plane in the cvv. } /* // Also only makes sense for square device windows. float Matrix34::setToNffCvv(float near, float far, float angle) { float h = near * sin(angle * (M_PI / 180.0)); setIdentity(); v[0][0] = near/(h*far); v[1][1] = near/(h*far); v[2][2] = 1/far; return near * v[2][2]; // Position of the near plane in the cvv. } // this would work with rectangular windows, perhaps a little clumsy float Matrix34::setToCvv(float near, float far, float xdim, float ydim) { float n = 2*near; setIdentity(); v[0][0] = n/(xdim*far); v[1][1] = n/(ydim*far); v[2][2] = 1/far; return near * v[2][2]; } */ float Matrix34::setToCvv(float near, float far, float angle, float aspect) { float h = tan(angle * (M_PI / 180.0)); setIdentity(); v[0][0] = 1/(aspect*h*far); v[1][1] = 1/(h*far); v[2][2] = 1/far; return near * v[2][2]; // Position of the near plane in the cvv. } void Matrix4::setCvvPerspective(float D) { setIdentity(); v[0][0] = 1; v[1][1] = 1; v[2][2] = 1 / (1 - D); v[3][2] = 1; v[2][3] = - D / (1 - D); v[3][3] = 0; } void Matrix4::setPerspective(float d, float f, float dimension) { float h = dimension / 2; setIdentity(); v[0][0] = d/h; v[1][1] = d/h; v[2][2] = f / (f - d); v[3][2] = 1; v[2][3] = - f * d / (f - d); v[3][3] = 0; } // Adapted from Mesa. Find matrix inverse by Gaussian elimination. // This function isn't used in the current renderer. void Matrix4::invert( const Matrix4 &source ) { Matrix4 tmp = source; setIdentity(); for (int i = 0; i < 4; i++) { int ind = i; float val = tmp.v[i][i]; // Find largest value for this row. int j; for (j = i + 1; j < 4; j++) { if (fabs(tmp.v[j][i]) > fabs(val)) { ind = j; val = tmp.v[j][i]; } } // A row of zeros -> the matrix has no inverse. if (val == 0.0F) { setIdentity(); return; } // Move the largest value for the row to the diagonal axis, if // it isn't already there. if (ind != i) { for (int row = 0; row < 4; row++) { float val2; val2 = v[i][row]; v[i][row] = v[ind][row]; v[ind][row] = val2; val2 = tmp.v[i][row]; tmp.v[i][row] = tmp.v[ind][row]; tmp.v[ind][row] = val2; } } // Scale the row so that the entry on the diagonal axis becomes 1. float ival = 1/val; for ( j = 0 ; j < 4 ; j++) { tmp.v[j][i] *= ival; v[j][i] *= ival; } // Add multiples of the scaled row to elminate nonzero entries // in the current axis column. for ( j = 0 ; j < 4 ; j++) { if (j == i) continue; val = tmp.v[i][j]; for (int k = 0; k < 4; k++) { tmp.v[k][j] -= tmp.v[k][i] * val; v[k][j] -= v[k][i] * val; } } } } // Adapted from Graphic Gems 2: // // matrix34_inverse // // This procedure treats the 3 by 4 matrix as a block matrix and // calculates the inverse of one submatrix for a significant perform- // ance improvement over a general procedure that can invert any non- // singular matrix: // -- -- -- -- // | | -1 | -1 -1 | // | A C | | A -C A | // -1 | | | | // M = |----------| = |-----------------| // | 0 1 | | 0 1 | (implicit values) // | | | | // -- -- -- -- // // where M is a 4 by 4 matrix, // A is the 3 by 3 upper left submatrix of M, // C is the 3 by 1 upper right submatrix of M. // void Matrix34::invert( const Matrix34 &m ) { float pos, neg, t; // Calculate the determinant of submatrix A and determine if the // the matrix is singular as limited by the double precision // floating-point data representation. pos = neg = 0.0; t = m.v[0][0] * m.v[1][1] * m.v[2][2]; if (t >= 0.0) pos += t; else neg += t; t = m.v[1][0] * m.v[2][1] * m.v[0][2]; if (t >= 0.0) pos += t; else neg += t; t = m.v[2][0] * m.v[0][1] * m.v[1][2]; if (t >= 0.0) pos += t; else neg += t; t = -m.v[2][0] * m.v[1][1] * m.v[0][2]; if (t >= 0.0) pos += t; else neg += t; t = -m.v[1][0] * m.v[0][1] * m.v[2][2]; if (t >= 0.0) pos += t; else neg += t; t = -m.v[0][0] * m.v[2][1] * m.v[1][2]; if (t >= 0.0) pos += t; else neg += t; float det = pos + neg; // Is the submatrix A singular? if (fabs(det) < ((pos - neg) * 1.0e-12)) { setIdentity(); return; } // Calculate inverse(A) = adj(A) / det(A) float det_1 = 1.0 / det; v[0][0] = ( (m.v[1][1]*m.v[2][2] - m.v[2][1]*m.v[1][2] )*det_1); v[0][1] = (- (m.v[0][1]*m.v[2][2] - m.v[2][1]*m.v[0][2] )*det_1); v[0][2] = ( (m.v[0][1]*m.v[1][2] - m.v[1][1]*m.v[0][2] )*det_1); v[1][0] = (- (m.v[1][0]*m.v[2][2] - m.v[2][0]*m.v[1][2] )*det_1); v[1][1] = ( (m.v[0][0]*m.v[2][2] - m.v[2][0]*m.v[0][2] )*det_1); v[1][2] = (- (m.v[0][0]*m.v[1][2] - m.v[1][0]*m.v[0][2] )*det_1); v[2][0] = ( (m.v[1][0]*m.v[2][1] - m.v[2][0]*m.v[1][1] )*det_1); v[2][1] = (- (m.v[0][0]*m.v[2][1] - m.v[2][0]*m.v[0][1] )*det_1); v[2][2] = ( (m.v[0][0]*m.v[1][1] - m.v[1][0]*m.v[0][1] )*det_1); /* Calculate -C * inverse(A) */ v[0][3] = - (m.v[0][3] * v[0][0] + m.v[1][3] * v[0][1] + m.v[2][3] * v[0][2] ); v[1][3] = - (m.v[0][3] * v[1][0] + m.v[1][3] * v[1][1] + m.v[2][3] * v[1][2] ); v[2][3] = - (m.v[0][3] * v[2][0] + m.v[1][3] * v[2][1] + m.v[2][3] * v[2][2] ); } // Adapted from Graphics Gems IV: // // Computes the inverse of a 3-D angle-preserving matrix. // // This procedure treats the 4 by 4 angle-preserving matrix as a block // matrix and calculates the inverse of one submatrix for a significant // performance improvement over a general procedure that can invert any // nonsingular matrix: // -- -- -- -- // | | -1 | -2 T -2 T | // | A C | | s A - s A C | // -1 | | | | // M = |----------| = |---------------------| // | 0 1 | | 0 1 | (implicit values) // | | | | // -- -- -- -- // where M is a 4 by 4 angle-preserving matrix, // A is the 3 by 3 upper-left submatrix of M, // C is the 3 by 1 upper-right submatrix of M. // void Matrix34::invert_ap( const Matrix34 &source ) { float scale; // Calculate the square of the isotropic scale factor. scale = source.v[0][0] * source.v[0][0] + source.v[0][1] * source.v[0][1] + source.v[0][2] * source.v[0][2]; // Is the submatrix A singular? if (scale == 0.0) { setIdentity(); // No inverse. return; } // Calculate the inverse of the square of the isotropic scale factor. scale = 1.0 / scale; // Transpose and scale the 3 by 3 upper-left submatrix. v[0][0] = scale * source.v[0][0]; v[1][0] = scale * source.v[0][1]; v[2][0] = scale * source.v[0][2]; v[0][1] = scale * source.v[1][0]; v[1][1] = scale * source.v[1][1]; v[2][1] = scale * source.v[1][2]; v[0][2] = scale * source.v[2][0]; v[1][2] = scale * source.v[2][1]; v[2][2] = scale * source.v[2][2]; // Calculate -(transpose(A) / s*s) C v[0][3] = - (v[0][0] * source.v[0][3] + v[0][1] * source.v[1][3] + v[0][2] * source.v[2][3]); v[1][3] = - (v[1][0] * source.v[0][3] + v[1][1] * source.v[1][3] + v[1][2] * source.v[2][3]); v[2][3] = - (v[2][0] * source.v[0][3] + v[2][1] * source.v[1][3] + v[2][2] * source.v[2][3]); } // Adapted from contribution to Mesa by Erich Boleyn (erich@uruk.org). void Matrix4::setRotation( float angle, float x, float y, float z ) { float mag, s, c; float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; s = sin( angle * (M_PI / 180.0) ); c = cos( angle * (M_PI / 180.0) ); mag = sqrt( x*x + y*y + z*z ); if (mag != 0.0) { x /= mag; y /= mag; z /= mag; xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * s; ys = y * s; zs = z * s; one_c = 1.0F - c; v[0][0] = (one_c * xx) + c; v[1][0] = (one_c * xy) - zs; v[2][0] = (one_c * zx) + ys; v[3][0] = 0.0F; v[0][1] = (one_c * xy) + zs; v[1][1] = (one_c * yy) + c; v[2][1] = (one_c * yz) - xs; v[3][1] = 0.0F; v[0][2] = (one_c * zx) - ys; v[1][2] = (one_c * yz) + xs; v[2][2] = (one_c * zz) + c; v[3][2] = 0.0F; v[0][3] = 0.0F; v[1][3] = 0.0F; v[2][3] = 0.0F; v[3][3] = 1.0F; return; } setIdentity(); } void Matrix34::setRotation( float angle, float x, float y, float z ) { float mag, s, c; float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; s = sin( angle * (M_PI / 180.0) ); c = cos( angle * (M_PI / 180.0) ); mag = sqrt( x*x + y*y + z*z ); if (mag != 0.0) { x /= mag; y /= mag; z /= mag; xx = x * x; yy = y * y; zz = z * z; xy = x * y; yz = y * z; zx = z * x; xs = x * s; ys = y * s; zs = z * s; one_c = 1.0F - c; v[0][0] = (one_c * xx) + c; v[1][0] = (one_c * xy) - zs; v[2][0] = (one_c * zx) + ys; v[0][1] = (one_c * xy) + zs; v[1][1] = (one_c * yy) + c; v[2][1] = (one_c * yz) - xs; v[0][2] = (one_c * zx) - ys; v[1][2] = (one_c * yz) + xs; v[2][2] = (one_c * zz) + c; v[0][3] = 0.0F; v[1][3] = 0.0F; v[2][3] = 0.0F; return; } setIdentity(); } void Matrix34::setRotationNormalized(float c, float s, Vector3 axis) { float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; xx = axis.v[X] * axis.v[X]; yy = axis.v[Y] * axis.v[Y]; zz = axis.v[Z] * axis.v[Z]; xy = axis.v[X] * axis.v[Y]; yz = axis.v[Y] * axis.v[Z]; zx = axis.v[Z] * axis.v[X]; xs = axis.v[X] * s; ys = axis.v[Y] * s; zs = axis.v[Z] * s; one_c = 1.0F - c; v[0][0] = (one_c * xx) + c; v[1][0] = (one_c * xy) - zs; v[2][0] = (one_c * zx) + ys; v[0][1] = (one_c * xy) + zs; v[1][1] = (one_c * yy) + c; v[2][1] = (one_c * yz) - xs; v[0][2] = (one_c * zx) - ys; v[1][2] = (one_c * yz) + xs; v[2][2] = (one_c * zz) + c; v[0][3] = 0.0F; v[1][3] = 0.0F; v[2][3] = 0.0F; } void Matrix4::scale(float xf, float yf, float zf) { v[0][0] *= xf; v[0][1] *= xf; v[0][2] *= xf; v[0][3] *= xf; v[1][0] *= yf; v[1][1] *= yf; v[1][2] *= yf; v[1][3] *= yf; v[2][0] *= zf; v[2][1] *= zf; v[2][2] *= zf; v[2][3] *= zf; } void Matrix4::translate(float x, float y, float z) { v[0][3] += x; v[1][3] += y; v[2][3] += z; } void Matrix34::translate(float x, float y, float z) { v[0][3] += x; v[1][3] += y; v[2][3] += z; } void Matrix34::scale(float xf, float yf, float zf) { v[0][0] *= xf; v[0][1] *= xf; v[0][2] *= xf; v[0][3] *= xf; v[1][0] *= yf; v[1][1] *= yf; v[1][2] *= yf; v[1][3] *= yf; v[2][0] *= zf; v[2][1] *= zf; v[2][2] *= zf; v[2][3] *= zf; } void Matrix34::setLookAt(const Vector3 &vrp, const Vector3 &at, const Vector3 &up ) { Vector3 n; n.sub(at, vrp); n.normalize(); Vector3 V; V.sub(up, vrp); float d = dot( V, n ); // Make v orthogonal to n and normalize. V.v[X] -= d * n.v[X]; V.v[Y] -= d * n.v[Y]; V.v[Z] -= d * n.v[Z]; V.normalize(); Vector3 u; u.cross( V, n ); // Complete the coordinate system. v[0][0] = u.v[X]; v[0][1] = u.v[Y]; v[0][2] = u.v[Z]; v[1][0] = V.v[X]; v[1][1] = V.v[Y]; v[1][2] = V.v[Z]; v[2][0] = n.v[X]; v[2][1] = n.v[Y]; v[2][2] = n.v[Z]; v[0][3] = - (u.v[X]*vrp.v[X] + u.v[Y]*vrp.v[Y] + u.v[Z] * vrp.v[Z]); v[1][3] = - (V.v[X]*vrp.v[X] + V.v[Y]*vrp.v[Y] + V.v[Z] * vrp.v[Z]); v[2][3] = - (n.v[X]*vrp.v[X] + n.v[Y]*vrp.v[Y] + n.v[Z] * vrp.v[Z]); } ostream & operator<<( ostream &out, const Matrix34 &m ) { out.precision(3); out <<"\n\t|" << m.v[0][0] <<"\t"<< m.v[1][0] <<"\t"<< m.v[2][0] <<"\t(0) | "; out <<"\n\t|" << m.v[0][1] <<"\t"<< m.v[1][1] <<"\t"<< m.v[2][1] <<"\t(0) | "; out <<"\n\t|" << m.v[0][2] <<"\t"<< m.v[1][2] <<"\t"<< m.v[2][2] <<"\t(0) | "; out <<"\n\t|" << m.v[0][3] <<"\t"<< m.v[1][3] <<"\t"<< m.v[2][3] <<"\t(1) | "; return out; } ostream & operator<<( ostream &out, const Matrix4 &m ) { out.precision(3); out <<"\n\t|" << m.v[0][0] <<"\t"<< m.v[1][0] <<"\t"<< m.v[2][0] <<"\t"<< m.v[3][0] <<" | "; out <<"\n\t|" << m.v[0][1] <<"\t"<< m.v[1][1] <<"\t"<< m.v[2][1] <<"\t"<< m.v[3][1] <<"| "; out <<"\n\t|" << m.v[0][2] <<"\t"<< m.v[1][2] <<"\t"<< m.v[2][2] <<"\t"<< m.v[3][2] <<"| "; out <<"\n\t|" << m.v[0][3] <<"\t"<< m.v[1][3] <<"\t"<< m.v[2][3] <<"\t"<< m.v[3][3] <<"| "; return out; } #if 0 ostream & operator<<( ostream &out, const Matrix34 &m ) { out.precision(3); out <<"\n\t|" << m.v[0][0] <<"\t"<< m.v[0][1] <<"\t"<< m.v[0][2] <<"\t"<< m.v[0][3] <<" | "; out <<"\n\t|" << m.v[1][0] <<"\t"<< m.v[1][1] <<"\t"<< m.v[1][2] <<"\t"<< m.v[1][3] <<"| "; out <<"\n\t|" << m.v[2][0] <<"\t"<< m.v[2][1] <<"\t"<< m.v[2][2] <<"\t"<< m.v[2][3] <<"| "; out <<"\n\t(0) \t(0) \t(0) \t(1)" <<"| "; return out; } ostream & operator<<( ostream &out, const Matrix4 &m ) { out.precision(3); out <<"\n\t|" << m.v[0][0] <<"\t"<< m.v[0][1] <<"\t"<< m.v[0][2] <<"\t"<< m.v[0][3] <<" | "; out <<"\n\t|" << m.v[1][0] <<"\t"<< m.v[1][1] <<"\t"<< m.v[1][2] <<"\t"<< m.v[1][3] <<"| "; out <<"\n\t|" << m.v[2][0] <<"\t"<< m.v[2][1] <<"\t"<< m.v[2][2] <<"\t"<< m.v[2][3] <<"| "; out <<"\n\t|" << m.v[3][0] <<"\t"<< m.v[3][1] <<"\t"<< m.v[3][2] <<"\t"<< m.v[3][3] <<"| "; return out; } #endif // See graphics gems 3. void Matrix34::setArcBallIncrement(float Radius, int dx, int dy) { float dr, denom, cos_theta, sin_theta; Vector3 n; if (dx == 0 && dy == 0) { setIdentity(); return; } dr = sqrt((float)(dx*dx + dy*dy)); denom = sqrt(Radius*Radius + dr*dr); cos_theta = Radius/denom; sin_theta = dr/denom; n.v[0] = -float(dy)/dr; /* r-h coord system. */ n.v[1] = float(dx)/dr; n.v[2] = 0.0; setRotationNormalized(cos_theta, sin_theta, n); }