() const noexcept
{
return size_cast(std::make_index_sequence
{});
}
/// @}
/// @name Column access
/// @{
/**
* Returns a reference to the column vector at a given index.
*
* @param i Index of a column vector.
*
* @return Reference to the column vector at index @p i.
*/
/// @{
[[nodiscard]] inline constexpr column_vector_type& operator[](std::size_t i) noexcept
{
return columns[i];
}
[[nodiscard]] inline constexpr const column_vector_type& operator[](std::size_t i) const noexcept
{
return columns[i];
}
[[nodiscard]] inline constexpr column_vector_type& column(std::size_t i) noexcept
{
return columns[i];
}
[[nodiscard]] inline constexpr const column_vector_type& column(std::size_t i) const noexcept
{
return columns[i];
}
/// @}
/**
* Returns a reference to the first column vector.
*/
/// @{
[[nodiscard]] inline constexpr column_vector_type& front() noexcept
{
return columns[0];
}
[[nodiscard]] inline constexpr const column_vector_type& front() const noexcept
{
return columns[0];
}
/// @}
/**
* Returns a reference to the last column vector.
*/
/// @{
[[nodiscard]] inline constexpr column_vector_type& back() noexcept
{
return columns[column_count - 1];
}
[[nodiscard]] inline constexpr const column_vector_type& back() const noexcept
{
return columns[column_count - 1];
}
/// @}
/// @}
/// @name Element access
/// @{
/**
* Returns a reference to the element at a given column-major index.
*
* @param i Column-major index of a matrix element.
*
* @return Reference to the element at column-major index @p i.
*/
/// @{
[[nodiscard]] inline constexpr T& element(std::size_t i) noexcept
{
return columns[i / row_count][i % row_count];
}
[[nodiscard]] inline constexpr const T& element(std::size_t i) const noexcept
{
return columns[i / row_count][i % row_count];
}
/// @}
/**
* Returns a pointer to the first element.
*
* @warning If matrix::element_type is not a POD type, elements may not be stored contiguously.
*/
/// @{
[[nodiscard]] inline constexpr element_type* data() noexcept
{
return &columns[0][0];
};
[[nodiscard]] inline constexpr const element_type* data() const noexcept
{
return &columns[0][0];
};
/// @}
/// @}
/// @name Iterators
/// @{
/**
* Returns an iterator to the first column vector.
*/
/// @{
[[nodiscard]] inline constexpr column_vector_type* begin() noexcept
{
return columns;
}
[[nodiscard]] inline constexpr const column_vector_type* begin() const noexcept
{
return columns;
}
[[nodiscard]] inline constexpr const column_vector_type* cbegin() const noexcept
{
return columns;
}
/// @}
/**
* Returns an iterator to the column vector following the last column vector.
*/
/// @{
[[nodiscard]] inline constexpr column_vector_type* end() noexcept
{
return columns + column_count;
}
[[nodiscard]] inline constexpr const column_vector_type* end() const noexcept
{
return columns + column_count;
}
[[nodiscard]] inline constexpr const column_vector_type* cend() const noexcept
{
return columns + column_count;
}
/// @}
/**
* Returns a reverse iterator to the first column vector of the reversed matrix.
*/
/// @{
[[nodiscard]] inline constexpr std::reverse_iterator rbegin() noexcept
{
return std::reverse_iterator(columns + column_count);
}
[[nodiscard]] inline constexpr std::reverse_iterator rbegin() const noexcept
{
return std::reverse_iterator(columns + column_count);
}
[[nodiscard]] inline constexpr std::reverse_iterator crbegin() const noexcept
{
return std::reverse_iterator(columns + column_count);
}
/// @}
/**
* Returns a reverse iterator to the column vector following the last column vector of the reversed matrix.
*/
/// @{
[[nodiscard]] inline constexpr std::reverse_iterator rend() noexcept
{
return std::reverse_iterator(columns);
}
[[nodiscard]] inline constexpr std::reverse_iterator rend() const noexcept
{
return std::reverse_iterator(columns);
}
[[nodiscard]] inline constexpr std::reverse_iterator crend() const noexcept
{
return std::reverse_iterator(columns);
}
/// @}
/// @}
/// @name Capacity
/// @{
/**
* Returns the number of elements in the matrix.
*/
[[nodiscard]] inline constexpr std::size_t size() const noexcept
{
return element_count;
};
/// @}
/// @name Constants
/// @{
/**
* Returns a zero matrix, where every element is equal to zero.
*/
[[nodiscard]] static constexpr matrix zero() noexcept
{
return {};
}
/// @private
template
[[nodiscard]] static inline constexpr matrix one(std::index_sequence) noexcept
{
//return {column_vector_type::one() ...};
// MSVC bug workaround (I must be referenced for parameter pack expansion)
return {(I ? column_vector_type::one() : column_vector_type::one()) ...};
}
/**
* Returns a matrix of ones, where every element is equal to one.
*/
[[nodiscard]] static constexpr matrix one() noexcept
{
return one(std::make_index_sequence{});
}
/// @private
template
[[nodiscard]] static inline constexpr column_vector_type identity_column(std::size_t i, std::index_sequence) noexcept
{
return {(I == i ? T{1} : T{0}) ...};
}
/// @private
template
[[nodiscard]] static inline constexpr matrix identity(std::index_sequence) noexcept
{
return {identity_column(I, std::make_index_sequence{}) ...};
}
/**
* Returns an identity matrix, with ones on the main diagonal and zeros elsewhere.
*/
[[nodiscard]] static constexpr matrix identity() noexcept
{
return identity(std::make_index_sequence{});
}
/// @}
};
/// Matrix types.
namespace matrix_types {
/**
* *n* by *m* matrix.
*
* @tparam T Element type.
*/
/// @{
template
using mat2x2 = matrix;
template
using mat2x3 = matrix;
template
using mat2x4 = matrix;
template
using mat3x2 = matrix;
template
using mat3x3 = matrix;
template
using mat3x4 = matrix;
template
using mat4x2 = matrix;
template
using mat4x3 = matrix;
template
using mat4x4 = matrix;
/// @}
/**
* *n* by *n* square matrix.
*
* @tparam T Element type.
*/
/// @{
template
using mat2 = mat2x2;
template
using mat3 = mat3x3;
template
using mat4 = mat4x4;
/// @}
/**
* *n* by *m* matrix of single-precision floating-point numbers.
*
* @tparam N Number of columns.
* @tparam M Number of rows.
*/
/// @{
template
using fmat = matrix;
using fmat2x2 = fmat<2, 2>;
using fmat2x3 = fmat<2, 3>;
using fmat2x4 = fmat<2, 4>;
using fmat3x2 = fmat<3, 2>;
using fmat3x3 = fmat<3, 3>;
using fmat3x4 = fmat<3, 4>;
using fmat4x2 = fmat<4, 2>;
using fmat4x3 = fmat<4, 3>;
using fmat4x4 = fmat<4, 4>;
/// @}
/// *n* by *n* square matrix of single-precision floating-point numbers.
/// @{
using fmat2 = fmat2x2;
using fmat3 = fmat3x3;
using fmat4 = fmat4x4;
/// @}
/**
* *n* by *m* matrix of double-precision floating-point numbers.
*
* @tparam N Number of columns.
* @tparam M Number of rows.
*/
/// @{
template
using dmat = matrix;
using dmat2x2 = dmat<2, 2>;
using dmat2x3 = dmat<2, 3>;
using dmat2x4 = dmat<2, 4>;
using dmat3x2 = dmat<3, 2>;
using dmat3x3 = dmat<3, 3>;
using dmat3x4 = dmat<3, 4>;
using dmat4x2 = dmat<4, 2>;
using dmat4x3 = dmat<4, 3>;
using dmat4x4 = dmat<4, 4>;
/// @}
/// *n* by *n* square matrix of double-precision floating-point numbers.
/// @{
using dmat2 = dmat2x2;
using dmat3 = dmat3x3;
using dmat4 = dmat4x4;
/// @}
} // namespace matrix_types
// Bring matrix types into math namespace
using namespace matrix_types;
// Bring matrix types into math::types namespace
namespace types { using namespace matrix_types; }
/**
* Adds two matrices.
*
* @param a First matrix.
* @param b Second matrix.
*
* @return Sum of the two matrices.
*/
template
[[nodiscard]] constexpr matrix add(const matrix& a, const matrix& b) noexcept;
/**
* Adds a matrix and a scalar.
*
* @param a Matrix.
* @param b scalar.
*
* @return Sum of the matrix and scalar.
*/
template
[[nodiscard]] constexpr matrix add(const matrix& a, T b) noexcept;
/**
* Calculates the determinant of a square matrix.
*
* @param m Matrix of which to take the determinant.
*
* @return Determinant of @p m.
*
* @warning Currently only implemented for 2x2, 3x3, and 4x4 matrices.
*/
template
[[nodiscard]] constexpr T determinant(const matrix& m) noexcept;
/**
* Performs a component-wise multiplication of two matrices.
*
* @param x First matrix multiplicand.
* @param y Second matrix multiplicand.
*
* @return Product of the component-wise multiplcation.
*/
template
[[nodiscard]] constexpr matrix componentwise_mul(const matrix& a, const matrix& b) noexcept;
/**
* Divides a matrix by a matrix.
*
* @param a First matrix.
* @param b Second matrix.
*
* @return Result of the division.
*/
template
[[nodiscard]] constexpr matrix div(const matrix& a, const matrix& b) noexcept;
/**
* Divides a matrix by a scalar.
*
* @param a Matrix.
* @param b Scalar.
*
* @return Result of the division.
*/
template
[[nodiscard]] constexpr matrix div(const matrix& a, T b) noexcept;
/**
* Divides a scalar by a matrix.
*
* @param a Scalar.
* @param b Matrix.
*
* @return Result of the division.
*/
template
[[nodiscard]] constexpr matrix div(T a, const matrix& b) noexcept;
/**
* Extracts the Ith column from a matrix.
*
* @tparam I Index of a column.
* @tparam T Element type.
* @tparam N Number of columns.
* @tparam M Number of rows.
*
* @param m Matrix from which to extract a column.
*
* @return Reference to the Ith column of @p m.
*/
/// @{
template
[[nodiscard]] constexpr typename matrix::column_vector_type& get(matrix& m) noexcept;
template
[[nodiscard]] constexpr typename matrix::column_vector_type&& get(matrix&& m) noexcept;
template
[[nodiscard]] constexpr const typename matrix::column_vector_type& get(const matrix& m) noexcept;
template
[[nodiscard]] constexpr const typename matrix::column_vector_type&& get(const matrix&& m) noexcept;
/// @}
/**
* Calculates the inverse of a square matrix.
*
* @param m Square matrix.
*
* @return Inverse of matrix @p m.
*
* @warning Currently only implemented for 2x2, 3x3, and 4x4 matrices.
*/
template
[[nodiscard]] constexpr matrix inverse(const matrix& m) noexcept;
/**
* Creates a viewing transformation matrix.
*
* @param position Position of the view point.
* @param target Position of the target.
* @param up Unit vector pointing in the up direction.
*
* @return Viewing transformation matrix.
*/
template
[[nodiscard]] constexpr mat4 look_at(const vec3& position, const vec3& target, vec3 up);
/**
* Multiplies two matrices
*
* @tparam T Matrix element type.
* @tparam N Number of columns in matrix @p a, and rows in matrix @p b.
* @tparam M Number of rows in matrix @p a.
* @tparam P Number of columns in matrix @p b.
*
* @param a First matrix.
* @param b Second matrix.
*
* @return Product of `a * b`.
*/
template
[[nodiscard]] constexpr matrix mul(const matrix& a, const matrix& b) noexcept;
/**
* Multiplies a matrix by a scalar.
*
* @param a Matrix.
* @param b Scalar.
*
* @return Product of the matrix and the scalar.
*/
template
[[nodiscard]] constexpr matrix mul(const matrix& a, T b) noexcept;
/**
* Calculates the product of a matrix and a row vector.
*
* @param a Matrix.
* @param b Row vector
*
* @return Product of the matrix and the row vector.
*/
template
[[nodiscard]] constexpr typename matrix::column_vector_type mul(const matrix& a, const typename matrix::row_vector_type& b) noexcept;
/**
* Calculates the product of a column vector and a matrix.
*
* @param a Column vector.
* @param b Matrix.
*
* @return Product of the column vector and the matrix.
*/
template
[[nodiscard]] constexpr typename matrix::row_vector_type mul(const typename matrix::column_vector_type& a, const matrix& b) noexcept;
/**
* Constructs a rotation matrix.
*
* @param angle Angle of rotation, in radians.
* @param axis Axis of rotation.
*
* @return Rotation matrix.
*/
template
[[nodiscard]] mat3 rotate(T angle, const vector& axis);
/**
* Produces a matrix which rotates Cartesian coordinates about the x-axis by a given angle.
*
* @param angle Angle of rotation, in radians.
*
* @return Rotation matrix.
*/
template
[[nodiscard]] mat3 rotate_x(T angle);
/**
* Produces a matrix which rotates Cartesian coordinates about the y-axis by a given angle.
*
* @param angle Angle of rotation, in radians.
*
* @return Rotation matrix.
*/
template
[[nodiscard]] mat3 rotate_y(T angle);
/**
* Produces a matrix which rotates Cartesian coordinates about the z-axis by a given angle.
*
* @param angle Angle of rotation, in radians.
*
* @return Rotation matrix.
*/
template
[[nodiscard]] mat3 rotate_z(T angle);
/**
* Constructs a scale matrix.
*
* @param v Scale vector.
*
* @return Scale matrix.
*/
template
[[nodiscard]] constexpr mat4 scale(const vec3& v);
/**
* Subtracts a matrix from another matrix.
*
* @param a First matrix.
* @param b Second matrix.
*
* @return Difference between the two matrices.
*/
template
[[nodiscard]] constexpr matrix sub(const matrix& a, const matrix& b) noexcept;
/**
* Subtracts a scalar from matrix.
*
* @param a Matrix.
* @param b Scalar.
*
* @return Difference between the matrix and scalar.
*/
template
[[nodiscard]] constexpr matrix sub(const matrix& a, T b) noexcept;
/**
* Subtracts a matrix from a scalar.
*
* @param a Scalar.
* @param b Matrix.
*
* @return Difference between the scalar and matrix.
*/
template
[[nodiscard]] constexpr matrix sub(T a, const matrix& b) noexcept;
/**
* Calculates the trace of a square matrix.
*
* @param m Square matrix.
*
* @return Sum of elements on the main diagonal.
*/
template
[[nodiscard]] constexpr T trace(const matrix& m) noexcept;
/**
* Constructs a translation matrix.
*
* @param v Translation vector.
*
* @return Translation matrix.
*/
template
[[nodiscard]] constexpr mat4 translate(const vec3& v);
/**
* Calculates the transpose of a matrix.
*
* @param m Matrix to transpose.
*
* @return Transposed matrix.
*/
template
[[nodiscard]] constexpr matrix transpose(const matrix& m) noexcept;
/// @private
template
inline constexpr matrix add(const matrix& a, const matrix& b, std::index_sequence) noexcept
{
return {(a[I] + b[I]) ...};
}
template
constexpr matrix add(const matrix& a, const matrix& b) noexcept
{
return add(a, b, std::make_index_sequence{});
}
/// @private
template
inline constexpr matrix add(const matrix& a, T b, std::index_sequence) noexcept
{
return {(a[I] + b) ...};
}
template
constexpr matrix add(const matrix& a, T b) noexcept
{
return add(a, b, std::make_index_sequence{});
}
/// @private
template
constexpr T determinant(const matrix& m) noexcept
{
return
m[0][0] * m[1][1] -
m[0][1] * m[1][0];
}
/// @private
template
constexpr T determinant(const mat3& m) noexcept
{
return
m[0][0] * m[1][1] * m[2][2] +
m[0][1] * m[1][2] * m[2][0] +
m[0][2] * m[1][0] * m[2][1] -
m[0][0] * m[1][2] * m[2][1] -
m[0][1] * m[1][0] * m[2][2] -
m[0][2] * m[1][1] * m[2][0];
}
/// @private
template
constexpr T determinant(const matrix& m) noexcept
{
return
m[0][3] * m[1][2] * m[2][1] * m[3][0] - m[0][2] * m[1][3] * m[2][1] * m[3][0] -
m[0][3] * m[1][1] * m[2][2] * m[3][0] + m[0][1] * m[1][3] * m[2][2] * m[3][0] +
m[0][2] * m[1][1] * m[2][3] * m[3][0] - m[0][1] * m[1][2] * m[2][3] * m[3][0] -
m[0][3] * m[1][2] * m[2][0] * m[3][1] + m[0][2] * m[1][3] * m[2][0] * m[3][1] +
m[0][3] * m[1][0] * m[2][2] * m[3][1] - m[0][0] * m[1][3] * m[2][2] * m[3][1] -
m[0][2] * m[1][0] * m[2][3] * m[3][1] + m[0][0] * m[1][2] * m[2][3] * m[3][1] +
m[0][3] * m[1][1] * m[2][0] * m[3][2] - m[0][1] * m[1][3] * m[2][0] * m[3][2] -
m[0][3] * m[1][0] * m[2][1] * m[3][2] + m[0][0] * m[1][3] * m[2][1] * m[3][2] +
m[0][1] * m[1][0] * m[2][3] * m[3][2] - m[0][0] * m[1][1] * m[2][3] * m[3][2] -
m[0][2] * m[1][1] * m[2][0] * m[3][3] + m[0][1] * m[1][2] * m[2][0] * m[3][3] +
m[0][2] * m[1][0] * m[2][1] * m[3][3] - m[0][0] * m[1][2] * m[2][1] * m[3][3] -
m[0][1] * m[1][0] * m[2][2] * m[3][3] + m[0][0] * m[1][1] * m[2][2] * m[3][3];
}
/// @private
template
inline constexpr matrix componentwise_mul(const matrix& a, const matrix& b, std::index_sequence) noexcept
{
return {(a[I] * b[I]) ...};
}
template
constexpr matrix componentwise_mul(const matrix& a, const matrix& b) noexcept
{
return componentwise_mul(a, b, std::make_index_sequence{});
}
/// @private
template
inline constexpr matrix div(const matrix& a, const matrix& b, std::index_sequence) noexcept
{
return {(a[I] / b[I]) ...};
}
template
constexpr matrix div(const matrix& a, const matrix& b) noexcept
{
return div(a, b, std::make_index_sequence{});
}
/// @private
template
inline constexpr matrix div(const matrix& a, T b, std::index_sequence) noexcept
{
return {(a[I] / b) ...};
}
template
constexpr matrix div(const matrix& a, T b) noexcept
{
return div(a, b, std::make_index_sequence{});
}
/// @private
template
inline constexpr matrix div(T a, const matrix& b, std::index_sequence) noexcept
{
return {(a / b[I]) ...};
}
template
constexpr matrix div(T a, const matrix& b) noexcept
{
return div(a, b, std::make_index_sequence{});
}
template
inline constexpr typename matrix::column_vector_type& get(matrix& m) noexcept
{
static_assert(I < N);
return m.columns[I];
}
template
inline constexpr typename matrix::column_vector_type&& get(matrix&& m) noexcept
{
static_assert(I < N);
return std::move(m.columns[I]);
}
template
inline constexpr const typename matrix::column_vector_type& get(const matrix& m) noexcept
{
static_assert(I < N);
return m.columns[I];
}
template
inline constexpr const typename matrix::column_vector_type&& get(const matrix&& m) noexcept
{
static_assert(I < N);
return std::move(m.columns[I]);
}
/// @private
template
constexpr matrix inverse(const matrix& m) noexcept
{
const T inv_det = T{1} / determinant(m);
return
{
m[1][1] * inv_det,
-m[0][1] * inv_det,
-m[1][0] * inv_det,
m[0][0] * inv_det
};
}
/// @private
template
constexpr mat3 inverse(const mat3& m) noexcept
{
const T inv_det = T{1} / determinant(m);
return
{
(m[1][1] * m[2][2] - m[1][2] * m[2][1]) * inv_det,
(m[0][2] * m[2][1] - m[0][1] * m[2][2]) * inv_det,
(m[0][1] * m[1][2] - m[0][2] * m[1][1]) * inv_det,
(m[1][2] * m[2][0] - m[1][0] * m[2][2]) * inv_det,
(m[0][0] * m[2][2] - m[0][2] * m[2][0]) * inv_det,
(m[0][2] * m[1][0] - m[0][0] * m[1][2]) * inv_det,
(m[1][0] * m[2][1] - m[1][1] * m[2][0]) * inv_det,
(m[0][1] * m[2][0] - m[0][0] * m[2][1]) * inv_det,
(m[0][0] * m[1][1] - m[0][1] * m[1][0]) * inv_det
};
}
/// @private
template
constexpr matrix inverse(const matrix& m) noexcept
{
const T inv_det = T{1} / determinant(m);
return
{
(m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] + m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] - m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * inv_det,
(m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] - m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] + m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * inv_det,
(m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] + m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] - m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * inv_det,
(m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] - m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] + m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * inv_det,
(m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] - m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] + m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * inv_det,
(m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] + m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] - m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * inv_det,
(m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] - m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] + m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * inv_det,
(m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] + m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] - m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * inv_det,
(m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] + m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] - m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * inv_det,
(m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] - m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] + m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * inv_det,
(m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] + m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] - m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * inv_det,
(m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] - m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] + m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * inv_det,
(m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] - m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] + m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * inv_det,
(m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] + m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] - m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * inv_det,
(m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] - m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] + m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * inv_det,
(m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * inv_det
};
}
template
constexpr mat4 look_at(const vec3& position, const vec3& target, vec3 up)
{
const auto forward = normalize(sub(target, position));
const auto right = normalize(cross(forward, up));
up = cross(right, forward);
const auto m = mat4
{{
{right[0], up[0], -forward[0], T{0}},
{right[1], up[1], -forward[1], T{0}},
{right[2], up[2], -forward[2], T{0}},
{T{0}, T{0}, T{0}, T{1}}
}};
return mul(m, translate(-position));
}
template
constexpr matrix mul(const matrix& a, const matrix& b) noexcept
{
matrix c = matrix