aboutsummaryrefslogtreecommitdiff
path: root/src/libmatrix
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmatrix')
-rw-r--r--src/libmatrix/COPYING21
-rw-r--r--src/libmatrix/Makefile42
-rw-r--r--src/libmatrix/README11
-rw-r--r--src/libmatrix/gl-if.h18
-rw-r--r--src/libmatrix/log.cc173
-rw-r--r--src/libmatrix/log.h51
-rw-r--r--src/libmatrix/mat.cc173
-rw-r--r--src/libmatrix/mat.h1221
-rw-r--r--src/libmatrix/program.cc360
-rw-r--r--src/libmatrix/program.h165
-rw-r--r--src/libmatrix/shader-source.cc615
-rw-r--r--src/libmatrix/shader-source.h103
-rw-r--r--src/libmatrix/stack.h106
-rw-r--r--src/libmatrix/test/basic-global-const.vert15
-rw-r--r--src/libmatrix/test/basic.frag7
-rw-r--r--src/libmatrix/test/basic.vert14
-rw-r--r--src/libmatrix/test/const_vec_test.cc60
-rw-r--r--src/libmatrix/test/const_vec_test.h39
-rw-r--r--src/libmatrix/test/inverse_test.cc172
-rw-r--r--src/libmatrix/test/inverse_test.h39
-rw-r--r--src/libmatrix/test/libmatrix_test.cc72
-rw-r--r--src/libmatrix/test/libmatrix_test.h51
-rw-r--r--src/libmatrix/test/options.cc76
-rw-r--r--src/libmatrix/test/shader_source_test.cc49
-rw-r--r--src/libmatrix/test/shader_source_test.h32
-rw-r--r--src/libmatrix/test/transpose_test.cc297
-rw-r--r--src/libmatrix/test/transpose_test.h38
-rw-r--r--src/libmatrix/test/util_split_test.cc180
-rw-r--r--src/libmatrix/test/util_split_test.h31
-rw-r--r--src/libmatrix/util.cc343
-rw-r--r--src/libmatrix/util.h142
-rw-r--r--src/libmatrix/vec.h716
32 files changed, 5432 insertions, 0 deletions
diff --git a/src/libmatrix/COPYING b/src/libmatrix/COPYING
new file mode 100644
index 0000000..3e4d480
--- /dev/null
+++ b/src/libmatrix/COPYING
@@ -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.
diff --git a/src/libmatrix/Makefile b/src/libmatrix/Makefile
new file mode 100644
index 0000000..418311f
--- /dev/null
+++ b/src/libmatrix/Makefile
@@ -0,0 +1,42 @@
+CXXFLAGS = -Wall -Werror -pedantic -O3
+LIBMATRIX = libmatrix.a
+LIBSRCS = mat.cc program.cc log.cc util.cc shader-source.cc
+LIBOBJS = $(LIBSRCS:.cc=.o)
+TESTDIR = test
+LIBMATRIX_TESTS = $(TESTDIR)/libmatrix_test
+TESTSRCS = $(TESTDIR)/options.cc \
+ $(TESTDIR)/const_vec_test.cc \
+ $(TESTDIR)/inverse_test.cc \
+ $(TESTDIR)/transpose_test.cc \
+ $(TESTDIR)/shader_source_test.cc \
+ $(TESTDIR)/util_split_test.cc \
+ $(TESTDIR)/libmatrix_test.cc
+TESTOBJS = $(TESTSRCS:.cc=.o)
+
+# Make sure to build both the library targets and the tests, and generate
+# a make failure if the tests don't pass.
+default: $(LIBMATRIX) $(LIBMATRIX_TESTS) run_tests
+
+# Main library targets here.
+mat.o : mat.cc mat.h vec.h
+program.o: program.cc program.h mat.h vec.h
+log.o: log.cc log.h
+util.o: util.cc util.h
+shader-source.o: shader-source.cc shader-source.h mat.h vec.h util.h
+libmatrix.a : mat.o stack.h program.o log.o util.o shader-source.o
+ $(AR) -r $@ $(LIBOBJS)
+
+# Tests and execution targets here.
+$(TESTDIR)/options.o: $(TESTDIR)/options.cc $(TESTDIR)/libmatrix_test.h
+$(TESTDIR)/libmatrix_test.o: $(TESTDIR)/libmatrix_test.cc $(TESTDIR)/libmatrix_test.h $(TESTDIR)/inverse_test.h $(TESTDIR)/transpose_test.h
+$(TESTDIR)/const_vec_test.o: $(TESTDIR)/const_vec_test.cc $(TESTDIR)/const_vec_test.h $(TESTDIR)/libmatrix_test.h vec.h
+$(TESTDIR)/inverse_test.o: $(TESTDIR)/inverse_test.cc $(TESTDIR)/inverse_test.h $(TESTDIR)/libmatrix_test.h mat.h
+$(TESTDIR)/transpose_test.o: $(TESTDIR)/transpose_test.cc $(TESTDIR)/transpose_test.h $(TESTDIR)/libmatrix_test.h mat.h
+$(TESTDIR)/shader_source_test.o: $(TESTDIR)/shader_source_test.cc $(TESTDIR)/shader_source_test.h $(TESTDIR)/libmatrix_test.h shader-source.h
+$(TESTDIR)/util_split_test.o: $(TESTDIR)/util_split_test.cc $(TESTDIR)/util_split_test.h $(TESTDIR)/libmatrix_test.h util.h
+$(TESTDIR)/libmatrix_test: $(TESTOBJS) libmatrix.a
+ $(CXX) -o $@ $^
+run_tests: $(LIBMATRIX_TESTS)
+ $(LIBMATRIX_TESTS)
+clean :
+ $(RM) $(LIBOBJS) $(TESTOBJS) $(LIBMATRIX) $(LIBMATRIX_TESTS)
diff --git a/src/libmatrix/README b/src/libmatrix/README
new file mode 100644
index 0000000..17229f6
--- /dev/null
+++ b/src/libmatrix/README
@@ -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.
diff --git a/src/libmatrix/gl-if.h b/src/libmatrix/gl-if.h
new file mode 100644
index 0000000..89b84e9
--- /dev/null
+++ b/src/libmatrix/gl-if.h
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2012 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 GL_IF_H_
+#define GL_IF_H_
+// Inclusion abstraction to provide project specific interface headers for
+// whatever flavor of OpenGL(|ES) is appropriate. For core libmatrix, this
+// is GLEW.
+#include "gl-headers.h"
+#endif // GL_IF_H_
diff --git a/src/libmatrix/log.cc b/src/libmatrix/log.cc
new file mode 100644
index 0000000..10603ae
--- /dev/null
+++ b/src/libmatrix/log.cc
@@ -0,0 +1,173 @@
+//
+// Copyright (c) 2010-2012 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:
+// Alexandros Frantzis <alexandros.frantzis@linaro.org>
+// Jesse Barker <jesse.barker@linaro.org>
+//
+#include <unistd.h>
+#include <cstdio>
+#include <cstdarg>
+#include <string>
+#include <sstream>
+#include <iostream>
+#include "log.h"
+
+#ifdef ANDROID
+#include <android/log.h>
+#endif
+
+using std::string;
+
+const string Log::continuation_prefix("\x10");
+string Log::appname_;
+bool Log::do_debug_(false);
+std::ostream* Log::extra_out_(0);
+
+static const string terminal_color_normal("\033[0m");
+static const string terminal_color_red("\033[1;31m");
+static const string terminal_color_cyan("\033[36m");
+static const string terminal_color_yellow("\033[33m");
+static const string empty;
+
+static void
+print_prefixed_message(std::ostream& stream, const string& color, const string& prefix,
+ const string& fmt, va_list ap)
+{
+ va_list aq;
+
+ /* Estimate message size */
+ va_copy(aq, ap);
+ int msg_size = vsnprintf(NULL, 0, fmt.c_str(), aq);
+ va_end(aq);
+
+ /* Create the buffer to hold the message */
+ char *buf = new char[msg_size + 1];
+
+ /* Store the message in the buffer */
+ va_copy(aq, ap);
+ vsnprintf(buf, msg_size + 1, fmt.c_str(), aq);
+ va_end(aq);
+
+ /*
+ * Print the message lines prefixed with the supplied prefix.
+ * If the target stream is a terminal make the prefix colored.
+ */
+ string linePrefix;
+ if (!prefix.empty())
+ {
+ static const string colon(": ");
+ string start_color;
+ string end_color;
+ if (!color.empty())
+ {
+ start_color = color;
+ end_color = terminal_color_normal;
+ }
+ linePrefix = start_color + prefix + end_color + colon;
+ }
+
+ std::string line;
+ std::stringstream ss(buf);
+
+ while(std::getline(ss, line)) {
+ /*
+ * If this line is a continuation of a previous log message
+ * just print the line plainly.
+ */
+ if (line[0] == Log::continuation_prefix[0]) {
+ stream << line.c_str() + 1;
+ }
+ else {
+ /* Normal line, emit the prefix. */
+ stream << linePrefix << line;
+ }
+
+ /* Only emit a newline if the original message has it. */
+ if (!(ss.rdstate() & std::stringstream::eofbit))
+ stream << std::endl;
+ }
+
+ delete[] buf;
+}
+
+
+void
+Log::info(const char *fmt, ...)
+{
+ static const string infoprefix("Info");
+ const string& prefix(do_debug_ ? infoprefix : empty);
+ va_list ap;
+ va_start(ap, fmt);
+
+#ifndef ANDROID
+ static const string& infocolor(isatty(fileno(stdout)) ? terminal_color_cyan : empty);
+ const string& color(do_debug_ ? infocolor : empty);
+ print_prefixed_message(std::cout, color, prefix, fmt, ap);
+#else
+ __android_log_vprint(ANDROID_LOG_INFO, appname_.c_str(), fmt, ap);
+#endif
+
+ if (extra_out_)
+ print_prefixed_message(*extra_out_, empty, prefix, fmt, ap);
+
+ va_end(ap);
+}
+
+void
+Log::debug(const char *fmt, ...)
+{
+ static const string dbgprefix("Debug");
+ if (!do_debug_)
+ return;
+ va_list ap;
+ va_start(ap, fmt);
+
+#ifndef ANDROID
+ static const string& dbgcolor(isatty(fileno(stdout)) ? terminal_color_yellow : empty);
+ print_prefixed_message(std::cout, dbgcolor, dbgprefix, fmt, ap);
+#else
+ __android_log_vprint(ANDROID_LOG_DEBUG, appname_.c_str(), fmt, ap);
+#endif
+
+ if (extra_out_)
+ print_prefixed_message(*extra_out_, empty, dbgprefix, fmt, ap);
+
+ va_end(ap);
+}
+
+void
+Log::error(const char *fmt, ...)
+{
+ static const string errprefix("Error");
+ va_list ap;
+ va_start(ap, fmt);
+
+#ifndef ANDROID
+ static const string& errcolor(isatty(fileno(stderr)) ? terminal_color_red : empty);
+ print_prefixed_message(std::cerr, errcolor, errprefix, fmt, ap);
+#else
+ __android_log_vprint(ANDROID_LOG_ERROR, appname_.c_str(), fmt, ap);
+#endif
+
+ if (extra_out_)
+ print_prefixed_message(*extra_out_, empty, errprefix, fmt, ap);
+
+ va_end(ap);
+}
+
+void
+Log::flush()
+{
+#ifndef ANDROID
+ std::cout.flush();
+ std::cerr.flush();
+#endif
+ if (extra_out_)
+ extra_out_->flush();
+}
diff --git a/src/libmatrix/log.h b/src/libmatrix/log.h
new file mode 100644
index 0000000..9054323
--- /dev/null
+++ b/src/libmatrix/log.h
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2010-2012 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:
+// Alexandros Frantzis <alexandros.frantzis@linaro.org>
+// Jesse Barker <jesse.barker@linaro.org>
+//
+#ifndef LOG_H_
+#define LOG_H_
+
+#include <string>
+#include <iostream>
+
+class Log
+{
+public:
+ static void init(const std::string& appname, bool do_debug = false,
+ std::ostream *extra_out = 0)
+ {
+ appname_ = appname;
+ do_debug_ = do_debug;
+ extra_out_ = extra_out;
+ }
+ // Emit an informational message
+ static void info(const char *fmt, ...);
+ // Emit a debugging message
+ static void debug(const char *fmt, ...);
+ // Emit an error message
+ static void error(const char *fmt, ...);
+ // Explicit flush of the log buffer
+ static void flush();
+ // A prefix constant that informs the logging infrastructure that the log
+ // message is a continuation of a previous log message to be put on the
+ // same line.
+ static const std::string continuation_prefix;
+private:
+ // A constant for identifying the log messages as originating from a
+ // particular application.
+ static std::string appname_;
+ // Indicates whether debug level messages should generate any output
+ static bool do_debug_;
+ // Extra stream to output log messages to
+ static std::ostream *extra_out_;
+};
+
+#endif /* LOG_H_ */
diff --git a/src/libmatrix/mat.cc b/src/libmatrix/mat.cc
new file mode 100644
index 0000000..93ef63c
--- /dev/null
+++ b/src/libmatrix/mat.cc
@@ -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
diff --git a/src/libmatrix/mat.h b/src/libmatrix/mat.h
new file mode 100644
index 0000000..a55cd45
--- /dev/null
+++ b/src/libmatrix/mat.h
@@ -0,0 +1,1221 @@
+//
+// 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"
+#ifndef USE_EXCEPTIONS
+// If we're not throwing exceptions, we'll need the logger to make sure the
+// caller is informed of errors.
+#include "log.h"
+#endif // USE_EXCEPTIONS
+
+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.
+//
+// A template class for creating, managing and operating on a 2x2 matrix
+// of any type you like (intended for built-in types, but as long as it
+// supports the basic arithmetic and assignment operators, any type should
+// work).
+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() {}
+
+ // Reset this to the identity matrix.
+ void setIdentity()
+ {
+ m_[0] = 1;
+ m_[1] = 0;
+ m_[2] = 0;
+ m_[3] = 1;
+ }
+
+ // Transpose this. Return a reference to this.
+ tmat2& transpose()
+ {
+ T tmp_val = m_[1];
+ m_[1] = m_[2];
+ m_[2] = tmp_val;
+ return *this;
+ }
+
+ // Compute the determinant of this and return it.
+ T determinant()
+ {
+ return (m_[0] * m_[3]) - (m_[2] * m_[1]);
+ }
+
+ // Invert this. Return a reference to this.
+ //
+ // NOTE: If this is non-invertible, we will
+ // throw to avoid undefined behavior.
+ tmat2& inverse()
+#ifdef USE_EXCEPTIONS
+ throw(std::runtime_error)
+#endif // USE_EXCEPTIONS
+ {
+ T d(determinant());
+ if (d == static_cast<T>(0))
+ {
+#ifdef USE_EXCEPTIONS
+ throw std::runtime_error("Matrix is noninvertible!!!!");
+#else // !USE_EXCEPTIONS
+ Log::error("Matrix is noninvertible!!!!\n");
+ return *this;
+#endif // USE_EXCEPTIONS
+ }
+ 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;
+ }
+
+ // Print the elements of the matrix to standard out.
+ // Really only useful for debug and test.
+ 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;
+ }
+
+ // Allow raw data access for API calls and the like.
+ // For example, it is valid to pass a tmat2<float> into a call to
+ // the OpenGL command "glUniformMatrix2fv()".
+ operator const T*() const { return &m_[0];}
+
+ // Test if 'rhs' is equal to this.
+ 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];
+ }
+
+ // Test if 'rhs' is not equal to this.
+ bool operator!=(const tmat2& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ // A direct assignment of 'rhs' to this. Return a reference to this.
+ 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;
+ }
+
+ // Add another matrix to this. Return a reference to 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;
+ }
+
+ // Add another matrix to a copy of this. Return the copy.
+ const tmat2 operator+(const tmat2& rhs)
+ {
+ return tmat2(*this) += rhs;
+ }
+
+ // Subtract another matrix from this. Return a reference to 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;
+ }
+
+ // Subtract another matrix from a copy of this. Return the copy.
+ const tmat2 operator-(const tmat2& rhs)
+ {
+ return tmat2(*this) += rhs;
+ }
+
+ // Multiply this by another matrix. Return a reference to this.
+ 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;
+ }
+
+ // Multiply a copy of this by another matrix. Return the copy.
+ const tmat2 operator*(const tmat2& rhs)
+ {
+ return tmat2(*this) *= rhs;
+ }
+
+ // Multiply this by a scalar. Return a reference to this.
+ tmat2& operator*=(const T& rhs)
+ {
+ m_[0] *= rhs;
+ m_[1] *= rhs;
+ m_[2] *= rhs;
+ m_[3] *= rhs;
+ return *this;
+ }
+
+ // Multiply a copy of this by a scalar. Return the copy.
+ const tmat2 operator*(const T& rhs)
+ {
+ return tmat2(*this) *= rhs;
+ }
+
+ // Divide this by a scalar. Return a reference to this.
+ tmat2& operator/=(const T& rhs)
+ {
+ m_[0] /= rhs;
+ m_[1] /= rhs;
+ m_[2] /= rhs;
+ m_[3] /= rhs;
+ return *this;
+ }
+
+ // Divide a copy of this by a scalar. Return the copy.
+ const tmat2 operator/(const T& rhs)
+ {
+ return tmat2(*this) /= rhs;
+ }
+
+ // Use an instance of the ArrayProxy class to support double-indexed
+ // references to a matrix (i.e., m[1][1]). See comments above the
+ // ArrayProxy definition for more details.
+ 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];
+};
+
+// Multiply a scalar and a matrix just like the member operator, but allow
+// the scalar to be the left-hand operand.
+template<typename T>
+const tmat2<T> operator*(const T& lhs, const tmat2<T>& rhs)
+{
+ return tmat2<T>(rhs) * lhs;
+}
+
+// Multiply a copy of a vector and a matrix (matrix is right-hand operand).
+// Return the copy.
+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);
+}
+
+// Multiply a copy of a vector and a matrix (matrix is left-hand operand).
+// Return the copy.
+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);
+}
+
+// Compute the outer product of two vectors. Return the resultant matrix.
+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;
+}
+
+// A template class for creating, managing and operating on a 3x3 matrix
+// of any type you like (intended for built-in types, but as long as it
+// supports the basic arithmetic and assignment operators, any type should
+// work).
+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() {}
+
+ // Reset this to the identity matrix.
+ 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;
+ }
+
+ // Transpose this. Return a reference to this.
+ 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;
+ }
+
+ // Compute the determinant of this and return it.
+ 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());
+ }
+
+ // Invert this. Return a reference to this.
+ //
+ // NOTE: If this is non-invertible, we will
+ // throw to avoid undefined behavior.
+ tmat3& inverse()
+#ifdef USE_EXCEPTIONS
+ throw(std::runtime_error)
+#endif // USE_EXCEPTIONS
+ {
+ T d(determinant());
+ if (d == static_cast<T>(0))
+ {
+#ifdef USE_EXCEPTIONS
+ throw std::runtime_error("Matrix is noninvertible!!!!");
+#else // !USE_EXCEPTIONS
+ Log::error("Matrix is noninvertible!!!!\n");
+ return *this;
+#endif // USE_EXCEPTIONS
+ }
+ 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;
+ }
+
+ // Print the elements of the matrix to standard out.
+ // Really only useful for debug and test.
+ 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;
+ }
+
+ // Allow raw data access for API calls and the like.
+ // For example, it is valid to pass a tmat3<float> into a call to
+ // the OpenGL command "glUniformMatrix3fv()".
+ operator const T*() const { return &m_[0];}
+
+ // Test if 'rhs' is equal to this.
+ 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];
+ }
+
+ // Test if 'rhs' is not equal to this.
+ bool operator!=(const tmat3& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ // A direct assignment of 'rhs' to this. Return a reference to this.
+ 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;
+ }
+
+ // Add another matrix to this. Return a reference to 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;
+ }
+
+ // Add another matrix to a copy of this. Return the copy.
+ const tmat3 operator+(const tmat3& rhs)
+ {
+ return tmat3(*this) += rhs;
+ }
+
+ // Subtract another matrix from this. Return a reference to 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;
+ }
+
+ // Subtract another matrix from a copy of this. Return the copy.
+ const tmat3 operator-(const tmat3& rhs)
+ {
+ return tmat3(*this) -= rhs;
+ }
+
+ // Multiply this by another matrix. Return a reference to this.
+ 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;
+ }
+
+ // Multiply a copy of this by another matrix. Return the copy.
+ const tmat3 operator*(const tmat3& rhs)
+ {
+ return tmat3(*this) *= rhs;
+ }
+
+ // Multiply this by a scalar. Return a reference to this.
+ 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;
+ }
+
+ // Multiply a copy of this by a scalar. Return the copy.
+ const tmat3 operator*(const T& rhs)
+ {
+ return tmat3(*this) *= rhs;
+ }
+
+ // Divide this by a scalar. Return a reference to this.
+ 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;
+ }
+
+ // Divide a copy of this by a scalar. Return the copy.
+ const tmat3 operator/(const T& rhs)
+ {
+ return tmat3(*this) /= rhs;
+ }
+
+ // Use an instance of the ArrayProxy class to support double-indexed
+ // references to a matrix (i.e., m[1][1]). See comments above the
+ // ArrayProxy definition for more details.
+ 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];
+};
+
+// Multiply a scalar and a matrix just like the member operator, but allow
+// the scalar to be the left-hand operand.
+template<typename T>
+const tmat3<T> operator*(const T& lhs, const tmat3<T>& rhs)
+{
+ return tmat3<T>(rhs) * lhs;
+}
+
+// Multiply a copy of a vector and a matrix (matrix is right-hand operand).
+// Return the copy.
+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);
+}
+
+// Multiply a copy of a vector and a matrix (matrix is left-hand operand).
+// Return the copy.
+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);
+}
+
+// Compute the outer product of two vectors. Return the resultant matrix.
+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;
+}
+
+// A template class for creating, managing and operating on a 4x4 matrix
+// of any type you like (intended for built-in types, but as long as it
+// supports the basic arithmetic and assignment operators, any type should
+// work).
+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() {}
+
+ // Reset this to the identity matrix.
+ 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;
+ }
+
+ // Transpose this. Return a reference to this.
+ 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;
+ }
+
+ // Compute the determinant of this and return it.
+ 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());
+ }
+
+ // Invert this. Return a reference to this.
+ //
+ // NOTE: If this is non-invertible, we will
+ // throw to avoid undefined behavior.
+ tmat4& inverse()
+#ifdef USE_EXCEPTIONS
+ throw(std::runtime_error)
+#endif // USE_EXCEPTIONS
+ {
+ T d(determinant());
+ if (d == static_cast<T>(0))
+ {
+#ifdef USE_EXCEPTIONS
+ throw std::runtime_error("Matrix is noninvertible!!!!");
+#else // !USE_EXCEPTIONS
+ Log::error("Matrix is noninvertible!!!!\n");
+ return *this;
+#endif // USE_EXCEPTIONS
+ }
+ 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;
+ }
+
+ // Print the elements of the matrix to standard out.
+ // Really only useful for debug and test.
+ 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;
+ }
+
+ // Allow raw data access for API calls and the like.
+ // For example, it is valid to pass a tmat4<float> into a call to
+ // the OpenGL command "glUniformMatrix4fv()".
+ operator const T*() const { return &m_[0];}
+
+ // Test if 'rhs' is equal to this.
+ 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];
+ }
+
+ // Test if 'rhs' is not equal to this.
+ bool operator!=(const tmat4& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ // A direct assignment of 'rhs' to this. Return a reference to this.
+ 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;
+ }
+
+ // Add another matrix to this. Return a reference to 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;
+ }
+
+ // Add another matrix to a copy of this. Return the copy.
+ const tmat4 operator+(const tmat4& rhs)
+ {
+ return tmat4(*this) += rhs;
+ }
+
+ // Subtract another matrix from this. Return a reference to 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;
+ }
+
+ // Subtract another matrix from a copy of this. Return the copy.
+ const tmat4 operator-(const tmat4& rhs)
+ {
+ return tmat4(*this) -= rhs;
+ }
+
+ // Multiply this by another matrix. Return a reference to this.
+ 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;
+ }
+
+ // Multiply a copy of this by another matrix. Return the copy.
+ const tmat4 operator*(const tmat4& rhs)
+ {
+ return tmat4(*this) *= rhs;
+ }
+
+ // Multiply this by a scalar. Return a reference to this.
+ 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;
+ }
+
+ // Multiply a copy of this by a scalar. Return the copy.
+ const tmat4 operator*(const T& rhs)
+ {
+ return tmat4(*this) *= rhs;
+ }
+
+ // Divide this by a scalar. Return a reference to this.
+ 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;
+ }
+
+ // Divide a copy of this by a scalar. Return the copy.
+ const tmat4 operator/(const T& rhs)
+ {
+ return tmat4(*this) /= rhs;
+ }
+
+ // Use an instance of the ArrayProxy class to support double-indexed
+ // references to a matrix (i.e., m[1][1]). See comments above the
+ // ArrayProxy definition for more details.
+ 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];
+};
+
+// Multiply a scalar and a matrix just like the member operator, but allow
+// the scalar to be the left-hand operand.
+template<typename T>
+const tmat4<T> operator*(const T& lhs, const tmat4<T>& rhs)
+{
+ return tmat4<T>(rhs) * lhs;
+}
+
+// Multiply a copy of a vector and a matrix (matrix is right-hand operand).
+// Return the copy.
+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);
+}
+
+// Multiply a copy of a vector and a matrix (matrix is left-hand operand).
+// Return the copy.
+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);
+}
+
+// Compute the outer product of two vectors. Return the resultant matrix.
+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_
diff --git a/src/libmatrix/program.cc b/src/libmatrix/program.cc
new file mode 100644
index 0000000..b27298b
--- /dev/null
+++ b/src/libmatrix/program.cc
@@ -0,0 +1,360 @@
+//
+// Copyright (c) 2011-2012 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 "gl-if.h"
+#include "program.h"
+
+using std::string;
+using LibMatrix::mat4;
+using LibMatrix::mat3;
+using LibMatrix::vec2;
+using LibMatrix::vec3;
+using LibMatrix::vec4;
+
+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();
+
+ // Release all of the symbol map resources.
+ for (std::map<string, Symbol*>::iterator symbolIt = symbols_.begin(); symbolIt != symbols_.end(); symbolIt++)
+ {
+ delete (*symbolIt).second;
+ }
+ symbols_.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);
+}
+
+
+int
+Program::getUniformLocation(const string& name)
+{
+ GLint location = glGetUniformLocation(handle_, name.c_str());
+ if (location < 0)
+ {
+ message_ = string("Failed to get uniform location for \"") + name +
+ string("\"");
+ }
+ return location;
+}
+
+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;
+}
+
+Program::Symbol&
+Program::Symbol::operator=(const mat4& m)
+{
+ if (type_ == Uniform)
+ {
+ // Our matrix representation is column-major, so transpose is false here.
+ glUniformMatrix4fv(location_, 1, GL_FALSE, m);
+ }
+ return *this;
+}
+
+Program::Symbol&
+Program::Symbol::operator=(const mat3& m)
+{
+ if (type_ == Uniform)
+ {
+ // Our matrix representation is column-major, so transpose is false here.
+ glUniformMatrix3fv(location_, 1, GL_FALSE, m);
+ }
+ return *this;
+}
+
+Program::Symbol&
+Program::Symbol::operator=(const vec2& v)
+{
+ if (type_ == Uniform)
+ {
+ glUniform2fv(location_, 1, v);
+ }
+ return *this;
+}
+
+Program::Symbol&
+Program::Symbol::operator=(const vec3& v)
+{
+ if (type_ == Uniform)
+ {
+ glUniform3fv(location_, 1, v);
+ }
+ return *this;
+}
+
+Program::Symbol&
+Program::Symbol::operator=(const vec4& v)
+{
+ if (type_ == Uniform)
+ {
+ glUniform4fv(location_, 1, v);
+ }
+ return *this;
+}
+
+Program::Symbol&
+Program::Symbol::operator=(const float& f)
+{
+ if (type_ == Uniform)
+ {
+ glUniform1f(location_, f);
+ }
+ return *this;
+}
+
+Program::Symbol&
+Program::Symbol::operator=(const int& i)
+{
+ if (type_ == Uniform)
+ {
+ glUniform1i(location_, i);
+ }
+ return *this;
+}
+
+Program::Symbol&
+Program::operator[](const std::string& name)
+{
+ std::map<std::string, Symbol*>::iterator mapIt = symbols_.find(name);
+ if (mapIt == symbols_.end())
+ {
+ Program::Symbol::SymbolType type(Program::Symbol::Attribute);
+ int location = getAttribIndex(name);
+ if (location < 0)
+ {
+ // No attribute found by that name. Let's try a uniform...
+ type = Program::Symbol::Uniform;
+ location = getUniformLocation(name);
+ if (location < 0)
+ {
+ type = Program::Symbol::None;
+ }
+ }
+ mapIt = symbols_.insert(mapIt, std::make_pair(name, new Symbol(name, location, type)));
+ }
+ return *(*mapIt).second;
+}
diff --git a/src/libmatrix/program.h b/src/libmatrix/program.h
new file mode 100644
index 0000000..b7ba3df
--- /dev/null
+++ b/src/libmatrix/program.h
@@ -0,0 +1,165 @@
+//
+// Copyright (c) 2011-2012 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 <map>
+#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();
+
+ class Symbol
+ {
+public:
+ enum SymbolType
+ {
+ None,
+ Attribute,
+ Uniform
+ };
+ Symbol(const std::string& name, int location, SymbolType type) :
+ type_(type),
+ location_(location),
+ name_(name) {}
+ int location() const { return location_; }
+ // These members cause data to be bound to program variables, so
+ // the program must be bound for use for these to be effective.
+ Symbol& operator=(const LibMatrix::mat4& m);
+ Symbol& operator=(const LibMatrix::mat3& m);
+ Symbol& operator=(const LibMatrix::vec2& v);
+ Symbol& operator=(const LibMatrix::vec3& v);
+ Symbol& operator=(const LibMatrix::vec4& v);
+ Symbol& operator=(const float& f);
+ Symbol& operator=(const int& i);
+private:
+ Symbol();
+ SymbolType type_;
+ GLint location_;
+ std::string name_;
+ };
+ // Get the handle to a named program input (the location in OpenGL
+ // vernacular). Typically used in conjunction with various VertexAttrib
+ // interfaces. Equality operators are used to load uniform data.
+ Symbol& operator[](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:
+ int getAttribIndex(const std::string& name);
+ int getUniformLocation(const std::string& name);
+ unsigned int handle_;
+ std::map<std::string, Symbol*> symbols_;
+ std::vector<Shader> shaders_;
+ std::string message_;
+ bool ready_;
+ bool valid_;
+};
+
+#endif // PROGRAM_H_
diff --git a/src/libmatrix/shader-source.cc b/src/libmatrix/shader-source.cc
new file mode 100644
index 0000000..bf80d21
--- /dev/null
+++ b/src/libmatrix/shader-source.cc
@@ -0,0 +1,615 @@
+//
+// Copyright (c) 2010-2012 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:
+// Alexandros Frantzis <alexandros.frantzis@linaro.org>
+// Jesse Barker <jesse.barker@linaro.org>
+//
+#include <istream>
+#include <memory>
+
+#include "shader-source.h"
+#include "log.h"
+#include "vec.h"
+#include "util.h"
+
+/**
+ * Holds default precision values for all shader types
+ * (even the unknown type, which is hardwired to default precision values)
+ */
+std::vector<ShaderSource::Precision>
+ShaderSource::default_precision_(ShaderSource::ShaderTypeUnknown + 1);
+
+/**
+ * Loads the contents of a file into a string.
+ *
+ * @param filename the name of the file
+ * @param str the string to put the contents of the file into
+ */
+bool
+ShaderSource::load_file(const std::string& filename, std::string& str)
+{
+ std::auto_ptr<std::istream> is_ptr(Util::get_resource(filename));
+ std::istream& inputFile(*is_ptr);
+
+ if (!inputFile)
+ {
+ Log::error("Failed to open \"%s\"\n", filename.c_str());
+ return false;
+ }
+
+ std::string curLine;
+ while (getline(inputFile, curLine))
+ {
+ str += curLine;
+ str += '\n';
+ }
+
+ return true;
+}
+
+
+/**
+ * Appends a string to the shader source.
+ *
+ * @param str the string to append
+ */
+void
+ShaderSource::append(const std::string &str)
+{
+ source_ << str;
+}
+
+/**
+ * Appends the contents of a file to the shader source.
+ *
+ * @param filename the name of the file to append
+ */
+void
+ShaderSource::append_file(const std::string &filename)
+{
+ std::string source;
+ if (load_file(filename, source))
+ source_ << source;
+}
+
+/**
+ * Replaces a string in the source with another string.
+ *
+ * @param remove the string to replace
+ * @param insert the string to replace with
+ */
+void
+ShaderSource::replace(const std::string &remove, const std::string &insert)
+{
+ std::string::size_type pos = 0;
+ std::string str(source_.str());
+
+ while ((pos = str.find(remove, pos)) != std::string::npos) {
+ str.replace(pos, remove.size(), insert);
+ pos++;
+ }
+
+ source_.clear();
+ source_.str(str);
+}
+
+/**
+ * Replaces a string in the source with the contents of a file.
+ *
+ * @param remove the string to replace
+ * @param filename the name of the file to read from
+ */
+void
+ShaderSource::replace_with_file(const std::string &remove, const std::string &filename)
+{
+ std::string source;
+ if (load_file(filename, source))
+ replace(remove, source);
+}
+
+/**
+ * Adds a string (usually containing a constant definition) at
+ * global (per shader) scope.
+ *
+ * The string is placed after any default precision qualifiers.
+ *
+ * @param str the string to add
+ */
+void
+ShaderSource::add_global(const std::string &str)
+{
+ std::string::size_type pos = 0;
+ std::string source(source_.str());
+
+ /* Find the last precision qualifier */
+ pos = source.rfind("precision");
+
+ if (pos != std::string::npos) {
+ /*
+ * Find the next #endif line of a preprocessor block that contains
+ * the precision qualifier.
+ */
+ std::string::size_type pos_if = source.find("#if", pos);
+ std::string::size_type pos_endif = source.find("#endif", pos);
+
+ if (pos_endif != std::string::npos && pos_endif < pos_if)
+ pos = pos_endif;
+
+ /* Go to the next line */
+ pos = source.find("\n", pos);
+ if (pos != std::string::npos)
+ pos++;
+ }
+ else
+ pos = 0;
+
+ source.insert(pos, str);
+
+ source_.clear();
+ source_.str(source);
+}
+
+/**
+ * Adds a string (usually containing a constant definition) at
+ * global (per shader) scope.
+ *
+ * The string is placed after any default precision qualifiers.
+ *
+ * @param function the function to add the string into
+ * @param str the string to add
+ */
+void
+ShaderSource::add_local(const std::string &str, const std::string &function)
+{
+ std::string::size_type pos = 0;
+ std::string source(source_.str());
+
+ /* Find the function */
+ pos = source.find(function);
+ pos = source.find('{', pos);
+
+ /* Go to the next line */
+ pos = source.find("\n", pos);
+ if (pos != std::string::npos)
+ pos++;
+
+ source.insert(pos, str);
+
+ source_.clear();
+ source_.str(source);
+}
+
+/**
+ * Adds a string (usually containing a constant definition) to a shader source
+ *
+ * If the function parameter is empty, the string will be added to global
+ * scope, after any precision definitions.
+ *
+ * @param str the string to add
+ * @param function if not empty, the function to add the string into
+ */
+void
+ShaderSource::add(const std::string &str, const std::string &function)
+{
+ if (!function.empty())
+ add_local(str, function);
+ else
+ add_global(str);
+}
+
+/**
+ * Adds a float constant definition.
+ *
+ * @param name the name of the constant
+ * @param f the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, float f,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const float " << name << " = " << std::fixed << f << ";" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a float array constant definition.
+ *
+ * Note that various GLSL versions (including ES) don't support
+ * array constants.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, std::vector<float> &array,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const float " << name << "[" << array.size() << "] = {" << std::fixed;
+ for(std::vector<float>::const_iterator iter = array.begin();
+ iter != array.end();
+ iter++)
+ {
+ ss << *iter;
+ if (iter + 1 != array.end())
+ ss << ", " << std::endl;
+ }
+
+ ss << "};" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a vec2 constant definition.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, const LibMatrix::vec2 &v,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const vec2 " << name << " = vec2(" << std::fixed;
+ ss << v.x() << ", " << v.y() << ");" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a vec3 constant definition.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, const LibMatrix::vec3 &v,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const vec3 " << name << " = vec3(" << std::fixed;
+ ss << v.x() << ", " << v.y() << ", " << v.z() << ");" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a vec4 constant definition.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, const LibMatrix::vec4 &v,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const vec4 " << name << " = vec4(" << std::fixed;
+ ss << v.x() << ", " << v.y() << ", " << v.z() << ", " << v.w() << ");" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a mat3 constant definition.
+ *
+ * @param name the name of the constant
+ * @param v the value of the constant
+ * @param function if not empty, the function to put the definition in
+ */
+void
+ShaderSource::add_const(const std::string &name, const LibMatrix::mat3 &m,
+ const std::string &function)
+{
+ std::stringstream ss;
+
+ ss << "const mat3 " << name << " = mat3(" << std::fixed;
+ ss << m[0][0] << ", " << m[1][0] << ", " << m[2][0] << "," << std::endl;
+ ss << m[0][1] << ", " << m[1][1] << ", " << m[2][1] << "," << std::endl;
+ ss << m[0][2] << ", " << m[1][2] << ", " << m[2][2] << std::endl;
+ ss << ");" << std::endl;
+
+ add(ss.str(), function);
+}
+
+/**
+ * Adds a float array declaration and initialization.
+ *
+ * @param name the name of the array
+ * @param array the array values
+ * @param init_function the function to put the initialization in
+ * @param decl_function if not empty, the function to put the declaration in
+ */
+void
+ShaderSource::add_array(const std::string &name, std::vector<float> &array,
+ const std::string &init_function,
+ const std::string &decl_function)
+{
+ if (init_function.empty() || name.empty())
+ return;
+
+ std::stringstream ss;
+ ss << "float " << name << "[" << array.size() << "];" << std::endl;
+
+ std::string decl(ss.str());
+
+ ss.clear();
+ ss.str("");
+ ss << std::fixed;
+
+ for(std::vector<float>::const_iterator iter = array.begin();
+ iter != array.end();
+ iter++)
+ {
+ ss << name << "[" << iter - array.begin() << "] = " << *iter << ";" << std::endl;
+ }
+
+ add(ss.str(), init_function);
+
+ add(decl, decl_function);
+}
+
+/**
+ * Gets the ShaderType for this ShaderSource.
+ *
+ * If the ShaderType is unknown, an attempt is made to infer
+ * the type from the shader source contents.
+ *
+ * @return the ShaderType
+ */
+ShaderSource::ShaderType
+ShaderSource::type()
+{
+ /* Try to infer the type from the source contents */
+ if (type_ == ShaderSource::ShaderTypeUnknown) {
+ std::string source(source_.str());
+
+ if (source.find("gl_FragColor") != std::string::npos)
+ type_ = ShaderSource::ShaderTypeFragment;
+ else if (source.find("gl_Position") != std::string::npos)
+ type_ = ShaderSource::ShaderTypeVertex;
+ else
+ Log::debug("Cannot infer shader type from contents. Leaving it Unknown.\n");
+ }
+
+ return type_;
+}
+
+/**
+ * Helper function that emits a precision statement.
+ *
+ * @param ss the stringstream to add the statement to
+ * @param val the precision value
+ * @param type_str the variable type to apply the precision value to
+ */
+void
+ShaderSource::emit_precision(std::stringstream& ss, ShaderSource::PrecisionValue val,
+ const std::string& type_str)
+{
+ static const char *precision_map[] = {
+ "lowp", "mediump", "highp", NULL
+ };
+
+ if (val == ShaderSource::PrecisionValueHigh) {
+ if (type_ == ShaderSource::ShaderTypeFragment)
+ ss << "#ifdef GL_FRAGMENT_PRECISION_HIGH" << std::endl;
+
+ ss << "precision highp " << type_str << ";" << std::endl;
+
+ if (type_ == ShaderSource::ShaderTypeFragment) {
+ ss << "#else" << std::endl;
+ ss << "precision mediump " << type_str << ";" << std::endl;
+ ss << "#endif" << std::endl;
+ }
+ }
+ else if (val >= 0 && val < ShaderSource::PrecisionValueDefault) {
+ ss << "precision " << precision_map[val] << " ";
+ ss << type_str << ";" << std::endl;
+ }
+
+ /* There is no default precision in the fragment shader, so set it to mediump */
+ if (val == ShaderSource::PrecisionValueDefault
+ && type_str == "float" && type_ == ShaderSource::ShaderTypeFragment)
+ {
+ ss << "precision mediump float;" << std::endl;
+ }
+}
+
+/**
+ * Gets a string containing the complete shader source.
+ *
+ * Precision statements are applied at this point.
+ *
+ * @return the shader source
+ */
+std::string
+ShaderSource::str()
+{
+ /* Decide which precision values to use */
+ ShaderSource::Precision precision;
+
+ /* Ensure we have tried to infer the type from the contents */
+ type();
+
+ if (precision_has_been_set_)
+ precision = precision_;
+ else
+ precision = default_precision(type_);
+
+ /* Create the precision statements */
+ std::stringstream ss;
+
+ emit_precision(ss, precision.int_precision, "int");
+ emit_precision(ss, precision.float_precision, "float");
+ emit_precision(ss, precision.sampler2d_precision, "sampler2D");
+ emit_precision(ss, precision.samplercube_precision, "samplerCube");
+
+ std::string precision_str(ss.str());
+ if (!precision_str.empty()) {
+ precision_str.insert(0, "#ifdef GL_ES\n");
+ precision_str.insert(precision_str.size(), "#endif\n");
+ }
+
+ return precision_str + source_.str();
+}
+
+/**
+ * Sets the precision that will be used for this shader.
+ *
+ * This overrides any default values set with ShaderSource::default_*_precision().
+ *
+ * @param precision the precision to set
+ */
+void
+ShaderSource::precision(const ShaderSource::Precision& precision)
+{
+ precision_ = precision;
+ precision_has_been_set_ = true;
+}
+
+/**
+ * Gets the precision that will be used for this shader.
+ *
+ * @return the precision
+ */
+const ShaderSource::Precision&
+ShaderSource::precision()
+{
+ return precision_;
+}
+
+/**
+ * Sets the default precision that will be used for a shaders type.
+ *
+ * If type is ShaderTypeUnknown the supplied precision is used for all
+ * shader types.
+ *
+ * This can be overriden per ShaderSource object by using ::precision().
+ *
+ * @param precision the default precision to set
+ * @param type the ShaderType to use the precision for
+ */
+void
+ShaderSource::default_precision(const ShaderSource::Precision& precision,
+ ShaderSource::ShaderType type)
+{
+ if (type < 0 || type > ShaderSource::ShaderTypeUnknown)
+ type = ShaderSource::ShaderTypeUnknown;
+
+ if (type == ShaderSource::ShaderTypeUnknown) {
+ for (size_t i = 0; i < ShaderSource::ShaderTypeUnknown; i++)
+ default_precision_[i] = precision;
+ }
+ else {
+ default_precision_[type] = precision;
+ }
+}
+
+/**
+ * Gets the default precision that will be used for a shader type.
+ *
+ * It is valid to use a type of ShaderTypeUnknown. This will always
+ * return a Precision with default values.
+ *
+ * @param type the ShaderType to get the precision of
+ *
+ * @return the precision
+ */
+const ShaderSource::Precision&
+ShaderSource::default_precision(ShaderSource::ShaderType type)
+{
+ if (type < 0 || type > ShaderSource::ShaderTypeUnknown)
+ type = ShaderSource::ShaderTypeUnknown;
+
+ return default_precision_[type];
+}
+
+/****************************************
+ * ShaderSource::Precision constructors *
+ ****************************************/
+
+/**
+ * Creates a ShaderSource::Precision with default precision values.
+ */
+ShaderSource::Precision::Precision() :
+ int_precision(ShaderSource::PrecisionValueDefault),
+ float_precision(ShaderSource::PrecisionValueDefault),
+ sampler2d_precision(ShaderSource::PrecisionValueDefault),
+ samplercube_precision(ShaderSource::PrecisionValueDefault)
+{
+}
+
+/**
+ * Creates a ShaderSource::Precision using the supplied precision values.
+ */
+ShaderSource::Precision::Precision(ShaderSource::PrecisionValue int_p,
+ ShaderSource::PrecisionValue float_p,
+ ShaderSource::PrecisionValue sampler2d_p,
+ ShaderSource::PrecisionValue samplercube_p) :
+ int_precision(int_p), float_precision(float_p),
+ sampler2d_precision(sampler2d_p), samplercube_precision(samplercube_p)
+{
+}
+
+/**
+ * Creates a ShaderSource::Precision from a string representation of
+ * precision values.
+ *
+ * The string format is:
+ * "<int>,<float>,<sampler2d>,<samplercube>"
+ *
+ * Each precision value is one of "high", "medium", "low" or "default".
+ *
+ * @param precision_values the string representation of the precision values
+ */
+ShaderSource::Precision::Precision(const std::string& precision_values) :
+ int_precision(ShaderSource::PrecisionValueDefault),
+ float_precision(ShaderSource::PrecisionValueDefault),
+ sampler2d_precision(ShaderSource::PrecisionValueDefault),
+ samplercube_precision(ShaderSource::PrecisionValueDefault)
+{
+ std::vector<std::string> elems;
+
+ Util::split(precision_values, ',', elems, Util::SplitModeNormal);
+
+ for (size_t i = 0; i < elems.size() && i < 4; i++) {
+ const std::string& pstr(elems[i]);
+ ShaderSource::PrecisionValue pval;
+
+ if (pstr == "high")
+ pval = ShaderSource::PrecisionValueHigh;
+ else if (pstr == "medium")
+ pval = ShaderSource::PrecisionValueMedium;
+ else if (pstr == "low")
+ pval = ShaderSource::PrecisionValueLow;
+ else
+ pval = ShaderSource::PrecisionValueDefault;
+
+ switch(i) {
+ case 0: int_precision = pval; break;
+ case 1: float_precision = pval; break;
+ case 2: sampler2d_precision = pval; break;
+ case 3: samplercube_precision = pval; break;
+ default: break;
+ }
+ }
+}
diff --git a/src/libmatrix/shader-source.h b/src/libmatrix/shader-source.h
new file mode 100644
index 0000000..4dc1d1d
--- /dev/null
+++ b/src/libmatrix/shader-source.h
@@ -0,0 +1,103 @@
+//
+// Copyright (c) 2010-2012 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:
+// Alexandros Frantzis <alexandros.frantzis@linaro.org>
+// Jesse Barker <jesse.barker@linaro.org>
+//
+#include <string>
+#include <sstream>
+#include <vector>
+#include "vec.h"
+#include "mat.h"
+
+/**
+ * Helper class for loading and manipulating shader sources.
+ */
+class ShaderSource
+{
+public:
+ enum ShaderType {
+ ShaderTypeVertex,
+ ShaderTypeFragment,
+ ShaderTypeUnknown
+ };
+
+ ShaderSource(ShaderType type = ShaderTypeUnknown) :
+ precision_has_been_set_(false), type_(type) {}
+ ShaderSource(const std::string &filename, ShaderType type = ShaderTypeUnknown) :
+ precision_has_been_set_(false), type_(type) { append_file(filename); }
+
+ void append(const std::string &str);
+ void append_file(const std::string &filename);
+
+ void replace(const std::string &remove, const std::string &insert);
+ void replace_with_file(const std::string &remove, const std::string &filename);
+
+ void add(const std::string &str, const std::string &function = "");
+
+ void add_const(const std::string &name, float f,
+ const std::string &function = "");
+ void add_const(const std::string &name, std::vector<float> &f,
+ const std::string &function = "");
+ void add_const(const std::string &name, const LibMatrix::vec2 &v,
+ const std::string &function = "");
+ void add_const(const std::string &name, const LibMatrix::vec3 &v,
+ const std::string &function = "");
+ void add_const(const std::string &name, const LibMatrix::vec4 &v,
+ const std::string &function = "");
+ void add_const(const std::string &name, const LibMatrix::mat3 &m,
+ const std::string &function = "");
+
+ void add_array(const std::string &name, std::vector<float> &array,
+ const std::string &init_function,
+ const std::string &decl_function = "");
+
+ ShaderType type();
+ std::string str();
+
+ enum PrecisionValue {
+ PrecisionValueLow,
+ PrecisionValueMedium,
+ PrecisionValueHigh,
+ PrecisionValueDefault
+ };
+
+ struct Precision {
+ Precision();
+ Precision(PrecisionValue int_p, PrecisionValue float_p,
+ PrecisionValue sampler2d_p, PrecisionValue samplercube_p);
+ Precision(const std::string& list);
+
+ PrecisionValue int_precision;
+ PrecisionValue float_precision;
+ PrecisionValue sampler2d_precision;
+ PrecisionValue samplercube_precision;
+ };
+
+ void precision(const Precision& precision);
+ const Precision& precision();
+
+ static void default_precision(const Precision& precision,
+ ShaderType type = ShaderTypeUnknown);
+ static const Precision& default_precision(ShaderType type);
+
+private:
+ void add_global(const std::string &str);
+ void add_local(const std::string &str, const std::string &function);
+ bool load_file(const std::string& filename, std::string& str);
+ void emit_precision(std::stringstream& ss, ShaderSource::PrecisionValue val,
+ const std::string& type_str);
+
+ std::stringstream source_;
+ Precision precision_;
+ bool precision_has_been_set_;
+ ShaderType type_;
+
+ static std::vector<Precision> default_precision_;
+};
diff --git a/src/libmatrix/stack.h b/src/libmatrix/stack.h
new file mode 100644
index 0000000..c14cec3
--- /dev/null
+++ b/src/libmatrix/stack.h
@@ -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_
diff --git a/src/libmatrix/test/basic-global-const.vert b/src/libmatrix/test/basic-global-const.vert
new file mode 100644
index 0000000..18dc358
--- /dev/null
+++ b/src/libmatrix/test/basic-global-const.vert
@@ -0,0 +1,15 @@
+const vec4 ConstantColor = vec4(1.000000, 1.000000, 1.000000, 1.000000);
+attribute vec3 position;
+
+uniform mat4 modelview;
+uniform mat4 projection;
+
+varying vec4 color;
+
+void
+main(void)
+{
+ vec4 curVertex = vec4(position, 1.0);
+ gl_Position = projection * modelview * curVertex;
+ color = ConstantColor;
+}
diff --git a/src/libmatrix/test/basic.frag b/src/libmatrix/test/basic.frag
new file mode 100644
index 0000000..1b648db
--- /dev/null
+++ b/src/libmatrix/test/basic.frag
@@ -0,0 +1,7 @@
+varying vec4 color;
+
+void
+main(void)
+{
+ gl_FragColor = color;
+}
diff --git a/src/libmatrix/test/basic.vert b/src/libmatrix/test/basic.vert
new file mode 100644
index 0000000..d93289e
--- /dev/null
+++ b/src/libmatrix/test/basic.vert
@@ -0,0 +1,14 @@
+attribute vec3 position;
+
+uniform mat4 modelview;
+uniform mat4 projection;
+
+varying vec4 color;
+
+void
+main(void)
+{
+ vec4 curVertex = vec4(position, 1.0);
+ gl_Position = projection * modelview * curVertex;
+ color = ConstantColor;
+}
diff --git a/src/libmatrix/test/const_vec_test.cc b/src/libmatrix/test/const_vec_test.cc
new file mode 100644
index 0000000..879d4e6
--- /dev/null
+++ b/src/libmatrix/test/const_vec_test.cc
@@ -0,0 +1,60 @@
+//
+// 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 <iostream>
+#include "libmatrix_test.h"
+#include "const_vec_test.h"
+#include "../vec.h"
+
+using LibMatrix::vec2;
+using LibMatrix::vec3;
+using LibMatrix::vec4;
+using std::cout;
+using std::endl;
+
+void
+Vec2TestConstOperator::run(const Options& options)
+{
+ const vec2 a(1.0, 1.0);
+ const vec2 b(2.0, 2.0);
+ vec2 aplusb(a + b);
+ vec2 aminusb(a - b);
+ vec2 atimesb(a * b);
+ vec2 adivb(a / b);
+ const float s(2.5);
+ vec2 stimesb(s * b);
+}
+
+void
+Vec3TestConstOperator::run(const Options& options)
+{
+ const vec3 a(1.0, 1.0, 1.0);
+ const vec3 b(2.0, 2.0, 2.0);
+ vec3 aplusb(a + b);
+ vec3 aminusb(a - b);
+ vec3 atimesb(a * b);
+ vec3 adivb(a / b);
+ const float s(2.5);
+ vec3 stimesb(s * b);
+}
+
+void
+Vec4TestConstOperator::run(const Options& options)
+{
+ const vec4 a(1.0, 1.0, 1.0, 1.0);
+ const vec4 b(2.0, 2.0, 2.0, 2.0);
+ vec4 aplusb(a + b);
+ vec4 aminusb(a - b);
+ vec4 atimesb(a * b);
+ vec4 adivb(a / b);
+ const float s(2.5);
+ vec4 stimesb(s * b);
+}
diff --git a/src/libmatrix/test/const_vec_test.h b/src/libmatrix/test/const_vec_test.h
new file mode 100644
index 0000000..834f4a8
--- /dev/null
+++ b/src/libmatrix/test/const_vec_test.h
@@ -0,0 +1,39 @@
+//
+// 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 CONST_VEC_TEST_H_
+#define CONST_VEC_TEST_H_
+
+class MatrixTest;
+class Options;
+
+class Vec2TestConstOperator : public MatrixTest
+{
+public:
+ Vec2TestConstOperator() : MatrixTest("vec2::const") {}
+ virtual void run(const Options& options);
+};
+
+class Vec3TestConstOperator : public MatrixTest
+{
+public:
+ Vec3TestConstOperator() : MatrixTest("vec3::const") {}
+ virtual void run(const Options& options);
+};
+
+class Vec4TestConstOperator : public MatrixTest
+{
+public:
+ Vec4TestConstOperator() : MatrixTest("vec4::const") {}
+ virtual void run(const Options& options);
+};
+
+#endif // CONST_VEC_TEST_H_
diff --git a/src/libmatrix/test/inverse_test.cc b/src/libmatrix/test/inverse_test.cc
new file mode 100644
index 0000000..51a8072
--- /dev/null
+++ b/src/libmatrix/test/inverse_test.cc
@@ -0,0 +1,172 @@
+//
+// 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 "libmatrix_test.h"
+#include "inverse_test.h"
+#include "../mat.h"
+
+using LibMatrix::mat2;
+using LibMatrix::mat3;
+using LibMatrix::mat4;
+using std::cout;
+using std::endl;
+
+void
+MatrixTest2x2Inverse::run(const Options& options)
+{
+ mat2 m;
+
+ if (options.beVerbose())
+ {
+ cout << "Starting with mat2 (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ m[0][1] = -2.5;
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Matrix should now have (0, 1) == -2.500000" << endl << endl;
+ m.print();
+ }
+
+ mat2 mi(m);
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Copy of previous matrix (should have (0, 1) == -2.500000)" << endl << endl;
+ mi.print();
+ }
+
+ mi.inverse();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Inverse of copy: " << endl << endl;
+ mi.print();
+ }
+
+ mat2 i = m * mi;
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Product of original and inverse (should be identity): " << endl << endl;
+ i.print();
+ }
+
+ mat2 ident;
+ if (i == ident)
+ {
+ pass_ = true;
+ }
+}
+
+void
+MatrixTest3x3Inverse::run(const Options& options)
+{
+ mat3 m;
+
+ if (options.beVerbose())
+ {
+ cout << "Starting with mat3 (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ m[1][2] = -2.5;
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Matrix should now have (1, 2) == -2.500000" << endl << endl;
+ m.print();
+ }
+
+ mat3 mi(m);
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Copy of previous matrix (should have (1, 2) == -2.500000)" << endl << endl;
+ mi.print();
+ }
+
+ mi.inverse();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Inverse of copy: " << endl << endl;
+ mi.print();
+ }
+
+ mat3 i = m * mi;
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Product of original and inverse (should be identity): " << endl << endl;
+ i.print();
+ }
+
+ mat3 ident;
+ if (i == ident)
+ {
+ pass_ = true;
+ }
+}
+
+void
+MatrixTest4x4Inverse::run(const Options& options)
+{
+ mat4 m;
+
+ if (options.beVerbose())
+ {
+ cout << "Starting with mat4 (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ m[2][3] = -2.5;
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Matrix should now have (2, 3) == -2.500000" << endl << endl;
+ m.print();
+ }
+
+ mat4 mi(m);
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Copy of previous matrix (should have (2, 3) == -2.500000)" << endl << endl;
+ mi.print();
+ }
+
+ mi.inverse();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Inverse of copy: " << endl << endl;
+ mi.print();
+ }
+
+ mat4 i = m * mi;
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Product of original and inverse (should be identity): " << endl << endl;
+ i.print();
+ }
+
+ mat4 ident;
+ if (i == ident)
+ {
+ pass_ = true;
+ }
+}
+
diff --git a/src/libmatrix/test/inverse_test.h b/src/libmatrix/test/inverse_test.h
new file mode 100644
index 0000000..4c5b584
--- /dev/null
+++ b/src/libmatrix/test/inverse_test.h
@@ -0,0 +1,39 @@
+//
+// 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 INVERSE_TEST_H_
+#define INVERSE_TEST_H_
+
+class MatrixTest;
+class Options;
+
+class MatrixTest2x2Inverse : public MatrixTest
+{
+public:
+ MatrixTest2x2Inverse() : MatrixTest("mat2::inverse") {}
+ virtual void run(const Options& options);
+};
+
+class MatrixTest3x3Inverse : public MatrixTest
+{
+public:
+ MatrixTest3x3Inverse() : MatrixTest("mat3::inverse") {}
+ virtual void run(const Options& options);
+};
+
+class MatrixTest4x4Inverse : public MatrixTest
+{
+public:
+ MatrixTest4x4Inverse() : MatrixTest("mat4::inverse") {}
+ virtual void run(const Options& options);
+};
+
+#endif // INVERSE_TEST_H_
diff --git a/src/libmatrix/test/libmatrix_test.cc b/src/libmatrix/test/libmatrix_test.cc
new file mode 100644
index 0000000..5e4ff12
--- /dev/null
+++ b/src/libmatrix/test/libmatrix_test.cc
@@ -0,0 +1,72 @@
+//
+// 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.
+// Alexandros Frantzis - Util::split tests
+//
+#include <iostream>
+#include <string>
+#include <vector>
+#include "libmatrix_test.h"
+#include "inverse_test.h"
+#include "transpose_test.h"
+#include "const_vec_test.h"
+#include "shader_source_test.h"
+#include "util_split_test.h"
+
+using std::cerr;
+using std::cout;
+using std::endl;
+
+int
+main(int argc, char** argv)
+{
+ Options testOptions("matrix_test");
+ testOptions.parseArgs(argc, argv);
+ if (testOptions.showHelp())
+ {
+ testOptions.printUsage();
+ return 0;
+ }
+
+ using std::vector;
+ vector<MatrixTest*> testVec;
+ testVec.push_back(new MatrixTest2x2Inverse());
+ testVec.push_back(new MatrixTest3x3Inverse());
+ testVec.push_back(new MatrixTest4x4Inverse());
+ testVec.push_back(new MatrixTest2x2Transpose());
+ testVec.push_back(new MatrixTest3x3Transpose());
+ testVec.push_back(new MatrixTest4x4Transpose());
+ testVec.push_back(new ShaderSourceBasic());
+ testVec.push_back(new UtilSplitTestNormal());
+ testVec.push_back(new UtilSplitTestQuoted());
+
+ for (vector<MatrixTest*>::iterator testIt = testVec.begin();
+ testIt != testVec.end();
+ testIt++)
+ {
+ MatrixTest* curTest = *testIt;
+ if (testOptions.beVerbose())
+ {
+ cout << "Running test " << curTest->name() << endl;
+ }
+ curTest->run(testOptions);
+ if (!curTest->passed())
+ {
+ cerr << curTest->name() << " does not work!" << endl;
+ return 1;
+ }
+ if (testOptions.beVerbose())
+ {
+ cout << curTest->name() << " is okay!" << endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/libmatrix/test/libmatrix_test.h b/src/libmatrix/test/libmatrix_test.h
new file mode 100644
index 0000000..4ae0a8a
--- /dev/null
+++ b/src/libmatrix/test/libmatrix_test.h
@@ -0,0 +1,51 @@
+//
+// 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 LIBMATRIX_TEST_H_
+#define LIBMATRIX_TEST_H_
+
+class Options
+{
+ Options();
+ static const std::string verbose_name_;
+ static const std::string help_name_;
+ std::string app_name_;
+ bool show_help_;
+ bool verbose_;
+public:
+ Options(const std::string& app_name) :
+ app_name_(app_name),
+ show_help_(false),
+ verbose_(false) {}
+ ~Options() {}
+ bool beVerbose() const { return verbose_; }
+ bool showHelp() const { return show_help_; }
+ void parseArgs(int argc, char** argv);
+ void printUsage();
+};
+
+class MatrixTest
+{
+ std::string name_;
+protected:
+ bool pass_;
+ MatrixTest();
+public:
+ MatrixTest(const std::string& name) :
+ name_(name),
+ pass_(false) {}
+ ~MatrixTest();
+ const std::string& name() const { return name_; }
+ virtual void run(const Options& options) = 0;
+ const bool passed() const { return pass_; }
+};
+
+#endif // LIBMATRIX_TEST_H_
diff --git a/src/libmatrix/test/options.cc b/src/libmatrix/test/options.cc
new file mode 100644
index 0000000..ec15f3c
--- /dev/null
+++ b/src/libmatrix/test/options.cc
@@ -0,0 +1,76 @@
+//
+// 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 <iomanip>
+#include <getopt.h>
+#include "libmatrix_test.h"
+
+using std::cout;
+using std::endl;
+
+const std::string Options::verbose_name_("verbose");
+const std::string Options::help_name_("help");
+
+void
+Options::parseArgs(int argc, char** argv)
+{
+ static struct option long_options[] = {
+ {"verbose", 0, 0, 0},
+ {"help", 0, 0, 0},
+ {0, 0, 0, 0}
+ };
+ int option_index(0);
+ int c = getopt_long(argc, argv, "", long_options, &option_index);
+ while (c != -1)
+ {
+ // getopt_long() returns '?' and prints an "unrecognized option" error
+ // to stderr if it does not recognize an option. Just trigger
+ // the help/usage message, stop processing and get out.
+ if (c == '?')
+ {
+ show_help_ = true;
+ break;
+ }
+
+ std::string optname(long_options[option_index].name);
+
+ if (optname == verbose_name_)
+ {
+ verbose_ = true;
+ }
+ else if (optname == help_name_)
+ {
+ show_help_ = true;
+ }
+ c = getopt_long(argc, argv, "",
+ long_options, &option_index);
+ }
+}
+
+
+static void
+emitColumnOne(const std::string& text)
+{
+ cout << std::setw(16) << text;
+}
+
+void
+Options::printUsage()
+{
+ cout << app_name_ << ": directed functional test utility for libmatrix." << endl;
+ cout << "Options:" << endl;
+ emitColumnOne("--verbose");
+ cout << std::setw(0) << " Enable verbose output during test runs." << endl;
+ emitColumnOne("--help");
+ cout << std::setw(0) << " Print this usage text." << endl;
+}
+
diff --git a/src/libmatrix/test/shader_source_test.cc b/src/libmatrix/test/shader_source_test.cc
new file mode 100644
index 0000000..31d0265
--- /dev/null
+++ b/src/libmatrix/test/shader_source_test.cc
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2012 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 "libmatrix_test.h"
+#include "shader_source_test.h"
+#include "../shader-source.h"
+#include "../vec.h"
+
+using std::string;
+using LibMatrix::vec4;
+
+void
+ShaderSourceBasic::run(const Options& options)
+{
+ static const string vtx_shader_filename("test/basic.vert");
+
+ ShaderSource vtx_source(vtx_shader_filename);
+ ShaderSource vtx_source2(vtx_shader_filename);
+
+ pass_ = (vtx_source.str() == vtx_source2.str());
+}
+
+void
+ShaderSourceAddConstGlobal::run(const Options& options)
+{
+ // Load the original shader source.
+ static const string src_shader_filename("test/basic.vert");
+ ShaderSource src_shader(src_shader_filename);
+
+ // Add constant at global scope
+ static const vec4 constantColor(1.0, 1.0, 1.0, 1.0);
+ src_shader.add_const("ConstantColor", constantColor);
+
+ // Load the pre-modified shader
+ static const string result_shader_filename("test/basic-global-const.vert");
+ ShaderSource result_shader(result_shader_filename);
+
+ // Compare the output strings to confirm the results.
+ pass_ = (src_shader.str() == result_shader.str());
+}
diff --git a/src/libmatrix/test/shader_source_test.h b/src/libmatrix/test/shader_source_test.h
new file mode 100644
index 0000000..cf49766
--- /dev/null
+++ b/src/libmatrix/test/shader_source_test.h
@@ -0,0 +1,32 @@
+//
+// Copyright (c) 2012 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 SHADER_SOURCE_TEST_H_
+#define SHADER_SOURCE_TEST_H_
+
+class MatrixTest;
+class Options;
+
+class ShaderSourceBasic : public MatrixTest
+{
+public:
+ ShaderSourceBasic() : MatrixTest("ShaderSource::basic") {}
+ virtual void run(const Options& options);
+};
+
+class ShaderSourceAddConstGlobal : public MatrixTest
+{
+public:
+ ShaderSourceAddConstGlobal() : MatrixTest("ShaderSource::AddConstGlobal") {}
+ virtual void run(const Options& options);
+};
+
+#endif // SHADER_SOURCE_TEST_H
diff --git a/src/libmatrix/test/transpose_test.cc b/src/libmatrix/test/transpose_test.cc
new file mode 100644
index 0000000..574486d
--- /dev/null
+++ b/src/libmatrix/test/transpose_test.cc
@@ -0,0 +1,297 @@
+//
+// 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 "libmatrix_test.h"
+#include "transpose_test.h"
+#include "../mat.h"
+
+using LibMatrix::mat2;
+using LibMatrix::mat3;
+using LibMatrix::mat4;
+using std::cout;
+using std::endl;
+
+void
+MatrixTest2x2Transpose::run(const Options& options)
+{
+ // First, a simple test to ensure that the transpose of the identity is
+ // the identity.
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 1: Transpose of the identity is the identity." << endl << endl;
+ }
+
+ mat2 m;
+
+ if (options.beVerbose())
+ {
+ cout << "Starting with mat2 (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ m.transpose();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Transpose of identity (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ mat2 mi;
+ if (m != mi)
+ {
+ // FAIL! Transpose of the identity is the identity.
+ return;
+ }
+
+ // At this point, we have 2 identity matrices.
+ // Next, set an element in the matrix and transpose twice. We should see
+ // the original matrix (with i,j set).
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 2: Transposing a matrix twice yields the original matrix." << endl << endl;
+ }
+
+ m[0][1] = 6.3;
+
+ if (options.beVerbose())
+ {
+ cout << "Matrix should now have (0, 1) == 6.300000" << endl << endl;
+ m.print();
+ }
+
+ mi = m;
+
+ m.transpose().transpose();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Matrix should now have (0, 1) == 6.300000" << endl << endl;
+ m.print();
+ }
+
+ if (m != mi)
+ {
+ // FAIL! Transposing the same matrix twice should yield the original.
+ return;
+ }
+
+ // Next, reset mi back to the identity. Set element element j,i in this
+ // matrix and transpose m. They should now be equal.
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 3: Transpose of matrix (i,j) == x is equal to matrix (j,i) == x." << endl << endl;
+ }
+
+ mi.setIdentity();
+ mi[1][0] = 6.3;
+
+ m.transpose();
+
+ if (options.beVerbose())
+ {
+ cout << "Matrix should now have (1, 0) == 6.300000" << endl << endl;
+ m.print();
+ cout << endl;
+ }
+
+ if (m == mi)
+ {
+ pass_ = true;
+ }
+
+ // FAIL! Transposing the same matrix twice should yield the original.
+}
+
+void
+MatrixTest3x3Transpose::run(const Options& options)
+{
+ // First, a simple test to ensure that the transpose of the identity is
+ // the identity.
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 1: Transpose of the identity is the identity." << endl << endl;
+ }
+
+ mat3 m;
+
+ if (options.beVerbose())
+ {
+ cout << "Starting with mat2 (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ m.transpose();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Transpose of identity (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ mat3 mi;
+ if (m != mi)
+ {
+ // FAIL! Transpose of the identity is the identity.
+ return;
+ }
+
+ // At this point, we have 2 identity matrices.
+ // Next, set an element in the matrix and transpose twice. We should see
+ // the original matrix (with i,j set).
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 2: Transposing a matrix twice yields the original matrix." << endl << endl;
+ }
+
+ m[0][1] = 6.3;
+
+ if (options.beVerbose())
+ {
+ cout << "Matrix should now have (0, 1) == 6.300000" << endl << endl;
+ m.print();
+ }
+
+ mi = m;
+
+ m.transpose().transpose();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Matrix should now have (0, 1) == 6.300000" << endl << endl;
+ m.print();
+ }
+
+ if (m != mi)
+ {
+ // FAIL! Transposing the same matrix twice should yield the original.
+ return;
+ }
+
+ // Next, reset mi back to the identity. Set element element j,i in this
+ // matrix and transpose m. They should now be equal.
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 3: Transpose of matrix (i,j) == x is equal to matrix (j,i) == x." << endl << endl;
+ }
+
+ mi.setIdentity();
+ mi[1][0] = 6.3;
+
+ m.transpose();
+
+ if (options.beVerbose())
+ {
+ cout << "Matrix should now have (1, 0) == 6.300000" << endl << endl;
+ m.print();
+ cout << endl;
+ }
+
+ if (m == mi)
+ {
+ pass_ = true;
+ }
+
+ // FAIL! Transposing the same matrix twice should yield the original.
+}
+
+void
+MatrixTest4x4Transpose::run(const Options& options)
+{
+ // First, a simple test to ensure that the transpose of the identity is
+ // the identity.
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 1: Transpose of the identity is the identity." << endl << endl;
+ }
+
+ mat4 m;
+
+ if (options.beVerbose())
+ {
+ cout << "Starting with mat2 (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ m.transpose();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Transpose of identity (should be identity): " << endl << endl;
+ m.print();
+ }
+
+ mat4 mi;
+ if (m != mi)
+ {
+ // FAIL! Transpose of the identity is the identity.
+ return;
+ }
+
+ // At this point, we have 2 identity matrices.
+ // Next, set an element in the matrix and transpose twice. We should see
+ // the original matrix (with i,j set).
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 2: Transposing a matrix twice yields the original matrix." << endl << endl;
+ }
+
+ m[0][1] = 6.3;
+
+ if (options.beVerbose())
+ {
+ cout << "Matrix should now have (0, 1) == 6.300000" << endl << endl;
+ m.print();
+ }
+
+ mi = m;
+
+ m.transpose().transpose();
+
+ if (options.beVerbose())
+ {
+ cout << endl << "Matrix should now have (0, 1) == 6.300000" << endl << endl;
+ m.print();
+ }
+
+ if (m != mi)
+ {
+ // FAIL! Transposing the same matrix twice should yield the original.
+ return;
+ }
+
+ // Next, reset mi back to the identity. Set element element j,i in this
+ // matrix and transpose m. They should now be equal.
+ if (options.beVerbose())
+ {
+ cout << endl << "Assertion 3: Transpose of matrix (i,j) == x is equal to matrix (j,i) == x." << endl << endl;
+ }
+
+ mi.setIdentity();
+ mi[1][0] = 6.3;
+
+ m.transpose();
+
+ if (options.beVerbose())
+ {
+ cout << "Matrix should now have (1, 0) == 6.300000" << endl << endl;
+ m.print();
+ cout << endl;
+ }
+
+ if (m == mi)
+ {
+ pass_ = true;
+ }
+
+ // FAIL! Transposing the same matrix twice should yield the original.
+}
diff --git a/src/libmatrix/test/transpose_test.h b/src/libmatrix/test/transpose_test.h
new file mode 100644
index 0000000..3a4398f
--- /dev/null
+++ b/src/libmatrix/test/transpose_test.h
@@ -0,0 +1,38 @@
+//
+// 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 TRANSPOSE_TEST_H_
+#define TRANSPOSE_TEST_H_
+
+class MatrixTest;
+class Options;
+
+class MatrixTest2x2Transpose : public MatrixTest
+{
+public:
+ MatrixTest2x2Transpose() : MatrixTest("mat2::transpose") {}
+ virtual void run(const Options& options);
+};
+
+class MatrixTest3x3Transpose : public MatrixTest
+{
+public:
+ MatrixTest3x3Transpose() : MatrixTest("mat3::transpose") {}
+ virtual void run(const Options& options);
+};
+
+class MatrixTest4x4Transpose : public MatrixTest
+{
+public:
+ MatrixTest4x4Transpose() : MatrixTest("mat4::transpose") {}
+ virtual void run(const Options& options);
+};
+#endif // TRANSPOSE_TEST_H_
diff --git a/src/libmatrix/test/util_split_test.cc b/src/libmatrix/test/util_split_test.cc
new file mode 100644
index 0000000..4399f77
--- /dev/null
+++ b/src/libmatrix/test/util_split_test.cc
@@ -0,0 +1,180 @@
+//
+// Copyright (c) 2012 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:
+// Alexandros Frantzis - original implementation.
+//
+#include <iostream>
+#include <string>
+#include <vector>
+#include "libmatrix_test.h"
+#include "util_split_test.h"
+#include "../util.h"
+
+using std::cout;
+using std::endl;
+using std::string;
+using std::vector;
+
+template <typename T> static bool
+areVectorsEqual(vector<T>& vec1, vector<T>& vec2)
+{
+ if (vec1.size() != vec2.size())
+ return false;
+
+ for (unsigned int i = 0; i < vec1.size(); i++)
+ {
+ if (vec1[i] != vec2[i])
+ return false;
+ }
+
+ return true;
+}
+
+template <typename T> static void
+printVector(vector<T>& vec)
+{
+ cout << "[";
+ for (unsigned int i = 0; i < vec.size(); i++)
+ {
+ cout << '"' << vec[i] << '"';
+ if (i < vec.size() - 1)
+ cout << ", ";
+ }
+ cout << "]";
+}
+
+void
+UtilSplitTestNormal::run(const Options& options)
+{
+ const string test1("abc def ghi");
+ const string test2(" abc: def :ghi ");
+ vector<string> expected1;
+ vector<string> expected2;
+ vector<string> results;
+
+ expected1.push_back("abc");
+ expected1.push_back("def");
+ expected1.push_back("ghi");
+
+ expected2.push_back(" abc");
+ expected2.push_back(" def ");
+ expected2.push_back("ghi ");
+
+ if (options.beVerbose())
+ {
+ cout << "Testing string \"" << test1 << "\"" << endl;
+ }
+
+ Util::split(test1, ' ', results, Util::SplitModeNormal);
+
+ if (options.beVerbose())
+ {
+ cout << "Split result: ";
+ printVector(results);
+ cout << endl << "Expected: ";
+ printVector(expected1);
+ cout << endl;
+ }
+
+ if (!areVectorsEqual(results, expected1))
+ {
+ return;
+ }
+
+ results.clear();
+
+ if (options.beVerbose())
+ {
+ cout << "Testing string \"" << test2 << "\"" << endl;
+ }
+
+ Util::split(test2, ':', results, Util::SplitModeNormal);
+
+ if (options.beVerbose())
+ {
+ cout << "Split result: ";
+ printVector(results);
+ cout << endl << "Expected: ";
+ printVector(expected2);
+ cout << endl;
+ }
+
+ if (!areVectorsEqual(results, expected2))
+ {
+ return;
+ }
+
+ pass_ = true;
+}
+
+void
+UtilSplitTestQuoted::run(const Options& options)
+{
+ const string test1("abc \"def' ghi\" klm\\ nop -b qr:title='123 \"456'");
+ const string test2("abc: def='1:2:3:'ghi : \":jk\"");
+ vector<string> expected1;
+ vector<string> expected2;
+ vector<string> results;
+
+ expected1.push_back("abc");
+ expected1.push_back("def' ghi");
+ expected1.push_back("klm nop");
+ expected1.push_back("-b");
+ expected1.push_back("qr:title=123 \"456");
+
+ expected2.push_back("abc");
+ expected2.push_back(" def=1:2:3:ghi ");
+ expected2.push_back(" :jk");
+
+ if (options.beVerbose())
+ {
+ cout << "Testing string \"" << test1 << "\"" << endl;
+ }
+
+ Util::split(test1, ' ', results, Util::SplitModeQuoted);
+
+ if (options.beVerbose())
+ {
+ cout << "Split result: ";
+ printVector(results);
+ cout << endl << "Expected: ";
+ printVector(expected1);
+ cout << endl;
+ }
+
+ if (!areVectorsEqual(results, expected1))
+ {
+ return;
+ }
+
+ results.clear();
+
+ if (options.beVerbose())
+ {
+ cout << "Testing string \"" << test2 << "\"" << endl;
+ }
+
+ Util::split(test2, ':', results, Util::SplitModeQuoted);
+
+ if (options.beVerbose())
+ {
+ cout << "Split result: ";
+ printVector(results);
+ cout << endl << "Expected: ";
+ printVector(expected2);
+ cout << endl;
+ }
+
+ if (!areVectorsEqual(results, expected2))
+ {
+ return;
+ }
+
+ pass_ = true;
+}
diff --git a/src/libmatrix/test/util_split_test.h b/src/libmatrix/test/util_split_test.h
new file mode 100644
index 0000000..a8023ff
--- /dev/null
+++ b/src/libmatrix/test/util_split_test.h
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2012 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:
+// Alexandros Frantzis - original implementation.
+//
+#ifndef UTIL_SPLIT_TEST_H_
+#define UTIL_SPLIT_TEST_H_
+
+class MatrixTest;
+class Options;
+
+class UtilSplitTestNormal : public MatrixTest
+{
+public:
+ UtilSplitTestNormal() : MatrixTest("Util::split::normal") {}
+ virtual void run(const Options& options);
+};
+
+class UtilSplitTestQuoted : public MatrixTest
+{
+public:
+ UtilSplitTestQuoted() : MatrixTest("Util::split::quoted") {}
+ virtual void run(const Options& options);
+};
+#endif // UTIL_SPLIT_TEST_H_
diff --git a/src/libmatrix/util.cc b/src/libmatrix/util.cc
new file mode 100644
index 0000000..d96f393
--- /dev/null
+++ b/src/libmatrix/util.cc
@@ -0,0 +1,343 @@
+//
+// Copyright (c) 2010-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:
+// Alexandros Frantzis <alexandros.frantzis@linaro.org>
+// Jesse Barker <jesse.barker@linaro.org>
+//
+#include <sstream>
+#include <fstream>
+#include <sys/time.h>
+#ifdef ANDROID
+#include <android/asset_manager.h>
+#else
+#include <dirent.h>
+#endif
+
+#include "log.h"
+#include "util.h"
+
+using std::string;
+using std::vector;
+
+/*
+ * State machine for bash-like quoted string escaping:
+ *
+ * \
+ * -----------> +---------+
+ * | ---------- | Escaped |
+ * | | *,ESC +---------+
+ * | |
+ * | v '
+ * +--------+ ---> +--------------+ -----
+ * | Normal | <--- | SingleQuoted | | *, ESC
+ * +--------+ ' +--------------+ <----
+ * | ^
+ * | |
+ * | | " +--------------+ ----
+ * | ---------- | DoubleQuoted | | *, ESC
+ * -----------> +--------------+ <---
+ * " | ^
+ * \ | | *, ESC
+ * v |
+ * +---------------------+
+ * | DoubleQuotedEscaped |
+ * +---------------------+
+ *
+ * ESC: Mark character as Escaped
+ */
+static void
+fill_escape_vector(const string &str, vector<bool> &esc_vec)
+{
+ enum State {
+ StateNormal,
+ StateEscaped,
+ StateDoubleQuoted,
+ StateDoubleQuotedEscaped,
+ StateSingleQuoted
+ };
+
+ State state = StateNormal;
+
+ for (string::const_iterator iter = str.begin();
+ iter != str.end();
+ iter++)
+ {
+ const char c(*iter);
+ bool esc = false;
+
+ switch (state) {
+ case StateNormal:
+ if (c == '"')
+ state = StateDoubleQuoted;
+ else if (c == '\\')
+ state = StateEscaped;
+ else if (c == '\'')
+ state = StateSingleQuoted;
+ break;
+ case StateEscaped:
+ esc = true;
+ state = StateNormal;
+ break;
+ case StateDoubleQuoted:
+ if (c == '"')
+ state = StateNormal;
+ else if (c == '\\')
+ state = StateDoubleQuotedEscaped;
+ else
+ esc = true;
+ break;
+ case StateDoubleQuotedEscaped:
+ esc = true;
+ state = StateDoubleQuoted;
+ break;
+ case StateSingleQuoted:
+ if (c == '\'')
+ state = StateNormal;
+ else
+ esc = true;
+ default:
+ break;
+ }
+
+ esc_vec.push_back(esc);
+ }
+}
+
+static void
+split_normal(const string& src, char delim, vector<string>& elementVec)
+{
+ std::stringstream ss(src);
+ string item;
+ while(std::getline(ss, item, delim))
+ elementVec.push_back(item);
+}
+
+static void
+split_fuzzy(const string& src, char delim, vector<string>& elementVec)
+{
+ // Fuzzy case: Initialize our delimiter string based upon the caller's plus
+ // a space to allow for more flexibility.
+ string delimiter(" ");
+ delimiter += delim;
+ // Starting index into the string of the first token (by definition, if
+ // we're parsing a string, there is at least one token).
+ string::size_type startPos(0);
+ // string::find_first_of() looks for any character in the string provided,
+ // it is not treated as a sub-string, so regardless of where the space or
+ // comma is or how many there are, the result is the same.
+ string str(src);
+ string::size_type endPos = str.find_first_of(delimiter);
+ while (endPos != string::npos)
+ {
+ // Push back the current element starting at startPos for
+ // (endPos - startPos) characters. std::string takes care of
+ // terminators, etc.
+ elementVec.push_back(string(str, startPos, endPos - startPos));
+ // Index of the next element after any delimiter characters. Same
+ // caveat applies to find_first_not_of() that applies to
+ // find_first_of(); endPos tells it where to start the search.
+ string::size_type nextPos = str.find_first_not_of(delimiter, endPos);
+ // Erase the part of the string we've already parsed.
+ str = str.erase(startPos, nextPos - startPos);
+ // Look for the next delimiter. If there isn't one, we bail out.
+ endPos = str.find_first_of(delimiter);
+ }
+ // Regardless of whether we initially had one element or many, 'str' now
+ // only contains one.
+ elementVec.push_back(str);
+}
+
+static void
+split_quoted(const string& src, char delim, vector<string>& elementVec)
+{
+ std::stringstream ss;
+ vector<bool> escVec;
+
+ /* Mark characters in the string as escaped or not */
+ fill_escape_vector(src, escVec);
+
+ /* Sanity check... */
+ if (src.length() != escVec.size())
+ return;
+
+ for (vector<bool>::const_iterator iter = escVec.begin();
+ iter != escVec.end();
+ iter++)
+ {
+ bool escaped = static_cast<bool>(*iter);
+ char c = src[iter - escVec.begin()];
+
+ /* Output all characters, except unescaped ",\,' */
+ if ((c != '"' && c != '\\' && c != '\'') || escaped) {
+ /* If we reach an unescaped delimiter character, do a split */
+ if (c == delim && !escaped) {
+ elementVec.push_back(ss.str());
+ ss.str("");
+ ss.clear();
+ }
+ else {
+ ss << c;
+ }
+ }
+
+ }
+
+ /* Handle final element, delimited by end of string */
+ const string &finalElement(ss.str());
+ if (!finalElement.empty())
+ elementVec.push_back(finalElement);
+}
+
+void
+Util::split(const string& src, char delim, vector<string>& elementVec,
+ Util::SplitMode mode)
+{
+ // Trivial rejection
+ if (src.empty())
+ {
+ return;
+ }
+
+ switch (mode)
+ {
+ case Util::SplitModeNormal:
+ return split_normal(src, delim, elementVec);
+ case Util::SplitModeFuzzy:
+ return split_fuzzy(src, delim, elementVec);
+ case Util::SplitModeQuoted:
+ return split_quoted(src, delim, elementVec);
+ default:
+ break;
+ }
+}
+
+uint64_t
+Util::get_timestamp_us()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ uint64_t now = static_cast<uint64_t>(tv.tv_sec) * 1000000 +
+ static_cast<double>(tv.tv_usec);
+ return now;
+}
+
+std::string
+Util::appname_from_path(const std::string& path)
+{
+ std::string::size_type slashPos = path.rfind("/");
+ std::string::size_type startPos(0);
+ if (slashPos != std::string::npos)
+ {
+ startPos = slashPos + 1;
+ }
+ return std::string(path, startPos, std::string::npos);
+}
+
+#ifndef ANDROID
+
+std::istream *
+Util::get_resource(const std::string &path)
+{
+ std::ifstream *ifs = new std::ifstream(path.c_str());
+
+ return static_cast<std::istream *>(ifs);
+}
+
+void
+Util::list_files(const std::string& dirName, std::vector<std::string>& fileVec)
+{
+ DIR* dir = opendir(dirName.c_str());
+ if (!dir)
+ {
+ Log::error("Failed to open models directory '%s'\n", dirName.c_str());
+ return;
+ }
+
+ struct dirent* entry = readdir(dir);
+ while (entry)
+ {
+ std::string pathname(dirName + "/");
+ pathname += std::string(entry->d_name);
+ // Skip '.' and '..'
+ if (entry->d_name[0] != '.')
+ {
+ fileVec.push_back(pathname);
+ }
+ entry = readdir(dir);
+ }
+ closedir(dir);
+}
+
+#else
+
+AAssetManager *Util::android_asset_manager = 0;
+
+void
+Util::android_set_asset_manager(AAssetManager *asset_manager)
+{
+ Util::android_asset_manager = asset_manager;
+}
+
+AAssetManager *
+Util::android_get_asset_manager()
+{
+ return Util::android_asset_manager;
+}
+
+std::istream *
+Util::get_resource(const std::string &path)
+{
+ std::string path2(path);
+ /* Remove leading '/' from path name, it confuses the AssetManager */
+ if (path2.size() > 0 && path2[0] == '/')
+ path2.erase(0, 1);
+
+ std::stringstream *ss = new std::stringstream;
+ AAsset *asset = AAssetManager_open(Util::android_asset_manager,
+ path2.c_str(), AASSET_MODE_RANDOM);
+ if (asset) {
+ ss->write(reinterpret_cast<const char *>(AAsset_getBuffer(asset)),
+ AAsset_getLength(asset));
+ Log::debug("Load asset %s\n", path2.c_str());
+ AAsset_close(asset);
+ }
+ else {
+ Log::error("Couldn't load asset %s\n", path2.c_str());
+ }
+
+ return static_cast<std::istream *>(ss);
+}
+
+void
+Util::list_files(const std::string& dirName, std::vector<std::string>& fileVec)
+{
+ AAssetManager *mgr(Util::android_get_asset_manager());
+ std::string dir_name(dirName);
+
+ /* Remove leading '/' from path, it confuses the AssetManager */
+ if (dir_name.size() > 0 && dir_name[0] == '/')
+ dir_name.erase(0, 1);
+
+ AAssetDir* dir = AAssetManager_openDir(mgr, dir_name.c_str());
+ if (!dir)
+ {
+ Log::error("Failed to open models directory '%s'\n", dir_name.c_str());
+ return;
+ }
+
+ const char *filename(0);
+ while ((filename = AAssetDir_getNextFileName(dir)) != 0)
+ {
+ std::string pathname(dir_name + "/");
+ pathname += std::string(filename);
+ fileVec.push_back(pathname);
+ }
+ AAssetDir_close(dir);
+}
+#endif
diff --git a/src/libmatrix/util.h b/src/libmatrix/util.h
new file mode 100644
index 0000000..2b0f0f0
--- /dev/null
+++ b/src/libmatrix/util.h
@@ -0,0 +1,142 @@
+//
+// Copyright (c) 2010-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:
+// Alexandros Frantzis <alexandros.frantzis@linaro.org>
+// Jesse Barker <jesse.barker@linaro.org>
+//
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <string>
+#include <vector>
+#include <istream>
+#include <sstream>
+#include <stdint.h>
+
+#ifdef ANDROID
+#include <android/asset_manager_jni.h>
+#endif
+
+struct Util {
+ /**
+ * How to perform the split() operation
+ */
+ enum SplitMode {
+ /** Normal split operation */
+ SplitModeNormal,
+ /** Allow for spaces and multiple consecutive occurences of the delimiter */
+ SplitModeFuzzy,
+ /** Take into account bash-like quoting and escaping rules */
+ SplitModeQuoted
+ };
+
+ /**
+ * split() - Splits a string into elements using a provided delimiter
+ *
+ * @s: the string to split
+ * @delim: the delimiter to use
+ * @elems: the string vector to populate
+ * @mode: the SplitMode to use
+ *
+ * Using @delim to determine field boundaries, splits @s into separate
+ * string elements. These elements are returned in the string vector
+ * @elems. As long as @s is non-empty, there will be at least one
+ * element in @elems.
+ */
+ static void split(const std::string& src, char delim,
+ std::vector<std::string>& elems,
+ Util::SplitMode mode);
+ /**
+ * get_timestamp_us() - Returns the current time in microseconds
+ */
+ static uint64_t get_timestamp_us();
+ /**
+ * get_resource() - Gets an input filestream for a given file.
+ *
+ * @path: the path to the file
+ *
+ * Returns a pointer to an input stream, which must be deleted when no
+ * longer in use.
+ */
+ static std::istream *get_resource(const std::string &path);
+ /**
+ * list_files() - Get a list of the files in a given directory.
+ *
+ * @dirName: the directory path to be listed.
+ * @fileVec: the string vector to populate.
+ *
+ * Obtains a list of the files in @dirName, and returns them in the string
+ * vector @fileVec.
+ */
+ static void list_files(const std::string& dirName, std::vector<std::string>& fileVec);
+ /**
+ * dispose_pointer_vector() - cleans up a vector of pointers
+ *
+ * @vec: vector of pointers to objects or plain-old-data
+ *
+ * Iterates across @vec and deletes the data pointed to by each of the
+ * elements. Clears the vector, resetting it for reuse.
+ */
+ template <class T> static void dispose_pointer_vector(std::vector<T*> &vec)
+ {
+ for (typename std::vector<T*>::const_iterator iter = vec.begin();
+ iter != vec.end();
+ iter++)
+ {
+ delete *iter;
+ }
+
+ vec.clear();
+ }
+ /**
+ * toString() - Converts a string to a plain-old-data type.
+ *
+ * @asString: a string representation of plain-old-data.
+ */
+ template<typename T>
+ static T
+ fromString(const std::string& asString)
+ {
+ std::stringstream ss(asString);
+ T retVal = T();
+ ss >> retVal;
+ return retVal;
+ }
+ /**
+ * toString() - Converts a plain-old-data type to a string.
+ *
+ * @t: a simple value to be converted to a string
+ */
+ template<typename T>
+ static std::string
+ toString(const T t)
+ {
+ std::stringstream ss;
+ ss << t;
+ return ss.str();
+ }
+ /**
+ * appname_from_path() - get the name of an executable from an absolute path
+ *
+ * @path: absolute path of the running application (argv[0])
+ *
+ * Returns the last portion of @path (everything after the final '/').
+ */
+ static std::string
+ appname_from_path(const std::string& path);
+
+#ifdef ANDROID
+ static void android_set_asset_manager(AAssetManager *asset_manager);
+ static AAssetManager *android_get_asset_manager(void);
+private:
+ static AAssetManager *android_asset_manager;
+#endif
+};
+
+#endif /* UTIL_H */
diff --git a/src/libmatrix/vec.h b/src/libmatrix/vec.h
new file mode 100644
index 0000000..2680ebc
--- /dev/null
+++ b/src/libmatrix/vec.h
@@ -0,0 +1,716 @@
+//
+// Copyright (c) 2010-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 VEC_H_
+#define VEC_H_
+
+#include <iostream> // only needed for print() functions...
+#include <math.h>
+
+namespace LibMatrix
+{
+// A template class for creating, managing and operating on a 2-element vector
+// of any type you like (intended for built-in types, but as long as it
+// supports the basic arithmetic and assignment operators, any type should
+// work).
+template<typename T>
+class tvec2
+{
+public:
+ tvec2() :
+ x_(0),
+ y_(0) {}
+ tvec2(const T t) :
+ x_(t),
+ y_(t) {}
+ tvec2(const T x, const T y) :
+ x_(x),
+ y_(y) {}
+ tvec2(const tvec2& v) :
+ x_(v.x_),
+ y_(v.y_) {}
+ ~tvec2() {}
+
+ // Print the elements of the vector to standard out.
+ // Really only useful for debug and test.
+ void print() const
+ {
+ std::cout << "| " << x_ << " " << y_ << " |" << std::endl;
+ }
+
+ // Allow raw data access for API calls and the like.
+ // For example, it is valid to pass a tvec2<float> into a call to
+ // the OpenGL command "glUniform2fv()".
+ operator const T*() const { return &x_;}
+
+ // Get and set access members for the individual elements.
+ 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; }
+
+ // A direct assignment of 'rhs' to this. Return a reference to this.
+ tvec2& operator=(const tvec2& rhs)
+ {
+ if (this != &rhs)
+ {
+ x_ = rhs.x_;
+ y_ = rhs.y_;
+ }
+ return *this;
+ }
+
+ // Divide this by a scalar. Return a reference to this.
+ tvec2& operator/=(const T& rhs)
+ {
+ x_ /= rhs;
+ y_ /= rhs;
+ return *this;
+ }
+
+ // Divide a copy of this by a scalar. Return the copy.
+ const tvec2 operator/(const T& rhs) const
+ {
+ return tvec2(*this) /= rhs;
+ }
+
+ // Component-wise divide of this by another vector.
+ // Return a reference to this.
+ tvec2& operator/=(const tvec2& rhs)
+ {
+ x_ /= rhs.x_;
+ y_ /= rhs.y_;
+ return *this;
+ }
+
+ // Component-wise divide of a copy of this by another vector.
+ // Return the copy.
+ const tvec2 operator/(const tvec2& rhs) const
+ {
+ return tvec2(*this) /= rhs;
+ }
+
+ // Multiply this by a scalar. Return a reference to this.
+ tvec2& operator*=(const T& rhs)
+ {
+ x_ *= rhs;
+ y_ *= rhs;
+ return *this;
+ }
+
+ // Multiply a copy of this by a scalar. Return the copy.
+ const tvec2 operator*(const T& rhs) const
+ {
+ return tvec2(*this) *= rhs;
+ }
+
+ // Component-wise multiply of this by another vector.
+ // Return a reference to this.
+ tvec2& operator*=(const tvec2& rhs)
+ {
+ x_ *= rhs.x_;
+ y_ *= rhs.y_;
+ return *this;
+ }
+
+ // Component-wise multiply of a copy of this by another vector.
+ // Return the copy.
+ const tvec2 operator*(const tvec2& rhs) const
+ {
+ return tvec2(*this) *= rhs;
+ }
+
+ // Add a scalar to this. Return a reference to this.
+ tvec2& operator+=(const T& rhs)
+ {
+ x_ += rhs;
+ y_ += rhs;
+ return *this;
+ }
+
+ // Add a scalar to a copy of this. Return the copy.
+ const tvec2 operator+(const T& rhs) const
+ {
+ return tvec2(*this) += rhs;
+ }
+
+ // Component-wise addition of another vector to this.
+ // Return a reference to this.
+ tvec2& operator+=(const tvec2& rhs)
+ {
+ x_ += rhs.x_;
+ y_ += rhs.y_;
+ return *this;
+ }
+
+ // Component-wise addition of another vector to a copy of this.
+ // Return the copy.
+ const tvec2 operator+(const tvec2& rhs) const
+ {
+ return tvec2(*this) += rhs;
+ }
+
+ // Subtract a scalar from this. Return a reference to this.
+ tvec2& operator-=(const T& rhs)
+ {
+ x_ -= rhs;
+ y_ -= rhs;
+ return *this;
+ }
+
+ // Subtract a scalar from a copy of this. Return the copy.
+ const tvec2 operator-(const T& rhs) const
+ {
+ return tvec2(*this) -= rhs;
+ }
+
+ // Component-wise subtraction of another vector from this.
+ // Return a reference to this.
+ tvec2& operator-=(const tvec2& rhs)
+ {
+ x_ -= rhs.x_;
+ y_ -= rhs.y_;
+ return *this;
+ }
+
+ // Component-wise subtraction of another vector from a copy of this.
+ // Return the copy.
+ const tvec2 operator-(const tvec2& rhs) const
+ {
+ return tvec2(*this) -= rhs;
+ }
+
+ // Compute the length of this and return it.
+ float length() const
+ {
+ return sqrt(dot(*this, *this));
+ }
+
+ // Make this a unit vector.
+ void normalize()
+ {
+ float l = length();
+ x_ /= l;
+ y_ /= l;
+ }
+
+ // Compute the dot product of two vectors.
+ static T dot(const tvec2& v1, const tvec2& v2)
+ {
+ return (v1.x_ * v2.x_) + (v1.y_ * v2.y_);
+ }
+
+private:
+ T x_;
+ T y_;
+};
+
+// A template class for creating, managing and operating on a 3-element vector
+// of any type you like (intended for built-in types, but as long as it
+// supports the basic arithmetic and assignment operators, any type should
+// work).
+template<typename T>
+class tvec3
+{
+public:
+ tvec3() :
+ x_(0),
+ y_(0),
+ z_(0) {}
+ tvec3(const T t) :
+ x_(t),
+ y_(t),
+ z_(t) {}
+ tvec3(const T x, const T y, const T z) :
+ x_(x),
+ y_(y),
+ z_(z) {}
+ tvec3(const tvec3& v) :
+ x_(v.x_),
+ y_(v.y_),
+ z_(v.z_) {}
+ ~tvec3() {}
+
+ // Print the elements of the vector to standard out.
+ // Really only useful for debug and test.
+ void print() const
+ {
+ std::cout << "| " << x_ << " " << y_ << " " << z_ << " |" << std::endl;
+ }
+
+ // Allow raw data access for API calls and the like.
+ // For example, it is valid to pass a tvec3<float> into a call to
+ // the OpenGL command "glUniform3fv()".
+ operator const T*() const { return &x_;}
+
+ // Get and set access members for the individual elements.
+ 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; }
+
+ // A direct assignment of 'rhs' to this. Return a reference to this.
+ tvec3& operator=(const tvec3& rhs)
+ {
+ if (this != &rhs)
+ {
+ x_ = rhs.x_;
+ y_ = rhs.y_;
+ z_ = rhs.z_;
+ }
+ return *this;
+ }
+
+ // Divide this by a scalar. Return a reference to this.
+ tvec3& operator/=(const T& rhs)
+ {
+ x_ /= rhs;
+ y_ /= rhs;
+ z_ /= rhs;
+ return *this;
+ }
+
+ // Divide a copy of this by a scalar. Return the copy.
+ const tvec3 operator/(const T& rhs) const
+ {
+ return tvec3(*this) /= rhs;
+ }
+
+ // Component-wise divide of this by another vector.
+ // Return a reference to this.
+ tvec3& operator/=(const tvec3& rhs)
+ {
+ x_ /= rhs.x_;
+ y_ /= rhs.y_;
+ z_ /= rhs.z_;
+ return *this;
+ }
+
+ // Component-wise divide of a copy of this by another vector.
+ // Return the copy.
+ const tvec3 operator/(const tvec3& rhs) const
+ {
+ return tvec3(*this) /= rhs;
+ }
+
+ // Multiply this by a scalar. Return a reference to this.
+ tvec3& operator*=(const T& rhs)
+ {
+ x_ *= rhs;
+ y_ *= rhs;
+ z_ *= rhs;
+ return *this;
+ }
+
+ // Multiply a copy of this by a scalar. Return the copy.
+ const tvec3 operator*(const T& rhs) const
+ {
+ return tvec3(*this) *= rhs;
+ }
+
+ // Component-wise multiply of this by another vector.
+ // Return a reference to this.
+ tvec3& operator*=(const tvec3& rhs)
+ {
+ x_ *= rhs.x_;
+ y_ *= rhs.y_;
+ z_ *= rhs.z_;
+ return *this;
+ }
+
+ // Component-wise multiply of a copy of this by another vector.
+ // Return the copy.
+ const tvec3 operator*(const tvec3& rhs) const
+ {
+ return tvec3(*this) *= rhs;
+ }
+
+ // Add a scalar to this. Return a reference to this.
+ tvec3& operator+=(const T& rhs)
+ {
+ x_ += rhs;
+ y_ += rhs;
+ z_ += rhs;
+ return *this;
+ }
+
+ // Add a scalar to a copy of this. Return the copy.
+ const tvec3 operator+(const T& rhs) const
+ {
+ return tvec3(*this) += rhs;
+ }
+
+ // Component-wise addition of another vector to this.
+ // Return a reference to this.
+ tvec3& operator+=(const tvec3& rhs)
+ {
+ x_ += rhs.x_;
+ y_ += rhs.y_;
+ z_ += rhs.z_;
+ return *this;
+ }
+
+ // Component-wise addition of another vector to a copy of this.
+ // Return the copy.
+ const tvec3 operator+(const tvec3& rhs) const
+ {
+ return tvec3(*this) += rhs;
+ }
+
+ // Subtract a scalar from this. Return a reference to this.
+ tvec3& operator-=(const T& rhs)
+ {
+ x_ -= rhs;
+ y_ -= rhs;
+ z_ -= rhs;
+ return *this;
+ }
+
+ // Subtract a scalar from a copy of this. Return the copy.
+ const tvec3 operator-(const T& rhs) const
+ {
+ return tvec3(*this) -= rhs;
+ }
+
+ // Component-wise subtraction of another vector from this.
+ // Return a reference to this.
+ tvec3& operator-=(const tvec3& rhs)
+ {
+ x_ -= rhs.x_;
+ y_ -= rhs.y_;
+ z_ -= rhs.z_;
+ return *this;
+ }
+
+ // Component-wise subtraction of another vector from a copy of this.
+ // Return the copy.
+ const tvec3 operator-(const tvec3& rhs) const
+ {
+ return tvec3(*this) -= rhs;
+ }
+
+ // Compute the length of this and return it.
+ float length() const
+ {
+ return sqrt(dot(*this, *this));
+ }
+
+ // Make this a unit vector.
+ void normalize()
+ {
+ float l = length();
+ x_ /= l;
+ y_ /= l;
+ z_ /= l;
+ }
+
+ // Compute the dot product of two vectors.
+ static T dot(const tvec3& v1, const tvec3& v2)
+ {
+ return (v1.x_ * v2.x_) + (v1.y_ * v2.y_) + (v1.z_ * v2.z_);
+ }
+
+ // Compute the cross product of two vectors.
+ 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_;
+};
+
+// A template class for creating, managing and operating on a 4-element vector
+// of any type you like (intended for built-in types, but as long as it
+// supports the basic arithmetic and assignment operators, any type should
+// work).
+template<typename T>
+class tvec4
+{
+public:
+ tvec4() :
+ x_(0),
+ y_(0),
+ z_(0),
+ w_(0) {}
+ tvec4(const T t) :
+ x_(t),
+ y_(t),
+ z_(t),
+ w_(t) {}
+ tvec4(const T x, const T y, const T z, const 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() {}
+
+ // Print the elements of the vector to standard out.
+ // Really only useful for debug and test.
+ void print() const
+ {
+ std::cout << "| " << x_ << " " << y_ << " " << z_ << " " << w_ << " |" << std::endl;
+ }
+
+ // Allow raw data access for API calls and the like.
+ // For example, it is valid to pass a tvec4<float> into a call to
+ // the OpenGL command "glUniform4fv()".
+ operator const T*() const { return &x_;}
+
+ // Get and set access members for the individual elements.
+ 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; }
+
+ // A direct assignment of 'rhs' to this. Return a reference to this.
+ tvec4& operator=(const tvec4& rhs)
+ {
+ if (this != &rhs)
+ {
+ x_ = rhs.x_;
+ y_ = rhs.y_;
+ z_ = rhs.z_;
+ w_ = rhs.w_;
+ }
+ return *this;
+ }
+
+ // Divide this by a scalar. Return a reference to this.
+ tvec4& operator/=(const T& rhs)
+ {
+ x_ /= rhs;
+ y_ /= rhs;
+ z_ /= rhs;
+ w_ /= rhs;
+ return *this;
+ }
+
+ // Divide a copy of this by a scalar. Return the copy.
+ const tvec4 operator/(const T& rhs) const
+ {
+ return tvec4(*this) /= rhs;
+ }
+
+ // Component-wise divide of this by another vector.
+ // Return a reference to this.
+ tvec4& operator/=(const tvec4& rhs)
+ {
+ x_ /= rhs.x_;
+ y_ /= rhs.y_;
+ z_ /= rhs.z_;
+ w_ /= rhs.w_;
+ return *this;
+ }
+
+ // Component-wise divide of a copy of this by another vector.
+ // Return the copy.
+ const tvec4 operator/(const tvec4& rhs) const
+ {
+ return tvec4(*this) /= rhs;
+ }
+
+ // Multiply this by a scalar. Return a reference to this.
+ tvec4& operator*=(const T& rhs)
+ {
+ x_ *= rhs;
+ y_ *= rhs;
+ z_ *= rhs;
+ w_ *= rhs;
+ return *this;
+ }
+
+ // Multiply a copy of this by a scalar. Return the copy.
+ const tvec4 operator*(const T& rhs) const
+ {
+ return tvec4(*this) *= rhs;
+ }
+
+ // Component-wise multiply of this by another vector.
+ // Return a reference to this.
+ tvec4& operator*=(const tvec4& rhs)
+ {
+ x_ *= rhs.x_;
+ y_ *= rhs.y_;
+ z_ *= rhs.z_;
+ w_ *= rhs.w_;
+ return *this;
+ }
+
+ // Component-wise multiply of a copy of this by another vector.
+ // Return the copy.
+ const tvec4 operator*(const tvec4& rhs) const
+ {
+ return tvec4(*this) *= rhs;
+ }
+
+ // Add a scalar to this. Return a reference to this.
+ tvec4& operator+=(const T& rhs)
+ {
+ x_ += rhs;
+ y_ += rhs;
+ z_ += rhs;
+ w_ += rhs;
+ return *this;
+ }
+
+ // Add a scalar to a copy of this. Return the copy.
+ const tvec4 operator+(const T& rhs) const
+ {
+ return tvec4(*this) += rhs;
+ }
+
+ // Component-wise addition of another vector to this.
+ // Return a reference to this.
+ tvec4& operator+=(const tvec4& rhs)
+ {
+ x_ += rhs.x_;
+ y_ += rhs.y_;
+ z_ += rhs.z_;
+ w_ += rhs.w_;
+ return *this;
+ }
+
+ // Component-wise addition of another vector to a copy of this.
+ // Return the copy.
+ const tvec4 operator+(const tvec4& rhs) const
+ {
+ return tvec4(*this) += rhs;
+ }
+
+ // Subtract a scalar from this. Return a reference to this.
+ tvec4& operator-=(const T& rhs)
+ {
+ x_ -= rhs;
+ y_ -= rhs;
+ z_ -= rhs;
+ w_ -= rhs;
+ return *this;
+ }
+
+ // Subtract a scalar from a copy of this. Return the copy.
+ const tvec4 operator-(const T& rhs) const
+ {
+ return tvec4(*this) -= rhs;
+ }
+
+ // Component-wise subtraction of another vector from this.
+ // Return a reference to this.
+ tvec4& operator-=(const tvec4& rhs)
+ {
+ x_ -= rhs.x_;
+ y_ -= rhs.y_;
+ z_ -= rhs.z_;
+ w_ -= rhs.w_;
+ return *this;
+ }
+
+ // Component-wise subtraction of another vector from a copy of this.
+ // Return the copy.
+ const tvec4 operator-(const tvec4& rhs) const
+ {
+ return tvec4(*this) -= rhs;
+ }
+
+ // Compute the length of this and return it.
+ float length() const
+ {
+ return sqrt(dot(*this, *this));
+ }
+
+ // Make this a unit vector.
+ void normalize()
+ {
+ float l = length();
+ x_ /= l;
+ y_ /= l;
+ z_ /= l;
+ w_ /= l;
+ }
+
+ // Compute the dot product of two vectors.
+ 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
+
+// Global operators to allow for things like defining a new vector in terms of
+// a product of a scalar and a vector
+template<typename T>
+const LibMatrix::tvec2<T> operator*(const T t, const LibMatrix::tvec2<T>& v)
+{
+ return v * t;
+}
+
+template<typename T>
+const LibMatrix::tvec3<T> operator*(const T t, const LibMatrix::tvec3<T>& v)
+{
+ return v * t;
+}
+
+template<typename T>
+const LibMatrix::tvec4<T> operator*(const T t, const LibMatrix::tvec4<T>& v)
+{
+ return v * t;
+}
+
+#endif // VEC_H_