first commit
This commit is contained in:
807
ios/include/math/TMatHelpers.h
Normal file
807
ios/include/math/TMatHelpers.h
Normal file
@@ -0,0 +1,807 @@
|
||||
/*
|
||||
* 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 MATH_TMATHELPERS_H_
|
||||
#define MATH_TMATHELPERS_H_
|
||||
|
||||
#include <math/compiler.h>
|
||||
#include <math/quat.h>
|
||||
#include <math/TVecHelpers.h>
|
||||
|
||||
#include <algorithm> // for std::swap
|
||||
#include <cmath> // for std:: namespace
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
namespace details {
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* No user serviceable parts here.
|
||||
*
|
||||
* Don't use this file directly, instead include math/mat*.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Matrix utilities
|
||||
*/
|
||||
|
||||
namespace matrix {
|
||||
|
||||
/*
|
||||
* Matrix inversion
|
||||
*/
|
||||
template<typename MATRIX>
|
||||
constexpr MATRIX MATH_PURE gaussJordanInverse(MATRIX src) {
|
||||
typedef typename MATRIX::value_type T;
|
||||
constexpr unsigned int N = MATRIX::NUM_ROWS;
|
||||
MATRIX inverted;
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
// look for largest element in i'th column
|
||||
size_t swap = i;
|
||||
T t = src[i][i] < 0 ? -src[i][i] : src[i][i];
|
||||
for (size_t j = i + 1; j < N; ++j) {
|
||||
const T t2 = src[j][i] < 0 ? -src[j][i] : src[j][i];
|
||||
if (t2 > t) {
|
||||
swap = j;
|
||||
t = t2;
|
||||
}
|
||||
}
|
||||
|
||||
if (swap != i) {
|
||||
// swap columns.
|
||||
std::swap(src[i], src[swap]);
|
||||
std::swap(inverted[i], inverted[swap]);
|
||||
}
|
||||
|
||||
const T denom(src[i][i]);
|
||||
for (size_t k = 0; k < N; ++k) {
|
||||
src[i][k] /= denom;
|
||||
inverted[i][k] /= denom;
|
||||
}
|
||||
|
||||
// Factor out the lower triangle
|
||||
for (size_t j = 0; j < N; ++j) {
|
||||
if (j != i) {
|
||||
const T t = src[j][i];
|
||||
for (size_t k = 0; k < N; ++k) {
|
||||
src[j][k] -= src[i][k] * t;
|
||||
inverted[j][k] -= inverted[i][k] * t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inverted;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 2x2 matrix inverse is easy.
|
||||
template<typename MATRIX>
|
||||
constexpr MATRIX MATH_PURE fastInverse2(const MATRIX& x) {
|
||||
typedef typename MATRIX::value_type T;
|
||||
|
||||
// Assuming the input matrix is:
|
||||
// | a b |
|
||||
// | c d |
|
||||
//
|
||||
// The analytic inverse is
|
||||
// | d -b |
|
||||
// | -c a | / (a d - b c)
|
||||
//
|
||||
// Importantly, our matrices are column-major!
|
||||
|
||||
MATRIX inverted{};
|
||||
|
||||
const T a = x[0][0];
|
||||
const T c = x[0][1];
|
||||
const T b = x[1][0];
|
||||
const T d = x[1][1];
|
||||
|
||||
const T det((a * d) - (b * c));
|
||||
inverted[0][0] = d / det;
|
||||
inverted[0][1] = -c / det;
|
||||
inverted[1][0] = -b / det;
|
||||
inverted[1][1] = a / det;
|
||||
return inverted;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// From the Wikipedia article on matrix inversion's section on fast 3x3
|
||||
// matrix inversion:
|
||||
// http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices
|
||||
template<typename MATRIX>
|
||||
constexpr MATRIX MATH_PURE fastInverse3(const MATRIX& x) {
|
||||
typedef typename MATRIX::value_type T;
|
||||
|
||||
// Assuming the input matrix is:
|
||||
// | a b c |
|
||||
// | d e f |
|
||||
// | g h i |
|
||||
//
|
||||
// The analytic inverse is
|
||||
// | A B C |^T
|
||||
// | D E F |
|
||||
// | G H I | / determinant
|
||||
//
|
||||
// Which is
|
||||
// | A D G |
|
||||
// | B E H |
|
||||
// | C F I | / determinant
|
||||
//
|
||||
// Where:
|
||||
// A = (ei - fh), B = (fg - di), C = (dh - eg)
|
||||
// D = (ch - bi), E = (ai - cg), F = (bg - ah)
|
||||
// G = (bf - ce), H = (cd - af), I = (ae - bd)
|
||||
//
|
||||
// and the determinant is a*A + b*B + c*C (The rule of Sarrus)
|
||||
//
|
||||
// Importantly, our matrices are column-major!
|
||||
|
||||
MATRIX inverted{};
|
||||
|
||||
const T a = x[0][0];
|
||||
const T b = x[1][0];
|
||||
const T c = x[2][0];
|
||||
const T d = x[0][1];
|
||||
const T e = x[1][1];
|
||||
const T f = x[2][1];
|
||||
const T g = x[0][2];
|
||||
const T h = x[1][2];
|
||||
const T i = x[2][2];
|
||||
|
||||
// Do the full analytic inverse
|
||||
const T A = e * i - f * h;
|
||||
const T B = f * g - d * i;
|
||||
const T C = d * h - e * g;
|
||||
inverted[0][0] = A; // A
|
||||
inverted[0][1] = B; // B
|
||||
inverted[0][2] = C; // C
|
||||
inverted[1][0] = c * h - b * i; // D
|
||||
inverted[1][1] = a * i - c * g; // E
|
||||
inverted[1][2] = b * g - a * h; // F
|
||||
inverted[2][0] = b * f - c * e; // G
|
||||
inverted[2][1] = c * d - a * f; // H
|
||||
inverted[2][2] = a * e - b * d; // I
|
||||
|
||||
const T det(a * A + b * B + c * C);
|
||||
for (size_t col = 0; col < 3; ++col) {
|
||||
for (size_t row = 0; row < 3; ++row) {
|
||||
inverted[col][row] /= det;
|
||||
}
|
||||
}
|
||||
|
||||
return inverted;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Determinant and cofactor
|
||||
|
||||
// this is just a dummy matrix helper
|
||||
template<typename T, size_t ORDER>
|
||||
class Matrix {
|
||||
T m[ORDER][ORDER];
|
||||
public:
|
||||
constexpr auto operator[](size_t i) const noexcept { return m[i]; }
|
||||
|
||||
constexpr auto& operator[](size_t i) noexcept { return m[i]; }
|
||||
|
||||
static constexpr Matrix<T, ORDER - 1> submatrix(Matrix in, size_t row, size_t col) noexcept {
|
||||
size_t colCount = 0, rowCount = 0;
|
||||
Matrix<T, ORDER - 1> dest{};
|
||||
for (size_t i = 0; i < ORDER; i++) {
|
||||
if (i != row) {
|
||||
colCount = 0;
|
||||
for (size_t j = 0; j < ORDER; j++) {
|
||||
if (j != col) {
|
||||
dest[rowCount][colCount] = in[i][j];
|
||||
colCount++;
|
||||
}
|
||||
}
|
||||
rowCount++;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t O>
|
||||
struct Determinant {
|
||||
static constexpr T determinant(Matrix<T, O> in) {
|
||||
T det = {};
|
||||
for (size_t i = 0; i < O; i++) {
|
||||
T m = Determinant<T, O - 1>::determinant(Matrix<T, O>::submatrix(in, 0, i));
|
||||
T factor = (i % 2 == 1) ? T(-1) : T(1);
|
||||
det += factor * in[0][i] * m;
|
||||
}
|
||||
return det;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Determinant<T, 3> {
|
||||
static constexpr T determinant(Matrix<T, 3> in) {
|
||||
return
|
||||
in[0][0] * in[1][1] * in[2][2] +
|
||||
in[1][0] * in[2][1] * in[0][2] +
|
||||
in[2][0] * in[0][1] * in[1][2] -
|
||||
in[2][0] * in[1][1] * in[0][2] -
|
||||
in[1][0] * in[0][1] * in[2][2] -
|
||||
in[0][0] * in[2][1] * in[1][2];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Determinant<T, 2> {
|
||||
static constexpr T determinant(Matrix<T, 2> in) {
|
||||
return in[0][0] * in[1][1] - in[0][1] * in[1][0];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Determinant<T, 1> {
|
||||
static constexpr T determinant(Matrix<T, 1> in) { return in[0][0]; }
|
||||
};
|
||||
|
||||
template<typename MATRIX>
|
||||
constexpr MATRIX MATH_PURE cofactor(const MATRIX& m) {
|
||||
typedef typename MATRIX::value_type T;
|
||||
|
||||
MATRIX out;
|
||||
constexpr size_t order = MATRIX::NUM_COLS;
|
||||
|
||||
Matrix<T, order> in{};
|
||||
for (size_t i = 0; i < order; i++) {
|
||||
for (size_t j = 0; j < order; j++) {
|
||||
in[i][j] = m[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < order; i++) {
|
||||
for (size_t j = 0; j < order; j++) {
|
||||
T factor = ((i + j) % 2 == 1) ? T(-1) : T(1);
|
||||
out[i][j] = Determinant<T, order - 1>::determinant(
|
||||
Matrix<T, order>::submatrix(in, i, j)) * factor;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename MATRIX>
|
||||
constexpr MATRIX MATH_PURE fastCofactor2(const MATRIX& m) {
|
||||
typedef typename MATRIX::value_type T;
|
||||
|
||||
// Assuming the input matrix is:
|
||||
// | a b |
|
||||
// | c d |
|
||||
//
|
||||
// The cofactor are
|
||||
// | d -c |
|
||||
// | -b a |
|
||||
//
|
||||
// Importantly, our matrices are column-major!
|
||||
|
||||
MATRIX cof{};
|
||||
|
||||
const T a = m[0][0];
|
||||
const T c = m[0][1];
|
||||
const T b = m[1][0];
|
||||
const T d = m[1][1];
|
||||
|
||||
cof[0][0] = d;
|
||||
cof[0][1] = -b;
|
||||
cof[1][0] = -c;
|
||||
cof[1][1] = a;
|
||||
return cof;
|
||||
}
|
||||
|
||||
template<typename MATRIX>
|
||||
constexpr MATRIX MATH_PURE fastCofactor3(const MATRIX& m) {
|
||||
typedef typename MATRIX::value_type T;
|
||||
|
||||
// Assuming the input matrix is:
|
||||
// | a b c |
|
||||
// | d e f |
|
||||
// | g h i |
|
||||
//
|
||||
// The cofactor are
|
||||
// | A B C |
|
||||
// | D E F |
|
||||
// | G H I |
|
||||
|
||||
// Where:
|
||||
// A = (ei - fh), B = (fg - di), C = (dh - eg)
|
||||
// D = (ch - bi), E = (ai - cg), F = (bg - ah)
|
||||
// G = (bf - ce), H = (cd - af), I = (ae - bd)
|
||||
|
||||
// Importantly, our matrices are column-major!
|
||||
|
||||
MATRIX cof{};
|
||||
|
||||
const T a = m[0][0];
|
||||
const T b = m[1][0];
|
||||
const T c = m[2][0];
|
||||
const T d = m[0][1];
|
||||
const T e = m[1][1];
|
||||
const T f = m[2][1];
|
||||
const T g = m[0][2];
|
||||
const T h = m[1][2];
|
||||
const T i = m[2][2];
|
||||
|
||||
cof[0][0] = e * i - f * h; // A
|
||||
cof[0][1] = c * h - b * i; // D
|
||||
cof[0][2] = b * f - c * e; // G
|
||||
cof[1][0] = f * g - d * i; // B
|
||||
cof[1][1] = a * i - c * g; // E
|
||||
cof[1][2] = c * d - a * f; // H
|
||||
cof[2][0] = d * h - e * g; // C
|
||||
cof[2][1] = b * g - a * h; // F
|
||||
cof[2][2] = a * e - b * d; // I
|
||||
|
||||
return cof;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cofactor function which switches on the matrix size.
|
||||
*/
|
||||
template<typename MATRIX,
|
||||
typename = std::enable_if_t<MATRIX::NUM_ROWS == MATRIX::NUM_COLS, int>>
|
||||
inline constexpr MATRIX MATH_PURE cof(const MATRIX& matrix) {
|
||||
return (MATRIX::NUM_ROWS == 2) ? fastCofactor2<MATRIX>(matrix) :
|
||||
((MATRIX::NUM_ROWS == 3) ? fastCofactor3<MATRIX>(matrix) :
|
||||
cofactor<MATRIX>(matrix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determinant of a matrix
|
||||
*/
|
||||
template<typename MATRIX,
|
||||
typename = std::enable_if_t<MATRIX::NUM_ROWS == MATRIX::NUM_COLS, int>>
|
||||
inline constexpr typename MATRIX::value_type MATH_PURE det(const MATRIX& matrix) {
|
||||
typedef typename MATRIX::value_type T;
|
||||
constexpr unsigned int N = MATRIX::NUM_ROWS;
|
||||
Matrix<T, N> in{};
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
for (size_t j = 0; j < N; j++) {
|
||||
in[i][j] = matrix[i][j];
|
||||
}
|
||||
}
|
||||
return Determinant<typename MATRIX::value_type, MATRIX::NUM_COLS>::determinant(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inversion function which switches on the matrix size.
|
||||
* @warning This function assumes the matrix is invertible. The result is
|
||||
* undefined if it is not. It is the responsibility of the caller to
|
||||
* make sure the matrix is not singular.
|
||||
*/
|
||||
template<typename MATRIX,
|
||||
typename = std::enable_if_t<MATRIX::NUM_ROWS == MATRIX::NUM_COLS, int>>
|
||||
inline constexpr MATRIX MATH_PURE inverse(const MATRIX& matrix) {
|
||||
return (MATRIX::NUM_ROWS == 2) ? fastInverse2<MATRIX>(matrix) :
|
||||
((MATRIX::NUM_ROWS == 3) ? fastInverse3<MATRIX>(matrix) :
|
||||
gaussJordanInverse<MATRIX>(matrix));
|
||||
}
|
||||
|
||||
template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B,
|
||||
typename = std::enable_if_t<
|
||||
MATRIX_A::NUM_COLS == MATRIX_B::NUM_ROWS &&
|
||||
MATRIX_R::NUM_COLS == MATRIX_B::NUM_COLS &&
|
||||
MATRIX_R::NUM_ROWS == MATRIX_A::NUM_ROWS, int>>
|
||||
constexpr MATRIX_R MATH_PURE multiply(MATRIX_A lhs, MATRIX_B rhs) {
|
||||
// pre-requisite:
|
||||
// lhs : D columns, R rows
|
||||
// rhs : C columns, D rows
|
||||
// res : C columns, R rows
|
||||
MATRIX_R res{};
|
||||
for (size_t col = 0; col < MATRIX_R::NUM_COLS; ++col) {
|
||||
res[col] = lhs * rhs[col];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename MATRIX,
|
||||
typename = std::enable_if_t<MATRIX::NUM_ROWS == MATRIX::NUM_COLS, int>>
|
||||
inline constexpr MATRIX MATH_PURE transpose(MATRIX m) {
|
||||
// for now we only handle square matrix transpose
|
||||
MATRIX result{};
|
||||
for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
|
||||
for (size_t row = 0; row < MATRIX::NUM_ROWS; ++row) {
|
||||
result[col][row] = m[row][col];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename MATRIX,
|
||||
typename = std::enable_if_t<MATRIX::NUM_ROWS == MATRIX::NUM_COLS, int>>
|
||||
inline constexpr typename MATRIX::value_type MATH_PURE trace(MATRIX m) {
|
||||
typename MATRIX::value_type result{};
|
||||
for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
|
||||
result += m[col][col];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename MATRIX,
|
||||
typename = std::enable_if_t<MATRIX::NUM_ROWS == MATRIX::NUM_COLS, int>>
|
||||
inline constexpr typename MATRIX::col_type MATH_PURE diag(MATRIX m) {
|
||||
typename MATRIX::col_type result{};
|
||||
for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
|
||||
result[col] = m[col][col];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// This is taken from the Imath MatrixAlgo code, and is identical to Eigen.
|
||||
template<typename MATRIX>
|
||||
TQuaternion<typename MATRIX::value_type> extractQuat(const MATRIX& mat) {
|
||||
typedef typename MATRIX::value_type T;
|
||||
|
||||
TQuaternion<T> quat(TQuaternion<T>::NO_INIT);
|
||||
|
||||
// Compute the trace to see if it is positive or not.
|
||||
const T trace = mat[0][0] + mat[1][1] + mat[2][2];
|
||||
|
||||
// check the sign of the trace
|
||||
if (MATH_LIKELY(trace > 0)) {
|
||||
// trace is positive
|
||||
T s = std::sqrt(trace + 1);
|
||||
quat.w = T(0.5) * s;
|
||||
s = T(0.5) / s;
|
||||
quat.x = (mat[1][2] - mat[2][1]) * s;
|
||||
quat.y = (mat[2][0] - mat[0][2]) * s;
|
||||
quat.z = (mat[0][1] - mat[1][0]) * s;
|
||||
} else {
|
||||
// trace is negative
|
||||
|
||||
// Find the index of the greatest diagonal
|
||||
size_t i = 0;
|
||||
if (mat[1][1] > mat[0][0]) { i = 1; }
|
||||
if (mat[2][2] > mat[i][i]) { i = 2; }
|
||||
|
||||
// Get the next indices: (n+1)%3
|
||||
static constexpr size_t next_ijk[3] = { 1, 2, 0 };
|
||||
size_t j = next_ijk[i];
|
||||
size_t k = next_ijk[j];
|
||||
T s = std::sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1);
|
||||
quat[i] = T(0.5) * s;
|
||||
if (s != 0) {
|
||||
s = T(0.5) / s;
|
||||
}
|
||||
quat.w = (mat[j][k] - mat[k][j]) * s;
|
||||
quat[j] = (mat[i][j] + mat[j][i]) * s;
|
||||
quat[k] = (mat[i][k] + mat[k][i]) * s;
|
||||
}
|
||||
return quat;
|
||||
}
|
||||
|
||||
} // namespace matrix
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* TMatProductOperators implements basic arithmetic and basic compound assignments
|
||||
* operators on a vector of type BASE<T>.
|
||||
*
|
||||
* BASE only needs to implement operator[] and size().
|
||||
* By simply inheriting from TMatProductOperators<BASE, T> BASE will automatically
|
||||
* get all the functionality here.
|
||||
*/
|
||||
|
||||
template<template<typename> class BASE, typename T,
|
||||
template<typename> class VEC>
|
||||
class TMatProductOperators {
|
||||
public:
|
||||
// matrix *= matrix
|
||||
template<typename U>
|
||||
constexpr BASE<T>& operator*=(const BASE<U>& rhs) {
|
||||
BASE<T>& lhs(static_cast< BASE<T>& >(*this));
|
||||
lhs = matrix::multiply<BASE<T>>(lhs, rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// matrix *= scalar
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
constexpr BASE<T>& operator*=(U v) {
|
||||
BASE<T>& lhs(static_cast< BASE<T>& >(*this));
|
||||
for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
|
||||
lhs[col] *= v;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// matrix /= scalar
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
constexpr BASE<T>& operator/=(U v) {
|
||||
BASE<T>& lhs(static_cast< BASE<T>& >(*this));
|
||||
for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
|
||||
lhs[col] /= v;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* NOTE: the functions below ARE NOT member methods. They are friend functions
|
||||
* with they definition inlined with their declaration. This makes these
|
||||
* template functions available to the compiler when (and only when) this class
|
||||
* is instantiated, at which point they're only templated on the 2nd parameter
|
||||
* (the first one, BASE<T> being known).
|
||||
*/
|
||||
|
||||
// matrix * matrix
|
||||
template<typename U>
|
||||
friend inline constexpr BASE<arithmetic_result_t<T, U>> MATH_PURE
|
||||
operator*(BASE<T> lhs, BASE<U> rhs) {
|
||||
return matrix::multiply<BASE<arithmetic_result_t<T, U>>>(lhs, rhs);
|
||||
}
|
||||
|
||||
// matrix * vector
|
||||
template<typename U>
|
||||
friend inline constexpr typename BASE<arithmetic_result_t<T, U>>::col_type MATH_PURE
|
||||
operator*(const BASE<T>& lhs, const VEC<U>& rhs) {
|
||||
typename BASE<arithmetic_result_t<T, U>>::col_type result{};
|
||||
for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
|
||||
result += lhs[col] * rhs[col];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// row-vector * matrix
|
||||
template<typename U>
|
||||
friend inline constexpr typename BASE<arithmetic_result_t<T, U>>::row_type MATH_PURE
|
||||
operator*(const VEC<U>& lhs, const BASE<T>& rhs) {
|
||||
typename BASE<arithmetic_result_t<T, U>>::row_type result{};
|
||||
for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
|
||||
result[col] = dot(lhs, rhs[col]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// matrix * scalar
|
||||
template<typename U, typename = enable_if_arithmetic_t <U>>
|
||||
friend inline constexpr BASE<arithmetic_result_t < T, U>> MATH_PURE
|
||||
operator*(const BASE<T>& lhs, U rhs) {
|
||||
BASE<arithmetic_result_t<T, U>> result{};
|
||||
for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
|
||||
result[col] = lhs[col] * rhs;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// scalar * matrix
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr BASE<arithmetic_result_t<T, U>> MATH_PURE
|
||||
operator*(U rhs, const BASE<T>& lhs) {
|
||||
return lhs * rhs;
|
||||
}
|
||||
|
||||
// matrix / scalar
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr BASE<arithmetic_result_t<T, U>> MATH_PURE
|
||||
operator/(const BASE<T>& lhs, U rhs) {
|
||||
BASE<arithmetic_result_t<T, U>> result{};
|
||||
for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
|
||||
result[col] = lhs[col] / rhs;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* TMatSquareFunctions implements functions on a matrix of type BASE<T>.
|
||||
*
|
||||
* BASE only needs to implement:
|
||||
* - operator[]
|
||||
* - col_type
|
||||
* - row_type
|
||||
* - COL_SIZE
|
||||
* - ROW_SIZE
|
||||
*
|
||||
* By simply inheriting from TMatSquareFunctions<BASE, T> BASE will automatically
|
||||
* get all the functionality here.
|
||||
*/
|
||||
|
||||
template<template<typename U> class BASE, typename T>
|
||||
class TMatSquareFunctions {
|
||||
private:
|
||||
/*
|
||||
* NOTE: the functions below ARE NOT member methods. They are friend functions
|
||||
* with they definition inlined with their declaration. This makes these
|
||||
* template functions available to the compiler when (and only when) this class
|
||||
* is instantiated, at which point they're only templated on the 2nd parameter
|
||||
* (the first one, BASE<T> being known).
|
||||
*/
|
||||
friend inline constexpr BASE<T> MATH_PURE inverse(const BASE<T>& matrix) {
|
||||
return matrix::inverse(matrix);
|
||||
}
|
||||
|
||||
friend inline constexpr BASE<T> MATH_PURE cof(const BASE<T>& matrix) {
|
||||
return matrix::cof(matrix);
|
||||
}
|
||||
|
||||
friend inline constexpr BASE<T> MATH_PURE transpose(BASE<T> m) {
|
||||
return matrix::transpose(m);
|
||||
}
|
||||
|
||||
friend inline constexpr T MATH_PURE trace(BASE<T> m) {
|
||||
return matrix::trace(m);
|
||||
}
|
||||
|
||||
friend inline constexpr T MATH_PURE det(const BASE<T>& m) {
|
||||
return matrix::det(m);
|
||||
}
|
||||
|
||||
// unclear why we have to use 'auto' here. 'typename BASE<T>::col_type' produces
|
||||
// error: no type named 'col_type' in 'filament::math::details::TMat44<float>'
|
||||
friend inline constexpr auto MATH_PURE diag(const BASE<T>& m) {
|
||||
return matrix::diag(m);
|
||||
}
|
||||
};
|
||||
|
||||
template<template<typename U> class BASE, typename T>
|
||||
class TMatHelpers {
|
||||
public:
|
||||
constexpr inline size_t getColumnSize() const { return BASE<T>::COL_SIZE; }
|
||||
constexpr inline size_t getRowSize() const { return BASE<T>::ROW_SIZE; }
|
||||
constexpr inline size_t getColumnCount() const { return BASE<T>::NUM_COLS; }
|
||||
constexpr inline size_t getRowCount() const { return BASE<T>::NUM_ROWS; }
|
||||
constexpr inline size_t size() const { return BASE<T>::ROW_SIZE; } // for TVec*<>
|
||||
|
||||
// array access
|
||||
constexpr T const* asArray() const {
|
||||
return &static_cast<BASE<T> const &>(*this)[0][0];
|
||||
}
|
||||
|
||||
// element access
|
||||
inline constexpr T const& operator()(size_t row, size_t col) const {
|
||||
return static_cast<BASE<T> const &>(*this)[col][row];
|
||||
}
|
||||
|
||||
inline T& operator()(size_t row, size_t col) {
|
||||
return static_cast<BASE<T>&>(*this)[col][row];
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr friend inline BASE<T> MATH_PURE abs(BASE<T> m) {
|
||||
for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
|
||||
m[col] = abs(m[col]);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
};
|
||||
|
||||
// functions for 3x3 and 4x4 matrices
|
||||
template<template<typename U> class BASE, typename T>
|
||||
class TMatTransform {
|
||||
public:
|
||||
inline constexpr TMatTransform() {
|
||||
static_assert(BASE<T>::NUM_ROWS == 3 || BASE<T>::NUM_ROWS == 4, "3x3 or 4x4 matrices only");
|
||||
}
|
||||
|
||||
template<typename A, typename VEC, typename = enable_if_arithmetic_t<A>>
|
||||
static BASE<T> rotation(A radian, VEC about) {
|
||||
BASE<T> r;
|
||||
T c = std::cos(radian);
|
||||
T s = std::sin(radian);
|
||||
if (about[0] == 1 && about[1] == 0 && about[2] == 0) {
|
||||
r[1][1] = c; r[2][2] = c;
|
||||
r[1][2] = s; r[2][1] = -s;
|
||||
} else if (about[0] == 0 && about[1] == 1 && about[2] == 0) {
|
||||
r[0][0] = c; r[2][2] = c;
|
||||
r[2][0] = s; r[0][2] = -s;
|
||||
} else if (about[0] == 0 && about[1] == 0 && about[2] == 1) {
|
||||
r[0][0] = c; r[1][1] = c;
|
||||
r[0][1] = s; r[1][0] = -s;
|
||||
} else {
|
||||
VEC nabout = normalize(about);
|
||||
typename VEC::value_type x = nabout[0];
|
||||
typename VEC::value_type y = nabout[1];
|
||||
typename VEC::value_type z = nabout[2];
|
||||
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][0] = x*x*nc + c; r[1][0] = xy*nc - zs; r[2][0] = zx*nc + ys;
|
||||
r[0][1] = xy*nc + zs; r[1][1] = y*y*nc + c; r[2][1] = yz*nc - xs;
|
||||
r[0][2] = zx*nc - ys; r[1][2] = yz*nc + xs; r[2][2] = z*z*nc + c;
|
||||
|
||||
// Clamp results to -1, 1.
|
||||
for (size_t col = 0; col < 3; ++col) {
|
||||
for (size_t row = 0; row < 3; ++row) {
|
||||
r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a matrix from euler angles using YPR around YXZ respectively
|
||||
* @param yaw about Y axis
|
||||
* @param pitch about X axis
|
||||
* @param roll about Z axis
|
||||
*/
|
||||
template<typename Y, typename P, typename R, typename = enable_if_arithmetic_t<Y, P, R>>
|
||||
static BASE<T> eulerYXZ(Y yaw, P pitch, R roll) {
|
||||
return eulerZYX(roll, pitch, yaw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a matrix from euler angles using YPR around ZYX respectively
|
||||
* @param roll about X axis
|
||||
* @param pitch about Y axis
|
||||
* @param yaw about Z axis
|
||||
*
|
||||
* The euler angles are applied in ZYX order. i.e: a vector is first rotated
|
||||
* about X (roll) then Y (pitch) and then Z (yaw).
|
||||
*/
|
||||
template<typename Y, typename P, typename R, typename = enable_if_arithmetic_t<Y, P, R>>
|
||||
static BASE<T> eulerZYX(Y yaw, P pitch, R roll) {
|
||||
BASE<T> r;
|
||||
T cy = std::cos(yaw);
|
||||
T sy = std::sin(yaw);
|
||||
T cp = std::cos(pitch);
|
||||
T sp = std::sin(pitch);
|
||||
T cr = std::cos(roll);
|
||||
T sr = std::sin(roll);
|
||||
T cc = cr * cy;
|
||||
T cs = cr * sy;
|
||||
T sc = sr * cy;
|
||||
T ss = sr * sy;
|
||||
r[0][0] = cp * cy;
|
||||
r[0][1] = cp * sy;
|
||||
r[0][2] = -sp;
|
||||
r[1][0] = sp * sc - cs;
|
||||
r[1][1] = sp * ss + cc;
|
||||
r[1][2] = cp * sr;
|
||||
r[2][0] = sp * cc + ss;
|
||||
r[2][1] = sp * cs - sc;
|
||||
r[2][2] = cp * cr;
|
||||
|
||||
// Clamp results to -1, 1.
|
||||
for (size_t col = 0; col < 3; ++col) {
|
||||
for (size_t row = 0; row < 3; ++row) {
|
||||
r[col][row] = std::min(std::max(r[col][row], T(-1)), T(1));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
TQuaternion <T> toQuaternion() const {
|
||||
return matrix::extractQuat(static_cast<const BASE<T>&>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
} // namespace details
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // MATH_TMATHELPERS_H_
|
||||
292
ios/include/math/TQuatHelpers.h
Normal file
292
ios/include/math/TQuatHelpers.h
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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 MATH_TQUATHELPERS_H_
|
||||
#define MATH_TQUATHELPERS_H_
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <math/compiler.h>
|
||||
#include <math/scalar.h>
|
||||
#include <math/vec3.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
namespace details {
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* No user serviceable parts here.
|
||||
*
|
||||
* Don't use this file directly, instead include math/quat.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* TQuatProductOperators implements basic arithmetic and basic compound assignment
|
||||
* operators on a quaternion of type BASE<T>.
|
||||
*
|
||||
* BASE only needs to implement operator[] and size().
|
||||
* By simply inheriting from TQuatProductOperators<BASE, T> BASE will automatically
|
||||
* get all the functionality here.
|
||||
*/
|
||||
|
||||
template<template<typename T> class QUATERNION, typename T>
|
||||
class TQuatProductOperators {
|
||||
public:
|
||||
/* compound assignment from a another quaternion of the same size but different
|
||||
* element type.
|
||||
*/
|
||||
template<typename OTHER>
|
||||
constexpr QUATERNION<T>& operator*=(const QUATERNION<OTHER>& r) {
|
||||
QUATERNION<T>& q = static_cast<QUATERNION<T>&>(*this);
|
||||
q = q * r;
|
||||
return q;
|
||||
}
|
||||
|
||||
/* compound assignment products by a scalar
|
||||
*/
|
||||
constexpr QUATERNION<T>& operator*=(T v) {
|
||||
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
|
||||
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
|
||||
lhs[i] *= v;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
constexpr QUATERNION<T>& operator/=(T v) {
|
||||
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
|
||||
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
|
||||
lhs[i] /= v;
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: the functions below ARE NOT member methods. They are friend functions
|
||||
* with they definition inlined with their declaration. This makes these
|
||||
* template functions available to the compiler when (and only when) this class
|
||||
* is instantiated, at which point they're only templated on the 2nd parameter
|
||||
* (the first one, BASE<T> being known).
|
||||
*/
|
||||
|
||||
/* The operators below handle operation between quaternion of the same size
|
||||
* but of a different element type.
|
||||
*/
|
||||
template<typename RT>
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE operator*(const QUATERNION<T>& q, const QUATERNION<RT>& r) {
|
||||
// could be written as:
|
||||
// return QUATERNION<T>(
|
||||
// q.w*r.w - dot(q.xyz, r.xyz),
|
||||
// q.w*r.xyz + r.w*q.xyz + cross(q.xyz, r.xyz));
|
||||
|
||||
return QUATERNION<T>(
|
||||
q.w * r.w - q.x * r.x - q.y * r.y - q.z * r.z,
|
||||
q.w * r.x + q.x * r.w + q.y * r.z - q.z * r.y,
|
||||
q.w * r.y - q.x * r.z + q.y * r.w + q.z * r.x,
|
||||
q.w * r.z + q.x * r.y - q.y * r.x + q.z * r.w);
|
||||
}
|
||||
|
||||
template<typename RT>
|
||||
friend inline
|
||||
constexpr TVec3<T> MATH_PURE operator*(const QUATERNION<T>& q, const TVec3<RT>& v) {
|
||||
// note: if q is known to be a unit quaternion, then this simplifies to:
|
||||
// TVec3<T> t = 2 * cross(q.xyz, v)
|
||||
// return v + (q.w * t) + cross(q.xyz, t)
|
||||
return imaginary(q * QUATERNION<T>(v, 0) * inverse(q));
|
||||
}
|
||||
|
||||
|
||||
/* For quaternions, we use explicit "by a scalar" products because it's much faster
|
||||
* than going (implicitly) through the quaternion multiplication.
|
||||
* For reference: we could use the code below instead, but it would be a lot slower.
|
||||
* friend inline
|
||||
* constexpr BASE<T> MATH_PURE operator *(const BASE<T>& q, const BASE<T>& r) {
|
||||
* return BASE<T>(
|
||||
* q.w*r.w - q.x*r.x - q.y*r.y - q.z*r.z,
|
||||
* q.w*r.x + q.x*r.w + q.y*r.z - q.z*r.y,
|
||||
* q.w*r.y - q.x*r.z + q.y*r.w + q.z*r.x,
|
||||
* q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w);
|
||||
*
|
||||
*/
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE operator*(QUATERNION<T> q, T scalar) {
|
||||
// don't pass q by reference because we need a copy anyways
|
||||
return q *= scalar;
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE operator*(T scalar, QUATERNION<T> q) {
|
||||
// don't pass q by reference because we need a copy anyways
|
||||
return q *= scalar;
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE operator/(QUATERNION<T> q, T scalar) {
|
||||
// don't pass q by reference because we need a copy anyways
|
||||
return q /= scalar;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* TQuatFunctions implements functions on a quaternion of type BASE<T>.
|
||||
*
|
||||
* BASE only needs to implement operator[] and size().
|
||||
* By simply inheriting from TQuatFunctions<BASE, T> BASE will automatically
|
||||
* get all the functionality here.
|
||||
*/
|
||||
template<template<typename T> class QUATERNION, typename T>
|
||||
class TQuatFunctions {
|
||||
public:
|
||||
/*
|
||||
* NOTE: the functions below ARE NOT member methods. They are friend functions
|
||||
* with they definition inlined with their declaration. This makes these
|
||||
* template functions available to the compiler when (and only when) this class
|
||||
* is instantiated, at which point they're only templated on the 2nd parameter
|
||||
* (the first one, BASE<T> being known).
|
||||
*/
|
||||
|
||||
template<typename RT>
|
||||
friend inline
|
||||
constexpr T MATH_PURE dot(const QUATERNION<T>& p, const QUATERNION<RT>& q) {
|
||||
return p.x * q.x +
|
||||
p.y * q.y +
|
||||
p.z * q.z +
|
||||
p.w * q.w;
|
||||
}
|
||||
|
||||
friend inline
|
||||
T MATH_PURE norm(const QUATERNION<T>& q) {
|
||||
return std::sqrt(dot(q, q));
|
||||
}
|
||||
|
||||
friend inline
|
||||
T MATH_PURE length(const QUATERNION<T>& q) {
|
||||
return norm(q);
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr T MATH_PURE length2(const QUATERNION<T>& q) {
|
||||
return dot(q, q);
|
||||
}
|
||||
|
||||
friend inline
|
||||
QUATERNION<T> MATH_PURE normalize(const QUATERNION<T>& q) {
|
||||
return length(q) ? q / length(q) : QUATERNION<T>(static_cast<T>(1));
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE conj(const QUATERNION<T>& q) {
|
||||
return QUATERNION<T>(q.w, -q.x, -q.y, -q.z);
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE inverse(const QUATERNION<T>& q) {
|
||||
return conj(q) * (1 / dot(q, q));
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr T MATH_PURE real(const QUATERNION<T>& q) {
|
||||
return q.w;
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr TVec3<T> MATH_PURE imaginary(const QUATERNION<T>& q) {
|
||||
return q.xyz;
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE unreal(const QUATERNION<T>& q) {
|
||||
return QUATERNION<T>(q.xyz, 0);
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE cross(const QUATERNION<T>& p, const QUATERNION<T>& q) {
|
||||
return unreal(p * q);
|
||||
}
|
||||
|
||||
friend inline
|
||||
QUATERNION<T> MATH_PURE exp(const QUATERNION<T>& q) {
|
||||
const T nq(norm(q.xyz));
|
||||
return std::exp(q.w) * QUATERNION<T>((sin(nq) / nq) * q.xyz, cos(nq));
|
||||
}
|
||||
|
||||
friend inline
|
||||
QUATERNION<T> MATH_PURE log(const QUATERNION<T>& q) {
|
||||
const T nq(norm(q));
|
||||
return QUATERNION<T>((std::acos(q.w / nq) / norm(q.xyz)) * q.xyz, std::log(nq));
|
||||
}
|
||||
|
||||
friend inline
|
||||
QUATERNION<T> MATH_PURE pow(const QUATERNION<T>& q, T a) {
|
||||
// could also be computed as: exp(a*log(q));
|
||||
const T nq(norm(q));
|
||||
const T theta(a * std::acos(q.w / nq));
|
||||
return std::pow(nq, a) * QUATERNION<T>(normalize(q.xyz) * std::sin(theta), std::cos(theta));
|
||||
}
|
||||
|
||||
friend inline
|
||||
QUATERNION<T> MATH_PURE slerp(const QUATERNION<T>& p, const QUATERNION<T>& q, T t) {
|
||||
// could also be computed as: pow(q * inverse(p), t) * p;
|
||||
const T d = dot(p, q);
|
||||
const T absd = std::abs(d);
|
||||
static constexpr T value_eps = T(10) * std::numeric_limits<T>::epsilon();
|
||||
// Prevent blowing up when slerping between two quaternions that are very near each other.
|
||||
if ((T(1) - absd) < value_eps) {
|
||||
return normalize(lerp(d < 0 ? -p : p, q, t));
|
||||
}
|
||||
const T npq = std::sqrt(dot(p, p) * dot(q, q)); // ||p|| * ||q||
|
||||
const T a = std::acos(filament::math::clamp(absd / npq, T(-1), T(1)));
|
||||
const T a0 = a * (1 - t);
|
||||
const T a1 = a * t;
|
||||
const T sina = sin(a);
|
||||
if (sina < value_eps) {
|
||||
return normalize(lerp(p, q, t));
|
||||
}
|
||||
const T isina = 1 / sina;
|
||||
const T s0 = std::sin(a0) * isina;
|
||||
const T s1 = std::sin(a1) * isina;
|
||||
// ensure we're taking the "short" side
|
||||
return normalize(s0 * p + ((d < 0) ? (-s1) : (s1)) * q);
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE lerp(const QUATERNION<T>& p, const QUATERNION<T>& q, T t) {
|
||||
return ((1 - t) * p) + (t * q);
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE nlerp(const QUATERNION<T>& p, const QUATERNION<T>& q, T t) {
|
||||
return normalize(lerp(p, q, t));
|
||||
}
|
||||
|
||||
friend inline
|
||||
constexpr QUATERNION<T> MATH_PURE positive(const QUATERNION<T>& q) {
|
||||
return q.w < 0 ? -q : q;
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
} // namespace details
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // MATH_TQUATHELPERS_H_
|
||||
625
ios/include/math/TVecHelpers.h
Normal file
625
ios/include/math/TVecHelpers.h
Normal file
@@ -0,0 +1,625 @@
|
||||
/*
|
||||
* 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 MATH_TVECHELPERS_H_
|
||||
#define MATH_TVECHELPERS_H_
|
||||
|
||||
#include <math/compiler.h>
|
||||
|
||||
#include <cmath> // for std:: namespace
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
namespace details {
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
template<typename U>
|
||||
inline constexpr U min(U a, U b) noexcept {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
inline constexpr U max(U a, U b) noexcept {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
struct arithmetic_result {
|
||||
using type = decltype(std::declval<T>() + std::declval<U>());
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
using arithmetic_result_t = typename arithmetic_result<T, U>::type;
|
||||
|
||||
template<typename A, typename B = int, typename C = int, typename D = int>
|
||||
using enable_if_arithmetic_t = std::enable_if_t<
|
||||
is_arithmetic<A>::value &&
|
||||
is_arithmetic<B>::value &&
|
||||
is_arithmetic<C>::value &&
|
||||
is_arithmetic<D>::value>;
|
||||
|
||||
/*
|
||||
* No user serviceable parts here.
|
||||
*
|
||||
* Don't use this file directly, instead include math/vec{2|3|4}.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments
|
||||
* operators on a vector of type BASE<T>.
|
||||
*
|
||||
* BASE only needs to implement operator[] and size().
|
||||
* By simply inheriting from TVec{Add|Product}Operators<BASE, T> BASE will automatically
|
||||
* get all the functionality here.
|
||||
*/
|
||||
|
||||
template<template<typename T> class VECTOR, typename T>
|
||||
class TVecAddOperators {
|
||||
public:
|
||||
/* compound assignment from a another vector of the same size but different
|
||||
* element type.
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr VECTOR<T>& operator+=(const VECTOR<U>& v) {
|
||||
VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
|
||||
for (size_t i = 0; i < lhs.size(); i++) {
|
||||
lhs[i] += v[i];
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
constexpr VECTOR<T>& operator+=(U v) {
|
||||
return operator+=(VECTOR<U>(v));
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
constexpr VECTOR<T>& operator-=(const VECTOR<U>& v) {
|
||||
VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
|
||||
for (size_t i = 0; i < lhs.size(); i++) {
|
||||
lhs[i] -= v[i];
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
constexpr VECTOR<T>& operator-=(U v) {
|
||||
return operator-=(VECTOR<U>(v));
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* NOTE: the functions below ARE NOT member methods. They are friend functions
|
||||
* with they definition inlined with their declaration. This makes these
|
||||
* template functions available to the compiler when (and only when) this class
|
||||
* is instantiated, at which point they're only templated on the 2nd parameter
|
||||
* (the first one, BASE<T> being known).
|
||||
*/
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<arithmetic_result_t<T, U>> res(lv);
|
||||
res += rv;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(const VECTOR<T>& lv, U rv) {
|
||||
return lv + VECTOR<U>(rv);
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator+(U lv, const VECTOR<T>& rv) {
|
||||
return VECTOR<U>(lv) + rv;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<arithmetic_result_t<T, U>> res(lv);
|
||||
res -= rv;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(const VECTOR<T>& lv, U rv) {
|
||||
return lv - VECTOR<U>(rv);
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator-(U lv, const VECTOR<T>& rv) {
|
||||
return VECTOR<U>(lv) - rv;
|
||||
}
|
||||
};
|
||||
|
||||
template<template<typename T> class VECTOR, typename T>
|
||||
class TVecProductOperators {
|
||||
public:
|
||||
/* compound assignment from a another vector of the same size but different
|
||||
* element type.
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr VECTOR<T>& operator*=(const VECTOR<U>& v) {
|
||||
VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
|
||||
for (size_t i = 0; i < lhs.size(); i++) {
|
||||
lhs[i] *= v[i];
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
constexpr VECTOR<T>& operator*=(U v) {
|
||||
return operator*=(VECTOR<U>(v));
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
constexpr VECTOR<T>& operator/=(const VECTOR<U>& v) {
|
||||
VECTOR<T>& lhs = static_cast<VECTOR<T>&>(*this);
|
||||
for (size_t i = 0; i < lhs.size(); i++) {
|
||||
lhs[i] /= v[i];
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
constexpr VECTOR<T>& operator/=(U v) {
|
||||
return operator/=(VECTOR<U>(v));
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* NOTE: the functions below ARE NOT member methods. They are friend functions
|
||||
* with they definition inlined with their declaration. This makes these
|
||||
* template functions available to the compiler when (and only when) this class
|
||||
* is instantiated, at which point they're only templated on the 2nd parameter
|
||||
* (the first one, BASE<T> being known).
|
||||
*/
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<arithmetic_result_t<T, U>> res(lv);
|
||||
res *= rv;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(const VECTOR<T>& lv, U rv) {
|
||||
return lv * VECTOR<U>(rv);
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator*(U lv, const VECTOR<T>& rv) {
|
||||
return VECTOR<U>(lv) * rv;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<arithmetic_result_t<T, U>> res(lv);
|
||||
res /= rv;
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(const VECTOR<T>& lv, U rv) {
|
||||
return lv / VECTOR<U>(rv);
|
||||
}
|
||||
|
||||
template<typename U, typename = enable_if_arithmetic_t<U>>
|
||||
friend inline constexpr
|
||||
VECTOR<arithmetic_result_t<T, U>> MATH_PURE operator/(U lv, const VECTOR<T>& rv) {
|
||||
return VECTOR<U>(lv) / rv;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* TVecUnaryOperators implements unary operators on a vector of type BASE<T>.
|
||||
*
|
||||
* BASE only needs to implement operator[] and size().
|
||||
* By simply inheriting from TVecUnaryOperators<BASE, T> BASE will automatically
|
||||
* get all the functionality here.
|
||||
*
|
||||
* These operators are implemented as friend functions of TVecUnaryOperators<BASE, T>
|
||||
*/
|
||||
template<template<typename T> class VECTOR, typename T>
|
||||
class TVecUnaryOperators {
|
||||
public:
|
||||
constexpr VECTOR<T> operator-() const {
|
||||
VECTOR<T> r{};
|
||||
VECTOR<T> const& rv(static_cast<VECTOR<T> const&>(*this));
|
||||
for (size_t i = 0; i < r.size(); i++) {
|
||||
r[i] = -rv[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* TVecComparisonOperators implements relational/comparison operators
|
||||
* on a vector of type BASE<T>.
|
||||
*
|
||||
* BASE only needs to implement operator[] and size().
|
||||
* By simply inheriting from TVecComparisonOperators<BASE, T> BASE will automatically
|
||||
* get all the functionality here.
|
||||
*/
|
||||
template<template<typename T> class VECTOR, typename T>
|
||||
class TVecComparisonOperators {
|
||||
private:
|
||||
/*
|
||||
* NOTE: the functions below ARE NOT member methods. They are friend functions
|
||||
* with they definition inlined with their declaration. This makes these
|
||||
* template functions available to the compiler when (and only when) this class
|
||||
* is instantiated, at which point they're only templated on the 2nd parameter
|
||||
* (the first one, BASE<T> being known).
|
||||
*/
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
bool MATH_PURE operator==(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
// w/ inlining we end-up with many branches that will pollute the BPU cache
|
||||
MATH_NOUNROLL
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
if (lv[i] != rv[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
bool MATH_PURE operator!=(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
return !operator==(lv, rv);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<bool> MATH_PURE equal(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<bool> r{};
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
r[i] = lv[i] == rv[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<bool> MATH_PURE notEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<bool> r{};
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
r[i] = lv[i] != rv[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<bool> MATH_PURE lessThan(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<bool> r{};
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
r[i] = lv[i] < rv[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<bool> MATH_PURE lessThanEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<bool> r{};
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
r[i] = lv[i] <= rv[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
VECTOR<bool> MATH_PURE greaterThan(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<bool> r;
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
r[i] = lv[i] > rv[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline
|
||||
VECTOR<bool> MATH_PURE greaterThanEqual(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
VECTOR<bool> r{};
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
r[i] = lv[i] >= rv[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* TVecFunctions implements functions on a vector of type BASE<T>.
|
||||
*
|
||||
* BASE only needs to implement operator[] and size().
|
||||
* By simply inheriting from TVecFunctions<BASE, T> BASE will automatically
|
||||
* get all the functionality here.
|
||||
*/
|
||||
template<template<typename T> class VECTOR, typename T>
|
||||
class TVecFunctions {
|
||||
private:
|
||||
/*
|
||||
* NOTE: the functions below ARE NOT member methods. They are friend functions
|
||||
* with they definition inlined with their declaration. This makes these
|
||||
* template functions available to the compiler when (and only when) this class
|
||||
* is instantiated, at which point they're only templated on the 2nd parameter
|
||||
* (the first one, BASE<T> being known).
|
||||
*/
|
||||
template<typename U>
|
||||
friend constexpr inline
|
||||
arithmetic_result_t<T, U> MATH_PURE dot(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
arithmetic_result_t<T, U> r{};
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
r += lv[i] * rv[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
friend inline T MATH_PURE norm(const VECTOR<T>& lv) {
|
||||
return std::sqrt(dot(lv, lv));
|
||||
}
|
||||
|
||||
friend inline T MATH_PURE length(const VECTOR<T>& lv) {
|
||||
return norm(lv);
|
||||
}
|
||||
|
||||
friend inline constexpr T MATH_PURE norm2(const VECTOR<T>& lv) {
|
||||
return dot(lv, lv);
|
||||
}
|
||||
|
||||
friend inline constexpr T MATH_PURE length2(const VECTOR<T>& lv) {
|
||||
return norm2(lv);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
arithmetic_result_t<T, U> MATH_PURE distance(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
return length(rv - lv);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
arithmetic_result_t<T, U> MATH_PURE distance2(const VECTOR<T>& lv, const VECTOR<U>& rv) {
|
||||
return length2(rv - lv);
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE normalize(const VECTOR<T>& lv) {
|
||||
return lv * (T(1) / length(lv));
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE rcp(VECTOR<T> v) {
|
||||
return T(1) / v;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE abs(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = v[i] < 0 ? -v[i] : v[i];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE floor(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::floor(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE ceil(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::ceil(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE round(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::round(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE inversesqrt(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = T(1) / std::sqrt(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE sqrt(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::sqrt(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE cbrt(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::cbrt(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE exp(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::exp(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE pow(VECTOR<T> v, T p) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::pow(v[i], p);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE pow(T v, VECTOR<T> p) {
|
||||
for (size_t i = 0; i < p.size(); i++) {
|
||||
p[i] = std::pow(v, p[i]);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE pow(VECTOR<T> v, VECTOR<T> p) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::pow(v[i], p[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE log(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::log(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE log10(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::log10(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline VECTOR<T> MATH_PURE log2(VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = std::log2(v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE saturate(const VECTOR<T>& lv) {
|
||||
return clamp(lv, T(0), T(1));
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE clamp(VECTOR<T> v, T min, T max) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = details::min(max, details::max(min, v[i]));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE clamp(VECTOR<T> v, VECTOR<T> min, VECTOR<T> max) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = details::min(max[i], details::max(min[i], v[i]));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv,
|
||||
VECTOR<T> a) {
|
||||
for (size_t i = 0; i < lv.size(); i++) {
|
||||
a[i] += (lv[i] * rv[i]);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE min(const VECTOR<T>& u, VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = details::min(u[i], v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE max(const VECTOR<T>& u, VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = details::max(u[i], v[i]);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline constexpr T MATH_PURE max(const VECTOR<T>& v) {
|
||||
T r(v[0]);
|
||||
for (size_t i = 1; i < v.size(); i++) {
|
||||
r = max(r, v[i]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
friend inline constexpr T MATH_PURE min(const VECTOR<T>& v) {
|
||||
T r(v[0]);
|
||||
for (size_t i = 1; i < v.size(); i++) {
|
||||
r = min(r, v[i]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE mix(const VECTOR<T>& u, VECTOR<T> v, T a) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = u[i] * (T(1) - a) + v[i] * a;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE smoothstep(T edge0, T edge1, VECTOR<T> v) {
|
||||
VECTOR<T> t = saturate((v - edge0) / (edge1 - edge0));
|
||||
return t * t * (T(3) - T(2) * t);
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE step(T edge, VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = v[i] < edge ? T(0) : T(1);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline constexpr VECTOR<T> MATH_PURE step(VECTOR<T> edge, VECTOR<T> v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i] = v[i] < edge[i] ? T(0) : T(1);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
friend inline constexpr bool MATH_PURE any(const VECTOR<T>& v) {
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
if (v[i] != T(0)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
friend inline constexpr bool MATH_PURE all(const VECTOR<T>& v) {
|
||||
bool result = true;
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
result &= (v[i] != T(0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
} // namespace details
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // MATH_TVECHELPERS_H_
|
||||
126
ios/include/math/compiler.h
Normal file
126
ios/include/math/compiler.h
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#if defined (WIN32)
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#ifdef far
|
||||
#undef far
|
||||
#endif
|
||||
|
||||
#ifdef near
|
||||
#undef near
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// compatibility with non-clang compilers...
|
||||
#ifndef __has_attribute
|
||||
#define __has_attribute(x) 0
|
||||
#endif
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_expect)
|
||||
# ifdef __cplusplus
|
||||
# define MATH_LIKELY( exp ) (__builtin_expect( !!(exp), true ))
|
||||
# define MATH_UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
|
||||
# else
|
||||
# define MATH_LIKELY( exp ) (__builtin_expect( !!(exp), 1 ))
|
||||
# define MATH_UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
|
||||
# endif
|
||||
#else
|
||||
# define MATH_LIKELY( exp ) (exp)
|
||||
# define MATH_UNLIKELY( exp ) (exp)
|
||||
#endif
|
||||
|
||||
#if __has_attribute(unused)
|
||||
# define MATH_UNUSED __attribute__((unused))
|
||||
#else
|
||||
# define MATH_UNUSED
|
||||
#endif
|
||||
|
||||
#if __has_attribute(pure)
|
||||
# define MATH_PURE __attribute__((pure))
|
||||
#else
|
||||
# define MATH_PURE
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define MATH_EMPTY_BASES __declspec(empty_bases)
|
||||
|
||||
// MSVC does not support loop unrolling hints
|
||||
# define MATH_NOUNROLL
|
||||
|
||||
// Sadly, MSVC does not support __builtin_constant_p
|
||||
# ifndef MAKE_CONSTEXPR
|
||||
# define MAKE_CONSTEXPR(e) (e)
|
||||
# endif
|
||||
|
||||
// About value initialization, the C++ standard says:
|
||||
// if T is a class type with a default constructor that is neither user-provided nor deleted
|
||||
// (that is, it may be a class with an implicitly-defined or defaulted default constructor),
|
||||
// the object is zero-initialized and then it is default-initialized
|
||||
// if it has a non-trivial default constructor;
|
||||
// Unfortunately, MSVC always calls the default constructor, even if it is trivial, which
|
||||
// breaks constexpr-ness. To workaround this, we're always zero-initializing TVecN<>
|
||||
# define MATH_CONSTEXPR_INIT {}
|
||||
# define MATH_DEFAULT_CTOR {}
|
||||
# define MATH_DEFAULT_CTOR_CONSTEXPR constexpr
|
||||
# define CONSTEXPR_IF_NOT_MSVC // when declared constexpr, msvc fails with "failure was caused by cast of object of dynamic type"
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
# define MATH_EMPTY_BASES
|
||||
// C++11 allows pragmas to be specified as part of defines using the _Pragma syntax.
|
||||
# define MATH_NOUNROLL _Pragma("nounroll")
|
||||
|
||||
# ifndef MAKE_CONSTEXPR
|
||||
# define MAKE_CONSTEXPR(e) __builtin_constant_p(e) ? (e) : (e)
|
||||
# endif
|
||||
|
||||
# define MATH_CONSTEXPR_INIT
|
||||
# define MATH_DEFAULT_CTOR = default;
|
||||
# define MATH_DEFAULT_CTOR_CONSTEXPR
|
||||
# define CONSTEXPR_IF_NOT_MSVC constexpr
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
|
||||
// MSVC 2019 16.4 doesn't seem to like it when we specialize std::is_arithmetic for
|
||||
// filament::math::half, so we're forced to create our own is_arithmetic here and specialize it
|
||||
// inside of half.h.
|
||||
template<typename T>
|
||||
struct is_arithmetic : std::integral_constant<bool,
|
||||
std::is_integral<T>::value || std::is_floating_point<T>::value> {
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
174
ios/include/math/fast.h
Normal file
174
ios/include/math/fast.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 TNT_MATH_FAST_H
|
||||
#define TNT_MATH_FAST_H
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include <math/compiler.h>
|
||||
#include <math/scalar.h>
|
||||
|
||||
#ifdef __ARM_NEON
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
namespace fast {
|
||||
|
||||
// fast cos(x), ~8 cycles (vs. 66 cycles on ARM)
|
||||
// can be vectorized
|
||||
// x between -pi and pi
|
||||
template<typename T, typename = std::enable_if_t<std::is_floating_point<T>::value>>
|
||||
constexpr T MATH_PURE cos(T x) noexcept {
|
||||
x *= T(F_1_PI / 2);
|
||||
x -= T(0.25) + std::floor(x + T(0.25));
|
||||
x *= T(16.0) * std::abs(x) - T(8.0);
|
||||
x += T(0.225) * x * (std::abs(x) - T(1.0));
|
||||
return x;
|
||||
}
|
||||
|
||||
// fast sin(x), ~8 cycles (vs. 66 cycles on ARM)
|
||||
// can be vectorized
|
||||
// x between -pi and pi
|
||||
template<typename T, typename = std::enable_if_t<std::is_floating_point<T>::value>>
|
||||
constexpr T MATH_PURE sin(T x) noexcept {
|
||||
return filament::math::fast::cos<T>(x - T(F_PI_2));
|
||||
}
|
||||
|
||||
constexpr inline float MATH_PURE ilog2(float x) noexcept {
|
||||
union {
|
||||
float val;
|
||||
int32_t x;
|
||||
} u = { x };
|
||||
return float(((u.x >> 23) & 0xff) - 127);
|
||||
}
|
||||
|
||||
constexpr inline float MATH_PURE log2(float x) noexcept {
|
||||
union {
|
||||
float val;
|
||||
int32_t x;
|
||||
} u = { x };
|
||||
float ilog2 = float(((u.x >> 23) & 0xff) - 128);
|
||||
u.x = (u.x & 0x007fffff) | 0x3f800000;
|
||||
return ilog2 + (-0.34484843f * u.val + 2.02466578f) * u.val - 0.67487759f;
|
||||
}
|
||||
|
||||
// fast 1/sqrt(), on ARMv8 this is 5 cycles vs. 7 cycles, so maybe not worth it.
|
||||
// we keep this mostly for reference and benchmarking.
|
||||
inline float MATH_PURE isqrt(float x) noexcept {
|
||||
#if defined(__ARM_NEON) && defined(__aarch64__)
|
||||
float y = vrsqrtes_f32(x);
|
||||
return y * vrsqrtss_f32(x, y * y);
|
||||
#else
|
||||
return 1 / std::sqrt(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline double MATH_PURE isqrt(double x) noexcept {
|
||||
#if defined(__ARM_NEON) && defined(__aarch64__)
|
||||
double y = vrsqrted_f64(x);
|
||||
return y * vrsqrtsd_f64(x, y * y);
|
||||
#else
|
||||
return 1 / std::sqrt(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int signbit(float x) noexcept {
|
||||
#if __has_builtin(__builtin_signbitf)
|
||||
// Note: on Android NDK, signbit() is a function call -- not what we want.
|
||||
return __builtin_signbitf(x);
|
||||
#else
|
||||
return std::signbit(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* constexpr exp(), pow(), factorial()
|
||||
*/
|
||||
|
||||
constexpr double pow(double x, unsigned int y) noexcept {
|
||||
return y == 0 ? 1.0 : x * pow(x, y - 1);
|
||||
}
|
||||
|
||||
constexpr unsigned int factorial(unsigned int x) noexcept {
|
||||
return x == 0 ? 1 : x * factorial(x - 1);
|
||||
}
|
||||
|
||||
constexpr double exp(double x) noexcept {
|
||||
return 1.0 + x + pow(x, 2) / factorial(2) + pow(x, 3) / factorial(3)
|
||||
+ pow(x, 4) / factorial(4) + pow(x, 5) / factorial(5)
|
||||
+ pow(x, 6) / factorial(6) + pow(x, 7) / factorial(7)
|
||||
+ pow(x, 8) / factorial(8) + pow(x, 9) / factorial(9);
|
||||
}
|
||||
|
||||
constexpr float exp(float x) noexcept {
|
||||
return float(exp(double(x)));
|
||||
}
|
||||
|
||||
/*
|
||||
* unsigned saturated arithmetic
|
||||
*/
|
||||
|
||||
#if defined(__ARM_NEON) && defined(__aarch64__)
|
||||
inline uint8_t MATH_PURE qadd(uint8_t a, uint8_t b) noexcept { return vuqaddb_s8(a, b); }
|
||||
inline uint16_t MATH_PURE qadd(uint16_t a, uint16_t b) noexcept { return vuqaddh_s16(a, b); }
|
||||
inline uint32_t MATH_PURE qadd(uint32_t a, uint32_t b) noexcept { return vuqadds_s32(a, b); }
|
||||
|
||||
inline uint8_t MATH_PURE qsub(uint8_t a, uint8_t b) noexcept { return vqsubb_s8(a, b); }
|
||||
inline uint16_t MATH_PURE qsub(uint16_t a, uint16_t b) noexcept { return vqsubh_s16(a, b); }
|
||||
inline uint32_t MATH_PURE qsub(uint32_t a, uint32_t b) noexcept { return vqsubs_s32(a, b); }
|
||||
#else
|
||||
|
||||
template<typename T, typename = std::enable_if_t<
|
||||
std::is_same<uint8_t, T>::value ||
|
||||
std::is_same<uint16_t, T>::value ||
|
||||
std::is_same<uint32_t, T>::value>>
|
||||
inline T MATH_PURE qadd(T a, T b) noexcept {
|
||||
T r = a + b;
|
||||
return r | -T(r < a);
|
||||
}
|
||||
|
||||
template<typename T, typename = std::enable_if_t<
|
||||
std::is_same<uint8_t, T>::value ||
|
||||
std::is_same<uint16_t, T>::value ||
|
||||
std::is_same<uint32_t, T>::value>>
|
||||
inline T MATH_PURE qsub(T a, T b) noexcept {
|
||||
T r = a - b;
|
||||
return r & -T(r <= a);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
inline T MATH_PURE qinc(T a) noexcept {
|
||||
return qadd(a, T(1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T MATH_PURE qdec(T a) noexcept {
|
||||
return qsub(a, T(1));
|
||||
}
|
||||
|
||||
|
||||
} // namespace fast
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_MATH_FAST_H
|
||||
224
ios/include/math/half.h
Normal file
224
ios/include/math/half.h
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 TNT_MATH_HALF_H
|
||||
#define TNT_MATH_HALF_H
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <math/compiler.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
|
||||
template<unsigned S, unsigned E, unsigned M>
|
||||
class fp {
|
||||
static_assert(S + E + M <= 16, "we only support 16-bits max custom floats");
|
||||
|
||||
using TYPE = uint16_t; // this should be dynamic
|
||||
|
||||
static constexpr unsigned S_SHIFT = E + M;
|
||||
static constexpr unsigned E_SHIFT = M;
|
||||
static constexpr unsigned M_SHIFT = 0;
|
||||
static constexpr unsigned S_MASK = ((1u << S) - 1u) << S_SHIFT;
|
||||
static constexpr unsigned E_MASK = ((1u << E) - 1u) << E_SHIFT;
|
||||
static constexpr unsigned M_MASK = ((1u << M) - 1u) << M_SHIFT;
|
||||
|
||||
struct fp32 {
|
||||
explicit constexpr fp32(float f) noexcept : fp(f) { } // NOLINT
|
||||
explicit constexpr fp32(uint32_t b) noexcept : bits(b) { } // NOLINT
|
||||
constexpr void setS(unsigned int s) noexcept {
|
||||
bits = uint32_t((bits & 0x7FFFFFFFu) | (s << 31u));
|
||||
}
|
||||
constexpr unsigned int getS() const noexcept { return bits >> 31u; }
|
||||
constexpr unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; }
|
||||
constexpr unsigned int getM() const noexcept { return bits & 0x7FFFFFu; }
|
||||
union {
|
||||
uint32_t bits;
|
||||
float fp;
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
static constexpr fp fromf(float f) noexcept {
|
||||
fp out;
|
||||
if (S == 0 && f < 0.0f) {
|
||||
return out;
|
||||
}
|
||||
|
||||
fp32 in(f);
|
||||
unsigned int sign = in.getS();
|
||||
in.setS(0);
|
||||
if (MATH_UNLIKELY(in.getE() == 0xFF)) { // inf or nan
|
||||
out.setE((1u << E) - 1u);
|
||||
out.setM(in.getM() ? (1u << (M - 1u)) : 0);
|
||||
} else {
|
||||
constexpr fp32 infinity(((1u << E) - 1u) << 23u); // fp infinity in fp32 position
|
||||
constexpr fp32 magic(((1u << (E - 1u)) - 1u) << 23u); // exponent offset
|
||||
in.bits &= ~((1u << (22 - M)) - 1u); // erase extra mantissa bits
|
||||
in.bits += 1u << (22 - M); // rounding
|
||||
in.fp *= magic.fp; // add exponent offset
|
||||
in.bits = in.bits < infinity.bits ? in.bits : infinity.bits;
|
||||
out.bits = uint16_t(in.bits >> (23 - M));
|
||||
}
|
||||
out.setS(sign);
|
||||
return out;
|
||||
}
|
||||
|
||||
static constexpr float tof(fp in) noexcept {
|
||||
constexpr fp32 magic ((0xFE - ((1u << (E - 1u)) - 1u)) << 23u);
|
||||
constexpr fp32 infnan((0x80 + ((1u << (E - 1u)) - 1u)) << 23u);
|
||||
fp32 out((in.bits & ((1u << (E + M)) - 1u)) << (23u - M));
|
||||
out.fp *= magic.fp;
|
||||
if (out.fp >= infnan.fp) {
|
||||
out.bits |= 0xFFu << 23u;
|
||||
}
|
||||
out.bits |= (in.bits & S_MASK) << (31u - S_SHIFT);
|
||||
return out.fp;
|
||||
}
|
||||
|
||||
TYPE bits{};
|
||||
static constexpr size_t getBitCount() noexcept { return S + E + M; }
|
||||
constexpr fp() noexcept = default;
|
||||
explicit constexpr fp(TYPE bits) noexcept : bits(bits) { }
|
||||
constexpr void setS(unsigned int s) noexcept { bits = TYPE((bits & ~S_MASK) | (s << S_SHIFT)); }
|
||||
constexpr void setE(unsigned int s) noexcept { bits = TYPE((bits & ~E_MASK) | (s << E_SHIFT)); }
|
||||
constexpr void setM(unsigned int s) noexcept { bits = TYPE((bits & ~M_MASK) | (s << M_SHIFT)); }
|
||||
constexpr unsigned int getS() const noexcept { return (bits & S_MASK) >> S_SHIFT; }
|
||||
constexpr unsigned int getE() const noexcept { return (bits & E_MASK) >> E_SHIFT; }
|
||||
constexpr unsigned int getM() const noexcept { return (bits & M_MASK) >> M_SHIFT; }
|
||||
};
|
||||
|
||||
/*
|
||||
* half-float
|
||||
*
|
||||
* 1 5 10
|
||||
* +-+------+------------+
|
||||
* |s|eee.ee|mm.mmmm.mmmm|
|
||||
* +-+------+------------+
|
||||
*
|
||||
* minimum (denormal) value: 2^-24 = 5.96e-8
|
||||
* minimum (normal) value: 2^-14 = 6.10e-5
|
||||
* maximum value: (2 - 2^-10) * 2^15 = 65504
|
||||
*
|
||||
* Integers between 0 and 2048 can be represented exactly
|
||||
*/
|
||||
|
||||
#ifdef __ARM_NEON
|
||||
|
||||
using half = __fp16;
|
||||
|
||||
inline constexpr uint16_t getBits(half const& h) noexcept {
|
||||
return MAKE_CONSTEXPR(reinterpret_cast<uint16_t const&>(h));
|
||||
}
|
||||
|
||||
inline constexpr half makeHalf(uint16_t bits) noexcept {
|
||||
return MAKE_CONSTEXPR(reinterpret_cast<half const&>(bits));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
class half {
|
||||
using fp16 = fp<1, 5, 10>;
|
||||
|
||||
public:
|
||||
half() = default;
|
||||
constexpr half(float v) noexcept : mBits(fp16::fromf(v)) { } // NOLINT
|
||||
constexpr operator float() const noexcept { return fp16::tof(mBits); } // NOLINT
|
||||
|
||||
private:
|
||||
// these are friends, not members (and they're not "private")
|
||||
friend constexpr uint16_t getBits(half const& h) noexcept { return h.mBits.bits; }
|
||||
friend constexpr inline half makeHalf(uint16_t bits) noexcept;
|
||||
|
||||
enum Binary { binary };
|
||||
explicit constexpr half(Binary, uint16_t bits) noexcept : mBits(bits) { }
|
||||
|
||||
fp16 mBits;
|
||||
};
|
||||
|
||||
constexpr inline half makeHalf(uint16_t bits) noexcept {
|
||||
return half(half::binary, bits);
|
||||
}
|
||||
|
||||
#endif // __ARM_NEON
|
||||
|
||||
inline constexpr half operator "" _h(long double v) {
|
||||
return half( static_cast<float>(v) );
|
||||
}
|
||||
|
||||
template<> struct is_arithmetic<filament::math::half> : public std::true_type {};
|
||||
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
namespace std {
|
||||
|
||||
template<> struct is_floating_point<filament::math::half> : public std::true_type {};
|
||||
|
||||
// note: this shouldn't be needed (is_floating_point<> is enough) but some version of msvc need it
|
||||
// This stopped working with MSVC 2019 16.4, so we specialize our own version of is_arithmetic in
|
||||
// the math::filament namespace (see above).
|
||||
template<> struct is_arithmetic<filament::math::half> : public std::true_type {};
|
||||
|
||||
template<>
|
||||
class numeric_limits<filament::math::half> {
|
||||
public:
|
||||
typedef filament::math::half type;
|
||||
|
||||
static constexpr const bool is_specialized = true;
|
||||
static constexpr const bool is_signed = true;
|
||||
static constexpr const bool is_integer = false;
|
||||
static constexpr const bool is_exact = false;
|
||||
static constexpr const bool has_infinity = true;
|
||||
static constexpr const bool has_quiet_NaN = true;
|
||||
static constexpr const bool has_signaling_NaN = false;
|
||||
static constexpr const float_denorm_style has_denorm = denorm_absent;
|
||||
static constexpr const bool has_denorm_loss = true;
|
||||
static constexpr const bool is_iec559 = false;
|
||||
static constexpr const bool is_bounded = true;
|
||||
static constexpr const bool is_modulo = false;
|
||||
static constexpr const bool traps = false;
|
||||
static constexpr const bool tinyness_before = false;
|
||||
static constexpr const float_round_style round_style = round_indeterminate;
|
||||
|
||||
static constexpr const int digits = 11;
|
||||
static constexpr const int digits10 = 3;
|
||||
static constexpr const int max_digits10 = 5;
|
||||
static constexpr const int radix = 2;
|
||||
static constexpr const int min_exponent = -13;
|
||||
static constexpr const int min_exponent10 = -4;
|
||||
static constexpr const int max_exponent = 16;
|
||||
static constexpr const int max_exponent10 = 4;
|
||||
|
||||
inline static constexpr type round_error() noexcept { return filament::math::makeHalf(0x3800); }
|
||||
inline static constexpr type min() noexcept { return filament::math::makeHalf(0x0400); }
|
||||
inline static constexpr type max() noexcept { return filament::math::makeHalf(0x7bff); }
|
||||
inline static constexpr type lowest() noexcept { return filament::math::makeHalf(0xfbff); }
|
||||
inline static constexpr type epsilon() noexcept { return filament::math::makeHalf(0x1400); }
|
||||
inline static constexpr type infinity() noexcept { return filament::math::makeHalf(0x7c00); }
|
||||
inline static constexpr type quiet_NaN() noexcept { return filament::math::makeHalf(0x7fff); }
|
||||
inline static constexpr type denorm_min() noexcept { return filament::math::makeHalf(0x0001); }
|
||||
inline static constexpr type signaling_NaN() noexcept { return filament::math::makeHalf(0x7dff); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // TNT_MATH_HALF_H
|
||||
361
ios/include/math/mat2.h
Normal file
361
ios/include/math/mat2.h
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* 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 MATH_MAT2_H_
|
||||
#define MATH_MAT2_H_
|
||||
|
||||
#include <math/TMatHelpers.h>
|
||||
#include <math/vec2.h>
|
||||
#include <math/compiler.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
// -------------------------------------------------------------------------------------
|
||||
namespace details {
|
||||
|
||||
/**
|
||||
* A 2x2 column-major matrix class.
|
||||
*
|
||||
* Conceptually a 2x2 matrix is a an array of 2 column vec2:
|
||||
*
|
||||
* mat2 m =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cc}
|
||||
* m[0] & m[1] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
* =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cc}
|
||||
* m[0][0] & m[1][0] \\
|
||||
* m[0][1] & m[1][1] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
* =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cc}
|
||||
* m(0,0) & m(0,1) \\
|
||||
* m(1,0) & m(1,1) \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*
|
||||
* m[n] is the \f$ n^{th} \f$ column of the matrix and is a vec2.
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
class MATH_EMPTY_BASES TMat22 :
|
||||
public TVecUnaryOperators<TMat22, T>,
|
||||
public TVecComparisonOperators<TMat22, T>,
|
||||
public TVecAddOperators<TMat22, T>,
|
||||
public TMatProductOperators<TMat22, T, TVec2>,
|
||||
public TMatSquareFunctions<TMat22, T>,
|
||||
public TMatHelpers<TMat22, T> {
|
||||
public:
|
||||
enum no_init {
|
||||
NO_INIT
|
||||
};
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef size_t size_type;
|
||||
typedef TVec2<T> col_type;
|
||||
typedef TVec2<T> row_type;
|
||||
|
||||
static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows)
|
||||
static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns)
|
||||
static constexpr size_t NUM_ROWS = COL_SIZE;
|
||||
static constexpr size_t NUM_COLS = ROW_SIZE;
|
||||
|
||||
private:
|
||||
/*
|
||||
* <-- N columns -->
|
||||
*
|
||||
* a[0][0] a[1][0] a[2][0] ... a[N][0] ^
|
||||
* a[0][1] a[1][1] a[2][1] ... a[N][1] |
|
||||
* a[0][2] a[1][2] a[2][2] ... a[N][2] M rows
|
||||
* ... |
|
||||
* a[0][M] a[1][M] a[2][M] ... a[N][M] v
|
||||
*
|
||||
* COL_SIZE = M
|
||||
* ROW_SIZE = N
|
||||
* m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ]
|
||||
*/
|
||||
|
||||
col_type m_value[NUM_COLS];
|
||||
|
||||
public:
|
||||
// array access
|
||||
inline constexpr col_type const& operator[](size_t column) const noexcept {
|
||||
assert(column < NUM_COLS);
|
||||
return m_value[column];
|
||||
}
|
||||
|
||||
inline constexpr col_type& operator[](size_t column) noexcept {
|
||||
assert(column < NUM_COLS);
|
||||
return m_value[column];
|
||||
}
|
||||
|
||||
/**
|
||||
* constructors
|
||||
*/
|
||||
|
||||
/**
|
||||
* leaves object uninitialized. use with caution.
|
||||
*/
|
||||
constexpr explicit TMat22(no_init) noexcept {}
|
||||
|
||||
|
||||
/**
|
||||
* initialize to identity.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cc}
|
||||
* 1 & 0 \\
|
||||
* 0 & 1 \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
constexpr TMat22() noexcept ;
|
||||
|
||||
/**
|
||||
* initialize to Identity*scalar.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cc}
|
||||
* v & 0 \\
|
||||
* 0 & v \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat22(U v) noexcept;
|
||||
|
||||
/**
|
||||
* sets the diagonal to a vector.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cc}
|
||||
* v[0] & 0 \\
|
||||
* 0 & v[1] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat22(const TVec2<U>& v) noexcept;
|
||||
|
||||
/**
|
||||
* construct from another matrix of the same size
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat22(const TMat22<U>& rhs) noexcept;
|
||||
|
||||
/**
|
||||
* construct from 2 column vectors.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cc}
|
||||
* v0 & v1 \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename A, typename B>
|
||||
constexpr TMat22(const TVec2<A>& v0, const TVec2<B>& v1) noexcept;
|
||||
|
||||
/** construct from 4 elements in column-major form.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cc}
|
||||
* m[0][0] & m[1][0] \\
|
||||
* m[0][1] & m[1][1] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<
|
||||
typename A, typename B,
|
||||
typename C, typename D>
|
||||
constexpr explicit TMat22(A m00, B m01, C m10, D m11) noexcept ;
|
||||
|
||||
|
||||
struct row_major_init {
|
||||
template<typename A, typename B,
|
||||
typename C, typename D>
|
||||
constexpr explicit row_major_init(A m00, B m01, C m10, D m11) noexcept
|
||||
: m(m00, m10, m01, m11) {}
|
||||
|
||||
private:
|
||||
friend TMat22;
|
||||
TMat22 m;
|
||||
};
|
||||
|
||||
constexpr explicit TMat22(row_major_init c) noexcept : TMat22(std::move(c.m)) {}
|
||||
|
||||
/**
|
||||
* Rotate by radians in the 2D plane
|
||||
*/
|
||||
static TMat22<T> rotate(T radian) noexcept {
|
||||
TMat22<T> r(TMat22<T>::NO_INIT);
|
||||
T c = std::cos(radian);
|
||||
T s = std::sin(radian);
|
||||
r[0][0] = c;
|
||||
r[1][1] = c;
|
||||
r[0][1] = s;
|
||||
r[1][0] = -s;
|
||||
return r;
|
||||
}
|
||||
|
||||
// returns false if the two matrices are different. May return false if they're the
|
||||
// same, with some elements only differing by +0 or -0. Behaviour is undefined with NaNs.
|
||||
static constexpr bool fuzzyEqual(TMat22 l, TMat22 r) noexcept {
|
||||
uint64_t const* const li = reinterpret_cast<uint64_t const*>(&l);
|
||||
uint64_t const* const ri = reinterpret_cast<uint64_t const*>(&r);
|
||||
uint64_t result = 0;
|
||||
// For some reason clang is not able to vectoize this loop when the number of iteration
|
||||
// is known and constant (!?!?!). Still this is better than operator==.
|
||||
#pragma clang loop vectorize_width(2)
|
||||
for (size_t i = 0; i < sizeof(TMat22) / sizeof(uint64_t); i++) {
|
||||
result |= li[i] ^ ri[i];
|
||||
}
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat22 translation(const TVec2<A>& t) noexcept {
|
||||
TMat22 r;
|
||||
r[2] = t;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat22 scaling(const TVec2<A>& s) noexcept {
|
||||
return TMat22{ s };
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat22 scaling(A s) noexcept {
|
||||
return TMat22{ TVec2<T>{ s, s }};
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// Constructors
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
// Since the matrix code could become pretty big quickly, we don't inline most
|
||||
// operations.
|
||||
|
||||
template<typename T>
|
||||
constexpr TMat22<T>::TMat22() noexcept
|
||||
: m_value{ col_type(1, 0), col_type(0, 1) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat22<T>::TMat22(U v) noexcept
|
||||
: m_value{ col_type(v, 0), col_type(0, v) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat22<T>::TMat22(const TVec2<U>& v) noexcept
|
||||
: m_value{ col_type(v[0], 0), col_type(0, v[1]) } {
|
||||
}
|
||||
|
||||
// construct from 4 scalars. Note that the arrangement
|
||||
// of values in the constructor is the transpose of the matrix
|
||||
// notation.
|
||||
template<typename T>
|
||||
template<typename A, typename B,
|
||||
typename C, typename D>
|
||||
constexpr TMat22<T>::TMat22(A m00, B m01, C m10, D m11) noexcept
|
||||
: m_value{ col_type(m00, m01), col_type(m10, m11) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat22<T>::TMat22(const TMat22<U>& rhs) noexcept {
|
||||
for (size_t col = 0; col < NUM_COLS; ++col) {
|
||||
m_value[col] = col_type(rhs[col]);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct from 2 column vectors.
|
||||
template<typename T>
|
||||
template<typename A, typename B>
|
||||
constexpr TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& v1) noexcept
|
||||
: m_value{ v0, v1 } {
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
typedef details::TMat22<double> mat2;
|
||||
typedef details::TMat22<float> mat2f;
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
constexpr void swap(filament::math::details::TMat22<T>& lhs,
|
||||
filament::math::details::TMat22<T>& rhs) noexcept {
|
||||
// This generates much better code than the default implementation
|
||||
// It's unclear why, I believe this is due to an optimization bug in the clang.
|
||||
//
|
||||
// filament::math::details::TMat22<T> t(lhs);
|
||||
// lhs = rhs;
|
||||
// rhs = t;
|
||||
//
|
||||
// clang always copy lhs on the stack, even if it's never using it (it's using the
|
||||
// copy it has in registers).
|
||||
|
||||
const T t00 = lhs[0][0];
|
||||
const T t01 = lhs[0][1];
|
||||
const T t10 = lhs[1][0];
|
||||
const T t11 = lhs[1][1];
|
||||
|
||||
lhs[0][0] = rhs[0][0];
|
||||
lhs[0][1] = rhs[0][1];
|
||||
lhs[1][0] = rhs[1][0];
|
||||
lhs[1][1] = rhs[1][1];
|
||||
|
||||
rhs[0][0] = t00;
|
||||
rhs[0][1] = t01;
|
||||
rhs[1][0] = t10;
|
||||
rhs[1][1] = t11;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MATH_MAT2_H_
|
||||
490
ios/include/math/mat3.h
Normal file
490
ios/include/math/mat3.h
Normal file
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* 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 MATH_MAT3_H_
|
||||
#define MATH_MAT3_H_
|
||||
|
||||
#include <math/quat.h>
|
||||
#include <math/TMatHelpers.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/compiler.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
// -------------------------------------------------------------------------------------
|
||||
namespace details {
|
||||
|
||||
/**
|
||||
* A 3x3 column-major matrix class.
|
||||
*
|
||||
* Conceptually a 3x3 matrix is a an array of 3 column vec3:
|
||||
*
|
||||
* mat3 m =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{ccc}
|
||||
* m[0] & m[1] & m[2] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
* =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{ccc}
|
||||
* m[0][0] & m[1][0] & m[2][0] \\
|
||||
* m[0][1] & m[1][1] & m[2][1] \\
|
||||
* m[0][2] & m[1][2] & m[2][2] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
* =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{ccc}
|
||||
* m(0,0) & m(0,1) & m(0,2) \\
|
||||
* m(1,0) & m(1,1) & m(1,2) \\
|
||||
* m(2,0) & m(2,1) & m(2,2) \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*
|
||||
* m[n] is the \f$ n^{th} \f$ column of the matrix and is a vec3.
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
class MATH_EMPTY_BASES TMat33 :
|
||||
public TVecUnaryOperators<TMat33, T>,
|
||||
public TVecComparisonOperators<TMat33, T>,
|
||||
public TVecAddOperators<TMat33, T>,
|
||||
public TMatProductOperators<TMat33, T, TVec3>,
|
||||
public TMatSquareFunctions<TMat33, T>,
|
||||
public TMatTransform<TMat33, T>,
|
||||
public TMatHelpers<TMat33, T> {
|
||||
public:
|
||||
enum no_init {
|
||||
NO_INIT
|
||||
};
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef size_t size_type;
|
||||
typedef TVec3<T> col_type;
|
||||
typedef TVec3<T> row_type;
|
||||
|
||||
static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows)
|
||||
static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns)
|
||||
static constexpr size_t NUM_ROWS = COL_SIZE;
|
||||
static constexpr size_t NUM_COLS = ROW_SIZE;
|
||||
|
||||
private:
|
||||
/*
|
||||
* <-- N columns -->
|
||||
*
|
||||
* a[0][0] a[1][0] a[2][0] ... a[N][0] ^
|
||||
* a[0][1] a[1][1] a[2][1] ... a[N][1] |
|
||||
* a[0][2] a[1][2] a[2][2] ... a[N][2] M rows
|
||||
* ... |
|
||||
* a[0][M] a[1][M] a[2][M] ... a[N][M] v
|
||||
*
|
||||
* COL_SIZE = M
|
||||
* ROW_SIZE = N
|
||||
* m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ]
|
||||
*/
|
||||
|
||||
col_type m_value[NUM_COLS];
|
||||
|
||||
public:
|
||||
// array access
|
||||
inline constexpr col_type const& operator[](size_t column) const noexcept {
|
||||
assert(column < NUM_COLS);
|
||||
return m_value[column];
|
||||
}
|
||||
|
||||
inline constexpr col_type& operator[](size_t column) noexcept {
|
||||
assert(column < NUM_COLS);
|
||||
return m_value[column];
|
||||
}
|
||||
|
||||
/**
|
||||
* constructors
|
||||
*/
|
||||
|
||||
/**
|
||||
* leaves object uninitialized. use with caution.
|
||||
*/
|
||||
constexpr explicit TMat33(no_init) noexcept {}
|
||||
|
||||
|
||||
/**
|
||||
* initialize to identity.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{ccc}
|
||||
* 1 & 0 & 0 \\
|
||||
* 0 & 1 & 0 \\
|
||||
* 0 & 0 & 1 \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
constexpr TMat33() noexcept;
|
||||
|
||||
/**
|
||||
* initialize to Identity*scalar.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{ccc}
|
||||
* v & 0 & 0 \\
|
||||
* 0 & v & 0 \\
|
||||
* 0 & 0 & v \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat33(U v) noexcept;
|
||||
|
||||
/**
|
||||
* sets the diagonal to a vector.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{ccc}
|
||||
* v[0] & 0 & 0 \\
|
||||
* 0 & v[1] & 0 \\
|
||||
* 0 & 0 & v[2] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat33(const TVec3<U>& v) noexcept;
|
||||
|
||||
/**
|
||||
* construct from another matrix of the same size
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat33(const TMat33<U>& rhs) noexcept;
|
||||
|
||||
/**
|
||||
* construct from 3 column vectors.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{ccc}
|
||||
* v0 & v1 & v2 \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename A, typename B, typename C>
|
||||
constexpr TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2) noexcept;
|
||||
|
||||
/** construct from 9 elements in column-major form.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{ccc}
|
||||
* m[0][0] & m[1][0] & m[2][0] \\
|
||||
* m[0][1] & m[1][1] & m[2][1] \\
|
||||
* m[0][2] & m[1][2] & m[2][2] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<
|
||||
typename A, typename B, typename C,
|
||||
typename D, typename E, typename F,
|
||||
typename G, typename H, typename I>
|
||||
constexpr explicit TMat33(A m00, B m01, C m02,
|
||||
D m10, E m11, F m12,
|
||||
G m20, H m21, I m22) noexcept;
|
||||
|
||||
|
||||
struct row_major_init {
|
||||
template<
|
||||
typename A, typename B, typename C,
|
||||
typename D, typename E, typename F,
|
||||
typename G, typename H, typename I>
|
||||
constexpr explicit row_major_init(A m00, B m01, C m02,
|
||||
D m10, E m11, F m12,
|
||||
G m20, H m21, I m22) noexcept
|
||||
: m(m00, m10, m20,
|
||||
m01, m11, m21,
|
||||
m02, m12, m22) {}
|
||||
|
||||
private:
|
||||
friend TMat33;
|
||||
TMat33 m;
|
||||
};
|
||||
|
||||
constexpr explicit TMat33(row_major_init c) noexcept : TMat33(std::move(c.m)) {}
|
||||
|
||||
/**
|
||||
* construct from a quaternion
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat33(const TQuaternion<U>& q) noexcept;
|
||||
|
||||
/**
|
||||
* orthogonalize only works on matrices of size 3x3
|
||||
*/
|
||||
friend inline
|
||||
constexpr TMat33 orthogonalize(const TMat33& m) noexcept {
|
||||
TMat33 ret(TMat33::NO_INIT);
|
||||
ret[0] = normalize(m[0]);
|
||||
ret[2] = normalize(cross(ret[0], m[1]));
|
||||
ret[1] = normalize(cross(ret[2], ret[0]));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a matrix suitable for transforming normals
|
||||
*
|
||||
* Note that the inverse-transpose of a matrix is equal to its cofactor matrix divided by its
|
||||
* determinant:
|
||||
*
|
||||
* transpose(inverse(M)) = cof(M) / det(M)
|
||||
*
|
||||
* The cofactor matrix is faster to compute than the inverse-transpose, and it can be argued
|
||||
* that it is a more correct way of transforming normals anyway. Some references from Dale
|
||||
* Weiler, Nathan Reed, Inigo Quilez, and Eric Lengyel:
|
||||
*
|
||||
* - https://github.com/graphitemaster/normals_revisited
|
||||
* - http://www.reedbeta.com/blog/normals-inverse-transpose-part-1/
|
||||
* - https://www.shadertoy.com/view/3s33zj
|
||||
* - FGED Volume 1, section 1.7.5 "Inverses of Small Matrices"
|
||||
* - FGED Volume 1, section 3.2.2 "Transforming Normal Vectors"
|
||||
*
|
||||
* In "Transforming Normal Vectors", Lengyel notes that there are two types of transformed
|
||||
* normals: one that uses the transposed adjugate (aka cofactor matrix) and one that uses the
|
||||
* transposed inverse. He goes on to say that this difference is inconsequential, except when
|
||||
* mirroring is involved.
|
||||
*
|
||||
* @param m the transform applied to vertices
|
||||
* @return a matrix to apply to normals
|
||||
*
|
||||
* @warning normals transformed by this matrix must be normalized
|
||||
*/
|
||||
static constexpr TMat33 getTransformForNormals(const TMat33& m) noexcept {
|
||||
return matrix::cof(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Packs the tangent frame represented by the specified matrix into a quaternion.
|
||||
* Reflection is preserved by encoding it as the sign of the w component in the
|
||||
* resulting quaternion. Since -0 cannot always be represented on the GPU, this
|
||||
* function computes a bias to ensure values are always either positive or negative,
|
||||
* never 0. The bias is computed based on the specified storageSize, which defaults
|
||||
* to 2 bytes, making the resulting quaternion suitable for storage into an SNORM16
|
||||
* vector.
|
||||
*/
|
||||
static constexpr TQuaternion<T> packTangentFrame(
|
||||
const TMat33& m, size_t storageSize = sizeof(int16_t)) noexcept;
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat33 translation(const TVec3<A>& t) noexcept {
|
||||
TMat33 r;
|
||||
r[2] = t;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat33 scaling(const TVec3<A>& s) noexcept {
|
||||
return TMat33{ s };
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat33 scaling(A s) noexcept {
|
||||
return TMat33{ TVec3<T>{ s }};
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// Constructors
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
// Since the matrix code could become pretty big quickly, we don't inline most
|
||||
// operations.
|
||||
|
||||
template<typename T>
|
||||
constexpr TMat33<T>::TMat33() noexcept
|
||||
: m_value{
|
||||
col_type(1, 0, 0),
|
||||
col_type(0, 1, 0),
|
||||
col_type(0, 0, 1) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat33<T>::TMat33(U v) noexcept
|
||||
: m_value{
|
||||
col_type(v, 0, 0),
|
||||
col_type(0, v, 0),
|
||||
col_type(0, 0, v) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat33<T>::TMat33(const TVec3<U>& v) noexcept
|
||||
: m_value{
|
||||
col_type(v[0], 0, 0),
|
||||
col_type(0, v[1], 0),
|
||||
col_type(0, 0, v[2]) } {
|
||||
}
|
||||
|
||||
// construct from 16 scalars. Note that the arrangement
|
||||
// of values in the constructor is the transpose of the matrix
|
||||
// notation.
|
||||
template<typename T>
|
||||
template<
|
||||
typename A, typename B, typename C,
|
||||
typename D, typename E, typename F,
|
||||
typename G, typename H, typename I>
|
||||
constexpr TMat33<T>::TMat33(A m00, B m01, C m02,
|
||||
D m10, E m11, F m12,
|
||||
G m20, H m21, I m22) noexcept
|
||||
: m_value{
|
||||
col_type(m00, m01, m02),
|
||||
col_type(m10, m11, m12),
|
||||
col_type(m20, m21, m22) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat33<T>::TMat33(const TMat33<U>& rhs) noexcept {
|
||||
for (size_t col = 0; col < NUM_COLS; ++col) {
|
||||
m_value[col] = col_type(rhs[col]);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct from 3 column vectors.
|
||||
template<typename T>
|
||||
template<typename A, typename B, typename C>
|
||||
constexpr TMat33<T>::TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2) noexcept
|
||||
: m_value{ v0, v1, v2 } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat33<T>::TMat33(const TQuaternion<U>& q) noexcept : m_value{} {
|
||||
const U n = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
|
||||
const U s = n > 0 ? 2 / n : 0;
|
||||
const U x = s * q.x;
|
||||
const U y = s * q.y;
|
||||
const U z = s * q.z;
|
||||
const U xx = x * q.x;
|
||||
const U xy = x * q.y;
|
||||
const U xz = x * q.z;
|
||||
const U xw = x * q.w;
|
||||
const U yy = y * q.y;
|
||||
const U yz = y * q.z;
|
||||
const U yw = y * q.w;
|
||||
const U zz = z * q.z;
|
||||
const U zw = z * q.w;
|
||||
m_value[0] = col_type(1 - yy - zz, xy + zw, xz - yw); // NOLINT
|
||||
m_value[1] = col_type(xy - zw, 1 - xx - zz, yz + xw); // NOLINT
|
||||
m_value[2] = col_type(xz + yw, yz - xw, 1 - xx - yy); // NOLINT
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename T>
|
||||
constexpr TQuaternion<T> TMat33<T>::packTangentFrame(const TMat33<T>& m, size_t storageSize) noexcept {
|
||||
TQuaternion<T> q = TMat33<T>{ m[0], cross(m[2], m[0]), m[2] }.toQuaternion();
|
||||
q = positive(normalize(q));
|
||||
|
||||
// Ensure w is never 0.0
|
||||
// Bias is 2^(nb_bits - 1) - 1
|
||||
const T bias = T(1.0) / T((1 << (storageSize * CHAR_BIT - 1)) - 1);
|
||||
if (q.w < bias) {
|
||||
q.w = bias;
|
||||
|
||||
const T factor = (T)(std::sqrt(1.0 - (double)bias * (double)bias));
|
||||
q.xyz *= factor;
|
||||
}
|
||||
|
||||
// If there's a reflection ((n x t) . b <= 0), make sure w is negative
|
||||
if (dot(cross(m[0], m[2]), m[1]) < T(0)) {
|
||||
q = -q;
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
typedef details::TMat33<double> mat3;
|
||||
typedef details::TMat33<float> mat3f;
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
constexpr void swap(filament::math::details::TMat33<T>& lhs,
|
||||
filament::math::details::TMat33<T>& rhs) noexcept {
|
||||
// This generates much better code than the default implementation
|
||||
// It's unclear why, I believe this is due to an optimization bug in the clang.
|
||||
//
|
||||
// filament::math::details::TMat33<T> t(lhs);
|
||||
// lhs = rhs;
|
||||
// rhs = t;
|
||||
//
|
||||
// clang always copy lhs on the stack, even if it's never using it (it's using the
|
||||
// copy it has in registers).
|
||||
|
||||
const T t00 = lhs[0][0];
|
||||
const T t01 = lhs[0][1];
|
||||
const T t02 = lhs[0][2];
|
||||
const T t10 = lhs[1][0];
|
||||
const T t11 = lhs[1][1];
|
||||
const T t12 = lhs[1][2];
|
||||
const T t20 = lhs[2][0];
|
||||
const T t21 = lhs[2][1];
|
||||
const T t22 = lhs[2][2];
|
||||
|
||||
lhs[0][0] = rhs[0][0];
|
||||
lhs[0][1] = rhs[0][1];
|
||||
lhs[0][2] = rhs[0][2];
|
||||
lhs[1][0] = rhs[1][0];
|
||||
lhs[1][1] = rhs[1][1];
|
||||
lhs[1][2] = rhs[1][2];
|
||||
lhs[2][0] = rhs[2][0];
|
||||
lhs[2][1] = rhs[2][1];
|
||||
lhs[2][2] = rhs[2][2];
|
||||
|
||||
rhs[0][0] = t00;
|
||||
rhs[0][1] = t01;
|
||||
rhs[0][2] = t02;
|
||||
rhs[1][0] = t10;
|
||||
rhs[1][1] = t11;
|
||||
rhs[1][2] = t12;
|
||||
rhs[2][0] = t20;
|
||||
rhs[2][1] = t21;
|
||||
rhs[2][2] = t22;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MATH_MAT3_H_
|
||||
631
ios/include/math/mat4.h
Normal file
631
ios/include/math/mat4.h
Normal file
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* 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 MATH_MAT4_H_
|
||||
#define MATH_MAT4_H_
|
||||
|
||||
#include <math/compiler.h>
|
||||
#include <math/mat3.h>
|
||||
#include <math/quat.h>
|
||||
#include <math/scalar.h>
|
||||
#include <math/TMatHelpers.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <limits>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
// -------------------------------------------------------------------------------------
|
||||
namespace details {
|
||||
|
||||
template<typename T>
|
||||
class TQuaternion;
|
||||
|
||||
/**
|
||||
* A 4x4 column-major matrix class.
|
||||
*
|
||||
* Conceptually a 4x4 matrix is a an array of 4 column double4:
|
||||
*
|
||||
* mat4 m =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cccc}
|
||||
* m[0] & m[1] & m[2] & m[3] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
* =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cccc}
|
||||
* m[0][0] & m[1][0] & m[2][0] & m[3][0] \\
|
||||
* m[0][1] & m[1][1] & m[2][1] & m[3][1] \\
|
||||
* m[0][2] & m[1][2] & m[2][2] & m[3][2] \\
|
||||
* m[0][3] & m[1][3] & m[2][3] & m[3][3] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
* =
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cccc}
|
||||
* m(0,0) & m(0,1) & m(0,2) & m(0,3) \\
|
||||
* m(1,0) & m(1,1) & m(1,2) & m(1,3) \\
|
||||
* m(2,0) & m(2,1) & m(2,2) & m(2,3) \\
|
||||
* m(3,0) & m(3,1) & m(3,2) & m(3,3) \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*
|
||||
* m[n] is the \f$ n^{th} \f$ column of the matrix and is a double4.
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
class MATH_EMPTY_BASES TMat44 :
|
||||
public TVecUnaryOperators<TMat44, T>,
|
||||
public TVecComparisonOperators<TMat44, T>,
|
||||
public TVecAddOperators<TMat44, T>,
|
||||
public TMatProductOperators<TMat44, T, TVec4>,
|
||||
public TMatSquareFunctions<TMat44, T>,
|
||||
public TMatTransform<TMat44, T>,
|
||||
public TMatHelpers<TMat44, T> {
|
||||
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<T> col_type;
|
||||
typedef TVec4<T> row_type;
|
||||
|
||||
static constexpr size_t COL_SIZE = col_type::SIZE; // size of a column (i.e.: number of rows)
|
||||
static constexpr size_t ROW_SIZE = row_type::SIZE; // size of a row (i.e.: number of columns)
|
||||
static constexpr size_t NUM_ROWS = COL_SIZE;
|
||||
static constexpr size_t NUM_COLS = ROW_SIZE;
|
||||
|
||||
private:
|
||||
/*
|
||||
* <-- N columns -->
|
||||
*
|
||||
* a[0][0] a[1][0] a[2][0] ... a[N][0] ^
|
||||
* a[0][1] a[1][1] a[2][1] ... a[N][1] |
|
||||
* a[0][2] a[1][2] a[2][2] ... a[N][2] M rows
|
||||
* ... |
|
||||
* a[0][M] a[1][M] a[2][M] ... a[N][M] v
|
||||
*
|
||||
* COL_SIZE = M
|
||||
* ROW_SIZE = N
|
||||
* m[0] = [ a[0][0] a[0][1] a[0][2] ... a[0][M] ]
|
||||
*/
|
||||
|
||||
col_type m_value[NUM_COLS];
|
||||
|
||||
public:
|
||||
// array access
|
||||
inline constexpr col_type const& operator[](size_t column) const noexcept {
|
||||
assert(column < NUM_COLS);
|
||||
return m_value[column];
|
||||
}
|
||||
|
||||
inline constexpr col_type& operator[](size_t column) noexcept {
|
||||
assert(column < NUM_COLS);
|
||||
return m_value[column];
|
||||
}
|
||||
|
||||
/*
|
||||
* constructors
|
||||
*/
|
||||
|
||||
// leaves object uninitialized. use with caution.
|
||||
constexpr explicit TMat44(no_init) noexcept {}
|
||||
|
||||
/** initialize to identity.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cccc}
|
||||
* 1 & 0 & 0 & 0 \\
|
||||
* 0 & 1 & 0 & 0 \\
|
||||
* 0 & 0 & 1 & 0 \\
|
||||
* 0 & 0 & 0 & 1 \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
constexpr TMat44() noexcept;
|
||||
|
||||
/** initialize to Identity*scalar.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cccc}
|
||||
* v & 0 & 0 & 0 \\
|
||||
* 0 & v & 0 & 0 \\
|
||||
* 0 & 0 & v & 0 \\
|
||||
* 0 & 0 & 0 & v \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat44(U v) noexcept;
|
||||
|
||||
/** sets the diagonal to a vector.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cccc}
|
||||
* v[0] & 0 & 0 & 0 \\
|
||||
* 0 & v[1] & 0 & 0 \\
|
||||
* 0 & 0 & v[2] & 0 \\
|
||||
* 0 & 0 & 0 & v[3] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat44(const TVec4<U>& v) noexcept;
|
||||
|
||||
// construct from another matrix of the same size
|
||||
template<typename U>
|
||||
constexpr explicit TMat44(const TMat44<U>& rhs) noexcept;
|
||||
|
||||
/** construct from 4 column vectors.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cccc}
|
||||
* v0 & v1 & v2 & v3 \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
template<typename A, typename B, typename C, typename D>
|
||||
constexpr TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2,
|
||||
const TVec4<D>& v3) noexcept;
|
||||
|
||||
/** construct from 16 elements in column-major form.
|
||||
*
|
||||
* \f$
|
||||
* \left(
|
||||
* \begin{array}{cccc}
|
||||
* m[0][0] & m[1][0] & m[2][0] & m[3][0] \\
|
||||
* m[0][1] & m[1][1] & m[2][1] & m[3][1] \\
|
||||
* m[0][2] & m[1][2] & m[2][2] & m[3][2] \\
|
||||
* m[0][3] & m[1][3] & m[2][3] & m[3][3] \\
|
||||
* \end{array}
|
||||
* \right)
|
||||
* \f$
|
||||
*/
|
||||
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>
|
||||
constexpr explicit 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) noexcept;
|
||||
|
||||
|
||||
struct row_major_init {
|
||||
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>
|
||||
constexpr explicit row_major_init(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) noexcept
|
||||
: m(m00, m10, m20, m30,
|
||||
m01, m11, m21, m31,
|
||||
m02, m12, m22, m32,
|
||||
m03, m13, m23, m33) {}
|
||||
|
||||
private:
|
||||
friend TMat44;
|
||||
TMat44 m;
|
||||
};
|
||||
|
||||
constexpr explicit TMat44(row_major_init c) noexcept : TMat44(std::move(c.m)) {}
|
||||
|
||||
/**
|
||||
* construct from a quaternion
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat44(const TQuaternion<U>& q) noexcept;
|
||||
|
||||
/**
|
||||
* construct from a 3x3 matrix
|
||||
*/
|
||||
template<typename U>
|
||||
constexpr explicit TMat44(const TMat33<U>& matrix) noexcept;
|
||||
|
||||
/**
|
||||
* construct from a 3x3 matrix and 3d translation
|
||||
*/
|
||||
template<typename U, typename V>
|
||||
constexpr TMat44(const TMat33<U>& matrix, const TVec3<V>& translation) noexcept;
|
||||
|
||||
/**
|
||||
* construct from a 3x3 matrix and 4d last column.
|
||||
*/
|
||||
template<typename U, typename V>
|
||||
constexpr TMat44(const TMat33<U>& matrix, const TVec4<V>& column3) noexcept;
|
||||
|
||||
/*
|
||||
* helpers
|
||||
*/
|
||||
|
||||
// returns false if the two matrices are different. May return false if they're the
|
||||
// same, with some elements only differing by +0 or -0. Behaviour is undefined with NaNs.
|
||||
static constexpr bool fuzzyEqual(TMat44 const& l, TMat44 const& r) noexcept {
|
||||
uint64_t const* const li = reinterpret_cast<uint64_t const*>(&l);
|
||||
uint64_t const* const ri = reinterpret_cast<uint64_t const*>(&r);
|
||||
uint64_t result = 0;
|
||||
// For some reason clang is not able to vectorize this loop when the number of iteration
|
||||
// is known and constant (!?!?!). Still this is better than operator==.
|
||||
for (size_t i = 0; i < sizeof(TMat44) / sizeof(uint64_t); i++) {
|
||||
result |= li[i] ^ ri[i];
|
||||
}
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
static constexpr TMat44 ortho(T left, T right, T bottom, T top, T near, T far) noexcept;
|
||||
|
||||
static constexpr TMat44 frustum(T left, T right, T bottom, T top, T near, T far) noexcept;
|
||||
|
||||
enum class Fov {
|
||||
HORIZONTAL,
|
||||
VERTICAL
|
||||
};
|
||||
static TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL) noexcept;
|
||||
|
||||
template<typename A, typename B, typename C>
|
||||
static TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) noexcept;
|
||||
|
||||
template<typename A>
|
||||
static constexpr TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) noexcept{
|
||||
TVec4<A> r = projectionMatrix * TVec4<A>{ vertice, 1 };
|
||||
return TVec3<A>{ r[0], r[1], r[2] } * (1 / r[3]);
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TVec4<A> project(const TMat44& projectionMatrix, TVec4<A> vertice) noexcept{
|
||||
vertice = projectionMatrix * vertice;
|
||||
return { TVec3<A>{ vertice[0], vertice[1], vertice[2] } * (1 / vertice[3]), 1 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a 3x3 matrix from the upper-left corner of this 4x4 matrix
|
||||
*/
|
||||
inline constexpr TMat33<T> upperLeft() const noexcept {
|
||||
const TVec3<T> v0 = { m_value[0][0], m_value[0][1], m_value[0][2] };
|
||||
const TVec3<T> v1 = { m_value[1][0], m_value[1][1], m_value[1][2] };
|
||||
const TVec3<T> v2 = { m_value[2][0], m_value[2][1], m_value[2][2] };
|
||||
return TMat33<T>(v0, v1, v2);
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat44 translation(const TVec3<A>& t) noexcept {
|
||||
TMat44 r;
|
||||
r[3] = TVec4<T>{ t, 1 };
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat44 scaling(const TVec3<A>& s) noexcept {
|
||||
return TMat44{ TVec4<T>{ s, 1 }};
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
static constexpr TMat44 scaling(A s) noexcept {
|
||||
return TMat44{ TVec4<T>{ s, s, s, 1 }};
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// Constructors
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
// Since the matrix code could become pretty big quickly, we don't inline most
|
||||
// operations.
|
||||
|
||||
template<typename T>
|
||||
constexpr TMat44<T>::TMat44() noexcept
|
||||
: m_value{
|
||||
col_type(1, 0, 0, 0),
|
||||
col_type(0, 1, 0, 0),
|
||||
col_type(0, 0, 1, 0),
|
||||
col_type(0, 0, 0, 1) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat44<T>::TMat44(U v) noexcept
|
||||
: m_value{
|
||||
col_type(v, 0, 0, 0),
|
||||
col_type(0, v, 0, 0),
|
||||
col_type(0, 0, v, 0),
|
||||
col_type(0, 0, 0, v) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat44<T>::TMat44(const TVec4<U>& v) noexcept
|
||||
: m_value{
|
||||
col_type(v[0], 0, 0, 0),
|
||||
col_type(0, v[1], 0, 0),
|
||||
col_type(0, 0, v[2], 0),
|
||||
col_type(0, 0, 0, v[3]) } {
|
||||
}
|
||||
|
||||
|
||||
// construct from 16 scalars
|
||||
template<typename T>
|
||||
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>
|
||||
constexpr TMat44<T>::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) noexcept
|
||||
: m_value{
|
||||
col_type(m00, m01, m02, m03),
|
||||
col_type(m10, m11, m12, m13),
|
||||
col_type(m20, m21, m22, m23),
|
||||
col_type(m30, m31, m32, m33) } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat44<T>::TMat44(const TMat44<U>& rhs) noexcept {
|
||||
for (size_t col = 0; col < NUM_COLS; ++col) {
|
||||
m_value[col] = col_type(rhs[col]);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct from 4 column vectors.
|
||||
template<typename T>
|
||||
template<typename A, typename B, typename C, typename D>
|
||||
constexpr TMat44<T>::TMat44(const TVec4<A>& v0, const TVec4<B>& v1,
|
||||
const TVec4<C>& v2, const TVec4<D>& v3) noexcept
|
||||
: m_value{ v0, v1, v2, v3 } {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat44<T>::TMat44(const TQuaternion<U>& q) noexcept : m_value{} {
|
||||
const U n = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
|
||||
const U s = n > 0 ? 2 / n : 0;
|
||||
const U x = s * q.x;
|
||||
const U y = s * q.y;
|
||||
const U z = s * q.z;
|
||||
const U xx = x * q.x;
|
||||
const U xy = x * q.y;
|
||||
const U xz = x * q.z;
|
||||
const U xw = x * q.w;
|
||||
const U yy = y * q.y;
|
||||
const U yz = y * q.z;
|
||||
const U yw = y * q.w;
|
||||
const U zz = z * q.z;
|
||||
const U zw = z * q.w;
|
||||
m_value[0] = col_type(1 - yy - zz, xy + zw, xz - yw, 0);
|
||||
m_value[1] = col_type(xy - zw, 1 - xx - zz, yz + xw, 0); // NOLINT
|
||||
m_value[2] = col_type(xz + yw, yz - xw, 1 - xx - yy, 0); // NOLINT
|
||||
m_value[3] = col_type(0, 0, 0, 1); // NOLINT
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr TMat44<T>::TMat44(const TMat33<U>& m) noexcept
|
||||
: m_value{
|
||||
col_type(m[0][0], m[0][1], m[0][2], 0),
|
||||
col_type(m[1][0], m[1][1], m[1][2], 0),
|
||||
col_type(m[2][0], m[2][1], m[2][2], 0),
|
||||
col_type(0, 0, 0, 1) } // NOLINT
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U, typename V>
|
||||
constexpr TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) noexcept
|
||||
: m_value{
|
||||
col_type(m[0][0], m[0][1], m[0][2], 0),
|
||||
col_type(m[1][0], m[1][1], m[1][2], 0),
|
||||
col_type(m[2][0], m[2][1], m[2][2], 0),
|
||||
col_type(v[0], v[1], v[2], 1) } // NOLINT
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U, typename V>
|
||||
constexpr TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) noexcept
|
||||
: m_value{
|
||||
col_type(m[0][0], m[0][1], m[0][2], 0),
|
||||
col_type(m[1][0], m[1][1], m[1][2], 0),
|
||||
col_type(m[2][0], m[2][1], m[2][2], 0),
|
||||
col_type(v[0], v[1], v[2], v[3]) } // NOLINT
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
constexpr TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) noexcept {
|
||||
TMat44<T> 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<typename T>
|
||||
constexpr TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) noexcept {
|
||||
TMat44<T> m;
|
||||
m[0][0] = (2 * near) / (right - left);
|
||||
m[1][1] = (2 * near) / (top - bottom);
|
||||
m[2][0] = (right + left) / (right - left);
|
||||
m[2][1] = (top + bottom) / (top - bottom);
|
||||
m[2][2] = -(far + near) / (far - near);
|
||||
m[2][3] = -1;
|
||||
m[3][2] = -(2 * far * near) / (far - near);
|
||||
m[3][3] = 0;
|
||||
return m;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) noexcept {
|
||||
T h, w;
|
||||
|
||||
if (direction == TMat44::Fov::VERTICAL) {
|
||||
h = std::tan(fov * F_PI / 360.0f) * near;
|
||||
w = h * aspect;
|
||||
} else {
|
||||
w = std::tan(fov * F_PI / 360.0f) * near;
|
||||
h = w / aspect;
|
||||
}
|
||||
return frustum(-w, w, -h, h, near, far);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a matrix representing the pose of a virtual camera looking towards -Z in its
|
||||
* local Y-up coordinate system. "eye" is where the camera is located, "center" is the point it's
|
||||
* looking at and "up" defines where the Y axis of the camera's local coordinate system is.
|
||||
*/
|
||||
template<typename T>
|
||||
template<typename A, typename B, typename C>
|
||||
TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center,
|
||||
const TVec3<C>& up) noexcept {
|
||||
TVec3<T> z_axis(normalize(center - eye));
|
||||
TVec3<T> norm_up(normalize(up));
|
||||
if (std::abs(dot(z_axis, norm_up)) > T(0.999)) {
|
||||
// Fix up vector if we're degenerate (looking straight up, basically)
|
||||
norm_up = { norm_up.z, norm_up.x, norm_up.y };
|
||||
}
|
||||
TVec3<T> x_axis(normalize(cross(z_axis, norm_up)));
|
||||
TVec3<T> y_axis(cross(x_axis, z_axis));
|
||||
return TMat44<T>(
|
||||
TVec4<T>(x_axis, 0),
|
||||
TVec4<T>(y_axis, 0),
|
||||
TVec4<T>(-z_axis, 0),
|
||||
TVec4<T>(eye, 1));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// Arithmetic operators outside of class
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
// mat44 * vec3, result is vec3( mat44 * {vec3, 1} )
|
||||
template<typename T, typename U>
|
||||
constexpr typename TMat44<T>::col_type MATH_PURE operator*(const TMat44<T>& lhs,
|
||||
const TVec3<U>& rhs) noexcept {
|
||||
return lhs * TVec4<U>{ rhs, 1 };
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
typedef details::TMat44<double> mat4;
|
||||
typedef details::TMat44<float> mat4f;
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
constexpr void swap(filament::math::details::TMat44<T>& lhs,
|
||||
filament::math::details::TMat44<T>& rhs) noexcept {
|
||||
// This generates much better code than the default implementation
|
||||
// It's unclear why, I believe this is due to an optimization bug in the clang.
|
||||
//
|
||||
// filament::math::details::TMat44<T> t(lhs);
|
||||
// lhs = rhs;
|
||||
// rhs = t;
|
||||
//
|
||||
// clang always copy lhs on the stack, even if it's never using it (it's using the
|
||||
// copy it has in registers).
|
||||
|
||||
const T t00 = lhs[0][0];
|
||||
const T t01 = lhs[0][1];
|
||||
const T t02 = lhs[0][2];
|
||||
const T t03 = lhs[0][3];
|
||||
const T t10 = lhs[1][0];
|
||||
const T t11 = lhs[1][1];
|
||||
const T t12 = lhs[1][2];
|
||||
const T t13 = lhs[1][3];
|
||||
const T t20 = lhs[2][0];
|
||||
const T t21 = lhs[2][1];
|
||||
const T t22 = lhs[2][2];
|
||||
const T t23 = lhs[2][3];
|
||||
const T t30 = lhs[3][0];
|
||||
const T t31 = lhs[3][1];
|
||||
const T t32 = lhs[3][2];
|
||||
const T t33 = lhs[3][3];
|
||||
|
||||
lhs[0][0] = rhs[0][0];
|
||||
lhs[0][1] = rhs[0][1];
|
||||
lhs[0][2] = rhs[0][2];
|
||||
lhs[0][3] = rhs[0][3];
|
||||
lhs[1][0] = rhs[1][0];
|
||||
lhs[1][1] = rhs[1][1];
|
||||
lhs[1][2] = rhs[1][2];
|
||||
lhs[1][3] = rhs[1][3];
|
||||
lhs[2][0] = rhs[2][0];
|
||||
lhs[2][1] = rhs[2][1];
|
||||
lhs[2][2] = rhs[2][2];
|
||||
lhs[2][3] = rhs[2][3];
|
||||
lhs[3][0] = rhs[3][0];
|
||||
lhs[3][1] = rhs[3][1];
|
||||
lhs[3][2] = rhs[3][2];
|
||||
lhs[3][3] = rhs[3][3];
|
||||
|
||||
rhs[0][0] = t00;
|
||||
rhs[0][1] = t01;
|
||||
rhs[0][2] = t02;
|
||||
rhs[0][3] = t03;
|
||||
rhs[1][0] = t10;
|
||||
rhs[1][1] = t11;
|
||||
rhs[1][2] = t12;
|
||||
rhs[1][3] = t13;
|
||||
rhs[2][0] = t20;
|
||||
rhs[2][1] = t21;
|
||||
rhs[2][2] = t22;
|
||||
rhs[2][3] = t23;
|
||||
rhs[3][0] = t30;
|
||||
rhs[3][1] = t31;
|
||||
rhs[3][2] = t32;
|
||||
rhs[3][3] = t33;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MATH_MAT4_H_
|
||||
94
ios/include/math/mathfwd.h
Normal file
94
ios/include/math/mathfwd.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 MATH_MATHFWD_H_
|
||||
#define MATH_MATHFWD_H_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// MSVC cannot compute the size of math types correctly when this file is included before the
|
||||
// actual implementations.
|
||||
// See github.com/google/filament/issues/2190.
|
||||
#include <math/vec2.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <math/mat2.h>
|
||||
#include <math/mat3.h>
|
||||
#include <math/mat4.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
namespace details {
|
||||
|
||||
template<typename T> class TVec2;
|
||||
template<typename T> class TVec3;
|
||||
template<typename T> class TVec4;
|
||||
|
||||
template<typename T> class TMat22;
|
||||
template<typename T> class TMat33;
|
||||
template<typename T> class TMat44;
|
||||
|
||||
} // namespace details
|
||||
|
||||
using double2 = details::TVec2<double>;
|
||||
using float2 = details::TVec2<float>;
|
||||
using int2 = details::TVec2<int32_t>;
|
||||
using uint2 = details::TVec2<uint32_t>;
|
||||
using short2 = details::TVec2<int16_t>;
|
||||
using ushort2 = details::TVec2<uint16_t>;
|
||||
using byte2 = details::TVec2<int8_t>;
|
||||
using ubyte2 = details::TVec2<uint8_t>;
|
||||
using bool2 = details::TVec2<bool>;
|
||||
|
||||
using double3 = details::TVec3<double>;
|
||||
using float3 = details::TVec3<float>;
|
||||
using int3 = details::TVec3<int32_t>;
|
||||
using uint3 = details::TVec3<uint32_t>;
|
||||
using short3 = details::TVec3<int16_t>;
|
||||
using ushort3 = details::TVec3<uint16_t>;
|
||||
using byte3 = details::TVec3<int8_t>;
|
||||
using ubyte3 = details::TVec3<uint8_t>;
|
||||
using bool3 = details::TVec3<bool>;
|
||||
|
||||
using double4 = details::TVec4<double>;
|
||||
using float4 = details::TVec4<float>;
|
||||
using int4 = details::TVec4<int32_t>;
|
||||
using uint4 = details::TVec4<uint32_t>;
|
||||
using short4 = details::TVec4<int16_t>;
|
||||
using ushort4 = details::TVec4<uint16_t>;
|
||||
using byte4 = details::TVec4<int8_t>;
|
||||
using ubyte4 = details::TVec4<uint8_t>;
|
||||
using bool4 = details::TVec4<bool>;
|
||||
|
||||
using mat2 = details::TMat22<double>;
|
||||
using mat2f = details::TMat22<float>;
|
||||
|
||||
using mat3 = details::TMat33<double>;
|
||||
using mat3f = details::TMat33<float>;
|
||||
|
||||
using mat4 = details::TMat44<double>;
|
||||
using mat4f = details::TMat44<float>;
|
||||
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#endif // MATH_MATHFWD_H_
|
||||
100
ios/include/math/norm.h
Normal file
100
ios/include/math/norm.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 TNT_MATH_NORM_H
|
||||
#define TNT_MATH_NORM_H
|
||||
|
||||
#include <math/scalar.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
|
||||
inline uint16_t packUnorm16(float v) noexcept {
|
||||
return static_cast<uint16_t>(std::round(clamp(v, 0.0f, 1.0f) * 65535.0f));
|
||||
}
|
||||
|
||||
inline ushort4 packUnorm16(float4 v) noexcept {
|
||||
return ushort4{ packUnorm16(v.x), packUnorm16(v.y), packUnorm16(v.z), packUnorm16(v.w) };
|
||||
}
|
||||
|
||||
inline int16_t packSnorm16(float v) noexcept {
|
||||
return static_cast<int16_t>(std::round(clamp(v, -1.0f, 1.0f) * 32767.0f));
|
||||
}
|
||||
|
||||
inline short2 packSnorm16(float2 v) noexcept {
|
||||
return short2{ packSnorm16(v.x), packSnorm16(v.y) };
|
||||
}
|
||||
|
||||
inline short4 packSnorm16(float4 v) noexcept {
|
||||
return short4{ packSnorm16(v.x), packSnorm16(v.y), packSnorm16(v.z), packSnorm16(v.w) };
|
||||
}
|
||||
|
||||
inline float unpackUnorm16(uint16_t v) noexcept {
|
||||
return v / 65535.0f;
|
||||
}
|
||||
|
||||
inline float4 unpackUnorm16(ushort4 v) noexcept {
|
||||
return float4{ unpackUnorm16(v.x), unpackUnorm16(v.y), unpackUnorm16(v.z), unpackUnorm16(v.w) };
|
||||
}
|
||||
|
||||
inline float unpackSnorm16(int16_t v) noexcept {
|
||||
return clamp(v / 32767.0f, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
inline float4 unpackSnorm16(short4 v) noexcept {
|
||||
return float4{ unpackSnorm16(v.x), unpackSnorm16(v.y), unpackSnorm16(v.z), unpackSnorm16(v.w) };
|
||||
}
|
||||
|
||||
inline uint8_t packUnorm8(float v) noexcept {
|
||||
return static_cast<uint8_t>(std::round(clamp(v, 0.0f, 1.0f) * 255.0));
|
||||
}
|
||||
|
||||
inline ubyte4 packUnorm8(float4 v) noexcept {
|
||||
return ubyte4{ packUnorm8(v.x), packUnorm8(v.y), packUnorm8(v.z), packUnorm8(v.w) };
|
||||
}
|
||||
|
||||
inline int8_t packSnorm8(float v) noexcept {
|
||||
return static_cast<int8_t>(std::round(clamp(v, -1.0f, 1.0f) * 127.0));
|
||||
}
|
||||
|
||||
inline byte4 packSnorm8(float4 v) noexcept {
|
||||
return byte4{ packSnorm8(v.x), packSnorm8(v.y), packSnorm8(v.z), packSnorm8(v.w) };
|
||||
}
|
||||
|
||||
inline float unpackUnorm8(uint8_t v) noexcept {
|
||||
return v / 255.0f;
|
||||
}
|
||||
|
||||
inline float4 unpackUnorm8(ubyte4 v) noexcept {
|
||||
return float4{ unpackUnorm8(v.x), unpackUnorm8(v.y), unpackUnorm8(v.z), unpackUnorm8(v.w) };
|
||||
}
|
||||
|
||||
inline float unpackSnorm8(int8_t v) noexcept {
|
||||
return clamp(v / 127.0f, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
inline float4 unpackSnorm8(byte4 v) noexcept {
|
||||
return float4{ unpackSnorm8(v.x), unpackSnorm8(v.y), unpackSnorm8(v.z), unpackSnorm8(v.w) };
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_MATH_NORM_H
|
||||
167
ios/include/math/quat.h
Normal file
167
ios/include/math/quat.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (C) 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 MATH_QUAT_H_
|
||||
#define MATH_QUAT_H_
|
||||
|
||||
#include <math/half.h>
|
||||
#include <math/TQuatHelpers.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <math/compiler.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename T>
|
||||
class MATH_EMPTY_BASES TQuaternion :
|
||||
public TVecAddOperators<TQuaternion, T>,
|
||||
public TVecUnaryOperators<TQuaternion, T>,
|
||||
public TVecComparisonOperators<TQuaternion, T>,
|
||||
public TQuatProductOperators<TQuaternion, T>,
|
||||
public TQuatFunctions<TQuaternion, T> {
|
||||
public:
|
||||
enum no_init {
|
||||
NO_INIT
|
||||
};
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef size_t size_type;
|
||||
|
||||
/*
|
||||
* quaternion internals stored as:
|
||||
*
|
||||
* q = w + xi + yj + zk
|
||||
*
|
||||
* q[0] = x;
|
||||
* q[1] = y;
|
||||
* q[2] = z;
|
||||
* q[3] = w;
|
||||
*
|
||||
*/
|
||||
union {
|
||||
struct { T x, y, z, w; };
|
||||
TVec4<T> xyzw;
|
||||
TVec3<T> xyz;
|
||||
TVec2<T> xy;
|
||||
};
|
||||
|
||||
enum { SIZE = 4 };
|
||||
inline constexpr static size_type size() { return SIZE; }
|
||||
|
||||
// array access
|
||||
inline constexpr T const& operator[](size_t i) const {
|
||||
// only possible in C++0x14 with constexpr
|
||||
assert(i < SIZE);
|
||||
return (&x)[i];
|
||||
}
|
||||
|
||||
inline constexpr T& operator[](size_t i) {
|
||||
assert(i < SIZE);
|
||||
return (&x)[i];
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// we want the compiler generated versions for these...
|
||||
TQuaternion(const TQuaternion&) = default;
|
||||
~TQuaternion() = default;
|
||||
TQuaternion& operator=(const TQuaternion&) = default;
|
||||
|
||||
// constructors
|
||||
|
||||
// leaves object uninitialized. use with caution.
|
||||
explicit constexpr TQuaternion(no_init) {}
|
||||
|
||||
// default constructor. sets all values to zero.
|
||||
constexpr TQuaternion() : x(0), y(0), z(0), w(0) {}
|
||||
|
||||
// handles implicit conversion to a quat. must not be explicit.
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr TQuaternion(A w) : x(0), y(0), z(0), w(w) {}
|
||||
|
||||
// initialize from 4 values to w + xi + yj + zk
|
||||
template<typename A, typename B, typename C, typename D,
|
||||
typename = enable_if_arithmetic_t<A, B, C, D>>
|
||||
constexpr TQuaternion(A w, B x, C y, D z) : x(x), y(y), z(z), w(w) {}
|
||||
|
||||
// initialize from a vec3 + a value to : v.xi + v.yj + v.zk + w
|
||||
template<typename A, typename B, typename = enable_if_arithmetic_t<A, B>>
|
||||
constexpr TQuaternion(const TVec3<A>& v, B w) : x(v.x), y(v.y), z(v.z), w(w) {}
|
||||
|
||||
// initialize from a vec4
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr explicit TQuaternion(const TVec4<A>& v) : x(v.x), y(v.y), z(v.z), w(v.w) {}
|
||||
|
||||
// initialize from a quaternion of a different type
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr explicit TQuaternion(const TQuaternion<A>& v) : x(v.x), y(v.y), z(v.z), w(v.w) {}
|
||||
|
||||
// conjugate operator
|
||||
constexpr TQuaternion operator~() const {
|
||||
return conj(*this);
|
||||
}
|
||||
|
||||
// constructs a quaternion from an axis and angle
|
||||
template<typename A, typename B, typename = enable_if_arithmetic_t<A, B>>
|
||||
constexpr static TQuaternion MATH_PURE fromAxisAngle(const TVec3<A>& axis, B angle) {
|
||||
return TQuaternion(std::sin(angle * 0.5) * normalize(axis), std::cos(angle * 0.5));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
typedef details::TQuaternion<double> quat;
|
||||
typedef details::TQuaternion<float> quatf;
|
||||
typedef details::TQuaternion<half> quath;
|
||||
|
||||
constexpr inline quat operator "" _i(long double v) {
|
||||
return quat(0.0, double(v), 0.0, 0.0);
|
||||
}
|
||||
|
||||
constexpr inline quat operator "" _j(long double v) {
|
||||
return quat(0.0, 0.0, double(v), 0.0);
|
||||
}
|
||||
|
||||
constexpr inline quat operator "" _k(long double v) {
|
||||
return quat(0.0, 0.0, 0.0, double(v));
|
||||
}
|
||||
|
||||
constexpr inline quat operator "" _i(unsigned long long v) {
|
||||
return quat(0.0, double(v), 0.0, 0.0);
|
||||
}
|
||||
|
||||
constexpr inline quat operator "" _j(unsigned long long v) {
|
||||
return quat(0.0, 0.0, double(v), 0.0);
|
||||
}
|
||||
|
||||
constexpr inline quat operator "" _k(unsigned long long v) {
|
||||
return quat(0.0, 0.0, 0.0, double(v));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // MATH_QUAT_H_
|
||||
124
ios/include/math/scalar.h
Normal file
124
ios/include/math/scalar.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 TNT_MATH_SCALAR_H
|
||||
#define TNT_MATH_SCALAR_H
|
||||
|
||||
#include <math/compiler.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
|
||||
constexpr const double F_E = 2.71828182845904523536028747135266250;
|
||||
constexpr const double F_LOG2E = 1.44269504088896340735992468100189214;
|
||||
constexpr const double F_LOG10E = 0.434294481903251827651128918916605082;
|
||||
constexpr const double F_LN2 = 0.693147180559945309417232121458176568;
|
||||
constexpr const double F_LN10 = 2.30258509299404568401799145468436421;
|
||||
constexpr const double F_PI = 3.14159265358979323846264338327950288;
|
||||
constexpr const double F_PI_2 = 1.57079632679489661923132169163975144;
|
||||
constexpr const double F_PI_4 = 0.785398163397448309615660845819875721;
|
||||
constexpr const double F_1_PI = 0.318309886183790671537767526745028724;
|
||||
constexpr const double F_2_PI = 0.636619772367581343075535053490057448;
|
||||
constexpr const double F_2_SQRTPI = 1.12837916709551257389615890312154517;
|
||||
constexpr const double F_SQRT2 = 1.41421356237309504880168872420969808;
|
||||
constexpr const double F_SQRT1_2 = 0.707106781186547524400844362104849039;
|
||||
constexpr const double F_TAU = 2.0 * F_PI;
|
||||
|
||||
namespace d {
|
||||
constexpr const double E = F_E;
|
||||
constexpr const double LOG2E = F_LOG2E;
|
||||
constexpr const double LOG10E = F_LOG10E;
|
||||
constexpr const double LN2 = F_LN2;
|
||||
constexpr const double LN10 = F_LN10;
|
||||
constexpr const double PI = F_PI;
|
||||
constexpr const double PI_2 = F_PI_2;
|
||||
constexpr const double PI_4 = F_PI_4;
|
||||
constexpr const double ONE_OVER_PI = F_1_PI;
|
||||
constexpr const double TWO_OVER_PI = F_2_PI;
|
||||
constexpr const double TWO_OVER_SQRTPI = F_2_SQRTPI;
|
||||
constexpr const double SQRT2 = F_SQRT2;
|
||||
constexpr const double SQRT1_2 = F_SQRT1_2;
|
||||
constexpr const double TAU = F_TAU;
|
||||
constexpr const double DEG_TO_RAD = F_PI / 180.0;
|
||||
constexpr const double RAD_TO_DEG = 180.0 / F_PI;
|
||||
} // namespace d
|
||||
|
||||
namespace f {
|
||||
constexpr const float E = (float)d::E;
|
||||
constexpr const float LOG2E = (float)d::LOG2E;
|
||||
constexpr const float LOG10E = (float)d::LOG10E;
|
||||
constexpr const float LN2 = (float)d::LN2;
|
||||
constexpr const float LN10 = (float)d::LN10;
|
||||
constexpr const float PI = (float)d::PI;
|
||||
constexpr const float PI_2 = (float)d::PI_2;
|
||||
constexpr const float PI_4 = (float)d::PI_4;
|
||||
constexpr const float ONE_OVER_PI = (float)d::ONE_OVER_PI;
|
||||
constexpr const float TWO_OVER_PI = (float)d::TWO_OVER_PI;
|
||||
constexpr const float TWO_OVER_SQRTPI = (float)d::TWO_OVER_SQRTPI;
|
||||
constexpr const float SQRT2 = (float)d::SQRT2;
|
||||
constexpr const float SQRT1_2 = (float)d::SQRT1_2;
|
||||
constexpr const float TAU = (float)d::TAU;
|
||||
constexpr const float DEG_TO_RAD = (float)d::DEG_TO_RAD;
|
||||
constexpr const float RAD_TO_DEG = (float)d::RAD_TO_DEG;
|
||||
} // namespace f
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T MATH_PURE min(T a, T b) noexcept {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T MATH_PURE max(T a, T b) noexcept {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T MATH_PURE clamp(T v, T min, T max) noexcept {
|
||||
assert(min <= max);
|
||||
return T(math::min(max, math::max(min, v)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T MATH_PURE saturate(T v) noexcept {
|
||||
return clamp(v, T(0), T(1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T MATH_PURE mix(T x, T y, T a) noexcept {
|
||||
return x * (T(1) - a) + y * a;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T MATH_PURE lerp(T x, T y, T a) noexcept {
|
||||
return mix(x, y, a);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T MATH_PURE smoothstep(T e0, T e1, T x) noexcept {
|
||||
T t = clamp((x - e0) / (e1 - e0), T(0), T(1));
|
||||
return t * t * (T(3) - T(2) * t);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T sign(T x) noexcept {
|
||||
return x < T(0) ? T(-1) : T(1);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_MATH_SCALAR_H
|
||||
113
ios/include/math/vec2.h
Normal file
113
ios/include/math/vec2.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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 MATH_VEC2_H_
|
||||
#define MATH_VEC2_H_
|
||||
|
||||
#include <math/TVecHelpers.h>
|
||||
#include <math/half.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename T>
|
||||
class MATH_EMPTY_BASES TVec2 :
|
||||
public TVecProductOperators<TVec2, T>,
|
||||
public TVecAddOperators<TVec2, T>,
|
||||
public TVecUnaryOperators<TVec2, T>,
|
||||
public TVecComparisonOperators<TVec2, T>,
|
||||
public TVecFunctions<TVec2, T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef size_t size_type;
|
||||
static constexpr size_t SIZE = 2;
|
||||
|
||||
union {
|
||||
T v[SIZE] MATH_CONSTEXPR_INIT;
|
||||
struct { T x, y; };
|
||||
struct { T s, t; };
|
||||
struct { T r, g; };
|
||||
};
|
||||
|
||||
inline constexpr size_type size() const { return SIZE; }
|
||||
|
||||
// array access
|
||||
inline constexpr T const& operator[](size_t i) const noexcept {
|
||||
assert(i < SIZE);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline constexpr T& operator[](size_t i) noexcept {
|
||||
assert(i < SIZE);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
// constructors
|
||||
|
||||
// default constructor
|
||||
MATH_DEFAULT_CTOR_CONSTEXPR TVec2() MATH_DEFAULT_CTOR
|
||||
|
||||
// handles implicit conversion to a tvec4. must not be explicit.
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr TVec2(A v) noexcept : v{ T(v), T(v) } {}
|
||||
|
||||
template<typename A, typename B, typename = enable_if_arithmetic_t<A, B>>
|
||||
constexpr TVec2(A x, B y) noexcept : v{ T(x), T(y) } {}
|
||||
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr TVec2(const TVec2<A>& v) noexcept : v{ T(v[0]), T(v[1]) } {}
|
||||
|
||||
// cross product works only on vectors of size 2 or 3
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
arithmetic_result_t<T, U> cross(const TVec2& u, const TVec2<U>& v) noexcept {
|
||||
return u[0] * v[1] - u[1] * v[0];
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T, typename = details::enable_if_arithmetic_t<T>>
|
||||
using vec2 = details::TVec2<T>;
|
||||
|
||||
using double2 = vec2<double>;
|
||||
using float2 = vec2<float>;
|
||||
using half2 = vec2<half>;
|
||||
using int2 = vec2<int32_t>;
|
||||
using uint2 = vec2<uint32_t>;
|
||||
using short2 = vec2<int16_t>;
|
||||
using ushort2 = vec2<uint16_t>;
|
||||
using byte2 = vec2<int8_t>;
|
||||
using ubyte2 = vec2<uint8_t>;
|
||||
using bool2 = vec2<bool>;
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // MATH_VEC2_H_
|
||||
133
ios/include/math/vec3.h
Normal file
133
ios/include/math/vec3.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 MATH_VEC3_H_
|
||||
#define MATH_VEC3_H_
|
||||
|
||||
#include <math/vec2.h>
|
||||
#include <math/half.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename T>
|
||||
class MATH_EMPTY_BASES TVec3 :
|
||||
public TVecProductOperators<TVec3, T>,
|
||||
public TVecAddOperators<TVec3, T>,
|
||||
public TVecUnaryOperators<TVec3, T>,
|
||||
public TVecComparisonOperators<TVec3, T>,
|
||||
public TVecFunctions<TVec3, T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef size_t size_type;
|
||||
static constexpr size_t SIZE = 3;
|
||||
|
||||
union {
|
||||
T v[SIZE] MATH_CONSTEXPR_INIT;
|
||||
TVec2<T> xy;
|
||||
TVec2<T> st;
|
||||
TVec2<T> rg;
|
||||
struct {
|
||||
union {
|
||||
T x;
|
||||
T s;
|
||||
T r;
|
||||
};
|
||||
union {
|
||||
struct { T y, z; };
|
||||
struct { T t, p; };
|
||||
struct { T g, b; };
|
||||
TVec2<T> yz;
|
||||
TVec2<T> tp;
|
||||
TVec2<T> gb;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
inline constexpr size_type size() const { return SIZE; }
|
||||
|
||||
// array access
|
||||
inline constexpr T const& operator[](size_t i) const noexcept {
|
||||
assert(i < SIZE);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline constexpr T& operator[](size_t i) noexcept {
|
||||
assert(i < SIZE);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
// constructors
|
||||
|
||||
// default constructor
|
||||
MATH_DEFAULT_CTOR_CONSTEXPR TVec3() noexcept MATH_DEFAULT_CTOR
|
||||
|
||||
// handles implicit conversion to a tvec3. must not be explicit.
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr TVec3(A v) noexcept : v{ T(v), T(v), T(v) } {}
|
||||
|
||||
template<typename A, typename B, typename C,
|
||||
typename = enable_if_arithmetic_t<A, B, C>>
|
||||
constexpr TVec3(A x, B y, C z) noexcept : v{ T(x), T(y), T(z) } {}
|
||||
|
||||
template<typename A, typename B, typename = enable_if_arithmetic_t<A, B>>
|
||||
constexpr TVec3(const TVec2<A>& v, B z) noexcept : v{ T(v[0]), T(v[1]), T(z) } {}
|
||||
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr TVec3(const TVec3<A>& v) noexcept : v{ T(v[0]), T(v[1]), T(v[2]) } {}
|
||||
|
||||
// cross product works only on vectors of size 3
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
TVec3<arithmetic_result_t<T, U>> cross(const TVec3& u, const TVec3<U>& v) noexcept {
|
||||
return {
|
||||
u[1] * v[2] - u[2] * v[1],
|
||||
u[2] * v[0] - u[0] * v[2],
|
||||
u[0] * v[1] - u[1] * v[0] };
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T, typename = details::enable_if_arithmetic_t<T>>
|
||||
using vec3 = details::TVec3<T>;
|
||||
|
||||
using double3 = vec3<double>;
|
||||
using float3 = vec3<float>;
|
||||
using half3 = vec3<half>;
|
||||
using int3 = vec3<int32_t>;
|
||||
using uint3 = vec3<uint32_t>;
|
||||
using short3 = vec3<int16_t>;
|
||||
using ushort3 = vec3<uint16_t>;
|
||||
using byte3 = vec3<int8_t>;
|
||||
using ubyte3 = vec3<uint8_t>;
|
||||
using bool3 = vec3<bool>;
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // MATH_VEC3_H_
|
||||
132
ios/include/math/vec4.h
Normal file
132
ios/include/math/vec4.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 MATH_VEC4_H_
|
||||
#define MATH_VEC4_H_
|
||||
|
||||
#include <math/vec3.h>
|
||||
#include <math/half.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
namespace filament {
|
||||
namespace math {
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename T>
|
||||
class MATH_EMPTY_BASES TVec4 :
|
||||
public TVecProductOperators<TVec4, T>,
|
||||
public TVecAddOperators<TVec4, T>,
|
||||
public TVecUnaryOperators<TVec4, T>,
|
||||
public TVecComparisonOperators<TVec4, T>,
|
||||
public TVecFunctions<TVec4, T> {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef size_t size_type;
|
||||
static constexpr size_t SIZE = 4;
|
||||
|
||||
union {
|
||||
T v[SIZE] MATH_CONSTEXPR_INIT;
|
||||
TVec2<T> xy, st, rg;
|
||||
TVec3<T> xyz, stp, rgb;
|
||||
struct {
|
||||
union { T x, s, r; };
|
||||
union {
|
||||
TVec2<T> yz, tp, gb;
|
||||
TVec3<T> yzw, tpq, gba;
|
||||
struct {
|
||||
union { T y, t, g; };
|
||||
union {
|
||||
TVec2<T> zw, pq, ba;
|
||||
struct { T z, w; };
|
||||
struct { T p, q; };
|
||||
struct { T b, a; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
inline constexpr size_type size() const { return SIZE; }
|
||||
|
||||
// array access
|
||||
inline constexpr T const& operator[](size_t i) const noexcept {
|
||||
assert(i < SIZE);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline constexpr T& operator[](size_t i) noexcept {
|
||||
assert(i < SIZE);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
// constructors
|
||||
|
||||
// default constructor
|
||||
MATH_DEFAULT_CTOR_CONSTEXPR TVec4() noexcept MATH_DEFAULT_CTOR
|
||||
|
||||
// handles implicit conversion to a tvec4. must not be explicit.
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr TVec4(A v) noexcept : v{ T(v), T(v), T(v), T(v) } {}
|
||||
|
||||
template<typename A, typename B, typename C, typename D,
|
||||
typename = enable_if_arithmetic_t<A, B, C, D>>
|
||||
constexpr TVec4(A x, B y, C z, D w) noexcept : v{ T(x), T(y), T(z), T(w) } {}
|
||||
|
||||
template<typename A, typename B, typename C,
|
||||
typename = enable_if_arithmetic_t<A, B, C>>
|
||||
constexpr TVec4(const TVec2<A>& v, B z, C w) noexcept : v{ T(v[0]), T(v[1]), T(z), T(w) } {}
|
||||
|
||||
template<typename A, typename B, typename = enable_if_arithmetic_t<A, B>>
|
||||
constexpr TVec4(const TVec2<A>& v, const TVec2<B>& w) noexcept : v{
|
||||
T(v[0]), T(v[1]), T(w[0]), T(w[1]) } {}
|
||||
|
||||
template<typename A, typename B, typename = enable_if_arithmetic_t<A, B>>
|
||||
constexpr TVec4(const TVec3<A>& v, B w) noexcept : v{ T(v[0]), T(v[1]), T(v[2]), T(w) } {}
|
||||
|
||||
template<typename A, typename = enable_if_arithmetic_t<A>>
|
||||
constexpr TVec4(const TVec4<A>& v) noexcept : v{ T(v[0]), T(v[1]), T(v[2]), T(v[3]) } {}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template<typename T, typename = details::enable_if_arithmetic_t<T>>
|
||||
using vec4 = details::TVec4<T>;
|
||||
|
||||
using double4 = vec4<double>;
|
||||
using float4 = vec4<float>;
|
||||
using half4 = vec4<half>;
|
||||
using int4 = vec4<int32_t>;
|
||||
using uint4 = vec4<uint32_t>;
|
||||
using short4 = vec4<int16_t>;
|
||||
using ushort4 = vec4<uint16_t>;
|
||||
using byte4 = vec4<int8_t>;
|
||||
using ubyte4 = vec4<uint8_t>;
|
||||
using bool4 = vec4<bool>;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
} // namespace math
|
||||
} // namespace filament
|
||||
|
||||
#endif // MATH_VEC4_H_
|
||||
Reference in New Issue
Block a user