From 751b5973f688e39e4217fcb60ca6d6fe139d4de0 Mon Sep 17 00:00:00 2001 From: Akiko Date: Mon, 21 Oct 2013 17:49:37 +0200 Subject: [PATCH] - updated "how to build" - fixed some move consructors/operators - added Quaternion class template (the better way to do rotations in 3D space) --- BUILDING | 3 +- engine/Quaternion.hxx | 542 ++++++++++++++++++++++++++++++++++++++++++++++++++ engine/Vector.hxx | 54 ++--- 3 files changed, 570 insertions(+), 29 deletions(-) create mode 100644 engine/Quaternion.hxx diff --git a/BUILDING b/BUILDING index d900f94..b8336cd 100644 --- a/BUILDING +++ b/BUILDING @@ -1,8 +1,7 @@ You need: - cmake 2.8.8+ - Qt 5.1+ -- Irrlicht 1.8+ (is not used yet) -- a decent compiler (at lease gcc 4.8.x or better clang 3.3+) +- a decent compiler, at least a gcc 4.8.x or better clang 3.3+, because you need ver strong C++11 support here howto: - if you like, set clang as default ("export CC=/usr/bin/clang; export CXX=/usr/bin/clang++") diff --git a/engine/Quaternion.hxx b/engine/Quaternion.hxx new file mode 100644 index 0000000..e5652d6 --- /dev/null +++ b/engine/Quaternion.hxx @@ -0,0 +1,542 @@ +#pragma once + +#include +#include +#include +#include +#include "Vector.hxx" + +template +class Quaternion { +public: + // --- public data structurs --- + + union { + struct { + MT s; + MT x; + MT y; + MT z; + }; + MT sxyz[4]; + } __attribute__((packed)); + + // --- constructors and deconstructors --- + + Quaternion() + : sxyz{1, 0, 0, 0} + { + } + + Quaternion(const MT& val) + : sxyz{val, val, val, val} + { + } + + Quaternion(const MT& s, const MT& val) + : sxyz{s, val, val, val} + { + } + + Quaternion(const MT& s, const MT& x, const MT& y, const MT& z) + : sxyz{s, x, y, z} + { + } + + Quaternion(const MT& s, const Vector3& vec) + : sxyz{s, vec.x, vec.y, vec.z} + { + } + + Quaternion(const Vector4& vec) + : sxyz{vec.w, vec.x, vec.y, vec.z} + { + } + + Quaternion(const Quaternion& rhs) + : sxyz{rhs.s, rhs.x, rhs.y, rhs.z} + { + } + + Quaternion(Quaternion&& rhs) + : sxyz{std::move(rhs.s), std::move(rhs.x), std::move(rhs.y), std::move(rhs.z)} + { + } + + virtual ~Quaternion() + { + } + + // --- default operators --- + + Quaternion operator=(const Quaternion& rhs) + { + if (this != &rhs) + { + s = rhs.s; + x = rhs.x; + y = rhs.y; + z = rhs.z; + } + + return *this; + } + + Quaternion operator=(Quaternion&& rhs) + { + if (this != &rhs) + { + s = std::move(rhs.s); + x = std::move(rhs.x); + y = std::move(rhs.y); + z = std::move(rhs.z); + } + + return *this; + } + + bool operator==(const Quaternion& rhs) const + { + return s == rhs.s && x == rhs.x && y == rhs.y && z == rhs.z; + } + + bool operator!=(const Quaternion& rhs) const + { + return !(*this == rhs); + } + + const MT operator[](const size_t& index) const + { + return sxyz[index]; + } + + MT& operator[](const size_t& index) + { + return sxyz[index]; + } + + Quaternion& operator~() + { + s = -s; + x = -x; + y = -y; + z = -z; + + return *this; + } + + Quaternion operator-() const + { + return {-s, -x, -y, -z}; + } + + // --- other operators --- + + Quaternion& operator+=(const Quaternion& rhs) + { + s += rhs.s; + x += rhs.x; + y += rhs.y; + z += rhs.z; + + return *this; + } + + template + Quaternion& operator+=(const T& val) + { + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + s += val; + x += val; + y += val; + z += val; + + return *this; + } + + Quaternion operator+(const Quaternion& rhs) const + { + return {s + rhs.s, x + rhs.x, y + rhs.y, z + rhs.z}; + } + + template + Quaternion operator+(const T& val) const + { + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {s + val, x + val, y + val, z + val}; + } + + // --- + + Quaternion& operator-=(const Quaternion& rhs) + { + s -= rhs.s; + x -= rhs.x; + y -= rhs.y; + z -= rhs.z; + + return *this; + } + + template + Quaternion& operator-=(const T& val) + { + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + s -= val; + x -= val; + y -= val; + z -= val; + + return *this; + } + + Quaternion operator-(const Quaternion& rhs) const + { + return {s - rhs.s, x - rhs.x, y - rhs.y, z - rhs.z}; + } + + template + Quaternion operator-(const T& val) const + { + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {s - val, x - val, y - val, z - val}; + } + + // --- + + Quaternion& operator*=(const Quaternion& rhs) + { + *this = *this * rhs; + + return *this; + } + + template + Quaternion& operator*=(const T& val) + { + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + s *= val; + x *= val; + y *= val; + z *= val; + + return *this; + } + + Quaternion operator*(const Quaternion& rhs) const + { + const MT cs = (z + x) * (rhs.x + rhs.y); + const MT cy = (s - y) * (rhs.s + rhs.z); + const MT cz = (s + y) * (rhs.s - rhs.z); + const MT cx = cs + cy + cz; + const MT cq = 0.5 * (cx + (z - x) * (rhs.x - rhs.y)); + + return {cq - cs + (z - y) * (rhs.y - rhs.z), + cq - cx + (x + s) * (rhs.x + rhs.s), + cq - cy + (s - x) * (rhs.y + rhs.z), + cq - cz + (z + y) * (rhs.s - rhs.x)}; + } + + template + Quaternion operator*(const T& val) const + { + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {s * val, x * val, y * val, z * val}; + } + + // --- + // just to make it clear, there is no Q/Q division because quaternions are non-commutative + // (q1 * q2^-1 is not the same like q1^-1 * q2) + + template + Quaternion& operator/=(const T& val) + { + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + s /= val; + x /= val; + y /= val; + z /= val; + + return *this; + } + + template + Quaternion operator/(const T& val) const + { + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {s / val, x / val, y / val, z / val}; + } + + // --- public methods --- + + void conjugate() + { + sxyz = {s, -x, -y, -z}; + } + + Quaternion conjugated() const + { + return {s, -x, -y, -z}; + } + + bool isIdentity() const + { + return s == 1 && x == 0 && y == 0 && z == 0; + } + + bool isNull() const + { + return s == 0 && x == 0 && y == 0 && z == 0; + } + + MT length() const + { + return std::sqrt(s * s + x * x + y * y + z * z); + } + + MT lengthSquared() const + { + return {s * s + x * x + y * y + z * z}; + } + + void normalize() + { + *this /= std::sqrt(s * s + x * x + y * y + z * z); + } + + Quaternion normalized() const + { + return sxyz / std::sqrt(s * s + x * x + y * y + z * z); + } + + Vector3 rotatedVector3(const Vector3& vec) const + { + return (*this * Quaternion(0, vec) * conjugated()).vector3(); + } + + std::string string() const + { + std::stringstream result; + + result << s << ", " << x << "," << y << ", " << z; + + return result.str(); + } + + Vector3 vector3() const + { + return {x, y, z}; + } + + Vector4 vector4() const + { + return {x, y, z, s}; + } + + // --- static methods --- + + static std::string toString(const Quaternion& quat) + { + std::stringstream result; + + result << quat.s << ", " << quat.x << ", " << quat.y << ", " << quat.z; + + return result.str(); + } + + static Vector3 toVector3(const Quaternion& quat) + { + return {quat.x, quat.y, quat.z}; + } + + static Vector4 toVector4(const Quaternion& quat) + { + return {quat.x, quat.y, quat.z, quat.s}; + } +}; + +// --- global operators --- + +template +bool operator==(const Quaternion& lhs, const Quaternion& rhs) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return lhs.s == rhs.s && lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z; +} + +template +bool operator!=(const Quaternion& lhs, const Quaternion& rhs) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return !(lhs == rhs); +} + +template +std::ostream& operator<<(std::ostream& lhs, const Quaternion& rhs) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + lhs << rhs.s << rhs.x << rhs.y << rhs.z; + + return lhs; +} + +template +std::istream& operator>>(std::istream& lhs, Quaternion& rhs) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + lhs >> rhs.s >> rhs.x >> rhs.y >> rhs.z; + + return lhs; +} + +// --- + +template +Quaternion operator+(const Quaternion& lhs, const Quaternion& rhs) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {lhs.s + rhs.s, lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z}; +} + +template +Quaternion operator+(const Quaternion& quat, const Val& val) +{ + static_assert (std::is_integral::value || std::is_floating_point::value || + std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {quat.s + val, quat.x + val, quat.y + val, quat.z + val}; +} + +template +Quaternion operator+(const Val& val, const Quaternion& quat) +{ + static_assert (std::is_integral::value || std::is_floating_point::value || + std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {val + quat.s, val + quat.x, val + quat.y, val + quat.z}; +} + +// --- + +template +Quaternion operator-(const Quaternion& lhs, const Quaternion& rhs) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {lhs.s - rhs.s, lhs.x - rhs.x, lhs.y - rhs.y, lhs.x - rhs.y}; +} + +template +Quaternion operator-(const Quaternion& quat, const Val& val) +{ + static_assert (std::is_integral::value || std::is_floating_point::value || + std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {quat.s - val, quat.x - val, quat.y - val, quat.z - val}; +} + +template +Quaternion operator-(const Val& val, const Quaternion& quat) +{ + static_assert (std::is_integral::value || std::is_floating_point::value || + std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {val - quat.s, val - quat.x, val - quat.y, val - quat.z}; +} + +template +Quaternion operator-(const Quaternion rhs) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {-rhs.s, -rhs.x, -rhs.y, -rhs.z}; +} + +// --- + +template +Quaternion operator*(const Quaternion& lhs, const Quaternion& rhs) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + const T cs = (lhs.z + lhs.x) * (rhs.x + rhs.y); + const T cy = (lhs.s - lhs.y) * (rhs.s + rhs.z); + const T cz = (lhs.s + lhs.y) * (rhs.s - rhs.z); + const T cx = cs + cy + cz; + const T cq = 0.5 * (cx + (lhs.z - lhs.x) * (rhs.x - rhs.y)); +} + +template +Quaternion operator*(const Quaternion& quat, const Val& val) +{ + static_assert (std::is_integral::value || std::is_floating_point::value || + std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {quat.s * val, quat.x * val, quat.y * val, quat.z * val}; +} + +template +Quaternion operator*(const Val& val, const Quaternion& quat) +{ + static_assert (std::is_integral::value || std::is_floating_point::value || + std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {val + quat.s, val * quat.x, val * quat.y, val * quat.z}; +} + +// --- + +template +Quaternion& operator/(const Quaternion& quat, const Val& val) +{ + static_assert (std::is_integral::value || std::is_floating_point::value || + std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {quat.s / val, quat.x / val, quat.y / val, quat.z / val}; +} + +template +Quaternion& operator/(const Val& val, const Quaternion& quat) +{ + static_assert (std::is_integral::value || std::is_floating_point::value || + std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {val / quat.s, val / quat.x, val / quat.y, val / quat.z}; +} diff --git a/engine/Vector.hxx b/engine/Vector.hxx index e2c9193..06f4aa5 100644 --- a/engine/Vector.hxx +++ b/engine/Vector.hxx @@ -25,7 +25,7 @@ class Vector2 { static_assert (std::is_integral::value || std::is_floating_point::value, "ERROR: template parameter is not an integral or floating point type"); public: - // --- data structures --- + // --- Vector2: data structures --- union { struct { @@ -35,7 +35,7 @@ public: MT xy[2]; } __attribute__((packed)); - // --- constructors and deconstructors --- + // --- Vector2: constructors and deconstructors --- Vector2() : xy{0, 0} @@ -67,7 +67,7 @@ public: { } - Vector2(const Vector2&& rhs) + Vector2(Vector2&& rhs) : xy{std::move(rhs.x), std::move(rhs.y)} { } @@ -76,7 +76,7 @@ public: { } - // --- default operators --- + // --- Vector2: default operators --- Vector2& operator=(const Vector2& rhs) { @@ -89,7 +89,7 @@ public: return *this; } - Vector2& operator=(const Vector2&& rhs) + Vector2& operator=(Vector2&& rhs) { if (this != &rhs) { @@ -133,7 +133,7 @@ public: return {-x, -y}; } - // --- other operators --- + // --- Vector2: other operators --- Vector2& operator+=(const Vector2& rhs) { @@ -277,7 +277,7 @@ public: return {x / val, y / val}; } - // --- public methods --- + // --- Vector2: public methods --- MT distanceToLine(const Vector2& origin, const Vector2& direction) const { @@ -353,7 +353,7 @@ public: return {x, y, 0, 0}; } - // --- static methods --- + // --- Vector2: static methods --- static MT toDotProduct(const Vector2& vec1, const Vector2& vec2) { @@ -380,7 +380,7 @@ public: } }; -// --- global operators --- +// --- Vector2: global operators --- template bool operator==(const Vector2& lhs, const Vector2& rhs) @@ -562,7 +562,7 @@ class Vector3 { static_assert (std::is_integral::value || std::is_floating_point::value, "ERROR: template parameter is not an integral or floating point type"); public: - // --- data structures --- + // --- Vector3: data structures --- union { struct { @@ -573,7 +573,7 @@ public: MT xyz[3]; } __attribute__((packed)); - // --- constructors and deconstructors --- + // --- Vector3: constructors and deconstructors --- Vector3() : xyz{0, 0, 0} @@ -610,7 +610,7 @@ public: { } - Vector3(const Vector3&& rhs) + Vector3(Vector3&& rhs) : xyz{std::move(rhs.x), std::move(rhs.y), std::move(rhs.z)} { } @@ -619,7 +619,7 @@ public: { } - // --- default operators --- + // --- Vector3: default operators --- Vector3& operator=(const Vector3& rhs) { @@ -633,7 +633,7 @@ public: return *this; } - Vector3& operator=(const Vector3&& rhs) + Vector3& operator=(Vector3&& rhs) { if (this != &rhs) { @@ -679,7 +679,7 @@ public: return {-x, -y, -z}; } - // --- other operators --- + // --- Vector3: other operators --- Vector3& operator+=(const Vector3& rhs) { @@ -831,7 +831,7 @@ public: return {x / val, y / val, z / val}; } - // --- public methods --- + // --- Vector3: public methods --- Vector3 crossProduct(const Vector3& vec) const { @@ -932,7 +932,7 @@ public: return {x, y, z, 0}; } - // --- static methods --- + // --- Vector3: static methods --- static Vector3 toCrossProduct(const Vector3& vec1, const Vector3& vec2) { @@ -976,7 +976,7 @@ public: } }; -// --- global operators --- +// --- Vector3: global operators --- template bool operator==(const Vector3& lhs, const Vector3& rhs) @@ -1158,7 +1158,7 @@ class Vector4 { static_assert (std::is_integral::value || std::is_floating_point::value, "ERROR: template parameter is not an integral or floating point type"); public: - // --- data structures --- + // --- Vector4: data structures --- union { struct { @@ -1170,7 +1170,7 @@ public: MT xyzw[4]; } __attribute__((packed)); - // --- constructors and deconstructors --- + // --- Vector4: constructors and deconstructors --- Vector4() : xyzw{0, 0, 0, 0} @@ -1217,7 +1217,7 @@ public: { } - Vector4(const Vector4&& rhs) + Vector4(Vector4&& rhs) : xyzw{std::move(rhs.x), std::move(rhs.y), std::move(rhs.z), std::move(rhs.w)} { } @@ -1226,7 +1226,7 @@ public: { } - // --- default operators --- + // --- Vector4: default operators --- Vector4& operator=(const Vector4& rhs) { @@ -1241,7 +1241,7 @@ public: return *this; } - Vector4& operator=(const Vector4&& rhs) + Vector4& operator=(Vector4&& rhs) { if (this != &rhs) { @@ -1289,7 +1289,7 @@ public: return {-x, -y, -z, -w}; } - // --- other operators --- + // --- Vector4: other operators --- Vector4& operator+=(const Vector4& rhs) { @@ -1449,7 +1449,7 @@ public: return {x / val, y / val, z / val, w / val}; } - // --- public methods --- + // --- Vector4: public methods --- MT dotProduct(const Vector4& vec) const { @@ -1502,7 +1502,7 @@ public: return {x, y, z}; } - // --- static methods --- + // --- Vector4: static methods --- static MT toDotProduct(const Vector4& vec1, const Vector4& vec2) { @@ -1529,7 +1529,7 @@ public: } }; -// --- global operators --- +// --- Vector4: global operators --- template bool operator==(const Vector4& lhs, const Vector4& rhs) -- 2.15.1