From 8dc864d22fc0ddc2189e258d82d20db487acde26 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Thu, 12 Aug 2021 15:21:11 +0200 Subject: [PATCH 1/6] Add Double2 vector implementation --- Source/Engine/Core/Math/Double2.cpp | 95 ++++ Source/Engine/Core/Math/Double2.h | 644 ++++++++++++++++++++++++++++ 2 files changed, 739 insertions(+) create mode 100644 Source/Engine/Core/Math/Double2.cpp create mode 100644 Source/Engine/Core/Math/Double2.h diff --git a/Source/Engine/Core/Math/Double2.cpp b/Source/Engine/Core/Math/Double2.cpp new file mode 100644 index 000000000..4aa16249f --- /dev/null +++ b/Source/Engine/Core/Math/Double2.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "Double2.h" +#include "Vector2.h" +#include "Vector3.h" +#include "Vector4.h" +#include "Color.h" +#include "Int2.h" +#include "Int3.h" +#include "Int4.h" +#include "../Types/String.h" + +static_assert(sizeof(Double2) == 16, "Invalid Double2 type size."); + +const Double2 Double2::Zero(0); +const Double2 Double2::One(1); +const Double2 Double2::UnitX(1, 0); +const Double2 Double2::UnitY(0, 1); +const Double2 Double2::Minimum(MIN_double); +const Double2 Double2::Maximum(MAX_double); + +Double2::Double2(const Int2& xy) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) +{ +} + +Double2::Double2(const Int3& xyz) + : X(static_cast(xyz.X)) + , Y(static_cast(xyz.Y)) +{ +} + +Double2::Double2(const Int4& xyzw) + : X(static_cast(xyzw.X)) + , Y(static_cast(xyzw.Y)) +{ +} + +Double2::Double2(const Vector2& xy) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) +{ +} + +Double2::Double2(const Vector3& xyz) + : X(xyz.X) + , Y(xyz.Y) +{ +} + +Double2::Double2(const Vector4& xyzw) + : X(xyzw.X) + , Y(xyzw.Y) +{ +} + +Double2::Double2(const Color& color) + : X(color.R) + , Y(color.G) +{ +} + +String Double2::ToString() const +{ + return String::Format(TEXT("{}"), *this); +} + +Double2 Double2::Normalize(const Double2& v) +{ + Double2 result = v; + const double length = v.Length(); + if (!Math::IsZero(length)) + { + const double inv = 1. / length; + result.X *= inv; + result.Y *= inv; + } + return result; +} + +Int2 Double2::CeilToInt(const Double2& v) +{ + return Int2(Math::CeilToInt(v.X), Math::CeilToInt(v.Y)); +} + +Int2 Double2::FloorToInt(const Double2& v) +{ + return Int2(Math::FloorToInt(v.X), Math::FloorToInt(v.Y)); +} + +double Double2::TriangleArea(const Double2& v0, const Double2& v1, const Double2& v2) +{ + return Math::Abs((v0.X * (v1.Y - v2.Y) + v1.X * (v2.Y - v0.Y) + v2.X * (v0.Y - v1.Y)) / 2.); +} diff --git a/Source/Engine/Core/Math/Double2.h b/Source/Engine/Core/Math/Double2.h new file mode 100644 index 000000000..a01e44fcb --- /dev/null +++ b/Source/Engine/Core/Math/Double2.h @@ -0,0 +1,644 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Math.h" +#include "Mathd.h" +#include "Engine/Core/Formatting.h" +#include "Engine/Core/Templates.h" + +struct Vector2; +struct Vector3; +struct Vector4; +struct Int2; +struct Int3; +struct Int4; +struct Color; +struct Matrix; + +/// +/// Represents a two dimensional mathematical vector. +/// +API_STRUCT() struct FLAXENGINE_API Double2 +{ +DECLARE_SCRIPTING_TYPE_MINIMAL(Double2); +public: + + union + { + struct + { + /// + /// The X component of the vector. + /// + API_FIELD() double X; + + /// + /// The Y component of the vector. + /// + API_FIELD() double Y; + }; + + // Raw values + double Raw[2]; + }; + +public: + + // Vector with all components equal 0 + static const Double2 Zero; + + // Vector with all components equal 1 + static const Double2 One; + + // Vector X=1, Y=0 + static const Double2 UnitX; + + // Vector X=0, Y=1 + static const Double2 UnitY; + + // A minimum Double2 + static const Double2 Minimum; + + // A maximum Double2 + static const Double2 Maximum; + +public: + + /// + /// Empty constructor. + /// + Double2() + { + } + + // Init + // @param xy Value to assign to the all components + Double2(double xy) + : X(xy) + , Y(xy) + { + } + + // Init + // @param x X component value + // @param y Y component value + Double2(double x, double y) + : X(x) + , Y(y) + { + } + + // Init + // @param v Int2 to use X and Y components + explicit Double2(const Int2& xy); + + // Init + // @param v Int3 to use X and Y components + explicit Double2(const Int3& xyz); + + // Init + // @param v Int4 to use X and Y components + explicit Double2(const Int4& xyzw); + + // Init + // @param v Vector2 to use X and Y components + explicit Double2(const Vector2& xy); + + // Init + // @param v Vector3 to use X and Y components + explicit Double2(const Vector3& xyz); + + // Init + // @param v Vector4 to use X and Y components + explicit Double2(const Vector4& xyzw); + + // Init + // @param color Color value + explicit Double2(const Color& color); + +public: + + String ToString() const; + +public: + + // Arithmetic operators with Double2 + Double2 operator+(const Double2& b) const + { + return Add(*this, b); + } + + Double2 operator-(const Double2& b) const + { + return Subtract(*this, b); + } + + Double2 operator*(const Double2& b) const + { + return Multiply(*this, b); + } + + Double2 operator/(const Double2& b) const + { + return Divide(*this, b); + } + + Double2 operator-() const + { + return Double2(-X, -Y); + } + + // op= operators with Double2 + Double2& operator+=(const Double2& b) + { + *this = Add(*this, b); + return *this; + } + + Double2& operator-=(const Double2& b) + { + *this = Subtract(*this, b); + return *this; + } + + Double2& operator*=(const Double2& b) + { + *this = Multiply(*this, b); + return *this; + } + + Double2& operator/=(const Double2& b) + { + *this = Divide(*this, b); + return *this; + } + + // Arithmetic operators with double + Double2 operator+(double b) const + { + return Add(*this, b); + } + + Double2 operator-(double b) const + { + return Subtract(*this, b); + } + + Double2 operator*(double b) const + { + return Multiply(*this, b); + } + + Double2 operator/(double b) const + { + return Divide(*this, b); + } + + // op= operators with double + Double2& operator+=(double b) + { + *this = Add(*this, b); + return *this; + } + + Double2& operator-=(double b) + { + *this = Subtract(*this, b); + return *this; + } + + Double2& operator*=(double b) + { + *this = Multiply(*this, b); + return *this; + } + + Double2& operator/=(double b) + { + *this = Divide(*this, b); + return *this; + } + + // Comparison operators + bool operator==(const Double2& b) const + { + return X == b.X && Y == b.Y; + } + + bool operator!=(const Double2& b) const + { + return X != b.X || Y != b.Y; + } + + bool operator>(const Double2& b) const + { + return X > b.X && Y > b.Y; + } + + bool operator>=(const Double2& b) const + { + return X >= b.X && Y >= b.Y; + } + + bool operator<(const Double2& b) const + { + return X < b.X && Y < b.Y; + } + + bool operator<=(const Double2& b) const + { + return X <= b.X && Y <= b.Y; + } + +public: + + static bool NearEqual(const Double2& a, const Double2& b) + { + return Math::NearEqual(a.X, b.X) && Math::NearEqual(a.Y, b.Y); + } + + static bool NearEqual(const Double2& a, const Double2& b, double epsilon) + { + return Math::NearEqual(a.X, b.X, epsilon) && Math::NearEqual(a.Y, b.Y, epsilon); + } + +public: + + static double Dot(const Double2& a, const Double2& b) + { + return a.X * b.X + a.Y * b.Y; + } + + static double Cross(const Double2& a, const Double2& b) + { + return a.X * b.Y - a.Y * b.X; + } + + static void Add(const Double2& a, const Double2& b, Double2& result) + { + result.X = a.X + b.X; + result.Y = a.Y + b.Y; + } + + static Double2 Add(const Double2& a, const Double2& b) + { + Double2 result; + Add(a, b, result); + return result; + } + + static void Subtract(const Double2& a, const Double2& b, Double2& result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + } + + static Double2 Subtract(const Double2& a, const Double2& b) + { + Double2 result; + Subtract(a, b, result); + return result; + } + + static Double2 Multiply(const Double2& a, const Double2& b) + { + return Double2(a.X * b.X, a.Y * b.Y); + } + + static Double2 Multiply(const Double2& a, double b) + { + return Double2(a.X * b, a.Y * b); + } + + static Double2 Divide(const Double2& a, const Double2& b) + { + return Double2(a.X / b.X, a.Y / b.Y); + } + + static Double2 Divide(const Double2& a, double b) + { + return Double2(a.X / b, a.Y / b); + } + + // Calculates distance between two points in 2D + // @param a 1st point + // @param b 2nd point + // @returns Distance + static double Distance(const Double2& a, const Double2& b) + { + const double x = a.X - b.X; + const double y = a.Y - b.Y; + return Math::Sqrt(x * x + y * y); + } + + // Calculates the squared distance between two points in 2D + // @param a 1st point + // @param b 2nd point + // @returns Distance + static double DistanceSquared(const Double2& a, const Double2& b) + { + const double x = a.X - b.X; + const double y = a.Y - b.Y; + return x * x + y * y; + } + + // Clamp vector values within given range + // @param v Vector to clamp + // @param min Minimum value + // @param max Maximum value + // @returns Clamped vector + static Double2 Clamp(const Double2& v, double min, double max) + { + return Double2(Math::Clamp(v.X, min, max), Math::Clamp(v.Y, min, max)); + } + + // Clamp vector values within given range + // @param v Vector to clamp + // @param min Minimum value + // @param max Maximum value + // @returns Clamped vector + static Double2 Clamp(const Double2& v, const Double2& min, const Double2& max) + { + return Double2(Math::Clamp(v.X, min.X, max.X), Math::Clamp(v.Y, min.Y, max.Y)); + } + + // Performs vector normalization (scales vector up to unit length) + void Normalize() + { + const double length = Length(); + if (!Math::IsZero(length)) + { + const double invLength = 1. / length; + X *= invLength; + Y *= invLength; + } + } + +public: + + // Gets a value indicting whether this instance is normalized + bool IsNormalized() const + { + return Math::IsOne(X * X + Y * Y); + } + + // Gets a value indicting whether this vector is zero + bool IsZero() const + { + return Math::IsZero(X) && Math::IsZero(Y); + } + + // Gets a value indicting whether any vector component is zero + bool IsAnyZero() const + { + return Math::IsZero(X) || Math::IsZero(Y); + } + + // Gets a value indicting whether this vector is zero + bool IsOne() const + { + return Math::IsOne(X) && Math::IsOne(Y); + } + + // Calculates length of the vector + // @returns Length of the vector + double Length() const + { + return Math::Sqrt(X * X + Y * Y); + } + + // Calculates the squared length of the vector + // @returns The squared length of the vector + double LengthSquared() const + { + return X * X + Y * Y; + } + + // Calculates inverted length of the vector (1 / Length()) + double InvLength() const + { + return 1. / Length(); + } + + // Calculates a vector with values being absolute values of that vector + Double2 GetAbsolute() const + { + return Double2(Math::Abs(X), Math::Abs(Y)); + } + + // Calculates a vector with values being opposite to values of that vector + Double2 GetNegative() const + { + return Double2(-X, -Y); + } + + /// + /// Returns average arithmetic of all the components + /// + /// Average arithmetic of all the components + double AverageArithmetic() const + { + return (X + Y) * 0.5; + } + + /// + /// Gets sum of all vector components values + /// + /// Sum of X,Y and Z + double SumValues() const + { + return X + Y; + } + + /// + /// Gets multiplication result of all vector components values + /// + /// X * Y + double MulValues() const + { + return X * Y; + } + + /// + /// Returns minimum value of all the components + /// + /// Minimum value + double MinValue() const + { + return Math::Min(X, Y); + } + + /// + /// Returns maximum value of all the components + /// + /// Maximum value + double MaxValue() const + { + return Math::Max(X, Y); + } + + /// + /// Returns true if vector has one or more components is not a number (NaN) + /// + /// True if one or more components is not a number (NaN) + bool IsNaN() const + { + return isnan(X) || isnan(Y); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity + /// + /// True if one or more components equal to +/- infinity + bool IsInfinity() const + { + return isinf(X) || isinf(Y); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity or NaN + /// + /// True if one or more components equal to +/- infinity or NaN + bool IsNanOrInfinity() const + { + return IsInfinity() || IsNaN(); + } + +public: + + // Performs a linear interpolation between two vectors + // @param start Start vector + // @param end End vector + // @param amount Value between 0 and 1 indicating the weight of end + // @param result When the method completes, contains the linear interpolation of the two vectors + static void Lerp(const Double2& start, const Double2& end, double amount, Double2& result) + { + result.X = Math::Lerp(start.X, end.X, amount); + result.Y = Math::Lerp(start.Y, end.Y, amount); + } + + // + // Performs a linear interpolation between two vectors. + // + // @param start Start vector, + // @param end End vector, + // @param amount Value between 0 and 1 indicating the weight of @paramref end"/>, + // @returns The linear interpolation of the two vectors + static Double2 Lerp(const Double2& start, const Double2& end, double amount) + { + Double2 result; + Lerp(start, end, amount, result); + return result; + } + + static Double2 Abs(const Double2& v) + { + return Double2(Math::Abs(v.X), Math::Abs(v.Y)); + } + + // Creates vector from minimum components of two vectors + static Double2 Min(const Double2& a, const Double2& b) + { + return Double2(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y); + } + + // Creates vector from minimum components of two vectors + static void Min(const Double2& a, const Double2& b, Double2& result) + { + result = Double2(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y); + } + + // Creates vector from maximum components of two vectors + static Double2 Max(const Double2& a, const Double2& b) + { + return Double2(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y); + } + + // Creates vector from maximum components of two vectors + static void Max(const Double2& a, const Double2& b, Double2& result) + { + result = Double2(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y); + } + + // Returns normalized vector + static Double2 Normalize(const Double2& v); + + static Double2 Round(const Double2& v) + { + return Double2(Math::Round(v.X), Math::Round(v.Y)); + } + + static Double2 Ceil(const Double2& v) + { + return Double2(Math::Ceil(v.X), Math::Ceil(v.Y)); + } + + static Double2 Floor(const Double2& v) + { + return Double2(Math::Floor(v.X), Math::Floor(v.Y)); + } + + static Double2 Frac(const Double2& v) + { + return Double2(v.X - (int64)v.X, v.Y - (int64)v.Y); + } + + static Int2 CeilToInt(const Double2& v); + static Int2 FloorToInt(const Double2& v); + + static Double2 Mod(const Double2& v) + { + return Double2( + v.X - (int64)v.X, + v.Y - (int64)v.Y + ); + } + +public: + + /// + /// Calculates the area of the triangle. + /// + /// The first triangle vertex. + /// The second triangle vertex. + /// The third triangle vertex. + /// The triangle area. + static double TriangleArea(const Double2& v0, const Double2& v1, const Double2& v2); +}; + +inline Double2 operator+(double a, const Double2& b) +{ + return b + a; +} + +inline Double2 operator-(double a, const Double2& b) +{ + return Double2(a) - b; +} + +inline Double2 operator*(double a, const Double2& b) +{ + return b * a; +} + +inline Double2 operator/(double a, const Double2& b) +{ + return Double2(a) / b; +} + +namespace Math +{ + FORCE_INLINE static bool NearEqual(const Double2& a, const Double2& b) + { + return Double2::NearEqual(a, b); + } +} + +template<> +struct TIsPODType +{ + enum { Value = true }; +}; + +DEFINE_DEFAULT_FORMATTING(Double2, "X:{0} Y:{1}", v.X, v.Y); From eedca14e6f3ba6cc173fda9c68ad4290af51cd34 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 18 Aug 2021 12:48:39 +0200 Subject: [PATCH 2/6] Add Double3 impl. cpp --- Source/Engine/Core/Math/Double3.cpp | 385 +++++++++++ Source/Engine/Core/Math/Double3.h | 970 ++++++++++++++++++++++++++++ 2 files changed, 1355 insertions(+) create mode 100644 Source/Engine/Core/Math/Double3.cpp create mode 100644 Source/Engine/Core/Math/Double3.h diff --git a/Source/Engine/Core/Math/Double3.cpp b/Source/Engine/Core/Math/Double3.cpp new file mode 100644 index 000000000..4c0a31df7 --- /dev/null +++ b/Source/Engine/Core/Math/Double3.cpp @@ -0,0 +1,385 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "Double2.h" +#include "Double3.h" +#include "Double4.h" +#include "Vector2.h" +#include "Vector3.h" +#include "Vector4.h" +#include "Quaternion.h" +#include "Matrix.h" +#include "Color.h" +#include "Int2.h" +#include "Int3.h" +#include "Int4.h" +#include "../Types/String.h" + +static_assert(sizeof(Double3) == 24, "Invalid Double3 type size."); + +const Double3 Double3::Zero(0.0); +const Double3 Double3::One(1.0); +const Double3 Double3::Half(0.5); +const Double3 Double3::UnitX(1.0, 0.0, 0.0); +const Double3 Double3::UnitY(0.0, 1.0, 0.0); +const Double3 Double3::UnitZ(0.0, 0.0, 1.0); +const Double3 Double3::Up(0.0, 1.0, 0.0); +const Double3 Double3::Down(0.0, -1.0, 0.0); +const Double3 Double3::Left(-1.0, 0.0, 0.0); +const Double3 Double3::Right(1.0, 0.0, 0.0); +const Double3 Double3::Forward(0.0, 0.0, 1.0); +const Double3 Double3::Backward(0.0, 0.0, -1.0); +const Double3 Double3::Minimum(MIN_double); +const Double3 Double3::Maximum(MAX_double); + +Double3::Double3(const Vector2& xy, double z) + : X(xy.X) + , Y(xy.Y) + , Z(z) +{ +} + +Double3::Double3(const Vector2& xy) + : X(xy.X) + , Y(xy.Y) + , Z(0) +{ +} + +Double3::Double3(const Int2& xy, double z) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) + , Z(z) +{ +} + +Double3::Double3(const Int3& xyz) + : X(static_cast(xyz.X)) + , Y(static_cast(xyz.Y)) + , Z(static_cast(xyz.Z)) +{ +} + +Double3::Double3(const Int4& xyzw) + : X(static_cast(xyzw.X)) + , Y(static_cast(xyzw.Y)) + , Z(static_cast(xyzw.Z)) +{ +} + +Double3::Double3(const Vector4& xyzw) + : X(xyzw.X) + , Y(xyzw.Y) + , Z(xyzw.Z) +{ +} + +Double3::Double3(const Double2& xy) + : X(xy.X) + , Y(xy.Y) + , Z(0) +{ +} + +Double3::Double3(const Double2& xy, double z) + : X(xy.X) + , Y(xy.Y) + , Z(z) +{ +} + +Double3::Double3(const Double4& xyzw) + : X(xyzw.X) + , Y(xyzw.Y) + , Z(xyzw.Z) +{ +} + +Double3::Double3(const Color& color) + : X(color.R) + , Y(color.G) + , Z(color.B) +{ +} + +String Double3::ToString() const +{ + return String::Format(TEXT("{}"), *this); +} + +void Double3::UnwindEuler() +{ + X = Math::UnwindDegrees(X); + Y = Math::UnwindDegrees(Y); + Z = Math::UnwindDegrees(Z); +} + +Double3 Double3::Floor(const Double3& v) +{ + return Double3( + Math::Floor(v.X), + Math::Floor(v.Y), + Math::Floor(v.Z) + ); +} + +Double3 Double3::Frac(const Double3& v) +{ + return Double3( + v.X - (int64)v.X, + v.Y - (int64)v.Y, + v.Z - (int64)v.Z + ); +} + +Double3 Double3::Clamp(const Double3& value, const Double3& min, const Double3& max) +{ + double x = value.X; + x = x > max.X ? max.X : x; + x = x < min.X ? min.X : x; + + double y = value.Y; + y = y > max.Y ? max.Y : y; + y = y < min.Y ? min.Y : y; + + double z = value.Z; + z = z > max.Z ? max.Z : z; + z = z < min.Z ? min.Z : z; + + return Double3(x, y, z); +} + +void Double3::Clamp(const Double3& value, const Double3& min, const Double3& max, Double3& result) +{ + double x = value.X; + x = x > max.X ? max.X : x; + x = x < min.X ? min.X : x; + + double y = value.Y; + y = y > max.Y ? max.Y : y; + y = y < min.Y ? min.Y : y; + + double z = value.Z; + z = z > max.Z ? max.Z : z; + z = z < min.Z ? min.Z : z; + + result = Double3(x, y, z); +} + +double Double3::Distance(const Double3& value1, const Double3& value2) +{ + const double x = value1.X - value2.X; + const double y = value1.Y - value2.Y; + const double z = value1.Z - value2.Z; + return Math::Sqrt(x * x + y * y + z * z); +} + +double Double3::DistanceSquared(const Double3& value1, const Double3& value2) +{ + const double x = value1.X - value2.X; + const double y = value1.Y - value2.Y; + const double z = value1.Z - value2.Z; + return x * x + y * y + z * z; +} + +Double3 Double3::Normalize(const Double3& input) +{ + Double3 output = input; + const double length = input.Length(); + if (!Math::IsZero(length)) + { + const double inv = 1.0f / length; + output.X *= inv; + output.Y *= inv; + output.Z *= inv; + } + return output; +} + +void Double3::Normalize(const Double3& input, Double3& result) +{ + result = input; + const double length = input.Length(); + if (!Math::IsZero(length)) + { + const double inv = 1.0f / length; + result.X *= inv; + result.Y *= inv; + result.Z *= inv; + } +} + +void Double3::Hermite(const Double3& value1, const Double3& tangent1, const Double3& value2, const Double3& tangent2, double amount, Double3& result) +{ + const double squared = amount * amount; + const double cubed = amount * squared; + const double part1 = 2.0 * cubed - 3.0 * squared + 1.0; + const double part2 = -2.0 * cubed + 3.0 * squared; + const double part3 = cubed - 2.0 * squared + amount; + const double part4 = cubed - squared; + + result.X = value1.X * part1 + value2.X * part2 + tangent1.X * part3 + tangent2.X * part4; + result.Y = value1.Y * part1 + value2.Y * part2 + tangent1.Y * part3 + tangent2.Y * part4; + result.Z = value1.Z * part1 + value2.Z * part2 + tangent1.Z * part3 + tangent2.Z * part4; +} + +void Double3::Reflect(const Double3& vector, const Double3& normal, Double3& result) +{ + const double dot = vector.X * normal.X + vector.Y * normal.Y + vector.Z * normal.Z; + result.X = vector.X - 2.0 * dot * normal.X; + result.Y = vector.Y - 2.0 * dot * normal.Y; + result.Z = vector.Z - 2.0 * dot * normal.Z; +} + +void Double3::Transform(const Double3& vector, const Quaternion& rotation, Double3& result) +{ + const double x = rotation.X + rotation.X; + const double y = rotation.Y + rotation.Y; + const double z = rotation.Z + rotation.Z; + const double wx = rotation.W * x; + const double wy = rotation.W * y; + const double wz = rotation.W * z; + const double xx = rotation.X * x; + const double xy = rotation.X * y; + const double xz = rotation.X * z; + const double yy = rotation.Y * y; + const double yz = rotation.Y * z; + const double zz = rotation.Z * z; + + result = Double3( + vector.X * (1.0 - yy - zz) + vector.Y * (xy - wz) + vector.Z * (xz + wy), + vector.X * (xy + wz) + vector.Y * (1.0 - xx - zz) + vector.Z * (yz - wx), + vector.X * (xz - wy) + vector.Y * (yz + wx) + vector.Z * (1.0 - xx - yy)); +} + +Double3 Double3::Transform(const Double3& vector, const Quaternion& rotation) +{ + const double x = rotation.X + rotation.X; + const double y = rotation.Y + rotation.Y; + const double z = rotation.Z + rotation.Z; + const double wx = rotation.W * x; + const double wy = rotation.W * y; + const double wz = rotation.W * z; + const double xx = rotation.X * x; + const double xy = rotation.X * y; + const double xz = rotation.X * z; + const double yy = rotation.Y * y; + const double yz = rotation.Y * z; + const double zz = rotation.Z * z; + + return Double3( + vector.X * (1.0 - yy - zz) + vector.Y * (xy - wz) + vector.Z * (xz + wy), + vector.X * (xy + wz) + vector.Y * (1.0 - xx - zz) + vector.Z * (yz - wx), + vector.X * (xz - wy) + vector.Y * (yz + wx) + vector.Z * (1.0 - xx - yy)); +} + +void Double3::Transform(const Double3& vector, const Matrix& transform, Double4& result) +{ + result = Double4( + vector.X * transform.M11 + vector.Y * transform.M21 + vector.Z * transform.M31 + transform.M41, + vector.X * transform.M12 + vector.Y * transform.M22 + vector.Z * transform.M32 + transform.M42, + vector.X * transform.M13 + vector.Y * transform.M23 + vector.Z * transform.M33 + transform.M43, + vector.X * transform.M14 + vector.Y * transform.M24 + vector.Z * transform.M34 + transform.M44); +} + +void Double3::Transform(const Double3& vector, const Matrix& transform, Double3& result) +{ + result = Double3( + vector.X * transform.M11 + vector.Y * transform.M21 + vector.Z * transform.M31 + transform.M41, + vector.X * transform.M12 + vector.Y * transform.M22 + vector.Z * transform.M32 + transform.M42, + vector.X * transform.M13 + vector.Y * transform.M23 + vector.Z * transform.M33 + transform.M43); +} + +void Double3::Transform(const Double3* vectors, const Matrix& transform, Double3* results, int32 vectorsCount) +{ + for (int32 i = 0; i < vectorsCount; i++) + { + Transform(vectors[i], transform, results[i]); + } +} + +Double3 Double3::Transform(const Double3& vector, const Matrix& transform) +{ + return Double3( + vector.X * transform.M11 + vector.Y * transform.M21 + vector.Z * transform.M31 + transform.M41, + vector.X * transform.M12 + vector.Y * transform.M22 + vector.Z * transform.M32 + transform.M42, + vector.X * transform.M13 + vector.Y * transform.M23 + vector.Z * transform.M33 + transform.M43); +} + +void Double3::TransformCoordinate(const Double3& coordinate, const Matrix& transform, Double3& result) +{ + Double4 vector; + vector.X = coordinate.X * transform.M11 + coordinate.Y * transform.M21 + coordinate.Z * transform.M31 + transform.M41; + vector.Y = coordinate.X * transform.M12 + coordinate.Y * transform.M22 + coordinate.Z * transform.M32 + transform.M42; + vector.Z = coordinate.X * transform.M13 + coordinate.Y * transform.M23 + coordinate.Z * transform.M33 + transform.M43; + vector.W = 1.0 / (coordinate.X * transform.M14 + coordinate.Y * transform.M24 + coordinate.Z * transform.M34 + transform.M44); + result = Double3(vector.X * vector.W, vector.Y * vector.W, vector.Z * vector.W); +} + +void Double3::TransformNormal(const Double3& normal, const Matrix& transform, Double3& result) +{ + result = Double3( + normal.X * transform.M11 + normal.Y * transform.M21 + normal.Z * transform.M31, + normal.X * transform.M12 + normal.Y * transform.M22 + normal.Z * transform.M32, + normal.X * transform.M13 + normal.Y * transform.M23 + normal.Z * transform.M33); +} + +Double3 Double3::Project(const Double3& vector, const Double3& onNormal) +{ + const double sqrMag = Dot(onNormal, onNormal); + if (sqrMag < ZeroTolerance) + return Zero; + return onNormal * Dot(vector, onNormal) / sqrMag; +} + +void Double3::Project(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection, Double3& result) +{ + Double3 v; + TransformCoordinate(vector, worldViewProjection, v); + + result = Double3((1.0 + v.X) * 0.5 * width + x, (1.0 - v.Y) * 0.5 * height + y, v.Z * (maxZ - minZ) + minZ); +} + +void Double3::Unproject(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection, Double3& result) +{ + Matrix matrix; + Matrix::Invert(worldViewProjection, matrix); + + const Double3 v = Double3((vector.X - x) / width * 2.0 - 1.0, -((vector.Y - y) / height * 2.0 - 1.0), (vector.Z - minZ) / (maxZ - minZ)); + + TransformCoordinate(v, matrix, result); +} + +void Double3::CreateOrthonormalBasis(Double3& xAxis, Double3& yAxis, Double3& zAxis) +{ + xAxis -= (xAxis | zAxis) / (zAxis | zAxis) * zAxis; + yAxis -= (yAxis | zAxis) / (zAxis | zAxis) * zAxis; + + if (xAxis.LengthSquared() < ZeroTolerance) + xAxis = yAxis ^ zAxis; + if (yAxis.LengthSquared() < ZeroTolerance) + yAxis = xAxis ^ zAxis; + + xAxis.Normalize(); + yAxis.Normalize(); + zAxis.Normalize(); +} + +void Double3::FindBestAxisVectors(Double3& firstAxis, Double3& secondAxis) const +{ + const double absX = Math::Abs(X); + const double absY = Math::Abs(Y); + const double absZ = Math::Abs(Z); + + if (absZ > absX && absZ > absY) + firstAxis = Double3(1, 0, 0); + else + firstAxis = Double3(0, 0, 1); + + firstAxis = (firstAxis - *this * (firstAxis | *this)).GetNormalized(); + secondAxis = firstAxis ^ *this; +} + +double Double3::TriangleArea(const Double3& v0, const Double3& v1, const Double3& v2) +{ + return (v2 - v0 ^ v1 - v0).Length() * 0.5; +} diff --git a/Source/Engine/Core/Math/Double3.h b/Source/Engine/Core/Math/Double3.h new file mode 100644 index 000000000..f57608190 --- /dev/null +++ b/Source/Engine/Core/Math/Double3.h @@ -0,0 +1,970 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Math.h" +#include "Mathd.h" +#include "Engine/Core/Formatting.h" +#include "Engine/Core/Templates.h" + +struct Double2; +struct Double4; +struct Vector2; +struct Vector3; +struct Vector4; +struct Int2; +struct Int3; +struct Int4; +struct Color; +struct Matrix; + +/// +/// Represents a two dimensional mathematical vector. +/// +API_STRUCT() struct FLAXENGINE_API Double3 +{ +DECLARE_SCRIPTING_TYPE_MINIMAL(Double3); +public: + + union + { + struct + { + /// + /// The X component of the vector. + /// + API_FIELD() double X; + + /// + /// The Y component of the vector. + /// + API_FIELD() double Y; + + /// + /// The Z component of the vector. + /// + API_FIELD() double Z; + }; + + // Raw values + double Raw[3]; + }; + +public: + + // Vector with all components equal 0 + static const Double3 Zero; + + // Vector with all components equal 1 + static const Double3 One; + + // Vector with all components equal half (0.5, 0.5, 0.5) + static const Double3 Half; + + // Vector X=1, Y=0, Z=0 + static const Double3 UnitX; + + // Vector X=0, Y=1, Z=0 + static const Double3 UnitY; + + // Vector X=0, Y=0, Z=1 + static const Double3 UnitZ; + + // A unit vector designating up (0, 1, 0) + static const Double3 Up; + + // A unit vector designating down (0, -1, 0) + static const Double3 Down; + + // A unit vector designating a (-1, 0, 0) + static const Double3 Left; + + // A unit vector designating b (1, 0, 0) + static const Double3 Right; + + // A unit vector designating forward in a a-handed coordinate system (0, 0, 1) + static const Double3 Forward; + + // A unit vector designating backward in a a-handed coordinate system (0, 0, -1) + static const Double3 Backward; + + // A minimum Double3 + static const Double3 Minimum; + + // A maximum Double3 + static const Double3 Maximum; + +public: + + + /// + /// Empty constructor. + /// + Double3() + { + } + + // Init + // @param xyz Value to assign to the all components + Double3(double xyz) + : X(xyz) + , Y(xyz) + , Z(xyz) + { + } + + // Init + // @param x X component value + // @param y Y component value + // @param z Z component value + Double3(double x, double y, double z) + : X(x) + , Y(y) + , Z(z) + { + } + + /// + /// Init + /// + /// X, Y and Z components in an array + explicit Double3(double xyz[3]) + : X(xyz[0]) + , Y(xyz[1]) + , Z(xyz[2]) + { + } + + // Init + // @param xy Vector2 with X and Y components values + // @param z Z component value + explicit Double3(const Vector2& xy, double z); + + // Init + // @param xy Vector2 value + explicit Double3(const Vector2& xy); + + // Init + // @param xy Int22 with X and Y components values + // @param z Z component value + explicit Double3(const Int2& xy, double z); + + // Init + // @param xyz Int3 value + explicit Double3(const Int3& xyz); + + // Init + // @param xyzw Int4 value + explicit Double3(const Int4& xyzw); + + // Init + // @param xyz Vector4 value + explicit Double3(const Vector4& xyzw); + + // Init + // @param xy Double2 value + Double3(const Double2& xy); + + // Init + // @param xy Double2 value + // @param z Z component value + explicit Double3(const Double2& xy, double z); + + + // Init + // @param xyzw Double4 value + explicit Double3(const Double4& xyzw); + + // Init + // @param color Color value + explicit Double3(const Color& color); + +public: + + String ToString() const; + +public: + + // Gets a value indicting whether this instance is normalized + bool IsNormalized() const + { + return Math::IsOne(X * X + Y * Y + Z * Z); + } + + // Gets a value indicting whether this vector is zero + bool IsZero() const + { + return Math::IsZero(X) && Math::IsZero(Y) && Math::IsZero(Z); + } + + // Gets a value indicting whether any vector component is zero + bool IsAnyZero() const + { + return Math::IsZero(X) || Math::IsZero(Y) || Math::IsZero(Z); + } + + // Gets a value indicting whether this vector is one + bool IsOne() const + { + return Math::IsOne(X) && Math::IsOne(Y) && Math::IsOne(Z); + } + + // Calculates length of the vector + // @returns Length of the vector + double Length() const + { + return Math::Sqrt(X * X + Y * Y + Z * Z); + } + + // Calculates the squared length of the vector + // @returns The squared length of the vector + double LengthSquared() const + { + return X * X + Y * Y + Z * Z; + } + + // Calculates inverted length of the vector (1 / Length()) + double InvLength() const + { + return 1.0 / Length(); + } + + /// + /// Calculates a vector with values being absolute values of that vector + /// + /// Absolute vector + Double3 GetAbsolute() const + { + return Double3(Math::Abs(X), Math::Abs(Y), Math::Abs(Z)); + } + + /// + /// Calculates a vector with values being opposite to values of that vector + /// + /// Negative vector + Double3 GetNegative() const + { + return Double3(-X, -Y, -Z); + } + + /// + /// Calculates a normalized vector that has length equal to 1. + /// + /// The normalized vector. + Double3 GetNormalized() const + { + const double rcp = 1.0 / Length(); + return Double3(X * rcp, Y * rcp, Z * rcp); + } + + /// + /// Returns average arithmetic of all the components + /// + /// Average arithmetic of all the components + double AverageArithmetic() const + { + return (X + Y + Z) * 0.333333334; + } + + /// + /// Gets sum of all vector components values + /// + /// Sum of X,Y and Z + double SumValues() const + { + return X + Y + Z; + } + + /// + /// Returns minimum value of all the components + /// + /// Minimum value + double MinValue() const + { + return Math::Min(X, Y, Z); + } + + /// + /// Returns maximum value of all the components + /// + /// Maximum value + double MaxValue() const + { + return Math::Max(X, Y, Z); + } + + /// + /// Returns true if vector has one or more components is not a number (NaN) + /// + /// True if one or more components is not a number (NaN) + bool IsNaN() const + { + return isnan(X) || isnan(Y) || isnan(Z); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity + /// + /// True if one or more components equal to +/- infinity + bool IsInfinity() const + { + return isinf(X) || isinf(Y) || isinf(Z); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity or NaN + /// + /// True if one or more components equal to +/- infinity or NaN + bool IsNanOrInfinity() const + { + return IsInfinity() || IsNaN(); + } + +public: + + /// + /// Performs vector normalization (scales vector up to unit length) + /// + void Normalize() + { + const double length = Length(); + if (!Math::IsZero(length)) + { + const double inv = 1.0f / length; + X *= inv; + Y *= inv; + Z *= inv; + } + } + + /// + /// Performs fast vector normalization (scales vector up to unit length) + /// + void NormalizeFast() + { + const double inv = 1.0f / Length(); + X *= inv; + Y *= inv; + Z *= inv; + } + + /// + /// Sets all vector components to the absolute values + /// + void Absolute() + { + X = Math::Abs(X); + Y = Math::Abs(Y); + Z = Math::Abs(Z); + } + + /// + /// Negates all components of that vector + /// + void Negate() + { + X = -X; + Y = -Y; + Z = -Z; + } + + /// + /// When this vector contains Euler angles (degrees), ensure that angles are between +/-180 + /// + void UnwindEuler(); + +public: + + // Arithmetic operators with Double3 + Double3 operator+(const Double3& b) const + { + return Add(*this, b); + } + + Double3 operator-(const Double3& b) const + { + return Subtract(*this, b); + } + + Double3 operator*(const Double3& b) const + { + return Multiply(*this, b); + } + + Double3 operator/(const Double3& b) const + { + return Divide(*this, b); + } + + Double3 operator-() const + { + return Double3(-X, -Y, -Z); + } + + Double3 operator^(const Double3& b) const + { + return Cross(*this, b); + } + + double operator|(const Double3& b) const + { + return Dot(*this, b); + } + + // op= operators with Vector3 + Double3& operator+=(const Double3& b) + { + *this = Add(*this, b); + return *this; + } + + Double3& operator-=(const Double3& b) + { + *this = Subtract(*this, b); + return *this; + } + + Double3& operator*=(const Double3& b) + { + *this = Multiply(*this, b); + return *this; + } + + Double3& operator/=(const Double3& b) + { + *this = Divide(*this, b); + return *this; + } + + // Arithmetic operators with double + Double3 operator+(double b) const + { + return Add(*this, b); + } + + Double3 operator-(double b) const + { + return Subtract(*this, b); + } + + Double3 operator*(double b) const + { + return Multiply(*this, b); + } + + Double3 operator/(double b) const + { + return Divide(*this, b); + } + + // op= operators with double + Double3& operator+=(double b) + { + *this = Add(*this, b); + return *this; + } + + Double3& operator-=(double b) + { + *this = Subtract(*this, b); + return *this; + } + + Double3& operator*=(double b) + { + *this = Multiply(*this, b); + return *this; + } + + Double3& operator/=(double b) + { + *this = Divide(*this, b); + return *this; + } + + // Comparison operators + bool operator==(const Double3& b) const + { + return X == b.X && Y == b.Y && Z == b.Z; + } + + bool operator!=(const Double3& b) const + { + return X != b.X || Y != b.Y || Z != b.Z; + } + + bool operator>(const Double3& b) const + { + return X > b.X && Y > b.Y && Z > b.Z; + } + + bool operator>=(const Double3& b) const + { + return X >= b.X && Y >= b.Y && Z >= b.Z; + } + + bool operator<(const Double3& b) const + { + return X < b.X && Y < b.Y && Z < b.Z; + } + + bool operator<=(const Double3& b) const + { + return X <= b.X && Y <= b.Y && Z <= b.Z; + } + +public: + + static bool NearEqual(const Double3& a, const Double3& b) + { + return Math::NearEqual(a.X, b.X) && Math::NearEqual(a.Y, b.Y) && Math::NearEqual(a.Z, b.Z); + } + + static bool NearEqual(const Double3& a, const Double3& b, double epsilon) + { + return Math::NearEqual(a.X, b.X, epsilon) && Math::NearEqual(a.Y, b.Y, epsilon) && Math::NearEqual(a.Z, b.Z, epsilon); + } + +public: + + static void Add(const Double3& a, const Double3& b, Double3& result) + { + result.X = a.X + b.X; + result.Y = a.Y + b.Y; + result.Z = a.Z + b.Z; + } + + static Double3 Add(const Double3& a, const Double3& b) + { + Double3 result; + Add(a, b, result); + return result; + } + + static void Subtract(const Double3& a, const Double3& b, Double3& result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + result.Z = a.Z - b.Z; + } + + static Double3 Subtract(const Double3& a, const Double3& b) + { + Double3 result; + Subtract(a, b, result); + return result; + } + + static Double3 Multiply(const Double3& a, const Double3& b) + { + return Double3(a.X * b.X, a.Y * b.Y, a.Z * b.Z); + } + + static void Multiply(const Double3& a, const Double3& b, Double3& result) + { + result = Double3(a.X * b.X, a.Y * b.Y, a.Z * b.Z); + } + + static Double3 Multiply(const Double3& a, double b) + { + return Double3(a.X * b, a.Y * b, a.Z * b); + } + + static Double3 Divide(const Double3& a, const Double3& b) + { + return Double3(a.X / b.X, a.Y / b.Y, a.Z / b.Z); + } + + static void Divide(const Double3& a, const Double3& b, Double3& result) + { + result = Double3(a.X / b.X, a.Y / b.Y, a.Z / b.Z); + } + + static Double3 Divide(const Double3& a, double b) + { + return Double3(a.X / b, a.Y / b, a.Z / b); + } + + static Double3 Floor(const Double3& v); + static Double3 Frac(const Double3& v); + + static double ScalarProduct(const Double3& a, const Double3& b) + { + return a.X * b.X + a.Y * b.Y + a.Z * b.Z; + } + +public: + + // Restricts a value to be within a specified range + // @param value The value to clamp + // @param min The minimum value, + // @param max The maximum value + // @returns Clamped value + static Double3 Clamp(const Double3& value, const Double3& min, const Double3& max); + + // Restricts a value to be within a specified range + // @param value The value to clamp + // @param min The minimum value, + // @param max The maximum value + // @param result When the method completes, contains the clamped value + static void Clamp(const Double3& value, const Double3& min, const Double3& max, Double3& result); + + // Calculates the distance between two vectors + // @param value1 The first vector + // @param value2 The second vector + // @returns The distance between the two vectors + static double Distance(const Double3& value1, const Double3& value2); + + // Calculates the squared distance between two vectors + // @param value1 The first vector + // @param value2 The second vector + // @returns The squared distance between the two vectors + static double DistanceSquared(const Double3& value1, const Double3& value2); + + // Performs vector normalization (scales vector up to unit length) + // @param inout Input vector to normalize + // @returns Output vector that is normalized (has unit length) + static Double3 Normalize(const Double3& input); + + // Performs vector normalization (scales vector up to unit length). This is a faster version that does not performs check for length equal 0 (it assumes that input vector is not empty). + // @param inout Input vector to normalize (cannot be zero). + // @returns Output vector that is normalized (has unit length) + static Double3 NormalizeFast(const Double3& input) + { + const double inv = 1.0 / input.Length(); + return Double3(input.X * inv, input.Y * inv, input.Z * inv); + } + + // Performs vector normalization (scales vector up to unit length) + // @param inout Input vector to normalize + // @param output Output vector that is normalized (has unit length) + static void Normalize(const Double3& input, Double3& result); + + // dot product with another vector + static double Dot(const Double3& a, const Double3& b) + { + return a.X * b.X + a.Y * b.Y + a.Z * b.Z; + } + + // Calculates the cross product of two vectors + // @param a First source vector + // @param b Second source vector + // @param result When the method completes, contains the cross product of the two vectors + static void Cross(const Double3& a, const Double3& b, Double3& result) + { + result = Double3( + a.Y * b.Z - a.Z * b.Y, + a.Z * b.X - a.X * b.Z, + a.X * b.Y - a.Y * b.X); + } + + // Calculates the cross product of two vectors + // @param a First source vector + // @param b Second source vector + // @returns Cross product of the two vectors + static Double3 Cross(const Double3& a, const Double3& b) + { + return Double3( + a.Y * b.Z - a.Z * b.Y, + a.Z * b.X - a.X * b.Z, + a.X * b.Y - a.Y * b.X); + } + + // Performs a linear interpolation between two vectors + // @param start Start vector + // @param end End vector + // @param amount Value between 0 and 1 indicating the weight of end + // @param result When the method completes, contains the linear interpolation of the two vectors + static void Lerp(const Double3& start, const Double3& end, double amount, Double3& result) + { + result.X = Math::Lerp(start.X, end.X, amount); + result.Y = Math::Lerp(start.Y, end.Y, amount); + result.Z = Math::Lerp(start.Z, end.Z, amount); + } + + // + // Performs a linear interpolation between two vectors. + // + // @param start Start vector, + // @param end End vector, + // @param amount Value between 0 and 1 indicating the weight of @paramref end"/>, + // @returns The linear interpolation of the two vectors + static Double3 Lerp(const Double3& start, const Double3& end, double amount) + { + Double3 result; + Lerp(start, end, amount, result); + return result; + } + + // Performs a cubic interpolation between two vectors + // @param start Start vector + // @param end End vector + // @param amount Value between 0 and 1 indicating the weight of end + // @param result When the method completes, contains the cubic interpolation of the two vectors + static void SmoothStep(const Double3& start, const Double3& end, double amount, Double3& result) + { + amount = Math::SmoothStep(amount); + Lerp(start, end, amount, result); + } + + // Performs a Hermite spline interpolation. + // @param value1 First source position vector + // @param tangent1 First source tangent vector + // @param value2 Second source position vector + // @param tangent2 Second source tangent vector + // @param amount Weighting factor, + // @param result When the method completes, contains the result of the Hermite spline interpolation, + static void Hermite(const Double3& value1, const Double3& tangent1, const Double3& value2, const Double3& tangent2, double amount, Double3& result); + + // Returns the reflection of a vector off a surface that has the specified normal + // @param vector The source vector + // @param normal Normal of the surface + // @param result When the method completes, contains the reflected vector + static void Reflect(const Double3& vector, const Double3& normal, Double3& result); + + // Transforms a 3D vector by the given Quaternion rotation + // @param vector The vector to rotate + // @param rotation The Quaternion rotation to apply + // @param result When the method completes, contains the transformed Vector4 + static void Transform(const Double3& vector, const Quaternion& rotation, Double3& result); + + // Transforms a 3D vector by the given Quaternion rotation + // @param vector The vector to rotate + // @param rotation The Quaternion rotation to apply + // @returns The transformed Double3 + static Double3 Transform(const Double3& vector, const Quaternion& rotation); + + // Transforms a 3D vector by the given matrix + // @param vector The source vector + // @param transform The transformation matrix + // @param result When the method completes, contains the transformed Double3 + static void Transform(const Double3& vector, const Matrix& transform, Double3& result); + + // Transforms a 3D vectors by the given matrix + // @param vectors The source vectors + // @param transform The transformation matrix + // @param results When the method completes, contains the transformed Vector3s + // @param vectorsCount Amount of vectors to transform + static void Transform(const Double3* vectors, const Matrix& transform, Double3* results, int32 vectorsCount); + + // Transforms a 3D vector by the given matrix + // @param vector The source vector + // @param transform The transformation matrix + // @returns Transformed Double3 + static Double3 Transform(const Double3& vector, const Matrix& transform); + + // Transforms a 3D vector by the given matrix + // @param vector The source vector + // @param transform The transformation matrix + // @param result When the method completes, contains the transformed Double4 + static void Transform(const Double3& vector, const Matrix& transform, Double4& result); + + // Performs a coordinate transformation using the given matrix + // @param coordinate The coordinate vector to transform + // @param transform The transformation matrix + // @param result When the method completes, contains the transformed coordinates + static void TransformCoordinate(const Double3& coordinate, const Matrix& transform, Double3& result); + + // Performs a normal transformation using the given matrix + // @param normal The normal vector to transform + // @param transform The transformation matrix + // @param result When the method completes, contains the transformed normal + static void TransformNormal(const Double3& normal, const Matrix& transform, Double3& result); + + // Returns a vector containing the largest components of the specified vectors + // @param a The first source vector + // @param b The second source vector + // @param result When the method completes, contains an new vector composed of the largest components of the source vectors + static Double3 Max(const Double3& a, const Double3& b) + { + return Double3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z); + } + + // Returns a vector containing the smallest components of the specified vectors + // @param a The first source vector + // @param b The second source vector + // @param result When the method completes, contains an new vector composed of the smallest components of the source vectors + static Double3 Min(const Double3& a, const Double3& b) + { + return Double3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z); + } + + // Returns a vector containing the largest components of the specified vectors + // @param a The first source vector + // @param b The second source vector + // @param result When the method completes, contains an new vector composed of the largest components of the source vectors + static void Max(const Double3& a, const Double3& b, Double3& result) + { + result = Double3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z); + } + + // Returns a vector containing the smallest components of the specified vectors + // @param a The first source vector + // @param b The second source vector + // @param result When the method completes, contains an new vector composed of the smallest components of the source vectors + static void Min(const Double3& a, const Double3& b, Double3& result) + { + result = Double3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z); + } + + /// + /// Projects a vector onto another vector. + /// + /// The vector to project. + /// The projection normal vector. + /// The projected vector. + static Double3 Project(const Double3& vector, const Double3& onNormal); + + /// + /// Projects a vector onto a plane defined by a normal orthogonal to the plane. + /// + /// The vector to project. + /// The plane normal vector. + /// The projected vector. + static Double3 ProjectOnPlane(const Double3& vector, const Double3& planeNormal) + { + return vector - Project(vector, planeNormal); + } + + // Projects a 3D vector from object space into screen space + // @param vector The vector to project + // @param x The X position of the viewport + // @param y The Y position of the viewport + // @param width The width of the viewport + // @param height The height of the viewport + // @param minZ The minimum depth of the viewport + // @param maxZ The maximum depth of the viewport + // @param worldViewProjection The combined world-view-projection matrix + // @param result When the method completes, contains the vector in screen space + static void Project(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection, Double3& result); + + // Projects a 3D vector from object space into screen space + // @param vector The vector to project + // @param x The X position of the viewport + // @param y The Y position of the viewport + // @param width The width of the viewport + // @param height The height of the viewport + // @param minZ The minimum depth of the viewport + // @param maxZ The maximum depth of the viewport + // @param worldViewProjection The combined world-view-projection matrix + // @returns The vector in screen space + static Double3 Project(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection) + { + Double3 result; + Project(vector, x, y, width, height, minZ, maxZ, worldViewProjection, result); + return result; + } + + // Projects a 3D vector from screen space into object space + // @param vector The vector to project + // @param x The X position of the viewport + // @param y The Y position of the viewport + // @param width The width of the viewport + // @param height The height of the viewport + // @param minZ The minimum depth of the viewport + // @param maxZ The maximum depth of the viewport + // @param worldViewProjection The combined world-view-projection matrix + // @param result When the method completes, contains the vector in object space + static void Unproject(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection, Double3& result); + + // Projects a 3D vector from screen space into object space + // @param vector The vector to project + // @param x The X position of the viewport + // @param y The Y position of the viewport + // @param width The width of the viewport + // @param height The height of the viewport + // @param minZ The minimum depth of the viewport + // @param maxZ The maximum depth of the viewport + // @param worldViewProjection The combined world-view-projection matrix + // @returns The vector in object space + static Double3 Unproject(const Double3& vector, double x, double y, double width, double height, double minZ, double maxZ, const Matrix& worldViewProjection) + { + Double3 result; + Unproject(vector, x, y, width, height, minZ, maxZ, worldViewProjection, result); + return result; + } + + /// + /// Creates an orthonormal basis from a basis with at least two orthogonal vectors. + /// + /// The X axis. + /// The y axis. + /// The z axis. + static void CreateOrthonormalBasis(Double3& xAxis, Double3& yAxis, Double3& zAxis); + + /// + /// Finds the best arbitrary axis vectors to represent U and V axes of a plane, by using this vector as the normal of the plane. + /// + /// The reference to first axis. + /// The reference to second axis. + void FindBestAxisVectors(Double3& firstAxis, Double3& secondAxis) const; + + static Double3 Round(const Double3& v) + { + return Double3( + Math::Round(v.X), + Math::Round(v.Y), + Math::Round(v.Z) + ); + } + + static Double3 Ceil(const Double3& v) + { + return Double3( + Math::Ceil(v.X), + Math::Ceil(v.Y), + Math::Ceil(v.Z) + ); + } + + static Double3 Abs(const Double3& v) + { + return Double3(Math::Abs(v.X), Math::Abs(v.Y), Math::Abs(v.Z)); + } + + /// + /// Calculates the area of the triangle. + /// + /// The first triangle vertex. + /// The second triangle vertex. + /// The third triangle vertex. + /// The triangle area. + static double TriangleArea(const Double3& v0, const Double3& v1, const Double3& v2); + +}; + +inline Double3 operator+(double a, const Double3& b) +{ + return b + a; +} + +inline Double3 operator-(double a, const Double3& b) +{ + return Double3(a) - b; +} + +inline Double3 operator*(double a, const Double3& b) +{ + return b * a; +} + +inline Double3 operator/(double a, const Double3& b) +{ + return Double3(a) / b; +} + +namespace Math +{ + FORCE_INLINE static bool NearEqual(const Double3& a, const Double3& b) + { + return Double3::NearEqual(a, b); + } +} + +template<> +struct TIsPODType +{ + enum { Value = true }; +}; + +DEFINE_DEFAULT_FORMATTING(Double3, "X:{0} Y:{1} Z:{2}", v.X, v.Y, v.Z); From 281673dd6bda56b79d03b26a1869ff609660473a Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 18 Aug 2021 12:48:52 +0200 Subject: [PATCH 3/6] Add Double4 impl. cpp --- Source/Engine/Core/Math/Double4.cpp | 208 +++++++++++ Source/Engine/Core/Math/Double4.h | 556 ++++++++++++++++++++++++++++ 2 files changed, 764 insertions(+) create mode 100644 Source/Engine/Core/Math/Double4.cpp create mode 100644 Source/Engine/Core/Math/Double4.h diff --git a/Source/Engine/Core/Math/Double4.cpp b/Source/Engine/Core/Math/Double4.cpp new file mode 100644 index 000000000..ecaf611c1 --- /dev/null +++ b/Source/Engine/Core/Math/Double4.cpp @@ -0,0 +1,208 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "Double2.h" +#include "Double3.h" +#include "Double4.h" +#include "Vector4.h" +#include "Vector2.h" +#include "Vector3.h" +#include "Int2.h" +#include "Int3.h" +#include "Int4.h" +#include "Color.h" +#include "Matrix.h" +#include "Rectangle.h" +#include "../Types/String.h" + +static_assert(sizeof(Double4) == 32, "Invalid Double4 type size."); + +const Double4 Double4::Zero(0.0); +const Double4 Double4::One(1.0); +const Double4 Double4::UnitX(1, 0, 0, 0); +const Double4 Double4::UnitY(0, 1, 0, 0); +const Double4 Double4::UnitZ(0, 0, 1, 0); +const Double4 Double4::UnitW(0, 0, 0, 1); +const Double4 Double4::Minimum(MIN_double); +const Double4 Double4::Maximum(MAX_double); + +Double4::Double4(double xyzw[4]) +{ + Platform::MemoryCopy(Raw, xyzw, sizeof(double) * 4); +} + +Double4::Double4(const Vector2& xy, double z, double w) + : X(xy.X) + , Y(xy.Y) + , Z(z) + , W(w) +{ +} + +Double4::Double4(const Vector2& xy, const Vector2& zw) + : X(xy.X) + , Y(xy.Y) + , Z(zw.X) + , W(zw.Y) +{ +} + +Double4::Double4(const Vector3& xyz, double w) + : X(xyz.X) + , Y(xyz.Y) + , Z(xyz.Z) + , W(w) +{ +} + +Double4::Double4(const Int2& xy, double z, double w) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) + , Z(z) + , W(w) +{ +} + +Double4::Double4(const Int3& xyz, double w) + : X(static_cast(xyz.X)) + , Y(static_cast(xyz.Y)) + , Z(static_cast(xyz.Z)) + , W(w) +{ +} + +Double4::Double4(const Int4& xyzw) + : X(static_cast(xyzw.X)) + , Y(static_cast(xyzw.Y)) + , Z(static_cast(xyzw.X)) + , W(static_cast(xyzw.Y)) +{ +} + +Double4::Double4(const Double2& xy, double z, double w) + : X(xy.X) + , Y(xy.Y) + , Z(z) + , W(w) +{ +} + +Double4::Double4(const Double3& xyz, double w) + : X(xyz.X) + , Y(xyz.Y) + , Z(xyz.Z) + , W(w) +{ +} + +Double4::Double4(const Color& color) + : X(color.R) + , Y(color.G) + , Z(color.B) + , W(color.A) +{ +} + +Double4::Double4(const Rectangle& rect) + : X(rect.Location.X) + , Y(rect.Location.Y) + , Z(rect.Size.X) + , W(rect.Size.Y) +{ +} + +String Double4::ToString() const +{ + return String::Format(TEXT("{}"), *this); +} + +Double4 Double4::Floor(const Double4& v) +{ + return Double4( + Math::Floor(v.X), + Math::Floor(v.Y), + Math::Floor(v.Z), + Math::Floor(v.W) + ); +} + +Double4 Double4::Frac(const Double4& v) +{ + return Double4( + v.X - (int64)v.X, + v.Y - (int64)v.Y, + v.Z - (int64)v.Z, + v.W - (int64)v.W + ); +} + +Double4 Double4::Round(const Double4& v) +{ + return Double4( + Math::Round(v.X), + Math::Round(v.Y), + Math::Round(v.Z), + Math::Round(v.W) + ); +} + +Double4 Double4::Ceil(const Double4& v) +{ + return Double4( + Math::Ceil(v.X), + Math::Ceil(v.Y), + Math::Ceil(v.Z), + Math::Ceil(v.W) + ); +} + +Double4 Double4::Clamp(const Double4& value, const Double4& min, const Double4& max) +{ + double x = value.X; + x = x > max.X ? max.X : x; + x = x < min.X ? min.X : x; + + double y = value.Y; + y = y > max.Y ? max.Y : y; + y = y < min.Y ? min.Y : y; + + double z = value.Z; + z = z > max.Z ? max.Z : z; + z = z < min.Z ? min.Z : z; + + double w = value.W; + w = w > max.W ? max.W : w; + w = w < min.W ? min.W : w; + + return Double4(x, y, z, w); +} + +void Double4::Clamp(const Double4& value, const Double4& min, const Double4& max, Double4& result) +{ + double x = value.X; + x = x > max.X ? max.X : x; + x = x < min.X ? min.X : x; + + double y = value.Y; + y = y > max.Y ? max.Y : y; + y = y < min.Y ? min.Y : y; + + double z = value.Z; + z = z > max.Z ? max.Z : z; + z = z < min.Z ? min.Z : z; + + double w = value.W; + w = w > max.W ? max.W : w; + w = w < min.W ? min.W : w; + + result = Double4(x, y, z, w); +} + +Double4 Double4::Transform(const Double4& v, const Matrix& m) +{ + return Double4( + m.Values[0][0] * v.Raw[0] + m.Values[1][0] * v.Raw[1] + m.Values[2][0] * v.Raw[2] + m.Values[3][0] * v.Raw[3], + m.Values[0][1] * v.Raw[0] + m.Values[1][1] * v.Raw[1] + m.Values[2][1] * v.Raw[2] + m.Values[3][1] * v.Raw[3], + m.Values[0][2] * v.Raw[0] + m.Values[1][2] * v.Raw[1] + m.Values[2][2] * v.Raw[2] + m.Values[3][2] * v.Raw[3], + m.Values[0][3] * v.Raw[0] + m.Values[1][3] * v.Raw[1] + m.Values[2][3] * v.Raw[2] + m.Values[3][3] * v.Raw[3] + ); +} diff --git a/Source/Engine/Core/Math/Double4.h b/Source/Engine/Core/Math/Double4.h new file mode 100644 index 000000000..65f32e279 --- /dev/null +++ b/Source/Engine/Core/Math/Double4.h @@ -0,0 +1,556 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Platform/Platform.h" +#include "Engine/Core/Formatting.h" +#include "Engine/Core/Templates.h" +#include "Math.h" +#include "Mathd.h" + +struct Double2; +struct Double3; +struct Vector2; +struct Vector3; +struct Vector4; +struct Color; +struct Matrix; +struct Rectangle; +class String; +struct Int2; +struct Int3; +struct Int4; + +/// +/// Represents a four dimensional mathematical vector. +/// +API_STRUCT() struct FLAXENGINE_API Double4 +{ +DECLARE_SCRIPTING_TYPE_MINIMAL(Double4); +public: + + union + { + struct + { + /// + /// The X component. + /// + API_FIELD() double X; + + /// + /// The Y component. + /// + API_FIELD() double Y; + + /// + /// The Z component. + /// + API_FIELD() double Z; + + /// + /// The W component. + /// + API_FIELD() double W; + }; + + /// + /// The raw vector values (in xyzw order). + /// + double Raw[4]; + }; + +public: + + // Vector with all components equal 0 + static const Double4 Zero; + + // Vector with all components equal 1 + static const Double4 One; + + // Vector X=1, Y=0, Z=0, W=0 + static const Double4 UnitX; + + // Vector X=0, Y=1, Z=0, W=0 + static const Double4 UnitY; + + // Vector X=0, Y=0, Z=1, W=0 + static const Double4 UnitZ; + + // Vector X=0, Y=0, Z=0, W=1 + static const Double4 UnitW; + + // A minimum Double4 + static const Double4 Minimum; + + // A maximum Double4 + static const Double4 Maximum; + +public: + + /// + /// Empty constructor. + /// + Double4() + { + } + + // Init + // @param xyzw Value to assign to the all components + Double4(double xyzw) + : X(xyzw) + , Y(xyzw) + , Z(xyzw) + , W(xyzw) + { + } + + // Init + // @param xyzw Values to assign + explicit Double4(double xyzw[4]); + + // Init + // @param x X component value + // @param y Y component value + // @param z Z component value + // @param w W component value + Double4(double x, double y, double z, double w) + : X(x) + , Y(y) + , Z(z) + , W(w) + { + } + + // Init + // @param xy X and Y values in the vector + // @param z Z component value + // @param w W component value + explicit Double4(const Vector2& xy, double z, double w); + + // Init + // @param xy X and Y values in the vector + // @param zw Z and W values in the vector + // @param z Z component value + // @param w W component value + explicit Double4(const Vector2& xy, const Vector2& zw); + + // Init + // @param xyz X, Y and Z values in the vector + // @param w W component value + explicit Double4(const Vector3& xyz, double w); + + // Init + // @param xy X and Y values in the vector + // @param z Z component value + // @param w W component value + explicit Double4(const Int2& xy, double z, double w); + + // Init + // @param xyz X, Y and Z values in the vector + // @param w W component value + explicit Double4(const Int3& xyz, double w); + + // Init + // @param color Int4 value + explicit Double4(const Int4& xyzw); + + // Init + // @param xy X and Y values in the vector + // @param z Z component value + // @param w W component value + explicit Double4(const Double2& xy, double z, double w); + + // Init + // @param xyz X, Y and Z values in the vector + // @param w W component value + explicit Double4(const Double3& xyz, double w); + + // Init + // @param color Color value + explicit Double4(const Color& color); + + // Init + // @param rect Rectangle value + explicit Double4(const Rectangle& rect); + +public: + + String ToString() const; + +public: + + // Gets a value indicting whether this vector is zero + bool IsZero() const + { + return Math::IsZero(X) && Math::IsZero(Y) && Math::IsZero(Z) && Math::IsZero(W); + } + + // Gets a value indicting whether any vector component is zero + bool IsAnyZero() const + { + return Math::IsZero(X) || Math::IsZero(Y) || Math::IsZero(Z) || Math::IsZero(W); + } + + // Gets a value indicting whether this vector is one + bool IsOne() const + { + return Math::IsOne(X) && Math::IsOne(Y) && Math::IsOne(Z) && Math::IsOne(W); + } + + /// + /// Calculates a vector with values being absolute values of that vector + /// + /// Absolute vector + Double4 GetAbsolute() const + { + return Double4(Math::Abs(X), Math::Abs(Y), Math::Abs(Z), Math::Abs(W)); + } + + /// + /// Calculates a vector with values being opposite to values of that vector + /// + /// Negative vector + Double4 GetNegative() const + { + return Double4(-X, -Y, -Z, -W); + } + + /// + /// Returns average arithmetic of all the components + /// + /// Average arithmetic of all the components + double AverageArithmetic() const + { + return (X + Y + Z + W) * 0.25f; + } + + /// + /// Gets sum of all vector components values + /// + /// Sum of X, Y, Z and W + double SumValues() const + { + return X + Y + Z + W; + } + + /// + /// Returns minimum value of all the components + /// + /// Minimum value + double MinValue() const + { + return Math::Min(X, Y, Z, W); + } + + /// + /// Returns maximum value of all the components + /// + /// Maximum value + double MaxValue() const + { + return Math::Max(X, Y, Z, W); + } + + /// + /// Returns true if vector has one or more components is not a number (NaN) + /// + /// True if one or more components is not a number (NaN) + bool IsNaN() const + { + return isnan(X) || isnan(Y) || isnan(Z) || isnan(W); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity + /// + /// True if one or more components equal to +/- infinity + bool IsInfinity() const + { + return isinf(X) || isinf(Y) || isinf(Z) || isinf(W); + } + + /// + /// Returns true if vector has one or more components equal to +/- infinity or NaN + /// + /// True if one or more components equal to +/- infinity or NaN + bool IsNanOrInfinity() const + { + return IsInfinity() || IsNaN(); + } + +public: + + // Arithmetic operators with Double4 + inline Double4 operator+(const Double4& b) const + { + return Add(*this, b); + } + + inline Double4 operator-(const Double4& b) const + { + return Subtract(*this, b); + } + + inline Double4 operator*(const Double4& b) const + { + return Multiply(*this, b); + } + + inline Double4 operator/(const Double4& b) const + { + return Divide(*this, b); + } + + // op= operators with Double4 + inline Double4& operator+=(const Double4& b) + { + *this = Add(*this, b); + return *this; + } + + inline Double4& operator-=(const Double4& b) + { + *this = Subtract(*this, b); + return *this; + } + + inline Double4& operator*=(const Double4& b) + { + *this = Multiply(*this, b); + return *this; + } + + inline Double4& operator/=(const Double4& b) + { + *this = Divide(*this, b); + return *this; + } + + // Arithmetic operators with double + inline Double4 operator+(double b) const + { + return Add(*this, b); + } + + inline Double4 operator-(double b) const + { + return Subtract(*this, b); + } + + inline Double4 operator*(double b) const + { + return Multiply(*this, b); + } + + inline Double4 operator/(double b) const + { + return Divide(*this, b); + } + + // op= operators with double + inline Double4& operator+=(double b) + { + *this = Add(*this, b); + return *this; + } + + inline Double4& operator-=(double b) + { + *this = Subtract(*this, b); + return *this; + } + + inline Double4& operator*=(double b) + { + *this = Multiply(*this, b); + return *this; + } + + inline Double4& operator/=(double b) + { + *this = Divide(*this, b); + return *this; + } + + // Comparison + inline bool operator==(const Double4& b) const + { + return X == b.X && Y == b.Y && Z == b.Z && W == b.W; + } + + inline bool operator!=(const Double4& b) const + { + return X != b.X || Y != b.Y || Z != b.Z || W != b.W; + } + + inline bool operator>(const Double4& b) const + { + return X > b.X && Y > b.Y && Z > b.Z && W > b.W; + } + + inline bool operator>=(const Double4& b) const + { + return X >= b.X && Y >= b.Y && Z >= b.Z && W >= b.W; + } + + inline bool operator<(const Double4& b) const + { + return X < b.X && Y < b.Y && Z < b.Z && W < b.W; + } + + inline bool operator<=(const Double4& b) const + { + return X <= b.X && Y <= b.Y && Z <= b.Z && W <= b.W; + } + +public: + + static bool NearEqual(const Double4& a, const Double4& b) + { + return Math::NearEqual(a.X, b.X) && Math::NearEqual(a.Y, b.Y) && Math::NearEqual(a.Z, b.Z) && Math::NearEqual(a.W, b.W); + } + + static bool NearEqual(const Double4& a, const Double4& b, double epsilon) + { + return Math::NearEqual(a.X, b.X, epsilon) && Math::NearEqual(a.Y, b.Y, epsilon) && Math::NearEqual(a.Z, b.Z, epsilon) && Math::NearEqual(a.W, b.W, epsilon); + } + +public: + + static void Add(const Double4& a, const Double4& b, Double4& result) + { + result.X = a.X + b.X; + result.Y = a.Y + b.Y; + result.Z = a.Z + b.Z; + result.W = a.W + b.W; + } + + static Double4 Add(const Double4& a, const Double4& b) + { + Double4 result; + Add(a, b, result); + return result; + } + + static void Subtract(const Double4& a, const Double4& b, Double4& result) + { + result.X = a.X - b.X; + result.Y = a.Y - b.Y; + result.Z = a.Z - b.Z; + result.W = a.W - b.W; + } + + static Double4 Subtract(const Double4& a, const Double4& b) + { + Double4 result; + Subtract(a, b, result); + return result; + } + + static Double4 Multiply(const Double4& a, const Double4& b) + { + return Double4(a.X * b.X, a.Y * b.Y, a.Z * b.Z, a.W * b.W); + } + + static Double4 Multiply(const Double4& a, double b) + { + return Double4(a.X * b, a.Y * b, a.Z * b, a.W * b); + } + + static Double4 Divide(const Double4& a, const Double4& b) + { + return Double4(a.X / b.X, a.Y / b.Y, a.Z / b.Z, a.W / b.W); + } + + static Double4 Divide(const Double4& a, double b) + { + return Double4(a.X / b, a.Y / b, a.Z / b, a.W / b); + } + + static Double4 Floor(const Double4& v); + static Double4 Frac(const Double4& v); + static Double4 Round(const Double4& v); + static Double4 Ceil(const Double4& v); + +public: + + // Restricts a value to be within a specified range + // @param value The value to clamp + // @param min The minimum value, + // @param max The maximum value + // @returns Clamped value + static Double4 Clamp(const Double4& value, const Double4& min, const Double4& max); + + // Restricts a value to be within a specified range + // @param value The value to clamp + // @param min The minimum value, + // @param max The maximum value + // @param result When the method completes, contains the clamped value + static void Clamp(const Double4& value, const Double4& min, const Double4& max, Double4& result); + + // Performs a linear interpolation between two vectors + // @param start Start vector + // @param end End vector + // @param amount Value between 0 and 1 indicating the weight of end + // @param result When the method completes, contains the linear interpolation of the two vectors + static void Lerp(const Double4& start, const Double4& end, double amount, Double4& result) + { + result.X = Math::Lerp(start.X, end.X, amount); + result.Y = Math::Lerp(start.Y, end.Y, amount); + result.Z = Math::Lerp(start.Z, end.Z, amount); + result.W = Math::Lerp(start.W, end.W, amount); + } + + // + // Performs a linear interpolation between two vectors. + // + // @param start Start vector, + // @param end End vector, + // @param amount Value between 0 and 1 indicating the weight of @paramref end"/>, + // @returns The linear interpolation of the two vectors + static Double4 Lerp(const Double4& start, const Double4& end, double amount) + { + Double4 result; + Lerp(start, end, amount, result); + return result; + } + + static Double4 Transform(const Double4& v, const Matrix& m); +}; + +inline Double4 operator+(double a, const Double4& b) +{ + return b + a; +} + +inline Double4 operator-(double a, const Double4& b) +{ + return Double4(a) - b; +} + +inline Double4 operator*(double a, const Double4& b) +{ + return b * a; +} + +inline Double4 operator/(double a, const Double4& b) +{ + return Double4(a) / b; +} + +namespace Math +{ + FORCE_INLINE static bool NearEqual(const Double4& a, const Double4& b) + { + return Double4::NearEqual(a, b); + } +} + +template<> +struct TIsPODType +{ + enum { Value = true }; +}; + +DEFINE_DEFAULT_FORMATTING(Double4, "X:{0} Y:{1} Z:{2} W:{3}", v.X, v.Y, v.Z, v.W); From e655ee6b78b7a635983a72d0b9c4cb63511bcfa5 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 18 Aug 2021 12:49:12 +0200 Subject: [PATCH 4/6] Tweaks Double2 --- Source/Engine/Core/Math/Double2.cpp | 26 ++++++++++++++++++++------ Source/Engine/Core/Math/Double2.h | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Source/Engine/Core/Math/Double2.cpp b/Source/Engine/Core/Math/Double2.cpp index 4aa16249f..48534cc7d 100644 --- a/Source/Engine/Core/Math/Double2.cpp +++ b/Source/Engine/Core/Math/Double2.cpp @@ -1,6 +1,8 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #include "Double2.h" +#include "Double3.h" +#include "Double4.h" #include "Vector2.h" #include "Vector3.h" #include "Vector4.h" @@ -12,10 +14,10 @@ static_assert(sizeof(Double2) == 16, "Invalid Double2 type size."); -const Double2 Double2::Zero(0); -const Double2 Double2::One(1); -const Double2 Double2::UnitX(1, 0); -const Double2 Double2::UnitY(0, 1); +const Double2 Double2::Zero(0.0); +const Double2 Double2::One(1.0); +const Double2 Double2::UnitX(1.0, 0.0); +const Double2 Double2::UnitY(0.0, 1.0); const Double2 Double2::Minimum(MIN_double); const Double2 Double2::Maximum(MAX_double); @@ -55,6 +57,18 @@ Double2::Double2(const Vector4& xyzw) { } +Double2::Double2(const Double3& xyz) + : X(xyz.X) + , Y(xyz.Y) +{ +} + +Double2::Double2(const Double4& xyzw) + : X(xyzw.X) + , Y(xyzw.Y) +{ +} + Double2::Double2(const Color& color) : X(color.R) , Y(color.G) @@ -81,12 +95,12 @@ Double2 Double2::Normalize(const Double2& v) Int2 Double2::CeilToInt(const Double2& v) { - return Int2(Math::CeilToInt(v.X), Math::CeilToInt(v.Y)); + return Int2((int32)Math::CeilToInt(v.X), (int32)Math::CeilToInt(v.Y)); } Int2 Double2::FloorToInt(const Double2& v) { - return Int2(Math::FloorToInt(v.X), Math::FloorToInt(v.Y)); + return Int2((int32)Math::FloorToInt(v.X), (int32)Math::FloorToInt(v.Y)); } double Double2::TriangleArea(const Double2& v0, const Double2& v1, const Double2& v2) diff --git a/Source/Engine/Core/Math/Double2.h b/Source/Engine/Core/Math/Double2.h index a01e44fcb..e1ee3ef46 100644 --- a/Source/Engine/Core/Math/Double2.h +++ b/Source/Engine/Core/Math/Double2.h @@ -7,6 +7,8 @@ #include "Engine/Core/Formatting.h" #include "Engine/Core/Templates.h" +struct Double3; +struct Double4; struct Vector2; struct Vector3; struct Vector4; @@ -89,6 +91,16 @@ public: { } + /// + /// Init + /// + /// X and Z components in an array + explicit Double2(double xy[2]) + : X(xy[0]) + , Y(xy[1]) + { + } + // Init // @param v Int2 to use X and Y components explicit Double2(const Int2& xy); @@ -113,6 +125,14 @@ public: // @param v Vector4 to use X and Y components explicit Double2(const Vector4& xyzw); + // Init + // @param v Double3 to use X and Y components + explicit Double2(const Double3& xyz); + + // Init + // @param v Double4 to use X and Y components + explicit Double2(const Double4& xyzw); + // Init // @param color Color value explicit Double2(const Color& color); From c8ceb4f86b61b0cb6c209cbfa8aaf0a7d2dd605c Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 18 Aug 2021 12:49:38 +0200 Subject: [PATCH 5/6] Add DoubleX constructors for VectorX --- Source/Engine/Core/Math/Vector2.cpp | 21 +++++++++++++++++++ Source/Engine/Core/Math/Vector2.h | 15 ++++++++++++++ Source/Engine/Core/Math/Vector3.cpp | 24 ++++++++++++++++++++++ Source/Engine/Core/Math/Vector3.h | 18 ++++++++++++++++- Source/Engine/Core/Math/Vector4.cpp | 31 +++++++++++++++++++++++++++-- Source/Engine/Core/Math/Vector4.h | 18 +++++++++++++++++ 6 files changed, 124 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Core/Math/Vector2.cpp b/Source/Engine/Core/Math/Vector2.cpp index 2c6979575..c0c40b647 100644 --- a/Source/Engine/Core/Math/Vector2.cpp +++ b/Source/Engine/Core/Math/Vector2.cpp @@ -1,5 +1,8 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +#include "Double2.h" +#include "Double3.h" +#include "Double4.h" #include "Vector2.h" #include "Vector3.h" #include "Vector4.h" @@ -48,6 +51,24 @@ Vector2::Vector2(const Vector4& xyzw) { } +Vector2::Vector2(const Double2& xy) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) +{ +} + +Vector2::Vector2(const Double3& xyz) + : X(static_cast(xyz.X)) + , Y(static_cast(xyz.Y)) +{ +} + +Vector2::Vector2(const Double4& xyzw) + : X(static_cast(xyzw.X)) + , Y(static_cast(xyzw.Y)) +{ +} + Vector2::Vector2(const Color& color) : X(color.R) , Y(color.G) diff --git a/Source/Engine/Core/Math/Vector2.h b/Source/Engine/Core/Math/Vector2.h index aaea1d73c..11abd87b9 100644 --- a/Source/Engine/Core/Math/Vector2.h +++ b/Source/Engine/Core/Math/Vector2.h @@ -6,6 +6,9 @@ #include "Engine/Core/Formatting.h" #include "Engine/Core/Templates.h" +struct Double2; +struct Double3; +struct Double4; struct Vector3; struct Vector4; struct Int2; @@ -107,6 +110,18 @@ public: // @param v Vector4 to use X and Y components explicit Vector2(const Vector4& xyzw); + // Init + // @param xy Double2 to use X and Y components + explicit Vector2(const Double2& xy); + + // Init + // @param xyz Double3 to use X and Y components + explicit Vector2(const Double3& xyz); + + // Init + // @param xyzw Double4 to use X and Y components + explicit Vector2(const Double4& xyzw); + // Init // @param color Color value explicit Vector2(const Color& color); diff --git a/Source/Engine/Core/Math/Vector3.cpp b/Source/Engine/Core/Math/Vector3.cpp index 9c8783dad..176819149 100644 --- a/Source/Engine/Core/Math/Vector3.cpp +++ b/Source/Engine/Core/Math/Vector3.cpp @@ -1,5 +1,8 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +#include "Double2.h" +#include "Double3.h" +#include "Double4.h" #include "Vector2.h" #include "Vector3.h" #include "Vector4.h" @@ -70,6 +73,27 @@ Vector3::Vector3(const Vector4& xyz) { } +Vector3::Vector3(const Double2& xy, float z) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) + , Z(z) +{ +} + +Vector3::Vector3(const Double3& xyz) + : X(static_cast(xyz.X)) + , Y(static_cast(xyz.Y)) + , Z(static_cast(xyz.Z)) +{ +} + +Vector3::Vector3(const Double4& xyzw) + : X(static_cast(xyzw.X)) + , Y(static_cast(xyzw.Y)) + , Z(static_cast(xyzw.Z)) +{ +} + Vector3::Vector3(const Color& color) : X(color.R) , Y(color.G) diff --git a/Source/Engine/Core/Math/Vector3.h b/Source/Engine/Core/Math/Vector3.h index 761977c96..47dc6a593 100644 --- a/Source/Engine/Core/Math/Vector3.h +++ b/Source/Engine/Core/Math/Vector3.h @@ -6,6 +6,9 @@ #include "Engine/Core/Formatting.h" #include "Engine/Core/Templates.h" +struct Double2; +struct Double3; +struct Double4; struct Quaternion; struct Matrix; struct Vector2; @@ -134,7 +137,7 @@ public: // Init // @param xy Vector2 with X and Y components values // @param z Z component value - Vector3(const Vector2& xy, float z); + explicit Vector3(const Vector2& xy, float z); // Init // @param xy Vector3 value @@ -157,6 +160,19 @@ public: // @param xyz Vector4 value explicit Vector3(const Vector4& xyz); + // Init + // @param xy Double2 with X and Y components values + // @param z Z component value + explicit Vector3(const Double2& xy, float z); + + // Init + // @param xyz Double3 value + explicit Vector3(const Double3& xyz); + + // Init + // @param xyzw Double4 value + explicit Vector3(const Double4& xyzw); + // Init // @param color Color value explicit Vector3(const Color& color); diff --git a/Source/Engine/Core/Math/Vector4.cpp b/Source/Engine/Core/Math/Vector4.cpp index 5da725c20..3549e9293 100644 --- a/Source/Engine/Core/Math/Vector4.cpp +++ b/Source/Engine/Core/Math/Vector4.cpp @@ -1,5 +1,8 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +#include "Double4.h" +#include "Double3.h" +#include "Double2.h" #include "Vector4.h" #include "Vector2.h" #include "Vector3.h" @@ -70,8 +73,32 @@ Vector4::Vector4(const Int3& xyz, float w) Vector4::Vector4(const Int4& xyzw) : X(static_cast(xyzw.X)) , Y(static_cast(xyzw.Y)) - , Z(static_cast(xyzw.X)) - , W(static_cast(xyzw.Y)) + , Z(static_cast(xyzw.Z)) + , W(static_cast(xyzw.W)) +{ +} + +Vector4::Vector4(const Double2& xy, float z, float w) + : X(static_cast(xy.X)) + , Y(static_cast(xy.Y)) + , Z(z) + , W(w) +{ +} + +Vector4::Vector4(const Double3& xyz, float w) + : X(static_cast(xyz.X)) + , Y(static_cast(xyz.Y)) + , Z(static_cast(xyz.Z)) + , W(w) +{ +} + +Vector4::Vector4(const Double4& xyzw) + : X(static_cast(xyzw.X)) + , Y(static_cast(xyzw.Y)) + , Z(static_cast(xyzw.Z)) + , W(static_cast(xyzw.W)) { } diff --git a/Source/Engine/Core/Math/Vector4.h b/Source/Engine/Core/Math/Vector4.h index fe25a80bd..1c0926bc3 100644 --- a/Source/Engine/Core/Math/Vector4.h +++ b/Source/Engine/Core/Math/Vector4.h @@ -7,6 +7,9 @@ #include "Engine/Core/Templates.h" #include "Math.h" +struct Double2; +struct Double3; +struct Double4; struct Vector2; struct Vector3; struct Color; @@ -151,6 +154,21 @@ public: // @param color Int4 value explicit Vector4(const Int4& xyzw); + // Init + // @param xy Double2. X and Y values in the vector + // @param z Z component value + // @param w W component value + explicit Vector4(const Double2& xy, float z, float w); + + // Init + // @param xyz Double3. X, Y and Z values in the vector + // @param w W component value + explicit Vector4(const Double3& xyz, float w); + + // Init + // @param xyzw Double4 value + explicit Vector4(const Double4& xyzw); + // Init // @param color Color value explicit Vector4(const Color& color); From 5aaf09018f6664620e5b9e987a65429b799a9cd8 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 18 Aug 2021 12:49:53 +0200 Subject: [PATCH 6/6] Add missing NearEqual for double --- Source/Engine/Core/Math/Mathd.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Source/Engine/Core/Math/Mathd.h b/Source/Engine/Core/Math/Mathd.h index 47b16b608..8f7ac05b7 100644 --- a/Source/Engine/Core/Math/Mathd.h +++ b/Source/Engine/Core/Math/Mathd.h @@ -248,6 +248,34 @@ namespace Math return ulp > maxUlp; } + /// + /// Checks if a and b are almost equals, taking into account the magnitude of double precision floating point numbers + /// + /// The left value to compare + /// The right value to compare + /// True if a almost equal to b, otherwise false + static bool NearEqual(double a, double b) + { + // Check if the numbers are really close - needed when comparing numbers near zero + if (IsZero(a - b)) + return true; + + // Original from Bruce Dawson: http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + const int64 aInt = *(int64*)&a; + const int64 bInt = *(int64*)&b; + + // Different signs means they do not match + if (aInt < 0 != bInt < 0) + return false; + + // Find the difference in ULPs + const int64 ulp = Abs(aInt - bInt); + + // Choose of maxUlp = 4 + // according to http://code.google.com/p/googletest/source/browse/trunk/include/gtest/internal/gtest-internal.h + const int maxUlp = 4; + return ulp <= maxUlp; + } /// /// Checks if a and b are almost equals within the given epsilon value.