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