/** This file is a part of our_dick Copyright (C) 2020 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifndef REXY_MAT_TPP #define REXY_MAT_TPP #include //size_t #include //sin, cos #include //decay_t, declval #include "detail/matrix.hpp" #include "quat.hpp" namespace math{ template template constexpr matrix_base::matrix_base(std::integer_sequence): m_data{Ss...}{} template constexpr matrix_base::matrix_base(): matrix_base(typename detail::default_initialization_matrix::tuple{}){} template constexpr matrix_base::matrix_base(detail::zero_initialize_t): m_data{}{} template constexpr matrix_base::matrix_base(detail::no_initialize_t){} template constexpr matrix_base::matrix_base(value_type v){ for(size_type i = 0; i < Columns*Rows; ++i) m_data[i] = v; } template template constexpr matrix_base::matrix_base(Args&&... args): m_data{std::forward(args)...}{} template template constexpr matrix_base::matrix_base(const matrix_base& m){ using mat = decltype(m); for(typename mat::size_type i = 0; i < mat::Columns*mat::Rows; ++i) m_data[i] = m.get(i); } template template constexpr matrix_base& matrix_base::operator=(const matrix_base& m){ using mat = decltype(m); for(typename mat::size_type i = 0; i < mat::Columns*mat::Rows; ++i) m_data[i] = m.get(i); return *this; } template constexpr auto matrix_base::operator[](size_type x){ return detail::mat_ref_obj{m_data, x}; } template constexpr auto matrix_base::operator[](size_type x)const{ return detail::mat_ref_obj{m_data, x}; } template constexpr auto matrix_base::get(size_type x, size_type y) -> reference{ return m_data[x+(y*Rows)]; } template constexpr auto matrix_base::get(size_type x, size_type y)const -> const_reference{ return m_data[x+(y*Rows)]; } template constexpr auto matrix_base::get(size_type i) -> reference{ return m_data[i]; } template constexpr auto matrix_base::get(size_type i)const -> const_reference{ return m_data[i]; } template constexpr auto matrix_base::columns()const -> size_type{ return Columns; } template constexpr auto matrix_base::rows()const -> size_type{ return Rows; } template constexpr auto matrix_base::size()const -> size_type{ return Columns*Rows; } template constexpr auto matrix_base::raw() -> pointer{ return m_data; } template constexpr auto matrix_base::raw()const -> const_pointer{ return m_data; } template constexpr matrix_base::operator pointer(){ return m_data; } template constexpr matrix_base::operator const_pointer()const{ return m_data; } template template constexpr matrix& matrix::operator=(const matrix& m){ base::operator=(m); return *this; } template constexpr matrix::matrix(detail::id_initialize_t): base(){} template template constexpr matrix& matrix::operator=(const matrix& m){ base::operator=(m); return *this; } template constexpr auto matrix::determinate()const -> value_type{ return math::determinate(*this); } template constexpr auto matrix::trace()const -> value_type{ value_type sum = 0; for(size_type i = 0; i < R; ++i){ sum += get(i, i); } } template constexpr matrix matrix::transpose()const{ matrix m(no_initialize); for(size_type i = 0; i < R; ++i){ for(size_type j = 0; j < R; ++j){ m.get(j, i) = get(i, j); } } return m; } template constexpr matrix matrix::inverse()const{ return math::inverse(*this); } template constexpr T determinate(const matrix& m){ return detail::determinate_helper::perform(m); } template constexpr matrix inverse(const matrix& m){ return detail::inverse_helper::perform(m); } template matrix rotation2d_pure(T angle){ return rotation2d_pure(std::sin(angle), std::cos(angle)); } template constexpr matrix rotation2d_pure(T sin, T cos){ return matrix(cos, sin, -sin, cos); } template constexpr matrix scale2d(T x, T y){ return matrix(x, 0, 0, y); } template matrix rotation2d(T angle){ return rotation2d(std::sin(angle), std::cos(angle)); } template constexpr matrix rotation2d(T sin, T cos){ return matrix(cos, -sin, 0, sin, cos, 0, 0, 0, 1); } template matrix rotation2d(T x, T y, T z){ quaternion q(x, y, z); return q.to_mat3(); } template matrix fov_projection(T fov, T asp, T near, T far){ T r = near * std::tan(fov / T{2.0}); return matrix((near / r) / asp, 0, 0, 0, 0, (near / r), 0, 0, 0, 0, (far + near) / (near - far), -1, 0, 0, (2 * near * far) / (near - far), 0); } template matrix fov_asymetric_projection(T fovl, T fovr, T fovb, T fovt, T asp, T n, T f){ T l = n * std::tan(fovl); T r = n * std::tan(fovr); T b = n * std::tan(fovb); T t = n * std::tan(fovt); return matrix(((2 * n) / (r - l)) * asp, 0, 0, 0, 0, (2 * n) / (t - b), 0, 0, (r + l) / (r - l), (t + b) / (t - b), (f + n) / (n - f), -1, 0, 0, (2 * n * f) / (n - f), 0); } template matrix ortho_projection(T w, T h, T n, T f){ return matrix(2 / w, 0, 0, 0, 0, 2 / h, 0, 0, 0, 0, 2 / (n - f), 0, 0, 0, (n + f) / (n - f), 1); } template matrix ortho_asymetric_projection(T l, T r, T b, T t, T n, T f){ return matrix(2 / (r - l), 0, 0, 0, 0, 2 / (t - b), 0, 0, 0, 0, 2 / (n - f), 0, (r + l) / (l - r), (t + b) / (b - t), (n + f) / (n - f), 1); } template constexpr matrix rotation3d(T angle_x, T angle_y, T angle_z){ quaternion q(angle_x, angle_y, angle_z); return q.to_mat4(); } template constexpr matrix translation3d(T x, T y, T z){ return matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1); } template constexpr matrix scale3d(T x, T y, T z){ return matrix(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1); } template constexpr bool operator==(const matrix_base& left, const matrix_base right){ for(size_t i = 0; i < left.size(); ++i){ if(left.get(i) != right.get(i)) return false; } return true; } template constexpr bool operator!=(const matrix_base& left, const matrix_base right){ return !(left == right); } template constexpr auto operator*(const matrix& left, const matrix& right){ using res_t = decltype(std::declval() * std::declval()); matrix res(zero_initialize); size_t index = 0; for(size_t i = 0; i < left.rows(); ++i){ for(size_t j = 0; j < right.columns(); ++j){ for(size_t k = 0; k < right.rows(); ++k){ res.get(index) += left[i][k] * right[k][j]; } ++index; } } } template::value,int>> constexpr auto operator*(const matrix& left, U&& right){ using res_t = decltype(std::declval() * std::declval()); matrix res(no_initialize); for(size_t i = 0; i < left.size(); ++i){ res.get(i) = left.get(i) * std::forward(right); } return res; } template::value,int>> constexpr auto operator*(U&& left, const matrix& right){ using res_t = decltype(std::declval() * std::declval()); matrix res(no_initialize); for(size_t i = 0; i < right.size(); ++i){ res.get(i) = std::forward(left) * right.get(i); } return res; } template::value,int>> constexpr auto operator/(const matrix& left, U&& right){ using res_t = decltype(std::declval() / std::declval()); matrix res(no_initialize); for(size_t i = 0; i < left.size(); ++i){ res.get(i) = left.get(i) / std::forward(right); } return res; } template constexpr auto operator+(const matrix& left, const matrix& right){ using res_t = decltype(std::declval() + std::declval()); matrix res(no_initialize); for(size_t i = 0; i < left.size(); ++i){ res.get(i) = left.get(i) + right.get(i); } return res; } template constexpr auto operator-(const matrix& left, const matrix& right){ using res_t = decltype(std::declval() - std::declval()); matrix res(no_initialize); for(size_t i = 0; i < left.size(); ++i){ res.get(i) = left.get(i) - right.get(i); } return res; } template constexpr auto operator-(const matrix& left){ using res_t = decltype(-std::declval()); matrix res(no_initialize); for(size_t i = 0; i < left.size(); ++i){ res.get(i) = -left.get(i); } return res; } template constexpr decltype(auto) operator*=(matrix& left, const matrix& right){ //have to evaluate entire expression first since matrix multiplication depends on reusing many elements //cannot be expression templatized, TODO return (left = (left * right)); } template::value,int>> constexpr decltype(auto) operator*=(matrix& left, U&& right){ for(size_t i = 0; i < left.size(); ++i){ left.get(i) = left.get(i) * std::forward(right); } return left; } template::value,int>> constexpr decltype(auto) operator/=(matrix& left, U&& right){ for(size_t i = 0; i < left.size(); ++i){ left.get(i) = left.get(i) / std::forward(right); } return left; } template constexpr decltype(auto) operator+=(matrix& left, const matrix& right){ for(size_t i = 0; i < left.size(); ++i){ left.get(i) = left.get(i) + right.get(i); } return left; } template constexpr decltype(auto) operator-=(matrix& left, const matrix& right){ for(size_t i = 0; i < left.size(); ++i){ left.get(i) = left.get(i) - right.get(i); } return left; } } #endif