/* * Copyright (C) 2023 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #ifndef ANTKEEPER_MATH_MATRIX_HPP #define ANTKEEPER_MATH_MATRIX_HPP #include #include #include #include #include namespace math { /** * *n* by *m* column-major matrix. * * @tparam T Element type. * @tparam N Number of columns. * @tparam M Number of rows. * * @see https://en.wikipedia.org/wiki/Row-_and_column-major_order */ template struct matrix { /// Element type. using element_type = T; /// Number of columns. static constexpr std::size_t column_count = N; /// Number of rows. static constexpr std::size_t row_count = M; /// Number of elements. static constexpr std::size_t element_count = column_count * row_count; /// Matrix column vector data type. using column_vector_type = vector; /// Matrix row vector data type. using row_vector_type = vector; /// Array of matrix column vectors. column_vector_type columns[column_count]; /// @name Conversion /// @{ /// @private template [[nodiscard]] inline constexpr matrix type_cast(std::index_sequence) const noexcept { return {vector(columns[I])...}; } /** * Type-casts the elements of this matrix using `static_cast`. * * @tparam U Target element type. * * @return Matrix containing the type-casted elements. */ template [[nodiscard]] inline constexpr explicit operator matrix() const noexcept { return type_cast(std::make_index_sequence{}); } /// @private template [[nodiscard]] inline constexpr matrix size_cast(std::index_sequence) const noexcept { if constexpr (O == M) { return {((I < N) ? columns[I] : matrix::identity()[I]) ...}; } else { return {((I < N) ? vector(columns[I]) : matrix::identity()[I]) ...}; } } /** * Size-casts this matrix to a matrix with different dimensions. Casting to greater dimensions causes new elements to be set to identity matrix elements. * * @tparam P Target number of columns. * @tparam O Target number of rows. * * @return *p* by *o* matrix. */ template [[nodiscard]] inline constexpr explicit operator matrix() 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::zero(); for (std::size_t i = 0; i < P; ++i) { for (std::size_t j = 0; j < M; ++j) { for (std::size_t k = 0; k < N; ++k) { c[i][j] += a[k][j] * b[i][k]; } } } return c; } /// @private template inline constexpr matrix mul(const matrix& a, T b, std::index_sequence) noexcept { return {(a[I] * b) ...}; } template constexpr matrix mul(const matrix& a, T b) noexcept { return mul(a, b, std::make_index_sequence{}); } /// @private template inline constexpr typename matrix::column_vector_type mul(const matrix& a, const typename matrix::row_vector_type& b, std::index_sequence) noexcept { return ((a[I] * b[I]) + ...); } template constexpr typename matrix::column_vector_type mul(const matrix& a, const typename matrix::row_vector_type& b) noexcept { return mul(a, b, std::make_index_sequence{}); } /// @private template inline constexpr typename matrix::row_vector_type mul(const typename matrix::column_vector_type& a, const matrix& b, std::index_sequence) noexcept { return {dot(a, b[I]) ...}; } template constexpr typename matrix::row_vector_type mul(const typename matrix::column_vector_type& a, const matrix& b) noexcept { return mul(a, b, std::make_index_sequence{}); } template mat3 rotate(T angle, const vector& axis) { const T c = std::cos(angle); const T s = std::sin(angle); const vector temp = mul(axis, T{1} - c); mat3 rotation; rotation[0][0] = axis[0] * temp[0] + c; rotation[0][1] = axis[1] * temp[0] + axis[2] * s; rotation[0][2] = axis[2] * temp[0] - axis[1] * s; rotation[1][0] = axis[0] * temp[1] - axis[2] * s; rotation[1][1] = axis[1] * temp[1] + c; rotation[1][2] = axis[2] * temp[1] + axis[0] * s; rotation[2][0] = axis[0] * temp[2] + axis[1] * s; rotation[2][1] = axis[1] * temp[2] - axis[0] * s; rotation[2][2] = axis[2] * temp[2] + c; return rotation; } template mat3 rotate_x(T angle) { const T c = std::cos(angle); const T s = std::sin(angle); return mat3 { T{1}, T{0}, T{0}, T{0}, c, s, T{0}, -s, c }; } template mat3 rotate_y(T angle) { const T c = std::cos(angle); const T s = std::sin(angle); return mat3 { c, T{0}, -s, T{0}, T{1}, T{0}, s, T{0}, c }; } template mat3 rotate_z(T angle) { const T c = std::cos(angle); const T s = std::sin(angle); return mat3 { c, s, T{0}, -s, c, T{0}, T{0}, T{0}, T{1} }; } template constexpr mat4 scale(const vec3& v) { return {{ {v[0], T{0}, T{0}, T{0}}, {T{0}, v[1], T{0}, T{0}}, {T{0}, T{0}, v[2], T{0}}, {T{0}, T{0}, T{0}, T{1}} }}; } /// @private template inline constexpr matrix sub(const matrix& a, const matrix& b, std::index_sequence) noexcept { return {(a[I] - b[I]) ...}; } template constexpr matrix sub(const matrix& a, const matrix& b) noexcept { return sub(a, b, std::make_index_sequence{}); } /// @private template inline constexpr matrix sub(const matrix& a, T b, std::index_sequence) noexcept { return {(a[I] - b) ...}; } template constexpr matrix sub(const matrix& a, T b) noexcept { return sub(a, b, std::make_index_sequence{}); } /// @private template inline constexpr matrix sub(T a, const matrix& b, std::index_sequence) noexcept { return {(a - b[I]) ...}; } template constexpr matrix sub(T a, const matrix& b) noexcept { return sub(a, b, std::make_index_sequence{}); } /// @private template inline constexpr T trace(const matrix& m, std::index_sequence) noexcept { return ((m[I][I]) + ...); } template constexpr T trace(const matrix& m) noexcept { return trace(m, std::make_index_sequence{}); } template constexpr mat4 translate(const vec3& v) { return {{ {T{1}, T{0}, T{0}, T{0}}, {T{0}, T{1}, T{0}, T{0}}, {T{0}, T{0}, T{1}, T{0}}, {v[0], v[1], v[2], T{1}} }}; } /// @private template inline constexpr typename matrix::column_vector_type transpose_column(const matrix& m, std::size_t i, std::index_sequence) noexcept { return {m[I][i] ...}; } /// @private template inline constexpr matrix transpose(const matrix& m, std::index_sequence) noexcept { return {transpose_column(m, I, std::make_index_sequence{}) ...}; } template constexpr matrix transpose(const matrix& m) noexcept { return transpose(m, std::make_index_sequence{}); } namespace operators { /// @copydoc add(const matrix&, const matrix&) template inline constexpr matrix operator+(const matrix& a, const matrix& b) noexcept { return add(a, b); } /// @copydoc add(const matrix&, T) /// @{ template inline constexpr matrix operator+(const matrix& a, T b) noexcept { return add(a, b); } template inline constexpr matrix operator+(T a, const matrix& b) noexcept { return add(b, a); } /// @} /// @copydoc div(const matrix&, const matrix&) template inline constexpr matrix operator/(const matrix& a, const matrix& b) noexcept { return div(a, b); } /// @copydoc div(const matrix&, T) template inline constexpr matrix operator/(const matrix& a, T b) noexcept { return div(a, b); } /// @copydoc div(T, const matrix&) template inline constexpr matrix operator/(T a, const matrix& b) noexcept { return div(a, b); } /// @copydoc mul(const matrix&, const matrix&) template inline constexpr matrix operator*(const matrix& a, const matrix& b) noexcept { return mul(a, b); } /// @copydoc mul(const matrix&, T) /// @{ template inline constexpr matrix operator*(const matrix& a, T b) noexcept { return mul(a, b); } template inline constexpr matrix operator*(T a, const matrix& b) noexcept { return mul(b, a); } /// @} /// @copydoc mul(const matrix&, const typename matrix::row_vector_type&) template inline constexpr typename matrix::column_vector_type operator*(const matrix& a, const typename matrix::row_vector_type& b) noexcept { return mul(a, b); } /// @copydoc mul(const typename matrix::column_vector_type&, const matrix&) template inline constexpr typename matrix::row_vector_type operator*(const typename matrix::column_vector_type& a, const matrix& b) noexcept { return mul(a, b); } /// @copydoc sub(const matrix&, const matrix&) template inline constexpr matrix operator-(const matrix& a, const matrix& b) noexcept { return sub(a, b); } /// @copydoc sub(const matrix&, T) template inline constexpr matrix operator-(const matrix& a, T b) noexcept { return sub(a, b); } /// @copydoc sub(T, const matrix&) template inline constexpr matrix operator-(T a, const matrix& b) noexcept { return sub(a, b); } /** * Adds two values and stores the result in the first value. * * @param a First value. * @param b Second value. * * @return Reference to the first value. */ /// @{ template inline constexpr matrix& operator+=(matrix& a, const matrix& b) noexcept { return (a = a + b); } template inline constexpr matrix& operator+=(matrix& a, T b) noexcept { return (a = a + b); } /// @} /** * Subtracts the first value by the second value and stores the result in the first value. * * @param a First value. * @param b Second value. * * @return Reference to the first value. */ /// @{ template inline constexpr matrix& operator-=(matrix& a, const matrix& b) noexcept { return (a = a - b); } template inline constexpr matrix& operator-=(matrix& a, T b) noexcept { return (a = a - b); } /// @} /** * Multiplies two values and stores the result in the first value. * * @param a First value. * @param b Second value. * * @return Reference to the first value. */ /// @{ template inline constexpr matrix& operator*=(matrix& a, const matrix& b) noexcept { return (a = a * b); } template inline constexpr matrix& operator*=(matrix& a, T b) noexcept { return (a = a * b); } /// @} /** * Divides the first value by the second value and stores the result in the first value. * * @param a First value. * @param b Second value. * * @return Reference to the first value. */ /// @{ template inline constexpr matrix& operator/=(matrix& a, const matrix& b) noexcept { return (a = a / b); } template inline constexpr matrix& operator/=(matrix& a, T b) noexcept { return (a = a / b); } /// @} } // namespace operators } // namespace math // Bring matrix operators into global namespace using namespace math::operators; // Structured binding support namespace std { /** * Provides access to the number of columns in a matrix as a compile-time constant expression. * * @tparam T Element type. * @tparam N Number of columns. * @tparam M Number of rows. */ template struct tuple_size> { /// Number of columns in the matrix. static constexpr std::size_t value = math::matrix::column_count; }; /** * Provides compile-time indexed access to the type of the columns in a matrix using a tuple-like interface. * * @tparam I Index of a column. * @tparam T Element type. * @tparam N Number of columns. * @tparam M Number of rows. */ template struct tuple_element> { /// Type of columns in the matrix. using type = math::matrix::column_vector_type; }; } #endif // ANTKEEPER_MATH_MATRIX_HPP