Home | History | Annotate | Download | only in math
      1 /*
      2  * Copyright 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #pragma once
     18 
     19 #include <math/mat3.h>
     20 #include <math/quat.h>
     21 #include <math/TMatHelpers.h>
     22 #include <math/vec3.h>
     23 #include <math/vec4.h>
     24 
     25 #include <stdint.h>
     26 #include <sys/types.h>
     27 #include <limits>
     28 
     29 #define PURE __attribute__((pure))
     30 
     31 #if __cplusplus >= 201402L
     32 #define CONSTEXPR constexpr
     33 #else
     34 #define CONSTEXPR
     35 #endif
     36 
     37 namespace android {
     38 // -------------------------------------------------------------------------------------
     39 namespace details {
     40 
     41 template<typename T>
     42 class TQuaternion;
     43 
     44 /**
     45  * A 4x4 column-major matrix class.
     46  *
     47  * Conceptually a 4x4 matrix is a an array of 4 column double4:
     48  *
     49  * mat4 m =
     50  *      \f$
     51  *      \left(
     52  *      \begin{array}{cccc}
     53  *      m[0] & m[1] & m[2] & m[3] \\
     54  *      \end{array}
     55  *      \right)
     56  *      \f$
     57  *      =
     58  *      \f$
     59  *      \left(
     60  *      \begin{array}{cccc}
     61  *      m[0][0] & m[1][0] & m[2][0] & m[3][0] \\
     62  *      m[0][1] & m[1][1] & m[2][1] & m[3][1] \\
     63  *      m[0][2] & m[1][2] & m[2][2] & m[3][2] \\
     64  *      m[0][3] & m[1][3] & m[2][3] & m[3][3] \\
     65  *      \end{array}
     66  *      \right)
     67  *      \f$
     68  *      =
     69  *      \f$
     70  *      \left(
     71  *      \begin{array}{cccc}
     72  *      m(0,0) & m(0,1) & m(0,2) & m(0,3) \\
     73  *      m(1,0) & m(1,1) & m(1,2) & m(1,3) \\
     74  *      m(2,0) & m(2,1) & m(2,2) & m(2,3) \\
     75  *      m(3,0) & m(3,1) & m(3,2) & m(3,3) \\
     76  *      \end{array}
     77  *      \right)
     78  *      \f$
     79  *
     80  * m[n] is the \f$ n^{th} \f$ column of the matrix and is a double4.
     81  *
     82  */
     83 template <typename T>
     84 class TMat44 :  public TVecUnaryOperators<TMat44, T>,
     85                 public TVecComparisonOperators<TMat44, T>,
     86                 public TVecAddOperators<TMat44, T>,
     87                 public TMatProductOperators<TMat44, T>,
     88                 public TMatSquareFunctions<TMat44, T>,
     89                 public TMatTransform<TMat44, T>,
     90                 public TMatHelpers<TMat44, T>,
     91                 public TMatDebug<TMat44, T> {
     92 public:
     93     enum no_init { NO_INIT };
     94     typedef T value_type;
     95     typedef T& reference;
     96     typedef T const& const_reference;
     97     typedef size_t size_type;
     98     typedef TVec4<T> col_type;
     99     typedef TVec4<T> row_type;
    100 
    101     static constexpr size_t COL_SIZE = col_type::SIZE;  // size of a column (i.e.: number of rows)
    102     static constexpr size_t ROW_SIZE = row_type::SIZE;  // size of a row (i.e.: number of columns)
    103     static constexpr size_t NUM_ROWS = COL_SIZE;
    104     static constexpr size_t NUM_COLS = ROW_SIZE;
    105 
    106 private:
    107     /*
    108      *  <--  N columns  -->
    109      *
    110      *  a[0][0] a[1][0] a[2][0] ... a[N][0]    ^
    111      *  a[0][1] a[1][1] a[2][1] ... a[N][1]    |
    112      *  a[0][2] a[1][2] a[2][2] ... a[N][2]  M rows
    113      *  ...                                    |
    114      *  a[0][M] a[1][M] a[2][M] ... a[N][M]    v
    115      *
    116      *  COL_SIZE = M
    117      *  ROW_SIZE = N
    118      *  m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ]
    119      */
    120 
    121     col_type m_value[NUM_COLS];
    122 
    123 public:
    124     // array access
    125     inline constexpr col_type const& operator[](size_t column) const {
    126 #if __cplusplus >= 201402L
    127         // only possible in C++0x14 with constexpr
    128         assert(column < NUM_COLS);
    129 #endif
    130         return m_value[column];
    131     }
    132 
    133     inline col_type& operator[](size_t column) {
    134         assert(column < NUM_COLS);
    135         return m_value[column];
    136     }
    137 
    138     // -----------------------------------------------------------------------
    139     // we want the compiler generated versions for these...
    140     TMat44(const TMat44&) = default;
    141     ~TMat44() = default;
    142     TMat44& operator = (const TMat44&) = default;
    143 
    144     /*
    145      *  constructors
    146      */
    147 
    148     // leaves object uninitialized. use with caution.
    149     explicit constexpr TMat44(no_init)
    150             : m_value{ col_type(col_type::NO_INIT),
    151                        col_type(col_type::NO_INIT),
    152                        col_type(col_type::NO_INIT),
    153                        col_type(col_type::NO_INIT) } {}
    154 
    155     /** initialize to identity.
    156      *
    157      *      \f$
    158      *      \left(
    159      *      \begin{array}{cccc}
    160      *      1 & 0 & 0 & 0 \\
    161      *      0 & 1 & 0 & 0 \\
    162      *      0 & 0 & 1 & 0 \\
    163      *      0 & 0 & 0 & 1 \\
    164      *      \end{array}
    165      *      \right)
    166      *      \f$
    167      */
    168     CONSTEXPR TMat44();
    169 
    170     /** initialize to Identity*scalar.
    171      *
    172      *      \f$
    173      *      \left(
    174      *      \begin{array}{cccc}
    175      *      v & 0 & 0 & 0 \\
    176      *      0 & v & 0 & 0 \\
    177      *      0 & 0 & v & 0 \\
    178      *      0 & 0 & 0 & v \\
    179      *      \end{array}
    180      *      \right)
    181      *      \f$
    182      */
    183     template<typename U>
    184     explicit CONSTEXPR TMat44(U v);
    185 
    186     /** sets the diagonal to a vector.
    187      *
    188      *      \f$
    189      *      \left(
    190      *      \begin{array}{cccc}
    191      *      v[0] & 0 & 0 & 0 \\
    192      *      0 & v[1] & 0 & 0 \\
    193      *      0 & 0 & v[2] & 0 \\
    194      *      0 & 0 & 0 & v[3] \\
    195      *      \end{array}
    196      *      \right)
    197      *      \f$
    198      */
    199     template <typename U>
    200     explicit CONSTEXPR TMat44(const TVec4<U>& v);
    201 
    202     // construct from another matrix of the same size
    203     template <typename U>
    204     explicit CONSTEXPR TMat44(const TMat44<U>& rhs);
    205 
    206     /** construct from 4 column vectors.
    207      *
    208      *      \f$
    209      *      \left(
    210      *      \begin{array}{cccc}
    211      *      v0 & v1 & v2 & v3 \\
    212      *      \end{array}
    213      *      \right)
    214      *      \f$
    215      */
    216     template <typename A, typename B, typename C, typename D>
    217     CONSTEXPR TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3);
    218 
    219     /** construct from 16 elements in column-major form.
    220      *
    221      *      \f$
    222      *      \left(
    223      *      \begin{array}{cccc}
    224      *      m[0][0] & m[1][0] & m[2][0] & m[3][0] \\
    225      *      m[0][1] & m[1][1] & m[2][1] & m[3][1] \\
    226      *      m[0][2] & m[1][2] & m[2][2] & m[3][2] \\
    227      *      m[0][3] & m[1][3] & m[2][3] & m[3][3] \\
    228      *      \end{array}
    229      *      \right)
    230      *      \f$
    231      */
    232     template <
    233         typename A, typename B, typename C, typename D,
    234         typename E, typename F, typename G, typename H,
    235         typename I, typename J, typename K, typename L,
    236         typename M, typename N, typename O, typename P>
    237     CONSTEXPR TMat44(
    238             A m00, B m01, C m02, D m03,
    239             E m10, F m11, G m12, H m13,
    240             I m20, J m21, K m22, L m23,
    241             M m30, N m31, O m32, P m33);
    242 
    243     /**
    244      * construct from a quaternion
    245      */
    246     template <typename U>
    247     explicit CONSTEXPR TMat44(const TQuaternion<U>& q);
    248 
    249     /**
    250      * construct from a C array in column major form.
    251      */
    252     template <typename U>
    253     explicit CONSTEXPR TMat44(U const* rawArray);
    254 
    255     /**
    256      * construct from a 3x3 matrix
    257      */
    258     template <typename U>
    259     explicit CONSTEXPR TMat44(const TMat33<U>& matrix);
    260 
    261     /**
    262      * construct from a 3x3 matrix and 3d translation
    263      */
    264     template <typename U, typename V>
    265     CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec3<V>& translation);
    266 
    267     /**
    268      * construct from a 3x3 matrix and 4d last column.
    269      */
    270     template <typename U, typename V>
    271     CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec4<V>& column3);
    272 
    273     /*
    274      *  helpers
    275      */
    276 
    277     static CONSTEXPR TMat44 ortho(T left, T right, T bottom, T top, T near, T far);
    278 
    279     static CONSTEXPR TMat44 frustum(T left, T right, T bottom, T top, T near, T far);
    280 
    281     enum class Fov {
    282         HORIZONTAL,
    283         VERTICAL
    284     };
    285     static CONSTEXPR TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL);
    286 
    287     template <typename A, typename B, typename C>
    288     static CONSTEXPR TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up);
    289 
    290     template <typename A>
    291     static CONSTEXPR TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) {
    292         TVec4<A> r = projectionMatrix * TVec4<A>{ vertice, 1 };
    293         return r.xyz / r.w;
    294     }
    295 
    296     template <typename A>
    297     static CONSTEXPR TVec4<A> project(const TMat44& projectionMatrix, TVec4<A> vertice) {
    298         vertice = projectionMatrix * vertice;
    299         return { vertice.xyz / vertice.w, 1 };
    300     }
    301 
    302     /**
    303      * Constructs a 3x3 matrix from the upper-left corner of this 4x4 matrix
    304      */
    305     inline constexpr TMat33<T> upperLeft() const {
    306         return TMat33<T>(m_value[0].xyz, m_value[1].xyz, m_value[2].xyz);
    307     }
    308 };
    309 
    310 // ----------------------------------------------------------------------------------------
    311 // Constructors
    312 // ----------------------------------------------------------------------------------------
    313 
    314 // Since the matrix code could become pretty big quickly, we don't inline most
    315 // operations.
    316 
    317 template <typename T>
    318 CONSTEXPR TMat44<T>::TMat44() {
    319     m_value[0] = col_type(1, 0, 0, 0);
    320     m_value[1] = col_type(0, 1, 0, 0);
    321     m_value[2] = col_type(0, 0, 1, 0);
    322     m_value[3] = col_type(0, 0, 0, 1);
    323 }
    324 
    325 template <typename T>
    326 template <typename U>
    327 CONSTEXPR TMat44<T>::TMat44(U v) {
    328     m_value[0] = col_type(v, 0, 0, 0);
    329     m_value[1] = col_type(0, v, 0, 0);
    330     m_value[2] = col_type(0, 0, v, 0);
    331     m_value[3] = col_type(0, 0, 0, v);
    332 }
    333 
    334 template<typename T>
    335 template<typename U>
    336 CONSTEXPR TMat44<T>::TMat44(const TVec4<U>& v) {
    337     m_value[0] = col_type(v.x, 0, 0, 0);
    338     m_value[1] = col_type(0, v.y, 0, 0);
    339     m_value[2] = col_type(0, 0, v.z, 0);
    340     m_value[3] = col_type(0, 0, 0, v.w);
    341 }
    342 
    343 // construct from 16 scalars
    344 template<typename T>
    345 template <
    346     typename A, typename B, typename C, typename D,
    347     typename E, typename F, typename G, typename H,
    348     typename I, typename J, typename K, typename L,
    349     typename M, typename N, typename O, typename P>
    350 CONSTEXPR TMat44<T>::TMat44(
    351         A m00, B m01, C m02, D m03,
    352         E m10, F m11, G m12, H m13,
    353         I m20, J m21, K m22, L m23,
    354         M m30, N m31, O m32, P m33) {
    355     m_value[0] = col_type(m00, m01, m02, m03);
    356     m_value[1] = col_type(m10, m11, m12, m13);
    357     m_value[2] = col_type(m20, m21, m22, m23);
    358     m_value[3] = col_type(m30, m31, m32, m33);
    359 }
    360 
    361 template <typename T>
    362 template <typename U>
    363 CONSTEXPR TMat44<T>::TMat44(const TMat44<U>& rhs) {
    364     for (size_t col = 0; col < NUM_COLS; ++col) {
    365         m_value[col] = col_type(rhs[col]);
    366     }
    367 }
    368 
    369 // Construct from 4 column vectors.
    370 template <typename T>
    371 template <typename A, typename B, typename C, typename D>
    372 CONSTEXPR TMat44<T>::TMat44(
    373         const TVec4<A>& v0, const TVec4<B>& v1,
    374         const TVec4<C>& v2, const TVec4<D>& v3) {
    375     m_value[0] = col_type(v0);
    376     m_value[1] = col_type(v1);
    377     m_value[2] = col_type(v2);
    378     m_value[3] = col_type(v3);
    379 }
    380 
    381 // Construct from raw array, in column-major form.
    382 template <typename T>
    383 template <typename U>
    384 CONSTEXPR TMat44<T>::TMat44(U const* rawArray) {
    385     for (size_t col = 0; col < NUM_COLS; ++col) {
    386         for (size_t row = 0; row < NUM_ROWS; ++row) {
    387             m_value[col][row] = *rawArray++;
    388         }
    389     }
    390 }
    391 
    392 template <typename T>
    393 template <typename U>
    394 CONSTEXPR TMat44<T>::TMat44(const TQuaternion<U>& q) {
    395     const U n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
    396     const U s = n > 0 ? 2/n : 0;
    397     const U x = s*q.x;
    398     const U y = s*q.y;
    399     const U z = s*q.z;
    400     const U xx = x*q.x;
    401     const U xy = x*q.y;
    402     const U xz = x*q.z;
    403     const U xw = x*q.w;
    404     const U yy = y*q.y;
    405     const U yz = y*q.z;
    406     const U yw = y*q.w;
    407     const U zz = z*q.z;
    408     const U zw = z*q.w;
    409     m_value[0] = col_type(1-yy-zz,    xy+zw,    xz-yw,   0);
    410     m_value[1] = col_type(  xy-zw,  1-xx-zz,    yz+xw,   0);  // NOLINT
    411     m_value[2] = col_type(  xz+yw,    yz-xw,  1-xx-yy,   0);  // NOLINT
    412     m_value[3] = col_type(      0,        0,        0,   1);  // NOLINT
    413 }
    414 
    415 template <typename T>
    416 template <typename U>
    417 CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m) {
    418     m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0);
    419     m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0);
    420     m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0);
    421     m_value[3] = col_type(      0,       0,       0, 1);  // NOLINT
    422 }
    423 
    424 template <typename T>
    425 template <typename U, typename V>
    426 CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) {
    427     m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0);
    428     m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0);
    429     m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0);
    430     m_value[3] = col_type(   v[0],    v[1],    v[2], 1);  // NOLINT
    431 }
    432 
    433 template <typename T>
    434 template <typename U, typename V>
    435 CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) {
    436     m_value[0] = col_type(m[0][0], m[0][1], m[0][2],    0);  // NOLINT
    437     m_value[1] = col_type(m[1][0], m[1][1], m[1][2],    0);  // NOLINT
    438     m_value[2] = col_type(m[2][0], m[2][1], m[2][2],    0);  // NOLINT
    439     m_value[3] = col_type(   v[0],    v[1],    v[2], v[3]);  // NOLINT
    440 }
    441 
    442 // ----------------------------------------------------------------------------------------
    443 // Helpers
    444 // ----------------------------------------------------------------------------------------
    445 
    446 template <typename T>
    447 CONSTEXPR TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
    448     TMat44<T> m;
    449     m[0][0] =  2 / (right - left);
    450     m[1][1] =  2 / (top   - bottom);
    451     m[2][2] = -2 / (far   - near);
    452     m[3][0] = -(right + left)   / (right - left);
    453     m[3][1] = -(top   + bottom) / (top   - bottom);
    454     m[3][2] = -(far   + near)   / (far   - near);
    455     return m;
    456 }
    457 
    458 template <typename T>
    459 CONSTEXPR TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
    460     TMat44<T> m;
    461     m[0][0] =  (2 * near) / (right - left);
    462     m[1][1] =  (2 * near) / (top   - bottom);
    463     m[2][0] =  (right + left)   / (right - left);
    464     m[2][1] =  (top   + bottom) / (top   - bottom);
    465     m[2][2] = -(far   + near)   / (far   - near);
    466     m[2][3] = -1;
    467     m[3][2] = -(2 * far * near) / (far   - near);
    468     m[3][3] =  0;
    469     return m;
    470 }
    471 
    472 template <typename T>
    473 CONSTEXPR TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) {
    474     T h;
    475     T w;
    476 
    477     if (direction == TMat44::Fov::VERTICAL) {
    478         h = std::tan(fov * M_PI / 360.0f) * near;
    479         w = h * aspect;
    480     } else {
    481         w = std::tan(fov * M_PI / 360.0f) * near;
    482         h = w / aspect;
    483     }
    484     return frustum(-w, w, -h, h, near, far);
    485 }
    486 
    487 /*
    488  * Returns a matrix representing the pose of a virtual camera looking towards -Z in its
    489  * local Y-up coordinate system. "eye" is where the camera is located, "center" is the points its
    490  * looking at and "up" defines where the Y axis of the camera's local coordinate system is.
    491  */
    492 template <typename T>
    493 template <typename A, typename B, typename C>
    494 CONSTEXPR TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) {
    495     TVec3<T> z_axis(normalize(center - eye));
    496     TVec3<T> norm_up(normalize(up));
    497     if (std::abs(dot(z_axis, norm_up)) > 0.999) {
    498         // Fix up vector if we're degenerate (looking straight up, basically)
    499         norm_up = { norm_up.z, norm_up.x, norm_up.y };
    500     }
    501     TVec3<T> x_axis(normalize(cross(z_axis, norm_up)));
    502     TVec3<T> y_axis(cross(x_axis, z_axis));
    503     return TMat44<T>(
    504             TVec4<T>(x_axis, 0),
    505             TVec4<T>(y_axis, 0),
    506             TVec4<T>(-z_axis, 0),
    507             TVec4<T>(eye, 1));
    508 }
    509 
    510 // ----------------------------------------------------------------------------------------
    511 // Arithmetic operators outside of class
    512 // ----------------------------------------------------------------------------------------
    513 
    514 /* We use non-friend functions here to prevent the compiler from using
    515  * implicit conversions, for instance of a scalar to a vector. The result would
    516  * not be what the caller expects.
    517  *
    518  * Also note that the order of the arguments in the inner loop is important since
    519  * it determines the output type (only relevant when T != U).
    520  */
    521 
    522 // matrix * column-vector, result is a vector of the same type than the input vector
    523 template <typename T, typename U>
    524 CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U>& rhs) {
    525     // Result is initialized to zero.
    526     typename TMat44<T>::col_type result;
    527     for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) {
    528         result += lhs[col] * rhs[col];
    529     }
    530     return result;
    531 }
    532 
    533 // mat44 * vec3, result is vec3( mat44 * {vec3, 1} )
    534 template <typename T, typename U>
    535 CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec3<U>& rhs) {
    536     return lhs * TVec4<U>{ rhs, 1 };
    537 }
    538 
    539 
    540 // row-vector * matrix, result is a vector of the same type than the input vector
    541 template <typename T, typename U>
    542 CONSTEXPR typename TMat44<U>::row_type PURE operator *(const TVec4<U>& lhs, const TMat44<T>& rhs) {
    543     typename TMat44<U>::row_type result(TMat44<U>::row_type::NO_INIT);
    544     for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) {
    545         result[col] = dot(lhs, rhs[col]);
    546     }
    547     return result;
    548 }
    549 
    550 // matrix * scalar, result is a matrix of the same type than the input matrix
    551 template <typename T, typename U>
    552 constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat44<T>>::type PURE
    553 operator *(TMat44<T> lhs, U rhs) {
    554     return lhs *= rhs;
    555 }
    556 
    557 // scalar * matrix, result is a matrix of the same type than the input matrix
    558 template <typename T, typename U>
    559 constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat44<T>>::type PURE
    560 operator *(U lhs, const TMat44<T>& rhs) {
    561     return rhs * lhs;
    562 }
    563 
    564 // ----------------------------------------------------------------------------------------
    565 
    566 /* FIXME: this should go into TMatSquareFunctions<> but for some reason
    567  * BASE<T>::col_type is not accessible from there (???)
    568  */
    569 template<typename T>
    570 typename TMat44<T>::col_type PURE diag(const TMat44<T>& m) {
    571     return matrix::diag(m);
    572 }
    573 
    574 } // namespace details
    575 
    576 // ----------------------------------------------------------------------------------------
    577 
    578 typedef details::TMat44<double> mat4d;
    579 typedef details::TMat44<float> mat4;
    580 typedef details::TMat44<float> mat4f;
    581 
    582 // ----------------------------------------------------------------------------------------
    583 }  // namespace android
    584 
    585 #undef PURE
    586 #undef CONSTEXPR
    587