| @@ -43,7 +43,7 @@ liblolcore_headers = \ | |||
| lol/math/all.h \ | |||
| lol/math/functions.h lol/math/vector.h lol/math/half.h lol/math/real.h \ | |||
| lol/math/geometry.h lol/math/interp.h lol/math/rand.h lol/math/array2d.h \ | |||
| lol/math/array3d.h lol/math/constants.h lol/math/matrix.h \ | |||
| lol/math/array3d.h lol/math/constants.h lol/math/matrix.h lol/math/ops.h \ | |||
| lol/math/transform.h \ | |||
| \ | |||
| lol/algorithm/all.h \ | |||
| @@ -15,6 +15,7 @@ | |||
| #include <lol/math/functions.h> | |||
| #include <lol/math/half.h> | |||
| #include <lol/math/real.h> | |||
| #include <lol/math/ops.h> | |||
| #include <lol/math/vector.h> | |||
| #include <lol/math/matrix.h> | |||
| #include <lol/math/transform.h> | |||
| @@ -116,6 +116,8 @@ public: | |||
| uint16_t bits; | |||
| }; | |||
| static_assert(sizeof(half) == 2, "sizeof(half) == 2"); | |||
| static inline half min(half a, half b) { return a < b ? a : b; } | |||
| static inline half max(half a, half b) { return a > b ? a : b; } | |||
| static inline float fmod(half a, half b) | |||
| @@ -33,8 +33,11 @@ namespace lol | |||
| */ | |||
| template<typename T, int COLS, int ROWS> | |||
| struct mat_t : public linear_ops::base | |||
| struct mat_t | |||
| : public linear_ops::base<vec_t<T,ROWS>> | |||
| { | |||
| static int const count = COLS; | |||
| typedef vec_t<T,ROWS> element; | |||
| typedef mat_t<T,COLS,ROWS> type; | |||
| inline mat_t() {} | |||
| @@ -59,8 +62,11 @@ private: | |||
| */ | |||
| template <typename T> | |||
| struct mat_t<T, 2, 2> : public linear_ops::base | |||
| struct mat_t<T, 2, 2> | |||
| : public linear_ops::base<vec_t<T,2>> | |||
| { | |||
| static int const count = 2; | |||
| typedef vec_t<T,2> element; | |||
| typedef mat_t<T,2,2> type; | |||
| inline mat_t() {} | |||
| @@ -119,13 +125,25 @@ private: | |||
| #endif | |||
| }; | |||
| static_assert(sizeof(i8mat2) == 4, "sizeof(i8mat2) == 4"); | |||
| static_assert(sizeof(i16mat2) == 8, "sizeof(i16mat2) == 8"); | |||
| static_assert(sizeof(imat2) == 16, "sizeof(imat2) == 16"); | |||
| static_assert(sizeof(i64mat2) == 32, "sizeof(i64mat2) == 32"); | |||
| static_assert(sizeof(f16mat2) == 8, "sizeof(f16mat2) == 8"); | |||
| static_assert(sizeof(mat2) == 16, "sizeof(mat2) == 16"); | |||
| static_assert(sizeof(dmat2) == 32, "sizeof(dmat2) == 32"); | |||
| /* | |||
| * 3×3-element matrices | |||
| */ | |||
| template <typename T> | |||
| struct mat_t<T, 3, 3> : public linear_ops::base | |||
| struct mat_t<T, 3, 3> | |||
| : public linear_ops::base<vec_t<T,3>> | |||
| { | |||
| static int const count = 3; | |||
| typedef vec_t<T,3> element; | |||
| typedef mat_t<T,3,3> type; | |||
| inline mat_t() {} | |||
| @@ -230,13 +248,25 @@ private: | |||
| #endif | |||
| }; | |||
| static_assert(sizeof(i8mat3) == 9, "sizeof(i8mat3) == 9"); | |||
| static_assert(sizeof(i16mat3) == 18, "sizeof(i16mat3) == 18"); | |||
| static_assert(sizeof(imat3) == 36, "sizeof(imat3) == 36"); | |||
| static_assert(sizeof(i64mat3) == 72, "sizeof(i64mat3) == 72"); | |||
| static_assert(sizeof(f16mat3) == 18, "sizeof(f16mat3) == 18"); | |||
| static_assert(sizeof(mat3) == 36, "sizeof(mat3) == 36"); | |||
| static_assert(sizeof(dmat3) == 72, "sizeof(dmat3) == 72"); | |||
| /* | |||
| * 4×4-element matrices | |||
| */ | |||
| template <typename T> | |||
| struct mat_t<T, 4, 4> : public linear_ops::base | |||
| struct mat_t<T, 4, 4> | |||
| : public linear_ops::base<vec_t<T,4>> | |||
| { | |||
| static int const count = 4; | |||
| typedef vec_t<T,4> element; | |||
| typedef mat_t<T,4,4> type; | |||
| inline mat_t() {} | |||
| @@ -388,6 +418,15 @@ private: | |||
| #endif | |||
| }; | |||
| static_assert(sizeof(i8mat4) == 16, "sizeof(i8mat4) == 16"); | |||
| static_assert(sizeof(i16mat4) == 32, "sizeof(i16mat4) == 32"); | |||
| static_assert(sizeof(imat4) == 64, "sizeof(imat4) == 64"); | |||
| static_assert(sizeof(i64mat4) == 128, "sizeof(i64mat4) == 128"); | |||
| static_assert(sizeof(f16mat4) == 32, "sizeof(f16mat4) == 32"); | |||
| static_assert(sizeof(mat4) == 64, "sizeof(mat4) == 64"); | |||
| static_assert(sizeof(dmat4) == 128, "sizeof(dmat4) == 128"); | |||
| template<typename T> T determinant(mat_t<T,2,2> const &); | |||
| template<typename T> T determinant(mat_t<T,3,3> const &); | |||
| template<typename T> T determinant(mat_t<T,4,4> const &); | |||
| @@ -406,53 +445,6 @@ static inline mat_t<T, ROWS, COLS> transpose(mat_t<T, COLS, ROWS> const &m) | |||
| return ret; | |||
| } | |||
| /* | |||
| * Addition/subtraction/unary | |||
| */ | |||
| template<typename T, int COLS, int ROWS> | |||
| static inline mat_t<T, COLS, ROWS> &operator +=(mat_t<T, COLS, ROWS> &a, | |||
| mat_t<T, COLS, ROWS> const &b) | |||
| { | |||
| for (int i = 0; i < COLS; ++i) | |||
| a[i] += b[i]; | |||
| return a; | |||
| } | |||
| template<typename T, int COLS, int ROWS> | |||
| static inline mat_t<T, COLS, ROWS> operator +(mat_t<T, COLS, ROWS> const &a, | |||
| mat_t<T, COLS, ROWS> const &b) | |||
| { | |||
| mat_t<T, COLS, ROWS> ret = a; | |||
| return ret += b; | |||
| } | |||
| template<typename T, int COLS, int ROWS> | |||
| static inline mat_t<T, COLS, ROWS> &operator -=(mat_t<T, COLS, ROWS> &a, | |||
| mat_t<T, COLS, ROWS> const &b) | |||
| { | |||
| for (int i = 0; i < COLS; ++i) | |||
| a[i] -= b[i]; | |||
| return a; | |||
| } | |||
| template<typename T, int COLS, int ROWS> | |||
| static inline mat_t<T, COLS, ROWS> operator -(mat_t<T, COLS, ROWS> const &a, | |||
| mat_t<T, COLS, ROWS> const &b) | |||
| { | |||
| mat_t<T, COLS, ROWS> ret = a; | |||
| return ret -= b; | |||
| } | |||
| template<typename T, int COLS, int ROWS> | |||
| static inline mat_t<T, COLS, ROWS> operator -(mat_t<T, COLS, ROWS> const &m) | |||
| { | |||
| mat_t<T, COLS, ROWS> ret; | |||
| for (int i = 0; i < COLS; ++i) | |||
| ret[i] = -m[i]; | |||
| return ret; | |||
| } | |||
| /* | |||
| * Matrix-vector and vector-matrix multiplication | |||
| */ | |||
| @@ -0,0 +1,344 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://www.wtfpl.net/ for more details. | |||
| // | |||
| // | |||
| // Operations for vector classes | |||
| // ----------------------------- | |||
| // | |||
| #if !defined __LOL_MATH_OPS_H__ | |||
| #define __LOL_MATH_OPS_H__ | |||
| #include <ostream> | |||
| #include <type_traits> | |||
| #include <lol/math/half.h> | |||
| #include <lol/math/real.h> | |||
| /* | |||
| * Utility namespaces for traits -- this file uses a combination of | |||
| * ADL black magic and enable_if to ensure that only the expected type | |||
| * conversions are done. | |||
| */ | |||
| namespace lol | |||
| { | |||
| /* | |||
| * Operators for swizzled vectors. Since template deduction cannot be | |||
| * done for two arbitrary vec_t<> values, we help the compiler understand | |||
| * the expected type. | |||
| */ | |||
| namespace swizzle_ops | |||
| { | |||
| template<typename T, int SWIZZLE = FULL_SWIZZLE> | |||
| struct base {}; | |||
| template<typename T, int N, int SWIZZLE1, int SWIZZLE2> | |||
| static inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE || SWIZZLE2 != FULL_SWIZZLE, bool>::type operator ==(vec_t<T,N,SWIZZLE1> const &a, | |||
| vec_t<T,N,SWIZZLE2> const &b) | |||
| { | |||
| return vec_t<T,N>(a) == vec_t<T,N>(b); | |||
| } | |||
| template<typename T, int N, int SWIZZLE1, int SWIZZLE2> | |||
| static inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE || SWIZZLE2 != FULL_SWIZZLE, bool>::type operator !=(vec_t<T,N,SWIZZLE1> const &a, | |||
| vec_t<T,N,SWIZZLE2> const &b) | |||
| { | |||
| return vec_t<T,N>(a) != vec_t<T,N>(b); | |||
| } | |||
| #define LOL_SWIZZLE_V_VV_OP(op) \ | |||
| template<typename T, int N, int SWIZZLE1, int SWIZZLE2> \ | |||
| inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE \ | |||
| || SWIZZLE2 != FULL_SWIZZLE,vec_t<T,N>>::type \ | |||
| operator op(vec_t<T,N,SWIZZLE1> const &a, \ | |||
| vec_t<T,N,SWIZZLE2> const &b) \ | |||
| { \ | |||
| return vec_t<T,N>(a) op vec_t<T,N>(b); \ | |||
| } \ | |||
| \ | |||
| template<typename T, int N, int SWIZZLE> \ | |||
| inline typename std::enable_if<SWIZZLE != FULL_SWIZZLE,vec_t<T,N>>::type & \ | |||
| operator op##=(vec_t<T,N> &a, \ | |||
| vec_t<T,N,SWIZZLE> const &b) \ | |||
| { \ | |||
| return a op##= vec_t<T,N>(b); \ | |||
| } \ | |||
| \ | |||
| template<typename T, int N, int SWIZZLE> \ | |||
| inline typename std::enable_if<SWIZZLE != FULL_SWIZZLE,vec_t<T,N>>::type \ | |||
| operator op(vec_t<T,N,SWIZZLE> a, T const &b) \ | |||
| { \ | |||
| return vec_t<T,N>(a) op b; \ | |||
| } | |||
| LOL_SWIZZLE_V_VV_OP(+) | |||
| LOL_SWIZZLE_V_VV_OP(-) | |||
| LOL_SWIZZLE_V_VV_OP(*) | |||
| LOL_SWIZZLE_V_VV_OP(/) | |||
| #undef LOL_SWIZZLE_V_VV_OP | |||
| } /* namespace swizzle_ops */ | |||
| /* | |||
| * Linear operations: operators and functions that work on all types | |||
| * (vectors, matrices, quaternions...) such as addition or equality test. | |||
| * | |||
| * Others, e.g. multiplication, cannot be implemented here, since it should | |||
| * be implemented as per-component multiplication for vectors, and matrix | |||
| * product for matrices. | |||
| */ | |||
| namespace linear_ops | |||
| { | |||
| template<typename T> | |||
| struct base {}; | |||
| /* | |||
| * Comparisons | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type | |||
| operator ==(V const &a, V const &b) | |||
| { | |||
| for (int i = 0; i < V::count; ++i) | |||
| if (!(a[i] == b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type | |||
| operator !=(V const &a, V const &b) | |||
| { | |||
| for (int i = 0; i < V::count; ++i) | |||
| if (a[i] != b[i]) | |||
| return true; | |||
| return false; | |||
| } | |||
| /* | |||
| * Unary plus and minus | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator +(V const &v) | |||
| { | |||
| return v; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator -(V const &v) | |||
| { | |||
| typename V::type ret; | |||
| for (int i = 0; i < V::count; ++i) | |||
| ret[i] = -v[i]; | |||
| return ret; | |||
| } | |||
| /* | |||
| * Addition and subtraction | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator +(V const &a, V const &b) | |||
| { | |||
| typename V::type ret; | |||
| for (int i = 0; i < V::count; ++i) | |||
| ret[i] = a[i] + b[i]; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| &operator +=(V &a, V const &b) | |||
| { | |||
| return a = a + b; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator -(V const &a, V const &b) | |||
| { | |||
| typename V::type ret; | |||
| for (int i = 0; i < V::count; ++i) | |||
| ret[i] = a[i] - b[i]; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| &operator -=(V &a, V const &b) | |||
| { | |||
| return a = a - b; | |||
| } | |||
| /* | |||
| * Multiplication by scalar (left) | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator *(typename V::element const &val, V const &a) | |||
| { | |||
| typename V::type ret; | |||
| for (int i = 0; i < V::count; ++i) | |||
| ret[i] = val * a[i]; | |||
| return ret; | |||
| } | |||
| /* | |||
| * Multiplication/division by scalar (right) | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator *(V const &a, typename V::element const &val) | |||
| { | |||
| typename V::type ret; | |||
| for (int i = 0; i < V::count; ++i) | |||
| ret[i] = a[i] * val; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type & | |||
| operator *=(V &a, typename V::element const &val) | |||
| { | |||
| return a = a * val; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator /(V const &a, typename V::element const &val) | |||
| { | |||
| typename V::type ret; | |||
| for (int i = 0; i < V::count; ++i) | |||
| ret[i] = a[i] / val; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type & | |||
| operator /=(V &a, typename V::element const &val) | |||
| { | |||
| return a = a / val; | |||
| } | |||
| } /* namespace linear_ops */ | |||
| /* | |||
| * Operations that work component-wise, such as comparisons or multiplication. | |||
| * This is only for vector types, as the other types (matrices, quaternions, | |||
| * complexes) have different meanings. | |||
| */ | |||
| namespace componentwise_ops | |||
| { | |||
| template<typename T> | |||
| struct base {}; | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator *(V const &a, V const &b) | |||
| { | |||
| typename V::type ret; | |||
| for (int i = 0; i < V::count; ++i) | |||
| ret[i] = a[i] * b[i]; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| &operator *=(V &a, V const &b) | |||
| { | |||
| return a = a * b; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| operator /(V const &a, V const &b) | |||
| { | |||
| typename V::type ret; | |||
| for (int i = 0; i < V::count; ++i) | |||
| ret[i] = a[i] / b[i]; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type | |||
| &operator /=(V &a, V const &b) | |||
| { | |||
| return a = a / b; | |||
| } | |||
| /* | |||
| * Comparisons | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type | |||
| operator <(V const &a, V const &b) | |||
| { | |||
| for (int i = 0; i < V::count; ++i) | |||
| if (!(a[i] < b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type | |||
| operator >(V const &a, V const &b) | |||
| { | |||
| for (int i = 0; i < V::count; ++i) | |||
| if (!(a[i] > b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type | |||
| operator <=(V const &a, V const &b) | |||
| { | |||
| for (int i = 0; i < V::count; ++i) | |||
| if (!(a[i] <= b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type | |||
| operator >=(V const &a, V const &b) | |||
| { | |||
| for (int i = 0; i < V::count; ++i) | |||
| if (!(a[i] >= b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| } /* namespace componentwise_ops */ | |||
| } /* namespace lol */ | |||
| #endif // __LOL_MATH_OPS_H__ | |||
| @@ -30,8 +30,10 @@ namespace lol | |||
| */ | |||
| template<typename T> | |||
| struct cmplx_t : public linear_ops::base | |||
| struct cmplx_t : public linear_ops::base<T> | |||
| { | |||
| static int const count = 2; | |||
| typedef T element; | |||
| typedef cmplx_t<T> type; | |||
| inline constexpr cmplx_t() {} | |||
| @@ -43,7 +45,6 @@ struct cmplx_t : public linear_ops::base | |||
| : x(z.x), y(z.y) {} | |||
| LOL_COMMON_MEMBER_OPS(x) | |||
| LOL_NONVECTOR_MEMBER_OPS() | |||
| inline cmplx_t<T> operator *(cmplx_t<T> const &val) const | |||
| { | |||
| @@ -66,13 +67,24 @@ struct cmplx_t : public linear_ops::base | |||
| T x, y; | |||
| }; | |||
| static_assert(sizeof(i8cmplx) == 2, "sizeof(i8cmplx) == 2"); | |||
| static_assert(sizeof(i16cmplx) == 4, "sizeof(i16cmplx) == 4"); | |||
| static_assert(sizeof(icmplx) == 8, "sizeof(icmplx) == 8"); | |||
| static_assert(sizeof(i64cmplx) == 16, "sizeof(i64cmplx) == 16"); | |||
| static_assert(sizeof(f16cmplx) == 4, "sizeof(f16cmplx) == 4"); | |||
| static_assert(sizeof(cmplx) == 8, "sizeof(cmplx) == 8"); | |||
| static_assert(sizeof(dcmplx) == 16, "sizeof(dcmplx) == 16"); | |||
| /* | |||
| * 4-element transforms: quaternions | |||
| */ | |||
| template<typename T> | |||
| struct quat_t : public linear_ops::base | |||
| struct quat_t : public linear_ops::base<T> | |||
| { | |||
| static int const count = 4; | |||
| typedef T element; | |||
| typedef quat_t<T> type; | |||
| /* Default constructor and copy constructor */ | |||
| @@ -95,7 +107,6 @@ struct quat_t : public linear_ops::base | |||
| explicit quat_t(mat_t<T,4,4> const &m); | |||
| LOL_COMMON_MEMBER_OPS(w) | |||
| LOL_NONVECTOR_MEMBER_OPS() | |||
| inline quat_t operator *(quat_t const &val) const | |||
| { | |||
| @@ -210,6 +221,15 @@ struct quat_t : public linear_ops::base | |||
| T w, x, y, z; | |||
| }; | |||
| static_assert(sizeof(i8quat) == 4, "sizeof(i8quat) == 4"); | |||
| static_assert(sizeof(i16quat) == 8, "sizeof(i16quat) == 8"); | |||
| static_assert(sizeof(iquat) == 16, "sizeof(iquat) == 16"); | |||
| static_assert(sizeof(i64quat) == 32, "sizeof(i64quat) == 32"); | |||
| static_assert(sizeof(f16quat) == 8, "sizeof(f16quat) == 8"); | |||
| static_assert(sizeof(quat) == 16, "sizeof(quat) == 16"); | |||
| static_assert(sizeof(dquat) == 32, "sizeof(dquat) == 32"); | |||
| /* | |||
| * Common operations on transforms | |||
| */ | |||
| @@ -17,10 +17,10 @@ | |||
| #define __LOL_MATH_VECTOR_H__ | |||
| #include <ostream> | |||
| #include <type_traits> | |||
| #include <lol/math/half.h> | |||
| #include <lol/math/real.h> | |||
| #include <lol/math/ops.h> | |||
| namespace lol | |||
| { | |||
| @@ -35,169 +35,6 @@ namespace lol | |||
| # define _____ /* */ | |||
| #endif | |||
| /* | |||
| * Utility namespaces for traits | |||
| */ | |||
| namespace swizzle_ops | |||
| { | |||
| } | |||
| namespace linear_ops | |||
| { | |||
| struct base {}; | |||
| /* | |||
| * Unary plus and minus | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| operator +(V const &v) | |||
| { | |||
| return v; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| operator -(V const &v) | |||
| { | |||
| V ret; | |||
| for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i) | |||
| ret[i] = -v[i]; | |||
| return ret; | |||
| } | |||
| /* | |||
| * Addition and subtraction | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| operator +(V const &a, V const &b) | |||
| { | |||
| V ret; | |||
| for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i) | |||
| ret[i] = a[i] + b[i]; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| &operator +=(V &a, V const &b) | |||
| { | |||
| return a = a + b; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| operator -(V const &a, V const &b) | |||
| { | |||
| V ret; | |||
| for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i) | |||
| ret[i] = a[i] - b[i]; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| &operator -=(V &a, V const &b) | |||
| { | |||
| return a = a - b; | |||
| } | |||
| } /* namespace linear_ops */ | |||
| namespace componentwise_ops | |||
| { | |||
| struct base {}; | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| operator *(V const &a, V const &b) | |||
| { | |||
| V ret; | |||
| for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i) | |||
| ret[i] = a[i] * b[i]; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| &operator *=(V &a, V const &b) | |||
| { | |||
| return a = a * b; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| operator /(V const &a, V const &b) | |||
| { | |||
| V ret; | |||
| for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i) | |||
| ret[i] = a[i] / b[i]; | |||
| return ret; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type | |||
| &operator /=(V &a, V const &b) | |||
| { | |||
| return a = a / b; | |||
| } | |||
| /* | |||
| * Comparisons | |||
| */ | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, bool>::type | |||
| operator <(V const &a, V const &b) | |||
| { | |||
| for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i) | |||
| if (!(a[i] < b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, bool>::type | |||
| operator >(V const &a, V const &b) | |||
| { | |||
| for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i) | |||
| if (!(a[i] > b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, bool>::type | |||
| operator <=(V const &a, V const &b) | |||
| { | |||
| for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i) | |||
| if (!(a[i] <= b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| template<typename V> | |||
| static inline typename std::enable_if<std::is_base_of<base, V>::value, bool>::type | |||
| operator >=(V const &a, V const &b) | |||
| { | |||
| for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i) | |||
| if (!(a[i] >= b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| } /* namespace componentwise_ops */ | |||
| /* | |||
| * Magic vector swizzling (part 1/2) | |||
| * These vectors are empty, but thanks to static_cast we can take their | |||
| @@ -214,7 +51,13 @@ operator >=(V const &a, V const &b) | |||
| template<typename T, int N, int SWIZZLE> | |||
| struct vec_t | |||
| /* MUST be a different base than e.g. vec_t<T,2> otherwise the unions | |||
| * in vec_t<T,2> with the same base will cause empty base optimisation | |||
| * failures. */ | |||
| : public swizzle_ops::base<T, SWIZZLE> | |||
| { | |||
| static int const count = N; | |||
| typedef T element; | |||
| typedef vec_t<T,N> type; | |||
| inline vec_t<T, N, SWIZZLE>& operator =(vec_t<T, N> that); | |||
| @@ -244,9 +87,11 @@ struct vec_t | |||
| * swizzling. There's an override for N=2, N=3, N=4 that has swizzling. */ | |||
| template<typename T, int N> | |||
| struct vec_t<T, N, FULL_SWIZZLE> | |||
| : public linear_ops::base, | |||
| public componentwise_ops::base | |||
| : public linear_ops::base<T>, | |||
| public componentwise_ops::base<T> | |||
| { | |||
| static int const count = N; | |||
| typedef T element; | |||
| typedef vec_t<T,N> type; | |||
| inline T& operator[](size_t n) { return m_data[n]; } | |||
| @@ -260,30 +105,6 @@ private: | |||
| * Helper macros for vector type member functions | |||
| */ | |||
| #define LOL_V_VS_OP(op) \ | |||
| friend inline type operator op(type const &a, T const &val) \ | |||
| { \ | |||
| type ret; \ | |||
| for (size_t i = 0; i < sizeof(type) / sizeof(T); ++i) \ | |||
| ret[i] = a[i] op val; \ | |||
| return ret; \ | |||
| } | |||
| #define LOL_V_VS_ASSIGN_OP(op) \ | |||
| friend inline type operator op##=(type &a, T const &val) \ | |||
| { \ | |||
| return a = a op val; \ | |||
| } | |||
| #define LOL_B_VV_OP(op, op2, ret) \ | |||
| friend inline bool operator op(type const &a, type const &b) \ | |||
| { \ | |||
| for (size_t i = 0; i < sizeof(type) / sizeof(T); ++i) \ | |||
| if (!(a[i] op2 b[i])) \ | |||
| return !ret; \ | |||
| return ret; \ | |||
| } | |||
| #define LOL_COMMON_MEMBER_OPS(first) \ | |||
| inline T& operator[](size_t n) { return (&this->first)[n]; } \ | |||
| inline T const& operator[](size_t n) const { return (&this->first)[n]; } \ | |||
| @@ -291,37 +112,13 @@ private: | |||
| /* Visual Studio insists on having an assignment operator. */ \ | |||
| inline type & operator =(type const &that) \ | |||
| { \ | |||
| for (size_t i = 0; i < sizeof(type) / sizeof(T); ++i) \ | |||
| for (int i = 0; i < type::count; ++i) \ | |||
| (*this)[i] = that[i]; \ | |||
| return *this; \ | |||
| } \ | |||
| \ | |||
| void printf() const; \ | |||
| String tostring() const; \ | |||
| \ | |||
| /* vec_t *(vec_t, scalar) | |||
| * vec_t /(vec_t, scalar) | |||
| * vec_t *=(vec_t, scalar) | |||
| * vec_t /=(vec_t, scalar) */ \ | |||
| LOL_V_VS_OP(*) \ | |||
| LOL_V_VS_OP(/) \ | |||
| LOL_V_VS_ASSIGN_OP(*) \ | |||
| LOL_V_VS_ASSIGN_OP(/) \ | |||
| \ | |||
| /* bool ==(vec_t, vec_t) | |||
| * bool !=(vec_t, vec_t) */ \ | |||
| LOL_B_VV_OP(==, ==, true) \ | |||
| LOL_B_VV_OP(!=, ==, false) | |||
| #define LOL_NONVECTOR_MEMBER_OPS() \ | |||
| /* vec_t *(scalar, vec_t) (no division, it works differently) */ \ | |||
| friend inline type operator *(T const &val, type const &a) \ | |||
| { \ | |||
| type ret; \ | |||
| for (size_t i = 0; i < sizeof(type) / sizeof(T); ++i) \ | |||
| ret[i] = val * a[i]; \ | |||
| return ret; \ | |||
| } | |||
| String tostring() const; | |||
| /* | |||
| * 2-element vectors | |||
| @@ -329,9 +126,12 @@ private: | |||
| template <typename T> | |||
| struct vec_t<T,2> | |||
| : public linear_ops::base, | |||
| public componentwise_ops::base | |||
| : public swizzle_ops::base<T>, | |||
| public linear_ops::base<T>, | |||
| public componentwise_ops::base<T> | |||
| { | |||
| static int const count = 2; | |||
| typedef T element; | |||
| typedef vec_t<T,2> type; | |||
| /* Default constructor, copy constructor, and destructor */ | |||
| @@ -405,15 +205,27 @@ struct vec_t<T,2> | |||
| }; | |||
| }; | |||
| static_assert(sizeof(i8vec2) == 2, "sizeof(i8vec2) == 2"); | |||
| static_assert(sizeof(i16vec2) == 4, "sizeof(i16vec2) == 4"); | |||
| static_assert(sizeof(ivec2) == 8, "sizeof(ivec2) == 8"); | |||
| static_assert(sizeof(i64vec2) == 16, "sizeof(i64vec2) == 16"); | |||
| static_assert(sizeof(f16vec2) == 4, "sizeof(f16vec2) == 4"); | |||
| static_assert(sizeof(vec2) == 8, "sizeof(vec2) == 8"); | |||
| static_assert(sizeof(dvec2) == 16, "sizeof(dvec2) == 16"); | |||
| /* | |||
| * 3-element vectors | |||
| */ | |||
| template <typename T> | |||
| struct vec_t<T,3> | |||
| : public linear_ops::base, | |||
| public componentwise_ops::base | |||
| : public swizzle_ops::base<T>, | |||
| public linear_ops::base<T>, | |||
| public componentwise_ops::base<T> | |||
| { | |||
| static int const count = 3; | |||
| typedef T element; | |||
| typedef vec_t<T,3> type; | |||
| /* Default constructor, copy constructor, and destructor */ | |||
| @@ -617,15 +429,27 @@ struct vec_t<T,3> | |||
| }; | |||
| }; | |||
| static_assert(sizeof(i8vec3) == 3, "sizeof(i8vec3) == 3"); | |||
| static_assert(sizeof(i16vec3) == 6, "sizeof(i16vec3) == 6"); | |||
| static_assert(sizeof(ivec3) == 12, "sizeof(ivec3) == 12"); | |||
| static_assert(sizeof(i64vec3) == 24, "sizeof(i64vec3) == 24"); | |||
| static_assert(sizeof(f16vec3) == 6, "sizeof(f16vec3) == 6"); | |||
| static_assert(sizeof(vec3) == 12, "sizeof(vec3) == 12"); | |||
| static_assert(sizeof(dvec3) == 24, "sizeof(dvec3) == 24"); | |||
| /* | |||
| * 4-element vectors | |||
| */ | |||
| template <typename T> | |||
| struct vec_t<T,4> | |||
| : public linear_ops::base, | |||
| public componentwise_ops::base | |||
| : public swizzle_ops::base<T>, | |||
| public linear_ops::base<T>, | |||
| public componentwise_ops::base<T> | |||
| { | |||
| static int const count = 4; | |||
| typedef T element; | |||
| typedef vec_t<T,4> type; | |||
| /* Default constructor, copy constructor, and destructor */ | |||
| @@ -1022,68 +846,24 @@ struct vec_t<T,4> | |||
| }; | |||
| }; | |||
| /* | |||
| * Operators for swizzled vectors. Since template deduction cannot be | |||
| * done for two arbitrary vec_t<> values, we help the compiler understand | |||
| * the expected type. | |||
| */ | |||
| static_assert(sizeof(i8vec4) == 4, "sizeof(i8vec4) == 4"); | |||
| static_assert(sizeof(i16vec4) == 8, "sizeof(i16vec4) == 8"); | |||
| static_assert(sizeof(ivec4) == 16, "sizeof(ivec4) == 16"); | |||
| static_assert(sizeof(i64vec4) == 32, "sizeof(i64vec4) == 32"); | |||
| template<typename T, int N, int SWIZZLE1, int SWIZZLE2> | |||
| static inline bool operator ==(vec_t<T,N,SWIZZLE1> const &a, | |||
| vec_t<T,N,SWIZZLE2> const &b) | |||
| { | |||
| for (size_t i = 0; i < N; ++i) | |||
| if (!(a[i] == b[i])) | |||
| return false; | |||
| return true; | |||
| } | |||
| template<typename T, int N, int SWIZZLE1, int SWIZZLE2> | |||
| static inline bool operator !=(vec_t<T,N,SWIZZLE1> const &a, | |||
| vec_t<T,N,SWIZZLE2> const &b) | |||
| { | |||
| for (size_t i = 0; i < N; ++i) | |||
| if (a[i] != b[i]) | |||
| return true; | |||
| return false; | |||
| } | |||
| static_assert(sizeof(f16vec4) == 8, "sizeof(f16vec4) == 8"); | |||
| static_assert(sizeof(vec4) == 16, "sizeof(vec4) == 16"); | |||
| static_assert(sizeof(dvec4) == 32, "sizeof(dvec4) == 32"); | |||
| #define LOL_SWIZZLE_V_VV_OP(op) \ | |||
| template<typename T, int N, int SWIZZLE1, int SWIZZLE2> \ | |||
| inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE \ | |||
| || SWIZZLE2 != FULL_SWIZZLE,vec_t<T,N>>::type \ | |||
| operator op(vec_t<T,N,SWIZZLE1> const &a, \ | |||
| vec_t<T,N,SWIZZLE2> const &b) \ | |||
| { \ | |||
| return vec_t<T,N>(a) op vec_t<T,N>(b); \ | |||
| } \ | |||
| \ | |||
| template<typename T, int N, int SWIZZLE> \ | |||
| inline typename std::enable_if<SWIZZLE != FULL_SWIZZLE,vec_t<T,N>>::type & \ | |||
| operator op##=(vec_t<T,N> &a, \ | |||
| vec_t<T,N,SWIZZLE> const &b) \ | |||
| { \ | |||
| return a op##= vec_t<T,N>(b); \ | |||
| } \ | |||
| \ | |||
| template<typename T, int N, int SWIZZLE> \ | |||
| inline vec_t<T,N> operator op(vec_t<T,N,SWIZZLE> a, T const &b) \ | |||
| { \ | |||
| return vec_t<T,N>(a) op b; \ | |||
| } | |||
| LOL_SWIZZLE_V_VV_OP(+) | |||
| LOL_SWIZZLE_V_VV_OP(-) | |||
| LOL_SWIZZLE_V_VV_OP(*) | |||
| LOL_SWIZZLE_V_VV_OP(/) | |||
| #undef LOL_SWIZZLE_V_VV_OP | |||
| /* | |||
| * vec_t *(scalar, vec_t) | |||
| */ | |||
| template<typename T, int N, int SWIZZLE> | |||
| static inline vec_t<T,N> operator *(T const &val, vec_t<T,N,SWIZZLE> const &a) | |||
| { | |||
| vec_t<T,N> ret; | |||
| for (size_t i = 0; i < N; ++i) | |||
| for (int i = 0; i < N; ++i) | |||
| ret[i] = val * a[i]; | |||
| return ret; | |||
| } | |||
| @@ -1100,7 +880,7 @@ static inline vec_t<T,N> operator *(T const &val, vec_t<T,N,SWIZZLE> const &a) | |||
| { \ | |||
| using lol::fun; \ | |||
| vec_t<T,N> ret; \ | |||
| for (size_t i = 0; i < N; ++i) \ | |||
| for (int i = 0; i < N; ++i) \ | |||
| ret[i] = fun(a[i], b[i]); \ | |||
| return ret; \ | |||
| } \ | |||
| @@ -1110,7 +890,7 @@ static inline vec_t<T,N> operator *(T const &val, vec_t<T,N,SWIZZLE> const &a) | |||
| { \ | |||
| using lol::fun; \ | |||
| vec_t<T,N> ret; \ | |||
| for (size_t i = 0; i < N; ++i) \ | |||
| for (int i = 0; i < N; ++i) \ | |||
| ret[i] = fun(a[i], b); \ | |||
| return ret; \ | |||
| } \ | |||
| @@ -1120,7 +900,7 @@ static inline vec_t<T,N> operator *(T const &val, vec_t<T,N,SWIZZLE> const &a) | |||
| { \ | |||
| using lol::fun; \ | |||
| vec_t<T,N> ret; \ | |||
| for (size_t i = 0; i < N; ++i) \ | |||
| for (int i = 0; i < N; ++i) \ | |||
| ret[i] = fun(a, b[i]); \ | |||
| return ret; \ | |||
| } | |||
| @@ -1200,7 +980,7 @@ static inline T dot(vec_t<T,N,SWIZZLE1> const &a, | |||
| vec_t<T,N,SWIZZLE2> const &b) | |||
| { | |||
| T ret(0); | |||
| for (size_t i = 0; i < N; ++i) | |||
| for (int i = 0; i < N; ++i) | |||
| ret += a[i] * b[i]; | |||
| return ret; | |||
| } | |||
| @@ -1224,7 +1004,7 @@ static inline vec_t<T,N> lerp(vec_t<T,N,SWIZZLE1> const &a, | |||
| T const &s) | |||
| { | |||
| vec_t<T,N> ret; | |||
| for (size_t i = 0; i < N; ++i) | |||
| for (int i = 0; i < N; ++i) | |||
| ret[i] = a[i] + s * (b[i] - a[i]); | |||
| return ret; | |||
| } | |||
| @@ -1240,7 +1020,7 @@ template<typename T, int N, int SWIZZLE> | |||
| static inline vec_t<T,N> fract(vec_t<T,N,SWIZZLE> const &a) | |||
| { | |||
| vec_t<T,N> ret; | |||
| for (size_t i = 0; i < N; ++i) | |||
| for (int i = 0; i < N; ++i) | |||
| ret[i] = fract(a[i]); | |||
| return ret; | |||
| } | |||
| @@ -1256,7 +1036,7 @@ template<typename T, int N, int SWIZZLE> | |||
| static inline vec_t<T,N> abs(vec_t<T,N,SWIZZLE> const &a) | |||
| { | |||
| vec_t<T,N> ret; | |||
| for (size_t i = 0; i < N; ++i) | |||
| for (int i = 0; i < N; ++i) | |||
| ret[i] = lol::abs(a[i]); | |||
| return ret; | |||
| } | |||
| @@ -1265,7 +1045,7 @@ template<typename T, int N, int SWIZZLE> | |||
| static inline vec_t<T,N> degrees(vec_t<T,N,SWIZZLE> const &a) | |||
| { | |||
| vec_t<T,N> ret; | |||
| for (size_t i = 0; i < N; ++i) | |||
| for (int i = 0; i < N; ++i) | |||
| ret[i] = lol::degrees(a[i]); | |||
| return ret; | |||
| } | |||
| @@ -1274,7 +1054,7 @@ template<typename T, int N, int SWIZZLE> | |||
| static inline vec_t<T,N> radians(vec_t<T,N,SWIZZLE> const &a) | |||
| { | |||
| vec_t<T,N> ret; | |||
| for (size_t i = 0; i < N; ++i) | |||
| for (int i = 0; i < N; ++i) | |||
| ret[i] = lol::radians(a[i]); | |||
| return ret; | |||
| } | |||
| @@ -327,6 +327,7 @@ | |||
| <ClInclude Include="lol\math\half.h" /> | |||
| <ClInclude Include="lol\math\interp.h" /> | |||
| <ClInclude Include="lol\math\matrix.h" /> | |||
| <ClInclude Include="lol\math\ops.h" /> | |||
| <ClInclude Include="lol\math\rand.h" /> | |||
| <ClInclude Include="lol\math\real.h" /> | |||
| <ClInclude Include="lol\math\remez.h" /> | |||
| @@ -441,6 +441,9 @@ | |||
| <ClInclude Include="lol\math\matrix.h"> | |||
| <Filter>lol\math</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\math\ops.h"> | |||
| <Filter>lol\math</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="lol\math\rand.h"> | |||
| <Filter>lol\math</Filter> | |||
| </ClInclude> | |||