to the Tait-Bryan angles we had for now). Also, change quaternion storage order to wxyz in order to match the constructors.legacy
| @@ -125,9 +125,9 @@ template<typename T, int N> struct XVec4 | |||||
| * Helper macro for vector type member functions | * Helper macro for vector type member functions | ||||
| */ | */ | ||||
| #define DECLARE_MEMBER_OPS(tname) \ | |||||
| inline T& operator[](size_t n) { return *(&this->x + n); } \ | |||||
| inline T const& operator[](size_t n) const { return *(&this->x + n); } \ | |||||
| #define DECLARE_MEMBER_OPS(tname, first) \ | |||||
| inline T& operator[](size_t n) { return *(&this->first + n); } \ | |||||
| inline T const& operator[](size_t n) const { return *(&this->first + n); } \ | |||||
| \ | \ | ||||
| /* Visual Studio insists on having an assignment operator. */ \ | /* Visual Studio insists on having an assignment operator. */ \ | ||||
| inline tname<T> const & operator =(tname<T> const &that) \ | inline tname<T> const & operator =(tname<T> const &that) \ | ||||
| @@ -233,7 +233,7 @@ template <typename T> struct Vec2 : BVec2<T> | |||||
| explicit inline Vec2(XVec2<U, N> const &v) | explicit inline Vec2(XVec2<U, N> const &v) | ||||
| : BVec2<T>(v[0], v[1]) {} | : BVec2<T>(v[0], v[1]) {} | ||||
| DECLARE_MEMBER_OPS(Vec2) | |||||
| DECLARE_MEMBER_OPS(Vec2, x) | |||||
| #if !defined __ANDROID__ | #if !defined __ANDROID__ | ||||
| template<typename U> | template<typename U> | ||||
| @@ -251,7 +251,7 @@ template <typename T> struct Cmplx | |||||
| inline Cmplx(T X) : x(X), y(0) {} | inline Cmplx(T X) : x(X), y(0) {} | ||||
| inline Cmplx(T X, T Y) : x(X), y(Y) {} | inline Cmplx(T X, T Y) : x(X), y(Y) {} | ||||
| DECLARE_MEMBER_OPS(Cmplx) | |||||
| DECLARE_MEMBER_OPS(Cmplx, x) | |||||
| inline Cmplx<T> operator *(Cmplx<T> const &val) const | inline Cmplx<T> operator *(Cmplx<T> const &val) const | ||||
| { | { | ||||
| @@ -491,7 +491,7 @@ template <typename T> struct Vec3 : BVec3<T> | |||||
| static Vec3<T> toeuler(Quat<T> const &q); | static Vec3<T> toeuler(Quat<T> const &q); | ||||
| DECLARE_MEMBER_OPS(Vec3) | |||||
| DECLARE_MEMBER_OPS(Vec3, x) | |||||
| #if !defined __ANDROID__ | #if !defined __ANDROID__ | ||||
| template<typename U> | template<typename U> | ||||
| @@ -900,7 +900,7 @@ template <typename T> struct Vec4 : BVec4<T> | |||||
| explicit inline Vec4(XVec4<U, N> const &v) | explicit inline Vec4(XVec4<U, N> const &v) | ||||
| : BVec4<T>(v[0], v[1], v[2], v[3]) {} | : BVec4<T>(v[0], v[1], v[2], v[3]) {} | ||||
| DECLARE_MEMBER_OPS(Vec4) | |||||
| DECLARE_MEMBER_OPS(Vec4, x) | |||||
| #if !defined __ANDROID__ | #if !defined __ANDROID__ | ||||
| template<typename U> | template<typename U> | ||||
| @@ -915,17 +915,34 @@ template <typename T> struct Vec4 : BVec4<T> | |||||
| template <typename T> struct Quat | template <typename T> struct Quat | ||||
| { | { | ||||
| inline Quat() {} | inline Quat() {} | ||||
| inline Quat(T W) : x(0), y(0), z(0), w(W) {} | |||||
| inline Quat(T W, T X, T Y, T Z) : x(X), y(Y), z(Z), w(W) {} | |||||
| inline Quat(T W) : w(W), x(0), y(0), z(0) {} | |||||
| inline Quat(T W, T X, T Y, T Z) : w(W), x(X), y(Y), z(Z) {} | |||||
| Quat(Mat3<T> const &m); | Quat(Mat3<T> const &m); | ||||
| Quat(Mat4<T> const &m); | Quat(Mat4<T> const &m); | ||||
| DECLARE_MEMBER_OPS(Quat) | |||||
| DECLARE_MEMBER_OPS(Quat, w) | |||||
| static Quat<T> rotate(T angle, T x, T y, T z); | static Quat<T> rotate(T angle, T x, T y, T z); | ||||
| static Quat<T> rotate(T angle, Vec3<T> const &v); | static Quat<T> rotate(T angle, Vec3<T> const &v); | ||||
| /* Convert from Euler angles. The axes in fromeuler_xyx are | |||||
| * x, then y', then x", ie. the axes are attached to the model. | |||||
| * If you want to rotate around static axes, just reverse the order | |||||
| * of the arguments. */ | |||||
| static Quat<T> fromeuler_xyx(Vec3<T> const &v); | |||||
| static Quat<T> fromeuler_xzx(Vec3<T> const &v); | |||||
| static Quat<T> fromeuler_yxy(Vec3<T> const &v); | |||||
| static Quat<T> fromeuler_yzy(Vec3<T> const &v); | |||||
| static Quat<T> fromeuler_zxz(Vec3<T> const &v); | |||||
| static Quat<T> fromeuler_zyz(Vec3<T> const &v); | |||||
| static Quat<T> fromeuler_xyx(T phi, T theta, T psi); | |||||
| static Quat<T> fromeuler_xzx(T phi, T theta, T psi); | |||||
| static Quat<T> fromeuler_yxy(T phi, T theta, T psi); | |||||
| static Quat<T> fromeuler_yzy(T phi, T theta, T psi); | |||||
| static Quat<T> fromeuler_zxz(T phi, T theta, T psi); | |||||
| static Quat<T> fromeuler_zyz(T phi, T theta, T psi); | |||||
| /* Convert from Tait-Bryan angles (incorrectly called Euler angles, | /* Convert from Tait-Bryan angles (incorrectly called Euler angles, | ||||
| * but since everyone does it…). The axes in fromeuler_xyz are | * but since everyone does it…). The axes in fromeuler_xyz are | ||||
| * x, then y', then z", ie. the axes are attached to the model. | * x, then y', then z", ie. the axes are attached to the model. | ||||
| @@ -978,8 +995,8 @@ template <typename T> struct Quat | |||||
| friend std::ostream &operator<<(std::ostream &stream, Quat<U> const &v); | friend std::ostream &operator<<(std::ostream &stream, Quat<U> const &v); | ||||
| #endif | #endif | ||||
| /* Storage order is still xyzw because operator[] uses &this->x */ | |||||
| T x, y, z, w; | |||||
| /* XXX: storage order is wxyz, unlike vectors! */ | |||||
| T w, x, y, z; | |||||
| }; | }; | ||||
| template<typename T> | template<typename T> | ||||
| @@ -538,7 +538,7 @@ template<> mat3 mat3::fromeuler(float x, float y, float z) | |||||
| return mat3::fromeuler(vec3(x, y, z)); | return mat3::fromeuler(vec3(x, y, z)); | ||||
| } | } | ||||
| static inline quat fromeuler_generic(vec3 const &v, int s, int i, int j, int k) | |||||
| static inline quat quat_fromeuler_generic(vec3 const &v, int i, int j, int k) | |||||
| { | { | ||||
| using std::sin; | using std::sin; | ||||
| using std::cos; | using std::cos; | ||||
| @@ -548,76 +548,63 @@ static inline quat fromeuler_generic(vec3 const &v, int s, int i, int j, int k) | |||||
| float s1 = sin(half_angles[1]), c1 = cos(half_angles[1]); | float s1 = sin(half_angles[1]), c1 = cos(half_angles[1]); | ||||
| float s2 = sin(half_angles[2]), c2 = cos(half_angles[2]); | float s2 = sin(half_angles[2]), c2 = cos(half_angles[2]); | ||||
| vec4 v1(c0 * c1 * c2, c0 * c1 * s2, c0 * s1 * c2, s0 * c1 * c2); | |||||
| vec4 v2(s0 * s1 * s2, -s0 * s1 * c2, s0 * c1 * s2, -c0 * s1 * s2); | |||||
| quat ret; | |||||
| if (s > 0) | |||||
| v1 += v2; | |||||
| if (i == k) | |||||
| { | |||||
| ret[0] = c1 * (c0 * c2 - s0 * s2); | |||||
| ret[1 + i] = c1 * (c0 * s2 + s0 * c2); | |||||
| ret[1 + j] = s1 * (c0 * c2 + s0 * s2); | |||||
| if ((2 + i - j) % 3) | |||||
| ret[4 - i - j] = s1 * (s0 * c2 - c0 * s2); | |||||
| else | |||||
| ret[4 - i - j] = s1 * (c0 * s2 - s0 * c2); | |||||
| } | |||||
| else | else | ||||
| v1 -= v2; | |||||
| return quat(v1[0], v1[i], v1[j], v1[k]); | |||||
| } | |||||
| template<> quat quat::fromeuler_xyz(vec3 const &v) | |||||
| { | |||||
| return fromeuler_generic(v, -1, 3, 2, 1); | |||||
| } | |||||
| template<> quat quat::fromeuler_xzy(vec3 const &v) | |||||
| { | |||||
| return fromeuler_generic(v, 1, 3, 1, 2); | |||||
| } | |||||
| template<> quat quat::fromeuler_yxz(vec3 const &v) | |||||
| { | |||||
| return fromeuler_generic(v, 1, 2, 3, 1); | |||||
| } | |||||
| template<> quat quat::fromeuler_yzx(vec3 const &v) | |||||
| { | |||||
| return fromeuler_generic(v, -1, 1, 3, 2); | |||||
| } | |||||
| template<> quat quat::fromeuler_zxy(vec3 const &v) | |||||
| { | |||||
| return fromeuler_generic(v, -1, 2, 1, 3); | |||||
| } | |||||
| template<> quat quat::fromeuler_zyx(vec3 const &v) | |||||
| { | |||||
| return fromeuler_generic(v, 1, 1, 2, 3); | |||||
| } | |||||
| template<> quat quat::fromeuler_xyz(float phi, float theta, float psi) | |||||
| { | |||||
| return quat::fromeuler_zyx(vec3(phi, theta, psi)); | |||||
| } | |||||
| template<> quat quat::fromeuler_xzy(float phi, float theta, float psi) | |||||
| { | |||||
| return quat::fromeuler_yxz(vec3(phi, theta, psi)); | |||||
| } | |||||
| template<> quat quat::fromeuler_yxz(float phi, float theta, float psi) | |||||
| { | |||||
| return quat::fromeuler_yxz(vec3(phi, theta, psi)); | |||||
| } | |||||
| { | |||||
| vec4 v1(c0 * c1 * c2, s0 * c1 * c2, c0 * s1 * c2, c0 * c1 * s2); | |||||
| vec4 v2(s0 * s1 * s2, -c0 * s1 * s2, s0 * c1 * s2, -s0 * s1 * c2); | |||||
| if ((2 + i - j) % 3) | |||||
| v1 -= v2; | |||||
| else | |||||
| v1 += v2; | |||||
| ret[0] = v1[0]; | |||||
| ret[1 + i] = v1[1]; | |||||
| ret[1 + j] = v1[2]; | |||||
| ret[4 - i - j] = v1[3]; | |||||
| } | |||||
| template<> quat quat::fromeuler_yzx(float phi, float theta, float psi) | |||||
| { | |||||
| return quat::fromeuler_yxz(vec3(phi, theta, psi)); | |||||
| return ret; | |||||
| } | } | ||||
| template<> quat quat::fromeuler_zxy(float phi, float theta, float psi) | |||||
| { | |||||
| return quat::fromeuler_yxz(vec3(phi, theta, psi)); | |||||
| } | |||||
| #define QUAT_FROMEULER_GENERIC(name, i, j, k) \ | |||||
| template<> quat quat::fromeuler_##name(vec3 const &v) \ | |||||
| { \ | |||||
| return quat_fromeuler_generic(v, i, j, k); \ | |||||
| } \ | |||||
| \ | |||||
| template<> quat quat::fromeuler_##name(float phi, float theta, float psi) \ | |||||
| { \ | |||||
| return quat::fromeuler_##name(vec3(phi, theta, psi)); \ | |||||
| } | |||||
| template<> quat quat::fromeuler_zyx(float phi, float theta, float psi) | |||||
| { | |||||
| return quat::fromeuler_yxz(vec3(phi, theta, psi)); | |||||
| } | |||||
| QUAT_FROMEULER_GENERIC(xyx, 0, 1, 0) | |||||
| QUAT_FROMEULER_GENERIC(xzx, 0, 2, 0) | |||||
| QUAT_FROMEULER_GENERIC(yxy, 1, 0, 1) | |||||
| QUAT_FROMEULER_GENERIC(yzy, 1, 2, 1) | |||||
| QUAT_FROMEULER_GENERIC(zxz, 2, 0, 2) | |||||
| QUAT_FROMEULER_GENERIC(zyz, 2, 1, 2) | |||||
| QUAT_FROMEULER_GENERIC(xyz, 0, 1, 2) | |||||
| QUAT_FROMEULER_GENERIC(xzy, 0, 2, 1) | |||||
| QUAT_FROMEULER_GENERIC(yxz, 1, 0, 2) | |||||
| QUAT_FROMEULER_GENERIC(yzx, 1, 2, 0) | |||||
| QUAT_FROMEULER_GENERIC(zxy, 2, 0, 1) | |||||
| QUAT_FROMEULER_GENERIC(zyx, 2, 1, 0) | |||||
| #undef QUAT_FROMEULER_GENERIC | |||||
| template<> mat4 mat4::lookat(vec3 eye, vec3 center, vec3 up) | template<> mat4 mat4::lookat(vec3 eye, vec3 center, vec3 up) | ||||
| { | { | ||||