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> &divideW();
	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