- Started 2D Transform Component and relevant math extensions - Switched sequence to use pointers instead of arrays
722 lines
24 KiB
C++
722 lines
24 KiB
C++
// =====================================================================================================================
|
|
// fennec, a free and open source game engine
|
|
// Copyright © 2025 Medusa Slockbower
|
|
//
|
|
// This program 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.
|
|
//
|
|
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
|
// =====================================================================================================================
|
|
|
|
///
|
|
/// \file matrix.h
|
|
/// \brief the \ref fennec_math_matrix
|
|
///
|
|
///
|
|
/// \details
|
|
/// \author Medusa Slockbower
|
|
///
|
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
|
///
|
|
///
|
|
|
|
#ifndef FENNEC_MATH_MATRIX_H
|
|
#define FENNEC_MATH_MATRIX_H
|
|
|
|
///
|
|
///
|
|
/// \page fennec_math_matrix Matrices
|
|
///
|
|
/// \brief The fennec Matrix Math Module
|
|
///
|
|
/// \code #include <fennec/math/matrix.h> \endcode
|
|
///
|
|
///
|
|
///
|
|
///
|
|
|
|
#include <fennec/math/detail/_fwd.h>
|
|
#include <fennec/math/detail/_matrix.h>
|
|
|
|
#include <fennec/containers/array.h>
|
|
|
|
#include <fennec/math/geometric.h>
|
|
#include <fennec/math/vector_traits.h>
|
|
|
|
namespace fennec
|
|
{
|
|
|
|
|
|
///
|
|
/// \brief returns a **copy** of the column \f$i\f$ of matrix \f$m\f$
|
|
/// \param m the matrix
|
|
/// \param i the index of the row
|
|
/// \returns a **copy** of the column at index \f$i\f$
|
|
template<typename scalar, size_t rows, size_t...cols>
|
|
constexpr vec<scalar, rows> column(const matrix<scalar, rows, cols...>& m, size_t i) noexcept {
|
|
return m[i];
|
|
}
|
|
|
|
|
|
///
|
|
/// \brief returns a **copy** of the row \f$i\f$ of matrix \f$m\f$
|
|
/// \param m the matrix
|
|
/// \param i the index of the row
|
|
/// \returns a **copy** of the row at index \f$i\f$
|
|
template<typename scalar, size_t rows, size_t...cols>
|
|
constexpr vec<scalar, sizeof...(cols)> row(const matrix<scalar, rows, cols...>& m, size_t i) noexcept {
|
|
return vec<scalar, sizeof...(cols)>(m[cols][i]...);
|
|
}
|
|
|
|
|
|
template<typename ScalarT>
|
|
using tmat2x2 = mat<ScalarT, 2, 2>; ///< helper for creating 2x2 matrices of the specified type.
|
|
template<typename ScalarT> using tmat2x3 = mat<ScalarT, 2, 3>; ///< helper for creating 2x3 matrices of the specified type.
|
|
template<typename ScalarT> using tmat2x4 = mat<ScalarT, 2, 4>; ///< helper for creating 2x4 matrices of the specified type.
|
|
template<typename ScalarT> using tmat3x2 = mat<ScalarT, 3, 2>; ///< helper for creating 3x2 matrices of the specified type.
|
|
template<typename ScalarT> using tmat3x3 = mat<ScalarT, 3, 3>; ///< helper for creating 3x3 matrices of the specified type.
|
|
template<typename ScalarT> using tmat3x4 = mat<ScalarT, 3, 4>; ///< helper for creating 3x4 matrices of the specified type.
|
|
template<typename ScalarT> using tmat4x2 = mat<ScalarT, 4, 2>; ///< helper for creating 4x2 matrices of the specified type.
|
|
template<typename ScalarT> using tmat4x3 = mat<ScalarT, 4, 3>; ///< helper for creating 4x3 matrices of the specified type.
|
|
template<typename ScalarT> using tmat4x4 = mat<ScalarT, 4, 4>; ///< helper for creating 4x4 matrices of the specified type.
|
|
|
|
using mat2 = tmat2x2<float_t>; ///< Specification for glsl float matrices
|
|
using mat3 = tmat3x3<float_t>; ///< Specification for glsl float matrices
|
|
using mat4 = tmat4x4<float_t>; ///< Specification for glsl float matrices
|
|
|
|
using mat2x2 = tmat2x2<float_t>; ///< Specification for sized glsl float matrices
|
|
using mat2x3 = tmat2x3<float_t>; ///< Specification for sized glsl float matrices
|
|
using mat2x4 = tmat2x4<float_t>; ///< Specification for sized glsl float matrices
|
|
using mat3x2 = tmat3x2<float_t>; ///< Specification for sized glsl float matrices
|
|
using mat3x3 = tmat3x3<float_t>; ///< Specification for sized glsl float matrices
|
|
using mat3x4 = tmat3x4<float_t>; ///< Specification for sized glsl float matrices
|
|
using mat4x2 = tmat4x2<float_t>; ///< Specification for sized glsl float matrices
|
|
using mat4x3 = tmat4x3<float_t>; ///< Specification for sized glsl float matrices
|
|
using mat4x4 = tmat4x4<float_t>; ///< Specification for sized glsl float matrices
|
|
|
|
using dmat2 = tmat2x2<double_t>; ///< Specification for glsl double matrices
|
|
using dmat3 = tmat3x3<double_t>; ///< Specification for glsl double matrices
|
|
using dmat4 = tmat3x3<double_t>; ///< Specification for glsl double matrices
|
|
|
|
using dmat2x2 = tmat2x2<double_t>; ///< Specification for size glsl double matrices
|
|
using dmat2x3 = tmat2x3<double_t>; ///< Specification for size glsl double matrices
|
|
using dmat2x4 = tmat2x4<double_t>; ///< Specification for size glsl double matrices
|
|
using dmat3x2 = tmat3x2<double_t>; ///< Specification for size glsl double matrices
|
|
using dmat3x3 = tmat3x3<double_t>; ///< Specification for size glsl double matrices
|
|
using dmat3x4 = tmat3x4<double_t>; ///< Specification for size glsl double matrices
|
|
using dmat4x2 = tmat4x2<double_t>; ///< Specification for size glsl double matrices
|
|
using dmat4x3 = tmat4x3<double_t>; ///< Specification for size glsl double matrices
|
|
using dmat4x4 = tmat4x4<double_t>; ///< Specification for size glsl double matrices
|
|
|
|
|
|
///
|
|
/// \brief Multiply matrix \$x\f$ by matrix \f$y\f$ component-wise.
|
|
/// \details Multiply matrix x by matrix y component-wise, i.e., result[i][j] is the scalar product of x[i][j] and y[i][j].<br><br>
|
|
/// Note: to get linear algebraic matrix multiplication, use
|
|
/// the multiply operator (*)
|
|
/// \param x the first matrix
|
|
/// \param y the second matrix
|
|
/// \returns the resulting product in a matrix of the same size and base type
|
|
template<typename scalar, size_t rows, size_t...cols>
|
|
constexpr matrix<scalar, rows, cols...> matrixCompMult(const matrix<scalar, rows, cols...>& x, const matrix<scalar, rows, cols...>& y) noexcept {
|
|
return matrix<scalar, rows, cols...>(x[cols] * y[cols] ...);
|
|
}
|
|
|
|
///
|
|
/// \brief Performs a linear algebraic multiply, multiplying \f$c\f$ by the components of \f$r\f$, producing a matrix.
|
|
///
|
|
/// \details Treats the first parameter \f$c\f$ as a column vector (matrix
|
|
/// with one column) and the second parameter \f$r\f$ as a row
|
|
/// vector (matrix with one row) and does a linear algebraic
|
|
/// matrix multiply \f$c \cross r\f$, yielding a matrix whose number of
|
|
/// rows is the number of components in \f$c\f$ and whose
|
|
/// number of columns is the number of components in \f$r\f$.
|
|
/// \param c the column vector
|
|
/// \param r the row vector
|
|
/// \returns the resulting matrix produced by the linear algebraic product
|
|
template<typename scalar, size_t...s0, size_t...s1>
|
|
constexpr matrix<scalar, sizeof...(s0), s1...> outerProduct(const vector<scalar, s0...>& c, const vector<scalar, s1...>& r) noexcept {
|
|
return matrix<scalar, sizeof...(s0), s1...>(
|
|
c * r[s1]...
|
|
);
|
|
}
|
|
|
|
///
|
|
/// \brief get the transpose of \f$m\f$
|
|
/// \param m the matrix to transpose
|
|
/// \returns a matrix that is the transpose of \f$m\f$
|
|
/// \details The input matrix m is not modified.
|
|
template<typename scalar, size_t rows, size_t...cols>
|
|
constexpr mat<scalar, rows, sizeof...(cols)> transpose(const matrix<scalar, rows, cols...>& m) noexcept {
|
|
return mat<scalar, rows, sizeof...(cols)>::transpose(m);
|
|
}
|
|
|
|
///
|
|
/// \brief Returns the determinant of m.
|
|
/// \param m the matrix
|
|
/// \returns the determinant of m.
|
|
template<typename scalar, size_t rows, size_t...cols>
|
|
constexpr scalar determinant(const matrix<scalar, rows, cols...>&) noexcept {
|
|
// ReSharper disable once CppStaticAssertFailure
|
|
static_assert(false, "implementation undefined");
|
|
return 0;
|
|
}
|
|
|
|
template<typename scalar, size_t rows, size_t...cols>
|
|
constexpr matrix<scalar, rows, cols...> inverse(const matrix<scalar, rows, cols...>&) noexcept {
|
|
// ReSharper disable once CppStaticAssertFailure
|
|
static_assert(false, "implementation undefined");
|
|
return 1;
|
|
}
|
|
|
|
///
|
|
/// \brief
|
|
/// \tparam ScalarT
|
|
/// \tparam RowsV
|
|
/// \tparam ColIndicesV
|
|
template<typename ScalarT, size_t RowsV, size_t...ColIndicesV>
|
|
struct matrix
|
|
{
|
|
// Assertions ==========================================================================================================
|
|
|
|
static_assert(is_arithmetic_v<ScalarT> or is_bool_v<ScalarT>);
|
|
|
|
|
|
// Typedefs & Constants ================================================================================================
|
|
|
|
///
|
|
/// \brief number of rows in the matrix
|
|
static constexpr size_t rows = RowsV;
|
|
|
|
///
|
|
/// \brief number of columns in the matrix
|
|
static constexpr size_t columns = sizeof...(ColIndicesV);
|
|
|
|
///
|
|
/// \brief number of total components
|
|
static constexpr size_t num_components = rows * columns;
|
|
|
|
///
|
|
/// \brief vector class correspondant to the rows
|
|
using row_t = vec<ScalarT, columns>;
|
|
|
|
///
|
|
/// \brief vector class correspondant to the columns
|
|
using column_t = vec<ScalarT, rows>;
|
|
|
|
///
|
|
/// \brief base scalar type
|
|
using scalar_t = ScalarT;
|
|
|
|
///
|
|
/// \brief alias for this matrix type
|
|
using matrix_t = matrix;
|
|
|
|
///
|
|
/// \brief alias for the transpose matrix type
|
|
using transpose_t = mat<ScalarT, rows, columns>;
|
|
|
|
|
|
///
|
|
/// \brief matrix array data
|
|
array<column_t, columns> data;
|
|
|
|
|
|
|
|
// Constructors ========================================================================================================
|
|
|
|
/// \name Constructors
|
|
/// @{
|
|
|
|
|
|
///
|
|
/// \brief default constructor, initializes elements with 0
|
|
///
|
|
/// \details
|
|
constexpr matrix() = default;
|
|
|
|
|
|
///
|
|
/// \brief copy constructor
|
|
///
|
|
/// \details
|
|
/// \param mat matrix to copy
|
|
constexpr matrix(const matrix_t& mat)
|
|
: data{ mat.data } {
|
|
}
|
|
|
|
///
|
|
/// \brief move constructor
|
|
///
|
|
/// \details
|
|
/// \param mat matrix to move
|
|
constexpr matrix(matrix_t&& mat) noexcept
|
|
: data{ mat.data } {
|
|
}
|
|
|
|
template<typename OScalarT>
|
|
constexpr matrix(const matrix<OScalarT, RowsV, ColIndicesV...>& mat)
|
|
: matrix() {
|
|
for (size_t i = 0; i < columns; ++i) {
|
|
for (size_t j = 0; j < rows; ++j) {
|
|
data[i][j] = scalar_t(mat[i][j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename OScalarT>
|
|
constexpr matrix(matrix<OScalarT, RowsV, ColIndicesV...>&& mat) noexcept
|
|
: matrix() {
|
|
for (size_t i = 0; i < columns; ++i) {
|
|
for (size_t j = 0; j < rows; ++j) {
|
|
data[i][j] = scalar_t(mat[i][j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///
|
|
/// \brief scalar constructor, initializes a diagonal matrix with a scale of \p s
|
|
///
|
|
/// \details
|
|
/// This function creates a diagonal matrix such that ```vec3(2.0f)``` would result in a matrix
|
|
/// <table>
|
|
/// <caption id="fennec_table_matrix_diagonal"></caption>
|
|
/// <tr><th> <th> 0 <th> 1 <th> 2
|
|
/// <tr><th> 0 <td>2.0<td>0.0<td>0.0
|
|
/// <tr><th> 1 <td>0.0<td>2.0<td>0.0
|
|
/// <tr><th> 2 <td>0.0<td>0.0<td>2.0
|
|
/// </table><br><br>
|
|
///
|
|
/// \param s scalar value
|
|
constexpr matrix(scalar_t s) {
|
|
(((ColIndicesV < rows) ? data[ColIndicesV][ColIndicesV] = s : 0), ...);
|
|
}
|
|
|
|
|
|
///
|
|
/// \brief Piece-wise constructor
|
|
///
|
|
/// \details
|
|
/// \tparam ArgsT
|
|
/// \param args
|
|
template<typename...ArgsT> requires(total_component_count_v<ArgsT...> == num_components)
|
|
constexpr matrix(ArgsT&&...args) {
|
|
matrix::_construct(fennec::forward<ArgsT>(args)...);
|
|
}
|
|
|
|
/// @}
|
|
|
|
// Assignment Operators ================================================================================================
|
|
|
|
/// \name Assignment Operators
|
|
/// @{
|
|
|
|
///
|
|
/// \brief copy assignment operator
|
|
///
|
|
/// \details
|
|
/// \returns a reference to **this** after copying the contents of \p rhs
|
|
/// \param rhs the matrix to copy
|
|
constexpr matrix_t& operator=(const matrix_t& rhs) {
|
|
data = rhs.data; return *this;
|
|
}
|
|
|
|
///
|
|
/// \brief move assignment operator
|
|
///
|
|
/// \details
|
|
/// \returns a reference to **this** after moving the contents of \p rhs
|
|
/// \param rhs the matrix to move
|
|
constexpr matrix_t& operator=(matrix_t&& rhs) noexcept {
|
|
data = rhs.data; return *this;
|
|
}
|
|
|
|
/// @}
|
|
|
|
|
|
// Access Operators ====================================================================================================
|
|
|
|
/// \name Access Operator
|
|
/// @{
|
|
|
|
///
|
|
/// \copydetails matrix::operator[](size_t) const
|
|
constexpr column_t& operator[](size_t i) {
|
|
return data[i];
|
|
}
|
|
|
|
///
|
|
/// \brief returns the column at index \f$i\f$
|
|
///
|
|
/// \details
|
|
/// \param i the index
|
|
/// \returns the column at index \f$i\f$
|
|
constexpr const column_t& operator[](size_t i) const {
|
|
return data[i];
|
|
}
|
|
|
|
///
|
|
/// \copydetails matrix::operator()(size_t, size_t) const
|
|
constexpr scalar_t& operator[](size_t i, size_t j) {
|
|
return data[i][j];
|
|
}
|
|
|
|
///
|
|
/// \brief returns the cell in row \p j column \p i
|
|
/// \param i the column
|
|
/// \param j the row
|
|
/// \returns the cell at the specified index.
|
|
constexpr scalar_t operator[](size_t i, size_t j) const {
|
|
return data[i][j];
|
|
}
|
|
|
|
/// @}
|
|
|
|
// Scalar Operators ====================================================================================================
|
|
|
|
/// \name Scalar Operators
|
|
/// @{
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar addition operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns a copy of the matrix with each component having been added by the scalar
|
|
constexpr friend matrix_t operator+(const matrix_t& lhs, scalar_t rhs) {
|
|
return matrix_t(lhs[ColIndicesV] + rhs ...);
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" addition operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns a copy of the matrix with each component having been added by the scalar
|
|
constexpr friend matrix_t operator+(scalar_t lhs, const matrix_t& rhs) {
|
|
return matrix_t(lhs + rhs[ColIndicesV] ...);
|
|
}
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar subtraction operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns a copy of the matrix with each component having been subtracted by the scalar
|
|
constexpr friend matrix_t operator-(const matrix_t& lhs, scalar_t rhs) {
|
|
return matrix_t(lhs[ColIndicesV] - rhs ...);
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" subtraction operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns a copy of the matrix with each component having been subtracted by the scalar
|
|
constexpr friend matrix_t operator-(scalar_t lhs, const matrix_t& rhs) {
|
|
return matrix_t(lhs - rhs[ColIndicesV] ...);
|
|
}
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar multiplication operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns a copy of the matrix with each component having been multiplied by the scalar
|
|
constexpr friend matrix_t operator*(const matrix_t& lhs, scalar_t rhs) {
|
|
return matrix_t(lhs[ColIndicesV] * rhs ...);
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" multiplication operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns a copy of the matrix with each component having been multiplied by the scalar
|
|
constexpr friend matrix_t operator*(scalar_t lhs, const matrix_t& rhs) {
|
|
return matrix_t(lhs * rhs[ColIndicesV] ...);
|
|
}
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar division operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns a copy of the matrix with each component having been divided by the scalar
|
|
constexpr friend matrix_t operator/(const matrix_t& lhs, scalar_t rhs) {
|
|
return matrix_t(lhs[ColIndicesV] / rhs ...);
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" division operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns a copy of the matrix with each component having been divided by the scalar
|
|
constexpr friend matrix_t operator/(scalar_t lhs, const matrix_t& rhs) {
|
|
return matrix_t(lhs / rhs[ColIndicesV] ...);
|
|
}
|
|
|
|
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar addition assignment operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns the matrix after having each component added by the scalar
|
|
constexpr friend matrix_t& operator+=(matrix_t& lhs, scalar_t rhs) {
|
|
((lhs[ColIndicesV] += rhs), ...);
|
|
return lhs;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" addition assignment operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns the matrix after having each component added by the scalar
|
|
constexpr friend matrix_t& operator+=(scalar_t lhs, matrix_t& rhs) {
|
|
((rhs[ColIndicesV] += lhs), ...);
|
|
return rhs;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar subtraction assignment operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns the matrix after having each component subtracted by the scalar
|
|
constexpr friend matrix_t& operator-=(matrix_t& lhs, scalar_t rhs) {
|
|
((lhs[ColIndicesV] -= rhs), ...);
|
|
return lhs;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" addition assignment operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns the matrix after having each component added by the scalar
|
|
constexpr friend matrix_t& operator-=(scalar_t lhs, matrix_t& rhs) {
|
|
((rhs[ColIndicesV] -= lhs), ...);
|
|
return rhs;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar multiplication assignment operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns the matrix after having each component multiplied by the scalar
|
|
constexpr friend matrix_t& operator*=(matrix_t& lhs, scalar_t rhs) {
|
|
((lhs[ColIndicesV] *= rhs), ...);
|
|
return lhs;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" multiplication assignment operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns the matrix after having each component multiplied by the scalar
|
|
constexpr friend matrix_t& operator*=(scalar_t lhs, matrix_t& rhs) {
|
|
((rhs[ColIndicesV] *= lhs), ...);
|
|
return rhs;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar division assignment operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns the matrix after having each component divided by the scalar
|
|
constexpr friend matrix_t& operator/=(matrix_t& lhs, scalar_t rhs) {
|
|
((lhs[ColIndicesV] /= rhs), ...);
|
|
return lhs;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" division assignment operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns the matrix after having each component divided by the scalar
|
|
constexpr friend matrix_t& operator/=(scalar_t lhs, matrix_t& rhs) {
|
|
((rhs[ColIndicesV] /= lhs), ...);
|
|
return rhs;
|
|
}
|
|
|
|
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar modulo operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns a copy of the matrix with each component having been reduced modulo by the scalar
|
|
constexpr friend matrix_t operator%(const matrix_t& lhs, scalar_t rhs) requires is_integral_v<scalar_t> {
|
|
matrix_t retval = lhs;
|
|
((retval[ColIndicesV] %= rhs), ...);
|
|
return retval;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" modulo operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns a copy of the matrix with each component having been reduced modulo by the scalar
|
|
constexpr friend matrix_t operator%(scalar_t lhs, const matrix_t& rhs) requires is_integral_v<scalar_t> {
|
|
matrix_t retval = rhs;
|
|
((retval[ColIndicesV] %= lhs), ...);
|
|
return retval;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref fennec::matrix "matrix" - \ref scalar modulo assignment operator.
|
|
/// \param lhs the matrix
|
|
/// \param rhs the scalar
|
|
/// \returns the matrix after having each component reduced modulo by the scalar
|
|
constexpr friend matrix_t& operator%=(matrix_t& lhs, scalar_t rhs) requires is_integral_v<scalar_t> {
|
|
((lhs[ColIndicesV] %= rhs), ...);
|
|
return lhs;
|
|
}
|
|
|
|
///
|
|
/// \brief \ref scalar - \ref fennec::matrix "matrix" modulo assignment operator.
|
|
/// \param lhs the scalar
|
|
/// \param rhs the matrix
|
|
/// \returns the matrix after having each component reduced modulo by the scalar
|
|
constexpr friend matrix_t& operator%=(scalar_t lhs, matrix_t& rhs) requires is_integral_v<scalar_t> {
|
|
((rhs[ColIndicesV] %= lhs), ...);
|
|
return rhs;
|
|
}
|
|
|
|
/// @}
|
|
|
|
// Vector Operators ====================================================================================================
|
|
|
|
/// \name \ref fennec::matrix "matrix" - \ref fennec::vector "vector" Operators
|
|
/// @{
|
|
|
|
///
|
|
/// \brief performs a linear algebraic multiply
|
|
/// \param lhs the matrix
|
|
/// \param rhs the vector
|
|
/// \returns a vector containing the dot products of \f$rhs\f$ with each row of \f$lhs\f$
|
|
constexpr friend column_t operator*(const matrix_t& lhs, const row_t& rhs) {
|
|
return _mul(lhs, rhs);
|
|
}
|
|
|
|
///
|
|
/// \brief performs a linear algebraic multiply
|
|
/// \param lhs the vector
|
|
/// \param rhs the matrix
|
|
/// \returns a vector containing the dot products of \f$lhs\f$ with each column of \f$rhs\f$
|
|
constexpr friend row_t operator*(const column_t& lhs, const matrix_t& rhs) {
|
|
return row_t(fennec::dot(fennec::column(rhs, ColIndicesV), lhs) ...);
|
|
}
|
|
|
|
/// @}
|
|
|
|
|
|
|
|
// Matrix Operators ====================================================================================================
|
|
|
|
/// \name \ref fennec::matrix "matrix" - \ref fennec::matrix "matrix" Operators
|
|
/// @{
|
|
|
|
///
|
|
/// \brief matrix comparison operator
|
|
/// \param lhs the first matrix
|
|
/// \param rhs the second matrix
|
|
/// \returns a boolean value that contains \f$true\f$ when all components of `lhs` and `rhs` are equal and \f$false\f$ otherwise
|
|
constexpr friend bool operator==(const matrix_t& lhs, const matrix_t& rhs) {
|
|
return lhs.data == rhs.data;
|
|
}
|
|
|
|
///
|
|
/// \brief matrix comparison operator
|
|
/// \param lhs the first matrix
|
|
/// \param rhs the second matrix
|
|
/// \returns a boolean value that contains \f$true\f$ when all components of `lhs` and `rhs` are not equal and \f$false\f$ otherwise
|
|
constexpr friend bool operator!=(const matrix_t& lhs, const matrix_t& rhs) {
|
|
return lhs.data != rhs.data;
|
|
}
|
|
|
|
///
|
|
/// \brief performs a linear algebraic matrix multiplication
|
|
/// \param lhs the rows to multiply with
|
|
/// \param rhs the columns to multiply with
|
|
template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
|
|
constexpr friend matrix<scalar_t, RowsV, OColIndicesV...> operator*(const matrix_t& lhs, const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
|
|
return matrix<scalar_t, RowsV, OColIndicesV...>(
|
|
matrix::_mul(lhs, rhs[OColIndicesV])...
|
|
);
|
|
}
|
|
|
|
template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
|
|
constexpr matrix<scalar_t, RowsV, OColIndicesV...>& operator*=(const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
|
|
return *this = *this * rhs;
|
|
}
|
|
|
|
/// @}
|
|
|
|
|
|
|
|
// Helpers =============================================================================================================
|
|
|
|
public:
|
|
|
|
static constexpr matrix_t transpose(const transpose_t& mat) {
|
|
return matrix_t(fennec::row(mat, ColIndicesV)...);
|
|
}
|
|
|
|
private:
|
|
|
|
// ReSharper disable once CppMemberFunctionMayBeStatic
|
|
template<size_t i0 = 0>
|
|
constexpr void _construct() {
|
|
// base case, does nothing, this will get optimized away
|
|
}
|
|
|
|
// helper for parsing parameter packs
|
|
template<size_t i0 = 0, typename HeadT, typename...RestT>
|
|
constexpr void _construct(HeadT&& head, RestT&&...rest) {
|
|
matrix::_insert<i0>(head); // insert the head element
|
|
matrix::_construct<i0 + component_count_v<HeadT>>(std::forward<RestT>(rest)...); // propagate to the rest of the arguments
|
|
}
|
|
|
|
// helper for inserting a scalar value
|
|
template<size_t i0 = 0>
|
|
constexpr void _insert(scalar_t s) {
|
|
data[i0 / rows][i0 % rows] = s;
|
|
}
|
|
|
|
// helper for inserting a scalar value of differing type
|
|
template<size_t i0 = 0, typename OScalarT> requires(is_arithmetic_v<OScalarT>)
|
|
constexpr void _insert(OScalarT s) {
|
|
data[i0 / rows][i0 % rows] = scalar_t(s);
|
|
}
|
|
|
|
// helper for inserting a vector
|
|
template<size_t i0 = 0, size_t...i>
|
|
constexpr void _insert(const vector<scalar_t, i...>& v) {
|
|
(matrix::_insert<i0 + i>(v[i]), ...);
|
|
}
|
|
|
|
// helper for inserting a vector of differing type
|
|
template<size_t i0 = 0, typename OScalarT, size_t...i>
|
|
constexpr void _insert(const vector<OScalarT, i...>& v) {
|
|
(matrix::_insert<i0 + i>(v[i]), ...);
|
|
}
|
|
|
|
// helper for a linear algebraic multiply
|
|
static constexpr column_t _mul(const matrix_t& lhs, const row_t& rhs) {
|
|
// the compiler will optimize this better than writing out a specific definition
|
|
// when compared to glm or CxxSwizzle, this is faster by a significant margin
|
|
// all implementations provide 7 decimal places of precision
|
|
return ((lhs[ColIndicesV] * rhs[ColIndicesV]) + ...);
|
|
}
|
|
};
|
|
|
|
|
|
// Internal ============================================================================================================
|
|
|
|
}
|
|
|
|
|
|
#endif // FENNEC_MATH_MATRIX_H
|