/* a heavily modified version of a vector library originally from Graphics Gems */ #ifndef _VECTORS_H_ #define _VECTORS_H_ #include // forward declarations template class vec4; template class mat4; enum {VX, VY, VZ, VW}; // axes // 4 element vector template class vec4 { public: T n[4]; // Constructors vec4() {}; vec4(const T& x, const T& y, const T& z, const T& w) { n[VX] = x; n[VY] = y; n[VZ] = z; n[VW] = w; }; explicit vec4(const T& d) { n[VX] = n[VY] = n[VZ] = n[VW] = d; }; // copy constructor vec4(const vec4& v) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; n[VW] = v.n[VW]; }; // Assignment operators // assignment of a vec4 vec4& operator = ( const vec4& v ) { n[VX] = v.n[VX]; n[VY] = v.n[VY]; n[VZ] = v.n[VZ]; n[VW] = v.n[VW]; return *this; }; // In-place update operators // incrementation by a vec4 vec4& operator += ( const vec4& v ) { n[VX] += v.n[VX]; n[VY] += v.n[VY]; n[VZ] += v.n[VZ]; n[VW] += v.n[VW]; return *this; }; // decrementation by a vec4 vec4& operator -= ( const vec4& v ) { n[VX] -= v.n[VX]; n[VY] -= v.n[VY]; n[VZ] -= v.n[VZ]; n[VW] -= v.n[VW]; return *this; }; // multiplication by a scalar vec4& operator *= ( const T& d ) { n[VX] *= d; n[VY] *= d; n[VZ] *= d; n[VW] *= d; return *this; }; // division by a constant vec4& operator /= ( const T& d ) { n[VX] /= d; n[VY] /= d; n[VZ] /= d; n[VW] /= d; return *this; }; // indexing T& operator [] ( int i) { return n[i]; }; T mag() { return n[VX]*n[VX] + n[VY]*n[VY] + n[VZ]*n[VZ] + n[VW]*n[VW]; } void norm() { T norm = sqrt(mag()); n[VX] /= norm; n[VY] /= norm; n[VZ] /= norm; n[VW] /= norm; } }; // vec4 friends template vec4 operator - (const vec4& a) { return vec4(-a.n[VX],-a.n[VY],-a.n[VZ],-a.n[VW]); } template vec4 operator + (const vec4& a, const vec4& b) { return vec4(a.n[VX] + b.n[VX], a.n[VY] + b.n[VY], a.n[VZ] + b.n[VZ], a.n[VW] + b.n[VW]); } template vec4 operator - (const vec4& a, const vec4& b) { return vec4(a.n[VX] - b.n[VX], a.n[VY] - b.n[VY], a.n[VZ] - b.n[VZ], a.n[VW] - b.n[VW]); } template vec4 operator * (const vec4& a, const U& d) { return vec4(d*a.n[VX], d*a.n[VY], d*a.n[VZ], d*a.n[VW] ); } template vec4 operator * (const U& d, const vec4& a) { return a*d; } template vec4 operator * (const mat4& a, const vec4& v) { #define ROWCOL(i) a.v[i].n[0]*v.n[VX] + a.v[i].n[1]*v.n[VY] \ + a.v[i].n[2]*v.n[VZ] + a.v[i].n[3]*v.n[VW] return vec4(ROWCOL(0), ROWCOL(1), ROWCOL(2), ROWCOL(3)); #undef ROWCOL } template vec4 operator * (const vec4& v, mat4& a) { return a.transpose() * v; } template T operator * (const vec4& a, const vec4& b) { return (a.n[VX]*b.n[VX] + a.n[VY]*b.n[VY] + a.n[VZ]*b.n[VZ] + a.n[VW]*b.n[VW]); } template vec4 operator / (const vec4& a, const U& d) { return vec4(a.n[VX]/d, a.n[VY]/d, a.n[VZ]/d, a.n[VW]/d); } template bool operator == (const vec4& a, const vec4& b) { return (a.n[VX] == b.n[VX]) && (a.n[VY] == b.n[VY]) && (a.n[VZ] == b.n[VZ]) && (a.n[VW] == b.n[VW]); } template bool operator != (const vec4& a, const vec4& b) { return !(a == b); } template void swap(vec4& a, vec4& b) { vec4 tmp(a); a = b; b = tmp; } template vec4 prod(const vec4& a, const vec4& b) { return vec4(a.n[VX] * b.n[VX], a.n[VY] * b.n[VY], a.n[VZ] * b.n[VZ], a.n[VW] * b.n[VW]); } // 4 x 4 matrix template class mat4 { protected: public: vec4 v[4]; // Constructors mat4() { }; mat4(const vec4& v0, const vec4& v1, const vec4& v2, const vec4& v3) { v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }; explicit mat4(const T& d) { v[0] = v[1] = v[2] = v[3] = vec4(d); }; // copy constructor mat4(const mat4& m) { v[0] = m.v[0]; v[1] = m.v[1]; v[2] = m.v[2]; v[3] = m.v[3]; }; // Assignment operators mat4& operator = ( const mat4& m ) { v[0] = m.v[0]; v[1] = m.v[1]; v[2] = m.v[2]; v[3] = m.v[3]; return *this; }; // In-place update operators // incrementation by a mat4 mat4& operator += ( const mat4& m ) { v[0] += m.v[0]; v[1] += m.v[1]; v[2] += m.v[2]; v[3] += m.v[3]; return *this; }; // decrementation by a mat4 mat4& operator -= ( const mat4& m ) { v[0] -= m.v[0]; v[1] -= m.v[1]; v[2] -= m.v[2]; v[3] -= m.v[3]; return *this; }; // multiplication by a scalar mat4& operator *= ( const T& d ) { v[0] *= d; v[1] *= d; v[2] *= d; v[3] *= d; return *this; }; // division by a scalar mat4& operator /= ( const T& d ) { v[0] /= d; v[1] /= d; v[2] /= d; v[3] /= d; return *this; }; // indexing vec4& operator [] ( int i) { return v[i]; }; // special functions mat4 transpose() { return mat4(vec4(v[0][0], v[1][0], v[2][0], v[3][0]), vec4(v[0][1], v[1][1], v[2][1], v[3][1]), vec4(v[0][2], v[1][2], v[2][2], v[3][2]), vec4(v[0][3], v[1][3], v[2][3], v[3][3])); }; #if 0 mat4 inverse() { // As a evolves from original mat into identity, // b evolves from identity into inverse(a) mat4 a(*this), b(identity3D()); int i, j, i1; // Loop over cols of a from left to right, // eliminating above and below diag for (j=0; j<4; j++) { // Find largest pivot in column j among rows j..3 i1 = j; // Row with largest pivot candidate for (i=j+1; i<4; i++) { if (fabs(a.v[i].n[j]) > fabs(a.v[i1].n[j])) i1 = i; } // Swap rows i1 and j in a and b to put pivot on diagonal swap(a.v[i1], a.v[j]); swap(b.v[i1], b.v[j]); // Scale row j to have a unit diagonal if (a.v[j].n[j]==0.) VECTOR_ERROR("mat4::inverse: singular matrix; can't invert\n"); b.v[j] /= a.v[j].n[j]; a.v[j] /= a.v[j].n[j]; // Eliminate off-diagonal elems in col j of a, doing identical ops to b for (i=0; i<4; i++) if (i!=j) { b.v[i] -= a.v[i].n[j]*b.v[j]; a.v[i] -= a.v[i].n[j]*a.v[j]; } } return b; }; #endif }; // mat4 friends template mat4 operator - (const mat4& a) { return mat4(-a.v[0], -a.v[1], -a.v[2], -a.v[3]); } template mat4 operator + (const mat4& a, const mat4& b) { return mat4(a.v[0] + b.v[0], a.v[1] + b.v[1], a.v[2] + b.v[2], a.v[3] + b.v[3]); } template mat4 operator - (const mat4& a, const mat4& b) { return mat4(a.v[0] - b.v[0], a.v[1] - b.v[1], a.v[2] - b.v[2], a.v[3] - b.v[3]); } template mat4 operator * (const mat4& ca, const mat4& cb) { mat4& a = const_cast&>(ca); mat4& b = const_cast&>(cb); #define ROWCOL(i, j) a.v[i].n[0]*b.v[0].n[j] + a.v[i].n[1]*b.v[1].n[j] + \ a.v[i].n[2]*b.v[2].n[j] + a.v[i].n[3]*b.v[3].n[j] return mat4( vec4(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2), ROWCOL(0,3)), vec4(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2), ROWCOL(1,3)), vec4(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2), ROWCOL(2,3)), vec4(ROWCOL(3,0), ROWCOL(3,1), ROWCOL(3,2), ROWCOL(3,3)) ); #undef ROWCOL } template mat4 operator * (const mat4& a, const U& d) { return mat4(a.v[0] * d, a.v[1] * d, a.v[2] * d, a.v[3] * d); } template mat4 operator * (const U& d, const mat4& a) { return a*d; } template mat4 operator / (const mat4& a, const U& d) { return mat4(a.v[0] / d, a.v[1] / d, a.v[2] / d, a.v[3] / d); } template bool operator == (const mat4& a, const mat4& b) { return ((a.v[0] == b.v[0]) && (a.v[1] == b.v[1]) && (a.v[2] == b.v[2]) && (a.v[3] == b.v[3])); } template bool operator != (const mat4& a, const mat4& b) { return !(a == b); } template void swap(mat4& a, mat4& b) { mat4 tmp(a); a = b; b = tmp; } /**************************************************************** * * * 2D functions and 3D functions * * * ****************************************************************/ template mat4 identity3D(T size = 1.0, T zero=0.0) { return mat4( vec4(size,zero,zero,zero), vec4(zero,size,zero,zero), vec4(zero,zero,size,zero), vec4(zero,zero,zero,size)); } template mat4 perspective3D(const T& d); // rotations about a plane in 4D; used for Mandelbrot weirdness template mat4 rotXY(const T& theta, T one=1.0, T zero=0.0) { T c = cos((T)theta), s = sin((T)theta); return mat4( vec4( c, -s,zero,zero), vec4( s, c,zero,zero), vec4(zero,zero, one,zero), vec4(zero,zero,zero, one)); } template mat4 rotXZ(const T& theta, T one=1.0, T zero=0.0) { T c = cos(theta), s = sin(theta); return mat4( vec4( c,zero, s,zero), vec4(zero, one,zero,zero), vec4( -s,zero, c,zero), vec4(zero,zero,zero, one)); } template mat4 rotXW(const T& theta, T one=1.0, T zero=0.0) { T c = cos(theta), s = sin(theta); return mat4( vec4( c,zero,zero, s), vec4(zero, one,zero,zero), vec4(zero,zero, one,zero), vec4( -s,zero,zero, c)); } template mat4 rotYZ(const T& theta, T one=1.0, T zero=0.0) { T c = cos(theta), s = sin(theta); return mat4( vec4( one,zero,zero,zero), vec4(zero, c, -s,zero), vec4(zero, s, c,zero), vec4(zero,zero,zero, one)); } template mat4 rotYW(const T& theta, T one=1.0, T zero=0.0) { T c = cos(theta), s = sin(theta); return mat4( vec4( one,zero,zero,zero), vec4(zero, c,zero, s), vec4(zero,zero, one,zero), vec4(zero, -s,zero, c)); } template mat4 rotZW(const T& theta, T one=1.0, T zero=0.0) { T c = cos(theta), s = sin(theta); return mat4( vec4( one,zero,zero,zero), vec4(zero, one,zero,zero), vec4(zero,zero, c, -s), vec4(zero,zero, s, c)); } typedef double d; typedef vec4 dvec4; typedef mat4 dmat4; #endif