first commit

This commit is contained in:
Nick Fisher
2021-09-15 20:07:11 +08:00
commit a0f877be48
292 changed files with 100157 additions and 0 deletions

View 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_

View 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_

View 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
View 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
View 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
View 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
View 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
View 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
View 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_

View 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
View 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
View 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
View 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
View 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
View 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
View 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_