vector and matrix classes for graphics use
- this implements vec2, vec3, vec4, which are float vectors
of size 2, 3 and 4 respectively.
the code allows easy instantiation of vectors of a different
type via the tvec{2|3|4}<T> template classes.
- this also implements mat4 which is a float 4x4 matrix. the
tmat44<T> template class allows easy instantiation of a
4x4 matrix of a different value_type.
The vector types have some minimal support for the
glsl style swizzled access; for instance:
vec4 u;
vec3 v = u.xyz;
only .x, .xy, .xyz and their .stpq / .rgba equivalent are
supported.
most operators are supported on both vector and matrices:
arithmetic, unary, compound assignment and comparison
(bit-wise operators NOT supported).
- operations available on vectors include:
dot, length, distance, normalize and cross
- operations available on matrices include:
transpose, inverse, trace
- and a few utilities to create matrices:
ortho, frustum, lookAt
Change-Id: I64add89ae90fa78d3f2f59985b63495575378635
diff --git a/include/ui/mat4.h b/include/ui/mat4.h
new file mode 100644
index 0000000..08a67c7
--- /dev/null
+++ b/include/ui/mat4.h
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UI_MAT4_H
+#define UI_MAT4_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <ui/vec4.h>
+#include <utils/String8.h>
+
+#define TMAT_IMPLEMENTATION
+#include <ui/TMatHelpers.h>
+
+#define PURE __attribute__((pure))
+
+namespace android {
+// -------------------------------------------------------------------------------------
+
+template <typename T>
+class tmat44 : public TVecUnaryOperators<tmat44, T>,
+ public TVecComparisonOperators<tmat44, T>
+{
+public:
+ enum no_init { NO_INIT };
+ typedef T value_type;
+ typedef T& reference;
+ typedef T const& const_reference;
+ typedef size_t size_type;
+ typedef tvec4<T> col_type;
+ typedef tvec4<T> row_type;
+
+ // size of a column (i.e.: number of rows)
+ enum { COL_SIZE = col_type::SIZE };
+ static inline size_t col_size() { return COL_SIZE; }
+
+ // size of a row (i.e.: number of columns)
+ enum { ROW_SIZE = row_type::SIZE };
+ static inline size_t row_size() { return ROW_SIZE; }
+ static inline size_t size() { return row_size(); } // for TVec*<>
+
+private:
+
+ /*
+ * <-- N columns -->
+ *
+ * a00 a10 a20 ... aN0 ^
+ * a01 a11 a21 ... aN1 |
+ * a02 a12 a22 ... aN2 M rows
+ * ... |
+ * a0M a1M a2M ... aNM v
+ *
+ * COL_SIZE = M
+ * ROW_SIZE = N
+ * m[0] = [a00 a01 a02 ... a01M]
+ */
+
+ col_type mValue[ROW_SIZE];
+
+public:
+ // array access
+ inline col_type const& operator [] (size_t i) const { return mValue[i]; }
+ inline col_type& operator [] (size_t i) { return mValue[i]; }
+
+ T const* asArray() const { return &mValue[0][0]; }
+
+ // -----------------------------------------------------------------------
+ // we don't provide copy-ctor and operator= on purpose
+ // because we want the compiler generated versions
+
+ /*
+ * constructors
+ */
+
+ // leaves object uninitialized. use with caution.
+ explicit tmat44(no_init) { }
+
+ // initialize to identity
+ tmat44();
+
+ // initialize to Identity*scalar.
+ template<typename U>
+ explicit tmat44(U v);
+
+ // sets the diagonal to the passed vector
+ template <typename U>
+ explicit tmat44(const tvec4<U>& rhs);
+
+ // construct from another matrix of the same size
+ template <typename U>
+ explicit tmat44(const tmat44<U>& rhs);
+
+ // construct from 4 column vectors
+ template <typename A, typename B, typename C, typename D>
+ tmat44(const tvec4<A>& v0, const tvec4<B>& v1, const tvec4<C>& v2, const tvec4<D>& v3);
+
+ // construct from a C array
+ template <typename U>
+ explicit tmat44(U const* rawArray);
+
+ /*
+ * helpers
+ */
+
+ static tmat44 ortho(T left, T right, T bottom, T top, T near, T far);
+
+ static tmat44 frustum(T left, T right, T bottom, T top, T near, T far);
+
+ template <typename A, typename B, typename C>
+ static tmat44 lookAt(const tvec3<A>& eye, const tvec3<B>& center, const tvec3<C>& up);
+
+ template <typename A>
+ static tmat44 translate(const tvec4<A>& t);
+
+ template <typename A>
+ static tmat44 scale(const tvec4<A>& s);
+
+ template <typename A, typename B>
+ static tmat44 rotate(A radian, const tvec3<B>& about);
+
+
+ /*
+ * Compound assignment arithmetic operators
+ */
+
+ // add another matrix of the same size
+ template <typename U>
+ tmat44& operator += (const tmat44<U>& v);
+
+ // subtract another matrix of the same size
+ template <typename U>
+ tmat44& operator -= (const tmat44<U>& v);
+
+ // multiply by a scalar
+ template <typename U>
+ tmat44& operator *= (U v);
+
+ // divide by a scalar
+ template <typename U>
+ tmat44& operator /= (U v);
+
+ /*
+ * debugging
+ */
+
+ String8 asString() const;
+};
+
+// ----------------------------------------------------------------------------------------
+// Constructors
+// ----------------------------------------------------------------------------------------
+
+/*
+ * Since the matrix code could become pretty big quickly, we don't inline most
+ * operations.
+ */
+
+template <typename T>
+tmat44<T>::tmat44() {
+ mValue[0] = col_type(1,0,0,0);
+ mValue[1] = col_type(0,1,0,0);
+ mValue[2] = col_type(0,0,1,0);
+ mValue[3] = col_type(0,0,0,1);
+}
+
+template <typename T>
+template <typename U>
+tmat44<T>::tmat44(U v) {
+ mValue[0] = col_type(v,0,0,0);
+ mValue[1] = col_type(0,v,0,0);
+ mValue[2] = col_type(0,0,v,0);
+ mValue[3] = col_type(0,0,0,v);
+}
+
+template<typename T>
+template<typename U>
+tmat44<T>::tmat44(const tvec4<U>& v) {
+ mValue[0] = col_type(v.x,0,0,0);
+ mValue[1] = col_type(0,v.y,0,0);
+ mValue[2] = col_type(0,0,v.z,0);
+ mValue[3] = col_type(0,0,0,v.w);
+}
+
+template <typename T>
+template <typename U>
+tmat44<T>::tmat44(const tmat44<U>& rhs) {
+ for (size_t r=0 ; r<row_size() ; r++)
+ mValue[r] = rhs[r];
+}
+
+template <typename T>
+template <typename A, typename B, typename C, typename D>
+tmat44<T>::tmat44(const tvec4<A>& v0, const tvec4<B>& v1, const tvec4<C>& v2, const tvec4<D>& v3) {
+ mValue[0] = v0;
+ mValue[1] = v1;
+ mValue[2] = v2;
+ mValue[3] = v3;
+}
+
+template <typename T>
+template <typename U>
+tmat44<T>::tmat44(U const* rawArray) {
+ for (size_t r=0 ; r<row_size() ; r++)
+ for (size_t c=0 ; c<col_size() ; c++)
+ mValue[r][c] = *rawArray++;
+}
+
+// ----------------------------------------------------------------------------------------
+// Helpers
+// ----------------------------------------------------------------------------------------
+
+template <typename T>
+tmat44<T> tmat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
+ tmat44<T> m;
+ m[0][0] = 2 / (right - left);
+ m[1][1] = 2 / (top - bottom);
+ m[2][2] = -2 / (far - near);
+ m[3][0] = -(right + left) / (right - left);
+ m[3][1] = -(top + bottom) / (top - bottom);
+ m[3][2] = -(far + near) / (far - near);
+ return m;
+}
+
+template <typename T>
+tmat44<T> tmat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
+ tmat44<T> m;
+ T A = (right + left) / (right - left);
+ T B = (top + bottom) / (top - bottom);
+ T C = (far + near) / (far - near);
+ T D = (2 * far * near) / (far - near);
+ m[0][0] = (2 * near) / (right - left);
+ m[1][1] = (2 * near) / (top - bottom);
+ m[2][0] = A;
+ m[2][1] = B;
+ m[2][2] = C;
+ m[2][3] =-1;
+ m[3][2] = D;
+ m[3][3] = 0;
+ return m;
+}
+
+template <typename T>
+template <typename A, typename B, typename C>
+tmat44<T> tmat44<T>::lookAt(const tvec3<A>& eye, const tvec3<B>& center, const tvec3<C>& up) {
+ tvec3<T> L(normalize(center - eye));
+ tvec3<T> S(normalize( cross(L, up) ));
+ tvec3<T> U(cross(S, L));
+ return tmat44<T>(
+ tvec4<T>( S, 0),
+ tvec4<T>( U, 0),
+ tvec4<T>(-L, 0),
+ tvec4<T>(-eye, 1));
+}
+
+template <typename T>
+template <typename A>
+tmat44<T> tmat44<T>::translate(const tvec4<A>& t) {
+ tmat44<T> r;
+ r[3] = t;
+ return r;
+}
+
+template <typename T>
+template <typename A>
+tmat44<T> tmat44<T>::scale(const tvec4<A>& s) {
+ tmat44<T> r;
+ r[0][0] = s[0];
+ r[1][1] = s[1];
+ r[2][2] = s[2];
+ r[3][3] = s[3];
+ return r;
+}
+
+template <typename T>
+template <typename A, typename B>
+tmat44<T> tmat44<T>::rotate(A radian, const tvec3<B>& about) {
+ tmat44<T> rotation;
+ T* r = const_cast<T*>(rotation.asArray());
+ T c = cos(radian);
+ T s = sin(radian);
+ if (about.x==1 && about.y==0 && about.z==0) {
+ r[5] = c; r[10]= c;
+ r[6] = s; r[9] = -s;
+ } else if (about.x==0 && about.y==1 && about.z==0) {
+ r[0] = c; r[10]= c;
+ r[8] = s; r[2] = -s;
+ } else if (about.x==0 && about.y==0 && about.z==1) {
+ r[0] = c; r[5] = c;
+ r[1] = s; r[4] = -s;
+ } else {
+ tvec3<B> nabout = normalize(about);
+ B x = nabout.x;
+ B y = nabout.y;
+ B z = nabout.z;
+ T nc = 1 - c;
+ T xy = x * y;
+ T yz = y * z;
+ T zx = z * x;
+ T xs = x * s;
+ T ys = y * s;
+ T zs = z * s;
+ r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys;
+ r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs;
+ r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c;
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+// Compound assignment arithmetic operators
+// ----------------------------------------------------------------------------------------
+
+template <typename T>
+template <typename U>
+tmat44<T>& tmat44<T>::operator += (const tmat44<U>& v) {
+ for (size_t r=0 ; r<row_size() ; r++)
+ mValue[r] += v[r];
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+tmat44<T>& tmat44<T>::operator -= (const tmat44<U>& v) {
+ for (size_t r=0 ; r<row_size() ; r++)
+ mValue[r] -= v[r];
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+tmat44<T>& tmat44<T>::operator *= (U v) {
+ for (size_t r=0 ; r<row_size() ; r++)
+ mValue[r] *= v;
+ return *this;
+}
+
+template <typename T>
+template <typename U>
+tmat44<T>& tmat44<T>::operator /= (U v) {
+ for (size_t r=0 ; r<row_size() ; r++)
+ mValue[r] /= v;
+ return *this;
+}
+
+// ----------------------------------------------------------------------------------------
+// Arithmetic operators outside of class
+// ----------------------------------------------------------------------------------------
+
+/* We use non-friend functions here to prevent the compiler from using
+ * implicit conversions, for instance of a scalar to a vector. The result would
+ * not be what the caller expects.
+ *
+ * Also note that the order of the arguments in the inner loop is important since
+ * it determines the output type (only relevant when T != U).
+ */
+
+// matrix + matrix, result is a matrix of the same type than the lhs matrix
+template <typename T, typename U>
+tmat44<T> PURE operator +(const tmat44<T>& lhs, const tmat44<U>& rhs) {
+ tmat44<T> result(tmat44<T>::NO_INIT);
+ for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
+ result[r] = lhs[r] + rhs[r];
+ return result;
+}
+
+// matrix - matrix, result is a matrix of the same type than the lhs matrix
+template <typename T, typename U>
+tmat44<T> PURE operator -(const tmat44<T>& lhs, const tmat44<U>& rhs) {
+ tmat44<T> result(tmat44<T>::NO_INIT);
+ for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
+ result[r] = lhs[r] - rhs[r];
+ return result;
+}
+
+// matrix * vector, result is a vector of the same type than the input vector
+template <typename T, typename U>
+typename tmat44<U>::col_type PURE operator *(const tmat44<T>& lv, const tvec4<U>& rv) {
+ typename tmat44<U>::col_type result;
+ for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
+ result += rv[r]*lv[r];
+ return result;
+}
+
+// vector * matrix, result is a vector of the same type than the input vector
+template <typename T, typename U>
+typename tmat44<U>::row_type PURE operator *(const tvec4<U>& rv, const tmat44<T>& lv) {
+ typename tmat44<U>::row_type result(tmat44<U>::row_type::NO_INIT);
+ for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
+ result[r] = dot(rv, lv[r]);
+ return result;
+}
+
+// matrix * scalar, result is a matrix of the same type than the input matrix
+template <typename T, typename U>
+tmat44<T> PURE operator *(const tmat44<T>& lv, U rv) {
+ tmat44<T> result(tmat44<T>::NO_INIT);
+ for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
+ result[r] = lv[r]*rv;
+ return result;
+}
+
+// scalar * matrix, result is a matrix of the same type than the input matrix
+template <typename T, typename U>
+tmat44<T> PURE operator *(U rv, const tmat44<T>& lv) {
+ tmat44<T> result(tmat44<T>::NO_INIT);
+ for (size_t r=0 ; r<tmat44<T>::row_size() ; r++)
+ result[r] = lv[r]*rv;
+ return result;
+}
+
+// matrix * matrix, result is a matrix of the same type than the lhs matrix
+template <typename T, typename U>
+tmat44<T> PURE operator *(const tmat44<T>& lhs, const tmat44<U>& rhs) {
+ return matrix::multiply< tmat44<T> >(lhs, rhs);
+}
+
+// ----------------------------------------------------------------------------------------
+// Functions
+// ----------------------------------------------------------------------------------------
+
+// inverse a matrix
+template <typename T>
+tmat44<T> PURE inverse(const tmat44<T>& m) {
+ return matrix::inverse(m);
+}
+
+template <typename T>
+tmat44<T> PURE transpose(const tmat44<T>& m) {
+ return matrix::transpose(m);
+}
+
+template <typename T>
+T PURE trace(const tmat44<T>& m) {
+ return matrix::trace(m);
+}
+
+template <typename T>
+tvec4<T> PURE diag(const tmat44<T>& m) {
+ return matrix::diag(m);
+}
+
+// ----------------------------------------------------------------------------------------
+// Debugging
+// ----------------------------------------------------------------------------------------
+
+template <typename T>
+String8 tmat44<T>::asString() const {
+ return matrix::asString(*this);
+}
+
+// ----------------------------------------------------------------------------------------
+
+typedef tmat44<float> mat4;
+
+// ----------------------------------------------------------------------------------------
+}; // namespace android
+
+#undef PURE
+
+#endif /* UI_MAT4_H */