=== added directory 'src/libmatrix'
=== added file 'src/libmatrix/COPYING'
--- src/libmatrix/COPYING	1970-01-01 00:00:00 +0000
+++ src/libmatrix/COPYING	2011-06-17 07:54:50 +0000
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2010 Linaro Limited
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

=== added file 'src/libmatrix/Makefile'
--- src/libmatrix/Makefile	1970-01-01 00:00:00 +0000
+++ src/libmatrix/Makefile	2011-06-17 07:54:50 +0000
@@ -0,0 +1,17 @@
+TARGETS = libmatrix.a matrix_inverse_test
+SRCS = mat.cc program.cc matrix_inverse_test.cc
+OBJS = $(SRCS:.cc=.o)
+CXXFLAGS = -Wall -Werror -pedantic -O3
+
+default: $(TARGETS)
+
+mat.o : mat.cc mat.h
+program.o: program.cc program.h
+matrix_inverse_test.o: matrix_inverse_test.cc mat.h
+matrix_inverse_test: matrix_inverse_test.o libmatrix.a
+	$(CXX) -o $@ $?
+libmatrix.a : mat.o mat.h stack.h vec.h program.o program.h
+	$(AR) -r $@  $(OBJS)
+
+clean :
+	$(RM) $(OBJS) $(TARGETS)

=== added file 'src/libmatrix/README'
--- src/libmatrix/README	1970-01-01 00:00:00 +0000
+++ src/libmatrix/README	2011-06-17 07:54:50 +0000
@@ -0,0 +1,11 @@
+libmatrix
+=========
+
+A simple C++ template library that provides containers and arithmetic 
+operations for vectors, matrices and matrix stacks of 2, 3 and 4 dimensions.
+Additionally, it provides implementations of the more common matrix 
+transformations described by the OpenGL programming guide.  libmatrix does
+not make any OpenGL calls, it merely replaces a portion of the fixed-function
+vertex processing API that have been removed from newer releases of core OpenGL
+and omitted from OpenGL ES.  The goal is simply to provide developers an easier
+point of entry into developing for OpenGL and OpenGL ES. 

=== added file 'src/libmatrix/mat.cc'
--- src/libmatrix/mat.cc	1970-01-01 00:00:00 +0000
+++ src/libmatrix/mat.cc	2011-06-17 07:54:50 +0000
@@ -0,0 +1,173 @@
+//
+// Copyright (c) 2010 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+//     Jesse Barker - original implementation.
+//
+#include <math.h>
+#include "mat.h"
+
+namespace LibMatrix
+{
+namespace Mat4
+{
+
+mat4
+translate(float x, float y, float z)
+{
+    mat4 t;
+    t[0][3] = x;
+    t[1][3] = y;
+    t[2][3] = z;
+    return t;
+}
+
+mat4
+scale(float x, float y, float z)
+{
+    mat4 s;
+    s[0][0] = x;
+    s[1][1] = y;
+    s[2][2] = z;
+    return s;
+}
+
+//
+// As per the OpenGL "red book" definition of rotation, from the appendix
+// on Homogeneous Coordinates and Transformation Matrices, the "upper left"
+// 3x3 portion of the result matrix is formed by:
+//
+// M = uuT + (cos a)(I - uuT) + (sin a)S
+//
+// where u is the normalized input vector, uuT is the outer product of that
+// vector and its transpose, I is the identity matrix and S is the matrix:
+//
+// |  0  -z'  y' |
+// |  z'  0  -x' |
+// | -y'  x'  0  |
+//
+// where x', y' and z' are the elements of u
+//
+mat4
+rotate(float angle, float x, float y, float z)
+{
+    vec3 u(x, y, z);
+    u.normalize();
+    mat3 uuT = outer(u, u);
+    mat3 s;   
+    s[0][0] = 0;
+    s[0][1] = -u.z();
+    s[0][2] = u.y();
+    s[1][0] = u.z();
+    s[1][1] = 0;
+    s[1][2] = -u.x();
+    s[2][0] = -u.y();
+    s[2][1] = u.x();
+    s[2][2] = 0;
+    mat3 i;
+    i -= uuT;
+    // degrees to radians
+    float angleRadians(angle * M_PI / 180.0);
+    i *= cos(angleRadians);
+    s *= sin(angleRadians);
+    i += s;
+    mat3 m = uuT + i;
+    mat4 r;
+    r[0][0] = m[0][0];
+    r[0][1] = m[0][1];
+    r[0][2] = m[0][2];
+    r[1][0] = m[1][0];
+    r[1][1] = m[1][1];
+    r[1][2] = m[1][2];
+    r[2][0] = m[2][0];
+    r[2][1] = m[2][1];
+    r[2][2] = m[2][2];
+    return r;
+}
+
+mat4
+frustum(float left, float right, float bottom, float top, float near, float far)
+{
+    float twiceNear(2 * near);
+    float width(right - left);
+    float height(top - bottom);
+    float depth(far - near);
+    mat4 f;
+    f[0][0] = twiceNear / width;
+    f[0][2] = (right + left) / width;
+    f[1][1] = twiceNear / height;
+    f[1][2] = (top + bottom) / height;
+    f[2][2] = -(far + near) / depth;
+    f[2][3] = -(twiceNear * far) / depth;
+    f[3][2] = -1;
+    f[3][3] = 0;
+    return f;
+}
+
+mat4
+ortho(float left, float right, float bottom, float top, float near, float far)
+{
+    float width(right - left);
+    float height(top - bottom);
+    float depth(far - near);
+    mat4 o;
+    o[0][0] = 2 / width;
+    o[0][3] = (right + left) / width;
+    o[1][1] = 2 / height;
+    o[1][3] = (top + bottom) / height;
+    o[2][2] = -2 / depth;
+    o[2][3] = (far + near) / depth;
+    return o;
+}
+
+mat4
+perspective(float fovy, float aspect, float zNear, float zFar)
+{
+    // degrees to radians
+    float fovyRadians(fovy * M_PI / 180.0);
+    // cotangent(x) = 1/tan(x)
+    float f = 1/tan(fovyRadians / 2);
+    float depth(zNear - zFar);
+    mat4 p;
+    p[0][0] = f / aspect;
+    p[1][1] = f;
+    p[2][2] = (zFar + zNear) / depth;
+    p[2][3] = (2 * zFar * zNear) / depth;
+    p[3][2] = -1;
+    p[3][3] = 0;
+    return p;
+}
+
+mat4 lookAt(float eyeX, float eyeY, float eyeZ, 
+    float centerX, float centerY, float centerZ, 
+    float upX, float upY, float upZ)
+{
+    vec3 f(centerX - eyeX, centerY - eyeY, centerZ - eyeZ);
+    f.normalize();
+    vec3 up(upX, upY, upZ);
+    vec3 s = vec3::cross(f, up);
+    vec3 u = vec3::cross(s, f);
+    s.normalize();
+    u.normalize();
+    mat4 la;
+    la[0][0] = s.x();
+    la[0][1] = s.y();
+    la[0][2] = s.z();
+    la[1][0] = u.x();
+    la[1][1] = u.y();
+    la[1][2] = u.z();
+    la[2][0] = -f.x();
+    la[2][1] = -f.y();
+    la[2][2] = -f.z();
+    la *= translate(-eyeX, -eyeY, -eyeZ);
+    return la;
+}
+
+} // namespace Mat4
+
+} // namespace LibMatrix

=== added file 'src/libmatrix/mat.h'
--- src/libmatrix/mat.h	1970-01-01 00:00:00 +0000
+++ src/libmatrix/mat.h	2011-06-17 07:54:50 +0000
@@ -0,0 +1,1074 @@
+//
+// Copyright (c) 2010 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+//     Jesse Barker - original implementation.
+//
+#ifndef MAT_H_
+#define MAT_H_
+#include <stdexcept>
+#include <iostream>
+#include <iomanip>
+#include "vec.h"
+
+namespace LibMatrix
+{
+// Proxy class for providing the functionality of a doubly-dimensioned array
+// representation of matrices.  Each matrix class defines its operator[]
+// to return an ArrayProxy.  The ArrayProxy then returns the appropriate item
+// from its operator[].
+template<typename T, unsigned int dimension>
+class ArrayProxy
+{
+public:
+    ArrayProxy(T* data) { data_ = data; }
+    ~ArrayProxy() { data_ = 0; }
+    T& operator[](int index)
+    {
+        return data_[index * dimension];
+    }
+    const T& operator[](int index) const
+    {
+        return data_[index * dimension];
+    }
+private:
+    T* data_;
+};
+
+
+// Programming interfaces to all matrix objects are represented row-centric 
+// (i.e. C/C++ style references to the data appear as matrix[row][column]).  
+// However, the internal data representation is column-major, so when using 
+// the raw data access member to treat the data as a singly-dimensioned array,
+// it does not have to be transposed.
+template<typename T>
+class tmat2
+{
+public:
+    tmat2()
+    {
+        setIdentity();
+    }
+    tmat2(const tmat2& m)
+    {
+        m_[0] = m.m_[0];
+        m_[1] = m.m_[1];
+        m_[2] = m.m_[2];
+        m_[3] = m.m_[3];
+    }
+    tmat2(const T& c0r0, const T& c0r1, const T& c1r0, const T& c1r1)
+    {
+        m_[0] = c0r0;
+        m_[1] = c0r1;
+        m_[2] = c1r0;
+        m_[3] = c1r1;
+    }
+    ~tmat2() {}
+
+    void setIdentity()
+    {
+        m_[0] = 1;
+        m_[1] = 0;
+        m_[2] = 0;
+        m_[3] = 1;
+    }
+
+    tmat2& transpose()
+    {
+        T tmp_val = m_[1];
+        m_[1] = m_[2];
+        m_[2] = tmp_val;
+        return *this;
+    }
+
+    T determinant()
+    {
+        return (m_[0] * m_[3]) - (m_[2] * m_[1]);
+    }
+
+    tmat2& inverse() throw(std::runtime_error)
+    {
+        T d(determinant());
+        if (d == static_cast<T>(0))
+        {
+            throw std::runtime_error("Matrix is noninvertible!!!!");
+        }
+        T c0r0(m_[3] / d);
+        T c0r1(-m_[1] / d);
+        T c1r0(-m_[2] / d);
+        T c1r1(m_[0] / d);
+        m_[0] = c0r0;
+        m_[1] = c0r1;
+        m_[2] = c1r0;
+        m_[3] = c1r1;        
+        return *this;
+    }
+
+    void print() const
+    {
+        static const int precision(6);
+        // row 0
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[0];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[2];
+        std::cout << " |" << std::endl;
+        // row 1
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[1];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[3];
+        std::cout << " |" << std::endl;
+    }
+
+    operator const T*() const { return &m_[0];}
+
+    bool operator==(const tmat2& rhs) const
+    {
+        return m_[0] == rhs.m_[0] &&
+               m_[1] == rhs.m_[1] &&
+               m_[2] == rhs.m_[2] &&
+               m_[3] == rhs.m_[3];
+    }
+
+    bool operator!=(const tmat2& rhs) const
+    {
+        return !(*this == rhs);
+    }
+
+    tmat2& operator=(const tmat2& rhs)
+    {
+        if (this != &rhs)
+        {
+            m_[0] = rhs.m_[0];
+            m_[1] = rhs.m_[1];
+            m_[2] = rhs.m_[2];
+            m_[3] = rhs.m_[3];
+        }
+        return *this;
+    }
+
+    tmat2& operator+=(const tmat2& rhs)
+    {
+        m_[0] += rhs.m_[0];
+        m_[1] += rhs.m_[1];
+        m_[2] += rhs.m_[2];
+        m_[3] += rhs.m_[3];
+        return *this;
+    }
+
+    const tmat2 operator+(const tmat2& rhs)
+    {
+        return tmat2(*this) += rhs;
+    }
+
+    tmat2& operator-=(const tmat2& rhs)
+    {
+        m_[0] -= rhs.m_[0];
+        m_[1] -= rhs.m_[1];
+        m_[2] -= rhs.m_[2];
+        m_[3] -= rhs.m_[3];
+        return *this;
+    }
+
+    const tmat2 operator-(const tmat2& rhs)
+    {
+        return tmat2(*this) += rhs;
+    }
+
+    tmat2& operator*=(const tmat2& rhs)
+    {
+        T c0r0((m_[0] * rhs.m_[0]) + (m_[2] * rhs.m_[1]));
+        T c0r1((m_[1] * rhs.m_[0]) + (m_[3] * rhs.m_[1]));
+        T c1r0((m_[0] * rhs.m_[2]) + (m_[2] * rhs.m_[3]));
+        T c1r1((m_[1] * rhs.m_[2]) + (m_[3] * rhs.m_[3]));
+        m_[0] = c0r0;
+        m_[1] = c0r1;
+        m_[2] = c1r0;
+        m_[3] = c1r1;
+        return *this;
+    }
+
+    const tmat2 operator*(const tmat2& rhs)
+    {
+        return tmat2(*this) *= rhs;
+    }
+
+    tmat2& operator*=(const T& rhs)
+    {
+        m_[0] *= rhs;
+        m_[1] *= rhs;
+        m_[2] *= rhs;
+        m_[3] *= rhs;
+        return *this;
+    }
+
+    const tmat2 operator*(const T& rhs)
+    {
+        return tmat2(*this) *= rhs;
+    }
+
+    tmat2& operator/=(const T& rhs)
+    {
+        m_[0] /= rhs;
+        m_[1] /= rhs;
+        m_[2] /= rhs;
+        m_[3] /= rhs;
+        return *this;
+    }
+
+    const tmat2 operator/(const T& rhs)
+    {
+        return tmat2(*this) /= rhs;
+    }
+
+    ArrayProxy<T, 2> operator[](int index)
+    {
+        return ArrayProxy<T, 2>(&m_[index]);
+    }
+    const ArrayProxy<T, 2> operator[](int index) const
+    {
+        return ArrayProxy<T, 2>(const_cast<T*>(&m_[index]));
+    }
+
+private:
+    T m_[4];
+};
+
+template<typename T>
+const tmat2<T> operator*(const T& lhs, const tmat2<T>& rhs)
+{
+    return tmat2<T>(rhs) * lhs;
+}
+
+template<typename T>
+const tvec2<T> operator*(const tvec2<T>& lhs, const tmat2<T>& rhs)
+{
+    T x((lhs.x() * rhs[0][0]) + (lhs.y() * rhs[1][0]));
+    T y((lhs.x() * rhs[0][1]) + (lhs.y() * rhs[1][1]));
+    return tvec2<T>(x,y);
+}
+
+template<typename T>
+const tvec2<T> operator*(const tmat2<T>& lhs, const tvec2<T>& rhs)
+{
+    T x((lhs[0][0] * rhs.x()) + (lhs[0][1] * rhs.y()));
+    T y((lhs[1][0] * rhs.x()) + (lhs[1][1] * rhs.y()));
+    return tvec2<T>(x, y);
+}
+
+template<typename T>
+const tmat2<T> outer(const tvec2<T>& a, const tvec2<T>& b)
+{
+    tmat2<T> product;
+    product[0][0] = a.x() * b.x();
+    product[0][1] = a.x() * b.y();
+    product[1][0] = a.y() * b.x();
+    product[1][1] = a.y() * b.y();
+    return product;
+}
+
+template<typename T>
+class tmat3
+{
+public:
+    tmat3()
+    {
+        setIdentity();
+    }
+    tmat3(const tmat3& m)
+    {
+        m_[0] = m.m_[0];
+        m_[1] = m.m_[1];
+        m_[2] = m.m_[2];
+        m_[3] = m.m_[3];
+        m_[4] = m.m_[4];
+        m_[5] = m.m_[5];
+        m_[6] = m.m_[6];
+        m_[7] = m.m_[7];
+        m_[8] = m.m_[8];
+    }
+    tmat3(const T& c0r0, const T& c0r1, const T& c0r2,
+           const T& c1r0, const T& c1r1, const T& c1r2,
+           const T& c2r0, const T& c2r1, const T& c2r2)
+    {
+        m_[0] = c0r0;
+        m_[1] = c0r1;
+        m_[2] = c0r2;
+        m_[3] = c1r0;
+        m_[4] = c1r1;
+        m_[5] = c1r2;
+        m_[6] = c2r0;
+        m_[7] = c2r1;
+        m_[8] = c2r2;
+    }
+    ~tmat3() {}
+
+    void setIdentity()
+    {
+        m_[0] = 1;
+        m_[1] = 0;
+        m_[2] = 0;
+        m_[3] = 0;
+        m_[4] = 1;
+        m_[5] = 0;
+        m_[6] = 0;
+        m_[7] = 0;
+        m_[8] = 1;
+    }
+
+    tmat3& transpose()
+    {
+        T tmp_val = m_[1];
+        m_[1] = m_[3];
+        m_[3] = tmp_val;
+        tmp_val = m_[2];
+        m_[2] = m_[6];
+        m_[6] = tmp_val;
+        tmp_val = m_[5];
+        m_[5] = m_[7];
+        m_[7] = tmp_val;
+        return *this;
+    }
+
+    T determinant()
+    {
+        tmat2<T> minor0(m_[4], m_[5], m_[7], m_[8]);
+        tmat2<T> minor3(m_[1], m_[2], m_[7], m_[8]);
+        tmat2<T> minor6(m_[1], m_[2], m_[4], m_[5]);
+        return (m_[0] * minor0.determinant()) - 
+               (m_[3] * minor3.determinant()) +
+               (m_[6] * minor6.determinant());
+    }
+
+    tmat3& inverse() throw(std::runtime_error)
+    {
+        T d(determinant());
+        if (d == static_cast<T>(0))
+        {
+            throw std::runtime_error("Matrix is noninvertible!!!!");
+        }
+        tmat2<T> minor0(m_[4], m_[5], m_[7], m_[8]);
+        tmat2<T> minor1(m_[7], m_[8], m_[1], m_[2]);
+        tmat2<T> minor2(m_[1], m_[2], m_[4], m_[5]);
+        tmat2<T> minor3(m_[6], m_[8], m_[3], m_[5]);
+        tmat2<T> minor4(m_[0], m_[2], m_[6], m_[8]);
+        tmat2<T> minor5(m_[3], m_[5], m_[0], m_[2]);
+        tmat2<T> minor6(m_[3], m_[4], m_[6], m_[7]);
+        tmat2<T> minor7(m_[6], m_[7], m_[0], m_[1]);
+        tmat2<T> minor8(m_[0], m_[1], m_[3], m_[4]);
+        m_[0] = minor0.determinant() / d;
+        m_[1] = minor1.determinant() / d;
+        m_[2] = minor2.determinant() / d;
+        m_[3] = minor3.determinant() / d;
+        m_[4] = minor4.determinant() / d;
+        m_[5] = minor5.determinant() / d;
+        m_[6] = minor6.determinant() / d;
+        m_[7] = minor7.determinant() / d;
+        m_[8] = minor8.determinant() / d;
+        return *this;       
+    }
+
+    void print() const
+    {
+        static const int precision(6);
+        // row 0
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[0];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[3];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[6];
+        std::cout << " |" << std::endl;
+        // row 1
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[1];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[4];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[7];
+        std::cout << " |" << std::endl;
+        // row 2
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[2];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[5];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[8];
+        std::cout << " |" << std::endl;
+    }
+
+    operator const T*() const { return &m_[0];}
+
+    bool operator==(const tmat3& rhs) const
+    {
+        return m_[0] == rhs.m_[0] &&
+               m_[1] == rhs.m_[1] &&
+               m_[2] == rhs.m_[2] &&
+               m_[3] == rhs.m_[3] &&
+               m_[4] == rhs.m_[4] &&
+               m_[5] == rhs.m_[5] &&
+               m_[6] == rhs.m_[6] &&
+               m_[7] == rhs.m_[7] &&
+               m_[8] == rhs.m_[8];
+    }
+
+    bool operator!=(const tmat3& rhs) const
+    {
+        return !(*this == rhs);
+    }
+
+    tmat3& operator=(const tmat3& rhs)
+    {
+        if (this != &rhs)
+        {
+            m_[0] = rhs.m_[0];
+            m_[1] = rhs.m_[1];
+            m_[2] = rhs.m_[2];
+            m_[3] = rhs.m_[3];
+            m_[4] = rhs.m_[4];
+            m_[5] = rhs.m_[5];
+            m_[6] = rhs.m_[6];
+            m_[7] = rhs.m_[7];
+            m_[8] = rhs.m_[8];
+        }
+        return *this;
+    }
+
+    tmat3& operator+=(const tmat3& rhs)
+    {
+        m_[0] += rhs.m_[0];
+        m_[1] += rhs.m_[1];
+        m_[2] += rhs.m_[2];
+        m_[3] += rhs.m_[3];
+        m_[4] += rhs.m_[4];
+        m_[5] += rhs.m_[5];
+        m_[6] += rhs.m_[6];
+        m_[7] += rhs.m_[7];
+        m_[8] += rhs.m_[8];
+        return *this;
+    }
+
+    const tmat3 operator+(const tmat3& rhs)
+    {
+        return tmat3(*this) += rhs;
+    }
+
+    tmat3& operator-=(const tmat3& rhs)
+    {
+        m_[0] -= rhs.m_[0];
+        m_[1] -= rhs.m_[1];
+        m_[2] -= rhs.m_[2];
+        m_[3] -= rhs.m_[3];
+        m_[4] -= rhs.m_[4];
+        m_[5] -= rhs.m_[5];
+        m_[6] -= rhs.m_[6];
+        m_[7] -= rhs.m_[7];
+        m_[8] -= rhs.m_[8];
+        return *this;
+    }
+
+    const tmat3 operator-(const tmat3& rhs)
+    {
+        return tmat3(*this) -= rhs;
+    }
+
+    tmat3& operator*=(const tmat3& rhs)
+    {
+        T c0r0((m_[0] * rhs.m_[0]) + (m_[3] * rhs.m_[1]) + (m_[6] * rhs.m_[2]));
+        T c0r1((m_[1] * rhs.m_[0]) + (m_[4] * rhs.m_[1]) + (m_[7] * rhs.m_[2]));
+        T c0r2((m_[2] * rhs.m_[0]) + (m_[5] * rhs.m_[1]) + (m_[8] * rhs.m_[2]));
+        T c1r0((m_[0] * rhs.m_[3]) + (m_[3] * rhs.m_[4]) + (m_[6] * rhs.m_[5]));
+        T c1r1((m_[1] * rhs.m_[3]) + (m_[4] * rhs.m_[4]) + (m_[7] * rhs.m_[5]));
+        T c1r2((m_[2] * rhs.m_[3]) + (m_[5] * rhs.m_[4]) + (m_[8] * rhs.m_[5]));
+        T c2r0((m_[0] * rhs.m_[6]) + (m_[3] * rhs.m_[7]) + (m_[6] * rhs.m_[8]));
+        T c2r1((m_[1] * rhs.m_[6]) + (m_[4] * rhs.m_[7]) + (m_[7] * rhs.m_[8]));
+        T c2r2((m_[2] * rhs.m_[6]) + (m_[5] * rhs.m_[7]) + (m_[8] * rhs.m_[8]));
+        m_[0] = c0r0;
+        m_[1] = c0r1;
+        m_[2] = c0r2;
+        m_[3] = c1r0;
+        m_[4] = c1r1;
+        m_[5] = c1r2;
+        m_[6] = c2r0;
+        m_[7] = c2r1;
+        m_[8] = c2r2;
+        return *this;
+    }
+
+    const tmat3 operator*(const tmat3& rhs)
+    {
+        return tmat3(*this) *= rhs;
+    }
+
+    tmat3& operator*=(const T& rhs)
+    {
+        m_[0] *= rhs;
+        m_[1] *= rhs;
+        m_[2] *= rhs;
+        m_[3] *= rhs;
+        m_[4] *= rhs;
+        m_[5] *= rhs;
+        m_[6] *= rhs;
+        m_[7] *= rhs;
+        m_[8] *= rhs;
+        return *this;
+    }
+
+    const tmat3 operator*(const T& rhs)
+    {
+        return tmat3(*this) *= rhs;
+    }
+
+    tmat3& operator/=(const T& rhs)
+    {
+        m_[0] /= rhs;
+        m_[1] /= rhs;
+        m_[2] /= rhs;
+        m_[3] /= rhs;
+        m_[4] /= rhs;
+        m_[5] /= rhs;
+        m_[6] /= rhs;
+        m_[7] /= rhs;
+        m_[8] /= rhs;
+        return *this;
+    }
+
+    const tmat3 operator/(const T& rhs)
+    {
+        return tmat3(*this) /= rhs;
+    }
+
+    ArrayProxy<T, 3> operator[](int index)
+    {
+        return ArrayProxy<T, 3>(&m_[index]);
+    }
+    const ArrayProxy<T, 3> operator[](int index) const
+    {
+        return ArrayProxy<T, 3>(const_cast<T*>(&m_[index]));
+    }
+
+private:
+    T m_[9];
+};
+
+template<typename T>
+const tmat3<T> operator*(const T& lhs, const tmat3<T>& rhs)
+{
+    return tmat3<T>(rhs) * lhs;
+}
+
+template<typename T>
+const tvec3<T> operator*(const tvec3<T>& lhs, const tmat3<T>& rhs)
+{
+    T x((lhs.x() * rhs[0][0]) + (lhs.y() * rhs[1][0]) + (lhs.z() * rhs[2][0]));
+    T y((lhs.x() * rhs[0][1]) + (lhs.y() * rhs[1][1]) + (lhs.z() * rhs[2][1]));
+    T z((lhs.x() * rhs[0][2]) + (lhs.y() * rhs[1][2]) + (lhs.z() * rhs[2][2]));
+    return tvec3<T>(x, y, z);
+}
+
+template<typename T>
+const tvec3<T> operator*(const tmat3<T>& lhs, const tvec3<T>& rhs)
+{
+    T x((lhs[0][0] * rhs.x()) + (lhs[0][1] * rhs.y()) + (lhs[0][2] * rhs.z()));
+    T y((lhs[1][0] * rhs.x()) + (lhs[1][1] * rhs.y()) + (lhs[1][2] * rhs.z()));
+    T z((lhs[2][0] * rhs.x()) + (lhs[2][1] * rhs.y()) + (lhs[2][2] * rhs.z()));
+    return tvec3<T>(x, y, z);
+}
+
+template<typename T>
+const tmat3<T> outer(const tvec3<T>& a, const tvec3<T>& b)
+{
+    tmat3<T> product;
+    product[0][0] = a.x() * b.x();
+    product[0][1] = a.x() * b.y();
+    product[0][2] = a.x() * b.z();
+    product[1][0] = a.y() * b.x();
+    product[1][1] = a.y() * b.y();
+    product[1][2] = a.y() * b.z();
+    product[2][0] = a.z() * b.x();
+    product[2][1] = a.z() * b.y();
+    product[2][2] = a.z() * b.z();
+    return product;
+}
+
+template<typename T>
+class tmat4
+{
+public:
+    tmat4()
+    {
+        setIdentity();
+    }
+    tmat4(const tmat4& m)
+    {
+        m_[0] = m.m_[0];
+        m_[1] = m.m_[1];
+        m_[2] = m.m_[2];
+        m_[3] = m.m_[3];
+        m_[4] = m.m_[4];
+        m_[5] = m.m_[5];
+        m_[6] = m.m_[6];
+        m_[7] = m.m_[7];
+        m_[8] = m.m_[8];
+        m_[9] = m.m_[9];
+        m_[10] = m.m_[10];
+        m_[11] = m.m_[11];
+        m_[12] = m.m_[12];
+        m_[13] = m.m_[13];
+        m_[14] = m.m_[14];
+        m_[15] = m.m_[15];
+    }
+    ~tmat4() {}
+
+    void setIdentity()
+    {
+        m_[0] = 1;
+        m_[1] = 0;
+        m_[2] = 0;
+        m_[3] = 0;
+        m_[4] = 0;
+        m_[5] = 1;
+        m_[6] = 0;
+        m_[7] = 0;
+        m_[8] = 0;
+        m_[9] = 0;
+        m_[10] = 1;
+        m_[11] = 0;
+        m_[12] = 0;
+        m_[13] = 0;
+        m_[14] = 0;
+        m_[15] = 1;
+    }
+
+    tmat4& transpose()
+    {
+        T tmp_val = m_[1];
+        m_[1] = m_[4];
+        m_[4] = tmp_val;
+        tmp_val = m_[2];
+        m_[2] = m_[8];
+        m_[8] = tmp_val;
+        tmp_val = m_[3];
+        m_[3] = m_[12];
+        m_[12] = tmp_val;
+        tmp_val = m_[6];
+        m_[6] = m_[9];
+        m_[9] = tmp_val;
+        tmp_val = m_[7];
+        m_[7] = m_[13];
+        m_[13] = tmp_val;
+        tmp_val = m_[11];
+        m_[11] = m_[14];
+        m_[14] = tmp_val;
+        return *this;
+    }
+
+    T determinant()
+    {
+        tmat3<T> minor0(m_[5], m_[6], m_[7], m_[9], m_[10], m_[11], m_[13], m_[14], m_[15]);
+        tmat3<T> minor4(m_[1], m_[2], m_[3], m_[9], m_[10], m_[11], m_[13], m_[14], m_[15]);
+        tmat3<T> minor8(m_[1], m_[2], m_[3], m_[5], m_[6], m_[7], m_[13], m_[14], m_[15]);
+        tmat3<T> minor12(m_[1], m_[2], m_[3], m_[5], m_[6], m_[7], m_[9], m_[10], m_[11]);
+        return (m_[0] * minor0.determinant()) -
+               (m_[4] * minor4.determinant()) +
+               (m_[8] * minor8.determinant()) -
+               (m_[12] * minor12.determinant());
+    }
+
+    tmat4& inverse() throw(std::runtime_error)
+    {
+        T d(determinant());
+        if (d == static_cast<T>(0))
+        {
+            throw std::runtime_error("Matrix is noninvertible!!!!");
+        }
+        tmat3<T> minor0(m_[5], m_[6], m_[7], m_[9], m_[10], m_[11], m_[13], m_[14], m_[15]);
+        tmat3<T> minor1(m_[1], m_[2], m_[3], m_[13], m_[14], m_[15], m_[9], m_[10], m_[11]);
+        tmat3<T> minor2(m_[1], m_[2], m_[3], m_[5], m_[6], m_[7], m_[13], m_[14], m_[15]);
+        tmat3<T> minor3(m_[1], m_[2], m_[3], m_[9], m_[10], m_[11], m_[5], m_[6], m_[7]);
+
+        tmat3<T> minor4(m_[4], m_[6], m_[7], m_[12], m_[14], m_[15], m_[8], m_[10], m_[11]);
+        tmat3<T> minor5(m_[0], m_[2], m_[3], m_[8], m_[10], m_[11], m_[12], m_[14], m_[15]);
+        tmat3<T> minor6(m_[0], m_[2], m_[3], m_[12], m_[14], m_[15], m_[4], m_[6], m_[7]);
+        tmat3<T> minor7(m_[0], m_[2], m_[3], m_[4], m_[6], m_[7], m_[8], m_[10], m_[11]);
+
+        tmat3<T> minor8(m_[4], m_[5], m_[7], m_[8], m_[9], m_[11], m_[12], m_[13], m_[15]);
+        tmat3<T> minor9(m_[0], m_[1], m_[3], m_[12], m_[13], m_[15], m_[8], m_[9], m_[11]);
+        tmat3<T> minor10(m_[0], m_[1], m_[3], m_[4], m_[5], m_[7], m_[12], m_[13], m_[15]);
+        tmat3<T> minor11(m_[0], m_[1], m_[3], m_[8], m_[9], m_[11], m_[4], m_[5], m_[7]);
+
+        tmat3<T> minor12(m_[4], m_[5], m_[6], m_[12], m_[13], m_[14], m_[8], m_[9], m_[10]);
+        tmat3<T> minor13(m_[0], m_[1], m_[2], m_[8], m_[9], m_[10], m_[12], m_[13], m_[14]);
+        tmat3<T> minor14(m_[0], m_[1], m_[2], m_[12], m_[13], m_[14], m_[4], m_[5], m_[6]);
+        tmat3<T> minor15(m_[0], m_[1], m_[2], m_[4], m_[5], m_[6], m_[8], m_[9], m_[10]);
+        m_[0] = minor0.determinant() / d;
+        m_[1] = minor1.determinant() / d;
+        m_[2] = minor2.determinant() / d;
+        m_[3] = minor3.determinant() / d;
+        m_[4] = minor4.determinant() / d;
+        m_[5] = minor5.determinant() / d;
+        m_[6] = minor6.determinant() / d;
+        m_[7] = minor7.determinant() / d;
+        m_[8] = minor8.determinant() / d;
+        m_[9] = minor9.determinant() / d;
+        m_[10] = minor10.determinant() / d;
+        m_[11] = minor11.determinant() / d;
+        m_[12] = minor12.determinant() / d;
+        m_[13] = minor13.determinant() / d;
+        m_[14] = minor14.determinant() / d;
+        m_[15] = minor15.determinant() / d;
+        return *this;
+    }
+
+    void print() const
+    {
+        static const int precision(6);
+        // row 0
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[0];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[4];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[8];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[12];
+        std::cout << " |" << std::endl;
+        // row 1
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[1];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[5];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[9];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[13];
+        std::cout << " |" << std::endl;
+        // row 2
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[2];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[6];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[10];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[14];
+        std::cout << " |" << std::endl;
+        // row 3
+        std::cout << "| ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[3];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[7];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[11];
+        std::cout << " ";
+        std::cout << std::fixed << std::showpoint << std::setprecision(precision) << m_[15];
+        std::cout << " |" << std::endl;
+    }
+
+    operator const T*() const { return &m_[0];}
+
+    bool operator==(const tmat4& rhs) const
+    {
+        return m_[0] == rhs.m_[0] &&
+               m_[1] == rhs.m_[1] &&
+               m_[2] == rhs.m_[2] &&
+               m_[3] == rhs.m_[3] &&
+               m_[4] == rhs.m_[4] &&
+               m_[5] == rhs.m_[5] &&
+               m_[6] == rhs.m_[6] &&
+               m_[7] == rhs.m_[7] &&
+               m_[8] == rhs.m_[8] &&
+               m_[9] == rhs.m_[9] &&
+               m_[10] == rhs.m_[10] &&
+               m_[11] == rhs.m_[11] &&
+               m_[12] == rhs.m_[12] &&
+               m_[13] == rhs.m_[13] &&
+               m_[14] == rhs.m_[14] &&
+               m_[15] == rhs.m_[15];
+    }
+
+    bool operator!=(const tmat4& rhs) const
+    {
+        return !(*this == rhs);
+    }
+
+    tmat4& operator=(const tmat4& rhs)
+    {
+        if (this != &rhs)
+        {
+            m_[0] = rhs.m_[0];
+            m_[1] = rhs.m_[1];
+            m_[2] = rhs.m_[2];
+            m_[3] = rhs.m_[3];
+            m_[4] = rhs.m_[4];
+            m_[5] = rhs.m_[5];
+            m_[6] = rhs.m_[6];
+            m_[7] = rhs.m_[7];
+            m_[8] = rhs.m_[8];
+            m_[9] = rhs.m_[9];
+            m_[10] = rhs.m_[10];
+            m_[11] = rhs.m_[11];
+            m_[12] = rhs.m_[12];
+            m_[13] = rhs.m_[13];
+            m_[14] = rhs.m_[14];
+            m_[15] = rhs.m_[15];
+        }
+        return *this;
+    }
+
+    tmat4& operator+=(const tmat4& rhs)
+    {
+        m_[0] += rhs.m_[0];
+        m_[1] += rhs.m_[1];
+        m_[2] += rhs.m_[2];
+        m_[3] += rhs.m_[3];
+        m_[4] += rhs.m_[4];
+        m_[5] += rhs.m_[5];
+        m_[6] += rhs.m_[6];
+        m_[7] += rhs.m_[7];
+        m_[8] += rhs.m_[8];
+        m_[9] += rhs.m_[9];
+        m_[10] += rhs.m_[10];
+        m_[11] += rhs.m_[11];
+        m_[12] += rhs.m_[12];
+        m_[13] += rhs.m_[13];
+        m_[14] += rhs.m_[14];
+        m_[15] += rhs.m_[15];
+        return *this;
+    }
+
+    const tmat4 operator+(const tmat4& rhs)
+    {
+        return tmat4(*this) += rhs;
+    }
+
+    tmat4& operator-=(const tmat4& rhs)
+    {
+        m_[0] -= rhs.m_[0];
+        m_[1] -= rhs.m_[1];
+        m_[2] -= rhs.m_[2];
+        m_[3] -= rhs.m_[3];
+        m_[4] -= rhs.m_[4];
+        m_[5] -= rhs.m_[5];
+        m_[6] -= rhs.m_[6];
+        m_[7] -= rhs.m_[7];
+        m_[8] -= rhs.m_[8];
+        m_[9] -= rhs.m_[9];
+        m_[10] -= rhs.m_[10];
+        m_[11] -= rhs.m_[11];
+        m_[12] -= rhs.m_[12];
+        m_[13] -= rhs.m_[13];
+        m_[14] -= rhs.m_[14];
+        m_[15] -= rhs.m_[15];
+        return *this;
+    }
+
+    const tmat4 operator-(const tmat4& rhs)
+    {
+        return tmat4(*this) -= rhs;
+    }
+
+    tmat4& operator*=(const tmat4& rhs)
+    {
+        T c0r0((m_[0] * rhs.m_[0]) + (m_[4] * rhs.m_[1]) + (m_[8] * rhs.m_[2]) + (m_[12] * rhs.m_[3]));
+        T c0r1((m_[1] * rhs.m_[0]) + (m_[5] * rhs.m_[1]) + (m_[9] * rhs.m_[2]) + (m_[13] * rhs.m_[3]));
+        T c0r2((m_[2] * rhs.m_[0]) + (m_[6] * rhs.m_[1]) + (m_[10] * rhs.m_[2]) + (m_[14] * rhs.m_[3]));
+        T c0r3((m_[3] * rhs.m_[0]) + (m_[7] * rhs.m_[1]) + (m_[11] * rhs.m_[2]) + (m_[15] * rhs.m_[3]));
+        T c1r0((m_[0] * rhs.m_[4]) + (m_[4] * rhs.m_[5]) + (m_[8] * rhs.m_[6]) + (m_[12] * rhs.m_[7]));
+        T c1r1((m_[1] * rhs.m_[4]) + (m_[5] * rhs.m_[5]) + (m_[9] * rhs.m_[6]) + (m_[13] * rhs.m_[7]));
+        T c1r2((m_[2] * rhs.m_[4]) + (m_[6] * rhs.m_[5]) + (m_[10] * rhs.m_[6]) + (m_[14] * rhs.m_[7]));
+        T c1r3((m_[3] * rhs.m_[4]) + (m_[7] * rhs.m_[5]) + (m_[11] * rhs.m_[6]) + (m_[15] * rhs.m_[7]));
+        T c2r0((m_[0] * rhs.m_[8]) + (m_[4] * rhs.m_[9]) + (m_[8] * rhs.m_[10]) + (m_[12] * rhs.m_[11]));
+        T c2r1((m_[1] * rhs.m_[8]) + (m_[5] * rhs.m_[9]) + (m_[9] * rhs.m_[10]) + (m_[13] * rhs.m_[11]));
+        T c2r2((m_[2] * rhs.m_[8]) + (m_[6] * rhs.m_[9]) + (m_[10] * rhs.m_[10]) + (m_[14] * rhs.m_[11]));
+        T c2r3((m_[3] * rhs.m_[8]) + (m_[7] * rhs.m_[9]) + (m_[11] * rhs.m_[10]) + (m_[15] * rhs.m_[11]));
+        T c3r0((m_[0] * rhs.m_[12]) + (m_[4] * rhs.m_[13]) + (m_[8] * rhs.m_[14]) + (m_[12] * rhs.m_[15]));
+        T c3r1((m_[1] * rhs.m_[12]) + (m_[5] * rhs.m_[13]) + (m_[9] * rhs.m_[14]) + (m_[13] * rhs.m_[15]));
+        T c3r2((m_[2] * rhs.m_[12]) + (m_[6] * rhs.m_[13]) + (m_[10] * rhs.m_[14]) + (m_[14] * rhs.m_[15]));
+        T c3r3((m_[3] * rhs.m_[12]) + (m_[7] * rhs.m_[13]) + (m_[11] * rhs.m_[14]) + (m_[15] * rhs.m_[15]));
+        m_[0] = c0r0;
+        m_[1] = c0r1;
+        m_[2] = c0r2;
+        m_[3] = c0r3;
+        m_[4] = c1r0;
+        m_[5] = c1r1;
+        m_[6] = c1r2;
+        m_[7] = c1r3;
+        m_[8] = c2r0;
+        m_[9] = c2r1;
+        m_[10] = c2r2;
+        m_[11] = c2r3;
+        m_[12] = c3r0;
+        m_[13] = c3r1;
+        m_[14] = c3r2;
+        m_[15] = c3r3;
+        return *this;
+    }
+
+    const tmat4 operator*(const tmat4& rhs)
+    {
+        return tmat4(*this) *= rhs;
+    }
+
+    tmat4& operator*=(const T& rhs)
+    {
+        m_[0] *= rhs;
+        m_[1] *= rhs;
+        m_[2] *= rhs;
+        m_[3] *= rhs;
+        m_[4] *= rhs;
+        m_[5] *= rhs;
+        m_[6] *= rhs;
+        m_[7] *= rhs;
+        m_[8] *= rhs;
+        m_[9] *= rhs;
+        m_[10] *= rhs;
+        m_[11] *= rhs;
+        m_[12] *= rhs;
+        m_[13] *= rhs;
+        m_[14] *= rhs;
+        m_[15] *= rhs;
+        return *this;
+    }
+
+    const tmat4 operator*(const T& rhs)
+    {
+        return tmat4(*this) *= rhs;
+    }
+
+    tmat4& operator/=(const T& rhs)
+    {
+        m_[0] /= rhs;
+        m_[1] /= rhs;
+        m_[2] /= rhs;
+        m_[3] /= rhs;
+        m_[4] /= rhs;
+        m_[5] /= rhs;
+        m_[6] /= rhs;
+        m_[7] /= rhs;
+        m_[8] /= rhs;
+        m_[9] /= rhs;
+        m_[10] /= rhs;
+        m_[11] /= rhs;
+        m_[12] /= rhs;
+        m_[13] /= rhs;
+        m_[14] /= rhs;
+        m_[15] /= rhs;
+        return *this;
+    }
+
+    const tmat4 operator/(const T& rhs)
+    {
+        return tmat4(*this) /= rhs;
+    }
+
+    ArrayProxy<T, 4> operator[](int index)
+    {
+        return ArrayProxy<T, 4>(&m_[index]);
+    }
+    const ArrayProxy<T, 4> operator[](int index) const
+    {
+        return ArrayProxy<T, 4>(const_cast<T*>(&m_[index]));
+    }
+
+private:
+    T m_[16];
+};
+
+template<typename T>
+const tmat4<T> operator*(const T& lhs, const tmat4<T>& rhs)
+{
+    return tmat4<T>(rhs) * lhs;
+}
+
+template<typename T>
+const tvec4<T> operator*(const tvec4<T>& lhs, const tmat4<T>& rhs)
+{
+    T x((lhs.x() * rhs[0][0]) + (lhs.y() * rhs[1][0]) + (lhs.z() * rhs[2][0]) + (lhs.w() * rhs[3][0]));
+    T y((lhs.x() * rhs[0][1]) + (lhs.y() * rhs[1][1]) + (lhs.z() * rhs[2][1]) + (lhs.w() * rhs[3][1]));
+    T z((lhs.x() * rhs[0][2]) + (lhs.y() * rhs[1][2]) + (lhs.z() * rhs[2][2]) + (lhs.w() * rhs[3][2]));
+    T w((lhs.x() * rhs[0][3]) + (lhs.y() * rhs[1][3]) + (lhs.z() * rhs[2][3]) + (lhs.w() * rhs[3][3]));
+    return tvec4<T>(x, y, z, w);
+}
+
+template<typename T>
+const tvec4<T> operator*(const tmat4<T>& lhs, const tvec4<T>& rhs)
+{
+    T x((lhs[0][0] * rhs.x()) + (lhs[0][1] * rhs.y()) + (lhs[0][2] * rhs.z()) + (lhs[0][3] * rhs.w()));
+    T y((lhs[1][0] * rhs.x()) + (lhs[1][1] * rhs.y()) + (lhs[1][2] * rhs.z()) + (lhs[1][3] * rhs.w()));
+    T z((lhs[2][0] * rhs.x()) + (lhs[2][1] * rhs.y()) + (lhs[2][2] * rhs.z()) + (lhs[2][3] * rhs.w()));
+    T w((lhs[3][0] * rhs.x()) + (lhs[3][1] * rhs.y()) + (lhs[3][2] * rhs.z()) + (lhs[3][3] * rhs.w()));
+    return tvec4<T>(x, y, z, w);
+}
+
+template<typename T>
+const tmat4<T> outer(const tvec4<T>& a, const tvec4<T>& b)
+{
+    tmat4<T> product;
+    product[0][0] = a.x() * b.x();
+    product[0][1] = a.x() * b.y();
+    product[0][2] = a.x() * b.z();
+    product[0][3] = a.x() * b.w();
+    product[1][0] = a.y() * b.x();
+    product[1][1] = a.y() * b.y();
+    product[1][2] = a.y() * b.z();
+    product[1][3] = a.y() * b.w();
+    product[2][0] = a.z() * b.x();
+    product[2][1] = a.z() * b.y();
+    product[2][2] = a.z() * b.z();
+    product[2][3] = a.z() * b.w();
+    product[3][0] = a.w() * b.x();
+    product[3][1] = a.w() * b.y();
+    product[3][2] = a.w() * b.z();
+    product[3][3] = a.w() * b.w();
+    return product;
+}
+
+//
+// Convenience typedefs.  These are here to present a homogeneous view of these
+// objects with respect to shader source.
+//
+typedef tmat2<float> mat2;
+typedef tmat3<float> mat3;
+typedef tmat4<float> mat4;
+
+typedef tmat2<double> dmat2;
+typedef tmat3<double> dmat3;
+typedef tmat4<double> dmat4;
+
+typedef tmat2<int> imat2;
+typedef tmat3<int> imat3;
+typedef tmat4<int> imat4;
+
+typedef tmat2<unsigned int> umat2;
+typedef tmat3<unsigned int> umat3;
+typedef tmat4<unsigned int> umat4;
+
+typedef tmat2<bool> bmat2;
+typedef tmat3<bool> bmat3;
+typedef tmat4<bool> bmat4;
+
+namespace Mat4
+{
+
+//
+// Some functions to generate transformation matrices that used to be provided
+// by OpenGL.
+//
+mat4 translate(float x, float y, float z);
+mat4 scale(float x, float y, float z);
+mat4 rotate(float angle, float x, float y, float z);
+mat4 frustum(float left, float right, float bottom, float top, float near, float far);
+mat4 ortho(float left, float right, float bottom, float top, float near, float far);
+mat4 perspective(float fovy, float aspect, float zNear, float zFar);
+mat4 lookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ);
+
+} // namespace Mat4
+} // namespace LibMatrix
+#endif // MAT_H_

=== added file 'src/libmatrix/matrix_inverse_test.cc'
--- src/libmatrix/matrix_inverse_test.cc	1970-01-01 00:00:00 +0000
+++ src/libmatrix/matrix_inverse_test.cc	2011-06-17 07:54:50 +0000
@@ -0,0 +1,152 @@
+//
+// Copyright (c) 2010 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+//     Jesse Barker - original implementation.
+//
+#include <iostream>
+#include "mat.h"
+
+using LibMatrix::mat4;
+using LibMatrix::mat3;
+using LibMatrix::mat2;
+using std::cerr;
+using std::cout;
+using std::endl;
+
+bool mat2OK()
+{
+    mat2 m;
+    cout << "Starting with mat2 (should be identity): " << endl << endl;
+    m.print();
+
+    m[0][1] = -2.5;
+    
+    cout << endl << "Matrix should now have (0, 1) == -2.500000" << endl << endl;
+    m.print();
+    
+    mat2 mi(m);
+
+    cout << endl << "Copy of previous matrix (should have (0, 1) == -2.500000)" << endl << endl;
+    mi.print();
+
+    mi.inverse();
+
+    cout << endl << "Inverse of copy: " << endl << endl;
+    mi.print();
+
+    mat2 i = m * mi;
+
+    cout << endl << "Product of original and inverse (should be identity): " << endl << endl;
+    i.print();
+
+    mat2 ident;
+    if (i != ident)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool mat3OK()
+{
+    mat3 m;
+    cout << "Starting with mat3 (should be identity): " << endl << endl;
+    m.print();
+
+    m[1][2] = -2.5;
+    
+    cout << endl << "Matrix should now have (1, 2) == -2.500000" << endl << endl;
+    m.print();
+    
+    mat3 mi(m);
+
+    cout << endl << "Copy of previous matrix (should have (1, 2) == -2.500000)" << endl << endl;
+    mi.print();
+
+    mi.inverse();
+
+    cout << endl << "Inverse of copy: " << endl << endl;
+    mi.print();
+
+    mat3 i = m * mi;
+
+    cout << endl << "Product of original and inverse (should be identity): " << endl << endl;
+    i.print();
+
+    mat3 ident;
+    if (i != ident)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool mat4OK()
+{
+    mat4 m;
+    cout << "Starting with mat4 (should be identity): " << endl << endl;
+    m.print();
+
+    m[2][3] = -2.5;
+    
+    cout << endl << "Matrix should now have (2, 3) == -2.500000" << endl << endl;
+    m.print();
+    
+    mat4 mi(m);
+
+    cout << endl << "Copy of previous matrix (should have (2, 3) == -2.500000)" << endl << endl;
+    mi.print();
+
+    mi.inverse();
+
+    cout << endl << "Inverse of copy: " << endl << endl;
+    mi.print();
+
+    mat4 i = m * mi;
+
+    cout << endl <<  "Product of original and inverse (should be identity): " << endl << endl;
+    i.print();
+
+    mat4 ident;
+    if (i != ident)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+int
+main(int argc, char** argv)
+{
+    if (!mat2OK())
+    {
+        cerr << "mat2::inverse() does not work!" << endl;
+        return 1;
+    }
+    cout << "mat2::inverse() is okay!" << endl << endl;
+
+    if (!mat3OK())
+    {
+        cerr << "mat3::inverse() does not work!" << endl;
+        return 1;
+    }
+    cout << "mat3::inverse() is okay!" << endl << endl;
+
+    if (!mat4OK())
+    {
+        cerr << "mat4::inverse() does not work!" << endl;
+        return 1;
+    }
+    cout << "mat4::inverse() is okay!" << endl << endl;
+
+    return 0;
+}

=== added file 'src/libmatrix/program.cc'
--- src/libmatrix/program.cc	1970-01-01 00:00:00 +0000
+++ src/libmatrix/program.cc	2011-06-17 13:09:21 +0000
@@ -0,0 +1,363 @@
+//
+// Copyright (c) 2011 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+//     Jesse Barker - original implementation.
+//
+#include <string>
+#include <vector>
+#include <sstream>
+#include <fstream>
+#include <iostream>
+
+#include "oglsdl.h"
+#include "program.h"
+
+using std::string;
+using LibMatrix::mat4;
+using LibMatrix::vec2;
+using LibMatrix::vec3;
+using LibMatrix::vec4;
+
+bool
+gotSource(const string& filename, string& source)
+{
+    using std::ifstream;
+    ifstream inputFile(filename.c_str());
+    if (!inputFile)
+    {
+        std::cerr << "Failed to open \"" << filename << "\"" << std::endl;
+        return false;
+    }
+
+    string curLine;
+    while (getline(inputFile, curLine))
+    {
+        source += curLine;
+        source += '\n';
+    }
+
+    return true;
+}
+
+Shader::Shader(unsigned int type, const string& source) :
+    handle_(0),
+    type_(type),
+    source_(source),
+    ready_(false),
+    valid_(false)
+{
+    // Create our shader and setup the source code.
+    handle_ = glCreateShader(type);
+    if (!handle_)
+    {
+        message_ = string("Failed to create the new shader.");
+        return;
+    }
+    const GLchar* shaderSource = source_.c_str();
+    glShaderSource(handle_, 1, &shaderSource, NULL);
+    GLint param = 0;
+    glGetShaderiv(handle_, GL_SHADER_SOURCE_LENGTH, &param);
+    if (static_cast<unsigned int>(param) != source_.length() + 1)
+    {
+        std::ostringstream o(string("Expected shader source length "));
+        o << source_.length() << ", but got " << param << std::endl;
+        message_ = o.str();
+        return;
+    }
+    valid_ = true;
+}
+
+Shader::~Shader()
+{
+    handle_ = 0;
+    type_ = 0;
+    ready_ = false;
+    valid_ = false;
+}
+
+void
+Shader::compile()
+{
+    // Make sure we have a good shader and haven't already compiled it.
+    if (!valid_ || ready_)
+    {
+        return;
+    }
+    glCompileShader(handle_);
+    GLint param = 0;
+    glGetShaderiv(handle_, GL_COMPILE_STATUS, &param);
+    if (param == GL_FALSE)
+    {
+        glGetShaderiv(handle_, GL_INFO_LOG_LENGTH, &param);
+        GLchar* infoLog = new GLchar[param + 1];
+        glGetShaderInfoLog(handle_, param + 1, NULL, infoLog);
+        message_ = infoLog;
+        delete [] infoLog;
+        return;
+    }
+    ready_ = true;
+}
+
+void
+Shader::attach(unsigned int program)
+{
+    // Shader must be valid and compiled to be attached to a program.
+    if (!valid_ || !ready_)
+    {
+        return;
+    }
+    glAttachShader(program, handle_);
+}
+
+void
+Shader::release()
+{
+    if (handle_)
+    {
+        glDeleteShader(handle_);
+    }
+    handle_ = 0;
+    type_ = 0;
+    ready_ = false;
+    valid_ = false;
+}
+
+Program::Program() :
+    handle_(0),
+    ready_(false),
+    valid_(false)
+{
+}
+
+Program::~Program()
+{
+    // First release all of the shader resources attached to us and clean up
+    // our handle.
+    release();
+}
+
+void
+Program::init()
+{
+    handle_ = glCreateProgram();
+    if (!handle_)
+    {
+        message_ = string("Failed to create the new program");
+        return;
+    }
+
+    valid_ = true;
+}
+
+void
+Program::release()
+{
+    // First delete all of the shader resources attached to us.
+    for (std::vector<Shader>::iterator shaderIt = shaders_.begin(); shaderIt != shaders_.end(); shaderIt++)
+    {
+        shaderIt->release();
+    }
+
+    // Clear out the shader vector so we're ready to reuse it.
+    shaders_.clear();
+
+    // Clear out the error string to make sure we don't return anything stale.
+    message_.clear();
+
+    if (handle_)
+    {
+        glDeleteProgram(handle_);
+    }
+    handle_ = 0;
+    ready_ = false;
+    valid_ = false;
+}
+void
+Program::addShader(unsigned int type, const string& source)
+{
+    if (!valid_)
+    {
+        return;
+    }
+
+    Shader shader(type, source);
+    if (!shader.valid())
+    {
+        message_ = shader.errorMessage();
+        valid_ = false;
+        return;
+    }
+
+    shader.compile();
+
+    if (!shader.ready())
+    {
+        message_ = shader.errorMessage();
+        valid_ = false;
+        return;
+    }
+
+    shader.attach(handle_);
+    shaders_.push_back(shader);
+    return;
+}
+
+void
+Program::build()
+{
+    if (!valid_ || ready_)
+    {
+        return;
+    }
+
+    if (shaders_.empty())
+    {
+        message_ = string("There are no shaders attached to this program");
+        return;
+    }
+
+    glLinkProgram(handle_);
+    GLint param = 1;
+    glGetProgramiv(handle_, GL_LINK_STATUS, &param);
+    if (param == GL_FALSE)
+    {
+        glGetProgramiv(handle_, GL_INFO_LOG_LENGTH, &param);
+        GLchar* infoLog = new GLchar[param + 1];
+        glGetProgramInfoLog(handle_, param + 1, NULL, infoLog);
+        message_ = infoLog;
+        delete [] infoLog;
+        return;
+    }
+    ready_ = true;
+}
+
+void
+Program::start()
+{
+    if (!valid_ || !ready_)
+    {
+        return;
+    }
+    glUseProgram(handle_);
+}
+
+void
+Program::stop()
+{
+    glUseProgram(0);
+}
+
+void
+Program::loadUniformMatrix(const mat4& m, const string& name)
+{
+    ready_ = false;
+    GLint location = glGetUniformLocation(handle_, name.c_str());
+    if (location < 0)
+    {
+        message_ = string("Failed to get uniform location for \"") + name +
+            string("\"");
+        return;
+    }
+
+    // Our matrix representation is column-major, so transpose is false here.
+    glUniformMatrix4fv(location, 1, GL_FALSE, m);
+    ready_ = true;
+}
+
+void
+Program::loadUniformVector(const vec2& v, const string& name)
+{
+    ready_ = false;
+    GLint location = glGetUniformLocation(handle_, name.c_str());
+    if (location < 0)
+    {
+        message_ = string("Failed to get uniform location for \"") + name +
+            string("\"");
+        return;
+    }
+
+    glUniform2fv(location, 1, v);
+    ready_ = true;
+}
+
+void
+Program::loadUniformVector(const vec3& v, const string& name)
+{
+    ready_ = false;
+    GLint location = glGetUniformLocation(handle_, name.c_str());
+    if (location < 0)
+    {
+        message_ = string("Failed to get uniform location for \"") + name +
+            string("\"");
+        return;
+    }
+
+    glUniform3fv(location, 1, v);
+    ready_ = true;
+}
+
+void
+Program::loadUniformVector(const vec4& v, const string& name)
+{
+    ready_ = false;
+    GLint location = glGetUniformLocation(handle_, name.c_str());
+    if (location < 0)
+    {
+        message_ = string("Failed to get uniform location for \"") + name +
+            string("\"");
+        return;
+    }
+
+    glUniform4fv(location, 1, v);
+    ready_ = true;
+}
+
+void
+Program::loadUniformScalar(const float& f, const string& name)
+{
+    ready_ = false;
+    GLint location = glGetUniformLocation(handle_, name.c_str());
+    if (location < 0)
+    {
+        message_ = string("Failed to get uniform location for \"") + name +
+            string("\"");
+        return;
+    }
+
+    glUniform1f(location, f);
+    ready_ = true;
+}
+
+void
+Program::loadUniformScalar(const int& i, const string& name)
+{
+    ready_ = false;
+    GLint location = glGetUniformLocation(handle_, name.c_str());
+    if (location < 0)
+    {
+        message_ = string("Failed to get uniform location for \"") + name +
+            string("\"");
+        return;
+    }
+
+    glUniform1i(location, i);
+    ready_ = true;
+}
+
+int
+Program::getAttribIndex(const string& name)
+{
+    GLint index = glGetAttribLocation(handle_, name.c_str());
+    if (index < 0)
+    {
+        message_ = string("Failed to get attribute location for \"") + name +
+            string("\"");
+    }
+    return index;
+}

=== added file 'src/libmatrix/program.h'
--- src/libmatrix/program.h	1970-01-01 00:00:00 +0000
+++ src/libmatrix/program.h	2011-06-17 07:54:50 +0000
@@ -0,0 +1,151 @@
+//
+// Copyright (c) 2011 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+//     Jesse Barker - original implementation.
+//
+#ifndef PROGRAM_H_
+#define PROGRAM_H_
+
+#include <string>
+#include <vector>
+#include "mat.h"
+
+// Simple shader container.  Abstracts all of the OpenGL bits, but leaves
+// much of the semantics intact.  This is typically only referenced directly
+// by the program object.
+class Shader
+{
+public:
+    Shader() :
+        handle_(0),
+        type_(0),
+        ready_(false),
+        valid_(false) {}
+    Shader(const Shader& shader) :
+        handle_(shader.handle_),
+        type_(shader.type_),
+        source_(shader.source_),
+        message_(shader.message_),
+        ready_(shader.ready_),
+        valid_(shader.valid_) {}
+    Shader(unsigned int type, const std::string& source);
+    ~Shader();
+
+    // Compiles the shader source so that it can be linked into a
+    // program.
+    //
+    // Make sure the shader is "valid" before calling this one.
+    void compile();
+
+    // Attaches a compiled shader to a program in preparation for
+    // linking.
+    //
+    // Make sure the shader is "ready" before calling this one.
+    void attach(unsigned int program);
+
+    // Release any resources associated with this shader back to
+    // OpenGL
+    void release();
+
+    // If "valid" then the shader has successfully been created.
+    // If "ready" then the shader has successfully been compiled.
+    // If either is false, then additional information can be obtained
+    // from the error message.
+    bool valid() const { return valid_; }
+    bool ready() const { return ready_; }
+    const std::string& errorMessage() const { return message_; }
+
+private:
+    unsigned int handle_;
+    unsigned int type_;
+    std::string source_;
+    std::string message_;
+    bool ready_;
+    bool valid_;
+};
+
+// Simple program container.  Abstracts all of the OpenGL bits, but leaves
+// much of the semantics intact.
+class Program
+{
+public:
+    Program();
+    ~Program();
+
+    // Initialize the program object for use.
+    void init();
+
+    // Release any resources associated with this program back to
+    // OpenGL
+    void release();
+
+    // Create a new shader of the given type and source, compile it and
+    // attach it to the program.
+    //
+    // Make sure the program is "valid" before calling this one.
+    void addShader(unsigned int type, const std::string& source);
+
+    // Link all of the attached shaders into a runnable program for use
+    // in a rendering operation.
+    //
+    // Make sure the program is "valid" and that at least one shader
+    // has been successfully added before calling this one.
+    void build();
+
+    // Bind the program for use by the rendering context (i.e. actually
+    // run it).
+    //
+    // Make sure the program is "ready" before calling this one.
+    void start();
+
+    // Unbind the program from use by the rendering context (i.e. stop
+    // using it).
+    void stop();
+
+    // These members cause data to be bound to program variables, so
+    // the program must be bound for use for these to be effective.
+    //
+    // Load a matrix into the named uniform variable in the program.
+    void loadUniformMatrix(const LibMatrix::mat4& m, const std::string& name);
+    // Load a vector into the named uniform variable in the program.
+    void loadUniformVector(const LibMatrix::vec2& v, const std::string& name);
+    // Load a vector into the named uniform variable in the program.
+    void loadUniformVector(const LibMatrix::vec3& v, const std::string& name);
+    // Load a vector into the named uniform variable in the program.
+    void loadUniformVector(const LibMatrix::vec4& v, const std::string& name);
+    // Load a scalar into the named uniform variable in the program.
+    void loadUniformScalar(const float& f, const std::string& name);
+    // Load a scalar into the named uniform variable in the program.
+    void loadUniformScalar(const int& i, const std::string& name);
+
+    // Get the handle to a named program input (the location in OpenGL
+    // vernacular).  Typically used in conjunction with various VertexAttrib
+    // interfaces.
+    int getAttribIndex(const std::string& name);
+
+    // If "valid" then the program has successfully been created.
+    // If "ready" then the program has successfully been built.
+    // If either is false, then additional information can be obtained
+    // from the error message.
+    bool valid() const { return valid_; }
+    bool ready() const { return ready_; }
+    const std::string& errorMessage() const { return message_; }
+
+private:
+    unsigned int handle_;
+    std::vector<Shader> shaders_;
+    std::string message_;
+    bool ready_;
+    bool valid_;
+};
+
+// Handy utility for extracting shader source from a named file
+bool gotSource(const std::string& filename, std::string& sourceOut);
+
+#endif // PROGRAM_H_

=== added file 'src/libmatrix/stack.h'
--- src/libmatrix/stack.h	1970-01-01 00:00:00 +0000
+++ src/libmatrix/stack.h	2011-06-17 07:54:50 +0000
@@ -0,0 +1,106 @@
+//
+// Copyright (c) 2010 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+//     Jesse Barker - original implementation.
+//
+#ifndef STACK_H_
+#define STACK_H_
+
+#include <vector>
+#include "mat.h"
+
+namespace LibMatrix
+{
+//
+// Simple matrix stack implementation suitable for tracking OpenGL matrix
+// state.  Default construction puts an identity matrix on the top of the 
+// stack.
+//
+template<typename T>
+class MatrixStack
+{
+public:
+    MatrixStack()
+    {
+        theStack_.push_back(T());
+    }
+    MatrixStack(const T& matrix)
+    {
+        theStack_.push_back(matrix);
+    }
+    ~MatrixStack() {}
+
+    const T& getCurrent() const { return theStack_.back(); }
+
+    void push()
+    {
+        theStack_.push_back(theStack_.back());
+    }
+    void pop()
+    {
+        theStack_.pop_back();
+    }
+    void loadIdentity()
+    {
+        theStack_.back().setIdentity();
+    }
+    T& operator*=(const T& rhs)
+    {
+        T& curMatrix = theStack_.back();
+        curMatrix *= rhs;
+        return curMatrix;
+    }
+    void print() const
+    {
+        const T& curMatrix = theStack_.back();
+        curMatrix.print();
+    }
+    unsigned int getDepth() const { return theStack_.size(); }
+private:
+    std::vector<T> theStack_;
+};
+
+class Stack4 : public MatrixStack<mat4> 
+{
+public:
+    void translate(float x, float y, float z)
+    {
+        *this *= Mat4::translate(x, y, z);
+    }
+    void scale(float x, float y, float z)
+    {
+        *this *= Mat4::scale(x, y, z);
+    }
+    void rotate(float angle, float x, float y, float z)
+    {
+        *this *= Mat4::rotate(angle, x, y, z);
+    }
+    void frustum(float left, float right, float bottom, float top, float near, float far)
+    {
+        *this *= Mat4::frustum(left, right, bottom, top, near, far);
+    }
+    void ortho(float left, float right, float bottom, float top, float near, float far)
+    {
+        *this *= Mat4::ortho(left, right, bottom, top, near, far);
+    }
+    void perspective(float fovy, float aspect, float zNear, float zFar)
+    {
+        *this *= Mat4::perspective(fovy, aspect, zNear, zFar);
+    }
+    void lookAt(float eyeX, float eyeY, float eyeZ, 
+                float centerX, float centerY, float centerZ, 
+                float upX, float upY, float upZ)
+    {
+        *this *= Mat4::lookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
+    }
+};
+
+} // namespace LibMatrix
+
+#endif // STACK_H_

=== added file 'src/libmatrix/vec.h'
--- src/libmatrix/vec.h	1970-01-01 00:00:00 +0000
+++ src/libmatrix/vec.h	2011-06-17 07:54:50 +0000
@@ -0,0 +1,500 @@
+//
+// Copyright (c) 2010 Linaro Limited
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the MIT License which accompanies
+// this distribution, and is available at
+// http://www.opensource.org/licenses/mit-license.php
+//
+// Contributors:
+//     Jesse Barker - original implementation.
+//
+#ifndef VEC_H_
+#define VEC_H_
+
+#include <iostream> // only needed for print() functions...
+#include <math.h>
+
+namespace LibMatrix
+{
+template<typename T>
+class tvec2
+{
+public:
+    tvec2() :
+        x_(0),
+        y_(0) {}
+    tvec2(T t) :
+        x_(t),
+        y_(t) {}
+    tvec2(T x, T y) :
+        x_(x),
+        y_(y) {}
+    tvec2(const tvec2& v) :
+        x_(v.x_),
+        y_(v.y_) {}
+    ~tvec2() {}
+
+    void print() const
+    {
+        std::cout << "| " << x_ << " " << y_ << " |" << std::endl;
+    }
+    operator const T*() const { return &x_;}
+
+    const T x() const { return x_; }
+    const T y() const { return y_; }
+
+    void x(const T& val) { x_ = val; }
+    void y(const T& val) { y_ = val; }
+
+    tvec2& operator=(const tvec2& rhs)
+    {
+        if (this != &rhs)
+        {
+            x_ = rhs.x_;
+            y_ = rhs.y_;
+        }
+        return *this;
+    }
+
+    tvec2& operator/=(const T& rhs)
+    {
+        x_ /= rhs;
+        y_ /= rhs;
+        return *this;
+    }
+
+    const tvec2 operator/(const T& rhs)
+    {
+        return tvec2(*this) /= rhs;
+    }
+
+    tvec2& operator*=(const T& rhs)
+    {
+        x_ *= rhs;
+        y_ *= rhs;
+        return *this;
+    }
+
+    const tvec2 operator*(const T& rhs)
+    {
+        return tvec2(*this) *= rhs;
+    }
+
+    tvec2& operator+=(const T& rhs)
+    {
+        x_ += rhs;
+        y_ += rhs;
+        return *this;
+    }
+    
+    const tvec2 operator+(const T& rhs)
+    {
+        return tvec2(*this) += rhs;
+    }
+
+    tvec2& operator+=(const tvec2& rhs)
+    {
+        x_ += rhs.x_;
+        y_ += rhs.y_;
+        return *this;
+    }
+
+    const tvec2 operator+(const tvec2& rhs)
+    {
+        return tvec2(*this) += rhs;
+    }
+
+    tvec2& operator-=(const T& rhs)
+    {
+        x_ -= rhs;
+        y_ -= rhs;
+        return *this;
+    }
+    
+    const tvec2 operator-(const T& rhs)
+    {
+        return tvec2(*this) -= rhs;
+    }
+
+    tvec2& operator-=(const tvec2& rhs)
+    {
+        x_ -= rhs.x_;
+        y_ -= rhs.y_;
+        return *this;
+    }
+
+    const tvec2 operator-(const tvec2& rhs)
+    {
+        return tvec2(*this) -= rhs;
+    }
+
+    float length() const
+    {
+        return sqrt(dot(*this, *this));
+    }
+
+    void normalize()
+    {
+        float l = length();
+        x_ /= l;
+        y_ /= l;
+    }
+
+    static T dot(const tvec2& v1, const tvec2& v2)
+    {
+        return (v1.x_ * v2.x_) + (v1.y_ * v2.y_); 
+    }
+
+private:
+    T x_;
+    T y_;
+};
+
+template<typename T>
+class tvec3
+{
+public:
+    tvec3() :
+        x_(0),
+        y_(0),
+        z_(0) {}
+    tvec3(T t) :
+        x_(t),
+        y_(t),
+        z_(t) {}
+    tvec3(T x, T y, T z) :
+        x_(x),
+        y_(y),
+        z_(z) {}
+    tvec3(const tvec3& v) :
+        x_(v.x_),
+        y_(v.y_),
+        z_(v.z_) {}
+    ~tvec3() {}
+
+    void print() const
+    {
+        std::cout << "| " << x_ << " " << y_ << " " << z_ << " |" << std::endl;
+    }
+    operator const T*() const { return &x_;}
+
+    const T x() const { return x_; }
+    const T y() const { return y_; }
+    const T z() const { return z_; }
+
+    void x(const T& val) { x_ = val; }
+    void y(const T& val) { y_ = val; }
+    void z(const T& val) { z_ = val; }
+
+    tvec3& operator=(const tvec3& rhs)
+    {
+        if (this != &rhs)
+        {
+            x_ = rhs.x_;
+            y_ = rhs.y_;
+            z_ = rhs.z_;
+        }
+        return *this;
+    }
+
+    tvec3& operator/=(const T& rhs)
+    {
+        x_ /= rhs;
+        y_ /= rhs;
+        z_ /= rhs;
+        return *this;
+    }
+
+    const tvec3 operator/(const T& rhs)
+    {
+        return tvec3(*this) /= rhs;
+    }
+
+    tvec3& operator*=(const T& rhs)
+    {
+        x_ *= rhs;
+        y_ *= rhs;
+        z_ *= rhs;
+        return *this;
+    }
+
+    const tvec3 operator*(const T& rhs)
+    {
+        return tvec3(*this) *= rhs;
+    }
+
+    tvec3& operator+=(const T& rhs)
+    {
+        x_ += rhs;
+        y_ += rhs;
+        z_ += rhs;
+        return *this;
+    }
+
+    const tvec3 operator+(const T& rhs)
+    {
+        return tvec3(*this) += rhs;
+    }
+
+    tvec3& operator+=(const tvec3& rhs)
+    {
+        x_ += rhs.x_;
+        y_ += rhs.y_;
+        z_ += rhs.z_;
+        return *this;
+    }
+
+    const tvec3 operator+(const tvec3& rhs)
+    {
+        return tvec3(*this) += rhs;
+    }
+
+    tvec3& operator-=(const T& rhs)
+    {
+        x_ -= rhs;
+        y_ -= rhs;
+        z_ -= rhs;
+        return *this;
+    }
+
+    const tvec3 operator-(const T& rhs)
+    {
+        return tvec3(*this) -= rhs;
+    }
+
+    tvec3& operator-=(const tvec3& rhs)
+    {
+        x_ -= rhs.x_;
+        y_ -= rhs.y_;
+        z_ -= rhs.z_;
+        return *this;
+    }
+
+    const tvec3 operator-(const tvec3& rhs)
+    {
+        return tvec3(*this) -= rhs;
+    }
+
+    float length() const
+    {
+        return sqrt(dot(*this, *this));
+    }
+
+    void normalize()
+    {
+        float l = length();
+        x_ /= l;
+        y_ /= l;
+        z_ /= l;
+    }
+
+    static T dot(const tvec3& v1, const tvec3& v2)
+    {
+        return (v1.x_ * v2.x_) + (v1.y_ * v2.y_) + (v1.z_ * v2.z_); 
+    }
+
+    static tvec3 cross(const tvec3& u, const tvec3& v)
+    {
+        return tvec3((u.y_ * v.z_) - (u.z_ * v.y_),
+                    (u.z_ * v.x_) - (u.x_ * v.z_),
+                    (u.x_ * v.y_) - (u.y_ * v.x_));
+    }
+
+private:
+    T x_;
+    T y_;
+    T z_;
+};
+
+template<typename T>
+class tvec4
+{
+public:
+    tvec4() :
+        x_(0),
+        y_(0),
+        z_(0),
+        w_(0) {}
+    tvec4(T t) :
+        x_(t),
+        y_(t),
+        z_(t),
+        w_(t) {}
+    tvec4(T x, T y, T z, T w) :
+        x_(x),
+        y_(y),
+        z_(z),
+        w_(w) {}
+    tvec4(const tvec4& v) :
+        x_(v.x_),
+        y_(v.y_),
+        z_(v.z_),
+        w_(v.w_) {}
+    ~tvec4() {}
+
+    void print() const
+    {
+        std::cout << "| " << x_ << " " << y_ << " " << z_ << " " << w_ << " |" << std::endl;
+    }
+    operator const T*() const { return &x_;}
+
+    const T x() const { return x_; }
+    const T y() const { return y_; }
+    const T z() const { return z_; }
+    const T w() const { return w_; }
+
+    void x(const T& val) { x_ = val; }
+    void y(const T& val) { y_ = val; }
+    void z(const T& val) { z_ = val; }
+    void w(const T& val) { w_ = val; }
+
+    tvec4& operator=(const tvec4& rhs)
+    {
+        if (this != &rhs)
+        {
+            x_ = rhs.x_;
+            y_ = rhs.y_;
+            z_ = rhs.z_;
+            w_ = rhs.w_;
+        }
+        return *this;
+    }
+
+    tvec4& operator/=(const T& rhs)
+    {
+        x_ /= rhs;
+        y_ /= rhs;
+        z_ /= rhs;
+        w_ /= rhs;
+        return *this;
+    }
+
+    const tvec4 operator/(const T& rhs)
+    {
+        return tvec4(*this) /= rhs;
+    }
+
+    tvec4& operator*=(const T& rhs)
+    {
+        x_ *= rhs;
+        y_ *= rhs;
+        z_ *= rhs;
+        w_ *= rhs;
+        return *this;
+    }
+
+    const tvec4 operator*(const T& rhs)
+    {
+        return tvec4(*this) *= rhs;
+    }
+
+    tvec4& operator+=(const T& rhs)
+    {
+        x_ += rhs;
+        y_ += rhs;
+        z_ += rhs;
+        w_ += rhs;
+        return *this;
+    }
+
+    const tvec4 operator+(const T& rhs)
+    {
+        return tvec4(*this) += rhs;
+    }
+
+    tvec4& operator+=(const tvec4& rhs)
+    {
+        x_ += rhs.x_;
+        y_ += rhs.y_;
+        z_ += rhs.z_;
+        w_ += rhs.w_;
+        return *this;
+    }
+
+    const tvec4 operator+(const tvec4& rhs)
+    {
+        return tvec4(*this) += rhs;
+    }
+
+    tvec4& operator-=(const T& rhs)
+    {
+        x_ -= rhs;
+        y_ -= rhs;
+        z_ -= rhs;
+        w_ -= rhs;
+        return *this;
+    }
+
+    const tvec4 operator-(const T& rhs)
+    {
+        return tvec4(*this) -= rhs;
+    }
+
+    tvec4& operator-=(const tvec4& rhs)
+    {
+        x_ -= rhs.x_;
+        y_ -= rhs.y_;
+        z_ -= rhs.z_;
+        w_ -= rhs.w_;
+        return *this;
+    }
+
+    const tvec4 operator-(const tvec4& rhs)
+    {
+        return tvec4(*this) -= rhs;
+    }
+
+    float length() const
+    {
+        return sqrt(dot(*this, *this));
+    }
+
+    void normalize()
+    {
+        float l = length();
+        x_ /= l;
+        y_ /= l;
+        z_ /= l;
+        w_ /= l;
+    }
+
+    static T dot(const tvec4& v1, const tvec4& v2)
+    {
+        return (v1.x_ * v2.x_) + (v1.y_ * v2.y_) + (v1.z_ * v2.z_) + (v1.w_ * v2.w_); 
+    }
+
+private:
+    T x_;
+    T y_;
+    T z_;
+    T w_;
+};
+
+//
+// Convenience typedefs.  These are here to present a homogeneous view of these
+// objects with respect to shader source.
+//
+typedef tvec2<float> vec2;
+typedef tvec3<float> vec3;
+typedef tvec4<float> vec4;
+
+typedef tvec2<double> dvec2;
+typedef tvec3<double> dvec3;
+typedef tvec4<double> dvec4;
+
+typedef tvec2<int> ivec2;
+typedef tvec3<int> ivec3;
+typedef tvec4<int> ivec4;
+
+typedef tvec2<unsigned int> uvec2;
+typedef tvec3<unsigned int> uvec3;
+typedef tvec4<unsigned int> uvec4;
+
+typedef tvec2<bool> bvec2;
+typedef tvec3<bool> bvec3;
+typedef tvec4<bool> bvec4;
+
+} // namespace LibMatrix
+
+#endif // VEC_H_

=== removed file 'src/matrix.cpp'
--- src/matrix.cpp	2011-01-25 15:00:12 +0000
+++ src/matrix.cpp	1970-01-01 00:00:00 +0000
@@ -1,265 +0,0 @@
-/*
- * Copyright © 2010-2011 Linaro Limited
- *
- * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
- *
- * glmark2 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 3 of the License, or (at your option) any later
- * version.
- *
- * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * glmark2.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- *  Alexandros Frantzis (glmark2)
- */
-#include "matrix.h"
-
-/**
- * Multiply arrays representing 4x4 matrices in column-major order.
- *
- * The result is stored in the first matrix.
- *
- * @param m the first matrix
- * @param n the second matrix
- */
-static void multiply(GLfloat *m, const GLfloat *n)
-{
-   GLfloat tmp[16];
-   const GLfloat *row, *column;
-   div_t d;
-   int i, j;
-
-   for (i = 0; i < 16; i++) {
-      tmp[i] = 0;
-      d = div(i, 4);
-      row = n + d.quot * 4;
-      column = m + d.rem;
-      for (j = 0; j < 4; j++)
-         tmp[i] += row[j] * column[j * 4];
-   }
-   memcpy(m, &tmp, sizeof tmp);
-}
-
-/**
- * Multiply this matrix with another.
- *
- * @param pM the matrix to multiply with.
- *
- * @return reference to this matrix (multiplied)
- */
-Matrix4f &Matrix4f::operator*=(const Matrix4f &pM)
-{
-    multiply(m, pM.m);
-
-    return *this;
-}
-
-/**
- * Rotates a matrix.
- *
- * @param angle the angle to rotate
- * @param x the x component of the rotation axis
- * @param y the y component of the rotation axis
- * @param z the z component of the rotation axis
- *
- * @return reference to the matrix
- */
-Matrix4f &Matrix4f::rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
-{
-   double s, c;
-
-   sincos(angle, &s, &c);
-
-   GLfloat r[16] = {
-      x * x * (1 - c) + c,     y * x * (1 - c) + z * s, x * z * (1 - c) - y * s, 0,
-      x * y * (1 - c) - z * s, y * y * (1 - c) + c,     y * z * (1 - c) + x * s, 0,
-      x * z * (1 - c) + y * s, y * z * (1 - c) - x * s, z * z * (1 - c) + c,     0,
-      0, 0, 0, 1
-   };
-
-   multiply(m, r);
-
-   return *this;
-}
-
-/**
- * Translates a matrix.
- *
- * @param x the x component of the translation
- * @param y the y component of the translation
- * @param z the z component of the translation
- *
- * @return reference to the matrix
- */
-Matrix4f &Matrix4f::translate(GLfloat x, GLfloat y, GLfloat z)
-{
-   GLfloat t[16] = { 1, 0, 0, 0,  0, 1, 0, 0,  0, 0, 1, 0,  x, y, z, 1 };
-
-   multiply(m, t);
-
-   return *this;
-}
-
-/**
- * Transposes a matrix.
- *
- * @return reference to the matrix
- */
-Matrix4f &Matrix4f::transpose()
-{
-   GLfloat t[16] = {
-      m[0], m[4], m[8],  m[12],
-      m[1], m[5], m[9],  m[13],
-      m[2], m[6], m[10], m[14],
-      m[3], m[7], m[11], m[15]};
-
-   memcpy(m, t, sizeof(m));
-
-   return *this;
-}
-
-/**
- * Makes this matrix an identity matrix.
- *
- * @return reference to the matrix
- */
-Matrix4f &Matrix4f::identity()
-{
-   m[0] = 1.0; m[4] = 0.0; m[8] = 0.0;  m[12] = 0.0;
-   m[1] = 0.0; m[5] = 1.0; m[9] = 0.0;  m[13] = 0.0;
-   m[2] = 0.0; m[6] = 0.0; m[10] = 1.0; m[14] = 0.0;
-   m[3] = 0.0; m[7] = 0.0; m[11] = 0.0; m[15] = 1.0;
-
-   return *this;
-}
-
-/**
- * Makes this matrix a perspective projection matrix.
- *
- * @param fovy field of view angle in degrees in the y direction
- * @param aspect aspect ratio of view
- * @param zNear the distance from the viewer to the near clipping plane
- * @param zFar the distance from the viewer to the far clipping plane
- *
- * @return reference to the matrix
- */
-Matrix4f &Matrix4f::perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
-{
-    GLfloat sine, cotangent, deltaZ;
-    GLfloat radians = fovy / 2 * M_PI / 180;
-
-    deltaZ = zFar - zNear;
-    sine = sin(radians);
-
-    if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
-       return *this;
-    }
-
-    cotangent = cos(radians) / sine;
-
-    identity();
-    m[0] = cotangent / aspect;
-    m[5] = cotangent;
-    m[10] = -(zFar + zNear) / deltaZ;
-    m[11] = -1;
-    m[14] = -2 * zNear * zFar / deltaZ;
-    m[15] = 0;
-
-    return *this;
-}
-
-/**
- * Inverts this matrix.
- *
- * This method can currently handle only pure translation-rotation matrices.
- *
- * @return reference to the matrix
- */
-Matrix4f &Matrix4f::invert()
-{
-   // If the bottom row is [0, 0, 0, 1] this is a pure translation-rotation
-   // transformation matrix and we can optimize the matrix inversion.
-   // Read http://www.gamedev.net/community/forums/topic.asp?topic_id=425118
-   // for an explanation.
-   if (m[3] == 0.0 &&  m[7] == 0.0 && m[11] == 0.0 && m[15] == 1.0) {
-      // Extract and invert the translation part 't'. The inverse of a
-      // translation matrix can be calculated by negating the translation
-      // coordinates.
-      Matrix4f t(1.0, 1.0, 1.0);
-      t.m[12] = -m[12]; t.m[13] = -m[13]; t.m[14] = -m[14];
-
-      // Invert the rotation part 'r'. The inverse of a rotation matrix is
-      // equal to its transpose.
-      m[12] = m[13] = m[14] = 0;
-      this->transpose();
-
-      // inv(m) = inv(r) * inv(t)
-      *this *= t;
-   }
-   else {
-      // Don't care about the general case for now
-   }
-
-   return *this;
-}
-
-/**
- * Creates an empty matrix.
- *
- * All matrix components are 0.0 expect the lower right
- * which is 1.0.
- */
-Matrix4f::Matrix4f()
-{
-    memset(m, 0, sizeof(m));
-    m[15] = 1.0;
-}
-
-/**
- * Copy constructor.
- *
- * @param mat the matrix to copy the contents of.
- */
-Matrix4f::Matrix4f(Matrix4f &mat)
-{
-   memcpy(m, mat.m, sizeof(m));
-}
-
-/**
- * Creates a matrix with specified values in the diagonal.
- *
- * The lower right value is initialized to 1.0.
- *
- * @param x the x component of the diagonal
- * @param y the y component of the diagonal
- * @param z the z component of the diagonal
- */
-Matrix4f::Matrix4f(GLfloat x, GLfloat y, GLfloat z)
-{
-    memset(m, 0, sizeof(m));
-    m[0] = x;
-    m[5] = y;
-    m[10] = z;
-    m[15] = 1.0;
-}
-
-/**
- * Displays a matrix.
- *
- * @param str string to display before matrix
- */
-void Matrix4f::display(const char *str)
-{
-   int r;
-   if (str != NULL)
-      printf("%s\n", str);
-   for(r = 0; r < 4; r++)
-      printf("%f %f %f %f\n", m[r], m[r + 4], m[r + 8], m[r + 12]);
-}

=== removed file 'src/matrix.h'
--- src/matrix.h	2011-01-25 15:06:04 +0000
+++ src/matrix.h	1970-01-01 00:00:00 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright © 2010-2011 Linaro Limited
- *
- * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
- *
- * glmark2 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 3 of the License, or (at your option) any later
- * version.
- *
- * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * glmark2.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- *  Alexandros Frantzis (glmark2)
- */
-#ifndef GLMARK2_MATRIX_H_
-#define GLMARK2_MATRIX_H_
-
-#include "oglsdl.h"
-
-#include <stdio.h>
-#include <math.h>
-
-class Matrix4f
-{
-
-public:
-    GLfloat m[16];
-
-    Matrix4f();
-    Matrix4f(Matrix4f &mat);
-    Matrix4f(GLfloat x, GLfloat y, GLfloat z);
-
-    Matrix4f &translate(GLfloat x, GLfloat y, GLfloat z);
-    Matrix4f &rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
-    Matrix4f &transpose();
-    Matrix4f &perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
-    Matrix4f &identity();
-    Matrix4f &invert();
-
-    Matrix4f &operator*=(const Matrix4f &pM);
-
-    void display(const char *str);
-};
-
-#endif

=== modified file 'src/mesh.cpp'
--- src/mesh.cpp	2011-06-07 09:40:55 +0000
+++ src/mesh.cpp	2011-06-17 13:16:16 +0000
@@ -22,17 +22,7 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "mesh.h"
-#include "shader.h"
-
-Texel::Texel()
-{
-    u = 0;  v = 0;
-}
-
-Texel::Texel(GLfloat pU, GLfloat pV)
-{
-    u = pU; v = pV;
-}
+
 
 Mesh::Mesh()
 {
@@ -74,7 +64,7 @@
     unsigned i, j;
     unsigned k = 0;
 
-    Vector3f a, b, c, d, n;
+    LibMatrix::vec3 a, b, c, d, n;
 
     mMode = GL_TRIANGLES;
     mVertexQty = wraps_qty * per_wrap_qty * 6;
@@ -87,60 +77,66 @@
             float phi = 2 * M_PI * wrap_frac;
             float theta = 2 * M_PI * (i + wrap_frac) / (float)wraps_qty;
             float r = major_radius + minor_radius * (float)cos(phi);
-            a.x = (float)sin(theta) * r;
-            a.y = minor_radius * (float)sin(phi);
-            a.z = (float)cos(theta) * r;
+            a.x((float)sin(theta) * r);
+            a.y(minor_radius * (float)sin(phi));
+            a.z((float)cos(theta) * r);
 
             theta = 2 * M_PI * (i + wrap_frac + 1) / (float)wraps_qty;
-            b.x = (float)sin(theta) * r;
-            b.y = minor_radius * (float)sin(phi);
-            b.z = (float)cos(theta) * r;
+            b.x((float)sin(theta) * r);
+            b.y(minor_radius * (float)sin(phi));
+            b.z((float)cos(theta) * r);
 
             wrap_frac = (j + 1) / (float)per_wrap_qty;
             phi = 2 * M_PI * wrap_frac;
             theta = 2 * M_PI * (i + wrap_frac) / (float)wraps_qty;
             r = major_radius + minor_radius * (float)cos(phi);
-            c.x = (float)sin(theta) * r;
-            c.y = minor_radius * (float)sin(phi);
-            c.z = (float)cos(theta) * r;
+            c.x((float)sin(theta) * r);
+            c.y(minor_radius * (float)sin(phi));
+            c.z((float)cos(theta) * r);
 
             theta = 2 * M_PI * (i + wrap_frac + 1) / (float)wraps_qty;
-            d.x = (float)sin(theta) * r;
-            d.y = minor_radius * (float)sin(phi);
-            d.z = (float)cos(theta) * r;
+            d.x((float)sin(theta) * r);
+            d.y(minor_radius * (float)sin(phi));
+            d.z((float)cos(theta) * r);
 
-            n = normal(a, b, c);
+            n = LibMatrix::vec3::cross(b - a, c - a);
+            n.normalize();
             mVertex[k].n = n;   mVertex[k].v = a;   k++;
             mVertex[k].n = n;   mVertex[k].v = b;   k++;
             mVertex[k].n = n;   mVertex[k].v = c;   k++;
-            n = normal(a, b, c);
+            n = LibMatrix::vec3::cross(c - b, d - b);
+            n.normalize();
             mVertex[k].n = n;   mVertex[k].v = b;   k++;
             mVertex[k].n = n;   mVertex[k].v = c;   k++;
             mVertex[k].n = n;   mVertex[k].v = d;   k++;
         }
 }
 
-void Mesh::render_array()
+void Mesh::render_array(int vertex_loc, int normal_loc, int texcoord_loc)
 {
-    // Enable the attributes
-    glEnableVertexAttribArray(Shader::VertexAttribLocation);
-    glEnableVertexAttribArray(Shader::NormalAttribLocation);
-    glEnableVertexAttribArray(Shader::TexCoordAttribLocation);
+    // Enable the attributes (texcoord is optional)
+    glEnableVertexAttribArray(vertex_loc);
+    glEnableVertexAttribArray(normal_loc);
+    if (texcoord_loc >= 0)
+        glEnableVertexAttribArray(texcoord_loc);
 
     glBindBuffer(GL_ARRAY_BUFFER, 0);
-    glVertexAttribPointer(Shader::VertexAttribLocation, 3, GL_FLOAT,
-                          GL_FALSE, sizeof(Vertex), &mVertex[0].v.x);
-    glVertexAttribPointer(Shader::NormalAttribLocation, 3, GL_FLOAT,
-                          GL_FALSE, sizeof(Vertex), &mVertex[0].n.x);
-    glVertexAttribPointer(Shader::TexCoordAttribLocation, 2, GL_FLOAT,
-                          GL_FALSE, sizeof(Vertex), &mVertex[0].t.u);
+    glVertexAttribPointer(vertex_loc, 3, GL_FLOAT, GL_FALSE,
+                          8 * sizeof(float), mVertex[0].v);
+    glVertexAttribPointer(normal_loc, 3, GL_FLOAT, GL_FALSE,
+                          8 * sizeof(float), mVertex[0].n);
+    if (texcoord_loc >= 0) {
+        glVertexAttribPointer(texcoord_loc, 2, GL_FLOAT, GL_FALSE,
+                              8 * sizeof(float), mVertex[0].t);
+    }
 
     glDrawArrays(GL_TRIANGLES, 0, mVertexQty);
 
     // Disable the attributes
-    glDisableVertexAttribArray(Shader::TexCoordAttribLocation);
-    glDisableVertexAttribArray(Shader::NormalAttribLocation);
-    glDisableVertexAttribArray(Shader::VertexAttribLocation);
+    glDisableVertexAttribArray(vertex_loc);
+    glDisableVertexAttribArray(normal_loc);
+    if (texcoord_loc >= 0)
+        glDisableVertexAttribArray(texcoord_loc);
 }
 
 void Mesh::build_vbo()
@@ -149,38 +145,43 @@
     printf("Building vbo for mesh...         ");
 #endif
 
-    Vector3f *vertex;
-    Texel *texel;
-    Vector3f *normal;
+    float *vertex;
+    float *texel;
+    float *normal;
 
-    vertex = new Vector3f[mVertexQty];
-    texel = new Texel[mVertexQty];
-    normal = new Vector3f[mVertexQty];
+    vertex = new float[mVertexQty * 3];
+    texel = new float[mVertexQty * 2];
+    normal = new float[mVertexQty * 3];
 
     for(unsigned i = 0; i < mVertexQty; i++)
     {
-        vertex[i] = mVertex[i].v;
-        texel[i] = mVertex[i].t;
-        normal[i] = mVertex[i].n;
+        vertex[3 * i] = mVertex[i].v.x();
+        vertex[3 * i + 1] = mVertex[i].v.y();
+        vertex[3 * i + 2] = mVertex[i].v.z();
+        texel[2 * i] = mVertex[i].t.x();
+        texel[2 * i + 1] = mVertex[i].t.y();
+        normal[3 * i] = mVertex[i].n.x();
+        normal[3 * i + 1] = mVertex[i].n.y();
+        normal[3 * i + 2] = mVertex[i].n.z();
     }
 
     // Generate And Bind The Vertex Buffer
     glGenBuffers(1, &mVBOVertices);
     glBindBuffer(GL_ARRAY_BUFFER, mVBOVertices);
     // Load The Data
-    glBufferData(GL_ARRAY_BUFFER, mVertexQty * sizeof(Vector3f), vertex, GL_STATIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, mVertexQty * 3 * sizeof(float), vertex, GL_STATIC_DRAW);
 
     // Generate And Bind The normal Buffer
     glGenBuffers(1, &mVBONormals);
     glBindBuffer(GL_ARRAY_BUFFER, mVBONormals);
     // Load The Data
-    glBufferData(GL_ARRAY_BUFFER, mVertexQty * sizeof(Vector3f), normal, GL_STATIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, mVertexQty * 3 * sizeof(float), normal, GL_STATIC_DRAW);
 
     // Generate And Bind The Texture Coordinate Buffer
     glGenBuffers(1, &mVBOTexCoords);
     glBindBuffer(GL_ARRAY_BUFFER, mVBOTexCoords);
     // Load The Data
-    glBufferData(GL_ARRAY_BUFFER, mVertexQty * sizeof(Texel), texel, GL_STATIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, mVertexQty * 2 * sizeof(float), texel, GL_STATIC_DRAW);
 
     glBindBuffer(GL_ARRAY_BUFFER, 0);
 
@@ -200,24 +201,28 @@
     glDeleteBuffers(1, &mVBOTexCoords);
 }
 
-void Mesh::render_vbo()
+void Mesh::render_vbo(int vertex_loc, int normal_loc, int texcoord_loc)
 {
-    // Enable the attributes
-    glEnableVertexAttribArray(Shader::VertexAttribLocation);
-    glEnableVertexAttribArray(Shader::NormalAttribLocation);
-    glEnableVertexAttribArray(Shader::TexCoordAttribLocation);
+    // Enable the attributes (texcoord is optional)
+    glEnableVertexAttribArray(vertex_loc);
+    glEnableVertexAttribArray(normal_loc);
+    if (texcoord_loc >= 0)
+        glEnableVertexAttribArray(texcoord_loc);
 
     glBindBuffer(GL_ARRAY_BUFFER, mVBOVertices);
-    glVertexAttribPointer(Shader::VertexAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
+    glVertexAttribPointer(vertex_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
     glBindBuffer(GL_ARRAY_BUFFER, mVBONormals);
-    glVertexAttribPointer(Shader::NormalAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
-    glBindBuffer(GL_ARRAY_BUFFER, mVBOTexCoords);
-    glVertexAttribPointer(Shader::TexCoordAttribLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
+    glVertexAttribPointer(normal_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
+    if (texcoord_loc >= 0) {
+        glBindBuffer(GL_ARRAY_BUFFER, mVBOTexCoords);
+        glVertexAttribPointer(texcoord_loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
+    }
 
     glDrawArrays(GL_TRIANGLES, 0, mVertexQty);
 
     // Disable the attributes
-    glDisableVertexAttribArray(Shader::TexCoordAttribLocation);
-    glDisableVertexAttribArray(Shader::NormalAttribLocation);
-    glDisableVertexAttribArray(Shader::VertexAttribLocation);
+    glDisableVertexAttribArray(vertex_loc);
+    glDisableVertexAttribArray(normal_loc);
+    if (texcoord_loc >= 0)
+        glDisableVertexAttribArray(texcoord_loc);
 }

=== modified file 'src/mesh.h'
--- src/mesh.h	2011-06-07 09:40:55 +0000
+++ src/mesh.h	2011-06-17 13:16:16 +0000
@@ -25,26 +25,15 @@
 #define GLMARK2_MESH_H_
 
 #include "screen.h"
-#include "vector.h"
+#include "vec.h"
 
 #include <stdio.h>
 #include <math.h>
 
-class Texel
-{
-public:
-    GLfloat u, v;
-
-    Texel();
-    Texel(GLfloat pU, GLfloat pV);
-};
-
-class Vertex
-{
-public:
-    Vector3f v;
-    Vector3f n;
-    Texel t;
+struct Vertex {
+    LibMatrix::vec3 v;
+    LibMatrix::vec3 n;
+    LibMatrix::vec2 t;
 };
 
 // Data for a mesh to be rendered by vertex arrays' or vbos' has 3 verticies per
@@ -67,10 +56,10 @@
     void reset();
     void make_cube();
     void make_torus();
-    void render_array();
+    void render_array(int vertex_loc, int normal_loc, int texcoord_loc);
     void build_vbo();
     void delete_vbo();
-    void render_vbo();
+    void render_vbo(int vertex_loc, int normal_loc, int texcoord_loc);
 };
 
 #endif

=== modified file 'src/model.cpp'
--- src/model.cpp	2011-06-07 09:40:55 +0000
+++ src/model.cpp	2011-06-17 09:39:44 +0000
@@ -22,6 +22,7 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "model.h"
+#include "vec.h"
 
 long filelength(int f)
 {
@@ -82,11 +83,13 @@
 #ifdef _DEBUG
     printf("Calculating normals for model... ");
 #endif
-    Vector3f n;
+    LibMatrix::vec3 n;
 
     for(unsigned i = 0; i < mPolygonQty; i++)
     {
-        n = normal(mVertex[mPolygon[i].mA].v, mVertex[mPolygon[i].mB].v, mVertex[mPolygon[i].mC].v);
+        n = LibMatrix::vec3::cross(mVertex[mPolygon[i].mB].v - mVertex[mPolygon[i].mA].v,
+                                   mVertex[mPolygon[i].mC].v - mVertex[mPolygon[i].mA].v);
+        n.normalize();
         mVertex[mPolygon[i].mA].n += n;
         mVertex[mPolygon[i].mB].n += n;
         mVertex[mPolygon[i].mC].n += n;
@@ -102,21 +105,22 @@
 
 void Model::center()
 {
-    Vector3f center;
-    Vector3f max = mVertex[0].v, min = mVertex[0].v;
+    LibMatrix::vec3 max(mVertex[0].v);
+    LibMatrix::vec3 min(mVertex[0].v);
 
     for(unsigned i = 1; i < mVertexQty; i++)
     {
-        if(mVertex[i].v.x > max.x) max.x = mVertex[i].v.x;
-        if(mVertex[i].v.y > max.y) max.y = mVertex[i].v.y;
-        if(mVertex[i].v.z > max.z) max.z = mVertex[i].v.z;
+        if(mVertex[i].v.x() > max.x()) max.x(mVertex[i].v.x());
+        if(mVertex[i].v.y() > max.y()) max.y(mVertex[i].v.y());
+        if(mVertex[i].v.z() > max.z()) max.z(mVertex[i].v.z());
 
-        if(mVertex[i].v.x < min.x) min.x = mVertex[i].v.x;
-        if(mVertex[i].v.y < min.y) min.y = mVertex[i].v.y;
-        if(mVertex[i].v.z < min.z) min.z = mVertex[i].v.z;
+        if(mVertex[i].v.x() < min.x()) min.x(mVertex[i].v.x());
+        if(mVertex[i].v.y() < min.y()) min.y(mVertex[i].v.y());
+        if(mVertex[i].v.z() < min.z()) min.z(mVertex[i].v.z());
     }
 
-    center = (max + min) / 2.0f;
+    LibMatrix::vec3 center(max + min);
+    center /= 2.0f;
 
     for(unsigned i = 0; i < mVertexQty; i++)
         mVertex[i].v -= center;
@@ -210,9 +214,11 @@
                 mVertexQty = l_qty;
                 mVertex = new Vertex[mVertexQty];
                 for (i = 0; i < l_qty; i++) {
-                    nread = fread (&mVertex[i].v.x, sizeof(float), 1, l_file);
-                    nread = fread (&mVertex[i].v.y, sizeof(float), 1, l_file);
-                    nread = fread (&mVertex[i].v.z, sizeof(float), 1, l_file);
+                    float f[3];
+                    nread = fread (f, sizeof(float), 3, l_file);
+                    mVertex[i].v.x(f[0]);
+                    mVertex[i].v.y(f[1]);
+                    mVertex[i].v.z(f[2]);
                 }
                 break;
 
@@ -245,8 +251,10 @@
             case 0x4140:
                 nread = fread (&l_qty, sizeof (unsigned short), 1, l_file);
                 for (i = 0; i < l_qty; i++) {
-                    nread = fread (&mVertex[i].t.u, sizeof (float), 1, l_file);
-                    nread = fread (&mVertex[i].t.v, sizeof (float), 1, l_file);
+                    float f[2];
+                    nread = fread (f, sizeof(float), 2, l_file);
+                    mVertex[i].t.x(f[0]);
+                    mVertex[i].t.y(f[1]);
                 }
                 break;
 

=== modified file 'src/scene.cpp'
--- src/scene.cpp	2011-06-15 11:20:45 +0000
+++ src/scene.cpp	2011-06-17 13:16:16 +0000
@@ -22,6 +22,7 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "scene.h"
+#include "log.h"
 #include <sstream>
 #include <cmath>
 
@@ -154,3 +155,50 @@
 
     return std::sqrt(s);
 }
+
+bool
+Scene::load_shaders(Program &program,
+                    const std::string &vtx_shader_filename,
+                    const std::string &frg_shader_filename)
+{
+    std::string vtx_shader;
+    std::string frg_shader;
+
+    if (!gotSource(vtx_shader_filename, vtx_shader))
+        return false;
+
+    if (!gotSource(frg_shader_filename, frg_shader))
+        return false;
+
+    program.init();
+
+    program.addShader(GL_VERTEX_SHADER, vtx_shader);
+    if (!program.valid()) {
+        Log::error("Failed to add vertex shader from file %s:\n  %s\n",
+                   vtx_shader_filename.c_str(),
+                   program.errorMessage().c_str());
+        program.release();
+        return false;
+    }
+
+    program.addShader(GL_FRAGMENT_SHADER, frg_shader);
+    if (!program.valid()) {
+        Log::error("Failed to add fragment shader from file %s:\n  %s\n",
+                   frg_shader_filename.c_str(),
+                   program.errorMessage().c_str());
+        program.release();
+        return false;
+    }
+
+    program.build();
+    if (!program.ready()) {
+        Log::error("Failed to link program created from files %s and %s:  %s\n",
+                   vtx_shader_filename.c_str(),
+                   frg_shader_filename.c_str(),
+                   program.errorMessage().c_str());
+        program.release();
+        return false;
+    }
+
+    return true;
+}

=== modified file 'src/scene.h'
--- src/scene.h	2011-06-16 07:43:05 +0000
+++ src/scene.h	2011-06-17 13:16:16 +0000
@@ -29,7 +29,8 @@
 #include "mesh.h"
 #include "model.h"
 #include "texture.h"
-#include "shader.h"
+#include "vec.h"
+#include "program.h"
 
 #include <math.h>
 
@@ -90,6 +91,10 @@
 
     virtual ValidationResult validate() { return ValidationUnknown; }
 
+    static bool load_shaders(Program &program,
+                             const std::string &vtx_shader_filename,
+                             const std::string &frg_shader_filename);
+
 protected:
     Scene(Screen &pScreen, const std::string &name);
     std::string construct_title(const std::string &title);
@@ -124,7 +129,10 @@
     ~SceneBuild();
 
 protected:
-    Shader mShader;
+    Program mProgram;
+    int mVertexAttribLocation;
+    int mNormalAttribLocation;
+    int mTexcoordAttribLocation;
 
     Mesh mMesh;
     float mRotation;
@@ -147,12 +155,15 @@
     ~SceneTexture();
 
 protected:
-    Shader mShader;
+    Program mProgram;
+    int mVertexAttribLocation;
+    int mNormalAttribLocation;
+    int mTexcoordAttribLocation;
 
     Mesh mCubeMesh;
     GLuint mTexture;
-    Vector3f mRotation;
-    Vector3f mRotationSpeed;
+    LibMatrix::vec3 mRotation;
+    LibMatrix::vec3 mRotationSpeed;
 };
 
 class SceneShading : public Scene
@@ -170,7 +181,10 @@
     ~SceneShading();
 
 protected:
-    Shader mShader;
+    Program mProgram;
+    int mVertexAttribLocation;
+    int mNormalAttribLocation;
+    int mTexcoordAttribLocation;
 
     Mesh mMesh;
     float mRotation;

=== modified file 'src/scenebuild.cpp'
--- src/scenebuild.cpp	2011-06-15 11:44:36 +0000
+++ src/scenebuild.cpp	2011-06-17 13:16:16 +0000
@@ -23,6 +23,8 @@
  */
 #include "scene.h"
 #include "log.h"
+#include "mat.h"
+#include "stack.h"
 #include <cmath>
 
 SceneBuild::SceneBuild(Screen &pScreen) :
@@ -38,6 +40,8 @@
 
 int SceneBuild::load()
 {
+    static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.vert");
+    static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.frag");
     Model model;
 
     if(!model.load_3ds(GLMARK_DATA_PATH"/models/horse.3ds"))
@@ -46,8 +50,12 @@
     model.calculate_normals();
     model.convert_to_mesh(&mMesh);
 
-    mShader.load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
-                 GLMARK_DATA_PATH"/shaders/light-basic.frag");
+    if (!Scene::load_shaders(mProgram, vtx_shader_filename, frg_shader_filename))
+        return 0;
+
+    mVertexAttribLocation = mProgram.getAttribIndex("position");
+    mNormalAttribLocation = mProgram.getAttribIndex("normal");
+    mTexcoordAttribLocation = mProgram.getAttribIndex("texcoord");
 
     mRotationSpeed = 36.0f;
 
@@ -59,34 +67,32 @@
 void SceneBuild::unload()
 {
     mMesh.reset();
-    mShader.remove();
-    mShader.unload();
+
+    mProgram.stop();
+    mProgram.release();
 }
 
 void SceneBuild::setup()
 {
     Scene::setup();
 
-    GLfloat lightAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
-    GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
-    GLfloat lightPosition[] = {20.0f, 20.0f, 10.0f, 1.0f};
-    GLfloat materialColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
-
+    static const LibMatrix::vec4 lightAmbient(0.0f, 0.0f, 0.0f, 1.0f);
+    static const LibMatrix::vec4 lightDiffuse(0.8f, 0.8f, 0.8f, 1.0f);
+    static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
+    static const LibMatrix::vec4 materialColor(1.0f, 1.0f, 1.0f, 1.0f);
 
     mUseVbo = (mOptions["use-vbo"].value == "true");
 
     if (mUseVbo)
         mMesh.build_vbo();
 
-    mShader.use();
+    mProgram.start();
 
     // Load lighting and material uniforms
-    glUniform4fv(mShader.mLocations.LightSourcePosition, 1, lightPosition);
-
-    glUniform3fv(mShader.mLocations.LightSourceAmbient, 1, lightAmbient);
-    glUniform3fv(mShader.mLocations.LightSourceDiffuse, 1, lightDiffuse);
-
-    glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
+    mProgram.loadUniformVector(lightAmbient, "LightSourceAmbient");
+    mProgram.loadUniformVector(lightPosition, "LightSourcePosition");
+    mProgram.loadUniformVector(lightDiffuse, "LightSourceDiffuse");
+    mProgram.loadUniformVector(materialColor, "MaterialColor");
 
     mCurrentFrame = 0;
     mRotation = 0.0;
@@ -98,7 +104,7 @@
 void
 SceneBuild::teardown()
 {
-    mShader.remove();
+    mProgram.stop();
 
     if (mUseVbo)
         mMesh.delete_vbo();
@@ -126,27 +132,33 @@
 
 void SceneBuild::draw()
 {
+    LibMatrix::Stack4 model_view;
+
     // Load the ModelViewProjectionMatrix uniform in the shader
-    Matrix4f model_view(1.0f, 1.0f, 1.0f);
-    Matrix4f model_view_proj(mScreen.mProjection);
+    LibMatrix::mat4 model_view_proj(mScreen.mProjection);
 
     model_view.translate(0.0f, 0.0f, -2.5f);
-    model_view.rotate(2 * M_PI * mRotation / 360.0, 0.0f, 1.0f, 0.0f);
-    model_view_proj *= model_view;
+    model_view.rotate(mRotation, 0.0f, 1.0f, 0.0f);
+    model_view_proj *= model_view.getCurrent();
 
-    glUniformMatrix4fv(mShader.mLocations.ModelViewProjectionMatrix, 1,
-                       GL_FALSE, model_view_proj.m);
+    mProgram.loadUniformMatrix(model_view_proj, "ModelViewProjectionMatrix");
 
     // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
     // inverse transpose of the model view matrix.
-    model_view.invert().transpose();
-    glUniformMatrix4fv(mShader.mLocations.NormalMatrix, 1,
-                       GL_FALSE, model_view.m);
+    LibMatrix::mat4 normal_matrix(model_view.getCurrent());
+    normal_matrix.inverse().transpose();
+    mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
 
-    if (mUseVbo)
-        mMesh.render_vbo();
-    else
-        mMesh.render_array();
+    if (mUseVbo) {
+        mMesh.render_vbo(mVertexAttribLocation,
+                         mNormalAttribLocation,
+                         mTexcoordAttribLocation);
+    }
+    else {
+        mMesh.render_array(mVertexAttribLocation,
+                           mNormalAttribLocation,
+                           mTexcoordAttribLocation);
+    }
 }
 
 Scene::ValidationResult

=== modified file 'src/sceneshading.cpp'
--- src/sceneshading.cpp	2011-06-16 07:43:05 +0000
+++ src/sceneshading.cpp	2011-06-17 13:16:16 +0000
@@ -22,7 +22,9 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "scene.h"
-#include "matrix.h"
+#include "mat.h"
+#include "stack.h"
+#include "vec.h"
 #include "log.h"
 
 #include <cmath>
@@ -66,48 +68,55 @@
 {
     Scene::setup();
 
-    GLfloat lightAmbient[] = {0.1f, 0.1f, 0.1f, 1.0f};
-    GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
-    GLfloat lightSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f};
-    GLfloat lightPosition[] = {20.0f, 20.0f, 10.0f, 1.0f};
-
-    float materialAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f};
-    float materialDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
-    float materialSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};
-    float materialColor[] = {0.0f, 0.0f, 1.0f, 1.0f};
-
+    static const LibMatrix::vec3 lightAmbient(0.1f, 0.1f, 0.1f);
+    static const LibMatrix::vec3 lightDiffuse(0.8f, 0.8f, 0.8f);
+    static const LibMatrix::vec3 lightSpecular(0.8f, 0.8f, 0.8f);
+    static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
+
+    static const LibMatrix::vec3 materialAmbient(1.0f, 1.0f, 1.0f);
+    static const LibMatrix::vec3 materialDiffuse(1.0f, 1.0f, 1.0f);
+    static const LibMatrix::vec3 materialSpecular(1.0f, 1.0f, 1.0f);
+    static const LibMatrix::vec4 materialColor(0.0f, 0.0f, 1.0f, 1.0f);
+
+    std::string vtx_shader_filename;
+    std::string frg_shader_filename;
     const std::string &shading = mOptions["shading"].value;
 
     if (shading == "gouraud") {
-        mShader.load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
-                     GLMARK_DATA_PATH"/shaders/light-basic.frag");
+        vtx_shader_filename = GLMARK_DATA_PATH"/shaders/light-basic.vert";
+        frg_shader_filename = GLMARK_DATA_PATH"/shaders/light-basic.frag";
     }
     else if (shading == "phong") {
-        mShader.load(GLMARK_DATA_PATH"/shaders/light-advanced.vert",
-                     GLMARK_DATA_PATH"/shaders/light-advanced.frag");
+        vtx_shader_filename = GLMARK_DATA_PATH"/shaders/light-advanced.vert";
+        frg_shader_filename = GLMARK_DATA_PATH"/shaders/light-advanced.frag";
     }
 
-    mShader.use();
+    if (!Scene::load_shaders(mProgram, vtx_shader_filename, frg_shader_filename))
+        return;
+
+    mProgram.start();
+
+    mVertexAttribLocation = mProgram.getAttribIndex("position");
+    mNormalAttribLocation = mProgram.getAttribIndex("normal");
+    mTexcoordAttribLocation = mProgram.getAttribIndex("texcoord");
 
     // Load lighting and material uniforms
-    glUniform4fv(mShader.mLocations.LightSourcePosition, 1, lightPosition);
-
-    glUniform3fv(mShader.mLocations.LightSourceAmbient, 1, lightAmbient);
-    glUniform3fv(mShader.mLocations.LightSourceDiffuse, 1, lightDiffuse);
-    glUniform3fv(mShader.mLocations.LightSourceSpecular, 1, lightSpecular);
-
-    glUniform3fv(mShader.mLocations.MaterialAmbient, 1, materialAmbient);
-    glUniform3fv(mShader.mLocations.MaterialDiffuse, 1, materialDiffuse);
-    glUniform3fv(mShader.mLocations.MaterialSpecular, 1, materialSpecular);
-    glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
+    mProgram.loadUniformVector(lightAmbient, "LightSourceAmbient");
+    mProgram.loadUniformVector(lightPosition, "LightSourcePosition");
+    mProgram.loadUniformVector(lightDiffuse, "LightSourceDiffuse");
+    mProgram.loadUniformVector(lightSpecular, "LightSourceSpecular");
+
+    mProgram.loadUniformVector(materialAmbient, "MaterialAmbient");
+    mProgram.loadUniformVector(materialDiffuse, "MaterialDiffuse");
+    mProgram.loadUniformVector(materialSpecular, "MaterialSpecular");
+    mProgram.loadUniformVector(materialColor, "MaterialColor");
 
     // Calculate and load the half vector
-    Vector3f halfVector = Vector3f(lightPosition[0], lightPosition[1], lightPosition[2]);
-    halfVector.normalize();
-    halfVector += Vector3f(0.0, 0.0, 1.0);
-    halfVector.normalize();
-    glUniform3fv(mShader.mLocations.LightSourceHalfVector, 1,
-                 (GLfloat *)&halfVector);
+    LibMatrix::vec3 halfVector(lightPosition[0], lightPosition[1], lightPosition[2]);
+    halfVector.normalize();
+    halfVector += LibMatrix::vec3(0.0, 0.0, 1.0);
+    halfVector.normalize();
+    mProgram.loadUniformVector(halfVector, "LightSourceHalfVector");
 
     mCurrentFrame = 0;
     mRotation = 0.0f;
@@ -118,8 +127,8 @@
 
 void SceneShading::teardown()
 {
-    mShader.remove();
-    mShader.unload();
+    mProgram.stop();
+    mProgram.release();
 
     Scene::teardown();
 }
@@ -145,23 +154,24 @@
 void SceneShading::draw()
 {
     // Load the ModelViewProjectionMatrix uniform in the shader
-    Matrix4f model_view(1.0f, 1.0f, 1.0f);
-    Matrix4f model_view_proj(mScreen.mProjection);
+    LibMatrix::Stack4 model_view;
+    LibMatrix::mat4 model_view_proj(mScreen.mProjection);
 
     model_view.translate(0.0f, 0.0f, -5.0f);
-    model_view.rotate(2 * M_PI * mRotation / 360.0, 0.0f, 1.0f, 0.0f);
-    model_view_proj *= model_view;
+    model_view.rotate(mRotation, 0.0f, 1.0f, 0.0f);
+    model_view_proj *= model_view.getCurrent();
 
-    glUniformMatrix4fv(mShader.mLocations.ModelViewProjectionMatrix, 1,
-                       GL_FALSE, model_view_proj.m);
+    mProgram.loadUniformMatrix(model_view_proj, "ModelViewProjectionMatrix");
 
     // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
     // inverse transpose of the model view matrix.
-    model_view.invert().transpose();
-    glUniformMatrix4fv(mShader.mLocations.NormalMatrix, 1,
-                       GL_FALSE, model_view.m);
+    LibMatrix::mat4 normal_matrix(model_view.getCurrent());
+    normal_matrix.inverse().transpose();
+    mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
 
-    mMesh.render_vbo();
+    mMesh.render_vbo(mVertexAttribLocation,
+                     mNormalAttribLocation,
+                     mTexcoordAttribLocation);
 }
 
 Scene::ValidationResult

=== modified file 'src/scenetexture.cpp'
--- src/scenetexture.cpp	2011-06-16 07:39:55 +0000
+++ src/scenetexture.cpp	2011-06-17 13:16:16 +0000
@@ -22,9 +22,12 @@
  *  Alexandros Frantzis (glmark2)
  */
 #include "scene.h"
-#include "matrix.h"
+#include "mat.h"
+#include "stack.h"
+#include "vec.h"
 #include "log.h"
 
+#include "program.h"
 #include <cmath>
 
 SceneTexture::SceneTexture(Screen &pScreen) :
@@ -40,6 +43,8 @@
 
 int SceneTexture::load()
 {
+    static const std::string vtx_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic.vert");
+    static const std::string frg_shader_filename(GLMARK_DATA_PATH"/shaders/light-basic-tex.frag");
     Model model;
 
     if(!model.load_3ds(GLMARK_DATA_PATH"/models/cube.3ds"))
@@ -49,10 +54,14 @@
     model.convert_to_mesh(&mCubeMesh);
     mCubeMesh.build_vbo();
 
-    mShader.load(GLMARK_DATA_PATH"/shaders/light-basic.vert",
-                 GLMARK_DATA_PATH"/shaders/light-basic-tex.frag");
-
-    mRotationSpeed = Vector3f(36.0f, 36.0f, 36.0f);
+    if (!Scene::load_shaders(mProgram, vtx_shader_filename, frg_shader_filename))
+        return 0;
+
+    mVertexAttribLocation = mProgram.getAttribIndex("position");
+    mNormalAttribLocation = mProgram.getAttribIndex("normal");
+    mTexcoordAttribLocation = mProgram.getAttribIndex("texcoord");
+
+    mRotationSpeed = LibMatrix::vec3(36.0f, 36.0f, 36.0f);
 
     mRunning = false;
 
@@ -62,17 +71,19 @@
 void SceneTexture::unload()
 {
     mCubeMesh.reset();
-    mShader.unload();
+
+    mProgram.stop();
+    mProgram.release();
 }
 
 void SceneTexture::setup()
 {
     Scene::setup();
 
-    GLfloat lightAmbient[] = {0.0f, 0.0f, 0.0f, 1.0f};
-    GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
-    GLfloat lightPosition[] = {20.0f, 20.0f, 10.0f, 1.0f};
-    GLfloat materialColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
+    static const LibMatrix::vec4 lightAmbient(0.0f, 0.0f, 0.0f, 1.0f);
+    static const LibMatrix::vec4 lightDiffuse(0.8f, 0.8f, 0.8f, 1.0f);
+    static const LibMatrix::vec4 lightPosition(20.0f, 20.0f, 10.0f, 1.0f);
+    static const LibMatrix::vec4 materialColor(1.0f, 1.0f, 1.0f, 1.0f);
 
     // Create texture according to selected filtering
     GLint min_filter = GL_NONE;
@@ -95,18 +106,16 @@
     Texture::load(GLMARK_DATA_PATH"/textures/crate-base.bmp", &mTexture,
                   min_filter, mag_filter, 0);
 
-    mShader.use();
+    mProgram.start();
 
     // Load lighting and material uniforms
-    glUniform4fv(mShader.mLocations.LightSourcePosition, 1, lightPosition);
-
-    glUniform3fv(mShader.mLocations.LightSourceAmbient, 1, lightAmbient);
-    glUniform3fv(mShader.mLocations.LightSourceDiffuse, 1, lightDiffuse);
-
-    glUniform4fv(mShader.mLocations.MaterialColor, 1, materialColor);
+    mProgram.loadUniformVector(lightAmbient, "LightSourceAmbient");
+    mProgram.loadUniformVector(lightPosition, "LightSourcePosition");
+    mProgram.loadUniformVector(lightDiffuse, "LightSourceDiffuse");
+    mProgram.loadUniformVector(materialColor, "MaterialColor");
 
     mCurrentFrame = 0;
-    mRotation = Vector3f();
+    mRotation = LibMatrix::vec3();
     mRunning = true;
     mStartTime = SDL_GetTicks() / 1000.0;
     mLastUpdateTime = mStartTime;
@@ -114,7 +123,7 @@
 
 void SceneTexture::teardown()
 {
-    mShader.remove();
+    mProgram.stop();
     glDeleteTextures(1, &mTexture);
 
     Scene::teardown();
@@ -141,28 +150,29 @@
 void SceneTexture::draw()
 {
     // Load the ModelViewProjectionMatrix uniform in the shader
-    Matrix4f model_view(1.0f, 1.0f, 1.0f);
-    Matrix4f model_view_proj(mScreen.mProjection);
+    LibMatrix::Stack4 model_view;
+    LibMatrix::mat4 model_view_proj(mScreen.mProjection);
 
     model_view.translate(0.0f, 0.0f, -5.0f);
-    model_view.rotate(2 * M_PI * mRotation.x / 360.0, 1.0f, 0.0f, 0.0f);
-    model_view.rotate(2 * M_PI * mRotation.y / 360.0, 0.0f, 1.0f, 0.0f);
-    model_view.rotate(2 * M_PI * mRotation.z / 360.0, 0.0f, 0.0f, 1.0f);
-    model_view_proj *= model_view;
+    model_view.rotate(mRotation.x(), 1.0f, 0.0f, 0.0f);
+    model_view.rotate(mRotation.y(), 0.0f, 1.0f, 0.0f);
+    model_view.rotate(mRotation.z(), 0.0f, 0.0f, 1.0f);
+    model_view_proj *= model_view.getCurrent();
 
-    glUniformMatrix4fv(mShader.mLocations.ModelViewProjectionMatrix, 1,
-                       GL_FALSE, model_view_proj.m);
+    mProgram.loadUniformMatrix(model_view_proj, "ModelViewProjectionMatrix");
 
     // Load the NormalMatrix uniform in the shader. The NormalMatrix is the
     // inverse transpose of the model view matrix.
-    model_view.invert().transpose();
-    glUniformMatrix4fv(mShader.mLocations.NormalMatrix, 1,
-                       GL_FALSE, model_view.m);
+    LibMatrix::mat4 normal_matrix(model_view.getCurrent());
+    normal_matrix.inverse().transpose();
+    mProgram.loadUniformMatrix(normal_matrix, "NormalMatrix");
 
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, mTexture);
 
-    mCubeMesh.render_vbo();
+    mCubeMesh.render_vbo(mVertexAttribLocation,
+                         mNormalAttribLocation,
+                         mTexcoordAttribLocation);
 }
 
 Scene::ValidationResult
@@ -170,7 +180,7 @@
 {
     static const double radius_3d(std::sqrt(3.0));
 
-    if (mRotation.x != 0 || mRotation.y != 0 || mRotation.z != 0)
+    if (mRotation.x() != 0 || mRotation.y() != 0 || mRotation.z() != 0)
         return Scene::ValidationUnknown;
 
     Screen::Pixel ref;

=== modified file 'src/screen-sdl.cpp'
--- src/screen-sdl.cpp	2011-04-26 12:10:35 +0000
+++ src/screen-sdl.cpp	2011-06-17 08:27:49 +0000
@@ -61,10 +61,11 @@
 
     SDL_WM_SetCaption("glmark2 " GLMARK_VERSION, NULL);
 
-    mProjection.perspective(60.0, mWidth / (float)mHeight, 1.0, 1024.0);
+    mProjection = LibMatrix::Mat4::perspective(60.0, mWidth / (float)mHeight,
+                                               1.0, 1024.0);
 
 #ifdef _DEBUG
-    mProjection.display("Projection");
+    mProjection.print();
 #endif
 
     mInitSuccess = 1;

=== modified file 'src/screen.h'
--- src/screen.h	2011-06-15 10:11:13 +0000
+++ src/screen.h	2011-06-17 08:27:49 +0000
@@ -25,7 +25,7 @@
 #define GLMARK2_SCREEN_H_
 
 #include "oglsdl.h"
-#include "matrix.h"
+#include "mat.h"
 
 #include <string>
 #include <stdio.h>
@@ -58,7 +58,7 @@
     int mHeight;
     int mBpp;
     int mFullScreen;
-    Matrix4f mProjection;
+    LibMatrix::mat4 mProjection;
     int mInitSuccess;
 
     virtual void clear() {}

=== removed file 'src/shader.cpp'
--- src/shader.cpp	2011-02-26 19:57:48 +0000
+++ src/shader.cpp	1970-01-01 00:00:00 +0000
@@ -1,179 +0,0 @@
-/*
- * Copyright © 2008 Ben Smith
- * Copyright © 2010-2011 Linaro Limited
- *
- * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
- *
- * glmark2 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 3 of the License, or (at your option) any later
- * version.
- *
- * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * glmark2.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- *  Ben Smith (original glmark benchmark)
- *  Alexandros Frantzis (glmark2)
- */
-#include "shader.h"
-
-char *readShaderFile(const char *FileName)
-{
-    FILE *fp;
-    char *DATA = NULL;
-
-    int flength = 0;
-
-    fp = fopen(FileName,"rt");
-
-    fseek(fp, 0, SEEK_END);
-
-    flength = ftell(fp);
-
-    rewind(fp);
-
-
-    DATA = (char *)malloc(sizeof(char) * (flength+1));
-    flength = fread(DATA, sizeof(char), flength, fp);
-    DATA[flength] = '\0';
-
-    fclose(fp);
-
-    return DATA;
-}
-
-Shader::~Shader()
-{
-    unload();
-}
-
-void Shader::load(const char *pVertexShaderFileName, const char *pFragmentShaderFileName)
-{
-    char *vertex_shader_source, *fragment_shader_source;
-    char msg[512];
-    GLint status;
-
-    mVertexShader = glCreateShader(GL_VERTEX_SHADER);
-    mFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
-
-    vertex_shader_source = readShaderFile(pVertexShaderFileName);
-
-    fragment_shader_source = readShaderFile(pFragmentShaderFileName);
-
-    const char *vs = vertex_shader_source;
-    const char *fs = fragment_shader_source;
-
-    glShaderSource(mVertexShader, 1, &vs, NULL);
-    glShaderSource(mFragmentShader, 1, &fs, NULL);
-
-    free(vertex_shader_source);
-    free(fragment_shader_source);
-
-    glCompileShader(mVertexShader);
-    glGetShaderiv(mVertexShader, GL_COMPILE_STATUS, &status);
-    if (status == GL_FALSE) {
-        glGetShaderInfoLog(mVertexShader, sizeof msg, NULL, msg);
-        fprintf(stderr, "Error compiling %s: %s", pVertexShaderFileName,
-                strlen(msg) > 0 ? msg : "[No info]");
-    }
-
-    glCompileShader(mFragmentShader);
-    glGetShaderiv(mFragmentShader, GL_COMPILE_STATUS, &status);
-    if (status == GL_FALSE) {
-        glGetShaderInfoLog(mFragmentShader, sizeof msg, NULL, msg);
-        fprintf(stderr, "Error compiling %s: %s", pFragmentShaderFileName,
-                strlen(msg) > 0 ? msg : "[No info]");
-    }
-
-    mShaderProgram = glCreateProgram();
-    glAttachShader(mShaderProgram, mFragmentShader);
-    glAttachShader(mShaderProgram, mVertexShader);
-    glBindAttribLocation(mShaderProgram, VertexAttribLocation, "position");
-    glBindAttribLocation(mShaderProgram, NormalAttribLocation, "normal");
-    glBindAttribLocation(mShaderProgram, TexCoordAttribLocation, "texcoord");
-
-    glLinkProgram(mShaderProgram);
-    glGetProgramiv(mShaderProgram, GL_LINK_STATUS, &status);
-    if (status == GL_FALSE) {
-        glGetProgramInfoLog(mShaderProgram, sizeof msg, NULL, msg);
-        fprintf(stderr, "Error linking shader program: %s",
-                strlen(msg) > 0 ? msg : "[No info]");
-    }
-
-    mLocations.ModelViewProjectionMatrix = glGetUniformLocation(mShaderProgram,
-            "ModelViewProjectionMatrix");
-    mLocations.NormalMatrix = glGetUniformLocation(mShaderProgram,
-            "NormalMatrix");
-    mLocations.LightSourcePosition = glGetUniformLocation(mShaderProgram,
-            "LightSourcePosition");
-    mLocations.LightSourceHalfVector = glGetUniformLocation(mShaderProgram,
-            "LightSourceHalfVector");
-
-    mLocations.LightSourceAmbient = glGetUniformLocation(mShaderProgram,
-            "LightSourceAmbient");
-    mLocations.LightSourceDiffuse = glGetUniformLocation(mShaderProgram,
-            "LightSourceDiffuse");
-    mLocations.LightSourceSpecular = glGetUniformLocation(mShaderProgram,
-            "LightSourceSpecular");
-
-    mLocations.MaterialAmbient = glGetUniformLocation(mShaderProgram,
-            "MaterialAmbient");
-    mLocations.MaterialDiffuse = glGetUniformLocation(mShaderProgram,
-            "MaterialDiffuse");
-    mLocations.MaterialSpecular = glGetUniformLocation(mShaderProgram,
-            "MaterialSpecular");
-    mLocations.MaterialColor = glGetUniformLocation(mShaderProgram,
-            "MaterialColor");
-    mLocations.MaterialTexture0 = glGetUniformLocation(mShaderProgram,
-            "MaterialTexture0");
-    glUseProgram(mShaderProgram);
-    glUniform1i(mLocations.MaterialTexture0, 0);
-    glUseProgram(0);
-
-#ifdef _DEBUG
-    printf("Uniform Locations: %d %d %d %d %d %d %d %d %d %d %d %d\n",
-            mLocations.ModelViewProjectionMatrix,
-            mLocations.NormalMatrix,
-            mLocations.LightSourcePosition,
-            mLocations.LightSourceHalfVector,
-            mLocations.LightSourceAmbient,
-            mLocations.LightSourceDiffuse,
-            mLocations.LightSourceSpecular,
-            mLocations.MaterialAmbient,
-            mLocations.MaterialDiffuse,
-            mLocations.MaterialSpecular,
-            mLocations.MaterialColor,
-            mLocations.MaterialTexture0);
-#endif
-
-}
-
-void Shader::use()
-{
-    glUseProgram(mShaderProgram);
-}
-
-void Shader::remove()
-{
-    glUseProgram(0);
-}
-
-void Shader::unload()
-{
-    glDetachShader(mShaderProgram, mVertexShader);
-    glDetachShader(mShaderProgram, mFragmentShader);
-    
-    glDeleteShader(mVertexShader);
-    glDeleteShader(mFragmentShader);
-    glDeleteProgram(mShaderProgram);
-
-    mVertexShader = 0;
-    mFragmentShader = 0;
-    mShaderProgram = 0;
-}

=== removed file 'src/shader.h'
--- src/shader.h	2011-01-25 15:06:04 +0000
+++ src/shader.h	1970-01-01 00:00:00 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright © 2008 Ben Smith
- * Copyright © 2010-2011 Linaro Limited
- *
- * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
- *
- * glmark2 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 3 of the License, or (at your option) any later
- * version.
- *
- * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * glmark2.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- *  Ben Smith (original glmark benchmark)
- *  Alexandros Frantzis (glmark2)
- */
-#ifndef GLMARK2_SHADER_H_
-#define GLMARK2_SHADER_H_
-
-#include "oglsdl.h"
-
-#include <fcntl.h>
-#include <unistd.h>
-
-class Shader
-{
-public:
-    ~Shader();
-    void load(const char *pVertexShaderFileName, const char *pFragmentShaderFileName);
-    void unload();
-
-    void use();
-    void remove();
-    
-    GLuint mVertexShader;
-    GLuint mFragmentShader;
-    int mShaderProgram;
-    struct {
-        GLint ModelViewProjectionMatrix;
-        GLint NormalMatrix;
-        GLint LightSourcePosition;
-        GLint LightSourceHalfVector;
-        GLint LightSourceAmbient;
-        GLint LightSourceDiffuse;
-        GLint LightSourceSpecular;
-        GLint MaterialAmbient;
-        GLint MaterialDiffuse;
-        GLint MaterialSpecular;
-        GLint MaterialColor;
-        GLint MaterialTexture0;
-    } mLocations;
-
-    enum {
-        VertexAttribLocation = 0,
-        NormalAttribLocation = 1,
-        TexCoordAttribLocation = 2
-    };
-};
-
-#endif

=== removed file 'src/vector.cpp'
--- src/vector.cpp	2011-01-25 15:00:12 +0000
+++ src/vector.cpp	1970-01-01 00:00:00 +0000
@@ -1,148 +0,0 @@
-/*
- * Copyright © 2008 Ben Smith
- * Copyright © 2010-2011 Linaro Limited
- *
- * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
- *
- * glmark2 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 3 of the License, or (at your option) any later
- * version.
- *
- * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * glmark2.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- *  Ben Smith (original glmark benchmark)
- *  Alexandros Frantzis (glmark2)
- */
-#include "vector.h"
-
-Vector3f::Vector3f()
-{
-    x = 0.0f;  y = 0.0f;  z = 0.0f;
-}
-
-Vector3f::Vector3f(GLfloat pX, GLfloat pY, GLfloat pZ)
-{
-    x = pX; y = pY; z = pZ;
-}
-
-void Vector3f::display()
-{
-    printf("(%f, %f, %f)\n", x, y, z);
-}
-
-float Vector3f::length()
-{
-    return sqrt(x * x + y * y + z * z);
-}
-
-void Vector3f::normalize()
-{
-    GLfloat l = length();
-    x /= l; y /= l; z /= l;
-}
-
-Vector3f &Vector3f::operator=(const Vector3f &pV)
-{
-    x = pV.x;
-    y = pV.y;
-    z = pV.z;
-    return *this;
-}
-
-Vector3f &Vector3f::operator+=(const Vector3f &pV)
-{
-    x += pV.x;
-    y += pV.y;
-    z += pV.z;
-    return *this;
-}
-
-Vector3f &Vector3f::operator-=(const Vector3f &pV)
-{
-    x -= pV.x;
-    y -= pV.y;
-    z -= pV.z;
-    return *this;
-}
-
-Vector3f &Vector3f::operator*=(float pF)
-{
-    x *= pF;
-    y *= pF;
-    z *= pF;
-    return *this;
-}
-
-Vector3f &Vector3f::operator*=(double pF)
-{
-    x *= pF;
-    y *= pF;
-    z *= pF;
-    return *this;
-}
-
-Vector3f &Vector3f::operator/=(float pF)
-{
-    x /= pF;
-    y /= pF;
-    z /= pF;
-    return *this;
-}
-
-Vector3f operator+(const Vector3f &pA, const Vector3f &pB)
-{
-    Vector3f v = pA;
-    return v += pB;
-}
-
-Vector3f operator-(const Vector3f &pA, const Vector3f &pB)
-{
-    Vector3f v = pA;
-    return v -= pB;
-}
-
-Vector3f operator*(const Vector3f &pA, const float &pB)
-{
-    Vector3f v = pA;
-    return v *= pB;
-}
-
-Vector3f operator/(const Vector3f &pA, const float &pB)
-{
-    Vector3f v = pA;
-    return v /= pB;
-}
-
-Vector3f operator*(const Vector3f &pA, const double &pB)
-{
-    Vector3f v = pA;
-    return v *= pB;
-}
-
-Vector3f cross(const Vector3f &pA, const Vector3f &pB)
-{
-    return Vector3f(pA.y * pB.z - pA.z * pB.y,
-                    pA.z * pB.x - pA.x * pB.z,
-                    pA.x * pB.y - pA.y * pB.x);
-}
-
-float dot(const Vector3f &pA, const Vector3f &pB)
-{
-    return pA.x * pB.x + pA.y * pB.y + pA.z * pB.z;
-}
-
-Vector3f normal(const Vector3f &pA, const Vector3f &pB, const Vector3f &pC)
-{
-    Vector3f n = cross(pB - pA, pC - pA);
-    n.normalize();
-    return n;
-}
-

=== removed file 'src/vector.h'
--- src/vector.h	2011-01-25 15:06:04 +0000
+++ src/vector.h	1970-01-01 00:00:00 +0000
@@ -1,68 +0,0 @@
-/*
- * Copyright © 2008 Ben Smith
- * Copyright © 2010-2011 Linaro Limited
- *
- * This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
- *
- * glmark2 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 3 of the License, or (at your option) any later
- * version.
- *
- * glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * glmark2.  If not, see <http://www.gnu.org/licenses/>.
- *
- * Authors:
- *  Ben Smith (original glmark benchmark)
- *  Alexandros Frantzis (glmark2)
- */
-#ifndef GLMARK2_VECTOR_H_
-#define GLMARK2_VECTOR_H_
-
-#include "oglsdl.h"
-
-#include <stdio.h>
-#include <math.h>
-
-class Vector3f
-{
-    union
-    {    
-        struct { GLfloat x; GLfloat y; GLfloat z; };
-        GLfloat v[3];
-    };
-
-public:
-
-    Vector3f();
-    Vector3f(GLfloat pX, GLfloat pY, GLfloat pZ);
-
-    void display();
-    float length();
-    void normalize();
-    
-    Vector3f &operator=(const Vector3f &pV);
-    Vector3f &operator+=(const Vector3f &pV);
-    Vector3f &operator-=(const Vector3f &pV);
-    Vector3f &operator*=(float pF);
-    Vector3f &operator/=(float pF);
-    Vector3f &operator*=(double pF);
-};
-
-extern Vector3f operator+(const Vector3f &pA, const Vector3f &pB);
-extern Vector3f operator-(const Vector3f &pA, const Vector3f &pB);
-extern Vector3f operator*(const Vector3f &pA, const float &pB);
-extern Vector3f operator/(const Vector3f &pA, const float &pB);
-
-extern Vector3f operator*(const Vector3f &pA, const double &pB);
-
-extern float dot(const Vector3f &pA, const Vector3f &pB);
-extern Vector3f cross(const Vector3f &pA, const Vector3f &pB);
-extern Vector3f normal(const Vector3f &pA, const Vector3f &pB, const Vector3f &pC);
-
-#endif

=== modified file 'src/wscript_build'
--- src/wscript_build	2011-01-25 00:59:11 +0000
+++ src/wscript_build	2011-06-17 13:09:21 +0000
@@ -2,19 +2,39 @@
 common_sources = [f for f in all_sources if f.name.find('screen-') == -1]
 gl_sources = ['screen-sdl.cpp', 'screen-sdl-gl.cpp']
 glesv2_sources = ['screen-sdl.cpp', 'screen-sdl-glesv2.cpp']
+libmatrix_sources = [f for f in bld.path.ant_glob('libmatrix/*.cc')
+                     if not f.name.endswith('test.cc')]
 
 if bld.env.USE_GL:
     bld(
+        features = ['cxx', 'cxxstlib'],
+        source   = libmatrix_sources,
+        target   = 'matrix',
+        lib      = ['m'],
+        includes = ['.'],
+        export_includes = 'libmatrix',
+        defines  = ['USE_GL']
+        )
+    bld(
         features     = ['cxx', 'cprogram'],
         source       = common_sources + gl_sources,
         target       = 'glmark2',
-        uselib       = ['sdl', 'gl'],
+        use          = ['sdl', 'gl', 'matrix'],
         lib          = ['m'],
         defines      = ['USE_GL']
         )
 
 if bld.env.USE_GLESv2:
     bld(
+        features = ['cxx', 'cxxstlib'],
+        source   = libmatrix_sources,
+        target   = 'matrix-es2',
+        lib      = ['m'],
+        includes = ['.'],
+        export_includes = 'libmatrix',
+        defines  = ['USE_GLESv2']
+        )
+    bld(
         features     = ['c', 'cstlib'],
         source       = bld.path.ant_glob('sdlgles/*.c'),
         target       = 'sdlgles',
@@ -24,8 +44,7 @@
         features     = ['cxx', 'cprogram'],
         source       = common_sources + glesv2_sources,
         target       = 'glmark2-es2',
-        uselib       = ['sdl', 'glesv2'],
-        use          = ['sdlgles'],
+        use          = ['sdl', 'glesv2', 'sdlgles', 'matrix-es2'],
         lib          = ['m', 'dl'],
         defines      = ['USE_GLESv2']
         )

