- updated "how to build"
authorAkiko <akiko@linux-addicted.net>
Mon, 21 Oct 2013 15:49:37 +0000 (17:49 +0200)
committerAkiko <akiko@linux-addicted.net>
Mon, 21 Oct 2013 15:49:37 +0000 (17:49 +0200)
- fixed some move consructors/operators
- added Quaternion class template (the better way to do rotations in 3D space)

BUILDING
engine/Quaternion.hxx [new file with mode: 0644]
engine/Vector.hxx

index d900f94..b8336cd 100644 (file)
--- 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 (file)
index 0000000..e5652d6
--- /dev/null
@@ -0,0 +1,542 @@
+#pragma once
+
+#include <cmath>
+#include <iostream>
+#include <sstream>
+#include <type_traits>
+#include "Vector.hxx"
+
+template <typename MT>
+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<MT>& vec)
+    : sxyz{s, vec.x, vec.y, vec.z}
+    {
+    }
+
+    Quaternion(const Vector4<MT>& 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 <typename T>
+    Quaternion& operator+=(const T& val)
+    {
+        static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename T>
+    Quaternion operator+(const T& val) const
+    {
+        static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename T>
+    Quaternion& operator-=(const T& val)
+    {
+        static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename T>
+    Quaternion operator-(const T& val) const
+    {
+        static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename T>
+    Quaternion& operator*=(const T& val)
+    {
+        static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename T>
+    Quaternion operator*(const T& val) const
+    {
+        static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename T>
+    Quaternion& operator/=(const T& val)
+    {
+        static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+                       "ERROR: template parameter is not an integral or floating point type");
+
+        s /= val;
+        x /= val;
+        y /= val;
+        z /= val;
+
+        return *this;
+    }
+
+    template <typename T>
+    Quaternion operator/(const T& val) const
+    {
+        static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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<MT> rotatedVector3(const Vector3<MT>& 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<MT> vector3() const
+    {
+        return {x, y, z};
+    }
+
+    Vector4<MT> 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<MT> toVector3(const Quaternion& quat)
+    {
+        return {quat.x, quat.y, quat.z};
+    }
+
+    static Vector4<MT> toVector4(const Quaternion& quat)
+    {
+        return {quat.x, quat.y, quat.z, quat.s};
+    }
+};
+
+// --- global operators ---
+
+template <typename T>
+bool operator==(const Quaternion<T>& lhs, const Quaternion<T>& rhs)
+{
+    static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename T>
+bool operator!=(const Quaternion<T>& lhs, const Quaternion<T>& rhs)
+{
+    static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+                   "ERROR: template parameter is not an integral or floating point type");
+
+    return !(lhs == rhs);
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& lhs, const Quaternion<T>& rhs)
+{
+    static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+                   "ERROR: template parameter is not an integral or floating point type");
+
+    lhs << rhs.s << rhs.x << rhs.y << rhs.z;
+
+    return lhs;
+}
+
+template <typename T>
+std::istream& operator>>(std::istream& lhs, Quaternion<T>& rhs)
+{
+    static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+                   "ERROR: template parameter is not an integral or floating point type");
+
+    lhs >> rhs.s >> rhs.x >> rhs.y >> rhs.z;
+
+    return lhs;
+}
+
+// ---
+
+template <typename T>
+Quaternion<T> operator+(const Quaternion<T>& lhs, const Quaternion<T>& rhs)
+{
+    static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename Quat, typename Val>
+Quaternion<Quat> operator+(const Quaternion<Quat>& quat, const Val& val)
+{
+    static_assert (std::is_integral<Quat>::value || std::is_floating_point<Quat>::value ||
+                   std::is_integral<Val>::value || std::is_floating_point<Val>::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 <typename Val, typename Quat>
+Quaternion<Quat> operator+(const Val& val, const Quaternion<Quat>& quat)
+{
+    static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+                   std::is_integral<Quat>::value || std::is_floating_point<Quat>::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 <typename T>
+Quaternion<T> operator-(const Quaternion<T>& lhs, const Quaternion<T>& rhs)
+{
+    static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename Quat, typename Val>
+Quaternion<Quat> operator-(const Quaternion<Quat>& quat, const Val& val)
+{
+    static_assert (std::is_integral<Quat>::value || std::is_floating_point<Quat>::value ||
+                   std::is_integral<Val>::value || std::is_floating_point<Val>::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 <typename Val, typename Quat>
+Quaternion<Quat> operator-(const Val& val, const Quaternion<Quat>& quat)
+{
+    static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+                   std::is_integral<Quat>::value || std::is_floating_point<Quat>::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 <typename T>
+Quaternion<T> operator-(const Quaternion<T> rhs)
+{
+    static_assert (std::is_integral<T>::value || std::is_floating_point<T>::value,
+                   "ERROR: template parameter is not an integral or floating point type");
+
+    return {-rhs.s, -rhs.x, -rhs.y, -rhs.z};
+}
+
+// ---
+
+template <typename T>
+Quaternion<T> operator*(const Quaternion<T>& lhs, const Quaternion<T>& rhs)
+{
+    static_assert (std::is_integral<T>::value || std::is_floating_point<T>::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 <typename Quat, typename Val>
+Quaternion<Quat> operator*(const Quaternion<Quat>& quat, const Val& val)
+{
+    static_assert (std::is_integral<Quat>::value || std::is_floating_point<Quat>::value ||
+                   std::is_integral<Val>::value || std::is_floating_point<Val>::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 <typename Val, typename Quat>
+Quaternion<Quat> operator*(const Val& val, const Quaternion<Quat>& quat)
+{
+    static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+                   std::is_integral<Quat>::value || std::is_floating_point<Quat>::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 <typename Quat, typename Val>
+Quaternion<Quat>& operator/(const Quaternion<Quat>& quat, const Val& val)
+{
+    static_assert (std::is_integral<Quat>::value || std::is_floating_point<Quat>::value ||
+                   std::is_integral<Val>::value || std::is_floating_point<Val>::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 <typename Val, typename Quat>
+Quaternion<Quat>& operator/(const Val& val, const Quaternion<Quat>& quat)
+{
+    static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+                   std::is_integral<Quat>::value || std::is_floating_point<Quat>::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};
+}
index e2c9193..06f4aa5 100644 (file)
@@ -25,7 +25,7 @@ class Vector2 {
     static_assert (std::is_integral<MT>::value || std::is_floating_point<MT>::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 <typename T>
 bool operator==(const Vector2<T>& lhs, const Vector2<T>& rhs)
@@ -562,7 +562,7 @@ class Vector3 {
     static_assert (std::is_integral<MT>::value || std::is_floating_point<MT>::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 <typename T>
 bool operator==(const Vector3<T>& lhs, const Vector3<T>& rhs)
@@ -1158,7 +1158,7 @@ class Vector4 {
     static_assert (std::is_integral<MT>::value || std::is_floating_point<MT>::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 <typename T>
 bool operator==(const Vector4<T>& lhs, const Vector4<T>& rhs)