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