diff --git a/framework/common/gjk.cpp b/framework/common/gjk.cpp index 885a8b7..8d602d6 100644 --- a/framework/common/gjk.cpp +++ b/framework/common/gjk.cpp @@ -1,4 +1,4 @@ -#include "xna/common/gjk.hpp" +#include "xna/common/collision.hpp" namespace xna { Vector3 Gjk::ComputeClosestPoint() { diff --git a/inc/xna/common/collision.hpp b/inc/xna/common/collision.hpp index e43d24c..b4872ac 100644 --- a/inc/xna/common/collision.hpp +++ b/inc/xna/common/collision.hpp @@ -1,15 +1,83 @@ -#ifndef XNA_COMMON_SHAPES_HPP -#define XNA_COMMON_SHAPES_HPP +#ifndef XNA_COMMON_COLLISION_HPP +#define XNA_COMMON_COLLISION_HPP #include "../default.hpp" -#include "numerics.hpp" -#include "gjk.hpp" -#include #include "math.hpp" +#include "numerics.hpp" +#include namespace xna { + class Gjk { + public: + constexpr Gjk() {} + + constexpr bool FullSimplex() const { return simplexBits == 15; } + constexpr float MaxLengthSquared() const { return maxLengthSq; } + constexpr Vector3 ClosestPoint() const { return closestPoint; } + + constexpr void Reset() { + simplexBits = 0; + maxLengthSq = 0.0f; + } + + bool AddSupportPoint(Vector3 const& newPoint); + + private: + using listv3 = std::vector; + using listv3v3 = std::vector>; + using listf = std::vector; + using listff = std::vector>; + + void UpdateDeterminant(Int xmIdx); + bool UpdateSimplex(Int newIndex); + Vector3 ComputeClosestPoint(); + + constexpr bool IsSatisfiesRule(Int xBits, Int yBits) const { + bool flag = true; + for (auto bitsToIndex = Gjk::BitsToIndices[yBits]; bitsToIndex != 0; bitsToIndex >>= 3) + { + auto index = (bitsToIndex & 7) - 1; + auto num = 1 << index; + + if ((num & xBits) != 0) { + if (static_cast(det[xBits][index]) <= 0.0F) { + flag = false; + break; + } + } + else if (static_cast(det[xBits | num][index]) > 0.0F) { + flag = false; + break; + } + } + return flag; + } + + private: + inline static auto BitsToIndices = std::vector{ + 0, 1, 2, 17, 3, 25, 26, 209, 4, 33, 34, 273, 35, 281, 282, 2257 + }; + + using listv3 = std::vector; + using listv3v3 = std::vector>; + using listf = std::vector; + using listff = std::vector>; + + Vector3 closestPoint{}; + Int simplexBits{ 0 }; + float maxLengthSq{ 0 }; + listv3 y = listv3(4); + listf yLengthSq = listf(4); + listv3v3 edges = listv3v3(4, listv3(4)); + listff edgeLengthSq = listff(4, listf(4)); + listff det = listff(16, listf(4)); + }; + + //Defines a plane. struct Plane { + //The normal vector of the Plane. Vector3 Normal{ 0 }; + //The distance of the Plane along its normal from the origin. float D{ 0 }; constexpr Plane() = default; @@ -26,22 +94,34 @@ namespace xna { return Normal == other.Normal && D == other.D; } + //Changes the coefficients of the Normal vector of a Plane to make it of unit length. void Normalize(); + //Changes the coefficients of the Normal vector of a Plane to make it of unit length. static Plane Normalize(Plane const& value); + //Transforms a normalized Plane by a Matrix or Quaternion. static constexpr Plane Transform(Plane const& plane, Matrix const& matrix); + //Transforms a normalized Plane by a Matrix or Quaternion. static constexpr Plane Transform(Plane const& plane, Quaternion const& rotation); + //Calculates the dot product of a specified Vector4 and this Plane. constexpr float Dot(Vector4 const& value) const; + //Returns the dot product of a specified Vector3 and the Normal vector of this Plane plus the D constant value of the Plane. constexpr float DotCoordinate(Vector3 const& value) const; + //Returns the dot product of a specified Vector3 and the Normal vector of this Plane. constexpr float DotNormal(Vector3 const& value) const; + //Checks whether a Plane intersects a bounding volume. constexpr PlaneIntersectionType Intersects(BoundingBox const& box) const; + //Checks whether a Plane intersects a bounding volume. constexpr PlaneIntersectionType Intersects(BoundingFrustum const& frustum) const; + //Checks whether a Plane intersects a bounding volume. constexpr PlaneIntersectionType Intersects(BoundingSphere const& sphere) const; + //Checks whether a Plane intersects a bounding volume. std::optional Intersects(Ray const& ray) const; }; + //Defines a frustum and helps determine whether forms intersect with it. struct BoundingFrustum { inline static constexpr int CornerCount = 8; inline static constexpr int PlaneCount = 6; @@ -51,11 +131,17 @@ namespace xna { SetMatrix(matrix); } + //Gets the near plane of the BoundingFrustum. Plane Near() { return planes[0]; } + //Gets the far plane of the BoundingFrustum. Plane Far() { return planes[1]; } + //Gets the left plane of the BoundingFrustum. Plane Left() { return planes[2]; } + //Gets the right plane of the BoundingFrustum. Plane Right() { return planes[3]; } + //Gets the top plane of the BoundingFrustum. Plane Top() { return planes[4]; } + //Gets the bottom plane of the BoundingFrustum. Plane Bottom() { return planes[5]; } constexpr bool operator==(BoundingFrustum const& other) const { @@ -69,20 +155,32 @@ namespace xna { return corners[index]; } + //Gets an array of points that make up the corners of the BoundingFrustum. constexpr void GetCorners(std::vector& destination) const; + //Gets or sets the Matrix that describes this bounding frustum. constexpr Matrix GetMatrix() const { return matrix; } + //Gets or sets the Matrix that describes this bounding frustum. constexpr void SetMatrix(Matrix const& value); + //Gets or sets the Matrix that describes this bounding frustum. bool Intersects(BoundingBox const& box); + //Gets or sets the Matrix that describes this bounding frustum. bool Intersects(BoundingSphere const& box); + //Gets or sets the Matrix that describes this bounding frustum. constexpr PlaneIntersectionType Intersects(Plane const& plane) const; + //Gets or sets the Matrix that describes this bounding frustum. bool Intersects(BoundingFrustum const& frustum); + //Gets or sets the Matrix that describes this bounding frustum. std::optional Intersects(Ray const& ray) const; + //Checks whether the current BoundingFrustum contains a specified bounding volume. constexpr ContainmentType Contains(BoundingBox const& box) const; + //Checks whether the current BoundingFrustum contains a specified bounding volume. ContainmentType Contains(BoundingFrustum const& box); + //Checks whether the current BoundingFrustum contains a specified bounding volume. constexpr ContainmentType Contains(Vector3 const& point) const; + //Checks whether the current BoundingFrustum contains a specified bounding volume. constexpr ContainmentType Contains(BoundingSphere const& box) const; - constexpr void SupportMapping(Vector3 const& v, Vector3& result) const; + constexpr void SupportMapping(Vector3 const& v, Vector3& result) const; public: std::vector corners{ 8 }; @@ -96,10 +194,14 @@ namespace xna { static constexpr Vector3 ComputeIntersection(Plane const& plane, Ray const& ray); }; + //Defines an axis-aligned box-shaped 3D volume. struct BoundingBox { + //Specifies the total number of corners (8) in the BoundingBox. inline static constexpr int CornerCount = 8; + //The maximum point the BoundingBox contains. Vector3 Min{}; + //The minimum point the BoundingBox contains. Vector3 Max{}; constexpr BoundingBox() = default; @@ -110,28 +212,44 @@ namespace xna { return Min == other.Min && Max == other.Max; } + //Gets an array of points that make up the corners of the BoundingBox. constexpr void GetCorners(std::vector& corners) const; + //Creates the smallest BoundingBox that contains the two specified BoundingBox instances. static constexpr BoundingBox CreateMerged(BoundingBox const& original, BoundingBox const& additional); + //Creates the smallest BoundingBox that will contain the specified BoundingSphere. static constexpr BoundingBox CreateFromSphere(BoundingSphere const& sphere); + //Creates the smallest BoundingBox that will contain a group of points. static constexpr BoundingBox CreateFromPoints(std::vector const& points); + //Checks whether the current BoundingBox intersects with another bounding volume. constexpr bool Intersects(BoundingBox const& box) const; + //Checks whether the current BoundingBox intersects with another bounding volume. bool Intersects(BoundingFrustum& frustum) const; + //Checks whether the current BoundingBox intersects with another bounding volume. constexpr PlaneIntersectionType Intersects(Plane const& plane) const; + //Checks whether the current BoundingBox intersects with another bounding volume. std::optional Intersects(Ray const& ray) const; + //Checks whether the current BoundingBox intersects with another bounding volume. constexpr bool Intersects(BoundingSphere const& sphere) const; + //Tests whether the BoundingBox overlaps another bounding volume. constexpr ContainmentType Contains(BoundingBox const& box) const; + //Tests whether the BoundingBox overlaps another bounding volume. ContainmentType Contains(BoundingFrustum& frustum) const; + //Tests whether the BoundingBox overlaps another bounding volume. constexpr ContainmentType Contains(Vector3 const& point) const; + //Tests whether the BoundingBox overlaps another bounding volume. constexpr ContainmentType Contains(BoundingSphere const& sphere) const; constexpr void SupportMapping(Vector3 const& v, Vector3& result) const; }; + //Defines a sphere. struct BoundingSphere { + //The center point of the sphere. Vector3 Center{}; + //The radius of the sphere. float Radius{ 0 }; constexpr BoundingSphere() = default; @@ -142,28 +260,46 @@ namespace xna { return Center == other.Center && Radius == other.Radius; } + //Creates a BoundingSphere that contains the two specified BoundingSphere instances. static BoundingSphere CreateMerged(BoundingSphere const& original, BoundingSphere const& additional); + //Creates the smallest BoundingSphere that can contain a specified BoundingBox. static BoundingSphere CreateFromBoundingBox(BoundingBox const& box); + //Creates a BoundingSphere that can contain a specified list of points. static BoundingSphere CreateFromPoints(std::vector const& points); + //Creates the smallest BoundingSphere that can contain a specified BoundingFrustum. static BoundingSphere CreateFromFrustum(BoundingFrustum const& points); + //Checks whether the current BoundingSphere intersects another bounding volume. constexpr bool Intersects(BoundingBox const& box) const; + //Checks whether the current BoundingSphere intersects another bounding volume. bool Intersects(BoundingFrustum& frustum) const; + //Checks whether the current BoundingSphere intersects another bounding volume. constexpr PlaneIntersectionType Intersects(Plane const& plane) const; + //Checks whether the current BoundingSphere intersects another bounding volume. std::optional Intersects(Ray const& ray) const; + //Checks whether the current BoundingSphere intersects another bounding volume. constexpr bool Intersects(BoundingSphere const& sphere) const; + //Checks whether the current BoundingSphere contains a specified bounding volume. ContainmentType Contains(BoundingBox const& box) const; + //Checks whether the current BoundingSphere contains a specified bounding volume. ContainmentType Contains(BoundingFrustum& frustum) const; + //Checks whether the current BoundingSphere contains a specified bounding volume. ContainmentType Contains(Vector3 const& point) const; + //Checks whether the current BoundingSphere contains a specified bounding volume. ContainmentType Contains(BoundingSphere const& sphere) const; + + //Translates and scales the BoundingSphere using a given Matrix. BoundingSphere Transform(Matrix const& matrix) const; void SupportMapping(Vector3 const& v, Vector3& result) const; }; + //Defines a ray. struct Ray { + //Specifies the starting point of the Ray. Vector3 Position{}; + //Unit vector specifying the direction the Ray is pointing. Vector3 Direction{}; constexpr Ray() = default; @@ -174,19 +310,23 @@ namespace xna { return Position == other.Position && Direction == other.Direction; } - std::optional Intersects(BoundingBox const& box) const { + //Checks whether the Ray intersects a specified plane or bounding volume. + inline std::optional Intersects(BoundingBox const& box) const { return box.Intersects(*this); } - std::optional Intersects(BoundingFrustum const& frustum) const { + //Checks whether the Ray intersects a specified plane or bounding volume. + inline std::optional Intersects(BoundingFrustum const& frustum) const { return frustum.Intersects(*this); } - std::optional Intersects(Plane const& plane) const { + //Checks whether the Ray intersects a specified plane or bounding volume. + inline std::optional Intersects(Plane const& plane) const { return plane.Intersects(*this); } - std::optional Sphere(BoundingSphere const& sphere) const { + //Checks whether the Ray intersects a specified plane or bounding volume. + inline std::optional Intersects(BoundingSphere const& sphere) const { return sphere.Intersects(*this); } }; diff --git a/inc/xna/common/gjk.hpp b/inc/xna/common/gjk.hpp deleted file mode 100644 index deaae30..0000000 --- a/inc/xna/common/gjk.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef XNA_COMMON_GDK_HPP -#define XNA_COMMON_GDK_HPP - -#include "../default.hpp" -#include "numerics.hpp" -#include "math.hpp" - -namespace xna { - class Gjk { - public: - constexpr Gjk() = default; - - constexpr bool FullSimplex() const { return simplexBits == 15; } - constexpr float MaxLengthSquared() const { return maxLengthSq; } - constexpr Vector3 ClosestPoint() const { return closestPoint; } - - constexpr void Reset() { - simplexBits = 0; - maxLengthSq = 0.0f; - } - - bool AddSupportPoint(Vector3 const& newPoint); - - private: - using listv3 = std::vector; - using listv3v3 = std::vector>; - using listf = std::vector; - using listff = std::vector>; - - void UpdateDeterminant(Int xmIdx); - bool UpdateSimplex(Int newIndex); - Vector3 ComputeClosestPoint(); - - constexpr bool IsSatisfiesRule(Int xBits, Int yBits) const { - bool flag = true; - for (auto bitsToIndex = Gjk::BitsToIndices[yBits]; bitsToIndex != 0; bitsToIndex >>= 3) - { - auto index = (bitsToIndex & 7) - 1; - auto num = 1 << index; - - if ((num & xBits) != 0) { - if (static_cast(det[xBits][index]) <= 0.0F) { - flag = false; - break; - } - } - else if (static_cast(det[xBits | num][index]) > 0.0F) { - flag = false; - break; - } - } - return flag; - } - - private: - inline static auto BitsToIndices = std::vector { - 0, 1, 2, 17, 3, 25, 26, 209, 4, 33, 34, 273, 35, 281, 282, 2257 - }; - - Vector3 closestPoint{}; - Int simplexBits{0}; - float maxLengthSq{0}; - listv3 y = listv3(4); - listf yLengthSq = listf(4); - listv3v3 edges = listv3v3(4, listv3(4)); - listff edgeLengthSq = listff(4, listf(4)); - listff det = listff(16, listf(4)); - }; -} - -#endif \ No newline at end of file diff --git a/inc/xna/common/numerics.hpp b/inc/xna/common/numerics.hpp index bb36aa5..d637230 100644 --- a/inc/xna/common/numerics.hpp +++ b/inc/xna/common/numerics.hpp @@ -90,42 +90,44 @@ namespace xna { } constexpr static Rectangle Intersect(Rectangle const& value1, Rectangle const& value2) { - const auto left1 = value1.Left(); - const auto left2 = value2.Left(); - const auto bottom1 = value1.Bottom(); - const auto bottom2 = value2.Bottom(); - const auto maxX = value1.X > value2.X ? value1.X : value2.X; - const auto maxY = value1.Y > value2.Y ? value1.Y : value2.Y; - const auto maxl = left1 < left2 ? left1 : left2; - const auto maxb = bottom1 < bottom2 ? bottom1 : bottom2; + const auto num1 = value1.X + value1.Width; + const auto num2 = value2.X + value2.Width; + const auto num3 = value1.Y + value1.Height; + const auto num4 = value2.Y + value2.Height; + const auto num5 = value1.X > value2.X ? value1.X : value2.X; + const auto num6 = value1.Y > value2.Y ? value1.Y : value2.Y; + const auto num7 = num1 < num2 ? num1 : num2; + const auto num8 = num3 < num4 ? num3 : num4; Rectangle rectangle{}; - if (maxl > maxX && maxb > maxY) { - rectangle.X = maxX; - rectangle.Y = maxY; - rectangle.Width = maxl - maxX; - rectangle.Height = maxb - maxY; + if (num7 > num5 && num8 > num6) + { + rectangle.X = num5; + rectangle.Y = num6; + rectangle.Width = num7 - num5; + rectangle.Height = num8 - num6; } - + return rectangle; } constexpr static Rectangle Union(Rectangle const& value1, Rectangle const& value2) { - const auto left1 = value1.Left(); - const auto left2 = value2.Left(); - const auto bottom1 = value1.Bottom(); - const auto bottom2 = value2.Bottom(); - const auto minX = value1.X < value2.X ? value1.X : value2.X; - const auto miny = value1.Y < value2.Y ? value1.Y : value2.Y; - const auto maxl = left1 > left2 ? left1 : left2; - const auto maxb = bottom1 > bottom2 ? bottom1 : bottom2; + const auto num1 = value1.X + value1.Width; + const auto num2 = value2.X + value2.Width; + const auto num3 = value1.Y + value1.Height; + const auto num4 = value2.Y + value2.Height; + const auto num5 = value1.X < value2.X ? value1.X : value2.X; + const auto num6 = value1.Y < value2.Y ? value1.Y : value2.Y; + const auto num7 = num1 > num2 ? num1 : num2; + const auto num8 = num3 > num4 ? num3 : num4; Rectangle rectangle; - rectangle.X = minX; - rectangle.Y = miny; - rectangle.Width = maxl - minX; - rectangle.Height = maxb - miny; + rectangle.X = num5; + rectangle.Y = num6; + rectangle.Width = num7 - num5; + rectangle.Height = num8 - num6; + return rectangle; } }; diff --git a/inc/xna/xna.hpp b/inc/xna/xna.hpp index 6d96b10..5f017df 100644 --- a/inc/xna/xna.hpp +++ b/inc/xna/xna.hpp @@ -4,7 +4,6 @@ #include "common/collision.hpp" #include "common/color.hpp" #include "common/curve.hpp" -#include "common/gjk.hpp" #include "common/math.hpp" #include "common/numerics.hpp" #include "common/packedvalue.hpp"