2 * Copyright 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <ui/TMatHelpers.h>
27 #include <sys/types.h>
30 #define PURE __attribute__((pure))
32 #if __cplusplus >= 201402L
33 #define CONSTEXPR constexpr
39 // -------------------------------------------------------------------------------------
46 * A 4x4 column-major matrix class.
48 * Conceptually a 4x4 matrix is a an array of 4 column double4:
54 * m[0] & m[1] & m[2] & m[3] \\
62 * m[0][0] & m[1][0] & m[2][0] & m[3][0] \\
63 * m[0][1] & m[1][1] & m[2][1] & m[3][1] \\
64 * m[0][2] & m[1][2] & m[2][2] & m[3][2] \\
65 * m[0][3] & m[1][3] & m[2][3] & m[3][3] \\
73 * m(0,0) & m(0,1) & m(0,2) & m(0,3) \\
74 * m(1,0) & m(1,1) & m(1,2) & m(1,3) \\
75 * m(2,0) & m(2,1) & m(2,2) & m(2,3) \\
76 * m(3,0) & m(3,1) & m(3,2) & m(3,3) \\
81 * m[n] is the \f$ n^{th} \f$ column of the matrix and is a double4.
85 class TMat44 : public TVecUnaryOperators<TMat44, T>,
86 public TVecComparisonOperators<TMat44, T>,
87 public TVecAddOperators<TMat44, T>,
88 public TMatProductOperators<TMat44, T>,
89 public TMatSquareFunctions<TMat44, T>,
90 public TMatTransform<TMat44, T>,
91 public TMatHelpers<TMat44, T>,
92 public TMatDebug<TMat44, T> {
94 enum no_init { NO_INIT };
97 typedef T const& const_reference;
98 typedef size_t size_type;
99 typedef TVec4<T> col_type;
100 typedef TVec4<T> row_type;
102 static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows)
103 static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns)
104 static constexpr size_t NUM_ROWS = COL_SIZE;
105 static constexpr size_t NUM_COLS = ROW_SIZE;
111 * a[0][0] a[1][0] a[2][0] ... a[N][0] ^
112 * a[0][1] a[1][1] a[2][1] ... a[N][1] |
113 * a[0][2] a[1][2] a[2][2] ... a[N][2] M rows
115 * a[0][M] a[1][M] a[2][M] ... a[N][M] v
119 * m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ]
122 col_type m_value[NUM_COLS];
126 inline constexpr col_type const& operator[](size_t column) const {
127 #if __cplusplus >= 201402L
128 // only possible in C++0x14 with constexpr
129 assert(column < NUM_COLS);
131 return m_value[column];
134 inline col_type& operator[](size_t column) {
135 assert(column < NUM_COLS);
136 return m_value[column];
139 // -----------------------------------------------------------------------
140 // we want the compiler generated versions for these...
141 TMat44(const TMat44&) = default;
143 TMat44& operator = (const TMat44&) = default;
149 // leaves object uninitialized. use with caution.
150 explicit constexpr TMat44(no_init)
151 : m_value{ col_type(col_type::NO_INIT),
152 col_type(col_type::NO_INIT),
153 col_type(col_type::NO_INIT),
154 col_type(col_type::NO_INIT) } {}
156 /** initialize to identity.
160 * \begin{array}{cccc}
171 /** initialize to Identity*scalar.
175 * \begin{array}{cccc}
185 explicit CONSTEXPR TMat44(U v);
187 /** sets the diagonal to a vector.
191 * \begin{array}{cccc}
192 * v[0] & 0 & 0 & 0 \\
193 * 0 & v[1] & 0 & 0 \\
194 * 0 & 0 & v[2] & 0 \\
195 * 0 & 0 & 0 & v[3] \\
200 template <typename U>
201 explicit CONSTEXPR TMat44(const TVec4<U>& v);
203 // construct from another matrix of the same size
204 template <typename U>
205 explicit CONSTEXPR TMat44(const TMat44<U>& rhs);
207 /** construct from 4 column vectors.
211 * \begin{array}{cccc}
212 * v0 & v1 & v2 & v3 \\
217 template <typename A, typename B, typename C, typename D>
218 CONSTEXPR TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3);
220 /** construct from 16 elements in column-major form.
224 * \begin{array}{cccc}
225 * m[0][0] & m[1][0] & m[2][0] & m[3][0] \\
226 * m[0][1] & m[1][1] & m[2][1] & m[3][1] \\
227 * m[0][2] & m[1][2] & m[2][2] & m[3][2] \\
228 * m[0][3] & m[1][3] & m[2][3] & m[3][3] \\
234 typename A, typename B, typename C, typename D,
235 typename E, typename F, typename G, typename H,
236 typename I, typename J, typename K, typename L,
237 typename M, typename N, typename O, typename P>
239 A m00, B m01, C m02, D m03,
240 E m10, F m11, G m12, H m13,
241 I m20, J m21, K m22, L m23,
242 M m30, N m31, O m32, P m33);
245 * construct from a quaternion
247 template <typename U>
248 explicit CONSTEXPR TMat44(const TQuaternion<U>& q);
251 * construct from a C array in column major form.
253 template <typename U>
254 explicit CONSTEXPR TMat44(U const* rawArray);
257 * construct from a 3x3 matrix
259 template <typename U>
260 explicit CONSTEXPR TMat44(const TMat33<U>& matrix);
263 * construct from a 3x3 matrix and 3d translation
265 template <typename U, typename V>
266 CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec3<V>& translation);
269 * construct from a 3x3 matrix and 4d last column.
271 template <typename U, typename V>
272 CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec4<V>& column3);
278 static CONSTEXPR TMat44 ortho(T left, T right, T bottom, T top, T near, T far);
280 static CONSTEXPR TMat44 frustum(T left, T right, T bottom, T top, T near, T far);
286 static CONSTEXPR TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL);
288 template <typename A, typename B, typename C>
289 static CONSTEXPR TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up);
291 template <typename A>
292 static CONSTEXPR TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) {
293 TVec4<A> r = projectionMatrix * TVec4<A>{ vertice, 1 };
297 template <typename A>
298 static CONSTEXPR TVec4<A> project(const TMat44& projectionMatrix, TVec4<A> vertice) {
299 vertice = projectionMatrix * vertice;
300 return { vertice.xyz / vertice.w, 1 };
304 * Constructs a 3x3 matrix from the upper-left corner of this 4x4 matrix
306 inline constexpr TMat33<T> upperLeft() const {
307 return TMat33<T>(m_value[0].xyz, m_value[1].xyz, m_value[2].xyz);
311 // ----------------------------------------------------------------------------------------
313 // ----------------------------------------------------------------------------------------
315 // Since the matrix code could become pretty big quickly, we don't inline most
318 template <typename T>
319 CONSTEXPR TMat44<T>::TMat44() {
320 m_value[0] = col_type(1, 0, 0, 0);
321 m_value[1] = col_type(0, 1, 0, 0);
322 m_value[2] = col_type(0, 0, 1, 0);
323 m_value[3] = col_type(0, 0, 0, 1);
326 template <typename T>
327 template <typename U>
328 CONSTEXPR TMat44<T>::TMat44(U v) {
329 m_value[0] = col_type(v, 0, 0, 0);
330 m_value[1] = col_type(0, v, 0, 0);
331 m_value[2] = col_type(0, 0, v, 0);
332 m_value[3] = col_type(0, 0, 0, v);
337 CONSTEXPR TMat44<T>::TMat44(const TVec4<U>& v) {
338 m_value[0] = col_type(v.x, 0, 0, 0);
339 m_value[1] = col_type(0, v.y, 0, 0);
340 m_value[2] = col_type(0, 0, v.z, 0);
341 m_value[3] = col_type(0, 0, 0, v.w);
344 // construct from 16 scalars
347 typename A, typename B, typename C, typename D,
348 typename E, typename F, typename G, typename H,
349 typename I, typename J, typename K, typename L,
350 typename M, typename N, typename O, typename P>
351 CONSTEXPR TMat44<T>::TMat44(
352 A m00, B m01, C m02, D m03,
353 E m10, F m11, G m12, H m13,
354 I m20, J m21, K m22, L m23,
355 M m30, N m31, O m32, P m33) {
356 m_value[0] = col_type(m00, m01, m02, m03);
357 m_value[1] = col_type(m10, m11, m12, m13);
358 m_value[2] = col_type(m20, m21, m22, m23);
359 m_value[3] = col_type(m30, m31, m32, m33);
362 template <typename T>
363 template <typename U>
364 CONSTEXPR TMat44<T>::TMat44(const TMat44<U>& rhs) {
365 for (size_t col = 0; col < NUM_COLS; ++col) {
366 m_value[col] = col_type(rhs[col]);
370 // Construct from 4 column vectors.
371 template <typename T>
372 template <typename A, typename B, typename C, typename D>
373 CONSTEXPR TMat44<T>::TMat44(
374 const TVec4<A>& v0, const TVec4<B>& v1,
375 const TVec4<C>& v2, const TVec4<D>& v3) {
376 m_value[0] = col_type(v0);
377 m_value[1] = col_type(v1);
378 m_value[2] = col_type(v2);
379 m_value[3] = col_type(v3);
382 // Construct from raw array, in column-major form.
383 template <typename T>
384 template <typename U>
385 CONSTEXPR TMat44<T>::TMat44(U const* rawArray) {
386 for (size_t col = 0; col < NUM_COLS; ++col) {
387 for (size_t row = 0; row < NUM_ROWS; ++row) {
388 m_value[col][row] = *rawArray++;
393 template <typename T>
394 template <typename U>
395 CONSTEXPR TMat44<T>::TMat44(const TQuaternion<U>& q) {
396 const U n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
397 const U s = n > 0 ? 2/n : 0;
410 m_value[0] = col_type(1-yy-zz, xy+zw, xz-yw, 0);
411 m_value[1] = col_type( xy-zw, 1-xx-zz, yz+xw, 0); // NOLINT
412 m_value[2] = col_type( xz+yw, yz-xw, 1-xx-yy, 0); // NOLINT
413 m_value[3] = col_type( 0, 0, 0, 1); // NOLINT
416 template <typename T>
417 template <typename U>
418 CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m) {
419 m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0);
420 m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0);
421 m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0);
422 m_value[3] = col_type( 0, 0, 0, 1); // NOLINT
425 template <typename T>
426 template <typename U, typename V>
427 CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) {
428 m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0);
429 m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0);
430 m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0);
431 m_value[3] = col_type( v[0], v[1], v[2], 1); // NOLINT
434 template <typename T>
435 template <typename U, typename V>
436 CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) {
437 m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0); // NOLINT
438 m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0); // NOLINT
439 m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0); // NOLINT
440 m_value[3] = col_type( v[0], v[1], v[2], v[3]); // NOLINT
443 // ----------------------------------------------------------------------------------------
445 // ----------------------------------------------------------------------------------------
447 template <typename T>
448 CONSTEXPR TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
450 m[0][0] = 2 / (right - left);
451 m[1][1] = 2 / (top - bottom);
452 m[2][2] = -2 / (far - near);
453 m[3][0] = -(right + left) / (right - left);
454 m[3][1] = -(top + bottom) / (top - bottom);
455 m[3][2] = -(far + near) / (far - near);
459 template <typename T>
460 CONSTEXPR TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
462 m[0][0] = (2 * near) / (right - left);
463 m[1][1] = (2 * near) / (top - bottom);
464 m[2][0] = (right + left) / (right - left);
465 m[2][1] = (top + bottom) / (top - bottom);
466 m[2][2] = -(far + near) / (far - near);
468 m[3][2] = -(2 * far * near) / (far - near);
473 template <typename T>
474 CONSTEXPR TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) {
478 if (direction == TMat44::Fov::VERTICAL) {
479 h = std::tan(fov * M_PI / 360.0f) * near;
482 w = std::tan(fov * M_PI / 360.0f) * near;
485 return frustum(-w, w, -h, h, near, far);
489 * Returns a matrix representing the pose of a virtual camera looking towards -Z in its
490 * local Y-up coordinate system. "eye" is where the camera is located, "center" is the points its
491 * looking at and "up" defines where the Y axis of the camera's local coordinate system is.
493 template <typename T>
494 template <typename A, typename B, typename C>
495 CONSTEXPR TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) {
496 TVec3<T> z_axis(normalize(center - eye));
497 TVec3<T> norm_up(normalize(up));
498 if (std::abs(dot(z_axis, norm_up)) > 0.999) {
499 // Fix up vector if we're degenerate (looking straight up, basically)
500 norm_up = { norm_up.z, norm_up.x, norm_up.y };
502 TVec3<T> x_axis(normalize(cross(z_axis, norm_up)));
503 TVec3<T> y_axis(cross(x_axis, z_axis));
507 TVec4<T>(-z_axis, 0),
511 // ----------------------------------------------------------------------------------------
512 // Arithmetic operators outside of class
513 // ----------------------------------------------------------------------------------------
515 /* We use non-friend functions here to prevent the compiler from using
516 * implicit conversions, for instance of a scalar to a vector. The result would
517 * not be what the caller expects.
519 * Also note that the order of the arguments in the inner loop is important since
520 * it determines the output type (only relevant when T != U).
523 // matrix * column-vector, result is a vector of the same type than the input vector
524 template <typename T, typename U>
525 CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U>& rhs) {
526 // Result is initialized to zero.
527 typename TMat44<T>::col_type result;
528 for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) {
529 result += lhs[col] * rhs[col];
534 // mat44 * vec3, result is vec3( mat44 * {vec3, 1} )
535 template <typename T, typename U>
536 CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec3<U>& rhs) {
537 return lhs * TVec4<U>{ rhs, 1 };
541 // row-vector * matrix, result is a vector of the same type than the input vector
542 template <typename T, typename U>
543 CONSTEXPR typename TMat44<U>::row_type PURE operator *(const TVec4<U>& lhs, const TMat44<T>& rhs) {
544 typename TMat44<U>::row_type result(TMat44<U>::row_type::NO_INIT);
545 for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) {
546 result[col] = dot(lhs, rhs[col]);
551 // matrix * scalar, result is a matrix of the same type than the input matrix
552 template <typename T, typename U>
553 constexpr typename std::enable_if<std::is_arithmetic<U>::value, TMat44<T>>::type PURE
554 operator *(TMat44<T> lhs, U rhs) {
558 // scalar * matrix, 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 *(U lhs, const TMat44<T>& rhs) {
565 // ----------------------------------------------------------------------------------------
567 /* FIXME: this should go into TMatSquareFunctions<> but for some reason
568 * BASE<T>::col_type is not accessible from there (???)
571 typename TMat44<T>::col_type PURE diag(const TMat44<T>& m) {
572 return matrix::diag(m);
575 } // namespace details
577 // ----------------------------------------------------------------------------------------
579 typedef details::TMat44<double> mat4d;
580 typedef details::TMat44<float> mat4;
581 typedef details::TMat44<float> mat4f;
583 // ----------------------------------------------------------------------------------------
584 } // namespace android