2012-05-23 17:04:46 +10:00
|
|
|
/*
|
2018-08-04 15:14:06 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2012-05-23 17:04:46 +10:00
|
|
|
*
|
2015-10-30 23:40:13 +11:00
|
|
|
* Copyright 2011-2015 Danny Robson <danny@nerdcruft.net>
|
2012-05-23 17:04:46 +10:00
|
|
|
*/
|
2011-06-21 20:26:32 +10:00
|
|
|
|
2011-05-23 17:18:52 +10:00
|
|
|
#include "matrix.hpp"
|
|
|
|
|
2019-05-17 12:26:08 +10:00
|
|
|
#include "debug/assert.hpp"
|
2019-03-18 16:18:27 +11:00
|
|
|
#include "iterator/infix.hpp"
|
2016-08-15 17:42:09 +10:00
|
|
|
#include "point.hpp"
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2011-10-18 21:45:55 +11:00
|
|
|
#include <cstring>
|
2014-12-15 13:44:33 +11:00
|
|
|
#include <cmath>
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
using cruft::matrix;
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
|
2015-11-04 23:23:46 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2017-11-22 17:03:00 +11:00
|
|
|
template <std::size_t Rows, std::size_t Cols, typename T>
|
2015-11-04 23:23:46 +11:00
|
|
|
T
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::matrix<Rows,Cols,T>::determinant (void) const
|
2015-11-04 23:23:46 +11:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
return cruft::determinant (*this);
|
2011-05-23 17:18:52 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-19 20:45:28 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2017-11-22 17:03:00 +11:00
|
|
|
template <std::size_t Rows, std::size_t Cols, typename T>
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::matrix<Rows,Cols,T>
|
|
|
|
cruft::matrix<Rows,Cols,T>::inverse (void) const
|
2015-11-04 23:23:46 +11:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
return cruft::inverse (*this);
|
2014-08-19 20:45:28 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-14 17:46:03 +10:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2017-11-22 17:03:00 +11:00
|
|
|
template <std::size_t Rows, std::size_t Cols, typename T>
|
2017-02-21 21:19:28 +11:00
|
|
|
matrix<Cols,Rows,T>
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::transposed (const matrix<Rows,Cols,T> &m)
|
2016-09-14 17:46:03 +10:00
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::matrix<Cols,Rows,T> res;
|
2016-09-14 17:46:03 +10:00
|
|
|
|
2017-11-22 17:03:00 +11:00
|
|
|
for (std::size_t y = 0; y < Rows; ++y)
|
|
|
|
for (std::size_t x = 0; x < Cols; ++x)
|
2016-09-14 17:46:03 +10:00
|
|
|
res[y][x] = m[x][y];
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-10-11 20:51:49 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
2018-08-05 14:42:02 +10:00
|
|
|
template cruft::matrix3f cruft::transposed (const matrix3f&);
|
|
|
|
template cruft::matrix4f cruft::transposed (const matrix4f&);
|
2015-01-13 18:38:12 +11:00
|
|
|
|
|
|
|
|
2015-07-21 01:40:00 +10:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2017-11-22 17:03:00 +11:00
|
|
|
template <std::size_t Rows, std::size_t Cols, typename T>
|
2011-05-23 17:18:52 +10:00
|
|
|
bool
|
2017-02-21 21:19:28 +11:00
|
|
|
matrix<Rows,Cols,T>::is_affine (void) const
|
2015-11-04 23:23:46 +11:00
|
|
|
{
|
2017-02-21 21:19:28 +11:00
|
|
|
if (Rows != Cols)
|
|
|
|
return false;
|
|
|
|
|
2017-11-22 17:03:00 +11:00
|
|
|
for (std::size_t i = 0; i < Rows - 1; ++i)
|
2017-02-21 21:19:28 +11:00
|
|
|
if (!exactly_zero (values[Rows-1][i]))
|
2015-11-04 23:23:46 +11:00
|
|
|
return false;
|
|
|
|
|
2018-01-31 19:33:42 +11:00
|
|
|
return equal (values[Rows-1][Rows-1], T{1});
|
2011-05-23 17:18:52 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-15 13:44:33 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
2017-11-22 17:03:00 +11:00
|
|
|
template <typename T>
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::matrix4<T>
|
|
|
|
cruft::ortho (T l, T r, // left, right
|
2018-03-06 13:53:39 +11:00
|
|
|
T b, T t, // bottom, top
|
|
|
|
T n, T f) // near, far
|
2014-12-15 13:44:33 +11:00
|
|
|
{
|
2018-03-06 13:53:39 +11:00
|
|
|
CHECK_GT (f, n);
|
2014-12-15 13:44:33 +11:00
|
|
|
|
2018-03-06 13:53:39 +11:00
|
|
|
T tx = - (r + l) / (r - l);
|
|
|
|
T ty = - (t + b) / (t - b);
|
|
|
|
T tz = - (f + n) / (f - n);
|
2014-12-15 13:44:33 +11:00
|
|
|
|
2018-03-06 13:53:39 +11:00
|
|
|
T rl = 2 / (r - l);
|
|
|
|
T tb = 2 / (t - b);
|
|
|
|
T fn = -2 / (f - n);
|
2014-12-15 13:44:33 +11:00
|
|
|
|
2017-11-22 17:03:00 +11:00
|
|
|
return {{
|
2014-12-15 13:44:33 +11:00
|
|
|
{ rl, 0, 0, tx },
|
|
|
|
{ 0, tb, 0, ty },
|
|
|
|
{ 0, 0, fn, tz },
|
|
|
|
{ 0, 0, 0, 1 },
|
2017-11-22 17:03:00 +11:00
|
|
|
}};
|
2014-12-15 13:44:33 +11:00
|
|
|
}
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
template cruft::matrix4f cruft::ortho (float, float, float, float, float, float);
|
2014-12-15 13:44:33 +11:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2017-11-22 17:03:00 +11:00
|
|
|
template <typename T>
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::matrix4<T>
|
|
|
|
cruft::ortho2D (T left, T right,
|
2017-11-22 17:03:00 +11:00
|
|
|
T bottom, T top)
|
2014-12-15 13:44:33 +11:00
|
|
|
{
|
2018-01-10 17:19:39 +11:00
|
|
|
return ortho (left, right, bottom, top, T{-1}, T{1});
|
2014-12-15 13:44:33 +11:00
|
|
|
}
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
template cruft::matrix4f cruft::ortho2D (float, float, float, float);
|
2018-01-10 17:19:39 +11:00
|
|
|
|
2014-12-15 13:44:33 +11:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2017-11-22 17:03:00 +11:00
|
|
|
template <typename T>
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::matrix4<T>
|
|
|
|
cruft::perspective (T fov, T aspect, range<T> Z)
|
2014-12-15 13:44:33 +11:00
|
|
|
{
|
2020-09-24 08:03:41 +10:00
|
|
|
CHECK_INCLUSIVE (fov, 0, 2 * cruft::pi<T>);
|
2016-12-21 16:44:48 +11:00
|
|
|
CHECK_GE (Z.lo, 0);
|
|
|
|
CHECK_GE (Z.hi, 0);
|
2014-12-15 13:44:33 +11:00
|
|
|
|
2018-04-11 18:23:17 +10:00
|
|
|
T f = cos (T{0.5} * fov) / sin (T{0.5} * fov);
|
2016-10-11 20:56:41 +11:00
|
|
|
|
|
|
|
T x = f / aspect;
|
|
|
|
T y = f;
|
2016-12-21 16:44:48 +11:00
|
|
|
T z1 = (Z.hi + Z.lo) / (Z.lo - Z.hi);
|
|
|
|
T z2 = (2 * Z.hi * Z.lo) / (Z.lo - Z.hi);
|
2014-12-15 13:44:33 +11:00
|
|
|
|
|
|
|
return { {
|
2016-10-11 20:56:41 +11:00
|
|
|
{ x, 0, 0, 0 },
|
|
|
|
{ 0, y, 0, 0 },
|
2014-12-15 13:44:33 +11:00
|
|
|
{ 0, 0, z1, z2 },
|
|
|
|
{ 0, 0, -1, 0 }
|
|
|
|
} };
|
|
|
|
}
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
template cruft::matrix4f cruft::perspective<float> (float, float, range<float>);
|
2018-01-10 17:19:39 +11:00
|
|
|
|
2014-12-15 13:44:33 +11:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Emulates gluLookAt
|
2016-10-17 16:51:26 +11:00
|
|
|
//
|
|
|
|
// Translates the viewpoint to the origin, then rotates the world to point
|
|
|
|
// along eye to centre (negative-Z).
|
|
|
|
// Implemented for right handed world coordinates.
|
|
|
|
//
|
|
|
|
// Assumes 'up' is normalised.
|
2017-11-22 17:03:00 +11:00
|
|
|
template <typename T>
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::matrix4<T>
|
|
|
|
cruft::look_at (const cruft::point<3,T> eye,
|
|
|
|
const cruft::point<3,T> centre,
|
|
|
|
const cruft::vector<3,T> up)
|
2014-12-15 13:44:33 +11:00
|
|
|
{
|
2016-10-07 17:32:28 +11:00
|
|
|
CHECK (is_normalised (up));
|
|
|
|
|
2018-03-06 13:54:12 +11:00
|
|
|
const auto forward = normalised (centre - eye);
|
|
|
|
const auto side = normalised (cross (forward, up));
|
|
|
|
const auto newup = cross (side, forward);
|
|
|
|
|
|
|
|
const auto &f = forward, &s = side, &u = newup;
|
2016-09-15 21:33:03 +10:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
const cruft::matrix4<T> rot {{
|
2016-10-17 16:51:26 +11:00
|
|
|
{ s.x, s.y, s.z, 0 },
|
|
|
|
{ u.x, u.y, u.z, 0 },
|
|
|
|
{-f.x,-f.y,-f.z, 0 },
|
|
|
|
{ 0, 0, 0, 1 },
|
2016-09-15 21:33:03 +10:00
|
|
|
}};
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
return rot * cruft::translation (0-eye);
|
2014-12-15 13:44:33 +11:00
|
|
|
}
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
template cruft::matrix4f cruft::look_at (cruft::point3f, cruft::point3f, cruft::vector3f);
|
2015-04-02 14:58:02 +11:00
|
|
|
|
|
|
|
|
2021-04-14 14:17:18 +10:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2017-11-22 17:03:00 +11:00
|
|
|
template <typename T>
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::matrix4<T>
|
|
|
|
cruft::rotation (T angle, cruft::vector<3,T> about)
|
2014-12-30 01:32:02 +11:00
|
|
|
{
|
2016-08-11 14:58:46 +10:00
|
|
|
CHECK (is_normalised (about));
|
2014-12-30 01:32:02 +11:00
|
|
|
|
|
|
|
T c = std::cos (angle);
|
|
|
|
T s = std::sin (angle);
|
|
|
|
T x = about.x,
|
|
|
|
y = about.y,
|
|
|
|
z = about.z;
|
|
|
|
|
|
|
|
return { {
|
|
|
|
{ x * x * (1 - c) + c,
|
|
|
|
x * y * (1 - c) - z * s,
|
|
|
|
x * z * (1 - c) + y * s,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{ y * x * (1 - c) + z * s,
|
|
|
|
y * y * (1 - c) + c,
|
|
|
|
y * z * (1 - c) - x * s,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{ z * x * (1 - c) - y * s,
|
|
|
|
z * y * (1 - c) + x * s,
|
|
|
|
z * z * (1 - c) + c,
|
|
|
|
0
|
|
|
|
},
|
|
|
|
|
|
|
|
{ 0, 0, 0, 1 }
|
|
|
|
} };
|
|
|
|
}
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
template cruft::matrix4f cruft::rotation (float, cruft::vector3f);
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2014-07-07 15:17:45 +10:00
|
|
|
//-----------------------------------------------------------------------------
|
2018-08-05 14:42:02 +10:00
|
|
|
template struct cruft::matrix<2,2,float>;
|
|
|
|
template struct cruft::matrix<2,2,double>;
|
2015-11-04 23:23:46 +11:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
template struct cruft::matrix<3,3,float>;
|
|
|
|
template struct cruft::matrix<3,3,double>;
|
2015-11-04 23:23:46 +11:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
template struct cruft::matrix<4,4,float>;
|
|
|
|
template struct cruft::matrix<4,4,double>;
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2015-11-04 23:23:46 +11:00
|
|
|
|
2016-09-14 17:53:34 +10:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Uses the algorithm from:
|
|
|
|
// "Extracting Euler Angles from a Rotation Matrix" by
|
|
|
|
// Mike Day, Insomniac Games.
|
2017-11-22 17:03:00 +11:00
|
|
|
template <std::size_t Rows, std::size_t Cols, typename T>
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::vector<3,T>
|
|
|
|
cruft::to_euler (const matrix<Rows,Cols,T> &m)
|
2016-09-14 17:53:34 +10:00
|
|
|
{
|
2017-02-21 21:19:28 +11:00
|
|
|
static_assert (Rows == Cols && (Rows == 3 || Rows == 4),
|
|
|
|
"only defined for 3d affine transforms");
|
2016-09-14 17:53:34 +10:00
|
|
|
|
|
|
|
const auto theta0 = std::atan2 (m[2][1], m[2][2]);
|
|
|
|
|
|
|
|
const auto c1 = std::hypot (m[0][0], m[1][0]);
|
|
|
|
const auto theta1 = std::atan2 (-m[2][0], c1);
|
|
|
|
|
|
|
|
const auto s0 = std::sin(theta0);
|
|
|
|
const auto c0 = std::cos(theta0);
|
|
|
|
const auto theta2 = std::atan2(
|
|
|
|
s0 * m[0][2] - c0 * m[0][1],
|
|
|
|
c0 * m[1][1] - s0 * m[1][2]
|
|
|
|
);
|
|
|
|
|
|
|
|
return { theta0, theta1, theta2 };
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2018-08-05 14:42:02 +10:00
|
|
|
template cruft::vector<3,float> cruft::to_euler (const matrix<3,3,float>&);
|
|
|
|
template cruft::vector<3,float> cruft::to_euler (const matrix<4,4,float>&);
|
2016-09-14 17:53:34 +10:00
|
|
|
|
2021-04-12 17:17:24 +10:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "iterator/infix.hpp"
|
|
|
|
#include "coord/iostream.hpp"
|
|
|
|
|
|
|
|
#include <ostream>
|
|
|
|
|
|
|
|
|
|
|
|
template <std::size_t Rows, std::size_t Cols, typename T>
|
|
|
|
std::ostream&
|
|
|
|
cruft::operator<< (std::ostream &os, matrix<Rows,Cols,T> const &m)
|
|
|
|
{
|
|
|
|
os << '[';
|
|
|
|
std::copy (
|
|
|
|
std::cbegin (m),
|
|
|
|
std::cend (m),
|
|
|
|
iterator::infix_iterator<decltype(m[0])> (os, ", ")
|
|
|
|
);
|
|
|
|
return os << ']';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template std::ostream& cruft::operator<< (std::ostream&, matrix<4,4,f32> const&);
|