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