Files
fennec/include/fennec/math/matrix.h
Medusa Slockbower f636feb4f1 - Rough First Pass implementation for format.h
- Started 2D Transform Component and relevant math extensions
 - Switched sequence to use pointers instead of arrays
2025-09-23 18:07:54 -04:00

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