blob: 73dc447415cb99242f6e948d9b25f3f7dea91d14 [file] [log] [blame]
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* 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 MATHFU_MATRIX_4X4_SIMD_H_
#define MATHFU_MATRIX_4X4_SIMD_H_
#include "mathfu/matrix.h"
#ifdef MATHFU_COMPILE_WITH_SIMD
#include "vectorial/simd4x4f.h"
#endif
/// @file mathfu/internal/matrix_4x4_simd.h MathFu Matrix<T, 4, 4>
/// Specialization
/// @brief 4x4 specialization of mathfu::Matrix for SIMD optimized builds.
/// @see mathfu::Matrix
namespace mathfu {
#ifdef MATHFU_COMPILE_WITH_SIMD
static const Vector<float, 4> kAffineWColumn(0.0f, 0.0f, 0.0f, 1.0f);
/// @cond MATHFU_INTERNAL
template <>
class Matrix<float, 4> {
public:
Matrix<float, 4>() {}
inline Matrix<float, 4>(const Matrix<float, 4>& m) {
data_.simd_matrix.x = m.data_.simd_matrix.x;
data_.simd_matrix.y = m.data_.simd_matrix.y;
data_.simd_matrix.z = m.data_.simd_matrix.z;
data_.simd_matrix.w = m.data_.simd_matrix.w;
}
explicit inline Matrix<float, 4>(const float& s) {
simd4f v = simd4f_create(s, s, s, s);
data_.simd_matrix = simd4x4f_create(v, v, v, v);
}
inline Matrix<float, 4>(const float& s00, const float& s10, const float& s20,
const float& s30, const float& s01, const float& s11,
const float& s21, const float& s31, const float& s02,
const float& s12, const float& s22, const float& s32,
const float& s03, const float& s13, const float& s23,
const float& s33) {
data_.simd_matrix = simd4x4f_create(
simd4f_create(s00, s10, s20, s30), simd4f_create(s01, s11, s21, s31),
simd4f_create(s02, s12, s22, s32), simd4f_create(s03, s13, s23, s33));
}
explicit inline Matrix<float, 4>(const float* m) {
data_.simd_matrix =
simd4x4f_create(simd4f_create(m[0], m[1], m[2], m[3]),
simd4f_create(m[4], m[5], m[6], m[7]),
simd4f_create(m[8], m[9], m[10], m[11]),
simd4f_create(m[12], m[13], m[14], m[15]));
}
inline Matrix<float, 4>(const Vector<float, 4>& column0,
const Vector<float, 4>& column1,
const Vector<float, 4>& column2,
const Vector<float, 4>& column3) {
#if defined(MATHFU_COMPILE_WITH_PADDING)
data_.simd_matrix = simd4x4f_create(column0.data_.simd, column1.data_.simd,
column2.data_.simd, column3.data_.simd);
#else
data_.simd_matrix = simd4x4f_create(
simd4f_create(column0[0], column0[1], column0[2], column0[3]),
simd4f_create(column1[0], column1[1], column1[2], column1[3]),
simd4f_create(column2[0], column2[1], column2[2], column2[3]),
simd4f_create(column3[0], column3[1], column3[2], column3[3]));
#endif // defined(MATHFU_COMPILE_WITH_PADDING)
}
explicit inline Matrix(const VectorPacked<float, 4>* const vectors) {
data_.simd_matrix.x = simd4f_uload4(vectors[0].data);
data_.simd_matrix.y = simd4f_uload4(vectors[1].data);
data_.simd_matrix.z = simd4f_uload4(vectors[2].data);
data_.simd_matrix.w = simd4f_uload4(vectors[3].data);
}
inline const float& operator()(const int i, const int j) const {
return FindElem(i, FindColumn(j));
}
inline float& operator()(const int i, const int j) {
return FindElem(i, FindColumn(j));
}
inline const float& operator()(const int i) const {
return this->operator[](i);
}
inline float& operator()(const int i) { return this->operator[](i); }
inline const float& operator[](const int i) const {
const int col = i / 4;
const int row = i % 4;
return FindElem(row, FindColumn(col));
}
inline float& operator[](const int i) {
const int col = i / 4;
const int row = i % 4;
return FindElem(row, FindColumn(col));
}
inline void Pack(VectorPacked<float, 4>* const vector) const {
simd4f_ustore4(data_.simd_matrix.x, vector[0].data);
simd4f_ustore4(data_.simd_matrix.y, vector[1].data);
simd4f_ustore4(data_.simd_matrix.z, vector[2].data);
simd4f_ustore4(data_.simd_matrix.w, vector[3].data);
}
inline Matrix<float, 4> operator-() const {
Matrix<float, 4> m(0.f);
simd4x4f_sub(&m.data_.simd_matrix, &data_.simd_matrix,
&m.data_.simd_matrix);
return m;
}
inline Matrix<float, 4> operator+(const Matrix<float, 4>& m) const {
Matrix<float, 4> return_m;
simd4x4f_add(&data_.simd_matrix, &m.data_.simd_matrix,
&return_m.data_.simd_matrix);
return return_m;
}
inline Matrix<float, 4> operator-(const Matrix<float, 4>& m) const {
Matrix<float, 4> return_m;
simd4x4f_sub(&data_.simd_matrix, &m.data_.simd_matrix,
&return_m.data_.simd_matrix);
return return_m;
}
inline Matrix<float, 4> operator*(const float& s) const {
Matrix<float, 4> m(s);
simd4x4f_mul(&m.data_.simd_matrix, &data_.simd_matrix,
&m.data_.simd_matrix);
return m;
}
inline Matrix<float, 4> operator/(const float& s) const {
Matrix<float, 4> m(1 / s);
simd4x4f_mul(&m.data_.simd_matrix, &data_.simd_matrix,
&m.data_.simd_matrix);
return m;
}
inline Vector<float, 3> operator*(const Vector<float, 3>& v) const {
Vector<float, 3> return_v;
Simd4fUnion temp_v;
#ifdef MATHFU_COMPILE_WITH_PADDING
temp_v.simd = v.data_.simd;
temp_v.float_array[3] = 1;
simd4x4f_matrix_vector_mul(&data_.simd_matrix, &temp_v.simd,
&return_v.data_.simd);
return_v *= (1 / return_v.data_.float_array[3]);
#else
temp_v.simd = simd4f_create(v[0], v[1], v[2], 1.0f);
simd4x4f_matrix_vector_mul(&data_.simd_matrix, &temp_v.simd, &temp_v.simd);
simd4f_mul(temp_v.simd, simd4f_splat(temp_v.float_array[3]));
MATHFU_VECTOR3_STORE3(temp_v.simd, return_v.data_);
#endif // MATHFU_COMPILE_WITH_PADDING
return return_v;
}
inline Vector<float, 4> operator*(const Vector<float, 4>& v) const {
Vector<float, 4> return_v;
simd4x4f_matrix_vector_mul(&data_.simd_matrix, &v.data_.simd,
&return_v.data_.simd);
return return_v;
}
inline Vector<float, 4> VecMatTimes(const Vector<float, 4>& v) const {
return Vector<float, 4>(
simd4f_dot3_scalar(v.data_.simd, data_.simd_matrix.x),
simd4f_dot3_scalar(v.data_.simd, data_.simd_matrix.y),
simd4f_dot3_scalar(v.data_.simd, data_.simd_matrix.z),
simd4f_dot3_scalar(v.data_.simd, data_.simd_matrix.w));
}
inline Matrix<float, 4> operator*(const Matrix<float, 4>& m) const {
Matrix<float, 4> return_m;
simd4x4f_matrix_mul(&data_.simd_matrix, &m.data_.simd_matrix,
&return_m.data_.simd_matrix);
return return_m;
}
inline Matrix<float, 4> Inverse() const {
Matrix<float, 4> return_m;
simd4x4f_inverse(&data_.simd_matrix, &return_m.data_.simd_matrix);
return return_m;
}
inline bool InverseWithDeterminantCheck(
Matrix<float, 4, 4>* const inverse) const {
return fabs(simd4f_get_x(simd4x4f_inverse(&data_.simd_matrix,
&inverse->data_.simd_matrix))) >=
Constants<float>::GetDeterminantThreshold();
}
/// Calculate the transpose of matrix.
/// @return The transpose of the specified matrix.
inline Matrix<float, 4, 4> Transpose() const {
Matrix<float, 4, 4> transpose;
simd4x4f_transpose(&data_.simd_matrix, &transpose.data_.simd_matrix);
return transpose;
}
inline Vector<float, 3> TranslationVector3D() const {
Vector<float, 3> return_v;
MATHFU_VECTOR3_STORE3(FindColumn(3).simd, return_v.data_);
return return_v;
}
inline Matrix<float, 4>& operator+=(const Matrix<float, 4>& m) {
simd4x4f_add(&data_.simd_matrix, &m.data_.simd_matrix, &data_.simd_matrix);
return *this;
}
inline Matrix<float, 4>& operator-=(const Matrix<float, 4>& m) {
simd4x4f_sub(&data_.simd_matrix, &m.data_.simd_matrix, &data_.simd_matrix);
return *this;
}
inline Matrix<float, 4>& operator*=(const float& s) {
Matrix<float, 4> m(s);
simd4x4f_mul(&m.data_.simd_matrix, &data_.simd_matrix, &data_.simd_matrix);
return *this;
}
inline Matrix<float, 4>& operator/=(const float& s) {
Matrix<float, 4> m(1 / s);
simd4x4f_mul(&m.data_.simd_matrix, &data_.simd_matrix, &data_.simd_matrix);
return *this;
}
inline Matrix<float, 4> operator*=(const Matrix<float, 4>& m) {
Matrix<float, 4> copy_of_this(*this);
simd4x4f_matrix_mul(&copy_of_this.data_.simd_matrix, &m.data_.simd_matrix,
&data_.simd_matrix);
return *this;
}
template <typename CompatibleT>
static inline Matrix<float, 4> FromType(const CompatibleT& compatible) {
return FromTypeHelper<float, 4, 4, CompatibleT>(compatible);
}
template <typename CompatibleT>
static inline CompatibleT ToType(const Matrix<float, 4>& m) {
return ToTypeHelper<float, 4, 4, CompatibleT>(m);
}
static inline Matrix<float, 4> OuterProduct(const Vector<float, 4>& v1,
const Vector<float, 4>& v2) {
Matrix<float, 4> m;
m.data_.simd_matrix =
simd4x4f_create(simd4f_mul(v1.data_.simd, simd4f_splat(v2[0])),
simd4f_mul(v1.data_.simd, simd4f_splat(v2[1])),
simd4f_mul(v1.data_.simd, simd4f_splat(v2[2])),
simd4f_mul(v1.data_.simd, simd4f_splat(v2[3])));
return m;
}
static inline Matrix<float, 4> HadamardProduct(const Matrix<float, 4>& m1,
const Matrix<float, 4>& m2) {
Matrix<float, 4> return_m;
simd4x4f_mul(&m1.data_.simd_matrix, &m2.data_.simd_matrix,
&return_m.data_.simd_matrix);
return return_m;
}
static inline Matrix<float, 4> Identity() {
Matrix<float, 4> return_m;
simd4x4f_identity(&return_m.data_.simd_matrix);
return return_m;
}
static inline Matrix<float, 4> FromTranslationVector(
const Vector<float, 3>& v) {
return Matrix<float, 4>(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, v[0], v[1],
v[2], 1);
}
static inline Matrix<float, 4> FromScaleVector(const Vector<float, 3>& v) {
return Matrix<float, 4>(v[0], 0, 0, 0, 0, v[1], 0, 0, 0, 0, v[2], 0, 0, 0,
0, 1);
}
static inline Matrix<float, 4> FromRotationMatrix(const Matrix<float, 3>& m) {
return Matrix<float, 4>(m[0], m[1], m[2], 0, m[3], m[4], m[5], 0, m[6],
m[7], m[8], 0, 0, 0, 0, 1);
}
/// @brief Constructs a Matrix<float, 4> from an AffineTransform.
///
/// @param affine An AffineTransform reference to be used to construct
/// a Matrix<float, 4> by adding in the 'w' row of [0, 0, 0, 1].
static inline Matrix<float, 4> FromAffineTransform(
const AffineTransform& affine) {
Matrix<float, 4> m;
m.data_.simd_matrix.x = simd4f_uload4(&affine[0]);
m.data_.simd_matrix.y = simd4f_uload4(&affine[4]);
m.data_.simd_matrix.z = simd4f_uload4(&affine[8]);
m.data_.simd_matrix.w = simd4f_uload4(&kAffineWColumn[0]);
return m.Transpose();
}
/// @brief Converts a Matrix<float, 4> into an AffineTransform.
///
/// @param m A Matrix<float, 4> reference to be converted into an
/// AffineTransform by dropping the fixed 'w' row.
///
/// @return Returns an AffineTransform that contains the essential
/// transformation data from the Matrix<float, 4>.
static inline AffineTransform ToAffineTransform(const Matrix<float, 4>& m) {
AffineTransform affine;
const Matrix<float, 4> mt = m.Transpose();
simd4f_ustore4(mt.data_.simd_matrix.x, &affine[0]);
simd4f_ustore4(mt.data_.simd_matrix.y, &affine[4]);
simd4f_ustore4(mt.data_.simd_matrix.z, &affine[8]);
return affine;
}
/// Create a 4x4 perpective matrix.
/// @handedness: 1.0f for RH, -1.0f for LH
static inline Matrix<float, 4, 4> Perspective(float fovy, float aspect,
float znear, float zfar,
float handedness = 1.0f) {
return PerspectiveHelper(fovy, aspect, znear, zfar, handedness);
}
/// Create a 4x4 orthographic matrix.
/// @param handedness 1.0f for RH, -1.0f for LH
static inline Matrix<float, 4, 4> Ortho(float left, float right, float bottom,
float top, float znear, float zfar,
float handedness = 1.0f) {
return OrthoHelper(left, right, bottom, top, znear, zfar, handedness);
}
/// Create a 3-dimensional camera matrix.
/// @param at The look-at target of the camera.
/// @param eye The position of the camera.
/// @param up The up vector in the world, for example (0, 1, 0) if the
/// @handedness: 1.0f for RH, -1.0f for LH
/// TODO: Change default handedness to 1.0f, to match Perspective().
/// y-axis is up.
static inline Matrix<float, 4, 4> LookAt(const Vector<float, 3>& at,
const Vector<float, 3>& eye,
const Vector<float, 3>& up,
float handedness = -1.0f) {
return LookAtHelper(at, eye, up, handedness);
}
/// @brief Get the 3D position in object space from a window coordinate.
///
/// @param window_coord The window coordinate. The z value is for depth.
/// A window coordinate on the near plane will have 0 as the z value.
/// And a window coordinate on the far plane will have 1 as the z value.
/// z value should be with in [0, 1] here.
/// @param model_view The Model View matrix.
/// @param projection The projection matrix.
/// @param window_width Width of the window.
/// @param window_height Height of the window.
/// @return the mapped 3D position in object space.
static inline Vector<float, 3> UnProject(
const Vector<float, 3>& window_coord,
const Matrix<float, 4, 4>& model_view,
const Matrix<float, 4, 4>& projection, const float window_width,
const float window_height) {
Vector<float, 3> result;
UnProjectHelper(window_coord, model_view, projection, window_width,
window_height, result);
return result;
}
// Dimensions of the matrix.
/// Number of rows in the matrix.
static const int kRows = 4;
/// Number of columns in the matrix.
static const int kColumns = 4;
/// Total number of elements in the matrix.
static const int kElements = 4 * 4;
MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE
private:
inline const Simd4fUnion& FindColumn(const int i) const {
return data_.simd4f_union_array[i];
}
inline Simd4fUnion& FindColumn(const int i) {
return data_.simd4f_union_array[i];
}
static inline const float& FindElem(const int i, const Simd4fUnion& column) {
return column.float_array[i];
}
static inline float& FindElem(const int i, Simd4fUnion& column) {
return column.float_array[i];
}
// Contents of the Matrix in different representations to work around
// strict aliasing rules.
union {
simd4x4f simd_matrix;
Simd4fUnion simd4f_union_array[4];
float float_array[16];
} data_;
};
inline Matrix<float, 4> operator*(const float& s, const Matrix<float, 4>& m) {
return m * s;
}
inline Vector<float, 4> operator*(const Vector<float, 4>& v,
const Matrix<float, 4>& m) {
return m.VecMatTimes(v);
}
/// @endcond
#endif // MATHFU_COMPILE_WITH_SIMD
} // namespace mathfu
#endif // MATHFU_MATRIX_4X4_SIMD_H_