-
-
Save nilium/1f5f4b20a82bd7e484b2 to your computer and use it in GitHub Desktop.
Combined maths headers from libsnow-common
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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