Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@nilium
Created March 2, 2013 09:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nilium/1f5f4b20a82bd7e484b2 to your computer and use it in GitHub Desktop.
Save nilium/1f5f4b20a82bd7e484b2 to your computer and use it in GitHub Desktop.
Combined maths headers from libsnow-common
// commath.hh -- Noel Cower -- Public Domain
#ifndef __SNOW_COMMON__COMMATH_HH__
#define __SNOW_COMMON__COMMATH_HH__
#include <cfloat>
#include <cmath>
#include <stdexcept>
// General degrees-to-radians constant
#define S_DEG2RAD (0.01745329251)
// Epsilon for testing for zero-ish
#define S_EPSILON (1e-5)
template <typename T> struct mat4_t;
template <typename T> struct mat3_t;
template <typename T> struct vec4_t;
template <typename T> struct vec3_t;
template <typename T> struct quat_t;
template <typename T> struct line_t;
typedef mat4_t<float> mat4f_t;
typedef mat4_t<double> mat4d_t;
typedef mat3_t<float> mat3f_t;
typedef mat3_t<double> mat3d_t;
typedef vec4_t<float> vec4f_t;
typedef vec4_t<double> vec4d_t;
typedef vec3_t<float> vec3f_t;
typedef vec3_t<double> vec3d_t;
typedef quat_t<float> quatf_t;
typedef quat_t<double> quatd_t;
typedef line_t<float> linef_t;
typedef line_t<double> lined_t;
/*==============================================================================
is_zero
Tests for whether a value is zero. Specialized for float, double, and long
double types to see if the value is less than their respective epsilons.
For all other types, simply returns (v == 0).
==============================================================================*/
template <typename T>
inline
bool is_zero(T value)
{
return value == T(0);
}
template <>
inline
bool is_zero<float>(float value)
{
return std::abs(value) < S_EPSILON;
}
template <>
inline
bool is_zero<double>(double value)
{
return std::abs(value) < S_EPSILON;
}
template <>
inline
bool is_zero<long double>(long double value)
{
return std::abs(value) < S_EPSILON;
}
/*==============================================================================
are_equiv
Compares whether two values are equivalent. For non-floating-point values,
this is the same as ==. For floating point values, this tests whether the
difference of the two values is less than S_EPSILON using is_zero.
==============================================================================*/
template <typename T>
bool are_equiv(T lhs, T rhs)
{
return (std::is_floating_point<T>::value
? is_zero(lhs - rhs)
: (lhs == rhs));
}
/*==============================================================================
max_value
Returns the maximum value for a given type. Only intended for use with
float, double, and long double. Other types will throw a runtime_error.
==============================================================================*/
template <typename T>
inline
T max_value() { throw std::runtime_error("no set maximum for type"); }
template <>
inline
float max_value<float>() { return FLT_MAX; }
template <>
inline
double max_value<double>() { return DBL_MAX; }
template <>
inline
long double max_value<long double>() { return LDBL_MAX; }
/*==============================================================================
clamp_value
Clamps a value from the given minimum value to the maximum value.
==============================================================================*/
template <typename T>
inline
constexpr T clamp_value(T val, T min, T max)
{
return (val < min ? min : (val > max ? max : val));
}
template <typename T, typename Q, typename R>
inline
constexpr T clamp_value(T val, Q min, R max)
{
return (val < min ? static_cast<T>(min) : (val > max ? static_cast<T>(max) : val));
}
/*==============================================================================
Line (ported over from Mark Sibly's Blitz3D maths routines)
Not required to be a POD type, though it may end up being one due to
restrictions placed on other types.
==============================================================================*/
template <typename T>
struct line_t
{
typedef T value_type;
typedef vec3_t<T> vec3;
vec3 origin;
vec3 dist;
auto end() const -> vec3;
auto translated(const vec3 &d) const -> line_t;
auto translate(const vec3 &d) -> line_t&;
auto scaled(value_type d) const -> line_t;
auto scale(value_type d) -> line_t&;
auto nearest_to(const vec3& p) const -> vec3;
};
/*==============================================================================
3x3 Square Matrix
==============================================================================*/
template <typename T = float>
struct alignas(4) mat3_t
{
static_assert(std::is_floating_point<T>::value,
"value_type must be floating point type");
static_assert(std::is_scalar<T>::value,
"value_type must be scalar type");
typedef T value_type;
typedef vec3_t<T> vec3;
typedef quat_t<T> quat;
vec3 r, s, t;
/*
r.x r.y r.z
s.x s.y s.z
t.x t.y t.z
*/
static const mat3_t identity;
static const mat3_t zero;
static mat3_t make(T rx, T ry, T rz,
T sx, T sy, T sz,
T tx, T ty, T tz);
static mat3_t make(const vec3 &x,
const vec3 &y,
const vec3 &z);
static mat3_t scaling(const vec3 &off);
static mat3_t rotation(T angle, const vec3 &axis);
static mat3_t from_quat(const quat &in);
mat3_t & transpose();
mat3_t transposed() const;
vec3 colvec3(int index) const;
mat3_t & set_colvec3(int index, const vec3 &col);
mat3_t negated() const;
mat3_t & negate();
mat3_t sum(const mat3_t &other) const;
mat3_t sum(T scalar) const;
mat3_t & add(const mat3_t &other);
mat3_t & add(T scalar);
mat3_t difference(const mat3_t &other) const;
mat3_t difference(T scalar) const;
mat3_t & subtract(const mat3_t &other);
mat3_t & subtract(T scalar);
mat3_t scaled(T scalar) const;
mat3_t & scale(T scalar);
mat3_t scaled(const mat3_t &other) const;
mat3_t & scale(const mat3_t &other);
mat3_t scaled(const vec3 &vec) const;
mat3_t & scale(const vec3 &vec);
mat3_t inverse() const;
mat3_t & invert();
mat3_t adjoint() const;
mat3_t cofactor() const;
T determinant() const;
mat3_t orthogonal() const;
mat3_t & orthogonalize();
mat3_t product(const mat3_t &other) const;
mat3_t & multiply(const mat3_t &other);
vec3 rotate(const vec3 &vec) const;
vec3 inverse_rotate(const vec3 &vec) const;
T & operator [] (int index);
T operator [] (int index) const;
operator T* ();
operator const T* () const;
operator quat_t<T>() const;
operator mat4_t<T>() const;
mat3_t & operator *= (const mat3_t &other);
mat3_t & operator *= (T scalar);
mat3_t & operator += (const mat3_t &other);
mat3_t & operator += (T scalar);
mat3_t & operator -= (const mat3_t &other);
mat3_t & operator -= (T scalar);
}; // struct mat3_t<T>
template <typename T>
std::ostream &operator << (std::ostream &out, const mat3_t<T> &in);
template <typename T, typename Q>
mat3_t<T> operator * (const mat3_t<T> &rhs, const mat3_t<Q> &lhs);
template <typename T, typename Q>
vec3_t<T> operator * (const mat3_t<T> &rhs, const vec3_t<Q> &lhs);
template <typename T, typename Q>
mat3_t<T> operator * (const mat3_t<T> &rhs, const Q &lhs);
template <typename T, typename Q>
mat3_t<T> operator + (const mat3_t<T> &rhs, const mat3_t<Q> &lhs);
template <typename T, typename Q>
mat3_t<T> operator + (const mat3_t<T> &rhs, const Q &lhs);
template <typename T, typename Q>
mat3_t<T> operator - (const mat3_t<T> &rhs, const mat3_t<Q> &lhs);
template <typename T, typename Q>
mat3_t<T> operator - (const mat3_t<T> &rhs, const Q &lhs);
template <typename T, typename Q>
bool operator == (const mat3_t<T> &rhs, const mat3_t<Q> &lhs);
template <typename T, typename Q>
bool operator != (const mat3_t<T> &rhs, const mat3_t<Q> &lhs);
/*==============================================================================
4x4 Square Matrix
==============================================================================*/
template <typename T = float>
struct alignas(4) mat4_t
{
static_assert(std::is_floating_point<T>::value,
"value_type must be floating point type");
static_assert(std::is_scalar<T>::value,
"value_type must be scalar type");
typedef T value_type;
typedef vec3_t<T> vec3;
typedef vec4_t<T> vec4;
typedef quat_t<T> quat;
// X Y Z W
value_type m00, m10, m20, m30; // X
value_type m01, m11, m21, m31; // Y
value_type m02, m12, m22, m32; // Z
value_type m03, m13, m23, m33; // Translation
static const mat4_t identity;
static const mat4_t zero;
static mat4_t make(T m00, T m10, T m20, T m30,
T m01, T m11, T m21, T m31,
T m02, T m12, T m22, T m32,
T m03, T m13, T m23, T m33);
static mat4_t translation(const vec3 &off);
static mat4_t scaling(const vec3 &off);
static mat4_t rotation(T angle, const vec3 &axis);
static mat4_t frustum(T left, T right, T bottom, T top, T near, T far);
static mat4_t orthographic(T left, T right, T top, T bottom, T near, T far);
static mat4_t perspective(T fovY, T aspect, T near, T far);
static mat4_t look_at(const vec3 &eye, const vec3& center, const vec3& up);
static mat4_t from_quat(const quat &in);
mat4_t & translate(const vec3 &translation);
mat4_t translated(const vec3 &translation) const;
mat4_t & transpose();
mat4_t transposed() const;
vec4 rowvec4(int index) const;
vec4 colvec4(int index) const;
mat4_t & set_rowvec4(int index, const vec4 &row);
mat4_t & set_colvec4(int index, const vec4 &col);
vec3 rowvec3(int index) const;
vec3 colvec3(int index) const;
mat4_t & set_rowvec3(int index, const vec3 &row);
mat4_t & set_colvec3(int index, const vec3 &col);
mat4_t negated() const;
mat4_t & negate();
mat4_t sum(const mat4_t &other) const;
mat4_t sum(T scalar) const;
mat4_t & add(const mat4_t &other);
mat4_t & add(T scalar);
mat4_t difference(const mat4_t &other) const;
mat4_t difference(T scalar) const;
mat4_t & subtract(const mat4_t &other);
mat4_t & subtract(T scalar);
mat4_t scaled(T scalar) const;
mat4_t & scale(T scalar);
mat4_t scaled(const mat4_t &other) const;
mat4_t & scale(const mat4_t &other);
mat4_t scaled(const vec3 &vec) const;
mat4_t & scale(const vec3 &vec);
mat4_t inverse_orthogonal();
bool inverse_affine(mat4_t &out) const;
bool inverse_general(mat4_t &out) const;
T cofactor(int r0, int r1, int r2, int c0, int c1, int c2) const;
T determinant() const;
mat4_t adjoint() const;
mat4_t product(const mat4_t &other) const;
mat4_t & multiply(const mat4_t &other);
vec4 multiply(const vec4 &vec) const;
vec3 multiply(const vec3 &vec) const;
vec3 rotate(const vec3 &vec) const;
vec3 inverse_rotate(const vec3 &vec) const;
T & operator [] (int index);
T operator [] (int index) const;
operator T* ();
operator const T* () const;
operator quat_t<T>() const;
operator mat3_t<T>() const;
mat4_t & operator *= (const mat4_t &other);
mat4_t & operator *= (T scalar);
mat4_t & operator += (const mat4_t &other);
mat4_t & operator += (T scalar);
mat4_t & operator -= (const mat4_t &other);
mat4_t & operator -= (T scalar);
}; // struct mat4_t<T>
template <typename T>
std::ostream &operator << (std::ostream &out, const mat4_t<T> &in);
template <typename T, typename Q>
mat4_t<T> operator * (const mat4_t<T> &rhs, const mat4_t<Q> &lhs);
template <typename T, typename Q>
vec4_t<T> operator * (const mat4_t<T> &rhs, const vec4_t<Q> &lhs);
template <typename T, typename Q>
vec3_t<T> operator * (const mat4_t<T> &rhs, const vec3_t<Q> &lhs);
template <typename T, typename Q>
mat4_t<T> operator * (const mat4_t<T> &rhs, const Q &lhs);
template <typename T, typename Q>
mat4_t<T> operator + (const mat4_t<T> &rhs, const mat4_t<Q> &lhs);
template <typename T, typename Q>
mat4_t<T> operator + (const mat4_t<T> &rhs, const Q &lhs);
template <typename T, typename Q>
mat4_t<T> operator - (const mat4_t<T> &rhs, const mat4_t<Q> &lhs);
template <typename T, typename Q>
mat4_t<T> operator - (const mat4_t<T> &rhs, const Q &lhs);
template <typename T, typename Q>
bool operator == (const mat4_t<T> &rhs, const mat4_t<Q> &lhs);
template <typename T, typename Q>
bool operator != (const mat4_t<T> &rhs, const mat4_t<Q> &lhs);
/*==============================================================================
Quaternion
==============================================================================*/
template <typename T = float>
struct alignas(4) quat_t {
static_assert(std::is_floating_point<T>::value,
"value_type must be floating point type");
static_assert(std::is_scalar<T>::value,
"value_type must be scalar type");
typedef T value_type;
typedef vec3_t<value_type> vec3;
vec3 xyz;
value_type w;
static const quat_t zero;
static const quat_t one;
static const quat_t identity;
static quat_t make(T x, T y, T z, T w);
static quat_t make(vec3 xyz, T w);
static quat_t from_angle_axis(T angle, const vec3 &axis);
static quat_t from_mat4(const mat4_t<T> &mat);
static quat_t from_mat3(const mat3_t<T> &mat);
value_type length() const;
value_type magnitude() const;
quat_t inverse() const;
quat_t & invert();
quat_t negated() const;
quat_t & negate();
quat_t product(const quat_t &other) const;
quat_t & multiply(const quat_t &other);
quat_t normalized() const;
quat_t & normalize();
quat_t difference(const quat_t &other) const;
quat_t & subtract(const quat_t &other);
quat_t sum(const quat_t &other) const;
quat_t & add(const quat_t &other);
quat_t scaled(value_type scalar) const;
quat_t scaled(const quat_t &other) const;
quat_t & scale(value_type scalar);
quat_t & scale(const quat_t &other);
value_type dot_product(const quat_t &other) const;
quat_t slerp(const quat_t &to, value_type delta) const;
quat_t lerp(const quat_t &to, value_type delta) const;
quat_t & operator *= (const quat_t &other);
quat_t & operator *= (value_type scalar);
quat_t & operator += (const quat_t &other);
quat_t & operator -= (const quat_t &other);
quat_t operator - () const;
quat_t operator ~ () const;
value_type & operator[] (int index);
value_type operator[] (int index) const;
operator value_type* ();
operator const T* () const;
operator mat4_t<T>() const;
operator mat3_t<T>() const;
template <typename Q>
operator quat_t<Q> () const;
};
template <typename T>
std::ostream& operator << (std::ostream &out, const quat_t<T> &in);
template <typename T, typename Q>
quat_t<T> operator * (const quat_t<T> &lhs, const quat_t<Q> &rhs);
template <typename T, typename Q>
quat_t<T> operator * (const quat_t<T> &lhs, Q rhs);
template <typename T, typename Q>
quat_t<T> operator + (const quat_t<T> &lhs, const quat_t<Q> &rhs);
template <typename T, typename Q>
quat_t<T> operator - (const quat_t<T> &lhs, const quat_t<Q> &rhs);
template <typename T, typename Q>
T operator % (const quat_t<T> &lhs, const quat_t<Q> &rhs);
template <typename T, typename Q>
bool operator == (const quat_t<T> &lhs, const quat_t<Q> &rhs);
template <typename T, typename Q>
bool operator != (const quat_t<T> &lhs, const quat_t<Q> &rhs);
/*==============================================================================
3-Component Vector
==============================================================================*/
template <typename T = float>
struct alignas(4) vec3_t {
static_assert(std::is_floating_point<T>::value,
"value_type must be floating point type");
static_assert(std::is_scalar<T>::value,
"value_type must be scalar type");
typedef T value_type;
value_type x, y, z;
static const vec3_t pos_X;
static const vec3_t pos_Y;
static const vec3_t pos_Z;
static const vec3_t neg_X;
static const vec3_t neg_Y;
static const vec3_t neg_Z;
static const vec3_t zero;
static const vec3_t one;
static vec3_t make(value_type x, value_type y, value_type z);
vec3_t & normalize();
vec3_t normalized() const;
value_type magnitude() const;
value_type length() const;
vec3_t difference(const vec3_t &other) const;
vec3_t & subtract(const vec3_t &other);
vec3_t sum(const vec3_t &other) const;
vec3_t & add(const vec3_t &other);
vec3_t scaled(value_type scalar) const;
vec3_t scaled(const vec3_t &other) const;
vec3_t & scale(value_type scalar);
vec3_t & scale(const vec3_t &other);
vec3_t negated() const;
vec3_t & negate();
vec3_t inverse() const;
vec3_t & invert();
vec3_t cross_product(const vec3_t &other) const;
value_type dot_product(const vec3_t &other) const;
vec3_t & operator += (const vec3_t &other);
vec3_t & operator -= (const vec3_t &other);
vec3_t & operator *= (value_type scalar);
vec3_t & operator *= (const vec3_t &other);
vec3_t & operator /= (value_type scalar);
vec3_t & operator /= (const vec3_t &other);
vec3_t operator - () const;
vec3_t operator ~ () const;
value_type & operator[] (int index);
value_type operator[] (int index) const;
operator value_type* ();
operator const value_type* () const;
template <typename Q>
operator vec3_t<Q> () const;
};
template <typename T>
std::ostream &operator << (std::ostream &out, const vec3_t<T> &in);
template <typename T, typename Q>
vec3_t<T> operator - (const vec3_t<T> &lhs, const vec3_t<Q> &rhs);
template <typename T, typename Q>
vec3_t<T> operator + (const vec3_t<T> &lhs, const vec3_t<Q> &rhs);
template <typename T, typename Q>
vec3_t<T> operator * (const vec3_t<T> &lhs, const vec3_t<Q> &rhs);
template <typename T, typename Q>
vec3_t<T> operator * (const vec3_t<T> &lhs, Q rhs);
template <typename T, typename Q>
vec3_t<T> operator / (const vec3_t<T> &lhs, const vec3_t<Q> &rhs);
template <typename T, typename Q>
vec3_t<T> operator / (const vec3_t<T> &lhs, Q rhs);
template <typename T, typename Q>
T operator % (const vec3_t<T> &lhs, const vec3_t<Q> &rhs);
template <typename T, typename Q>
bool operator == (const vec3_t<T> &lhs, const vec3_t<Q> &rhs);
template <typename T, typename Q>
bool operator != (const vec3_t<T> &lhs, const vec3_t<Q> &rhs);
#define splat_vec3(V) (V).x, (V).y, (V).z
/*==============================================================================
4-Component Vector
==============================================================================*/
template <typename T = float>
struct alignas(4) vec4_t {
static_assert(std::is_floating_point<T>::value,
"value_type must be floating point type");
static_assert(std::is_scalar<T>::value,
"value_type must be scalar type");
typedef T value_type;
value_type x, y, z, w;
static const vec4_t pos_X;
static const vec4_t pos_Y;
static const vec4_t pos_Z;
static const vec4_t neg_X;
static const vec4_t neg_Y;
static const vec4_t neg_Z;
static const vec4_t zero;
static const vec4_t one;
static vec4_t make(value_type x, value_type y, value_type z, value_type w);
vec4_t & normalize();
vec4_t normalized() const;
value_type magnitude() const;
value_type length() const;
vec4_t difference(const vec4_t &other) const;
vec4_t & subtract(const vec4_t &other);
vec4_t sum(const vec4_t &other) const;
vec4_t & add(const vec4_t &other);
vec4_t scaled(value_type scalar) const;
vec4_t scaled(const vec4_t &other) const;
vec4_t & scale(value_type scalar);
vec4_t & scale(const vec4_t &other);
vec4_t negated() const;
vec4_t & negate();
vec4_t inverse() const;
vec4_t & invert();
value_type dot_product(const vec4_t &other) const;
vec4_t & operator += (const vec4_t &other);
vec4_t & operator -= (const vec4_t &other);
vec4_t & operator *= (value_type scalar);
vec4_t & operator *= (const vec4_t &other);
vec4_t & operator /= (value_type scalar);
vec4_t & operator /= (const vec4_t &other);
vec4_t operator - () const;
vec4_t operator ~ () const;
value_type & operator[] (int index);
value_type operator[] (int index) const;
operator value_type* ();
operator const value_type* () const;
template <typename Q>
operator vec4_t<Q> () const;
};
template <typename T>
std::ostream &operator << (std::ostream &out, const vec4_t<T> &in);
template <typename T, typename Q>
vec4_t<T> operator - (const vec4_t<T> &lhs, const vec4_t<Q> &rhs);
template <typename T, typename Q>
vec4_t<T> operator + (const vec4_t<T> &lhs, const vec4_t<Q> &rhs);
template <typename T, typename Q>
vec4_t<T> operator * (const vec4_t<T> &lhs, const vec4_t<Q> &rhs);
template <typename T, typename Q>
vec4_t<T> operator * (const vec4_t<T> &lhs, Q rhs);
template <typename T, typename Q>
vec4_t<T> operator / (const vec4_t<T> &lhs, const vec4_t<Q> &rhs);
template <typename T, typename Q>
vec4_t<T> operator / (const vec4_t<T> &lhs, Q rhs);
template <typename T, typename Q>
T operator % (const vec4_t<T> &lhs, const vec4_t<Q> &rhs);
template <typename T, typename Q>
bool operator == (const vec4_t<T> &lhs, const vec4_t<Q> &rhs);
template <typename T, typename Q>
bool operator != (const vec4_t<T> &lhs, const vec4_t<Q> &rhs);
#define splat_vec4(V) (V).x, (V).y, (V).z, (V).w
template <typename T>
auto line_t<T>::end() const -> vec3
{
return origin + dist;
}
template <typename T>
auto line_t<T>::translated(const vec3 &d) const -> line_t
{
return {
origin + d, dist
};
}
template <typename T>
auto line_t<T>::translate(const vec3 &d) -> line_t&
{
origin += d;
return *this;
}
template <typename T>
auto line_t<T>::scaled(T d) const -> line_t
{
return {
origin, dist * d
};
}
template <typename T>
auto line_t<T>::scale(T d) -> line_t&
{
dist *= d;
return *this;
}
template <typename T>
auto line_t<T>::nearest_to(const vec3& p) const -> vec3
{
// This is borrowed from Mark Sibly's Blitz3D maths code since it's
// really rather nice.
return end().scale(dist.dot_product(p - origin) / dist.dot_product(dist));
}
template <typename T>
const mat3_t<T> mat3_t<T>::identity = {
{1, 0, 0},
{0, 1, 0},
{0, 0, 1}
};
template <typename T>
const mat3_t<T> mat3_t<T>::zero = {
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}
};
template <typename T>
auto mat3_t<T>::make(T rx, T ry, T rz,
T sx, T sy, T sz,
T tx, T ty, T tz) -> mat3_t
{
return {
{rx, ry, rz},
{sx, sy, sz},
{tx, ty, tz}
};
}
template <typename T>
auto mat3_t<T>::make(const vec3 &x, const vec3 &y, const vec3 &z) -> mat3_t
{
return {x, y, z};
}
template <typename T>
auto mat3_t<T>::scaling(const vec3 &off) -> mat3_t
{
return {
{off.x, 0, 0},
{0, off.y, 0},
{0, 0, off.z}
};
}
template <typename T>
auto mat3_t<T>::rotation(T angle, const vec3 &axis) -> mat3_t
{
angle *= S_DEG2RAD;
const T c = static_cast<T>(std::cos(angle));
const T s = static_cast<T>(std::sin(angle));
const T ic = T(1) - c;
const T xy = axis.x * axis.y * ic;
const T yz = axis.y * axis.z * ic;
const T xz = axis.x * axis.z * ic;
const T xs = s * axis.x;
const T ys = s * axis.y;
const T zs = s * axis.z;
return {
{((axis.x * axis.x) * ic) + c, xy + zs, xz - ys},
{xy - zs, ((axis.y * axis.y) * ic) + c, yz + xs},
{xz + ys, yz - xs, ((axis.z * axis.z) * ic) + c},
};
}
template <typename T>
auto mat3_t<T>::from_quat(const quat &in) -> mat3_t
{
T tx, ty, tz, xx, xy, xz, yy, yz, zz, wx, wy, wz;
tx = 2.0 * in.xyz.x;
ty = 2.0 * in.xyz.y;
tz = 2.0 * in.xyz.z;
xx = tx * in.xyz.x;
xy = tx * in.xyz.y;
xz = tx * in.xyz.z;
yy = ty * in.xyz.y;
yz = tz * in.xyz.y;
zz = tz * in.w;
wx = tx * in.w;
wy = ty * in.w;
wz = tz * in.w;
return {
{T(1) - (yy + zz), xy - wz, xz + wy},
{xy + wz, T(1) - (xx + zz), yz - wx},
{xz - wy, yz + wx, T(1) - (xx + yy)},
};
}
template <typename T>
auto mat3_t<T>::transpose() -> mat3_t &
{
#define S_SWAP_ELEM_(LHS, RHS) temp=(LHS);LHS=(RHS);RHS=temp;
value_type temp;
S_SWAP_ELEM_(r.y, s.x);
S_SWAP_ELEM_(r.z, t.x);
S_SWAP_ELEM_(s.z, t.y);
#undef S_SWAP_ELEM_
return *this;
}
template <typename T>
auto mat3_t<T>::transposed() const -> mat3_t
{
return {
{r.x, s.x, t.x},
{r.y, s.y, t.y},
{r.z, s.z, t.z}
};
}
template <typename T>
auto mat3_t<T>::colvec3(int index) const -> vec3
{
switch (index) {
case 0: return { r.x, s.x, t.x };
case 1: return { r.y, s.y, t.y };
case 2: return { r.z, s.z, t.z };
default: throw std::out_of_range("attempt to access out of range column");
}
}
template <typename T>
auto mat3_t<T>::set_colvec3(int index, const vec3 &col) -> mat3_t &
{
switch (index) {
case 0: r.x = col.x; r.y = col.y; r.z = col.z; break;
case 1: s.x = col.x; s.y = col.y; s.z = col.z; break;
case 2: t.x = col.x; t.y = col.y; t.z = col.z; break;
default: throw std::out_of_range("attempt to access out of range column");
}
return *this;
}
template <typename T>
auto mat3_t<T>::negated() const -> mat3_t
{
return { -r, -s, -t };
}
template <typename T>
auto mat3_t<T>::negate() -> mat3_t &
{
r = -r;
s = -s;
t = -t;
return *this;
}
template <typename T>
auto mat3_t<T>::sum(const mat3_t &other) const -> mat3_t
{
return {
r + other.r,
s + other.s,
t + other.t
};
}
template <typename T>
auto mat3_t<T>::sum(T scalar) const -> mat3_t
{
return {
{r.x + scalar, r.y + scalar, r.z + scalar},
{s.x + scalar, s.y + scalar, s.z + scalar},
{t.x + scalar, t.y + scalar, t.z + scalar}
};
}
template <typename T>
auto mat3_t<T>::add(const mat3_t &other) -> mat3_t &
{
r += other.r;
s += other.s;
t += other.t;
return *this;
}
template <typename T>
auto mat3_t<T>::add(T scalar) -> mat3_t &
{
r.x += scalar;
r.y += scalar;
r.z += scalar;
s.x += scalar;
s.y += scalar;
s.z += scalar;
t.x += scalar;
t.y += scalar;
t.z += scalar;
return *this;
}
template <typename T>
auto mat3_t<T>::difference(const mat3_t &other) const -> mat3_t
{
return {
r - other.r,
s - other.s,
t - other.t
};
}
template <typename T>
auto mat3_t<T>::difference(T scalar) const -> mat3_t
{
return {
{r.x - scalar, r.y - scalar, r.z - scalar},
{s.x - scalar, s.y - scalar, s.z - scalar},
{t.x - scalar, t.y - scalar, t.z - scalar}
};
}
template <typename T>
auto mat3_t<T>::subtract(const mat3_t &other) -> mat3_t &
{
r -= other.r;
s -= other.s;
t -= other.t;
return *this;
}
template <typename T>
auto mat3_t<T>::subtract(T scalar) -> mat3_t &
{
r.x -= scalar;
r.y -= scalar;
r.z -= scalar;
s.x -= scalar;
s.y -= scalar;
s.z -= scalar;
t.x -= scalar;
t.y -= scalar;
t.z -= scalar;
return *this;
}
template <typename T>
auto mat3_t<T>::scaled(T scalar) const -> mat3_t
{
return {
r.scaled(scalar),
s.scaled(scalar),
t.scaled(scalar)
};
}
template <typename T>
auto mat3_t<T>::scale(T scalar) -> mat3_t &
{
r.scale(scalar);
s.scale(scalar);
t.scale(scalar);
return *this;
}
template <typename T>
auto mat3_t<T>::scaled(const mat3_t &other) const -> mat3_t
{
return {
r * other.r,
s * other.s,
t * other.t
};
}
template <typename T>
auto mat3_t<T>::scale(const mat3_t &other) -> mat3_t &
{
r *= other.r;
s *= other.s;
t *= other.t;
return *this;
}
template <typename T>
auto mat3_t<T>::scaled(const vec3 &vec) const -> mat3_t
{
return {
r.scaled(vec.x),
s.scaled(vec.y),
t.scaled(vec.z)
};
}
template <typename T>
auto mat3_t<T>::scale(const vec3 &vec) -> mat3_t &
{
r.scale(vec.x);
s.scale(vec.y);
t.scale(vec.z);
return *this;
}
template <typename T>
auto mat3_t<T>::inverse() const -> mat3_t
{
return cofactor().transpose().invert();
}
template <typename T>
auto mat3_t<T>::invert() -> mat3_t &
{
value_type inv_det = T(1) / determinant();
*this = cofactor();
transpose().scale(inv_det);
return *this;
}
template <typename T>
auto mat3_t<T>::adjoint() const -> mat3_t
{
return cofactor().transpose();
}
template <typename T>
auto mat3_t<T>::cofactor() const -> mat3_t
{
return {
{ (s.y * t.z - s.z * t.y),
-(s.x * t.z - s.z * t.x),
(s.x * t.y - s.y * t.x) },
{-(r.y * t.z - r.z * t.y),
(r.x * t.z - r.z * t.x),
-(r.x * t.y - r.y * t.x) },
{ (r.y * s.z - r.z * s.y),
-(r.x * s.z - r.z * s.x),
(r.x * s.y - r.y * s.x) }
};
}
template <typename T>
auto mat3_t<T>::determinant() const -> T
{
return r.x * (s.y * t.z - s.z * t.y) +
r.y * (s.z * t.x - s.x * t.z) +
r.z * (s.x * t.y - s.y * t.x);
}
template <typename T>
auto mat3_t<T>::orthogonal() const -> mat3_t
{
mat3_t temp = *this;
temp.orthogonalize();
return temp;
}
template <typename T>
auto mat3_t<T>::orthogonalize() -> mat3_t &
{
r = s.cross_product(t.normalize()); r.normalize();
s = t.cross_product(r);
return *this;
}
template <typename T>
auto mat3_t<T>::product(const mat3_t &other) const -> mat3_t
{
mat3_t temp;
value_type *m = &temp.r.x;
for (int cindex = 0; cindex < 3; ++cindex) {
const vec3 column = colvec3(cindex);
m[cindex ] = column.dot_product(r);
m[cindex + 3] = column.dot_product(s);
m[cindex + 6] = column.dot_product(t);
}
return temp;
}
template <typename T>
auto mat3_t<T>::multiply(const mat3_t &other) -> mat3_t &
{
value_type *m = &r.x;
for (int cindex = 0; cindex < 3; ++cindex) {
const vec3 column = colvec3(cindex);
m[cindex ] = column.dot_product(r);
m[cindex + 3] = column.dot_product(s);
m[cindex + 6] = column.dot_product(t);
}
return *this;
}
template <typename T>
auto mat3_t<T>::rotate(const vec3 &vec) const -> vec3
{
return {
vec.dot_product(colvec3(0)),
vec.dot_product(colvec3(1)),
vec.dot_product(colvec3(2))
};
}
template <typename T>
auto mat3_t<T>::inverse_rotate(const vec3 &vec) const -> vec3
{
return {
vec.dot_product(r),
vec.dot_product(s),
vec.dot_product(t)
};
}
template <typename T>
auto mat3_t<T>::operator[] (int index) -> T&
{
static_assert(std::is_pod<mat3_t>::value, "mat4 must be POD to use subscript operator");
if (index < 0 || index > 9)
throw std::out_of_range("attempt to access out of range element");
return (&r.x)[index];
}
template <typename T>
auto mat3_t<T>::operator[] (int index) const -> T
{
static_assert(std::is_pod<mat3_t>::value, "mat4 must be POD to use subscript operator");
if (index < 0 || index > 9)
throw std::out_of_range("attempt to access out of range element");
return (&r.x)[index];
}
template <typename T>
mat3_t<T>::operator T* ()
{
static_assert(std::is_pod<mat3_t>::value, "mat4 must be POD to cast to T pointer");
return &r.x;
}
template <typename T>
mat3_t<T>::operator const T* () const
{
static_assert(std::is_pod<mat3_t>::value, "mat4 must be POD to cast to T pointer");
return &r.x;
}
template <typename T>
mat3_t<T>::operator mat4_t<T> () const
{
return {
splat_vec3(r), 0,
splat_vec3(s), 0,
splat_vec3(t), 0,
0, 0, 0, 1
};
}
template <typename T>
mat3_t<T>::operator quat_t<T> () const
{
return quat_t<T>::from_mat3(*this);
}
template <typename T>
auto mat3_t<T>::operator *= (const mat3_t &other) -> mat3_t &
{
return multiply(other);
}
template <typename T>
auto mat3_t<T>::operator *= (T scalar) -> mat3_t &
{
return scale(scalar);
}
template <typename T>
auto mat3_t<T>::operator += (const mat3_t &other) -> mat3_t &
{
return add(other);
}
template <typename T>
auto mat3_t<T>::operator += (T scalar) -> mat3_t &
{
return add(scalar);
}
template <typename T>
auto mat3_t<T>::operator -= (const mat3_t &other) -> mat3_t &
{
return subtract(other);
}
template <typename T>
auto mat3_t<T>::operator -= (T scalar) -> mat3_t &
{
return subtract(scalar);
}
template <typename T>
std::ostream &operator << (std::ostream &out, const mat3_t<T> &in)
{
out << "{";
for (int index = 0; index < 9; ++index) {
out << in[index];
if (index < 8)
out << ", ";
}
return out << "}";
}
template <typename T, typename Q>
mat3_t<T> operator * (const mat3_t<T> &rhs, const mat3_t<Q> &lhs)
{
return rhs.product(lhs);
}
template <typename T, typename Q>
vec3_t<T> operator * (const mat3_t<T> &rhs, const vec3_t<Q> &lhs)
{
return rhs.rotate(lhs);
}
template <typename T, typename Q>
mat3_t<T> operator * (const mat3_t<T> &rhs, const Q &lhs)
{
return rhs.scaled(lhs);
}
template <typename T, typename Q>
mat3_t<T> operator + (const mat3_t<T> &rhs, const mat3_t<Q> &lhs)
{
return rhs.sum(lhs);
}
template <typename T, typename Q>
mat3_t<T> operator + (const mat3_t<T> &rhs, const Q &lhs)
{
return rhs.sum(lhs);
}
template <typename T, typename Q>
mat3_t<T> operator - (const mat3_t<T> &rhs, const mat3_t<Q> &lhs)
{
return rhs.difference(lhs);
}
template <typename T, typename Q>
mat3_t<T> operator - (const mat3_t<T> &rhs, const Q &lhs)
{
return rhs.difference(lhs);
}
template <typename T, typename Q>
bool operator == (const mat3_t<T> &rhs, const mat3_t<Q> &lhs)
{
return lhs.r == rhs.r && lhs.s == rhs.s && lhs.t == rhs.t;
}
template <typename T, typename Q>
bool operator != (const mat3_t<T> &rhs, const mat3_t<Q> &lhs)
{
return !(rhs == lhs);
}
template <typename T>
const mat4_t<T> mat4_t<T>::identity = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};
template <typename T>
const mat4_t<T> mat4_t<T>::zero = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};
template <typename T>
auto mat4_t<T>::make(T m00, T m10, T m20, T m30,
T m01, T m11, T m21, T m31,
T m02, T m12, T m22, T m32,
T m03, T m13, T m23, T m33) -> mat4_t
{
return {
m00, m10, m20, m30,
m01, m11, m21, m31,
m02, m12, m22, m32,
m03, m13, m23, m33
};
}
template <typename T>
auto mat4_t<T>::translation(const vec3 &off) -> mat4_t
{
return {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
off.x, off.y, off.z, 1
};
}
template <typename T>
auto mat4_t<T>::scaling(const vec3 &off) -> mat4_t
{
return {
off.x, 0, 0, 0,
0, off.y, 0, 0,
0, 0, off.z, 0,
0, 0, 0, 1
};
}
template <typename T>
auto mat4_t<T>::rotation(T angle, const vec3 &axis) -> mat4_t
{
angle *= S_DEG2RAD;
const T c = static_cast<T>(std::cos(angle));
const T s = static_cast<T>(std::sin(angle));
const T ic = T(1) - c;
const T xy = axis.x * axis.y * ic;
const T yz = axis.y * axis.z * ic;
const T xz = axis.x * axis.z * ic;
const T xs = s * axis.x;
const T ys = s * axis.y;
const T zs = s * axis.z;
return {
((axis.x * axis.x) * ic) + c, xy + zs, xz - ys, 0,
xy - zs, ((axis.y * axis.y) * ic) + c, yz + xs, 0,
xz + ys, yz - xs, ((axis.z * axis.z) * ic) + c, 0,
0, 0, 0, 1
};
}
template <typename T>
auto mat4_t<T>::frustum(T left, T right, T bottom, T top, T near, T far) -> mat4_t
{
const T xdelta = right - left;
const T ydelta = top - bottom;
const T zdelta = far - near;
const T neardouble = 2.0 * near;
return {
neardouble / xdelta, 0, (right + left) / xdelta, 0,
0, neardouble / ydelta, (top + bottom) / ydelta, 0,
0, 0, -((far + near) / zdelta), -1.0,
0, 0, -((neardouble * far) / zdelta), 0
};
}
template <typename T>
auto mat4_t<T>::orthographic(T left, T right,
T top, T bottom,
T near, T far) -> mat4_t
{
const T xdelta = right - left;
const T ydelta = top - bottom;
const T zdelta = far - near;
return {
T(2) / xdelta, 0, 0, 0,
0, T(2) / ydelta, 0, 0,
0, 0, T(-2) / zdelta, 0,
-((right + left) / xdelta), -((top + bottom) / ydelta), -((far + near) / zdelta), 1
};
}
template <typename T>
auto mat4_t<T>::perspective(T fovY, T aspect, T near, T far) -> mat4_t
{
const float r = static_cast<T>(tanf(fovY * 0.5 * S_DEG2RAD));
const float left = -r * aspect;
const float right = r * aspect;
const float bottom = -r;
const float top = r;
const float twoNear = 2 * near;
const float zdelta = T(1) / (near - far);
return {
twoNear * (right - left), 0, 0, 0,
0, twoNear / (top - bottom), 0, 0,
0, 0, (far + near) * zdelta, -1,
0, 0, (twoNear * far) * zdelta, 0
};
}
template <typename T>
auto mat4_t<T>::look_at(const vec3 &eye, const vec3& center, const vec3& up) -> mat4_t
{
vec3 facing_norm = (center - eye).normalize();
vec3 up_norm = up.normalized();
vec3 s = (facing_norm.cross_product(up_norm)).normalize();
up_norm = s.cross_product(facing_norm);
facing_norm.negate();
up_norm.y = - up_norm.y;
mat4_t looker = {
up_norm.x, up_norm.y, up_norm.z, 0,
facing_norm.x, facing_norm.y, facing_norm.z, 0,
0, 0, 0, 0,
0, 0, 0, 1
};
return looker.translate(eye.negated());
}
template <typename T>
auto mat4_t<T>::from_quat(const quat &in) -> mat4_t
{
T tx, ty, tz, xx, xy, xz, yy, yz, zz, wx, wy, wz;
tx = 2.0 * in.xyz.x;
ty = 2.0 * in.xyz.y;
tz = 2.0 * in.xyz.z;
xx = tx * in.xyz.x;
xy = tx * in.xyz.y;
xz = tx * in.xyz.z;
yy = ty * in.xyz.y;
yz = tz * in.xyz.y;
zz = tz * in.w;
wx = tx * in.w;
wy = ty * in.w;
wz = tz * in.w;
return {
T(1) - (yy + zz), xy - wz, xz + wy, 0,
xy + wz, T(1) - (xx + zz), yz - wx, 0,
xz - wy, yz + wx, T(1) - (xx + yy), 0,
0, 0, 0, 1
};
}
template <typename T>
auto mat4_t<T>::translated(const vec3 &translation) const -> mat4_t
{
mat4_t r = *this;
return r.translate(translation);
}
template <typename T>
auto mat4_t<T>::transpose() -> mat4_t &
{
#define S_SWAP_ELEM_(LHS, RHS) t=LHS;LHS=RHS;RHS=t;
T t;
S_SWAP_ELEM_(m10, m01);
S_SWAP_ELEM_(m20, m02);
S_SWAP_ELEM_(m30, m03);
S_SWAP_ELEM_(m21, m12);
S_SWAP_ELEM_(m31, m13);
S_SWAP_ELEM_(m32, m23);
#undef S_SWAP_ELEM_
return *this;
}
template <typename T>
auto mat4_t<T>::transposed() const -> mat4_t
{
return {
m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33
};
}
template <typename T>
auto mat4_t<T>::rowvec4(int index) const -> vec4
{
switch (index) {
case 0: return { m00, m10, m20, m30 };
case 1: return { m01, m11, m21, m31 };
case 2: return { m02, m12, m22, m32 };
case 3: return { m03, m13, m23, m33 };
default: throw std::out_of_range("attempt to access out of range row");
}
}
template <typename T>
auto mat4_t<T>::colvec4(int index) const -> vec4
{
switch (index) {
case 0: return { m00, m01, m02, m03 };
case 1: return { m10, m11, m12, m13 };
case 2: return { m20, m21, m22, m23 };
case 3: return { m30, m31, m32, m33 };
default: throw std::out_of_range("attempt to access out of range column");
}
}
template <typename T>
auto mat4_t<T>::set_rowvec4(int index, const vec4 &row) -> mat4_t &
{
switch (index) {
case 0: m00 = row.x; m10 = row.y; m20 = row.z; m30 = row.w; break;
case 1: m01 = row.x; m11 = row.y; m21 = row.z; m31 = row.w; break;
case 2: m02 = row.x; m12 = row.y; m22 = row.z; m32 = row.w; break;
case 3: m03 = row.x; m13 = row.y; m23 = row.z; m33 = row.w; break;
default: throw std::out_of_range("attempt to access out of range row");
}
return *this;
}
template <typename T>
auto mat4_t<T>::set_colvec4(int index, const vec4 &col) -> mat4_t &
{
switch (index) {
case 0: m00 = col.x; m01 = col.y; m02 = col.z; m03 = col.w; break;
case 1: m10 = col.x; m11 = col.y; m12 = col.z; m13 = col.w; break;
case 2: m20 = col.x; m21 = col.y; m22 = col.z; m23 = col.w; break;
case 3: m30 = col.x; m31 = col.y; m32 = col.z; m33 = col.w; break;
default: throw std::out_of_range("attempt to access out of range column");
}
return *this;
}
template <typename T>
auto mat4_t<T>::rowvec3(int index) const -> vec3
{
switch (index) {
case 0: return { m00, m10, m20 };
case 1: return { m01, m11, m21 };
case 2: return { m02, m12, m22 };
case 3: return { m03, m13, m23 };
default: throw std::out_of_range("attempt to access out of range row");
}
}
template <typename T>
auto mat4_t<T>::colvec3(int index) const -> vec3
{
switch (index) {
case 0: return { m00, m01, m02 };
case 1: return { m10, m11, m12 };
case 2: return { m20, m21, m22 };
case 3: return { m30, m31, m32 };
default: throw std::out_of_range("attempt to access out of range column");
}
}
template <typename T>
auto mat4_t<T>::set_rowvec3(int index, const vec3 &row) -> mat4_t &
{
switch (index) {
case 0: m00 = row.x; m10 = row.y; m20 = row.z; break;
case 1: m01 = row.x; m11 = row.y; m21 = row.z; break;
case 2: m02 = row.x; m12 = row.y; m22 = row.z; break;
case 3: m03 = row.x; m13 = row.y; m23 = row.z; break;
default: throw std::out_of_range("attempt to access out of range row");
}
return *this;
}
template <typename T>
auto mat4_t<T>::set_colvec3(int index, const vec3 &col) -> mat4_t &
{
switch (index) {
case 0: m00 = col.x; m01 = col.y; m02 = col.z; break;
case 1: m10 = col.x; m11 = col.y; m12 = col.z; break;
case 2: m20 = col.x; m21 = col.y; m22 = col.z; break;
case 3: m30 = col.x; m31 = col.y; m32 = col.z; break;
default: throw std::out_of_range("attempt to access out of range column");
}
return *this;
}
template <typename T>
auto mat4_t<T>::inverse_orthogonal() -> mat4_t
{
vec3_t<T> row = { m03, m13, m23 };
mat4_t temp = {
m00, m01, m02, 0,
m10, m11, m12, 0,
m20, m21, m22, 0,
0, 0, 0, 1
};
temp.m03 = -row.dot_product(temp.colvec3(0));
temp.m13 = -row.dot_product(temp.colvec3(1));
temp.m23 = -row.dot_product(temp.colvec3(2));
return temp;
}
template <typename T>
auto mat4_t<T>::negated() const -> mat4_t
{
return {
-m00, -m10, -m20, -m30,
-m01, -m11, -m21, -m31,
-m02, -m12, -m22, -m32,
-m03, -m13, -m23, -m33
};
}
template <typename T>
auto mat4_t<T>::negate() -> mat4_t &
{
m00 = -m00; m10 = -m10; m20 = -m20; m30 = -m30;
m01 = -m01; m11 = -m11; m21 = -m21; m31 = -m31;
m02 = -m02; m12 = -m12; m22 = -m22; m32 = -m32;
m03 = -m03; m13 = -m13; m23 = -m23; m33 = -m33;
return *this;
}
template <typename T>
auto mat4_t<T>::sum(const mat4_t &other) const -> mat4_t
{
return {
m00 + other.m00,
m10 + other.m10,
m20 + other.m20,
m30 + other.m30,
m01 + other.m01,
m11 + other.m11,
m21 + other.m21,
m31 + other.m31,
m02 + other.m02,
m12 + other.m12,
m22 + other.m22,
m32 + other.m32,
m03 + other.m03,
m13 + other.m13,
m23 + other.m23,
m33 + other.m33
};
}
template <typename T>
auto mat4_t<T>::sum(T scalar) const -> mat4_t
{
return {
m00 + scalar,
m10 + scalar,
m20 + scalar,
m30 + scalar,
m01 + scalar,
m11 + scalar,
m21 + scalar,
m31 + scalar,
m02 + scalar,
m12 + scalar,
m22 + scalar,
m32 + scalar,
m03 + scalar,
m13 + scalar,
m23 + scalar,
m33 + scalar
};
}
template <typename T>
auto mat4_t<T>::add(const mat4_t &other) -> mat4_t &
{
m00 += other.m00;
m10 += other.m10;
m20 += other.m20;
m30 += other.m30;
m01 += other.m01;
m11 += other.m11;
m21 += other.m21;
m31 += other.m31;
m02 += other.m02;
m12 += other.m12;
m22 += other.m22;
m32 += other.m32;
m03 += other.m03;
m13 += other.m13;
m23 += other.m23;
m33 += other.m33;
return *this;
}
template <typename T>
auto mat4_t<T>::add(T scalar) -> mat4_t &
{
m00 += scalar;
m10 += scalar;
m20 += scalar;
m30 += scalar;
m01 += scalar;
m11 += scalar;
m21 += scalar;
m31 += scalar;
m02 += scalar;
m12 += scalar;
m22 += scalar;
m32 += scalar;
m03 += scalar;
m13 += scalar;
m23 += scalar;
m33 += scalar;
return *this;
}
template <typename T>
auto mat4_t<T>::difference(const mat4_t &other) const -> mat4_t
{
return {
m00 - other.m00,
m10 - other.m10,
m20 - other.m20,
m30 - other.m30,
m01 - other.m01,
m11 - other.m11,
m21 - other.m21,
m31 - other.m31,
m02 - other.m02,
m12 - other.m12,
m22 - other.m22,
m32 - other.m32,
m03 - other.m03,
m13 - other.m13,
m23 - other.m23,
m33 - other.m33
};
}
template <typename T>
auto mat4_t<T>::difference(T scalar) const -> mat4_t
{
return {
m00 - scalar,
m10 - scalar,
m20 - scalar,
m30 - scalar,
m01 - scalar,
m11 - scalar,
m21 - scalar,
m31 - scalar,
m02 - scalar,
m12 - scalar,
m22 - scalar,
m32 - scalar,
m03 - scalar,
m13 - scalar,
m23 - scalar,
m33 - scalar
};
}
template <typename T>
auto mat4_t<T>::subtract(const mat4_t &other) -> mat4_t &
{
m00 -= other.m00;
m10 -= other.m10;
m20 -= other.m20;
m30 -= other.m30;
m01 -= other.m01;
m11 -= other.m11;
m21 -= other.m21;
m31 -= other.m31;
m02 -= other.m02;
m12 -= other.m12;
m22 -= other.m22;
m32 -= other.m32;
m03 -= other.m03;
m13 -= other.m13;
m23 -= other.m23;
m33 -= other.m33;
return *this;
}
template <typename T>
auto mat4_t<T>::subtract(T scalar) -> mat4_t &
{
m00 -= scalar;
m10 -= scalar;
m20 -= scalar;
m30 -= scalar;
m01 -= scalar;
m11 -= scalar;
m21 -= scalar;
m31 -= scalar;
m02 -= scalar;
m12 -= scalar;
m22 -= scalar;
m32 -= scalar;
m03 -= scalar;
m13 -= scalar;
m23 -= scalar;
m33 -= scalar;
return *this;
}
template <typename T>
auto mat4_t<T>::scaled(T scalar) const -> mat4_t
{
return {
m00 * scalar,
m10 * scalar,
m20 * scalar,
m30 * scalar,
m01 * scalar,
m11 * scalar,
m21 * scalar,
m31 * scalar,
m02 * scalar,
m12 * scalar,
m22 * scalar,
m32 * scalar,
m03 * scalar,
m13 * scalar,
m23 * scalar,
m33 * scalar
};
}
template <typename T>
auto mat4_t<T>::scale(T scalar) -> mat4_t &
{
m00 *= scalar;
m10 *= scalar;
m20 *= scalar;
m30 *= scalar;
m01 *= scalar;
m11 *= scalar;
m21 *= scalar;
m31 *= scalar;
m02 *= scalar;
m12 *= scalar;
m22 *= scalar;
m32 *= scalar;
m03 *= scalar;
m13 *= scalar;
m23 *= scalar;
m33 *= scalar;
return *this;
}
template <typename T>
auto mat4_t<T>::scaled(const mat4_t &other) const -> mat4_t
{
return {
m00 * other.m00,
m10 * other.m10,
m20 * other.m20,
m30 * other.m30,
m01 * other.m01,
m11 * other.m11,
m21 * other.m21,
m31 * other.m31,
m02 * other.m02,
m12 * other.m12,
m22 * other.m22,
m32 * other.m32,
m03 * other.m03,
m13 * other.m13,
m23 * other.m23,
m33 * other.m33
};
}
template <typename T>
auto mat4_t<T>::scale(const mat4_t &other) -> mat4_t &
{
m00 *= other.m00;
m10 *= other.m10;
m20 *= other.m20;
m30 *= other.m30;
m01 *= other.m01;
m11 *= other.m11;
m21 *= other.m21;
m31 *= other.m31;
m02 *= other.m02;
m12 *= other.m12;
m22 *= other.m22;
m32 *= other.m32;
m03 *= other.m03;
m13 *= other.m13;
m23 *= other.m23;
m33 *= other.m33;
return *this;
}
template <typename T>
auto mat4_t<T>::scaled(const vec3 &vec) const -> mat4_t
{
return {
m00 * vec.x,
m10 * vec.x,
m20 * vec.x,
m30,
m01 * vec.y,
m11 * vec.y,
m21 * vec.y,
m31,
m02 * vec.z,
m12 * vec.z,
m22 * vec.z,
m32,
m03,
m13,
m23,
m33
};
}
template <typename T>
auto mat4_t<T>::scale(const vec3 &vec) -> mat4_t &
{
m00 *= vec.x;
m10 *= vec.x;
m20 *= vec.x;
m01 *= vec.y;
m11 *= vec.y;
m21 *= vec.y;
m02 *= vec.z;
m12 *= vec.z;
m22 *= vec.z;
return *this;
}
template <typename T>
auto mat4_t<T>::cofactor(int r0, int r1, int r2, int c0, int c1, int c2) const -> T
{
const T *m = &m00;
// Macro for getting the value at the cofactor address provided
#define S_CF_ADDR_(l, r) (m[(l * 4) + r])
return (
(S_CF_ADDR_(r0,c0) * ((S_CF_ADDR_(r1, c1) * S_CF_ADDR_(r2, c2)) - (S_CF_ADDR_(r2, c1) * S_CF_ADDR_(r1, c2)))) -
(S_CF_ADDR_(r0,c1) * ((S_CF_ADDR_(r1, c0) * S_CF_ADDR_(r2, c2)) - (S_CF_ADDR_(r2, c0) * S_CF_ADDR_(r1, c2)))) +
(S_CF_ADDR_(r0,c2) * ((S_CF_ADDR_(r1, c0) * S_CF_ADDR_(r2, c1)) - (S_CF_ADDR_(r2, c0) * S_CF_ADDR_(r1, c1))))
);
#undef S_CF_ADDR_
}
template <typename T>
auto mat4_t<T>::determinant() const -> T
{
return ((m00 * cofactor(1, 2, 3, 1, 2, 3)) -
(m01 * cofactor(1, 2, 3, 0, 2, 3)) +
(m02 * cofactor(1, 2, 3, 0, 1, 3)) -
(m03 * cofactor(1, 2, 3, 0, 1, 2)));
}
template <typename T>
auto mat4_t<T>::inverse_general(mat4_t &out) const -> bool
{
T det = determinant();
if (is_zero(det)) {
return false;
}
out = adjoint().scale(T(1) / det);
return true;
}
template <typename T>
auto mat4_t<T>::product(const mat4_t &other) const -> mat4_t
{
mat4_t temp;
T *m = &temp.m00;
const vec4 rowvecs[4] = {
rowvec4(0),
rowvec4(1),
rowvec4(2),
rowvec4(3)
};
for (int cindex = 0; cindex < 4; ++cindex) {
const vec4 column = colvec4(cindex);
m[cindex ] = column.dot_product(rowvecs[0]);
m[cindex + 4 ] = column.dot_product(rowvecs[1]);
m[cindex + 8 ] = column.dot_product(rowvecs[2]);
m[cindex + 12] = column.dot_product(rowvecs[3]);
}
return temp;
}
template <typename T>
auto mat4_t<T>::multiply(const mat4_t &other) -> mat4_t &
{
T *m = &m00;
const vec4 rowvecs[4] = {
rowvec4(0),
rowvec4(1),
rowvec4(2),
rowvec4(3)
};
for (int cindex = 0; cindex < 4; ++cindex) {
const vec4 column = colvec4(cindex);
m[cindex ] = column.dot_product(rowvecs[0]);
m[cindex + 4 ] = column.dot_product(rowvecs[1]);
m[cindex + 8 ] = column.dot_product(rowvecs[2]);
m[cindex + 12] = column.dot_product(rowvecs[3]);
}
return *this;
}
template <typename T>
auto mat4_t<T>::multiply(const vec4 &vec) const -> vec4
{
return {
vec.dot_product(colvec4(0)),
vec.dot_product(colvec4(1)),
vec.dot_product(colvec4(2)),
vec.dot_product(colvec4(3))
};
}
template <typename T>
auto mat4_t<T>::multiply(const vec3 &vec) const -> vec3
{
return {
vec.dot_product(colvec3(0)) + m03,
vec.dot_product(colvec3(1)) + m13,
vec.dot_product(colvec3(2)) + m23
};
}
template <typename T>
auto mat4_t<T>::rotate(const vec3 &vec) const -> vec3
{
return {
vec.dot_product(colvec3(0)),
vec.dot_product(colvec3(1)),
vec.dot_product(colvec3(2))
};
}
template <typename T>
auto mat4_t<T>::inverse_rotate(const vec3 &vec) const -> vec3
{
return {
vec.dot_product(rowvec3(0)),
vec.dot_product(rowvec3(1)),
vec.dot_product(rowvec3(2))
};
}
template <typename T>
auto mat4_t<T>::translate(const vec3 &translation) -> mat4_t &
{
m03 += translation.dot_product(colvec3(0));
m13 += translation.dot_product(colvec3(1));
m23 += translation.dot_product(colvec3(2));
m33 += translation.dot_product(colvec3(3));
return *this;
}
template <typename T>
auto mat4_t<T>::inverse_affine(mat4_t & out) const -> bool
{
T det;
mat4_t temp = {
(m11 * m22) - (m21 * m12),
(m20 * m12) - (m01 * m22),
(m01 * m21) - (m20 * m11),
0,
(m21 * m02) - (m01 * m22),
(m00 * m22) - (m20 * m02),
(m20 * m01) - (m00 * m21),
0,
(m01 * m12) - (m11 * m02),
(m01 * m02) - (m00 * m12),
(m00 * m11) - (m01 * m01),
0,
0, 0, 0, 0
};
det = m00 * temp.m00 + m10 * temp.m01 + m20 * temp.m02;
if (is_zero(det)) {
return false;
}
temp.scale(T(1) / det);
vec3 txyz = rowvec3(3);
temp.m03 = -txyz.dot_product(temp.colvec3(0));
temp.m13 = -txyz.dot_product(temp.colvec3(1));
temp.m23 = -txyz.dot_product(temp.colvec3(2));
out = temp;
return true;
}
template <typename T>
auto mat4_t<T>::adjoint() const -> mat4_t
{
return {
cofactor(1, 2, 3, 1, 2, 3),
-cofactor(0, 2, 3, 1, 2, 3),
cofactor(0, 1, 3, 1, 2, 3),
-cofactor(0, 1, 2, 1, 2, 3),
-cofactor(1, 2, 3, 0, 2, 3),
cofactor(0, 2, 3, 0, 2, 3),
-cofactor(0, 1, 3, 0, 2, 3),
cofactor(0, 1, 2, 0, 2, 3),
cofactor(1, 2, 3, 0, 1, 3),
-cofactor(0, 2, 3, 0, 1, 3),
cofactor(0, 1, 3, 0, 1, 3),
-cofactor(0, 1, 2, 0, 1, 3),
-cofactor(1, 2, 3, 0, 1, 2),
cofactor(0, 2, 3, 0, 1, 2),
-cofactor(0, 1, 3, 0, 1, 2),
cofactor(0, 1, 2, 0, 1, 2)
};
}
template <typename T>
auto mat4_t<T>::operator[] (int index) -> T&
{
static_assert(std::is_pod<mat4_t>::value, "mat4 must be POD to use subscript operator");
if (index < 0 || index > 15)
throw std::out_of_range("attempt to access out of range element");
return (&m00)[index];
}
template <typename T>
auto mat4_t<T>::operator[] (int index) const -> T
{
static_assert(std::is_pod<mat4_t>::value, "mat4 must be POD to use subscript operator");
if (index < 0 || index > 15)
throw std::out_of_range("attempt to access out of range element");
return (&m00)[index];
}
template <typename T>
mat4_t<T>::operator T* ()
{
static_assert(std::is_pod<mat4_t>::value, "mat4 must be POD to cast to T pointer");
return &m00;
}
template <typename T>
mat4_t<T>::operator const T* () const
{
static_assert(std::is_pod<mat4_t>::value, "mat4 must be POD to cast to T pointer");
return &m00;
}
template <typename T>
mat4_t<T>::operator mat3_t<T> () const
{
return {
rowvec3(0),
rowvec3(1),
rowvec3(2)
};
}
template <typename T>
mat4_t<T>::operator quat_t<T> () const
{
return quat_t<T>::from_mat4(*this);
}
template <typename T>
auto mat4_t<T>::operator *= (const mat4_t &other) -> mat4_t &
{
return multiply(other);
}
template <typename T>
auto mat4_t<T>::operator *= (T scalar) -> mat4_t &
{
return scale(scalar);
}
template <typename T>
auto mat4_t<T>::operator += (const mat4_t &other) -> mat4_t &
{
return add(other);
}
template <typename T>
auto mat4_t<T>::operator += (T scalar) -> mat4_t &
{
return add(scalar);
}
template <typename T>
auto mat4_t<T>::operator -= (const mat4_t &other) -> mat4_t &
{
return subtract(other);
}
template <typename T>
auto mat4_t<T>::operator -= (T scalar) -> mat4_t &
{
return subtract(scalar);
}
template <typename T>
std::ostream &operator << (std::ostream &out, const mat4_t<T> &in)
{
out << "{";
for (int index = 0; index < 16; ++index) {
out << in[index];
if (index < 15)
out << ", ";
}
return out << "}";
}
template <typename T, typename Q>
mat4_t<T> operator * (const mat4_t<T> &rhs, const mat4_t<Q> &lhs)
{
return rhs.product(lhs);
}
template <typename T, typename Q>
vec4_t<T> operator * (const mat4_t<T> &rhs, const vec4_t<Q> &lhs)
{
return rhs.multiply(lhs);
}
template <typename T, typename Q>
vec3_t<T> operator * (const mat4_t<T> &rhs, const vec3_t<Q> &lhs)
{
return rhs.multiply(lhs);
}
template <typename T, typename Q>
mat4_t<T> operator * (const mat4_t<T> &rhs, const Q &lhs)
{
return rhs.scaled(lhs);
}
template <typename T, typename Q>
mat4_t<T> operator + (const mat4_t<T> &rhs, const mat4_t<Q> &lhs)
{
return rhs.sum(lhs);
}
template <typename T, typename Q>
mat4_t<T> operator + (const mat4_t<T> &rhs, const Q &lhs)
{
return rhs.sum(lhs);
}
template <typename T, typename Q>
mat4_t<T> operator - (const mat4_t<T> &rhs, const mat4_t<Q> &lhs)
{
return rhs.difference(lhs);
}
template <typename T, typename Q>
mat4_t<T> operator - (const mat4_t<T> &rhs, const Q &lhs)
{
return rhs.difference(lhs);
}
template <typename T, typename Q>
bool operator == (const mat4_t<T> &rhs, const mat4_t<Q> &lhs)
{
return
is_zero(lhs.m00 - rhs.m00) &&
is_zero(lhs.m10 - rhs.m10) &&
is_zero(lhs.m20 - rhs.m20) &&
is_zero(lhs.m01 - rhs.m01) &&
is_zero(lhs.m11 - rhs.m11) &&
is_zero(lhs.m21 - rhs.m21) &&
is_zero(lhs.m02 - rhs.m02) &&
is_zero(lhs.m12 - rhs.m12) &&
is_zero(lhs.m22 - rhs.m22) &&
is_zero(lhs.m03 - rhs.m03) &&
is_zero(lhs.m13 - rhs.m13) &&
is_zero(lhs.m23 - rhs.m23) &&
is_zero(lhs.m30 - rhs.m30) &&
is_zero(lhs.m31 - rhs.m31) &&
is_zero(lhs.m32 - rhs.m32) &&
is_zero(lhs.m33 - rhs.m33);
}
template <typename T, typename Q>
bool operator != (const mat4_t<T> &rhs, const mat4_t<Q> &lhs)
{
return !(rhs == lhs);
}
template <typename T>
const quat_t<T> quat_t<T>::zero = { { 0, 0, 0 }, 0 };
template <typename T>
const quat_t<T> quat_t<T>::one = { { 1, 1, 1 }, 1 };
template <typename T>
const quat_t<T> quat_t<T>::identity = { { 0, 0, 0 }, 1 };
template <typename T>
auto quat_t<T>::make(T x, T y, T z, T w) -> quat_t
{
return { { x, y, z }, w };
}
template <typename T>
auto quat_t<T>::make(vec3 xyz, T w) -> quat_t
{
return { xyz, w };
}
template <typename T>
auto quat_t<T>::length() const -> T
{
return xyz.length() + w * w;
}
template <typename T>
auto quat_t<T>::magnitude() const -> T
{
const T sqrlen = length();
return sqrlen != 0
? static_cast<T>(std::sqrt(sqrlen))
: 0;
}
template <typename T>
auto quat_t<T>::inverse() const -> quat_t
{
return {
-xyz, w
};
}
template <typename T>
auto quat_t<T>::invert() -> quat_t&
{
xyz.negate();
return *this;
}
template <typename T>
auto quat_t<T>::negated() const -> quat_t
{
return {
-xyz, -w
};
}
template <typename T>
auto quat_t<T>::negate() -> quat_t&
{
invert();
w = -w;
return *this;
}
template <typename T>
auto quat_t<T>::product(const quat_t& other) const -> quat_t
{
T wt, w1, w2;
vec3 temp_xyz;
w1 = w;
w2 = other.w;
wt = w1 * w2 - xyz.dot_product(other.xyz);
temp_xyz = other.xyz * w1;
temp_xyz += xyz * w2;
temp_xyz += other.xyz.cross_product(xyz);
return {
temp_xyz, wt
};
}
template <typename T>
auto quat_t<T>::multiply(const quat_t& other) -> quat_t&
{
T w1, w2;
vec3 temp_xyz;
w1 = w;
w2 = other.w;
w = w1 * w2 - xyz.dot_product(other.xyz);
temp_xyz = other.xyz * w1;
temp_xyz += xyz * w2;
temp_xyz += other.xyz.cross_product(xyz);
xyz = temp_xyz;
return *this;
}
template <typename T>
auto quat_t<T>::normalized() const -> quat_t
{
T sqrlen = xyz.length() + w * w;
if (sqrlen != 0)
sqrlen = T(1) / std::sqrt(sqrlen);
return {
xyz * sqrlen,
w * sqrlen
};
}
template <typename T>
auto quat_t<T>::normalize() -> quat_t&
{
T sqrlen = xyz.length() + w * w;
if (sqrlen != 0)
sqrlen = T(1) / std::sqrt(sqrlen);
xyz *= sqrlen;
w *= sqrlen;
return *this;
}
template <typename T>
auto quat_t<T>::difference(const quat_t &other) const -> quat_t
{
return {
xyz - other.xyz,
w - other.w
};
}
template <typename T>
auto quat_t<T>::subtract(const quat_t &other) -> quat_t&
{
xyz -= other.xyz;
w -= other.w;
return *this;
}
template <typename T>
auto quat_t<T>::sum(const quat_t &other) const -> quat_t
{
return {
xyz + other.xyz,
w + other.w
};
}
template <typename T>
auto quat_t<T>::add(const quat_t &other) -> quat_t&
{
xyz += other.xyz;
w += other.w;
return *this;
}
template <typename T>
auto quat_t<T>::scaled(T scalar) const -> quat_t
{
return {
xyz * scalar,
w * scalar
};
}
template <typename T>
auto quat_t<T>::scaled(const quat_t &other) const -> quat_t
{
return {
xyz * other.xyz,
w * other.w
};
}
template <typename T>
auto quat_t<T>::scale(T scalar) -> quat_t&
{
xyz *= scalar;
w *= scalar;
return *this;
}
template <typename T>
auto quat_t<T>::scale(const quat_t &other) -> quat_t&
{
xyz *= other.xyz;
w *= other.w;
return *this;
}
template <typename T>
auto quat_t<T>::dot_product(const quat_t &other) const -> T
{
return xyz.dot_product(other.xyz) + w * other.w;
}
template <typename T>
auto quat_t<T>::from_angle_axis(T angle, const vec3 &axis) -> quat_t
{
vec3 axis_n = axis.normalized();
T s;
angle *= S_DEG2RAD * 0.5;
s = std::sin(angle);
return {
axis_n * s,
std::cos(angle)
};
}
template <typename T>
auto quat_t<T>::from_mat4(const mat4_t<T> &mat) -> quat_t
{
quat_t out;
T r;
const T trace = mat.m00 + mat.m11 + mat.m22;
const T *m = (T *)m;
const T m01 = mat.m01, m02 = mat.m02, m10 = mat.m10,
m12 = mat.m12, m20 = mat.m20, m21 = mat.m21;
if (trace > 0) {
r = std::sqrt(trace + 1);
out.w = r * 0.5;
r = 0.5 / r;
out.xyz = {
(m12 - m21) * r,
(m20 - m02) * r,
(m01 - m10) * r
};
} else {
int index = 0;
if (mat.m11 > mat.m00) {
index = 1;
}
if (mat.m22 > (index ? mat.m11 : mat.m00)) {
index = 2;
}
switch (index) {
default:
case 0:
r = out.xyz.x = std::sqrt(mat.m00 - (mat.m11 + mat.m22) + 1) * 0.5;
if (r != 0) r = 0.5 / r;
out.xyz.y = (m10 + m01) * r;
out.xyz.z = (m20 + m02) * r;
out.w = (m12 - m21) * r;
break;
case 1:
r = out.xyz.y = std::sqrt(mat.m11 - (mat.m22 + mat.m00) + 1) * 0.5;
if (r != 0) r = 0.5 / r;
out.xyz.x = (m10 + m01) * r;
out.xyz.z = (m12 + m21) * r;
out.w = (m20 - m02) * r;
break;
case 2:
r = out.xyz.z = std::sqrt(mat.m11 - (mat.m00 + mat.m11) + 1) * 0.5;
if (r != 0) r = 0.5 / r;
out.xyz.x = (m20 + m02) * r;
out.xyz.y = (m21 + m12) * r;
out.w = (m01 - m10) * r;
break;
}
}
return out;
}
template <typename T>
auto quat_t<T>::from_mat3(const mat3_t<T> &mat) -> quat_t
{
quat_t out;
T r;
const T trace = mat.r.x + mat.s.y + mat.t.z;
const T *m = (T *)m;
const T m01 = mat.s.x, m02 = mat.t.x, m10 = mat.r.y,
m12 = mat.t.y, m20 = mat.r.z, m21 = mat.s.z;
if (trace > 0) {
r = std::sqrt(trace + 1);
out.w = r * 0.5;
r = 0.5 / r;
out.xyz = {
(m12 - m21) * r,
(m20 - m02) * r,
(m01 - m10) * r
};
} else {
int index = 0;
if (mat.s.y > mat.r.x) {
index = 1;
}
if (mat.t.z > (index ? mat.s.y : mat.r.x)) {
index = 2;
}
switch (index) {
default:
case 0:
r = out.xyz.x = std::sqrt(mat.r.x - (mat.s.y + mat.t.z) + 1) * 0.5;
if (r != 0) r = 0.5 / r;
out.xyz.y = (m10 + m01) * r;
out.xyz.z = (m20 + m02) * r;
out.w = (m12 - m21) * r;
break;
case 1:
r = out.xyz.y = std::sqrt(mat.s.y - (mat.t.z + mat.r.x) + 1) * 0.5;
if (r != 0) r = 0.5 / r;
out.xyz.x = (m10 + m01) * r;
out.xyz.z = (m12 + m21) * r;
out.w = (m20 - m02) * r;
break;
case 2:
r = out.xyz.z = std::sqrt(mat.s.y - (mat.r.x + mat.s.y) + 1) * 0.5;
if (r != 0) r = 0.5 / r;
out.xyz.x = (m20 + m02) * r;
out.xyz.y = (m21 + m12) * r;
out.w = (m01 - m10) * r;
break;
}
}
return out;
}
template <typename T>
auto quat_t<T>::slerp(const quat_t &to, T delta) const -> quat_t
{
T dot, scale0, scale1, angle, inv_sin;
quat_t dquat = to;
if (delta < 0 || is_zero(delta)) {
return *this;
} else if (delta >= 1) {
return to;
}
dot = dot_product(to);
if (dot < 0) {
dot = -dot;
dquat.negate();
}
if (dot > T(0.9999)) {
return lerp(to, delta);
} else {
angle = std::acos(dot);
inv_sin = T(1) / std::sin(angle);
scale0 = std::sin((T(1) - delta) * angle) * inv_sin;
scale1 = std::sin(delta * angle) * inv_sin;
}
return dquat.scale(scale1).add(scaled(scale0));
}
template <typename T>
auto quat_t<T>::lerp(const quat_t &to, T delta) const -> quat_t
{
if (delta < 0 || is_zero(delta)) {
return *this;
} else if (delta >= 1) {
return to;
}
quat_t dquat = to;
T scale1 = clamp_value(delta, 0, 1);
T scale0 = T(1) - delta;
return dquat.scale(scale1).add(scaled(scale0)).normalize();
}
template <typename T>
auto quat_t<T>::operator *= (const quat_t &other) -> quat_t&
{
return multiply(other);
}
template <typename T>
auto quat_t<T>::operator *= (T scalar) -> quat_t&
{
return scale(scalar);
}
template <typename T>
auto quat_t<T>::operator += (const quat_t &other) -> quat_t&
{
return add(other);
}
template <typename T>
auto quat_t<T>::operator -= (const quat_t &other) -> quat_t&
{
return subtract(other);
}
template <typename T>
auto quat_t<T>::operator - () const -> quat_t
{
return negated();
}
template <typename T>
auto quat_t<T>::operator ~ () const -> quat_t
{
return inverse();
}
template <typename T>
auto quat_t<T>::operator[] (int index) -> T&
{
static_assert(std::is_pod<quat_t>::value, "quaternion must be POD to use subscript operator");
if (index < 0 || index > 15)
throw std::out_of_range("attempt to access out of range element");
return (&xyz.x)[index];
}
template <typename T>
auto quat_t<T>::operator[] (int index) const -> T
{
static_assert(std::is_pod<quat_t>::value, "quaternion must be POD to use subscript operator");
if (index < 0 || index > 15)
throw std::out_of_range("attempt to access out of range element");
return (&xyz.x)[index];
}
template <typename T>
quat_t<T>::operator T* ()
{
static_assert(std::is_pod<quat_t>::value, "quaternion must be POD to cast to T pointer");
return &xyz.x;
}
template <typename T>
quat_t<T>::operator const T* () const
{
static_assert(std::is_pod<quat_t>::value, "quaternion must be POD to cast to T pointer");
return &xyz.x;
}
template <typename T>
quat_t<T>::operator mat3_t<T> () const
{
return mat3_t<T>::from_quat(*this);
}
template <typename T>
quat_t<T>::operator mat4_t<T> () const
{
return mat4_t<T>::from_quat(*this);
}
template <typename T>
template <typename Q>
quat_t<T>::operator quat_t<Q> () const
{
return {
static_cast<vec3_t<Q> >(xyz),
static_cast<Q>(w)
};
}
template <typename T>
auto operator << (std::ostream &out, const quat_t<T> &in) -> std::ostream&
{
return out << "{x:" << in.xyz.x << ", y:" << in.xyz.y << ", z:" << in.xyz.z << ", w:" << in.w << "}";
}
template <typename T, typename Q>
quat_t<T> operator * (const quat_t<T> &lhs, const quat_t<Q> &rhs)
{
return lhs.product(rhs);
}
template <typename T, typename Q>
quat_t<T> operator * (const quat_t<T> &lhs, Q rhs)
{
return lhs.scaled(rhs);
}
template <typename T, typename Q>
quat_t<T> operator + (const quat_t<T> &lhs, const quat_t<Q> &rhs)
{
return lhs.sum(rhs);
}
template <typename T, typename Q>
quat_t<T> operator - (const quat_t<T> &lhs, const quat_t<Q> &rhs)
{
return lhs.difference(rhs);
}
template <typename T, typename Q>
T operator % (const quat_t<T> &lhs, const quat_t<Q> &rhs)
{
return lhs.dot_product(rhs);
}
template <typename T, typename Q>
bool operator == (const quat_t<T> &lhs, const quat_t<Q> &rhs)
{
return
is_zero(lhs.xyz.x - rhs.xyz.x) &&
is_zero(lhs.xyz.y - rhs.xyz.y) &&
is_zero(lhs.xyz.z - rhs.xyz.z) &&
is_zero(lhs.w - rhs.w);
}
template <typename T, typename Q>
bool operator != (const quat_t<T> &lhs, const quat_t<Q> &rhs)
{
return !(lhs == rhs);
}
template <typename T>
const vec3_t<T> vec3_t<T>::pos_X = { 1, 0, 0 };
template <typename T>
const vec3_t<T> vec3_t<T>::pos_Y = { 0, 1, 0 };
template <typename T>
const vec3_t<T> vec3_t<T>::pos_Z = { 0, 0, 1 };
template <typename T>
const vec3_t<T> vec3_t<T>::neg_X = { -1, 0, 0 };
template <typename T>
const vec3_t<T> vec3_t<T>::neg_Y = { 0, -1, 0 };
template <typename T>
const vec3_t<T> vec3_t<T>::neg_Z = { 0, 0, -1 };
template <typename T>
const vec3_t<T> vec3_t<T>::zero = { 0, 0, 0 };
template <typename T>
const vec3_t<T> vec3_t<T>::one = { 1, 1, 1 };
template <typename T>
auto vec3_t<T>::make(value_type x, value_type y, value_type z) -> vec3_t
{
return { x, y, z };
}
template <typename T>
auto vec3_t<T>::normalize() -> vec3_t&
{
value_type one_over_mag = magnitude();
if (one_over_mag != 0) {
one_over_mag = value_type(1) / one_over_mag;
}
x *= one_over_mag;
y *= one_over_mag;
z *= one_over_mag;
return *this;
}
template <typename T>
auto vec3_t<T>::normalized() const -> vec3_t
{
value_type one_over_mag = magnitude();
if (one_over_mag != 0) {
one_over_mag = value_type(1) / one_over_mag;
}
return {
x * one_over_mag,
y * one_over_mag,
z * one_over_mag
};
}
template <typename T>
auto vec3_t<T>::magnitude() const -> value_type
{
const value_type sqrlen = length();
return sqrlen != 0
? static_cast<value_type>(std::sqrt(sqrlen))
: 0;
}
template <typename T>
auto vec3_t<T>::length() const -> value_type
{
return x * x + y * y + z * z;
}
template <typename T>
auto vec3_t<T>::difference(const vec3_t &other) const -> vec3_t
{
return {
x - other.x,
y - other.y,
z - other.z
};
}
template <typename T>
auto vec3_t<T>::subtract(const vec3_t &other) -> vec3_t&
{
x -= other.x;
y -= other.y;
z -= other.z;
return *this;
}
template <typename T>
auto vec3_t<T>::sum(const vec3_t &other) const -> vec3_t
{
return {
x + other.x,
y + other.y,
z + other.z
};
}
template <typename T>
auto vec3_t<T>::add(const vec3_t &other) -> vec3_t&
{
x += other.x;
y += other.y;
z += other.z;
return *this;
}
template <typename T>
auto vec3_t<T>::scaled(value_type scalar) const -> vec3_t
{
return {
x * scalar,
y * scalar,
z * scalar
};
}
template <typename T>
auto vec3_t<T>::scaled(const vec3_t &other) const -> vec3_t
{
return {
x * other.x,
y * other.y,
z * other.z
};
}
template <typename T>
auto vec3_t<T>::scale(value_type scalar) -> vec3_t&
{
x *= scalar;
y *= scalar;
z *= scalar;
return *this;
}
template <typename T>
auto vec3_t<T>::scale(const vec3_t &other) -> vec3_t&
{
x *= other.x;
y *= other.y;
z *= other.z;
return *this;
}
template <typename T>
auto vec3_t<T>::negated() const -> vec3_t
{
return {
-x, -y, -z
};
}
template <typename T>
auto vec3_t<T>::negate() -> vec3_t&
{
x = -x;
y = -y;
z = -z;
return *this;
}
template <typename T>
auto vec3_t<T>::inverse() const -> vec3_t
{
return {
(x != 0 ? value_type(1) / x : x),
(y != 0 ? value_type(1) / y : y),
(z != 0 ? value_type(1) / z : z)
};
}
template <typename T>
auto vec3_t<T>::invert() -> vec3_t&
{
if (x != 0) {
x = value_type(1) / x;
}
if (y != 0) {
y = value_type(1) / y;
}
if (z != 0) {
z = value_type(1) / z;
}
return *this;
}
template <typename T>
auto vec3_t<T>::cross_product(const vec3_t &other) const -> vec3_t
{
return {
y * other.z - z * other.y,
z * other.x - x * other.z,
x * other.y - y * other.x
};
}
template <typename T>
auto vec3_t<T>::dot_product(const vec3_t &other) const -> value_type
{
return x * other.x + y * other.y + z * other.z;
}
template <typename T>
auto vec3_t<T>::operator += (const vec3_t &other) -> vec3_t&
{
return add(other);
}
template <typename T>
auto vec3_t<T>::operator -= (const vec3_t &other) -> vec3_t&
{
return subtract(other);
}
template <typename T>
auto vec3_t<T>::operator *= (value_type scalar) -> vec3_t&
{
return scale(scalar);
}
template <typename T>
auto vec3_t<T>::operator *= (const vec3_t &other) -> vec3_t&
{
return scale(other);
}
template <typename T>
auto vec3_t<T>::operator /= (value_type scalar) -> vec3_t&
{
return scale(value_type(1) / scalar);
}
template <typename T>
auto vec3_t<T>::operator /= (const vec3_t &other) -> vec3_t&
{
return scale(other.inverse());
}
template <typename T>
auto vec3_t<T>::operator - () const -> vec3_t
{
return negated();
}
template <typename T>
auto vec3_t<T>::operator ~ () const -> vec3_t
{
return inverse();
}
template <typename T>
auto vec3_t<T>::operator[] (int index) -> value_type&
{
static_assert(std::is_pod<vec3_t>::value, "vec3 must be POD to use subscript operator");
if (index < 0 || index > 2)
throw std::out_of_range("attempt to access out of range element");
return (&x)[index];
}
template <typename T>
auto vec3_t<T>::operator[] (int index) const -> value_type
{
static_assert(std::is_pod<vec3_t>::value, "vec3 must be POD to use subscript operator");
if (index < 0 || index > 2)
throw std::out_of_range("attempt to access out of range element");
return (&x)[index];
}
template <typename T>
vec3_t<T>::operator value_type* ()
{
static_assert(std::is_pod<vec3_t>::value, "vec3 must be POD to cast to value_type pointer");
return &x;
}
template <typename T>
vec3_t<T>::operator const value_type* () const
{
static_assert(std::is_pod<vec3_t>::value, "vec3 must be POD to cast to value_type pointer");
return &x;
}
template <typename T>
template <typename Q>
vec3_t<T>::operator vec3_t<Q> () const
{
return {
static_cast<Q>(x),
static_cast<Q>(y),
static_cast<Q>(z)
};
}
template <typename T>
std::ostream &operator << (std::ostream &out, const vec3_t<T> &in)
{
return out << "{x:" << in.x << ", y:" << in.y << ", z:" << in.z << "}";
}
template <typename T, typename Q>
vec3_t<T> operator - (const vec3_t<T> &lhs, const vec3_t<Q> &rhs)
{
return lhs.difference(rhs);
}
template <typename T, typename Q>
vec3_t<T> operator + (const vec3_t<T> &lhs, const vec3_t<Q> &rhs)
{
return lhs.sum(rhs);
}
template <typename T, typename Q>
vec3_t<T> operator * (const vec3_t<T> &lhs, const vec3_t<Q> &rhs)
{
return lhs.scaled(rhs);
}
template <typename T, typename Q>
vec3_t<T> operator * (const vec3_t<T> &lhs, Q rhs)
{
return lhs.scaled(static_cast<T>(rhs));
}
template <typename T, typename Q>
vec3_t<T> operator / (const vec3_t<T> &lhs, const vec3_t<Q> &rhs)
{
return lhs.scaled(rhs.inverse());
}
template <typename T, typename Q>
vec3_t<T> operator / (const vec3_t<T> &lhs, Q rhs)
{
return lhs.scaled(T(1) / static_cast<T>(rhs));
}
template <typename T, typename Q>
T operator % (const vec3_t<T> &lhs, const vec3_t<Q> &rhs)
{
return lhs.dot_product(rhs);
}
template <typename T, typename Q>
bool operator == (const vec3_t<T> &lhs, const vec3_t<Q> &rhs)
{
return
is_zero(lhs.x - rhs.x) &&
is_zero(lhs.y - rhs.y) &&
is_zero(lhs.z - rhs.z);;
}
template <typename T, typename Q>
bool operator != (const vec3_t<T> &lhs, const vec3_t<Q> &rhs)
{
return !(lhs == rhs);
}
template <typename T>
const vec4_t<T> vec4_t<T>::pos_X = { 1, 0, 0, 1 };
template <typename T>
const vec4_t<T> vec4_t<T>::pos_Y = { 0, 1, 0, 1 };
template <typename T>
const vec4_t<T> vec4_t<T>::pos_Z = { 0, 0, 1, 1 };
template <typename T>
const vec4_t<T> vec4_t<T>::neg_X = { -1, 0, 0, 1 };
template <typename T>
const vec4_t<T> vec4_t<T>::neg_Y = { 0, -1, 0, 1 };
template <typename T>
const vec4_t<T> vec4_t<T>::neg_Z = { 0, 0, -1, 1 };
template <typename T>
const vec4_t<T> vec4_t<T>::zero = { 0, 0, 0, 0 };
template <typename T>
const vec4_t<T> vec4_t<T>::one = { 1, 1, 1, 1 };
template <typename T>
auto vec4_t<T>::make(value_type x, value_type y, value_type z, value_type w) -> vec4_t
{
return { x, y, z, w };
}
template <typename T>
auto vec4_t<T>::normalize() -> vec4_t&
{
value_type one_over_mag = magnitude();
if (one_over_mag != 0) {
one_over_mag = value_type(1) / one_over_mag;
}
x *= one_over_mag;
y *= one_over_mag;
z *= one_over_mag;
w *= one_over_mag;
return *this;
}
template <typename T>
auto vec4_t<T>::normalized() const -> vec4_t
{
value_type one_over_mag = magnitude();
if (one_over_mag != 0) {
one_over_mag = value_type(1) / one_over_mag;
}
return {
x * one_over_mag,
y * one_over_mag,
z * one_over_mag,
w * one_over_mag
};
}
template <typename T>
auto vec4_t<T>::magnitude() const -> value_type
{
const value_type sqrlen = length();
return sqrlen != 0
? static_cast<value_type>(std::sqrt(sqrlen))
: 0;
}
template <typename T>
auto vec4_t<T>::length() const -> value_type
{
return x * x + y * y + z * z + w * w;
}
template <typename T>
auto vec4_t<T>::difference(const vec4_t &other) const -> vec4_t
{
return {
x - other.x,
y - other.y,
z - other.z,
w - other.w
};
}
template <typename T>
auto vec4_t<T>::subtract(const vec4_t &other) -> vec4_t&
{
x -= other.x;
y -= other.y;
z -= other.z;
w -= other.w;
return *this;
}
template <typename T>
auto vec4_t<T>::sum(const vec4_t &other) const -> vec4_t
{
return {
x + other.x,
y + other.y,
z + other.z,
w + other.w
};
}
template <typename T>
auto vec4_t<T>::add(const vec4_t &other) -> vec4_t&
{
x += other.x;
y += other.y;
z += other.z;
w += other.w;
return *this;
}
template <typename T>
auto vec4_t<T>::scaled(value_type scalar) const -> vec4_t
{
return {
x * scalar,
y * scalar,
z * scalar,
w * scalar
};
}
template <typename T>
auto vec4_t<T>::scaled(const vec4_t &other) const -> vec4_t
{
return {
x * other.x,
y * other.y,
z * other.z,
w * other.w
};
}
template <typename T>
auto vec4_t<T>::scale(value_type scalar) -> vec4_t&
{
x *= scalar;
y *= scalar;
z *= scalar;
w *= scalar;
return *this;
}
template <typename T>
auto vec4_t<T>::scale(const vec4_t &other) -> vec4_t&
{
x *= other.x;
y *= other.y;
z *= other.z;
w *= other.w;
return *this;
}
template <typename T>
auto vec4_t<T>::negated() const -> vec4_t
{
return {
-x, -y, -z, -w
};
}
template <typename T>
auto vec4_t<T>::negate() -> vec4_t&
{
x = -x;
y = -y;
z = -z;
w = -w;
return *this;
}
template <typename T>
auto vec4_t<T>::inverse() const -> vec4_t
{
return {
(x != 0 ? value_type(1) / x : x),
(y != 0 ? value_type(1) / y : y),
(z != 0 ? value_type(1) / z : z),
(w != 0 ? value_type(1) / w : w)
};
}
template <typename T>
auto vec4_t<T>::invert() -> vec4_t&
{
if (x != 0) {
x = value_type(1) / x;
}
if (y != 0) {
y = value_type(1) / y;
}
if (z != 0) {
z = value_type(1) / z;
}
if (w != 0) {
w = value_type(1) / w;
}
return *this;
}
template <typename T>
auto vec4_t<T>::dot_product(const vec4_t &other) const -> value_type
{
return x * other.x + y * other.y + z * other.z + w * other.w;
}
template <typename T>
auto vec4_t<T>::operator += (const vec4_t &other) -> vec4_t&
{
return add(other);
}
template <typename T>
auto vec4_t<T>::operator -= (const vec4_t &other) -> vec4_t&
{
return subtract(other);
}
template <typename T>
auto vec4_t<T>::operator *= (value_type scalar) -> vec4_t&
{
return scale(scalar);
}
template <typename T>
auto vec4_t<T>::operator *= (const vec4_t &other) -> vec4_t&
{
return scale(other);
}
template <typename T>
auto vec4_t<T>::operator /= (value_type scalar) -> vec4_t&
{
return scale(value_type(1) / scalar);
}
template <typename T>
auto vec4_t<T>::operator /= (const vec4_t &other) -> vec4_t&
{
return scale(other.inverse());
}
template <typename T>
auto vec4_t<T>::operator - () const -> vec4_t
{
return negated();
}
template <typename T>
auto vec4_t<T>::operator ~ () const -> vec4_t
{
return inverse();
}
template <typename T>
auto vec4_t<T>::operator[] (int index) -> value_type&
{
static_assert(std::is_pod<vec4_t<T>>::value, "vec4 must be POD to use subscript operator");
if (index < 0 || index > 3)
throw std::out_of_range("attempt to access out of range element");
return (&x)[index];
}
template <typename T>
auto vec4_t<T>::operator[] (int index) const -> value_type
{
static_assert(std::is_pod<vec4_t<T>>::value, "vec4 must be POD to use subscript operator");
if (index < 0 || index > 3)
throw std::out_of_range("attempt to access out of range element");
return (&x)[index];
}
template <typename T>
vec4_t<T>::operator value_type* ()
{
static_assert(std::is_pod<vec4_t>::value, "vec4 must be POD to cast to value_type pointer");
return &x;
}
template <typename T>
vec4_t<T>::operator const value_type* () const
{
static_assert(std::is_pod<vec4_t>::value, "vec4 must be POD to cast to value_type pointer");
return &x;
}
template <typename T>
template <typename Q>
vec4_t<T>::operator vec4_t<Q> () const
{
return {
static_cast<Q>(x),
static_cast<Q>(y),
static_cast<Q>(z),
static_cast<Q>(w)
};
}
template <typename T>
std::ostream &operator << (std::ostream &out, const vec4_t<T> &in)
{
return out << "{x:" << in.x << ", y:" << in.y << ", z:" << in.z << ", w:" << in.w << "}";
}
template <typename T, typename Q>
vec4_t<T> operator - (const vec4_t<T> &lhs, const vec4_t<Q> &rhs)
{
return lhs.difference(rhs);
}
template <typename T, typename Q>
vec4_t<T> operator + (const vec4_t<T> &lhs, const vec4_t<Q> &rhs)
{
return lhs.sum(rhs);
}
template <typename T, typename Q>
vec4_t<T> operator * (const vec4_t<T> &lhs, const vec4_t<Q> &rhs)
{
return lhs.scaled(rhs);
}
template <typename T, typename Q>
vec4_t<T> operator * (const vec4_t<T> &lhs, Q rhs)
{
return lhs.scaled(static_cast<T>(rhs));
}
template <typename T, typename Q>
vec4_t<T> operator / (const vec4_t<T> &lhs, const vec4_t<Q> &rhs)
{
return lhs.scaled(rhs.inverse());
}
template <typename T, typename Q>
vec4_t<T> operator / (const vec4_t<T> &lhs, Q rhs)
{
return lhs.scaled(T(1) / static_cast<T>(rhs));
}
template <typename T, typename Q>
T operator % (const vec4_t<T> &lhs, const vec4_t<Q> &rhs)
{
return lhs.dot_product(rhs);
}
template <typename T, typename Q>
bool operator == (const vec4_t<T> &lhs, const vec4_t<Q> &rhs)
{
return
is_zero(lhs.x - rhs.x) &&
is_zero(lhs.y - rhs.y) &&
is_zero(lhs.z - rhs.z) &&
is_zero(lhs.w - rhs.w);
}
template <typename T, typename Q>
bool operator != (const vec4_t<T> &lhs, const vec4_t<Q> &rhs)
{
return !(lhs == rhs);
}
#endif /* end __SNOW_COMMON__COMMATH_HH__ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment