// vecmath.h // // Copyright (C) 2000, Chris Laurel // // Basic templatized vector and matrix math library. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. #ifndef _VECMATH_H_ #define _VECMATH_H_ #include template class Point3; template class Vector3 { public: inline Vector3(); inline Vector3(const Vector3&); inline Vector3(T, T, T); inline Vector3(T*); inline T& operator[](int) const; inline Vector3& operator+=(const Vector3&); inline Vector3& operator-=(const Vector3&); inline Vector3& operator*=(T); inline Vector3 operator-() const; inline Vector3 operator+() const; inline T length() const; inline T lengthSquared() const; inline void normalize(); T x, y, z; }; template class Point3 { public: inline Point3(); inline Point3(const Point3&); inline Point3(T, T, T); inline Point3(T*); inline T& operator[](int) const; inline Point3& operator+=(const Vector3&); inline Point3& operator-=(const Vector3&); inline Point3& operator*=(T); inline T distanceTo(const Point3&) const; inline T distanceToSquared(const Point3&) const; inline T distanceFromOrigin() const; inline T distanceFromOriginSquared() const; T x, y, z; }; template class Point2; template class Vector2 { public: inline Vector2(); inline Vector2(T, T); T x, y; }; template class Point2 { public: inline Point2(); inline Point2(T, T); T x, y; }; template class Vector4 { public: inline Vector4(); inline Vector4(T, T, T, T); inline T& operator[](int) const; inline Vector4& operator+=(const Vector4&); inline Vector4& operator-=(const Vector4&); inline Vector4& operator*=(T); inline Vector4 operator-() const; inline Vector4 operator+() const; T x, y, z, w; }; template class Matrix4 { public: Matrix4(); Matrix4(const Vector4&, const Vector4&, const Vector4&, const Vector4&); Matrix4(const Matrix4& m); inline const Vector4& operator[](int) const; inline Vector4 row(int) const; inline Vector4 column(int) const; static Matrix4 identity(); static Matrix4 translation(const Point3&); static Matrix4 translation(const Vector3&); static Matrix4 rotation(const Vector3&, T); static Matrix4 xrotation(T); static Matrix4 yrotation(T); static Matrix4 zrotation(T); static Matrix4 scaling(const Vector3&); static Matrix4 scaling(T); void translate(const Point3&); Matrix4 transpose() const; Matrix4 inverse() const; Vector4 r[4]; }; template class Matrix3 { public: Matrix3(); Matrix3(const Vector3&, const Vector3&, const Vector3&); template Matrix3(const Matrix3&); static Matrix3 xrotation(T); static Matrix3 yrotation(T); static Matrix3 zrotation(T); static Matrix3 scaling(const Vector3&); static Matrix3 scaling(T); inline const Vector3& operator[](int) const; inline Vector3 row(int) const; inline Vector3 column(int) const; inline Matrix3& operator*=(T); static Matrix3 identity(); Matrix3 transpose() const; Matrix3 inverse() const; T determinant() const; // template operator Matrix3() const; Vector3 r[3]; }; typedef Vector3 Vec3f; typedef Vector3 Vec3d; typedef Point3 Point3f; typedef Point3 Point3d; typedef Vector2 Vec2f; typedef Point2 Point2f; typedef Vector4 Vec4f; typedef Vector4 Vec4d; typedef Matrix4 Mat4f; typedef Matrix4 Mat4d; typedef Matrix3 Mat3f; typedef Matrix3 Mat3d; //**** Vector3 constructors template Vector3::Vector3() : x(0), y(0), z(0) { } template Vector3::Vector3(const Vector3& v) : x(v.x), y(v.y), z(v.z) { } template Vector3::Vector3(T _x, T _y, T _z) : x(_x), y(_y), z(_z) { } template Vector3::Vector3(T* v) : x(v[0]), y(v[1]), z(v[2]) { } //**** Vector3 operators template T& Vector3::operator[](int n) const { // Not portable--I'll write a new version when I try to compile on a // platform where it bombs. return ((T*) this)[n]; } template Vector3& Vector3::operator+=(const Vector3& a) { x += a.x; y += a.y; z += a.z; return *this; } template Vector3& Vector3::operator-=(const Vector3& a) { x -= a.x; y -= a.y; z -= a.z; return *this; } template Vector3& Vector3::operator*=(T s) { x *= s; y *= s; z *= s; return *this; } template Vector3 Vector3::operator-() const { return Vector3(-x, -y, -z); } template Vector3 Vector3::operator+() const { return *this; } template Vector3 operator+(const Vector3& a, const Vector3& b) { return Vector3(a.x + b.x, a.y + b.y, a.z + b.z); } template Vector3 operator-(const Vector3& a, const Vector3& b) { return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); } template Vector3 operator*(T s, const Vector3& v) { return Vector3(s * v.x, s * v.y, s * v.z); } template Vector3 operator*(const Vector3& v, T s) { return Vector3(s * v.x, s * v.y, s * v.z); } // dot product template T operator*(const Vector3& a, const Vector3& b) { return a.x * b.x + a.y * b.y + a.z * b.z; } // cross product template Vector3 operator^(const Vector3& a, const Vector3& b) { return Vector3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } template bool operator==(const Vector3& a, const Vector3& b) { return a.x == b.x && a.y == b.y && a.z == b.z; } template bool operator!=(const Vector3& a, const Vector3& b) { return a.x != b.x || a.y != b.y || a.z != b.z; } template Vector3 operator/(const Vector3& v, T s) { T is = 1 / s; return Vector3(is * v.x, is * v.y, is * v.z); } template T dot(const Vector3& a, const Vector3& b) { return a.x * b.x + a.y * b.y + a.z * b.z; } template Vector3 cross(const Vector3& a, const Vector3& b) { return Vector3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); } template T Vector3::length() const { return (T) sqrt(x * x + y * y + z * z); } template T Vector3::lengthSquared() const { return x * x + y * y + z * z; } template void Vector3::normalize() { T s = 1 / (T) sqrt(x * x + y * y + z * z); x *= s; y *= s; z *= s; } //**** Point3 constructors template Point3::Point3() : x(0), y(0), z(0) { } template Point3::Point3(const Point3& p) : x(p.x), y(p.y), z(p.z) { } template Point3::Point3(T _x, T _y, T _z) : x(_x), y(_y), z(_z) { } template Point3::Point3(T* p) : x(p[0]), y(p[1]), z(p[2]) { } //**** Point3 operators template T& Point3::operator[](int n) const { // Not portable--I'll write a new version when I try to compile on a // platform where it bombs. return ((T*) this)[n]; } template Vector3 operator-(const Point3& a, const Point3& b) { return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); } template Point3& Point3::operator+=(const Vector3& v) { x += v.x; y += v.y; z += v.z; return *this; } template Point3& Point3::operator-=(const Vector3& v) { x -= v.x; y -= v.y; z -= v.z; return *this; } template Point3& Point3::operator*=(T s) { x *= s; y *= s; z *= s; return *this; } template bool operator==(const Point3& a, const Point3& b) { return a.x == b.x && a.y == b.y && a.z == b.z; } template bool operator!=(const Point3& a, const Point3& b) { return a.x != b.x || a.y != b.y || a.z != b.z; } template Point3 operator+(const Point3& p, const Vector3& v) { return Point3(p.x + v.x, p.y + v.y, p.z + v.z); } template Point3 operator-(const Point3& p, const Vector3& v) { return Point3(p.x - v.x, p.y - v.y, p.z - v.z); } // Naughty naughty . . . remove these since they aren't proper // point methods--changing the implicit homogenous coordinate isn't // allowed. template Point3 operator*(const Point3& p, T s) { return Point3(p.x * s, p.y * s, p.z * s); } template Point3 operator*(T s, const Point3& p) { return Point3(p.x * s, p.y * s, p.z * s); } //**** Point3 methods template T Point3::distanceTo(const Point3& p) const { return (T) sqrt((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y) + (p.z - z) * (p.z - z)); } template T Point3::distanceToSquared(const Point3& p) const { return ((p.x - x) * (p.x - x) + (p.y - y) * (p.y - y) + (p.z - z) * (p.z - z)); } template T Point3::distanceFromOrigin() const { return (T) sqrt(x * x + y * y + z * z); } template T Point3::distanceFromOriginSquared() const { return x * x + y * y + z * z; } //**** Vector2 constructors template Vector2::Vector2() : x(0), y(0) { } template Vector2::Vector2(T _x, T _y) : x(_x), y(_y) { } //**** Vector2 operators template bool operator==(const Vector2& a, const Vector2& b) { return a.x == b.x && a.y == b.y; } template bool operator!=(const Vector2& a, const Vector2& b) { return a.x != b.x || a.y != b.y; } //**** Point2 constructors template Point2::Point2() : x(0), y(0) { } template Point2::Point2(T _x, T _y) : x(_x), y(_y) { } //**** Point2 operators template bool operator==(const Point2& a, const Point2& b) { return a.x == b.x && a.y == b.y; } template bool operator!=(const Point2& a, const Point2& b) { return a.x != b.x || a.y != b.y; } //**** Vector4 constructors template Vector4::Vector4() : x(0), y(0), z(0), w(0) { } template Vector4::Vector4(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) { } //**** Vector4 operators template T& Vector4::operator[](int n) const { // Not portable--I'll write a new version when I try to compile on a // platform where it bombs. return ((T*) this)[n]; } template bool operator==(const Vector4& a, const Vector4& b) { return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; } template bool operator!=(const Vector4& a, const Vector4& b) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; } template Vector4& Vector4::operator+=(const Vector4& a) { x += a.x; y += a.y; z += a.z; w += a.w; return *this; } template Vector4& Vector4::operator-=(const Vector4& a) { x -= a.x; y -= a.y; z -= a.z; w -= a.w; return *this; } template Vector4& Vector4::operator*=(T s) { x *= s; y *= s; z *= s; w *= s; return *this; } template Vector4 Vector4::operator-() const { return Vector4(-x, -y, -z, -w); } template Vector4 Vector4::operator+() const { return *this; } template Vector4 operator+(const Vector4& a, const Vector4& b) { return Vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } template Vector4 operator-(const Vector4& a, const Vector4& b) { return Vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } template Vector4 operator*(T s, const Vector4& v) { return Vector4(s * v.x, s * v.y, s * v.z, s * v.w); } template Vector4 operator*(const Vector4& v, T s) { return Vector4(s * v.x, s * v.y, s * v.z, s * v.w); } // dot product template T operator*(const Vector4& a, const Vector4& b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } template T dot(const Vector4& a, const Vector4& b) { return a * b; } //**** Matrix3 constructors template Matrix3::Matrix3() { r[0] = Vector3(0, 0, 0); r[1] = Vector3(0, 0, 0); r[2] = Vector3(0, 0, 0); } template Matrix3::Matrix3(const Vector3& r0, const Vector3& r1, const Vector3& r2) { r[0] = r0; r[1] = r1; r[2] = r2; } #if 0 template Matrix3::Matrix3(const Matrix3& m) { #if 0 r[0] = m.r[0]; r[1] = m.r[1]; r[2] = m.r[2]; #endif r[0].x = m.r[0].x; r[0].y = m.r[0].y; r[0].z = m.r[0].z; r[1].x = m.r[1].x; r[1].y = m.r[1].y; r[1].z = m.r[1].z; r[2].x = m.r[2].x; r[2].y = m.r[2].y; r[2].z = m.r[2].z; } #endif //**** Matrix3 operators template const Vector3& Matrix3::operator[](int n) const { // return const_cast&>(r[n]); return r[n]; } template Vector3 Matrix3::row(int n) const { return r[n]; } template Vector3 Matrix3::column(int n) const { return Vector3(r[0][n], r[1][n], r[2][n]); } template Matrix3& Matrix3::operator*=(T s) { r[0] *= s; r[1] *= s; r[2] *= s; return *this; } // pre-multiply column vector by a 3x3 matrix template Vector3 operator*(const Matrix3& m, const Vector3& v) { return Vector3(m.r[0].x * v.x + m.r[0].y * v.y + m.r[0].z * v.z, m.r[1].x * v.x + m.r[1].y * v.y + m.r[1].z * v.z, m.r[2].x * v.x + m.r[2].y * v.y + m.r[2].z * v.z); } // post-multiply row vector by a 3x3 matrix template Vector3 operator*(const Vector3& v, const Matrix3& m) { return Vector3(m.r[0].x * v.x + m.r[1].x * v.y + m.r[2].x * v.z, m.r[0].y * v.x + m.r[1].y * v.y + m.r[2].y * v.z, m.r[0].z * v.x + m.r[1].z * v.y + m.r[2].z * v.z); } // pre-multiply column point by a 3x3 matrix template Point3 operator*(const Matrix3& m, const Point3& p) { return Point3(m.r[0].x * p.x + m.r[0].y * p.y + m.r[0].z * p.z, m.r[1].x * p.x + m.r[1].y * p.y + m.r[1].z * p.z, m.r[2].x * p.x + m.r[2].y * p.y + m.r[2].z * p.z); } // post-multiply row point by a 3x3 matrix template Point3 operator*(const Point3& p, const Matrix3& m) { return Point3(m.r[0].x * p.x + m.r[1].x * p.y + m.r[2].x * p.z, m.r[0].y * p.x + m.r[1].y * p.y + m.r[2].y * p.z, m.r[0].z * p.x + m.r[1].z * p.y + m.r[2].z * p.z); } template Matrix3 operator*(const Matrix3& a, const Matrix3& b) { #define MATMUL(R, C) (a[R].x * b[0].C + a[R].y * b[1].C + a[R].z * b[2].C) return Matrix3(Vector3(MATMUL(0, x), MATMUL(0, y), MATMUL(0, z)), Vector3(MATMUL(1, x), MATMUL(1, y), MATMUL(1, z)), Vector3(MATMUL(2, x), MATMUL(2, y), MATMUL(2, z))); #undef MATMUL } template Matrix3 operator+(const Matrix3& a, const Matrix3& b) { return Matrix3(a.r[0] + b.r[0], a.r[1] + b.r[1], a.r[2] + b.r[2]); } template Matrix3 Matrix3::identity() { return Matrix3(Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1)); } template Matrix3 Matrix3::transpose() const { return Matrix3(Vector3(r[0].x, r[1].x, r[2].x), Vector3(r[0].y, r[1].y, r[2].y), Vector3(r[0].z, r[1].z, r[2].z)); } template T det2x2(T a, T b, T c, T d) { return a * d - b * c; } template T Matrix3::determinant() const { return (r[0].x * r[1].y * r[2].z + r[0].y * r[1].z * r[2].x + r[0].z * r[1].x * r[2].y - r[0].z * r[1].y * r[2].x - r[0].x * r[1].z * r[2].y - r[0].y * r[1].x * r[2].z); } template Matrix3 Matrix3::inverse() const { Matrix3 adjoint; // Just use Cramer's rule for now . . . adjoint.r[0].x = det2x2(r[1].y, r[1].z, r[2].y, r[2].z); adjoint.r[0].y = -det2x2(r[1].x, r[1].z, r[2].x, r[2].z); adjoint.r[0].z = det2x2(r[1].x, r[1].y, r[2].x, r[2].y); adjoint.r[1].x = -det2x2(r[0].y, r[0].z, r[2].y, r[2].z); adjoint.r[1].y = det2x2(r[0].x, r[0].z, r[2].x, r[2].z); adjoint.r[1].z = -det2x2(r[0].x, r[0].y, r[2].x, r[2].y); adjoint.r[2].x = det2x2(r[0].y, r[0].z, r[1].y, r[1].z); adjoint.r[2].y = -det2x2(r[0].x, r[0].z, r[1].x, r[1].z); adjoint.r[2].z = det2x2(r[0].x, r[0].y, r[1].x, r[1].y); adjoint *= 1 / determinant(); return adjoint; } template Matrix3 Matrix3::xrotation(T angle) { T c = (T) cos(angle); T s = (T) sin(angle); return Matrix3(Vector3(1, 0, 0), Vector3(0, c, -s), Vector3(0, s, c)); } template Matrix3 Matrix3::yrotation(T angle) { T c = (T) cos(angle); T s = (T) sin(angle); return Matrix3(Vector3(c, 0, s), Vector3(0, 1, 0), Vector3(-s, 0, c)); } template Matrix3 Matrix3::zrotation(T angle) { T c = (T) cos(angle); T s = (T) sin(angle); return Matrix3(Vector3(c, -s, 0), Vector3(s, c, 0), Vector3(0, 0, 1)); } template Matrix3 Matrix3::scaling(const Vector3& scale) { return Matrix3(Vector3(scale.x, 0, 0), Vector3(0, scale.y, 0), Vector3(0, 0, scale.z)); } template Matrix3 Matrix3::scaling(T scale) { return scaling(Vector3(scale, scale, scale)); } /*********************************************** ** ** Matrix4 methods ** ***********************************************/ template Matrix4::Matrix4() { r[0] = Vector4(0, 0, 0, 0); r[1] = Vector4(0, 0, 0, 0); r[2] = Vector4(0, 0, 0, 0); r[3] = Vector4(0, 0, 0, 0); } template Matrix4::Matrix4(const Vector4& v0, const Vector4& v1, const Vector4& v2, const Vector4& v3) { r[0] = v0; r[1] = v1; r[2] = v2; r[3] = v3; } template Matrix4::Matrix4(const Matrix4& m) { r[0] = m.r[0]; r[1] = m.r[1]; r[2] = m.r[2]; r[3] = m.r[3]; } template const Vector4& Matrix4::operator[](int n) const { return r[n]; // return const_cast&>(r[n]); } template Vector4 Matrix4::row(int n) const { return r[n]; } template Vector4 Matrix4::column(int n) const { return Vector4(r[0][n], r[1][n], r[2][n], r[3][n]); } template Matrix4 Matrix4::identity() { return Matrix4(Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, 0, 0, 1)); } template Matrix4 Matrix4::translation(const Point3& p) { return Matrix4(Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0), Vector4(0, 0, 1, 0), Vector4(p.x, p.y, p.z, 1)); } template Matrix4 Matrix4::translation(const Vector3& v) { return Matrix4(Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0), Vector4(0, 0, 1, 0), Vector4(v.x, v.y, v.z, 1)); } template void Matrix4::translate(const Point3& p) { r[3].x += p.x; r[3].y += p.y; r[3].z += p.z; } template Matrix4 Matrix4::rotation(const Vector3& axis, T angle) { T c = (T) cos(angle); T s = (T) sin(angle); T t = 1 - c; return Matrix4(Vector4(t * axis.x * axis.x + c, t * axis.x * axis.y - s * axis.z, t * axis.x * axis.z + s * axis.y, 0), Vector4(t * axis.x * axis.y + s * axis.z, t * axis.y * axis.y + c, t * axis.y * axis.z - s * axis.x, 0), Vector4(t * axis.x * axis.z - s * axis.y, t * axis.y * axis.z + s * axis.x, t * axis.z * axis.z + c, 0), Vector4(0, 0, 0, 1)); } template Matrix4 Matrix4::xrotation(T angle) { T c = (T) cos(angle); T s = (T) sin(angle); return Matrix4(Vector4(1, 0, 0, 0), Vector4(0, c, -s, 0), Vector4(0, s, c, 0), Vector4(0, 0, 0, 1)); } template Matrix4 Matrix4::yrotation(T angle) { T c = (T) cos(angle); T s = (T) sin(angle); return Matrix4(Vector4(c, 0, s, 0), Vector4(0, 1, 0, 0), Vector4(-s, 0, c, 0), Vector4(0, 0, 0, 1)); } template Matrix4 Matrix4::zrotation(T angle) { T c = (T) cos(angle); T s = (T) sin(angle); return Matrix4(Vector4(c, -s, 0, 0), Vector4(s, c, 0, 0), Vector4(0, 0, 1, 0), Vector4(0, 0, 0, 1)); } template Matrix4 Matrix4::scaling(const Vector3& scale) { return Matrix4(Vector4(scale.x, 0, 0, 0), Vector4(0, scale.y, 0, 0), Vector4(0, 0, scale.z, 0), Vector4(0, 0, 0, 1)); } template Matrix4 Matrix4::scaling(T scale) { return scaling(Vector3(scale, scale, scale)); } // multiply column vector by a 4x4 matrix template Vector3 operator*(const Matrix4& m, const Vector3& v) { return Vector3(m.r[0].x * v.x + m.r[0].y * v.y + m.r[0].z * v.z, m.r[1].x * v.x + m.r[1].y * v.y + m.r[1].z * v.z, m.r[2].x * v.x + m.r[2].y * v.y + m.r[2].z * v.z); } // multiply row vector by a 4x4 matrix template Vector3 operator*(const Vector3& v, const Matrix4& m) { return Vector3(m.r[0].x * v.x + m.r[1].x * v.y + m.r[2].x * v.z, m.r[0].y * v.x + m.r[1].y * v.y + m.r[2].y * v.z, m.r[0].z * v.x + m.r[1].z * v.y + m.r[2].z * v.z); } // multiply column point by a 4x4 matrix; no projection is performed template Point3 operator*(const Matrix4& m, const Point3& p) { return Point3(m.r[0].x * p.x + m.r[0].y * p.y + m.r[0].z * p.z + m.r[0].w, m.r[1].x * p.x + m.r[1].y * p.y + m.r[1].z * p.z + m.r[1].w, m.r[2].x * p.x + m.r[2].y * p.y + m.r[2].z * p.z + m.r[2].w); } // multiply row point by a 4x4 matrix; no projection is performed template Point3 operator*(const Point3& p, const Matrix4& m) { return Point3(m.r[0].x * p.x + m.r[1].x * p.y + m.r[2].x * p.z + m.r[3].x, m.r[0].y * p.x + m.r[1].y * p.y + m.r[2].y * p.z + m.r[3].y, m.r[0].z * p.x + m.r[1].z * p.y + m.r[2].z * p.z + m.r[3].z); } // multiply column vector by a 4x4 matrix template Vector4 operator*(const Matrix4& m, const Vector4& v) { return Vector4(m.r[0].x * v.x + m.r[0].y * v.y + m.r[0].z * v.z + m.r[0].w * v.w, m.r[1].x * v.x + m.r[1].y * v.y + m.r[1].z * v.z + m.r[1].w * v.w, m.r[2].x * v.x + m.r[2].y * v.y + m.r[2].z * v.z + m.r[2].w * v.w, m.r[3].x * v.x + m.r[3].y * v.y + m.r[3].z * v.z + m.r[3].w * v.w); } // multiply row vector by a 4x4 matrix template Vector4 operator*(const Vector4& v, const Matrix4& m) { return Vector4(m.r[0].x * v.x + m.r[1].x * v.y + m.r[2].x * v.z + m.r[3].x * v.w, m.r[0].y * v.x + m.r[1].y * v.y + m.r[2].y * v.z + m.r[3].y * v.w, m.r[0].z * v.x + m.r[1].z * v.y + m.r[2].z * v.z + m.r[3].z * v.w, m.r[0].w * v.x + m.r[1].w * v.y + m.r[2].w * v.z + m.r[3].w * v.w); } template Matrix4 Matrix4::transpose() const { return Matrix4(Vector4(r[0].x, r[1].x, r[2].x, r[3].x), Vector4(r[0].y, r[1].y, r[2].y, r[3].y), Vector4(r[0].z, r[1].z, r[2].z, r[3].z), Vector4(r[0].w, r[1].w, r[2].w, r[3].w)); } template Matrix4 operator*(const Matrix4& a, const Matrix4& b) { #define MATMUL(R, C) (a[R].x * b[0].C + a[R].y * b[1].C + a[R].z * b[2].C + a[R].w * b[3].C) return Matrix4(Vector4(MATMUL(0, x), MATMUL(0, y), MATMUL(0, z), MATMUL(0, w)), Vector4(MATMUL(1, x), MATMUL(1, y), MATMUL(1, z), MATMUL(1, w)), Vector4(MATMUL(2, x), MATMUL(2, y), MATMUL(2, z), MATMUL(2, w)), Vector4(MATMUL(3, x), MATMUL(3, y), MATMUL(3, z), MATMUL(3, w))); #undef MATMUL } template Matrix4 operator+(const Matrix4& a, const Matrix4& b) { return Matrix4(a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]); } // Compute inverse using Gauss-Jordan elimination; caller is responsible // for ensuring that the matrix isn't singular. template Matrix4 Matrix4::inverse() const { Matrix4 a(*this); Matrix4 b(Matrix4::identity()); int i, j; int p; for (j = 0; j < 4; j++) { p = j; for (i = j + 1; i < 4; i++) { if (fabs(a.r[i][j]) > fabs(a.r[p][j])) p = i; } // Swap rows p and j Vector4 t = a.r[p]; a.r[p] = a.r[j]; a.r[j] = t; t = b.r[p]; b.r[p] = b.r[j]; b.r[j] = t; T s = a.r[j][j]; // if s == 0, the matrix is singular a.r[j] *= (1.0f / s); b.r[j] *= (1.0f / s); // Eliminate off-diagonal elements for (i = 0; i < 4; i++) { if (i != j) { b.r[i] -= a.r[i][j] * b.r[j]; a.r[i] -= a.r[i][j] * a.r[j]; } } } return b; } #endif // _VECMATH_H_