* ~ Akiko ~
*/
-#include <cmath>
-#include <iostream>
-#include <sstream>
#include "Vector.hxx"
// --- generic forwarder ---
template <typename MT, size_t C, size_t R>
class Matrix {
public:
- // --- public data structures ---
+ // --- Generic Matrix: public data structures ---
enum : size_t {
columns = C,
MT m[C][R];
};
- // --- constructors and deconstructors ---
+ // --- Generic Matrix: constructors and deconstructors ---
Matrix()
{
{
}
- // --- default operators ---
+ // --- Generic Matrix: default operators ---
Matrix& operator=(const Matrix& rhs)
{
return ml[cell];
}
- // --- other operators ---
+ // --- Generic Matrix: other operators ---
- // --- public methodes ---
+ Matrix& operator+=(const Matrix& rhs)
+ {
+ for (size_t cell = 0; cell < cells; ++cell)
+ ml[cell] += rhs.ml[cell];
+
+ return *this;
+ }
+
+ template <typename T>
+ Matrix& operator+=(const T& val)
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ ml[cell] += val;
+
+ return *this;
+ }
+
+ Matrix operator+(const Matrix& rhs) const
+ {
+ Matrix mat(*this);
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ mat.ml[cell] += rhs.ml[cell];
+
+ return mat;
+ }
+
+ template <typename T>
+ Matrix operator+(const T& val) const
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix mat(*this);
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ mat.ml[cell] += val;
+
+ return mat;
+ }
+
+ // ---
+
+ Matrix& operator-=(const Matrix& rhs)
+ {
+ for (size_t cell = 0; cell < cells; ++cell)
+ ml[cell] -= rhs.ml[cell];
+
+ return *this;
+ }
+
+ template <typename T>
+ Matrix& operator-=(const T& val)
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ ml[cell] -= val;
+
+ return *this;
+ }
+
+ Matrix operator-(const Matrix& rhs) const
+ {
+ Matrix mat(*this);
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ mat.ml[cell] -= rhs.ml[cell];
+
+ return mat;
+ }
+
+ template <typename T>
+ Matrix operator-(const T& val) const
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix mat(*this);
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ mat.ml[cell] -= val;
+
+ return *this;
+ }
+
+ // ---
+
+ // this one is very tricky, do not use it, it will fail in many ways
+ Matrix& operator*=(const Matrix& rhs)
+ {
+ const MT other_dim = columns;
+ Matrix mat(*this);
+
+ for (size_t row = 0; row < rows; ++row)
+ {
+ for (size_t col = 0; col < columns; ++col)
+ {
+ MT sum = 0.0;
+
+ for (size_t i = 0; i < other_dim; ++i)
+ sum += mat.m[i][row] * rhs.m[col][i];
+
+ mat.m[col][row] = sum;
+ }
+ }
+ *this = mat;
+
+ return *this;
+ }
+
+ template <typename T>
+ Matrix& operator*=(const T& val)
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ ml[cell] *= val;
+
+ return *this;
+ }
+
+ // this one is very tricky, do not use it, it will fail in many ways
+ Matrix operator*(const Matrix& rhs) const
+ {
+ const MT other_dim = columns;
+ Matrix mat(*this);
+
+ for (size_t row = 0; row < rows; ++row)
+ {
+ for (size_t col = 0; col < columns; ++col)
+ {
+ MT sum = 0.0;
+
+ for (size_t i = 0; i < other_dim; ++i)
+ sum += mat.m[i][row] * rhs.m[col][i];
+
+ mat.m[col][row] = sum;
+ }
+ }
+
+ return mat;
+ }
+
+ template <typename T>
+ Matrix operator*(const T& val) const
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix mat(*this);
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ mat.ml[cell] *= val;
+
+ return mat;
+ }
+
+ // ---
+
+ template <typename T>
+ Matrix& operator/=(const T& val)
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ ml[cell] /= val;
+
+ return *this;
+ }
+
+ template <typename T>
+ Matrix operator/(const T& val) const
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix mat(*this);
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ mat.ml[cell] /= val;
+
+ return mat;
+ }
+
+ // --- Generic Matrix: public methodes ---
+
+ template <typename T>
+ void fill(const T& val)
+ {
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ for (size_t cell = 0; cell < cells; ++cell)
+ ml[cell] = val;
+ }
bool isIdentity() const
{
}
}
}
+
+ std::string string() const
+ {
+ std::stringstream result;
+
+ result << "(";
+ for (size_t row = 0; row < rows; ++row)
+ {
+ result << "(";
+ for (size_t col = 0; col < columns; ++col)
+ {
+ result << m[col][row];
+ if (col < (columns - 1))
+ result << ", ";
+ }
+ result << ")";
+ if (row < (rows - 1))
+ result << ", ";
+ }
+ result << ")";
+
+ return result.str();
+ }
};
-// --- 4x4 matrix ---
+// --- Generic Matrix: global operators ---
+
+template <typename T, size_t C, size_t R>
+bool operator==(const Matrix<T, C, R>& mat1, const Matrix<T, C, R>& mat2)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ bool result = true;
+
+ for (size_t cell = 0; cell < (C * R); ++cell)
+ result = result && mat1.ml[cell] == mat2.ml[cell];
+
+ return result;
+}
+
+template <typename T, size_t C, size_t R>
+bool operator!=(const Matrix<T, C, R>& mat1, const Matrix<T, C, R>& mat2)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return !(mat1 == mat2);
+}
+
+template <typename T, size_t C, size_t R>
+std::ostream& operator<<(std::ostream& lhs, const Matrix<T, C, R>& rhs)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ for (size_t cell = 0; cell < (C * R); ++cell)
+ lhs << rhs.ml[cell];
+
+ return lhs;
+}
+
+template <typename T, size_t C, size_t R>
+std::istream& operator<<(std::istream& lhs, Matrix<T, C, R>& rhs)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ for (size_t cell = 0; cell < (C * R); ++cell)
+ lhs >> rhs.ml[cell];
+
+ return lhs;
+}
+
+// ---
+
+template <typename T, size_t C, size_t R>
+Matrix<T, C, R> operator+(const Matrix<T, C, R>& mat1, const Matrix<T, C, R>& mat2)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<T, C, R> mat(mat1);
+
+ for (size_t cell = 0; cell < mat.cells; ++cell)
+ mat.ml[cell] += mat2.ml[cell];
+
+ return mat;
+}
+
+template <typename Mat, size_t C, size_t R, typename Val>
+Matrix<Mat, C, R> operator+(const Matrix<Mat, C, R>& mat, const Val& val)
+{
+ static_assert (std::is_integral<Mat>::value || std::is_floating_point<Mat>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<Mat, C, R> m(mat);
+
+ for (size_t cell = 0; cell < m.cells; ++cell)
+ m.ml[cell] += val;
+
+ return m;
+}
+
+template <typename Val, typename Mat, size_t C, size_t R>
+Matrix<Mat, C, R> operator+(const Val& val, const Matrix<Mat, C, R>& mat)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Mat>::value || std::is_floating_point<Mat>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<Mat, C, R> m;
+
+ for (size_t cell = 0; cell < m.cells; ++cell)
+ m.ml[cell] = val + mat.ml[cell];
+
+ return m;
+}
+
+// ---
+
+template <typename T, size_t C, size_t R>
+Matrix<T, C, R> operator-(const Matrix<T, C, R>& mat1, const Matrix<T, C, R>& mat2)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<T, C, R> mat(mat1);
+
+ for (size_t cell = 0; cell < mat.cells; ++cell)
+ mat.ml[cell] -= mat2.ml[cell];
+
+ return mat;
+}
+
+template <typename Mat, size_t C, size_t R, typename Val>
+Matrix<Mat, C, R> operator-(const Matrix<Mat, C, R>& mat, const Val& val)
+{
+ static_assert (std::is_integral<Mat>::value || std::is_floating_point<Mat>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<Mat, C, R> m(mat);
+
+ for (size_t cell = 0; cell < m.cells; ++cell)
+ m.ml[cell] -= val;
+
+ return m;
+}
+
+template <typename Val, typename Mat, size_t C, size_t R>
+Matrix<Mat, C, R> operator-(const Val& val, const Matrix<Mat, C, R>& mat)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Mat>::value || std::is_floating_point<Mat>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<Mat, C, R> m;
+
+ for (size_t cell = 0; cell < m.cells; ++cell)
+ m.ml[cell] = val - mat.ml[cell];
+
+ return m;
+}
+
+// ---
+
+// this one is very tricky, do not use it, it will fail in many ways
+template <typename T, size_t C, size_t R>
+Matrix<T, C, R> operator*(const Matrix<T, C, R>& mat1, const Matrix<T, C, R>& mat2)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ const T other_dim = C * R;
+ Matrix<T, C, R> mat;
+
+ for (size_t row = 0; row < mat.rows; ++row)
+ {
+ for (size_t col = 0; col < mat.columns; ++col)
+ {
+ T sum = 0.0;
+
+ for (size_t i = 0; i < other_dim; ++i)
+ sum += mat1.m[i][row] * mat2.m[col][i];
+
+ mat.m[col][row] = sum;
+ }
+ }
+
+ return mat;
+}
+
+template <typename Mat, size_t C, size_t R, typename Val>
+Matrix<Mat, C, R> operator*(const Matrix<Mat, C, R>& mat, const Val& val)
+{
+ static_assert (std::is_integral<Mat>::value || std::is_floating_point<Mat>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<Mat, C, R> m(mat);
+
+ for (size_t cell = 0; cell < mat.cells; ++cell)
+ m.ml[cell] *= val;
+
+ return m;
+}
+
+template <typename Val, typename Mat, size_t C, size_t R>
+Matrix<Mat, C, R> operator*(const Val& val, const Matrix<Mat, C, R>& mat)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Mat>::value || std::is_floating_point<Mat>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<Mat, C, R> m;
+
+ for (size_t cell = 0; cell < m.cells; ++cell)
+ m.ml[cell] = val * mat.ml[cell];
+
+ return m;
+}
+
+// ---
+
+template <typename Mat, size_t C, size_t R, typename Val>
+Matrix<Mat, C, R> operator/(const Matrix<Mat, C, R>& mat, const Val& val)
+{
+ static_assert (std::is_integral<Mat>::value || std::is_floating_point<Mat>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<Mat, C, R> m(mat);
+
+ for (size_t cell = 0; cell < m.cells; ++cell)
+ m.ml[cell] /= val;
+
+ return m;
+}
+
+template <typename Val, typename Mat, size_t C, size_t R>
+Matrix<Mat, C, R> operator/(const Val& val, const Matrix<Mat, C, R>& mat)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Mat>::value || std::is_floating_point<Mat>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ Matrix<Mat, C, R> m;
+
+ for (size_t cell = 0; cell < m.cells; ++cell)
+ m.ml[cell] = val / mat.ml[cell];
+
+ return m;
+}
+
+
+
+// --- Matrix 4x4 ---
template <typename MT>
class Matrix<MT, 4, 4> {
public:
- // --- public constants ---
+ // --- Matrix 4x4: public constants ---
enum : size_t {
columns = 4,
cells = 4 * 4
};
- // --- public data structures ---
+ // --- Matrix 4x4: public data structures ---
alignas (16) union {
struct {
MT ml[cells];
};
- // --- constructors and deconstructors ---
+ // --- Matrix 4x4: constructors and deconstructors ---
// default is an identity matrix
Matrix()
- : ml{1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1}
+ : ml{1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0}
{
}
{
}
- // --- default operators ---
+ // --- Matrix 4x4: default operators ---
Matrix& operator=(const Matrix& rhs)
{
-m14, -m24, -m34, -m44};
}
- // --- other operators ---
+ // --- Matrix 4x4: other operators ---
Matrix& operator+=(const Matrix& rhs)
{
template <typename T>
Matrix operator-(const T& val) const
{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
return {m11 - val, m21 - val, m31 - val, m41 - val,
m12 - val, m22 - val, m32 - val, m42 - val,
m13 - val, m23 - val, m33 - val, m43 - val,
m14 / val, m24 / val, m34 / val, m44 / val};
}
- // --- public methods ---
+ // --- Matrix 4x4: public methods ---
Vector4<MT> column(const size_t& index) const
{
template <typename T>
void fill(const T& val)
{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
for (size_t cell = 0; cell < cells; ++cell)
ml[cell] = val;
}
void inverte(bool& invertible)
{
- Matrix im(0);
+ Matrix im(0.0);
MT det = determinant(m);
- if (det == static_cast<const MT>(0))
+ if (det == 0.0)
{
invertible = false;
*this == Matrix(); // identity
return;
}
- det = static_cast<const MT>(1) / det;
+ det = 1.0 / det;
invertible = true;
im.m11 = determinant33(m, 1, 2, 3, 1, 2, 3) * det;
}
protected:
- // --- protected methods ---
+ // --- Matrix 4x4: protected methods ---
constexpr MT determinant22(const MT mm[4][4],
- const size_t& col1, const size_t& col2,
- const size_t& row1, const size_t& row2) const
+ const size_t& col1, const size_t& col2,
+ const size_t& row1, const size_t& row2) const
{
return mm[col1][row1] * mm[col2][row2] - mm[col1][row2] * mm[col2][row1];
}
constexpr MT determinant33(const MT mm[4][4],
- const size_t& col1, const size_t& col2, const size_t& col3,
- const size_t& row1, const size_t& row2, const size_t& row3) const
+ const size_t& col1, const size_t& col2, const size_t& col3,
+ const size_t& row1, const size_t& row2, const size_t& row3) const
{
return mm[col1][row1] * determinant22(mm, col2, col3, row2, row3) -
mm[col2][row1] * determinant22(mm, col1, col3, row2, row3) +
mm[3][0] * determinant33(mm, 0, 1, 2, 1, 2, 3);
}
};
+
+// --- Matrix 4x4: global operators ---
+
+template <typename T>
+bool operator==(const Matrix<T, 4, 4>& lhs, const Matrix<T, 4, 4>& rhs)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return lhs.m11 == rhs.m11 && lhs.m21 == rhs.m21 && lhs.m31 == rhs.m31 && lhs.m41 == rhs.m41 &&
+ lhs.m12 == rhs.m12 && lhs.m22 == rhs.m22 && lhs.m32 == rhs.m32 && lhs.m42 == rhs.m42 &&
+ lhs.m13 == rhs.m13 && lhs.m23 == rhs.m23 && lhs.m33 == rhs.m33 && lhs.m43 == rhs.m43 &&
+ lhs.m14 == rhs.m14 && lhs.m24 == rhs.m24 && lhs.m34 == rhs.m34 && lhs.m44 == rhs.m44;
+}
+
+template <typename T>
+bool operator!=(const Matrix<T, 4, 4>& lhs, const Matrix<T, 4, 4>& rhs)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return !(lhs == rhs);
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& lhs, const Matrix<T, 4, 4>& rhs)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ lhs << rhs.m11 << rhs.m21 << rhs.m31 << rhs.m41
+ << rhs.m12 << rhs.m22 << rhs.m32 << rhs.m42
+ << rhs.m13 << rhs.m23 << rhs.m33 << rhs.m43
+ << rhs.m14 << rhs.m24 << rhs.m34 << rhs.m44;
+
+ return lhs;
+}
+
+template <typename T>
+std::istream& operator>>(std::istream& lhs, Matrix<T, 4, 4>& rhs)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ lhs >> rhs.m11 >> rhs.m21 >> rhs.m31 >> rhs.m41
+ >> rhs.m12 >> rhs.m22 >> rhs.m32 >> rhs.m42
+ >> rhs.m13 >> rhs.m23 >> rhs.m33 >> rhs.m43
+ >> rhs.m14 >> rhs.m24 >> rhs.m34 >> rhs.m44;
+
+ return lhs;
+}
+
+// ---
+
+template <typename T>
+Matrix<T, 4, 4> operator+(const Matrix<T, 4, 4>& mat1, const Matrix<T, 4, 4>& mat2)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {mat1.m11 + mat2.m11, mat1.m21 + mat2.m21, mat1.m31 + mat2.m31, mat1.m41 + mat2.m41,
+ mat1.m12 + mat2.m12, mat1.m22 + mat2.m22, mat1.m32 + mat2.m32, mat1.m42 + mat2.m42,
+ mat1.m13 + mat2.m13, mat1.m23 + mat2.m23, mat1.m33 + mat2.m33, mat1.m43 + mat2.m43,
+ mat1.m14 + mat2.m14, mat1.m24 + mat2.m24, mat1.m34 + mat2.m34, mat1.m44 + mat2.m44};
+}
+
+template <typename Mat, typename Val>
+Matrix<Mat, 4, 4> operator+(const Matrix<Mat, 4, 4>& mat, const Val& val)
+{
+ static_assert (std::is_integral<Mat>::value || std::is_floating_point<Mat>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {mat.m11 + val, mat.m21 + val, mat.m31 + val, mat.m41 + val,
+ mat.m12 + val, mat.m22 + val, mat.m32 + val, mat.m42 + val,
+ mat.m13 + val, mat.m23 + val, mat.m33 + val, mat.m43 + val,
+ mat.m14 + val, mat.m24 + val, mat.m34 + val, mat.m44 + val};
+}
+
+template <typename Val, typename Mat>
+Matrix<Mat, 4, 4> operator+(const Val& val, const Matrix<Mat, 4, 4>& mat)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Mat>::value || std::is_floating_point<Mat>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val + mat.m11, val + mat.m21, val + mat.m31, val + mat.m41,
+ val + mat.m12, val + mat.m22, val + mat.m32, val + mat.m42,
+ val + mat.m13, val + mat.m23, val + mat.m33, val + mat.m43,
+ val + mat.m14, val + mat.m24, val + mat.m34, val + mat.m44};
+}
+
+// ---
+
+template <typename T>
+Matrix<T, 4, 4> operator-(const Matrix<T, 4, 4>& mat1, const Matrix<T, 4, 4>& mat2)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {mat1.m11 - mat2.m11, mat1.m21 - mat2.m21, mat1.m31 - mat2.m31, mat1.m41 - mat2.m41,
+ mat1.m12 - mat2.m12, mat1.m22 - mat2.m22, mat1.m32 - mat2.m32, mat1.m42 - mat2.m42,
+ mat1.m13 - mat2.m13, mat1.m23 - mat2.m23, mat1.m33 - mat2.m33, mat1.m43 - mat2.m43,
+ mat1.m14 - mat2.m14, mat1.m24 - mat2.m24, mat1.m34 - mat2.m34, mat1.m44 - mat2.m44};
+}
+
+template <typename Mat, typename Val>
+Matrix<Mat, 4, 4> operator-(const Matrix<Mat, 4, 4>& mat, const Val& val)
+{
+ static_assert (std::is_integral<Mat>::value || std::is_floating_point<Mat>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {mat.m11 - val, mat.m21 - val, mat.m31 - val, mat.m41 - val,
+ mat.m12 - val, mat.m22 - val, mat.m32 - val, mat.m42 - val,
+ mat.m13 - val, mat.m23 - val, mat.m33 - val, mat.m43 - val,
+ mat.m14 - val, mat.m24 - val, mat.m34 - val, mat.m44 - val};
+}
+
+template <typename Val, typename Mat>
+Matrix<Mat, 4, 4> operator-(const Val& val, const Matrix<Mat, 4, 4>& mat)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Mat>::value || std::is_floating_point<Mat>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val - mat.m11, val - mat.m21, val - mat.m31, val - mat.m41,
+ val - mat.m12, val - mat.m22, val - mat.m32, val - mat.m42,
+ val - mat.m13, val - mat.m23, val - mat.m33, val - mat.m43,
+ val - mat.m14, val - mat.m24, val - mat.m34, val - mat.m44};
+}
+
+// ---
+
+template <typename T>
+Matrix<T, 4, 4> operator*(const Matrix<T, 4, 4>& mat1, const Matrix<T, 4, 4>& mat2)
+{
+ static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {mat1.m11 * mat2.m11 + mat1.m21 * mat2.m12 + mat1.m31 * mat2.m13 + mat1.m41 * mat2.m14,
+ mat1.m11 * mat2.m21 + mat1.m21 * mat2.m22 + mat1.m31 * mat2.m23 + mat1.m41 * mat2.m24,
+ mat1.m11 * mat2.m31 + mat1.m21 * mat2.m32 + mat1.m31 * mat2.m33 + mat1.m41 * mat2.m34,
+ mat1.m11 * mat2.m41 + mat1.m21 * mat2.m42 + mat1.m31 * mat2.m43 + mat1.m41 * mat2.m44,
+
+ mat1.m12 * mat2.m11 + mat1.m22 * mat2.m12 + mat1.m32 * mat2.m13 + mat1.m42 * mat2.m14,
+ mat1.m12 * mat2.m21 + mat1.m22 * mat2.m22 + mat1.m32 * mat2.m23 + mat1.m42 * mat2.m24,
+ mat1.m12 * mat2.m31 + mat1.m22 * mat2.m32 + mat1.m32 * mat2.m33 + mat1.m42 * mat2.m34,
+ mat1.m12 * mat2.m41 + mat1.m22 * mat2.m42 + mat1.m32 * mat2.m43 + mat1.m42 * mat2.m44,
+
+ mat1.m13 * mat2.m11 + mat1.m23 * mat2.m12 + mat1.m33 * mat2.m13 + mat1.m43 * mat2.m14,
+ mat1.m13 * mat2.m21 + mat1.m23 * mat2.m22 + mat1.m33 * mat2.m23 + mat1.m43 * mat2.m24,
+ mat1.m13 * mat2.m31 + mat1.m23 * mat2.m32 + mat1.m33 * mat2.m33 + mat1.m43 * mat2.m34,
+ mat1.m13 * mat2.m41 + mat1.m23 * mat2.m42 + mat1.m33 * mat2.m43 + mat1.m43 * mat2.m44,
+
+ mat1.m14 * mat2.m11 + mat1.m24 * mat2.m12 + mat1.m34 * mat2.m13 + mat1.m44 * mat2.m14,
+ mat1.m14 * mat2.m21 + mat1.m24 * mat2.m22 + mat1.m34 * mat2.m23 + mat1.m44 * mat2.m24,
+ mat1.m14 * mat2.m31 + mat1.m24 * mat2.m32 + mat1.m34 * mat2.m33 + mat1.m44 * mat2.m34,
+ mat1.m14 * mat2.m41 + mat1.m24 * mat2.m42 + mat1.m34 * mat2.m43 + mat1.m44 * mat2.m44};
+}
+
+template <typename Mat, typename Val>
+Matrix<Mat, 4, 4> operator*(const Matrix<Mat, 4, 4>& mat, const Val& val)
+{
+ static_assert (std::is_integral<Mat>::value || std::is_floating_point<Mat>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {mat.m11 * val, mat.m21 * val, mat.m31 * val, mat.m41 * val,
+ mat.m12 * val, mat.m22 * val, mat.m32 * val, mat.m42 * val,
+ mat.m13 * val, mat.m23 * val, mat.m33 * val, mat.m43 * val,
+ mat.m14 * val, mat.m24 * val, mat.m34 * val, mat.m44 * val};
+}
+
+template <typename Val, typename Mat>
+Matrix<Mat, 4, 4> operator*(const Val& val, const Matrix<Mat, 4, 4>& mat)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Mat>::value || std::is_floating_point<Mat>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val * mat.m11, val * mat.m21, val * mat.m31, val * mat.m41,
+ val * mat.m12, val * mat.m22, val * mat.m32, val * mat.m42,
+ val * mat.m13, val * mat.m23, val * mat.m33, val * mat.m43,
+ val * mat.m14, val * mat.m24, val * mat.m34, val * mat.m44};
+}
+
+// ---
+
+template <typename Mat, typename Val>
+Matrix<Mat, 4, 4> operator/(const Matrix<Mat, 4, 4>& mat, const Val& val)
+{
+ static_assert (std::is_integral<Mat>::value || std::is_floating_point<Mat>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {mat.m11 / val, mat.m21 / val, mat.m31 / val, mat.m41 / val,
+ mat.m12 / val, mat.m22 / val, mat.m32 / val, mat.m42 / val,
+ mat.m13 / val, mat.m23 / val, mat.m33 / val, mat.m43 / val,
+ mat.m14 / val, mat.m24 / val, mat.m34 / val, mat.m44 / val};
+}
+
+template <typename Val, typename Mat>
+Matrix<Mat, 4, 4> operator/(const Val& val, const Matrix<Mat, 4, 4>& mat)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Mat>::value || std::is_floating_point<Mat>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val / mat.m11, val / mat.m21, val / mat.m31, val / mat.m41,
+ val / mat.m12, val / mat.m22, val / mat.m32, val / mat.m42,
+ val / mat.m13, val / mat.m23, val / mat.m33, val / mat.m43,
+ val / mat.m14, val / mat.m24, val / mat.m34, val / mat.m44};
+}