From ae758b3e7741097f94e72825577dd1697af03394 Mon Sep 17 00:00:00 2001 From: Akiko Date: Wed, 16 Oct 2013 11:02:20 +0200 Subject: [PATCH] - added my good old Vector class template implementation (we need it later for the BSP stuff) --- engine/Vector.hxx | 1705 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1705 insertions(+) create mode 100644 engine/Vector.hxx diff --git a/engine/Vector.hxx b/engine/Vector.hxx new file mode 100644 index 0000000..e9b2731 --- /dev/null +++ b/engine/Vector.hxx @@ -0,0 +1,1705 @@ +#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 +#include +#include +#include + +template class Vector2; +template class Vector3; +template class Vector4; + +// ****************************************************************************************************************** // + +template +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 --- + + 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& vec) + : XY{vec.X, vec.Y} + { + } + + Vector2(const Vector4& 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 + Vector2& 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"); + + X += val; + Y += val; + + return *this; + } + + Vector2 operator+(const Vector2& rhs) const + { + return {X + rhs.X, Y + rhs.Y}; + } + + template + Vector2 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 {X + val, Y + val}; + } + + // --- + + Vector2& operator-=(const Vector2& rhs) + { + X -= rhs.X; + Y -= rhs.Y; + + return *this; + } + + template + Vector2& 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"); + + X -= val; + Y -= val; + + return *this; + } + + Vector2 operator-(const Vector2& rhs) const + { + return {X - rhs.X, Y - rhs.Y}; + } + + template + Vector2 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"); + + return {X - val, Y - val}; + } + + // --- + + Vector2& operator*=(const Vector2& rhs) + { + X *= rhs.X; + Y *= rhs.Y; + + return *this; + } + + template + Vector2& 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"); + + X *= val; + Y *= val; + + return *this; + } + + Vector2 operator*(const Vector2& rhs) const + { + return {X * rhs.X, Y * rhs.Y}; + } + + template + Vector2 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"); + + return {X * val, Y * val}; + } + + // --- + + Vector2& operator/=(const Vector2& rhs) + { + X /= rhs.X; + Y /= rhs.Y; + + return *this; + } + + template + Vector2& 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"); + + X /= val; + Y /= val; + + return *this; + } + + Vector2 operator/(const Vector2& rhs) const + { + return {X / rhs.X, Y / rhs.Y}; + } + + template + Vector2 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 {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 vector3() const + { + return {X, Y, 0}; + } + + Vector4 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 toVector3(const Vector2& vec) + { + return {vec.X, vec.Y, 0}; + } + + static Vector4 toVector4(const Vector2& vec) + { + return {vec.X, vec.Y, 0, 0}; + } +}; + +// --- global operators --- + +template +bool operator==(const Vector2& lhs, const Vector2& 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.X == rhs.X && lhs.Y == rhs.Y; +} + +template +bool operator!=(const Vector2 lhs, const Vector2& 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 Vector2& 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.X << rhs.Y; + + return lhs; +} + +template +std::istream& operator>>(std::istream& lhs, Vector2& 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.X >> rhs.Y; + + return lhs; +} + +// --- + +template +Vector2 operator+(const Vector2& vec1, const Vector2& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {vec1.X + vec2.X, vec1.Y + vec2.Y}; +} + +template +Vector2 operator+(const Vector2& vec, 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 {vec.X + val, vec.Y + val}; +} + +template +Vector2 operator+(const Val& val, const Vector2& vec) +{ + 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 + vec.X, val + vec.Y}; +} + +// --- + +template +Vector2 operator-(const Vector2& vec1, const Vector2& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {vec1.X - vec2.X, vec1.Y - vec2.Y}; +} + +template +Vector2 operator-(const Vector2& vec, 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 {vec.X - val, vec.Y - val}; +} + +template +Vector2 operator-(const Val& val, const Vector2& vec) +{ + 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 - vec.X, val - vec.Y}; +} + +template +Vector2 operator-(const Vector2& vec) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {-vec.X, -vec.Y}; +} + +// --- + +template +Vector2 operator*(const Vector2& vec1, const Vector2& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {vec1.X * vec2.X, vec1.Y * vec2.Y}; +} + +template +Vector2 operator*(const Vector2& vec, 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 {vec.X * val, vec.Y * val}; +} + +template +Vector2 operator*(const Val& val, const Vector2& vec) +{ + 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 * vec.X, val + vec.Y}; +} + +// --- + +template +Vector2 operator/(const Vector2& vec1, const Vector2& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {vec1.X / vec2.X, vec1.Y / vec2.Y}; +} + +template +Vector2 operator/(const Vector2& vec, 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 {vec.X / val, vec.Y / val}; +} + +template +Vector2 operator/(const Val& val, const Vector2 vec) +{ + 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 / vec.X, val / vec.Y}; +} + +// ****************************************************************************************************************** // + +template +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 --- + + 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& vec) + : XYZ{vec.X, vec.Y, 0} + { + } + + Vector3(const Vector2& vec, const MT& val) + : XYZ{vec.X, vec.Y, val} + { + } + + Vector3(const Vector4& 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 + Vector3& 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"); + + 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 + Vector3 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 {X + val, Y + val, Z + val}; + } + + // --- + + Vector3& operator-=(const Vector3& rhs) + { + X -= rhs.X; + Y -= rhs.Y; + Z -= rhs.Z; + + return *this; + } + + template + Vector3& 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"); + + 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 + Vector3 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 {X - val, Y - val, Z - val}; + } + + // --- + + Vector3& operator*=(const Vector3& rhs) + { + X *= rhs.X; + Y *= rhs.Y; + Z *= rhs.Z; + + return *this; + } + + template + Vector3& 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"); + + 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 + Vector3 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 {X * val, Y * val, Z * val}; + } + + // --- + + Vector3& operator/=(const Vector3& rhs) + { + X /= rhs.X; + Y /= rhs.Y; + Z /= rhs.Z; + + return *this; + } + + template + Vector3& 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"); + + 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 + Vector3 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 {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 vector2() const + { + return {X, Y}; + } + + Vector4 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 toVector2(const Vector3& vec) + { + return {vec.X, vec.Y}; + } + + static Vector4 toVector4(const Vector3& vec) + { + return {vec.X, vec.Y, vec.Z, 0}; + } +}; + +// --- global operators --- + +template +bool operator==(const Vector3& lhs, const Vector3& 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.X == rhs.X && lhs.Y == rhs.Y && lhs.Z == rhs.Z; +} + +template +bool operator!=(const Vector3 lhs, const Vector3& 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 Vector3& 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.X << rhs.Y << rhs.Z; + + return lhs; +} + +template +std::istream& operator>>(std::istream& lhs, Vector3& 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.X >> rhs.Y >> rhs.Z; + + return lhs; +} + +// --- + +template +Vector3 operator+(const Vector3& vec1, const Vector3& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::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 +Vector3 operator+(const Vector3& vec, 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 {vec.X + val, vec.Y + val, vec.Z + val}; +} + +template +Vector3 operator+(const Val& val, const Vector3& vec) +{ + 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 + vec.X, val + vec.Y, val + vec.Z}; +} + +// --- + +template +Vector3 operator-(const Vector3& vec1, const Vector3& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::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 +Vector3 operator-(const Vector3& vec, 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 {vec.X - val, vec.Y - val, vec.Z - val}; +} + +template +Vector3 operator-(const Val& val, const Vector3& vec) +{ + 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 - vec.X, val - vec.Y, val - vec.Z}; +} + +template +Vector3 operator-(const Vector3& vec) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {-vec.X, -vec.Y, -vec.Z}; +} + +// --- + +template +Vector3 operator*(const Vector3& vec1, const Vector3& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::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 +Vector3 operator*(const Vector3& vec, 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 {vec.X * val, vec.Y * val, vec.Z * val}; +} + +template +Vector3 operator*(const Val& val, const Vector3& vec) +{ + 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 * vec.X, val + vec.Y, val * vec.Z}; +} + +// --- + +template +Vector3 operator/(const Vector3& vec1, const Vector3& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::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 +Vector3 operator/(const Vector3& vec, 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 {vec.X / val, vec.Y / val, vec.Z / val}; +} + +template +Vector3 operator/(const Val& val, const Vector3 vec) +{ + 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 / vec.X, val / vec.Y, val / vec.Z}; +} + +// ****************************************************************************************************************** // + +template +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 --- + + 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& vec) + : XYZW{vec.X, vec.Y, 0, 0} + { + } + + Vector4(const Vector2& vec, const MT& val1, const MT& val2) + : XYZW{vec.X, vec.Y, val1, val2} + { + } + + Vector4(const Vector2& vec1, const Vector2& vec2) + : XYZW{vec1.X, vec1.Y, vec2.X, vec2.Y} + { + } + + Vector4(const Vector3& vec) + : XYZW{vec.X, vec.Y, vec.Z, 0} + { + } + + Vector4(const Vector3& 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 + Vector4& 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"); + + 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 + Vector4 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 {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 + Vector4& 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"); + + 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 + Vector4 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 {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 + Vector4& 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"); + + 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 + Vector4 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 {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 + Vector4& 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"); + + 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 + Vector4 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 {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 vector2() const + { + return {X, Y}; + } + + Vector3 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 toVector2(const Vector4& vec) + { + return {vec.X, vec.Y}; + } + + static Vector3 toVector3(const Vector4& vec) + { + return {vec.X, vec.X, vec.Z}; + } +}; + +// --- global operators --- + +template +bool operator==(const Vector4& lhs, const Vector4& 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.X == rhs.X && lhs.Y == rhs.Y && lhs.Z == rhs.Z && lhs.W == rhs.W; +} + +template +bool operator!=(const Vector4 lhs, const Vector4& 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 Vector4& 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.X << rhs.Y << rhs.Z << rhs.W; + + return lhs; +} + +template +std::istream& operator>>(std::istream& lhs, Vector4& 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.X >> rhs.Y >> rhs.Z >> rhs.W; + + return lhs; +} + +// --- + +template +Vector4 operator+(const Vector4& vec1, const Vector4& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::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 +Vector4 operator+(const Vector4& vec, 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 {vec.X + val, vec.Y + val, vec.Z + val, vec.W + val}; +} + +template +Vector4 operator+(const Val& val, const Vector4& vec) +{ + 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 + vec.X, val + vec.Y, val + vec.Z, val + vec.W}; +} + +// --- + +template +Vector4 operator-(const Vector4& vec1, const Vector4& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::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 +Vector4 operator-(const Vector4& vec, 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 {vec.X - val, vec.Y - val, vec.Z - val, vec.W - val}; +} + +template +Vector4 operator-(const Val& val, const Vector4& vec) +{ + 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 - vec.X, val - vec.Y, val - vec.Z, val - vec.W}; +} + +template +Vector4 operator-(const Vector4& vec) +{ + static_assert (std::is_integral::value || std::is_floating_point::value, + "ERROR: template parameter is not an integral or floating point type"); + + return {-vec.X, -vec.Y, -vec.Z, -vec.W}; +} + +// --- + +template +Vector4 operator*(const Vector4& vec1, const Vector4& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::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 +Vector4 operator*(const Vector4& vec, 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 {vec.X * val, vec.Y * val, vec.Z * val, vec.W * val}; +} + +template +Vector4 operator*(const Val& val, const Vector4& vec) +{ + 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 * vec.X, val + vec.Y, val * vec.Z, val * vec.W}; +} + +// --- + +template +Vector4 operator/(const Vector4& vec1, const Vector4& vec2) +{ + static_assert (std::is_integral::value || std::is_floating_point::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 +Vector4 operator/(const Vector4& vec, 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 {vec.X / val, vec.Y / val, vec.Z / val, vec.W / val}; +} + +template +Vector4 operator/(const Val& val, const Vector4 vec) +{ + 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 / vec.X, val / vec.Y, val / vec.Z, val / vec.W}; +} -- 2.15.1