/* * 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 #include #include #include #define TMAT_IMPLEMENTATION #include #define PURE __attribute__((pure)) namespace android { // ------------------------------------------------------------------------------------- template class tmat44 : public TVecUnaryOperators, public TVecComparisonOperators, public TVecAddOperators, public TMatProductOperators, public TMatSquareFunctions, public TMatDebug { 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 col_type; typedef tvec4 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 explicit tmat44(U v); // sets the diagonal to the passed vector template explicit tmat44(const tvec4& rhs); // construct from another matrix of the same size template explicit tmat44(const tmat44& rhs); // construct from 4 column vectors template tmat44(const tvec4& v0, const tvec4& v1, const tvec4& v2, const tvec4& v3); // construct from 16 scalars template < typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P> tmat44( A m00, B m01, C m02, D m03, E m10, F m11, G m12, H m13, I m20, J m21, K m22, L m23, M m30, N m31, O m32, P m33); // construct from a C array template 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 static tmat44 lookAt(const tvec3& eye, const tvec3& center, const tvec3& up); template static tmat44 translate(const tvec4& t); template static tmat44 scale(const tvec4& s); template static tmat44 rotate(A radian, const tvec3& about); }; // ---------------------------------------------------------------------------------------- // Constructors // ---------------------------------------------------------------------------------------- /* * Since the matrix code could become pretty big quickly, we don't inline most * operations. */ template tmat44::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 template tmat44::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 template tmat44::tmat44(const tvec4& 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); } // construct from 16 scalars template template < typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P> tmat44::tmat44( A m00, B m01, C m02, D m03, E m10, F m11, G m12, H m13, I m20, J m21, K m22, L m23, M m30, N m31, O m32, P m33) { mValue[0] = col_type(m00, m01, m02, m03); mValue[1] = col_type(m10, m11, m12, m13); mValue[2] = col_type(m20, m21, m22, m23); mValue[3] = col_type(m30, m31, m32, m33); } template template tmat44::tmat44(const tmat44& rhs) { for (size_t r=0 ; r template tmat44::tmat44(const tvec4& v0, const tvec4& v1, const tvec4& v2, const tvec4& v3) { mValue[0] = v0; mValue[1] = v1; mValue[2] = v2; mValue[3] = v3; } template template tmat44::tmat44(U const* rawArray) { for (size_t r=0 ; r tmat44 tmat44::ortho(T left, T right, T bottom, T top, T near, T far) { tmat44 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 tmat44 tmat44::frustum(T left, T right, T bottom, T top, T near, T far) { tmat44 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 template tmat44 tmat44::lookAt(const tvec3& eye, const tvec3& center, const tvec3& up) { tvec3 L(normalize(center - eye)); tvec3 S(normalize( cross(L, up) )); tvec3 U(cross(S, L)); return tmat44( tvec4( S, 0), tvec4( U, 0), tvec4(-L, 0), tvec4(-eye, 1)); } template template tmat44 tmat44::translate(const tvec4& t) { tmat44 r; r[3] = t; return r; } template template tmat44 tmat44::scale(const tvec4& s) { tmat44 r; r[0][0] = s[0]; r[1][1] = s[1]; r[2][2] = s[2]; r[3][3] = s[3]; return r; } template template tmat44 tmat44::rotate(A radian, const tvec3& about) { tmat44 rotation; T* r = const_cast(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 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; } return rotation; } // ---------------------------------------------------------------------------------------- // 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 * vector, result is a vector of the same type than the input vector template typename tmat44::col_type PURE operator *(const tmat44& lv, const tvec4& rv) { typename tmat44::col_type result; for (size_t r=0 ; r::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 tmat44::row_type PURE operator *(const tvec4& rv, const tmat44& lv) { typename tmat44::row_type result(tmat44::row_type::NO_INIT); for (size_t r=0 ; r::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 tmat44 PURE operator *(const tmat44& lv, U rv) { tmat44 result(tmat44::NO_INIT); for (size_t r=0 ; r::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 tmat44 PURE operator *(U rv, const tmat44& lv) { tmat44 result(tmat44::NO_INIT); for (size_t r=0 ; r::row_size() ; r++) result[r] = lv[r]*rv; return result; } // ---------------------------------------------------------------------------------------- /* FIXME: this should go into TMatSquareFunctions<> but for some reason * BASE::col_type is not accessible from there (???) */ template typename tmat44::col_type PURE diag(const tmat44& m) { return matrix::diag(m); } // ---------------------------------------------------------------------------------------- typedef tmat44 mat4; // ---------------------------------------------------------------------------------------- }; // namespace android #undef PURE #endif /* UI_MAT4_H */