/**
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