// linalg.h - 2.2-beta - Single-header public domain linear algebra library // // The intent of this library is to provide the bulk of the functionality // you need to write programs that frequently use small, fixed-size vectors // and matrices, in domains such as computational geometry or computer // graphics. It strives for terse, readable source code. // // The original author of this software is Sterling Orsten, and its permanent // home is . If you find this software // useful, an acknowledgement in your source text and/or product documentation // is appreciated, but not required. // // The author acknowledges significant insights and contributions by: // Stan Melax // Dimitri Diakopoulos // // Some features are deprecated. Define LINALG_FORWARD_COMPATIBLE to remove them. // This is free and unencumbered software released into the public domain. // // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. // // In jurisdictions that recognize copyright laws, the author or authors // of this software dedicate any and all copyright interest in the // software to the public domain. We make this dedication for the benefit // of the public at large and to the detriment of our heirs and // successors. We intend this dedication to be an overt act of // relinquishment in perpetuity of all present and future rights to this // software under copyright law. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // For more information, please refer to #pragma once #ifndef LINALG_H #define LINALG_H #include // For various unary math functions, such as std::sqrt #include // To resolve std::abs ambiguity on clang #include // For implementing namespace linalg::aliases #include // For std::array #include // For forward definitions of std::ostream #include // For std::enable_if, std::is_same, std::declval #include // For std::hash declaration // In Visual Studio 2015, `constexpr` applied to a member function implies `const`, which causes ambiguous overload resolution #if _MSC_VER <= 1900 #define LINALG_CONSTEXPR14 #else #define LINALG_CONSTEXPR14 constexpr #endif namespace linalg { // Small, fixed-length vector type, consisting of exactly M elements of type T, and presumed to be a column-vector unless otherwise noted. template struct vec; // Small, fixed-size matrix type, consisting of exactly M rows and N columns of type T, stored in column-major order. template struct mat; // Specialize converter with a function application operator that converts type U to type T to enable implicit conversions template struct converter {}; namespace detail { template using conv_t = typename std::enable_if::value, decltype(converter{}(std::declval()))>::type; // Trait for retrieving scalar type of any linear algebra object template struct scalar_type {}; template struct scalar_type> { using type = T; }; template struct scalar_type> { using type = T; }; // Type returned by the compare(...) function which supports all six comparison operators against 0 template struct ord { T a,b; }; template constexpr bool operator == (const ord & o, std::nullptr_t) { return o.a == o.b; } template constexpr bool operator != (const ord & o, std::nullptr_t) { return !(o.a == o.b); } template constexpr bool operator < (const ord & o, std::nullptr_t) { return o.a < o.b; } template constexpr bool operator > (const ord & o, std::nullptr_t) { return o.b < o.a; } template constexpr bool operator <= (const ord & o, std::nullptr_t) { return !(o.b < o.a); } template constexpr bool operator >= (const ord & o, std::nullptr_t) { return !(o.a < o.b); } // Patterns which can be used with the compare(...) function template struct any_compare {}; template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return ord{a.x,b.x}; } }; template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : ord{a.y,b.y}; } }; template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : !(a.y==b.y) ? ord{a.y,b.y} : ord{a.z,b.z}; } }; template struct any_compare,vec> { using type=ord; constexpr ord operator() (const vec & a, const vec & b) const { return !(a.x==b.x) ? ord{a.x,b.x} : !(a.y==b.y) ? ord{a.y,b.y} : !(a.z==b.z) ? ord{a.z,b.z} : ord{a.w,b.w}; } }; template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return compare(a.x,b.x); } }; template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : compare(a.y,b.y); } }; template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : a.y!=b.y ? compare(a.y,b.y) : compare(a.z,b.z); } }; template struct any_compare,mat> { using type=ord; constexpr ord operator() (const mat & a, const mat & b) const { return a.x!=b.x ? compare(a.x,b.x) : a.y!=b.y ? compare(a.y,b.y) : a.z!=b.z ? compare(a.z,b.z) : compare(a.w,b.w); } }; // Helper for compile-time index-based access to members of vector and matrix types template struct getter; template<> struct getter<0> { template constexpr auto operator() (A & a) const -> decltype(a.x) { return a.x; } }; template<> struct getter<1> { template constexpr auto operator() (A & a) const -> decltype(a.y) { return a.y; } }; template<> struct getter<2> { template constexpr auto operator() (A & a) const -> decltype(a.z) { return a.z; } }; template<> struct getter<3> { template constexpr auto operator() (A & a) const -> decltype(a.w) { return a.w; } }; // Stand-in for std::integer_sequence/std::make_integer_sequence template struct seq {}; template struct make_seq_impl; template struct make_seq_impl { using type=seq<>; }; template struct make_seq_impl { using type=seq; }; template struct make_seq_impl { using type=seq; }; template struct make_seq_impl { using type=seq; }; template struct make_seq_impl { using type=seq; }; template using make_seq = typename make_seq_impl::type; template vec constexpr swizzle(const vec & v, seq i) { return {getter{}(v)...}; } template mat constexpr swizzle(const mat & m, seq i, seq j) { return {swizzle(getter{}(m),i)...}; } // SFINAE helpers to determine result of function application template using ret_t = decltype(std::declval()(std::declval()...)); // SFINAE helper which is defined if all provided types are scalars struct empty {}; template struct scalars; template<> struct scalars<> { using type=void; }; template struct scalars : std::conditional::value, scalars, empty>::type {}; template using scalars_t = typename scalars::type; // Helpers which indicate how apply(F, ...) should be called for various arguments template struct apply {}; // Patterns which contain only vectors or scalars template struct apply, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a ) { return {f(getter{}(a) )...}; } }; template struct apply, vec, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b ) { return {f(getter{}(a), getter{}(b) )...}; } }; template struct apply, vec, B > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b ) { return {f(getter{}(a), b )...}; } }; template struct apply, A, vec > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b ) { return {f(a, getter{}(b) )...}; } }; template struct apply, vec, vec, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b, const vec & c) { return {f(getter{}(a), getter{}(b), getter{}(c))...}; } }; template struct apply, vec, vec, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, const vec & b, C c) { return {f(getter{}(a), getter{}(b), c )...}; } }; template struct apply, vec, B, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b, const vec & c) { return {f(getter{}(a), b, getter{}(c))...}; } }; template struct apply, vec, B, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, const vec & a, B b, C c) { return {f(getter{}(a), b, c )...}; } }; template struct apply, A, vec, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b, const vec & c) { return {f(a, getter{}(b), getter{}(c))...}; } }; template struct apply, A, vec, C > { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, const vec & b, C c) { return {f(a, getter{}(b), c )...}; } }; template struct apply, A, B, vec> { using type=vec,M>; enum {size=M, mm=0}; template static constexpr type impl(seq, F f, A a, B b, const vec & c) { return {f(a, b, getter{}(c))...}; } }; template struct apply, mat > { using type=mat,M,N>; enum {size=N, mm=0}; template static constexpr type impl(seq, F f, const mat & a ) { return {apply >::impl(make_seq<0,M>{}, f, getter{}(a) )...}; } }; template struct apply, mat, mat> { using type=mat,M,N>; enum {size=N, mm=1}; template static constexpr type impl(seq, F f, const mat & a, const mat & b) { return {apply, vec>::impl(make_seq<0,M>{}, f, getter{}(a), getter{}(b))...}; } }; template struct apply, mat, B > { using type=mat,M,N>; enum {size=N, mm=0}; template static constexpr type impl(seq, F f, const mat & a, B b) { return {apply, B >::impl(make_seq<0,M>{}, f, getter{}(a), b )...}; } }; template struct apply, A, mat> { using type=mat,M,N>; enum {size=N, mm=0}; template static constexpr type impl(seq, F f, A a, const mat & b) { return {apply>::impl(make_seq<0,M>{}, f, a, getter{}(b))...}; } }; template struct apply, A...> { using type = ret_t; enum {size=0, mm=0}; static constexpr type impl(seq<>, F f, A... a) { return f(a...); } }; // Function objects for selecting between alternatives struct min { template constexpr auto operator() (A a, B b) const -> typename std::remove_reference::type { return a constexpr auto operator() (A a, B b) const -> typename std::remove_reference::type { return a constexpr auto operator() (A a, B b, C c) const -> typename std::remove_reference::type { return a constexpr auto operator() (A a, B b, C c) const -> typename std::remove_reference::type { return a ? b : c; } }; struct lerp { template constexpr auto operator() (A a, B b, C c) const -> decltype(a*(1-c) + b*c) { return a*(1-c) + b*c; } }; // Function objects for applying operators struct op_pos { template constexpr auto operator() (A a) const -> decltype(+a) { return +a; } }; struct op_neg { template constexpr auto operator() (A a) const -> decltype(-a) { return -a; } }; struct op_not { template constexpr auto operator() (A a) const -> decltype(!a) { return !a; } }; struct op_cmp { template constexpr auto operator() (A a) const -> decltype(~(a)) { return ~a; } }; struct op_mul { template constexpr auto operator() (A a, B b) const -> decltype(a * b) { return a * b; } }; struct op_div { template constexpr auto operator() (A a, B b) const -> decltype(a / b) { return a / b; } }; struct op_mod { template constexpr auto operator() (A a, B b) const -> decltype(a % b) { return a % b; } }; struct op_add { template constexpr auto operator() (A a, B b) const -> decltype(a + b) { return a + b; } }; struct op_sub { template constexpr auto operator() (A a, B b) const -> decltype(a - b) { return a - b; } }; struct op_lsh { template constexpr auto operator() (A a, B b) const -> decltype(a << b) { return a << b; } }; struct op_rsh { template constexpr auto operator() (A a, B b) const -> decltype(a >> b) { return a >> b; } }; struct op_lt { template constexpr auto operator() (A a, B b) const -> decltype(a < b) { return a < b; } }; struct op_gt { template constexpr auto operator() (A a, B b) const -> decltype(a > b) { return a > b; } }; struct op_le { template constexpr auto operator() (A a, B b) const -> decltype(a <= b) { return a <= b; } }; struct op_ge { template constexpr auto operator() (A a, B b) const -> decltype(a >= b) { return a >= b; } }; struct op_eq { template constexpr auto operator() (A a, B b) const -> decltype(a == b) { return a == b; } }; struct op_ne { template constexpr auto operator() (A a, B b) const -> decltype(a != b) { return a != b; } }; struct op_int { template constexpr auto operator() (A a, B b) const -> decltype(a & b) { return a & b; } }; struct op_xor { template constexpr auto operator() (A a, B b) const -> decltype(a ^ b) { return a ^ b; } }; struct op_un { template constexpr auto operator() (A a, B b) const -> decltype(a | b) { return a | b; } }; struct op_and { template constexpr auto operator() (A a, B b) const -> decltype(a && b) { return a && b; } }; struct op_or { template constexpr auto operator() (A a, B b) const -> decltype(a || b) { return a || b; } }; // Function objects for applying standard library math functions struct std_abs { template auto operator() (A a) const -> decltype(std::abs (a)) { return std::abs (a); } }; struct std_floor { template auto operator() (A a) const -> decltype(std::floor(a)) { return std::floor(a); } }; struct std_ceil { template auto operator() (A a) const -> decltype(std::ceil (a)) { return std::ceil (a); } }; struct std_exp { template auto operator() (A a) const -> decltype(std::exp (a)) { return std::exp (a); } }; struct std_log { template auto operator() (A a) const -> decltype(std::log (a)) { return std::log (a); } }; struct std_log10 { template auto operator() (A a) const -> decltype(std::log10(a)) { return std::log10(a); } }; struct std_sqrt { template auto operator() (A a) const -> decltype(std::sqrt (a)) { return std::sqrt (a); } }; struct std_sin { template auto operator() (A a) const -> decltype(std::sin (a)) { return std::sin (a); } }; struct std_cos { template auto operator() (A a) const -> decltype(std::cos (a)) { return std::cos (a); } }; struct std_tan { template auto operator() (A a) const -> decltype(std::tan (a)) { return std::tan (a); } }; struct std_asin { template auto operator() (A a) const -> decltype(std::asin (a)) { return std::asin (a); } }; struct std_acos { template auto operator() (A a) const -> decltype(std::acos (a)) { return std::acos (a); } }; struct std_atan { template auto operator() (A a) const -> decltype(std::atan (a)) { return std::atan (a); } }; struct std_sinh { template auto operator() (A a) const -> decltype(std::sinh (a)) { return std::sinh (a); } }; struct std_cosh { template auto operator() (A a) const -> decltype(std::cosh (a)) { return std::cosh (a); } }; struct std_tanh { template auto operator() (A a) const -> decltype(std::tanh (a)) { return std::tanh (a); } }; struct std_round { template auto operator() (A a) const -> decltype(std::round(a)) { return std::round(a); } }; struct std_fmod { template auto operator() (A a, B b) const -> decltype(std::fmod (a, b)) { return std::fmod (a, b); } }; struct std_pow { template auto operator() (A a, B b) const -> decltype(std::pow (a, b)) { return std::pow (a, b); } }; struct std_atan2 { template auto operator() (A a, B b) const -> decltype(std::atan2 (a, b)) { return std::atan2 (a, b); } }; struct std_copysign { template auto operator() (A a, B b) const -> decltype(std::copysign(a, b)) { return std::copysign(a, b); } }; } // Small, fixed-length vector type, consisting of exactly M elements of type T, and presumed to be a column-vector unless otherwise noted template struct vec { T x; constexpr vec() : x() {} constexpr vec(const T & x_) : x(x_) {} // NOTE: vec does NOT have a constructor from pointer, this can conflict with initializing its single element from zero template constexpr explicit vec(const vec & v) : vec(static_cast(v.x)) {} constexpr const T & operator[] (int i) const { return x; } LINALG_CONSTEXPR14 T & operator[] (int i) { return x; } template> constexpr vec(const U & u) : vec(converter{}(u)) {} template> constexpr operator U () const { return converter{}(*this); } }; template struct vec { T x,y; constexpr vec() : x(), y() {} constexpr vec(const T & x_, const T & y_) : x(x_), y(y_) {} constexpr explicit vec(const T & s) : vec(s, s) {} constexpr explicit vec(const T * p) : vec(p[0], p[1]) {} template constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y)) {} constexpr const T & operator[] (int i) const { return i==0?x:y; } LINALG_CONSTEXPR14 T & operator[] (int i) { return i==0?x:y; } template> constexpr vec(const U & u) : vec(converter{}(u)) {} template> constexpr operator U () const { return converter{}(*this); } }; template struct vec { T x,y,z; constexpr vec() : x(), y(), z() {} constexpr vec(const T & x_, const T & y_, const T & z_) : x(x_), y(y_), z(z_) {} constexpr vec(const vec & xy, const T & z_) : vec(xy.x, xy.y, z_) {} constexpr explicit vec(const T & s) : vec(s, s, s) {} constexpr explicit vec(const T * p) : vec(p[0], p[1], p[2]) {} template constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y), static_cast(v.z)) {} constexpr const T & operator[] (int i) const { return i==0?x:i==1?y:z; } LINALG_CONSTEXPR14 T & operator[] (int i) { return i==0?x:i==1?y:z; } constexpr const vec & xy() const { return *reinterpret_cast *>(this); } vec & xy() { return *reinterpret_cast *>(this); } template> constexpr vec(const U & u) : vec(converter{}(u)) {} template> constexpr operator U () const { return converter{}(*this); } }; template struct vec { T x,y,z,w; constexpr vec() : x(), y(), z(), w() {} constexpr vec(const T & x_, const T & y_, const T & z_, const T & w_) : x(x_), y(y_), z(z_), w(w_) {} constexpr vec(const vec & xy, const T & z_, const T & w_) : vec(xy.x, xy.y, z_, w_) {} constexpr vec(const vec & xyz, const T & w_) : vec(xyz.x, xyz.y, xyz.z, w_) {} constexpr explicit vec(const T & s) : vec(s, s, s, s) {} constexpr explicit vec(const T * p) : vec(p[0], p[1], p[2], p[3]) {} template constexpr explicit vec(const vec & v) : vec(static_cast(v.x), static_cast(v.y), static_cast(v.z), static_cast(v.w)) {} constexpr const T & operator[] (int i) const { return i==0?x:i==1?y:i==2?z:w; } LINALG_CONSTEXPR14 T & operator[] (int i) { return i==0?x:i==1?y:i==2?z:w; } constexpr const vec & xy() const { return *reinterpret_cast *>(this); } constexpr const vec & xyz() const { return *reinterpret_cast *>(this); } vec & xy() { return *reinterpret_cast *>(this); } vec & xyz() { return *reinterpret_cast *>(this); } template> constexpr vec(const U & u) : vec(converter{}(u)) {} template> constexpr operator U () const { return converter{}(*this); } }; // Small, fixed-size matrix type, consisting of exactly M rows and N columns of type T, stored in column-major order. template struct mat { typedef vec V; V x; constexpr mat() : x() {} constexpr mat(const V & x_) : x(x_) {} constexpr explicit mat(const T & s) : x(s) {} constexpr explicit mat(const T * p) : x(p+M*0) {} template constexpr explicit mat(const mat & m) : mat(V(m.x)) {} constexpr vec row(int i) const { return {x[i]}; } constexpr const V & operator[] (int j) const { return x; } LINALG_CONSTEXPR14 V & operator[] (int j) { return x; } template> constexpr mat(const U & u) : mat(converter{}(u)) {} template> constexpr operator U () const { return converter{}(*this); } }; template struct mat { typedef vec V; V x,y; constexpr mat() : x(), y() {} constexpr mat(const V & x_, const V & y_) : x(x_), y(y_) {} constexpr explicit mat(const T & s) : x(s), y(s) {} constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1) {} template constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y)) {} constexpr vec row(int i) const { return {x[i], y[i]}; } constexpr const V & operator[] (int j) const { return j==0?x:y; } LINALG_CONSTEXPR14 V & operator[] (int j) { return j==0?x:y; } template> constexpr mat(const U & u) : mat(converter{}(u)) {} template> constexpr operator U () const { return converter{}(*this); } }; template struct mat { typedef vec V; V x,y,z; constexpr mat() : x(), y(), z() {} constexpr mat(const V & x_, const V & y_, const V & z_) : x(x_), y(y_), z(z_) {} constexpr explicit mat(const T & s) : x(s), y(s), z(s) {} constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1), z(p+M*2) {} template constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y), V(m.z)) {} constexpr vec row(int i) const { return {x[i], y[i], z[i]}; } constexpr const V & operator[] (int j) const { return j==0?x:j==1?y:z; } LINALG_CONSTEXPR14 V & operator[] (int j) { return j==0?x:j==1?y:z; } template> constexpr mat(const U & u) : mat(converter{}(u)) {} template> constexpr operator U () const { return converter{}(*this); } }; template struct mat { typedef vec V; V x,y,z,w; constexpr mat() : x(), y(), z(), w() {} constexpr mat(const V & x_, const V & y_, const V & z_, const V & w_) : x(x_), y(y_), z(z_), w(w_) {} constexpr explicit mat(const T & s) : x(s), y(s), z(s), w(s) {} constexpr explicit mat(const T * p) : x(p+M*0), y(p+M*1), z(p+M*2), w(p+M*3) {} template constexpr explicit mat(const mat & m) : mat(V(m.x), V(m.y), V(m.z), V(m.w)) {} constexpr vec row(int i) const { return {x[i], y[i], z[i], w[i]}; } constexpr const V & operator[] (int j) const { return j==0?x:j==1?y:j==2?z:w; } LINALG_CONSTEXPR14 V & operator[] (int j) { return j==0?x:j==1?y:j==2?z:w; } template> constexpr mat(const U & u) : mat(converter{}(u)) {} template> constexpr operator U () const { return converter{}(*this); } }; // Define a type which will convert to the multiplicative identity of any square matrix struct identity_t { constexpr explicit identity_t(int) {} }; template struct converter, identity_t> { constexpr mat operator() (identity_t) const { return {vec{1}}; } }; template struct converter, identity_t> { constexpr mat operator() (identity_t) const { return {{1,0},{0,1}}; } }; template struct converter, identity_t> { constexpr mat operator() (identity_t) const { return {{1,0,0},{0,1,0},{0,0,1}}; } }; template struct converter, identity_t> { constexpr mat operator() (identity_t) const { return {{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}; } }; constexpr identity_t identity {1}; // Produce a scalar by applying f(A,B) -> A to adjacent pairs of elements from a vec/mat in left-to-right/column-major order (matching the associativity of arithmetic and logical operators) template constexpr A fold(F f, A a, const vec & b) { return f(a, b.x); } template constexpr A fold(F f, A a, const vec & b) { return f(f(a, b.x), b.y); } template constexpr A fold(F f, A a, const vec & b) { return f(f(f(a, b.x), b.y), b.z); } template constexpr A fold(F f, A a, const vec & b) { return f(f(f(f(a, b.x), b.y), b.z), b.w); } template constexpr A fold(F f, A a, const mat & b) { return fold(f, a, b.x); } template constexpr A fold(F f, A a, const mat & b) { return fold(f, fold(f, a, b.x), b.y); } template constexpr A fold(F f, A a, const mat & b) { return fold(f, fold(f, fold(f, a, b.x), b.y), b.z); } template constexpr A fold(F f, A a, const mat & b) { return fold(f, fold(f, fold(f, fold(f, a, b.x), b.y), b.z), b.w); } // Type aliases for the result of calling apply(...) with various arguments, can be used with return type SFINAE to constrian overload sets template using apply_t = typename detail::apply::type; template using mm_apply_t = typename std::enable_if::mm, apply_t>::type; template using no_mm_apply_t = typename std::enable_if::mm, apply_t>::type; template using scalar_t = typename detail::scalar_type::type; // Underlying scalar type when performing elementwise operations // apply(f,...) applies the provided function in an elementwise fashion to its arguments, producing an object of the same dimensions template constexpr apply_t apply(F func, const A & ... args) { return detail::apply::impl(detail::make_seq<0,detail::apply::size>{}, func, args...); } // map(a,f) is equivalent to apply(f,a) template constexpr apply_t map(const A & a, F func) { return apply(func, a); } // zip(a,b,f) is equivalent to apply(f,a,b) template constexpr apply_t zip(const A & a, const B & b, F func) { return apply(func, a, b); } // Relational operators are defined to compare the elements of two vectors or matrices lexicographically, in column-major order template constexpr typename detail::any_compare::type compare(const A & a, const B & b) { return detail::any_compare()(a,b); } template constexpr auto operator == (const A & a, const B & b) -> decltype(compare(a,b) == 0) { return compare(a,b) == 0; } template constexpr auto operator != (const A & a, const B & b) -> decltype(compare(a,b) != 0) { return compare(a,b) != 0; } template constexpr auto operator < (const A & a, const B & b) -> decltype(compare(a,b) < 0) { return compare(a,b) < 0; } template constexpr auto operator > (const A & a, const B & b) -> decltype(compare(a,b) > 0) { return compare(a,b) > 0; } template constexpr auto operator <= (const A & a, const B & b) -> decltype(compare(a,b) <= 0) { return compare(a,b) <= 0; } template constexpr auto operator >= (const A & a, const B & b) -> decltype(compare(a,b) >= 0) { return compare(a,b) >= 0; } // Functions for coalescing scalar values template constexpr bool any (const A & a) { return fold(detail::op_or{}, false, a); } template constexpr bool all (const A & a) { return fold(detail::op_and{}, true, a); } template constexpr scalar_t sum (const A & a) { return fold(detail::op_add{}, scalar_t(0), a); } template constexpr scalar_t product(const A & a) { return fold(detail::op_mul{}, scalar_t(1), a); } template constexpr scalar_t minelem(const A & a) { return fold(detail::min{}, a.x, a); } template constexpr scalar_t maxelem(const A & a) { return fold(detail::max{}, a.x, a); } template int argmin(const vec & a) { int j=0; for(int i=1; i int argmax(const vec & a) { int j=0; for(int i=1; i a[j]) j = i; return j; } // Unary operators are defined component-wise for linalg types template constexpr apply_t operator + (const A & a) { return apply(detail::op_pos{}, a); } template constexpr apply_t operator - (const A & a) { return apply(detail::op_neg{}, a); } template constexpr apply_t operator ~ (const A & a) { return apply(detail::op_cmp{}, a); } template constexpr apply_t operator ! (const A & a) { return apply(detail::op_not{}, a); } // Binary operators are defined component-wise for linalg types, EXCEPT for `operator *` template constexpr apply_t operator + (const A & a, const B & b) { return apply(detail::op_add{}, a, b); } template constexpr apply_t operator - (const A & a, const B & b) { return apply(detail::op_sub{}, a, b); } template constexpr apply_t cmul (const A & a, const B & b) { return apply(detail::op_mul{}, a, b); } template constexpr apply_t operator / (const A & a, const B & b) { return apply(detail::op_div{}, a, b); } template constexpr apply_t operator % (const A & a, const B & b) { return apply(detail::op_mod{}, a, b); } template constexpr apply_t operator | (const A & a, const B & b) { return apply(detail::op_un{}, a, b); } template constexpr apply_t operator ^ (const A & a, const B & b) { return apply(detail::op_xor{}, a, b); } template constexpr apply_t operator & (const A & a, const B & b) { return apply(detail::op_int{}, a, b); } template constexpr apply_t operator << (const A & a, const B & b) { return apply(detail::op_lsh{}, a, b); } template constexpr apply_t operator >> (const A & a, const B & b) { return apply(detail::op_rsh{}, a, b); } // Binary `operator *` was originally defined component-wise for all patterns, in a fashion consistent with the other operators. However, // this was one of the most frequent sources of confusion among new users of this library, with the binary `operator *` being used accidentally // by users who INTENDED the semantics of the algebraic matrix product, but RECEIVED the semantics of the Hadamard product. While there is // precedent within the HLSL, Fortran, R, APL, J, and Mathematica programming languages for `operator *` having the semantics of the Hadamard // product between matrices, it is counterintuitive to users of GLSL, Eigen, and many other languages and libraries that chose matrix product // semantics for `operator *`. // // For these reasons, binary `operator *` is now DEPRECATED between pairs of matrices. Users may call `cmul(...)` for component-wise multiplication, // or `mul(...)` for matrix multiplication. Binary `operator *` continues to be available for vector * vector, vector * scalar, matrix * scalar, etc. template constexpr no_mm_apply_t operator * (const A & a, const B & b) { return cmul(a,b); } #ifndef LINALG_FORWARD_COMPATIBLE template [[deprecated("`operator *` between pairs of matrices is deprecated. See the source text for details.")]] constexpr mm_apply_t operator * (const A & a, const B & b) { return cmul(a,b); } #endif // Binary assignment operators a $= b is always defined as though it were explicitly written a = a $ b template constexpr auto operator += (A & a, const B & b) -> decltype(a = a + b) { return a = a + b; } template constexpr auto operator -= (A & a, const B & b) -> decltype(a = a - b) { return a = a - b; } template constexpr auto operator *= (A & a, const B & b) -> decltype(a = a * b) { return a = a * b; } template constexpr auto operator /= (A & a, const B & b) -> decltype(a = a / b) { return a = a / b; } template constexpr auto operator %= (A & a, const B & b) -> decltype(a = a % b) { return a = a % b; } template constexpr auto operator |= (A & a, const B & b) -> decltype(a = a | b) { return a = a | b; } template constexpr auto operator ^= (A & a, const B & b) -> decltype(a = a ^ b) { return a = a ^ b; } template constexpr auto operator &= (A & a, const B & b) -> decltype(a = a & b) { return a = a & b; } template constexpr auto operator <<= (A & a, const B & b) -> decltype(a = a << b) { return a = a << b; } template constexpr auto operator >>= (A & a, const B & b) -> decltype(a = a >> b) { return a = a >> b; } // Swizzles and subobjects template constexpr vec swizzle(const vec & a) { return {detail::getter{}(a)...}; } template constexpr vec subvec (const vec & a) { return detail::swizzle(a, detail::make_seq{}); } template constexpr mat submat (const mat & a) { return detail::swizzle(a, detail::make_seq{}, detail::make_seq{}); } // Component-wise standard library math functions template apply_t abs (const A & a) { return apply(detail::std_abs{}, a); } template apply_t floor(const A & a) { return apply(detail::std_floor{}, a); } template apply_t ceil (const A & a) { return apply(detail::std_ceil{}, a); } template apply_t exp (const A & a) { return apply(detail::std_exp{}, a); } template apply_t log (const A & a) { return apply(detail::std_log{}, a); } template apply_t log10(const A & a) { return apply(detail::std_log10{}, a); } template apply_t sqrt (const A & a) { return apply(detail::std_sqrt{}, a); } template apply_t sin (const A & a) { return apply(detail::std_sin{}, a); } template apply_t cos (const A & a) { return apply(detail::std_cos{}, a); } template apply_t tan (const A & a) { return apply(detail::std_tan{}, a); } template apply_t asin (const A & a) { return apply(detail::std_asin{}, a); } template apply_t acos (const A & a) { return apply(detail::std_acos{}, a); } template apply_t atan (const A & a) { return apply(detail::std_atan{}, a); } template apply_t sinh (const A & a) { return apply(detail::std_sinh{}, a); } template apply_t cosh (const A & a) { return apply(detail::std_cosh{}, a); } template apply_t tanh (const A & a) { return apply(detail::std_tanh{}, a); } template apply_t round(const A & a) { return apply(detail::std_round{}, a); } template apply_t fmod (const A & a, const B & b) { return apply(detail::std_fmod{}, a, b); } template apply_t pow (const A & a, const B & b) { return apply(detail::std_pow{}, a, b); } template apply_t atan2 (const A & a, const B & b) { return apply(detail::std_atan2{}, a, b); } template apply_t copysign(const A & a, const B & b) { return apply(detail::std_copysign{}, a, b); } // Component-wise relational functions on vectors template constexpr apply_t equal (const A & a, const B & b) { return apply(detail::op_eq{}, a, b); } template constexpr apply_t nequal (const A & a, const B & b) { return apply(detail::op_ne{}, a, b); } template constexpr apply_t less (const A & a, const B & b) { return apply(detail::op_lt{}, a, b); } template constexpr apply_t greater(const A & a, const B & b) { return apply(detail::op_gt{}, a, b); } template constexpr apply_t lequal (const A & a, const B & b) { return apply(detail::op_le{}, a, b); } template constexpr apply_t gequal (const A & a, const B & b) { return apply(detail::op_ge{}, a, b); } // Component-wise selection functions on vectors template constexpr apply_t min(const A & a, const B & b) { return apply(detail::min{}, a, b); } template constexpr apply_t max(const A & a, const B & b) { return apply(detail::max{}, a, b); } template constexpr apply_t clamp (const X & x, const L & l, const H & h) { return apply(detail::clamp{}, x, l, h); } template constexpr apply_t select(const P & p, const A & a, const B & b) { return apply(detail::select{}, p, a, b); } template constexpr apply_t lerp (const A & a, const B & b, const T & t) { return apply(detail::lerp{}, a, b, t); } // Support for vector algebra template constexpr T cross (const vec & a, const vec & b) { return a.x*b.y-a.y*b.x; } template constexpr vec cross (T a, const vec & b) { return {-a*b.y, a*b.x}; } template constexpr vec cross (const vec & a, T b) { return {a.y*b, -a.x*b}; } template constexpr vec cross (const vec & a, const vec & b) { return {a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x}; } template constexpr T dot (const vec & a, const vec & b) { return sum(a*b); } template constexpr T length2 (const vec & a) { return dot(a,a); } template T length (const vec & a) { return std::sqrt(length2(a)); } template vec normalize(const vec & a) { return a / length(a); } template constexpr T distance2(const vec & a, const vec & b) { return length2(b-a); } template T distance (const vec & a, const vec & b) { return length(b-a); } template T uangle (const vec & a, const vec & b) { T d=dot(a,b); return d > 1 ? 0 : std::acos(d < -1 ? -1 : d); } template T angle (const vec & a, const vec & b) { return uangle(normalize(a), normalize(b)); } template vec rot (T a, const vec & v) { const T s = std::sin(a), c = std::cos(a); return {v.x*c - v.y*s, v.x*s + v.y*c}; } template vec nlerp (const vec & a, const vec & b, T t) { return normalize(lerp(a,b,t)); } template vec slerp (const vec & a, const vec & b, T t) { T th=uangle(a,b); return th == 0 ? a : a*(std::sin(th*(1-t))/std::sin(th)) + b*(std::sin(th*t)/std::sin(th)); } // Support for quaternion algebra using 4D vectors, representing xi + yj + zk + w template constexpr vec qconj(const vec & q) { return {-q.x,-q.y,-q.z,q.w}; } template vec qinv (const vec & q) { return qconj(q)/length2(q); } template vec qexp (const vec & q) { const auto v = q.xyz(); const auto vv = length(v); return std::exp(q.w) * vec{v * (vv > 0 ? std::sin(vv)/vv : 0), std::cos(vv)}; } template vec qlog (const vec & q) { const auto v = q.xyz(); const auto vv = length(v), qq = length(q); return {v * (vv > 0 ? std::acos(q.w/qq)/vv : 0), std::log(qq)}; } template vec qpow (const vec & q, const T & p) { const auto v = q.xyz(); const auto vv = length(v), qq = length(q), th = std::acos(q.w/qq); return std::pow(qq,p)*vec{v * (vv > 0 ? std::sin(p*th)/vv : 0), std::cos(p*th)}; } template constexpr vec qmul (const vec & a, const vec & b) { return {a.x*b.w+a.w*b.x+a.y*b.z-a.z*b.y, a.y*b.w+a.w*b.y+a.z*b.x-a.x*b.z, a.z*b.w+a.w*b.z+a.x*b.y-a.y*b.x, a.w*b.w-a.x*b.x-a.y*b.y-a.z*b.z}; } template constexpr vec qmul(const vec & a, R... r) { return qmul(a, qmul(r...)); } // Support for 3D spatial rotations using quaternions, via qmul(qmul(q, v), qconj(q)) template constexpr vec qxdir (const vec & q) { return {q.w*q.w+q.x*q.x-q.y*q.y-q.z*q.z, (q.x*q.y+q.z*q.w)*2, (q.z*q.x-q.y*q.w)*2}; } template constexpr vec qydir (const vec & q) { return {(q.x*q.y-q.z*q.w)*2, q.w*q.w-q.x*q.x+q.y*q.y-q.z*q.z, (q.y*q.z+q.x*q.w)*2}; } template constexpr vec qzdir (const vec & q) { return {(q.z*q.x+q.y*q.w)*2, (q.y*q.z-q.x*q.w)*2, q.w*q.w-q.x*q.x-q.y*q.y+q.z*q.z}; } template constexpr mat qmat (const vec & q) { return {qxdir(q), qydir(q), qzdir(q)}; } template constexpr vec qrot (const vec & q, const vec & v) { return qxdir(q)*v.x + qydir(q)*v.y + qzdir(q)*v.z; } template T qangle(const vec & q) { return std::atan2(length(q.xyz()), q.w)*2; } template vec qaxis (const vec & q) { return normalize(q.xyz()); } template vec qnlerp(const vec & a, const vec & b, T t) { return nlerp(a, dot(a,b) < 0 ? -b : b, t); } template vec qslerp(const vec & a, const vec & b, T t) { return slerp(a, dot(a,b) < 0 ? -b : b, t); } // Support for matrix algebra template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x; } template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y; } template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y + a.z*b.z; } template constexpr vec mul(const mat & a, const vec & b) { return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; } template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x)}; } template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y)}; } template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y), mul(a,b.z)}; } template constexpr mat mul(const mat & a, const mat & b) { return {mul(a,b.x), mul(a,b.y), mul(a,b.z), mul(a,b.w)}; } template constexpr vec mul(const mat & a, const mat & b, const vec & c) { return mul(mul(a,b),c); } template constexpr mat mul(const mat & a, const mat & b, const mat & c) { return mul(mul(a,b),c); } template constexpr vec mul(const mat & a, const mat & b, const mat & c, const vec & d) { return mul(mul(a,b,c),d); } template constexpr mat mul(const mat & a, const mat & b, const mat & c, const mat & d) { return mul(mul(a,b,c),d); } template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x}; } template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y}; } template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y, a*b.z}; } template constexpr mat outerprod(const vec & a, const vec & b) { return {a*b.x, a*b.y, a*b.z, a*b.w}; } template constexpr vec diagonal(const mat & a) { return {a.x.x}; } template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y}; } template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y, a.z.z}; } template constexpr vec diagonal(const mat & a) { return {a.x.x, a.y.y, a.z.z, a.w.w}; } template constexpr T trace(const mat & a) { return sum(diagonal(a)); } template constexpr mat transpose(const mat & m) { return {m.row(0)}; } template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1)}; } template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1), m.row(2)}; } template constexpr mat transpose(const mat & m) { return {m.row(0), m.row(1), m.row(2), m.row(3)}; } template constexpr mat transpose(const vec & m) { return transpose(mat(m)); } template constexpr mat adjugate(const mat & a) { return {vec{1}}; } template constexpr mat adjugate(const mat & a) { return {{a.y.y, -a.x.y}, {-a.y.x, a.x.x}}; } template constexpr mat adjugate(const mat & a); template constexpr mat adjugate(const mat & a); template constexpr mat comatrix(const mat & a) { return transpose(adjugate(a)); } template constexpr T determinant(const mat & a) { return a.x.x; } template constexpr T determinant(const mat & a) { return a.x.x*a.y.y - a.x.y*a.y.x; } template constexpr T determinant(const mat & a) { return a.x.x*(a.y.y*a.z.z - a.z.y*a.y.z) + a.x.y*(a.y.z*a.z.x - a.z.z*a.y.x) + a.x.z*(a.y.x*a.z.y - a.z.x*a.y.y); } template constexpr T determinant(const mat & a); template constexpr mat inverse(const mat & a) { return adjugate(a)/determinant(a); } // Vectors and matrices can be used as ranges template T * begin( vec & a) { return &a.x; } template const T * begin(const vec & a) { return &a.x; } template T * end ( vec & a) { return begin(a) + M; } template const T * end (const vec & a) { return begin(a) + M; } template vec * begin( mat & a) { return &a.x; } template const vec * begin(const mat & a) { return &a.x; } template vec * end ( mat & a) { return begin(a) + N; } template const vec * end (const mat & a) { return begin(a) + N; } // Factory functions for 3D spatial transformations (will possibly be removed or changed in a future version) enum fwd_axis { neg_z, pos_z }; // Should projection matrices be generated assuming forward is {0,0,-1} or {0,0,1} enum z_range { neg_one_to_one, zero_to_one }; // Should projection matrices map z into the range of [-1,1] or [0,1]? template vec rotation_quat (const vec & axis, T angle) { return {axis*std::sin(angle/2), std::cos(angle/2)}; } template vec rotation_quat (const mat & m); template mat translation_matrix(const vec & translation) { return {{1,0,0,0},{0,1,0,0},{0,0,1,0},{translation,1}}; } template mat rotation_matrix (const vec & rotation) { return {{qxdir(rotation),0}, {qydir(rotation),0}, {qzdir(rotation),0}, {0,0,0,1}}; } template mat scaling_matrix (const vec & scaling) { return {{scaling.x,0,0,0}, {0,scaling.y,0,0}, {0,0,scaling.z,0}, {0,0,0,1}}; } template mat pose_matrix (const vec & q, const vec & p) { return {{qxdir(q),0}, {qydir(q),0}, {qzdir(q),0}, {p,1}}; } template mat lookat_matrix (const vec & eye, const vec & center, const vec & view_y_dir, fwd_axis fwd = neg_z); template mat frustum_matrix (T x0, T x1, T y0, T y1, T n, T f, fwd_axis a = neg_z, z_range z = neg_one_to_one); template mat perspective_matrix(T fovy, T aspect, T n, T f, fwd_axis a = neg_z, z_range z = neg_one_to_one) { T y = n*std::tan(fovy / 2), x = y*aspect; return frustum_matrix(-x, x, -y, y, n, f, a, z); } // Provide implicit conversion between linalg::vec and std::array template struct converter, std::array> { vec operator() (const std::array & a) const { return {a[0]}; } }; template struct converter, std::array> { vec operator() (const std::array & a) const { return {a[0], a[1]}; } }; template struct converter, std::array> { vec operator() (const std::array & a) const { return {a[0], a[1], a[2]}; } }; template struct converter, std::array> { vec operator() (const std::array & a) const { return {a[0], a[1], a[2], a[3]}; } }; template struct converter, vec> { std::array operator() (const vec & a) const { return {a[0]}; } }; template struct converter, vec> { std::array operator() (const vec & a) const { return {a[0], a[1]}; } }; template struct converter, vec> { std::array operator() (const vec & a) const { return {a[0], a[1], a[2]}; } }; template struct converter, vec> { std::array operator() (const vec & a) const { return {a[0], a[1], a[2], a[3]}; } }; // Provide typedefs for common element types and vector/matrix sizes namespace aliases { typedef vec bool1; typedef vec byte1; typedef vec short1; typedef vec ushort1; typedef vec bool2; typedef vec byte2; typedef vec short2; typedef vec ushort2; typedef vec bool3; typedef vec byte3; typedef vec short3; typedef vec ushort3; typedef vec bool4; typedef vec byte4; typedef vec short4; typedef vec ushort4; typedef vec int1; typedef vec uint1; typedef vec float1; typedef vec double1; typedef vec int2; typedef vec uint2; typedef vec float2; typedef vec double2; typedef vec int3; typedef vec uint3; typedef vec float3; typedef vec double3; typedef vec int4; typedef vec uint4; typedef vec float4; typedef vec double4; typedef mat bool1x1; typedef mat int1x1; typedef mat float1x1; typedef mat double1x1; typedef mat bool1x2; typedef mat int1x2; typedef mat float1x2; typedef mat double1x2; typedef mat bool1x3; typedef mat int1x3; typedef mat float1x3; typedef mat double1x3; typedef mat bool1x4; typedef mat int1x4; typedef mat float1x4; typedef mat double1x4; typedef mat bool2x1; typedef mat int2x1; typedef mat float2x1; typedef mat double2x1; typedef mat bool2x2; typedef mat int2x2; typedef mat float2x2; typedef mat double2x2; typedef mat bool2x3; typedef mat int2x3; typedef mat float2x3; typedef mat double2x3; typedef mat bool2x4; typedef mat int2x4; typedef mat float2x4; typedef mat double2x4; typedef mat bool3x1; typedef mat int3x1; typedef mat float3x1; typedef mat double3x1; typedef mat bool3x2; typedef mat int3x2; typedef mat float3x2; typedef mat double3x2; typedef mat bool3x3; typedef mat int3x3; typedef mat float3x3; typedef mat double3x3; typedef mat bool3x4; typedef mat int3x4; typedef mat float3x4; typedef mat double3x4; typedef mat bool4x1; typedef mat int4x1; typedef mat float4x1; typedef mat double4x1; typedef mat bool4x2; typedef mat int4x2; typedef mat float4x2; typedef mat double4x2; typedef mat bool4x3; typedef mat int4x3; typedef mat float4x3; typedef mat double4x3; typedef mat bool4x4; typedef mat int4x4; typedef mat float4x4; typedef mat double4x4; } // Provide output streaming operators, writing something that resembles an aggregate literal that could be used to construct the specified value namespace ostream_overloads { template std::basic_ostream & operator << (std::basic_ostream & out, const vec & v) { return out << '{' << v[0] << '}'; } template std::basic_ostream & operator << (std::basic_ostream & out, const vec & v) { return out << '{' << v[0] << ',' << v[1] << '}'; } template std::basic_ostream & operator << (std::basic_ostream & out, const vec & v) { return out << '{' << v[0] << ',' << v[1] << ',' << v[2] << '}'; } template std::basic_ostream & operator << (std::basic_ostream & out, const vec & v) { return out << '{' << v[0] << ',' << v[1] << ',' << v[2] << ',' << v[3] << '}'; } template std::basic_ostream & operator << (std::basic_ostream & out, const mat & m) { return out << '{' << m[0] << '}'; } template std::basic_ostream & operator << (std::basic_ostream & out, const mat & m) { return out << '{' << m[0] << ',' << m[1] << '}'; } template std::basic_ostream & operator << (std::basic_ostream & out, const mat & m) { return out << '{' << m[0] << ',' << m[1] << ',' << m[2] << '}'; } template std::basic_ostream & operator << (std::basic_ostream & out, const mat & m) { return out << '{' << m[0] << ',' << m[1] << ',' << m[2] << ',' << m[3] << '}'; } } } namespace std { // Provide specializations for std::hash<...> with linalg types template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x); } }; template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1); } }; template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1) ^ (h(v.z) << 2); } }; template struct hash> { std::size_t operator()(const linalg::vec & v) const { std::hash h; return h(v.x) ^ (h(v.y) << 1) ^ (h(v.z) << 2) ^ (h(v.w) << 3); } }; template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x); } }; template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M); } }; template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M) ^ (h(v.z) << (M*2)); } }; template struct hash> { std::size_t operator()(const linalg::mat & v) const { std::hash> h; return h(v.x) ^ (h(v.y) << M) ^ (h(v.z) << (M*2)) ^ (h(v.w) << (M*3)); } }; } // Definitions of functions too long to be defined inline template constexpr linalg::mat linalg::adjugate(const mat & a) { return {{a.y.y*a.z.z - a.z.y*a.y.z, a.z.y*a.x.z - a.x.y*a.z.z, a.x.y*a.y.z - a.y.y*a.x.z}, {a.y.z*a.z.x - a.z.z*a.y.x, a.z.z*a.x.x - a.x.z*a.z.x, a.x.z*a.y.x - a.y.z*a.x.x}, {a.y.x*a.z.y - a.z.x*a.y.y, a.z.x*a.x.y - a.x.x*a.z.y, a.x.x*a.y.y - a.y.x*a.x.y}}; } template constexpr linalg::mat linalg::adjugate(const mat & a) { return {{a.y.y*a.z.z*a.w.w + a.w.y*a.y.z*a.z.w + a.z.y*a.w.z*a.y.w - a.y.y*a.w.z*a.z.w - a.z.y*a.y.z*a.w.w - a.w.y*a.z.z*a.y.w, a.x.y*a.w.z*a.z.w + a.z.y*a.x.z*a.w.w + a.w.y*a.z.z*a.x.w - a.w.y*a.x.z*a.z.w - a.z.y*a.w.z*a.x.w - a.x.y*a.z.z*a.w.w, a.x.y*a.y.z*a.w.w + a.w.y*a.x.z*a.y.w + a.y.y*a.w.z*a.x.w - a.x.y*a.w.z*a.y.w - a.y.y*a.x.z*a.w.w - a.w.y*a.y.z*a.x.w, a.x.y*a.z.z*a.y.w + a.y.y*a.x.z*a.z.w + a.z.y*a.y.z*a.x.w - a.x.y*a.y.z*a.z.w - a.z.y*a.x.z*a.y.w - a.y.y*a.z.z*a.x.w}, {a.y.z*a.w.w*a.z.x + a.z.z*a.y.w*a.w.x + a.w.z*a.z.w*a.y.x - a.y.z*a.z.w*a.w.x - a.w.z*a.y.w*a.z.x - a.z.z*a.w.w*a.y.x, a.x.z*a.z.w*a.w.x + a.w.z*a.x.w*a.z.x + a.z.z*a.w.w*a.x.x - a.x.z*a.w.w*a.z.x - a.z.z*a.x.w*a.w.x - a.w.z*a.z.w*a.x.x, a.x.z*a.w.w*a.y.x + a.y.z*a.x.w*a.w.x + a.w.z*a.y.w*a.x.x - a.x.z*a.y.w*a.w.x - a.w.z*a.x.w*a.y.x - a.y.z*a.w.w*a.x.x, a.x.z*a.y.w*a.z.x + a.z.z*a.x.w*a.y.x + a.y.z*a.z.w*a.x.x - a.x.z*a.z.w*a.y.x - a.y.z*a.x.w*a.z.x - a.z.z*a.y.w*a.x.x}, {a.y.w*a.z.x*a.w.y + a.w.w*a.y.x*a.z.y + a.z.w*a.w.x*a.y.y - a.y.w*a.w.x*a.z.y - a.z.w*a.y.x*a.w.y - a.w.w*a.z.x*a.y.y, a.x.w*a.w.x*a.z.y + a.z.w*a.x.x*a.w.y + a.w.w*a.z.x*a.x.y - a.x.w*a.z.x*a.w.y - a.w.w*a.x.x*a.z.y - a.z.w*a.w.x*a.x.y, a.x.w*a.y.x*a.w.y + a.w.w*a.x.x*a.y.y + a.y.w*a.w.x*a.x.y - a.x.w*a.w.x*a.y.y - a.y.w*a.x.x*a.w.y - a.w.w*a.y.x*a.x.y, a.x.w*a.z.x*a.y.y + a.y.w*a.x.x*a.z.y + a.z.w*a.y.x*a.x.y - a.x.w*a.y.x*a.z.y - a.z.w*a.x.x*a.y.y - a.y.w*a.z.x*a.x.y}, {a.y.x*a.w.y*a.z.z + a.z.x*a.y.y*a.w.z + a.w.x*a.z.y*a.y.z - a.y.x*a.z.y*a.w.z - a.w.x*a.y.y*a.z.z - a.z.x*a.w.y*a.y.z, a.x.x*a.z.y*a.w.z + a.w.x*a.x.y*a.z.z + a.z.x*a.w.y*a.x.z - a.x.x*a.w.y*a.z.z - a.z.x*a.x.y*a.w.z - a.w.x*a.z.y*a.x.z, a.x.x*a.w.y*a.y.z + a.y.x*a.x.y*a.w.z + a.w.x*a.y.y*a.x.z - a.x.x*a.y.y*a.w.z - a.w.x*a.x.y*a.y.z - a.y.x*a.w.y*a.x.z, a.x.x*a.y.y*a.z.z + a.z.x*a.x.y*a.y.z + a.y.x*a.z.y*a.x.z - a.x.x*a.z.y*a.y.z - a.y.x*a.x.y*a.z.z - a.z.x*a.y.y*a.x.z}}; } template constexpr T linalg::determinant(const mat & a) { return a.x.x*(a.y.y*a.z.z*a.w.w + a.w.y*a.y.z*a.z.w + a.z.y*a.w.z*a.y.w - a.y.y*a.w.z*a.z.w - a.z.y*a.y.z*a.w.w - a.w.y*a.z.z*a.y.w) + a.x.y*(a.y.z*a.w.w*a.z.x + a.z.z*a.y.w*a.w.x + a.w.z*a.z.w*a.y.x - a.y.z*a.z.w*a.w.x - a.w.z*a.y.w*a.z.x - a.z.z*a.w.w*a.y.x) + a.x.z*(a.y.w*a.z.x*a.w.y + a.w.w*a.y.x*a.z.y + a.z.w*a.w.x*a.y.y - a.y.w*a.w.x*a.z.y - a.z.w*a.y.x*a.w.y - a.w.w*a.z.x*a.y.y) + a.x.w*(a.y.x*a.w.y*a.z.z + a.z.x*a.y.y*a.w.z + a.w.x*a.z.y*a.y.z - a.y.x*a.z.y*a.w.z - a.w.x*a.y.y*a.z.z - a.z.x*a.w.y*a.y.z); } template linalg::vec linalg::rotation_quat(const mat & m) { const vec q {m.x.x-m.y.y-m.z.z, m.y.y-m.x.x-m.z.z, m.z.z-m.x.x-m.y.y, m.x.x+m.y.y+m.z.z}, s[] { {1, m.x.y + m.y.x, m.z.x + m.x.z, m.y.z - m.z.y}, {m.x.y + m.y.x, 1, m.y.z + m.z.y, m.z.x - m.x.z}, {m.x.z + m.z.x, m.y.z + m.z.y, 1, m.x.y - m.y.x}, {m.y.z - m.z.y, m.z.x - m.x.z, m.x.y - m.y.x, 1}}; return copysign(normalize(sqrt(max(T(0), T(1)+q))), s[argmax(q)]); } template linalg::mat linalg::lookat_matrix(const vec & eye, const vec & center, const vec & view_y_dir, fwd_axis a) { const vec f = normalize(center - eye), z = a == pos_z ? f : -f, x = normalize(cross(view_y_dir, z)), y = cross(z, x); return inverse(mat{{x,0},{y,0},{z,0},{eye,1}}); } template linalg::mat linalg::frustum_matrix(T x0, T x1, T y0, T y1, T n, T f, fwd_axis a, z_range z) { const T s = a == pos_z ? T(1) : T(-1), o = z == neg_one_to_one ? n : 0; return {{2*n/(x1-x0),0,0,0}, {0,2*n/(y1-y0),0,0}, {-s*(x0+x1)/(x1-x0),-s*(y0+y1)/(y1-y0),s*(f+o)/(f-n),s}, {0,0,-(n+o)*f/(f-n),0}}; } #endif