@@ -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> | |||