Code Sample
Below is a small sample of code, namely vector and matrix classes. I developed these to help with basic linear algebra, and to use seamlessly with OpenGL. Some examples of how these are used are in the Cube World project.
vec4.h
/* * To avoid normalization problems, addition, subtraction, * scalar multiplication & division, dot & cross products * are calculated using xyz only, not w. */ #ifndef Vec4_H #define Vec4_H #include <iostream> #include <sstream> #include <math.h> #include <string> #include <assert.h> template <class T> class Vec4{ public: union{ struct {T x, y, z, w;}; struct {T r, g, b, a;}; struct {T s, t, p, q;}; T v[4]; }; //constructors inline Vec4<T>(T x=0, T y=0, T z=0, T w=0); inline Vec4<T>(const Vec4<T> &r); inline ~Vec4<T>(); inline T &operator[](int index); inline operator T*(); inline bool operator==(const Vec4<T> &r)const; inline bool operator!=(const Vec4<T> &r)const; inline Vec4<T> &operator=(const Vec4<T> &r); template<class U> inline Vec4<T> &operator=(const Vec4<U> &r); template<class U> inline Vec4<T> &operator=(const U r[4]); template<class U> inline Vec4<T> &operator+=(const Vec4<U> &r); template<class U> inline Vec4<T> operator+(const Vec4<U> &r)const; template<class U> inline Vec4<T> &operator-=(const Vec4<U> &r); template<class U> inline Vec4<T> operator-(const Vec4<U> &r)const; template<class U> inline Vec4<T> &operator*=(const Vec4<U> &r); template<class U> inline Vec4<T> operator*(const Vec4<U> &r)const; template<class U> inline Vec4<T> &operator/=(const Vec4<U> &r); template<class U> inline Vec4<T> operator/(const Vec4<U> &r)const; inline Vec4<T> &operator*=(double scalar); inline Vec4<T> operator*(double scalar)const; inline Vec4<T> &operator/=(double scalar); inline Vec4<T> operator/(double scalar)const; inline T magnitude()const; inline Vec4<T> &normalize(); inline Vec4<T> ÷W(); std::string toString(); }; template<class T> inline Vec4<T>::Vec4(T x=0, T y=0, T z=0, T w=0) : x(x), y(y), z(z), w(w){ } template<class T> inline Vec4<T>::Vec4(const Vec4<T> &r) : x(r.x), y(r.y), z(r.z), w(r.w){ } template<class T> inline Vec4<T>::~Vec4(){ } template<class T> inline T &Vec4<T>::operator[](int index){ assert(index <= 3); return v[index]; } template<class T> inline Vec4<T>::operator T*(){ return &x; } template<class T> inline bool Vec4<T>::operator==(const Vec4<T> &r)const{ if(x == r.x && y == r.y && z == r.z && w == r.w) return true; return false; } template<class T> inline bool Vec4<T>::operator!=(const Vec4<T> &r)const{ return !((*this)==r); } template<class T> inline Vec4<T> &Vec4<T>::operator=(const Vec4<T> &r){ if(this != &r){ x = r.x; y = r.y; z = r.z; w = r.w; } return *this; } template<class T> template<class U> inline Vec4<T> &Vec4<T>::operator=(const Vec4<U> &r){ x = (T)r.x; y = (T)r.y; z = (T)r.z; w = (T)r.w; return *this; } template<class T> template<class U> inline Vec4<T> &Vec4<T>::operator=(const U r[4]){ if(v != r) for(int i = 0; i < 4; i++) v[i] = (T)r[i]; return *this; } //xyz only template<class T> template<class U> inline Vec4<T> &Vec4<T>::operator+=(const Vec4<U> &r){ x += (T)r.x; y += (T)r.y; z += (T)r.z; return *this; } //xyz only template<class T> template<class U> inline Vec4<T> Vec4<T>::operator+(const Vec4<U> &r)const{ return Vec4(*this) += r; } //xyz only template<class T> template<class U> inline Vec4<T> &Vec4<T>::operator-=(const Vec4<U> &r){ x -= (T)r.x; y -= (T)r.y; z -= (T)r.z; return *this; } //xyz only template<class T> template<class U> inline Vec4<T> Vec4<T>::operator-(const Vec4<U> &r)const{ return Vec4(*this) -= r; } //xyz only template<class T> template<class U> inline Vec4<T> &Vec4<T>::operator*=(const Vec4<U> &r){ x *= (T)r.x; y *= (T)r.y; z *= (T)r.z; return *this; } //xyz only template<class T> template<class U> inline Vec4<T> Vec4<T>::operator*(const Vec4<U> &r)const{ return Vec4(*this) *= r; } //xyz only template<class T> template<class U> inline Vec4<T> &Vec4<T>::operator/=(const Vec4<U> &r){ x /= (T)r.x; y /= (T)r.y; z /= (T)r.z; return *this; } //xyz only template<class T> template<class U> inline Vec4<T> Vec4<T>::operator/(const Vec4<U> &r)const{ return Vec4(*this) /= r; } //xyz only template<class T> inline Vec4<T> &Vec4<T>::operator*=(double scalar){ x = (T) (x * scalar); y = (T) (y * scalar); z = (T) (z * scalar); return *this; } //xyz only template<class T> inline Vec4<T> Vec4<T>::operator*(double scalar)const{ return Vec4(*this) *= scalar; } //xyz only template<class T> inline Vec4<T> &Vec4<T>::operator/=(double scalar){ assert(scalar != 0); x = (T) (x / scalar); y = (T) (y / scalar); z = (T) (z / scalar); return *this; } //xyz only template<class T> inline Vec4<T> Vec4<T>::operator/(double scalar)const{ return Vec4(*this) /= scalar; } //xyz only--NEEDS TO BE FLOAT/DOUBLE TO BE ACCURATE template<class T> inline T Vec4<T>::magnitude()const{ return (T)sqrt((double)(x*x + y*y + z*z)); } //xyz only template<class T> inline Vec4<T> &Vec4<T>::normalize(){ T d = magnitude(); x /= d; y /= d; z /= d; return *this; } template<class T> inline Vec4<T> &Vec4<T>::divideW(){ *this /= w; w = 1; return *this; } template<class T> std::string Vec4<T>::toString(){ std::ostringstream oss; oss << "("; for(int i = 0; i < 4; i++){ oss << v[i]; if(i != 3) oss << ", "; } oss << ")"; return oss.str(); } //xyz only template<class T, class U> inline T dot(const Vec4<T> &l, const Vec4<U> &r){ return l.x*r.x + l.y*r.y + l.z*r.z; } //xyz only template<class T, class U> inline Vec4<T> cross(const Vec4<T> &l, const Vec4<U> &r){ Vec4<T> temp = Vec4<T>(0,0,0,1); temp.x = l.y*r.z + l.z*r.y; temp.y = l.z*r.x + l.x*r.z; temp.z = l.x*r.y + l.y*r.x; return temp; } template<class T> inline Vec4<T> operator*(double scalar, Vec4<T> &r){ return r * scalar; } template<class T> inline std::ostream &operator <<(std::ostream &stream, Vec4<T> &r){ return stream << r.toString(); } typedef Vec4<float> Vec4f; typedef Vec4<double> Vec4d; typedef Vec4<int> Vec4i; typedef Vec4<float> Color4f; typedef Vec4<double> Color4d; typedef Vec4<int> Color4i; #endif // Vec4_H
mat4.h
/* * Mat4 is stored in row-major order. */ #ifndef Mat4_H #define Mat4_H #include "Vec4.h" template<class T> class Mat4{ private: T mi[4][4]; public: inline Mat4<T>(const Mat4<T> &r); inline Mat4<T>(T m00=0, T m01=0, T m02=0, T m03=0, T m10=0, T m11=0, T m12=0, T m13=0, T m20=0, T m21=0, T m22=0, T m23=0, T m30=0, T m31=0, T m32=0, T m33=0); inline ~Mat4<T>(); inline T *operator[](int index); inline operator T*(); inline bool operator==(const Mat4<T> &r); inline bool operator!=(const Mat4<T> &r); inline Mat4<T> &operator=(const Mat4<T> &r); template<class U> inline Mat4<T> &operator=(const Mat4<U> &r); template<class U> inline Mat4<T> &operator=(const U r[16]); template<class U> inline Mat4<T> &operator+=(const Mat4<U> &r); template<class U> inline Mat4<T> operator+(const Mat4<U> &r)const; template<class U> inline Mat4<T> &operator-=(const Mat4<U> &r); template<class U> inline Mat4<T> operator-(const Mat4<U> &r)const; template<class U> inline Mat4<T> &operator*=(const Mat4<U> &r); template<class U> inline Mat4<T> operator*(const Mat4<U> &r)const; template<class U> inline Vec4<U> operator*(const Vec4<U> &r)const; inline Mat4<T> &operator*=(double scalar); inline Mat4<T> operator*(double scalar)const; inline Mat4<T> &operator/=(double scalar); inline Mat4<T> operator/(double scalar)const; inline Mat4<T> &transpose(); std::string toString(); }; template<class T> inline Mat4<T>::Mat4(const Mat4<T> &r){ *this = r; } template<class T> inline Mat4<T>::Mat4(T m00=0, T m01=0, T m02=0, T m03=0, T m10=0, T m11=0, T m12=0, T m13=0, T m20=0, T m21=0, T m22=0, T m23=0, T m30=0, T m31=0, T m32=0, T m33=0){ mi[0][0] = m00; mi[0][1] = m01; mi[0][2] = m02; mi[0][3] = m03; mi[1][0] = m10; mi[1][1] = m11; mi[1][2] = m12; mi[1][3] = m13; mi[2][0] = m20; mi[2][1] = m21; mi[2][2] = m22; mi[2][3] = m23; mi[3][0] = m30; mi[3][1] = m31; mi[3][2] = m32; mi[3][3] = m33; } template<class T> inline Mat4<T>::~Mat4(){ } template<class T> inline T* Mat4<T>::operator[](int index){ return mi[index]; } template<class T> inline Mat4<T>::operator T*(){ return &mi[0][0]; } template<class T> inline bool Mat4<T>::operator==(const Mat4 &r){ for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) if(mi[i][j] != r.mi[i][j]) return false; return true; } template<class T> inline bool Mat4<T>::operator!=(const Mat4 &r){ return !((*this)==r); } template<class T> inline Mat4<T> &Mat4<T>::operator=(const Mat4<T> &r){ if(this != &r) for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) mi[i][j] = r.mi[i][j]; return *this; } template<class T> template<class U> inline Mat4<T> &Mat4<T>::operator=(const Mat4<U> &r){ for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) mi[i][j] = (T)r.mi[i][j]; return *this; } template<class T> template<class U> inline Mat4<T> &Mat4<T>::operator=(const U r[16]){ for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) mi[i][j] = (T)r[i*4 + j]; return *this; } template<class T> template<class U> inline Mat4<T> &Mat4<T>::operator+=(const Mat4<U> &r){ for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) mi[i][j] += (T)r.mi[i][j]; return *this; } template<class T> template<class U> inline Mat4<T> Mat4<T>::operator+(const Mat4<U> &r)const{ return Mat4(*this) += r; } template<class T> template<class U> inline Mat4<T> &Mat4<T>::operator-=(const Mat4<U> &r){ for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) mi[i][j] -= (T)r.mi[i][j]; return *this; } template<class T> template<class U> inline Mat4<T> Mat4<T>::operator-(const Mat4<U> &r)const{ return Mat4(*this) -= r; } template<class T> template<class U> inline Mat4<T> &Mat4<T>::operator*=(const Mat4<U> &r){ Mat4<T> temp; for(int i = 0; i < 4; i++){ for(int j = 0; j < 4; j++){ T tot = 0; for(int k = 0; k < 4; k++) tot += mi[i][k]*(T)r.mi[k][j]; temp[i][j] = tot; } } *this = temp; return *this; } template<class T> template<class U> inline Mat4<T> Mat4<T>::operator*(const Mat4<U> &r)const{ return Mat4(*this) *= r; } //Vec4 is treated as 4x1 matrix on rhs template<class T> template <class U> inline Vec4<U> Mat4<T>::operator*(const Vec4<U> &r)const{ Vec4<U> final; for(int i = 0; i < 4; i++){ T tot = 0; for(int j = 0; j < 4; j++) tot += mi[i][j] * (T)r.v[j]; final[i] = tot; } return final; } template<class T> inline Mat4<T> &Mat4<T>::operator*=(double scalar){ for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) mi[i][j] = (T) (mi[i][j] * scalar); return *this; } template<class T> inline Mat4<T> Mat4<T>::operator*(double scalar)const{ return Mat4(*this) *= scalar; } template<class T> inline Mat4<T> &Mat4<T>::operator/=(double scalar){ if(scalar != 0){ for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) mi[i][j] = (T) (mi[i][j] / scalar); } return *this; } template<class T> inline Mat4<T> Mat4<T>::operator/(double scalar)const{ return Mat4(*this) /= scalar; } template<class T> inline Mat4<T> &Mat4<T>::transpose(){ T temp; for(int i = 0; i < 3; i++) for(int j = 1; j < 4; j++) if(j > i){ temp = mi[i][j]; mi[i][j] = mi[j][i]; mi[j][i] = temp; } return *this; } template<class T> std::string Mat4<T>::toString(){ std::ostringstream oss; for(int i = 0; i < 4; i++){ for(int j = 0; j < 4; j++){ oss << mi[i][j]; if(j != 3) oss << "\t"; } if(i != 3) oss << "\n"; } return oss.str(); } template<class T> inline Mat4<T> operator*(double scalar, Mat4<T> &r){ return r * scalar; } template<class T> std::ostream &operator<<(std::ostream &stream, Mat4<T> &r){ return stream << r.toString(); } typedef Mat4<float> Mat4f; typedef Mat4<double> Mat4d; typedef Mat4<int> Mat4i; #endif //Mat4_H