--- /dev/null
+#pragma once
+
+/*
+ * Using Qt here would be nuts. Qt's vector components are no templates and I need some more control of that very
+ * important part of the engine code. So I made my own vector classes (also a bit more flexible) ...
+ * - Vector2 for GUI and 2D stuff
+ * - Vector3 for the common 3D stuff
+ * - Vector4 for the matrix and quaternion magic
+ * ~ Akiko ~
+ */
+
+#include <cmath>
+#include <iostream>
+#include <sstream>
+#include <type_traits>
+
+template <typename MT> class Vector2;
+template <typename MT> class Vector3;
+template <typename MT> class Vector4;
+
+// ****************************************************************************************************************** //
+
+template <typename MT>
+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 ---
+
+ union {
+ struct {
+ MT X;
+ MT Y;
+ };
+ MT XY[2];
+ } __attribute__((packed));
+
+ // --- constructors and deconstructors ---
+
+ Vector2()
+ : XY{0, 0}
+ {
+ }
+
+ Vector2(const MT& val)
+ : XY{val, val}
+ {
+ }
+
+ Vector2(const MT& x, const MT& y)
+ : XY{x, y}
+ {
+ }
+
+ Vector2(const Vector3<MT>& vec)
+ : XY{vec.X, vec.Y}
+ {
+ }
+
+ Vector2(const Vector4<MT>& vec)
+ : XY{vec.X, vec.Y}
+ {
+ }
+
+ Vector2(const Vector2& rhs)
+ : XY{rhs.X, rhs.Y}
+ {
+ }
+
+ Vector2(const Vector2&& rhs)
+ : XY{std::move(rhs.X), std::move(rhs.Y)}
+ {
+ }
+
+ virtual ~Vector2()
+ {
+ }
+
+ // --- default operators ---
+
+ Vector2& operator=(const Vector2& rhs)
+ {
+ if (this != &rhs)
+ {
+ X = rhs.X;
+ Y = rhs.Y;
+ }
+
+ return *this;
+ }
+
+ Vector2& operator=(const Vector2&& rhs)
+ {
+ if (this != &rhs)
+ {
+ X = std::move(rhs.X);
+ Y = std::move(rhs.Y);
+ }
+
+ return *this;
+ }
+
+ bool operator==(const Vector2& rhs)
+ {
+ return X == rhs.X && Y == rhs.Y;
+ }
+
+ bool operator!=(const Vector2& rhs)
+ {
+ return !(*this == rhs);
+ }
+
+ const MT operator[](const size_t& index) const
+ {
+ return XY[index];
+ }
+
+ MT& operator[](const size_t& index)
+ {
+ return XY[index];
+ }
+
+ Vector2& operator~()
+ {
+ X = -X;
+ Y = -Y;
+
+ return *this;
+ }
+
+ Vector2 operator-() const
+ {
+ return {-X, -Y};
+ }
+
+ // --- other operators ---
+
+ Vector2& operator+=(const Vector2& rhs)
+ {
+ X += rhs.X;
+ Y += rhs.Y;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector2& 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");
+
+ X += val;
+ Y += val;
+
+ return *this;
+ }
+
+ Vector2 operator+(const Vector2& rhs) const
+ {
+ return {X + rhs.X, Y + rhs.Y};
+ }
+
+ template <typename T>
+ Vector2 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 {X + val, Y + val};
+ }
+
+ // ---
+
+ Vector2& operator-=(const Vector2& rhs)
+ {
+ X -= rhs.X;
+ Y -= rhs.Y;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector2& 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");
+
+ X -= val;
+ Y -= val;
+
+ return *this;
+ }
+
+ Vector2 operator-(const Vector2& rhs) const
+ {
+ return {X - rhs.X, Y - rhs.Y};
+ }
+
+ template <typename T>
+ Vector2 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");
+
+ return {X - val, Y - val};
+ }
+
+ // ---
+
+ Vector2& operator*=(const Vector2& rhs)
+ {
+ X *= rhs.X;
+ Y *= rhs.Y;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector2& 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");
+
+ X *= val;
+ Y *= val;
+
+ return *this;
+ }
+
+ Vector2 operator*(const Vector2& rhs) const
+ {
+ return {X * rhs.X, Y * rhs.Y};
+ }
+
+ template <typename T>
+ Vector2 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");
+
+ return {X * val, Y * val};
+ }
+
+ // ---
+
+ Vector2& operator/=(const Vector2& rhs)
+ {
+ X /= rhs.X;
+ Y /= rhs.Y;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector2& 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");
+
+ X /= val;
+ Y /= val;
+
+ return *this;
+ }
+
+ Vector2 operator/(const Vector2& rhs) const
+ {
+ return {X / rhs.X, Y / rhs.Y};
+ }
+
+ template <typename T>
+ Vector2 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 {X / val, Y / val};
+ }
+
+ // --- public methods ---
+
+ MT distanceToLine(const Vector2& origin, const Vector2& direction) const
+ {
+ if (direction.isNull())
+ return (*this - origin).length();
+
+ return (*this - (origin + dotProduct(*this - origin, direction) * direction)).length();
+ }
+
+ MT distanceToLinePoints(const Vector2& point1, const Vector2& point2) const
+ {
+ const Vector2 direction = point2 - point1;
+
+ if (direction.isNull())
+ return (*this - point1).length();
+
+ return (*this - (point1 + dotProduct(*this - point1, direction) * direction)).length();
+ }
+
+ MT distanceToPoint(const Vector2& point) const
+ {
+ return (*this - point).length();
+ }
+
+ MT dotProduct(const Vector2& vec) const
+ {
+ return X * vec.X + Y * vec.Y;
+ }
+
+ bool isNull() const
+ {
+ return X == 0 && Y == 0;
+ }
+
+ MT length() const
+ {
+ return std::sqrt(X * X + Y * Y);
+ }
+
+ MT lengthSquared() const
+ {
+ return X * X + Y * Y;
+ }
+
+ void normalize()
+ {
+ *this /= std::sqrt(X * X + Y * Y);
+ }
+
+ Vector2 normalized() const
+ {
+ const MT len = std::sqrt(X * X + Y * Y);
+
+ return {X / len, Y / len};
+ }
+
+ std::string string() const
+ {
+ std::stringstream result;
+
+ result << X << ", " << Y;
+
+ return result.str();
+ }
+
+ Vector3<MT> vector3() const
+ {
+ return {X, Y, 0};
+ }
+
+ Vector4<MT> vector4() const
+ {
+ return {X, Y, 0, 0};
+ }
+
+ // --- static methods ---
+
+ static MT toDotProduct(const Vector2& vec1, const Vector2& vec2)
+ {
+ return vec1.X * vec2.X + vec1.Y * vec2.Y;
+ }
+
+ static std::string toString(const Vector2& vec)
+ {
+ std::stringstream result;
+
+ result << vec.X << ", " << vec.Y;
+
+ return result.str();
+ }
+
+ static Vector3<MT> toVector3(const Vector2& vec)
+ {
+ return {vec.X, vec.Y, 0};
+ }
+
+ static Vector4<MT> toVector4(const Vector2& vec)
+ {
+ return {vec.X, vec.Y, 0, 0};
+ }
+};
+
+// --- global operators ---
+
+template <typename T>
+bool operator==(const Vector2<T>& lhs, const Vector2<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.X == rhs.X && lhs.Y == rhs.Y;
+}
+
+template <typename T>
+bool operator!=(const Vector2<T> lhs, const Vector2<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 Vector2<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.X << rhs.Y;
+
+ return lhs;
+}
+
+template <typename T>
+std::istream& operator>>(std::istream& lhs, Vector2<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.X >> rhs.Y;
+
+ return lhs;
+}
+
+// ---
+
+template <typename T>
+Vector2<T> operator+(const Vector2<T>& vec1, const Vector2<T>& vec2)
+{
+ 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 {vec1.X + vec2.X, vec1.Y + vec2.Y};
+}
+
+template <typename Vec, typename Val>
+Vector2<Vec> operator+(const Vector2<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X + val, vec.Y + val};
+}
+
+template <typename Val, typename Vec>
+Vector2<Vec> operator+(const Val& val, const Vector2<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val + vec.X, val + vec.Y};
+}
+
+// ---
+
+template <typename T>
+Vector2<T> operator-(const Vector2<T>& vec1, const Vector2<T>& vec2)
+{
+ 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 {vec1.X - vec2.X, vec1.Y - vec2.Y};
+}
+
+template <typename Vec, typename Val>
+Vector2<Vec> operator-(const Vector2<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X - val, vec.Y - val};
+}
+
+template <typename Val, typename Vec>
+Vector2<Vec> operator-(const Val& val, const Vector2<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val - vec.X, val - vec.Y};
+}
+
+template <typename T>
+Vector2<T> operator-(const Vector2<T>& vec)
+{
+ 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 {-vec.X, -vec.Y};
+}
+
+// ---
+
+template <typename T>
+Vector2<T> operator*(const Vector2<T>& vec1, const Vector2<T>& vec2)
+{
+ 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 {vec1.X * vec2.X, vec1.Y * vec2.Y};
+}
+
+template <typename Vec, typename Val>
+Vector2<Vec> operator*(const Vector2<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X * val, vec.Y * val};
+}
+
+template <typename Val, typename Vec>
+Vector2<Vec> operator*(const Val& val, const Vector2<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val * vec.X, val + vec.Y};
+}
+
+// ---
+
+template <typename T>
+Vector2<T> operator/(const Vector2<T>& vec1, const Vector2<T>& vec2)
+{
+ 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 {vec1.X / vec2.X, vec1.Y / vec2.Y};
+}
+
+template <typename Vec, typename Val>
+Vector2<Vec> operator/(const Vector2<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X / val, vec.Y / val};
+}
+
+template <typename Val, typename Vec>
+Vector2<Vec> operator/(const Val& val, const Vector2<Vec> vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val / vec.X, val / vec.Y};
+}
+
+// ****************************************************************************************************************** //
+
+template <typename MT>
+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 ---
+
+ union {
+ struct {
+ MT X;
+ MT Y;
+ MT Z;
+ };
+ MT XYZ[3];
+ } __attribute__((packed));
+
+ // --- constructors and deconstructors ---
+
+ Vector3()
+ : XYZ{0, 0, 0}
+ {
+ }
+
+ Vector3(const MT& val)
+ : XYZ{val, val, val}
+ {
+ }
+
+ Vector3(const MT& x, const MT& y, const MT& z)
+ : XYZ{x, y, z}
+ {
+ }
+
+ Vector3(const Vector2<MT>& vec)
+ : XYZ{vec.X, vec.Y, 0}
+ {
+ }
+
+ Vector3(const Vector2<MT>& vec, const MT& val)
+ : XYZ{vec.X, vec.Y, val}
+ {
+ }
+
+ Vector3(const Vector4<MT>& vec)
+ : XYZ{vec.X, vec.Y, vec.Z}
+ {
+ }
+
+ Vector3(const Vector3& rhs)
+ : XYZ{rhs.X, rhs.Y, rhs.Z}
+ {
+ }
+
+ Vector3(const Vector3&& rhs)
+ : XYZ{std::move(rhs.X), std::move(rhs.Y), std::move(rhs.Z)}
+ {
+ }
+
+ virtual ~Vector3()
+ {
+ }
+
+ // --- default operators ---
+
+ Vector3& operator=(const Vector3& rhs)
+ {
+ if (this != &rhs)
+ {
+ X = rhs.X;
+ Y = rhs.Y;
+ Z = rhs.Z;
+ }
+
+ return *this;
+ }
+
+ Vector3& operator=(const Vector3&& rhs)
+ {
+ if (this != &rhs)
+ {
+ X = std::move(rhs.X);
+ Y = std::move(rhs.Y);
+ Z = std::move(rhs.Z);
+ }
+
+ return *this;
+ }
+
+ bool operator==(const Vector3& rhs) const
+ {
+ return X == rhs.X && Y == rhs.Y && Z == rhs.Z;
+ }
+
+ bool operator!=(const Vector3& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ const MT operator[](const size_t& index) const
+ {
+ return XYZ[index];
+ }
+
+ MT& operator[](const size_t& index)
+ {
+ return XYZ[index];
+ }
+
+ Vector3& operator~()
+ {
+ X = -X;
+ Y = -Y;
+ Z = -Z;
+
+ return *this;
+ }
+
+ Vector3 operator-() const
+ {
+ return {-X, -Y, -Z};
+ }
+
+ // --- other operators ---
+
+ Vector3& operator+=(const Vector3& rhs)
+ {
+ X += rhs.X;
+ Y += rhs.Y;
+ Z += rhs.Z;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector3& 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");
+
+ X += val;
+ Y += val;
+ Z += val;
+
+ return *this;
+ }
+
+ Vector3 operator+(const Vector3& rhs) const
+ {
+ return {X + rhs.X, Y + rhs.Y, Z + rhs.Z};
+ }
+
+ template <typename T>
+ Vector3 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 {X + val, Y + val, Z + val};
+ }
+
+ // ---
+
+ Vector3& operator-=(const Vector3& rhs)
+ {
+ X -= rhs.X;
+ Y -= rhs.Y;
+ Z -= rhs.Z;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector3& 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");
+
+ X -= val;
+ Y -= val;
+ Z -= val;
+
+ return *this;
+ }
+
+ Vector3 operator-(const Vector3& rhs) const
+ {
+ return {X - rhs.X, Y - rhs.Y, Z - rhs.Z};
+ }
+
+ template <typename T>
+ Vector3 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 {X - val, Y - val, Z - val};
+ }
+
+ // ---
+
+ Vector3& operator*=(const Vector3& rhs)
+ {
+ X *= rhs.X;
+ Y *= rhs.Y;
+ Z *= rhs.Z;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector3& 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");
+
+ X *= val;
+ Y *= val;
+ Z *= val;
+
+ return *this;
+ }
+
+ Vector3 operator*(const Vector3& rhs) const
+ {
+ return {X * rhs.X, Y * rhs.Y, Z * rhs.Z};
+ }
+
+ template <typename T>
+ Vector3 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 {X * val, Y * val, Z * val};
+ }
+
+ // ---
+
+ Vector3& operator/=(const Vector3& rhs)
+ {
+ X /= rhs.X;
+ Y /= rhs.Y;
+ Z /= rhs.Z;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector3& 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");
+
+ X /= val;
+ Y /= val;
+ Z /= val;
+
+ return *this;
+ }
+
+ Vector3 operator/(const Vector3& rhs) const
+ {
+ return {X / rhs.X, Y / rhs.Y, Z / rhs.Z};
+ }
+
+ template <typename T>
+ Vector3 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 {X / val, Y / val, Z / val};
+ }
+
+ // --- public methods ---
+
+ Vector3 crossProduct(const Vector3& vec) const
+ {
+ return {Y * vec.Z - Z * vec.Y, Z * vec.X - X * vec.Z, X * vec.Y - Y * vec.X};
+ }
+
+ MT distanceToLine(const Vector3& origin, const Vector3& direction) const
+ {
+ if (direction.isNull())
+ return (*this - origin).length();
+
+ return (*this - (origin + dotProduct(*this - origin, direction) * direction)).length();
+ }
+
+ MT distanceToLinePoints(const Vector3& point1, const Vector3& point2) const
+ {
+ const Vector3 direction = point2 - point1;
+
+ if (direction.isNull())
+ return (*this - point1).length();
+
+ return (*this - (point1 + dotProduct(*this - point1, direction) * direction)).length();
+ }
+
+ MT distanceToPlane(const Vector3& origin, const Vector3& normal) const
+ {
+ return dotProduct(*this - origin, normal);
+ }
+
+ MT distanceToPlane(const Vector3& point1, const Vector3& point2, const Vector3& point3) const
+ {
+ return dotProduct(*this - point1, Vector3::normal(point2 - point1, point3 - point1));
+ }
+
+ MT distanceToPoint(const Vector3& point) const
+ {
+ return (*this - point).length();
+ }
+
+ MT dotProduct(const Vector3& vec) const
+ {
+ return X * vec.X + Y * vec.Y + Z * vec.Z;
+ }
+
+ bool isNull() const
+ {
+ return X == 0 && Y == 0 && Z == 0;
+ }
+
+ MT length() const
+ {
+ return std::sqrt(X * X + Y * Y + Z * Z);
+ }
+
+ MT lengthSquared() const
+ {
+ return X * X + Y * Y + Z * Z;
+ }
+
+ Vector3 normal(const Vector3& vec) const
+ {
+ return crossProduct(vec).normalized();
+ }
+
+ Vector3 normal(const Vector3& point2, const Vector3& point3) const
+ {
+ return crossProduct(point2 - *this, point3 - *this).normalized();
+ }
+
+ void normalize()
+ {
+ *this /= std::sqrt(X * X + Y * Y + Z * Z);
+ }
+
+ Vector3 normalized() const
+ {
+ const MT len = std::sqrt(X * X + Y * Y + Z * Z);
+
+ return {X / len, Y / len, Z / len};
+ }
+
+ std::string string() const
+ {
+ std::stringstream result;
+
+ result << X << ", " << Y << ", " << Z;
+
+ return result.str();
+ }
+
+ Vector2<MT> vector2() const
+ {
+ return {X, Y};
+ }
+
+ Vector4<MT> vector4() const
+ {
+ return {X, Y, Z, 0};
+ }
+
+ // --- static methods ---
+
+ static Vector3 toCrossProduct(const Vector3& vec1, const Vector3& vec2)
+ {
+ return {vec1.Y * vec2.Z - vec1.Z * vec2.Y,
+ vec1.Z * vec2.X - vec1.X * vec2.Z,
+ vec1.X * vec2.Y - vec1.Y * vec2.X};
+ }
+
+ static MT toDotProduct(const Vector3& vec1, const Vector3& vec2)
+ {
+ return vec1.X * vec2.X + vec1.Y * vec2.Y + vec1.Z * vec2.Z;
+ }
+
+ static Vector3 toNormal(const Vector3& vec1, const Vector3& vec2)
+ {
+ return toCrossProduct(vec1, vec2).normalized();
+ }
+
+ static Vector3 toNormal(const Vector3& point1, const Vector3& point2, const Vector3& point3)
+ {
+ return toCrossProduct(point2 - point1, point3 - point1).normalized();
+ }
+
+ static std::string toString(const Vector3& vec)
+ {
+ std::stringstream result;
+
+ result << vec.X << ", " << vec.Y << ", " << vec.Z;
+
+ return result.str();
+ }
+
+ static Vector2<MT> toVector2(const Vector3& vec)
+ {
+ return {vec.X, vec.Y};
+ }
+
+ static Vector4<MT> toVector4(const Vector3& vec)
+ {
+ return {vec.X, vec.Y, vec.Z, 0};
+ }
+};
+
+// --- global operators ---
+
+template <typename T>
+bool operator==(const Vector3<T>& lhs, const Vector3<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.X == rhs.X && lhs.Y == rhs.Y && lhs.Z == rhs.Z;
+}
+
+template <typename T>
+bool operator!=(const Vector3<T> lhs, const Vector3<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 Vector3<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.X << rhs.Y << rhs.Z;
+
+ return lhs;
+}
+
+template <typename T>
+std::istream& operator>>(std::istream& lhs, Vector3<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.X >> rhs.Y >> rhs.Z;
+
+ return lhs;
+}
+
+// ---
+
+template <typename T>
+Vector3<T> operator+(const Vector3<T>& vec1, const Vector3<T>& vec2)
+{
+ 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 {vec1.X + vec2.X, vec1.Y + vec2.Y, vec1.Z + vec2.Z};
+}
+
+template <typename Vec, typename Val>
+Vector3<Vec> operator+(const Vector3<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X + val, vec.Y + val, vec.Z + val};
+}
+
+template <typename Val, typename Vec>
+Vector3<Vec> operator+(const Val& val, const Vector3<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val + vec.X, val + vec.Y, val + vec.Z};
+}
+
+// ---
+
+template <typename T>
+Vector3<T> operator-(const Vector3<T>& vec1, const Vector3<T>& vec2)
+{
+ 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 {vec1.X - vec2.X, vec1.Y - vec2.Y, vec1.Z - vec2.Z};
+}
+
+template <typename Vec, typename Val>
+Vector3<Vec> operator-(const Vector3<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X - val, vec.Y - val, vec.Z - val};
+}
+
+template <typename Val, typename Vec>
+Vector3<Vec> operator-(const Val& val, const Vector3<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val - vec.X, val - vec.Y, val - vec.Z};
+}
+
+template <typename T>
+Vector3<T> operator-(const Vector3<T>& vec)
+{
+ 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 {-vec.X, -vec.Y, -vec.Z};
+}
+
+// ---
+
+template <typename T>
+Vector3<T> operator*(const Vector3<T>& vec1, const Vector3<T>& vec2)
+{
+ 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 {vec1.X * vec2.X, vec1.Y * vec2.Y, vec1.Z * vec2.Z};
+}
+
+template <typename Vec, typename Val>
+Vector3<Vec> operator*(const Vector3<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X * val, vec.Y * val, vec.Z * val};
+}
+
+template <typename Val, typename Vec>
+Vector3<Vec> operator*(const Val& val, const Vector3<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val * vec.X, val + vec.Y, val * vec.Z};
+}
+
+// ---
+
+template <typename T>
+Vector3<T> operator/(const Vector3<T>& vec1, const Vector3<T>& vec2)
+{
+ 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 {vec1.X / vec2.X, vec1.Y / vec2.Y, vec1.Z / vec2.Z};
+}
+
+template <typename Vec, typename Val>
+Vector3<Vec> operator/(const Vector3<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X / val, vec.Y / val, vec.Z / val};
+}
+
+template <typename Val, typename Vec>
+Vector3<Vec> operator/(const Val& val, const Vector3<Vec> vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val / vec.X, val / vec.Y, val / vec.Z};
+}
+
+// ****************************************************************************************************************** //
+
+template <typename MT>
+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 ---
+
+ union {
+ struct {
+ MT X;
+ MT Y;
+ MT Z;
+ MT W;
+ };
+ MT XYZW[4];
+ } __attribute__((packed));
+
+ // --- constructors and deconstructors ---
+
+ Vector4()
+ : XYZW{0, 0, 0, 0}
+ {
+ }
+
+ Vector4(const MT& val)
+ : XYZW{val, val, val, val}
+ {
+ }
+
+ Vector4(const MT& x, const MT& y, const MT& z, const MT& w)
+ : XYZW{x, y, z, w}
+ {
+ }
+
+ Vector4(const Vector2<MT>& vec)
+ : XYZW{vec.X, vec.Y, 0, 0}
+ {
+ }
+
+ Vector4(const Vector2<MT>& vec, const MT& val1, const MT& val2)
+ : XYZW{vec.X, vec.Y, val1, val2}
+ {
+ }
+
+ Vector4(const Vector2<MT>& vec1, const Vector2<MT>& vec2)
+ : XYZW{vec1.X, vec1.Y, vec2.X, vec2.Y}
+ {
+ }
+
+ Vector4(const Vector3<MT>& vec)
+ : XYZW{vec.X, vec.Y, vec.Z, 0}
+ {
+ }
+
+ Vector4(const Vector3<MT>& vec, const MT& val)
+ : XYZW{vec.X, vec.Y, vec.Z, val}
+ {
+ }
+
+ Vector4(const Vector4& rhs)
+ : XYZW{rhs.X, rhs.Y, rhs.Z, rhs.W}
+ {
+ }
+
+ Vector4(const Vector4&& rhs)
+ : XYZW{std::move(rhs.X), std::move(rhs.Y), std::move(rhs.Z), std::move(rhs.W)}
+ {
+ }
+
+ virtual ~Vector4()
+ {
+ }
+
+ // --- default operators ---
+
+ Vector4& operator=(const Vector4& rhs)
+ {
+ if (this != &rhs)
+ {
+ X = rhs.X;
+ Y = rhs.Y;
+ Z = rhs.Z;
+ W = rhs.W;
+ }
+
+ return *this;
+ }
+
+ Vector4& operator=(const Vector4&& rhs)
+ {
+ if (this != &rhs)
+ {
+ X = std::move(rhs.X);
+ Y = std::move(rhs.Y);
+ Z = std::move(rhs.Z);
+ W = std::move(rhs.W);
+ }
+
+ return *this;
+ }
+
+ bool operator==(const Vector4& rhs) const
+ {
+ return X == rhs.X && Y == rhs.Y && Z == rhs.Z && W == rhs.W;
+ }
+
+ bool operator!=(const Vector4& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ const MT operator[](const size_t& index) const
+ {
+ return XYZW[index];
+ }
+
+ MT& operator[](const size_t& index)
+ {
+ return XYZW[index];
+ }
+
+ Vector4& operator~()
+ {
+ X = -X;
+ Y = -Y;
+ Z = -Z;
+ W = -W;
+
+ return *this;
+ }
+
+ Vector4 operator-() const
+ {
+ return {-X, -Y, -Z, -W};
+ }
+
+ // --- other operators ---
+
+ Vector4& operator+=(const Vector4& rhs)
+ {
+ X += rhs.X;
+ Y += rhs.Y;
+ Z += rhs.Z;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector4& 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");
+
+ X += val;
+ Y += val;
+ Z += val;
+ W += val;
+
+ return *this;
+ }
+
+ Vector4 operator+(const Vector4& rhs) const
+ {
+ return {X + rhs.X, Y + rhs.Y, Z + rhs.Z, W + rhs.W};
+ }
+
+ template <typename T>
+ Vector4 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 {X + val, Y + val, Z + val, W + val};
+ }
+
+ // ---
+
+ Vector4& operator-=(const Vector4& rhs)
+ {
+ X -= rhs.X;
+ Y -= rhs.Y;
+ Z -= rhs.Z;
+ W -= rhs.W;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector4& 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");
+
+ X -= val;
+ Y -= val;
+ Z -= val;
+ W -= val;
+
+ return *this;
+ }
+
+ Vector4 operator-(const Vector4& rhs) const
+ {
+ return {X - rhs.X, Y - rhs.Y, Z - rhs.Z, W - rhs.W};
+ }
+
+ template <typename T>
+ Vector4 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 {X - val, Y - val, Z - val, W - val};
+
+ }
+
+ // ---
+
+ Vector4& operator*=(const Vector4& rhs)
+ {
+ X *= rhs.X;
+ Y *= rhs.Y;
+ Z *= rhs.Z;
+ W *= rhs.W;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector4& 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");
+
+ X *= val;
+ Y *= val;
+ Z *= val;
+ W *= val;
+
+ return *this;
+ }
+
+ Vector4 operator*(const Vector4& rhs) const
+ {
+ return {X * rhs.X, Y * rhs.Y, Z * rhs.Z, W * rhs.W};
+ }
+
+ template <typename T>
+ Vector4 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 {X * val, Y * val, Z * val, W * val};
+ }
+
+ // ---
+
+ Vector4& operator/=(const Vector4& rhs)
+ {
+ X /= rhs.X;
+ Y /= rhs.Y;
+ Z /= rhs.Z;
+ W /= rhs.W;
+
+ return *this;
+ }
+
+ template <typename T>
+ Vector4& 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");
+
+ X /= val;
+ Y /= val;
+ Z /= val;
+ W /= val;
+
+ return *this;
+ }
+
+ Vector4 operator/(const Vector4& rhs) const
+ {
+ return {X / rhs.X, Y / rhs.Y, Z / rhs.Z, W / rhs.W};
+ }
+
+ template <typename T>
+ Vector4 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 {X / val, Y / val, Z / val, W / val};
+ }
+
+ // --- public methods ---
+
+ MT dotProduct(const Vector4& vec) const
+ {
+ return X * vec.X + Y * vec.Y + Z * vec.Z + W * vec.W;
+ }
+
+ bool isNull() const
+ {
+ return X == 0 && Y == 0 && Z == 0 && W == 0;
+ }
+
+ MT length() const
+ {
+ return std::sqrt(X * X + Y * Y + Z * Z + W * W);
+ }
+
+ MT lengthSquared() const
+ {
+ return X * X + Y * Y + Z * Z + W * W;
+ }
+
+ void normalize()
+ {
+ *this /= std::sqrt(X * X + Y * Y + Z * Z + W * W);
+ }
+
+ Vector4 normalized() const
+ {
+ const MT len = std::sqrt(X * X + Y * Y + Z * Z + W * W);
+
+ return {X / len, Y / len, Z / len, W / len};
+ }
+
+ std::string string() const
+ {
+ std::stringstream result;
+
+ result << X << ", " << Y << ", " << Z << ", " << W;
+
+ return result.str();
+ }
+
+ Vector2<MT> vector2() const
+ {
+ return {X, Y};
+ }
+
+ Vector3<MT> vector3() const
+ {
+ return {X, Y, Z};
+ }
+
+ // --- static methods ---
+
+ static MT toDotProduct(const Vector4& vec1, const Vector4& vec2)
+ {
+ return vec1.X * vec2.X + vec1.Y * vec2.Y + vec1.Z * vec2.Z + vec1.W * vec2.W;
+ }
+
+ static std::string toString(const Vector4& vec)
+ {
+ std::stringstream result;
+
+ result << vec.X << ", " << vec.Y << ", " << vec.Z << ", " << vec.W;
+
+ return result.str();
+ }
+
+ static Vector2<MT> toVector2(const Vector4& vec)
+ {
+ return {vec.X, vec.Y};
+ }
+
+ static Vector3<MT> toVector3(const Vector4& vec)
+ {
+ return {vec.X, vec.X, vec.Z};
+ }
+};
+
+// --- global operators ---
+
+template <typename T>
+bool operator==(const Vector4<T>& lhs, const Vector4<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.X == rhs.X && lhs.Y == rhs.Y && lhs.Z == rhs.Z && lhs.W == rhs.W;
+}
+
+template <typename T>
+bool operator!=(const Vector4<T> lhs, const Vector4<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 Vector4<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.X << rhs.Y << rhs.Z << rhs.W;
+
+ return lhs;
+}
+
+template <typename T>
+std::istream& operator>>(std::istream& lhs, Vector4<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.X >> rhs.Y >> rhs.Z >> rhs.W;
+
+ return lhs;
+}
+
+// ---
+
+template <typename T>
+Vector4<T> operator+(const Vector4<T>& vec1, const Vector4<T>& vec2)
+{
+ 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 {vec1.X + vec2.X, vec1.Y + vec2.Y, vec1.Z + vec2.Z, vec1.W + vec2.W};
+}
+
+template <typename Vec, typename Val>
+Vector4<Vec> operator+(const Vector4<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X + val, vec.Y + val, vec.Z + val, vec.W + val};
+}
+
+template <typename Val, typename Vec>
+Vector4<Vec> operator+(const Val& val, const Vector4<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val + vec.X, val + vec.Y, val + vec.Z, val + vec.W};
+}
+
+// ---
+
+template <typename T>
+Vector4<T> operator-(const Vector4<T>& vec1, const Vector4<T>& vec2)
+{
+ 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 {vec1.X - vec2.X, vec1.Y - vec2.Y, vec1.Z - vec2.Z, vec1.W - vec2.W};
+}
+
+template <typename Vec, typename Val>
+Vector4<Vec> operator-(const Vector4<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X - val, vec.Y - val, vec.Z - val, vec.W - val};
+}
+
+template <typename Val, typename Vec>
+Vector4<Vec> operator-(const Val& val, const Vector4<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val - vec.X, val - vec.Y, val - vec.Z, val - vec.W};
+}
+
+template <typename T>
+Vector4<T> operator-(const Vector4<T>& vec)
+{
+ 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 {-vec.X, -vec.Y, -vec.Z, -vec.W};
+}
+
+// ---
+
+template <typename T>
+Vector4<T> operator*(const Vector4<T>& vec1, const Vector4<T>& vec2)
+{
+ 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 {vec1.X * vec2.X, vec1.Y * vec2.Y, vec1.Z * vec2.Z, vec1.W * vec2.W};
+}
+
+template <typename Vec, typename Val>
+Vector4<Vec> operator*(const Vector4<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X * val, vec.Y * val, vec.Z * val, vec.W * val};
+}
+
+template <typename Val, typename Vec>
+Vector4<Vec> operator*(const Val& val, const Vector4<Vec>& vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val * vec.X, val + vec.Y, val * vec.Z, val * vec.W};
+}
+
+// ---
+
+template <typename T>
+Vector4<T> operator/(const Vector4<T>& vec1, const Vector4<T>& vec2)
+{
+ 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 {vec1.X / vec2.X, vec1.Y / vec2.Y, vec1.Z / vec2.Z, vec1.W / vec2.W};
+}
+
+template <typename Vec, typename Val>
+Vector4<Vec> operator/(const Vector4<Vec>& vec, const Val& val)
+{
+ static_assert (std::is_integral<Vec>::value || std::is_floating_point<Vec>::value ||
+ std::is_integral<Val>::value || std::is_floating_point<Val>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {vec.X / val, vec.Y / val, vec.Z / val, vec.W / val};
+}
+
+template <typename Val, typename Vec>
+Vector4<Vec> operator/(const Val& val, const Vector4<Vec> vec)
+{
+ static_assert (std::is_integral<Val>::value || std::is_floating_point<Val>::value ||
+ std::is_integral<Vec>::value || std::is_floating_point<Vec>::value,
+ "ERROR: template parameter is not an integral or floating point type");
+
+ return {val / vec.X, val / vec.Y, val / vec.Z, val / vec.W};
+}