diff --git a/framework/common/collision.cpp b/framework/common/collision.cpp index d8c8f55..7767d34 100644 --- a/framework/common/collision.cpp +++ b/framework/common/collision.cpp @@ -196,4 +196,87 @@ namespace xna { } return containmentType; } + + std::optional BoundingBox::Intersects(Ray const& ray) const { + float num1 = 0.0f; + float num2 = FloatMaxValue; + + if (std::abs(ray.Direction.X) < 9.9999999747524271E-07) + { + if (ray.Position.X < Min.X || ray.Position.X > Max.X) + return {}; + } + else + { + const auto num3 = 1.0f / ray.Direction.X; + auto num4 = (Min.X - ray.Position.X) * num3; + auto num5 = (Max.X - ray.Position.X) * num3; + if (num4 > num5) + { + float num6 = num4; + num4 = num5; + num5 = num6; + } + num1 = MathHelper::Max(num4, num1); + num2 = MathHelper::Min(num5, num2); + if (num1 > num2) + return {}; + } + if (std::abs(ray.Direction.Y) < 9.9999999747524271E-07) + { + if (ray.Position.Y < Min.Y || ray.Position.Y > Max.Y) + return {}; + } + else + { + const auto num7 = 1.0f / ray.Direction.Y; + auto num8 = (Min.Y - ray.Position.Y) * num7; + auto num9 = (Max.Y - ray.Position.Y) * num7; + if (num8 > num9) + { + float num10 = num8; + num8 = num9; + num9 = num10; + } + num1 = MathHelper::Max(num8, num1); + num2 = MathHelper::Min(num9, num2); + if (num1 > num2) + return {}; + } + if (std::abs(ray.Direction.Z) < 9.9999999747524271E-07) + { + if (ray.Position.Z < Min.Z || ray.Position.Z > Max.Z) + return {}; + } + else + { + const auto num11 = 1.0f / ray.Direction.Z; + auto num12 = (Min.Z - ray.Position.Z) * num11; + auto num13 = (Max.Z - ray.Position.Z) * num11; + if (num12 > num13) + { + float num14 = num12; + num12 = num13; + num13 = num14; + } + num1 = MathHelper::Max(num12, num1); + const auto num15 = MathHelper::Min(num13, num2); + if (num1 > num15) + return {}; + } + return num1; + } + + ContainmentType BoundingBox::Contains(BoundingFrustum& frustum) const { + if (!frustum.Intersects(*this)) + return ContainmentType::Disjoint; + + for (size_t i = 0; i < frustum.CornerCount; ++i) { + const auto corner = frustum[i]; + + if (Contains(corner) == ContainmentType::Disjoint) + return ContainmentType::Intersects; + } + return ContainmentType::Contains; + } } \ No newline at end of file diff --git a/inc/common/collision.hpp b/inc/common/collision.hpp index a194684..f35123a 100644 --- a/inc/common/collision.hpp +++ b/inc/common/collision.hpp @@ -17,6 +17,11 @@ namespace xna { inline static constexpr int CornerCount = 8; inline static constexpr int PlaneCount = 6; + constexpr BoundingFrustum() = default; + constexpr BoundingFrustum(Matrix const& matrix) { + SetMatrix(matrix); + } + Plane Near() { return planes[0]; } Plane Far() { return planes[1]; } Plane Left() { return planes[2]; } @@ -28,6 +33,13 @@ namespace xna { return matrix == other.matrix; } + constexpr Vector3 operator[](size_t index) const { + if (index >= CornerCount) + index = CornerCount - 1; + + return corners[index]; + } + constexpr void GetCorners(std::vector& destination) const; constexpr Matrix GetMatrix() const { return matrix; } constexpr void SetMatrix(Matrix const& value); @@ -40,11 +52,11 @@ namespace xna { ContainmentType Contains(BoundingFrustum const& box); constexpr ContainmentType Contains(Vector3 const& point) const; 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; private: - std::vector planes{ 6 }; std::vector corners{ 8 }; + std::vector planes{ 6 }; Matrix matrix{ Matrix::Identity() }; Gjk gjk{}; @@ -54,16 +66,37 @@ namespace xna { }; struct BoundingBox { + inline static constexpr int CornerCount = 8; + Vector3 Min{}; Vector3 Max{}; - constexpr PlaneIntersectionType Intersects(Plane const& plane) const { - return PlaneIntersectionType::Intersecting; + constexpr BoundingBox() = default; + constexpr BoundingBox(Vector3 const& min, Vector3 const& max): + Min(min), Max(max){} + + constexpr bool operator==(BoundingBox const& other) const { + return Min == other.Min && Max == other.Max; } - void SupportMapping(Vector3 const& v, Vector3& result) const { + constexpr void GetCorners(std::vector& corners) const; - } + static constexpr BoundingBox CreateMerged(BoundingBox const& original, BoundingBox const& additional); + static constexpr BoundingBox CreateFromSphere(BoundingSphere const& sphere); + static constexpr BoundingBox CreateFromPoints(std::vector const& points); + + constexpr bool Intersects(BoundingBox const& box) const; + bool Intersects(BoundingFrustum& frustum) const; + constexpr PlaneIntersectionType Intersects(Plane const& plane) const; + std::optional Intersects(Ray const& ray) const; + constexpr bool Intersects(BoundingSphere const& sphere) const; + + constexpr ContainmentType Contains(BoundingBox const& box) const; + ContainmentType Contains(BoundingFrustum& frustum) const; + constexpr ContainmentType Contains(Vector3 const& point) const; + constexpr ContainmentType Contains(BoundingSphere const& sphere) const; + + constexpr void SupportMapping(Vector3 const& v, Vector3& result) const; }; struct BoundingSphere { @@ -234,6 +267,137 @@ namespace xna { corners[5] = BoundingFrustum::ComputeIntersection(planes[4], intersectionLine2); corners[6] = BoundingFrustum::ComputeIntersection(planes[5], intersectionLine2); } + + + constexpr void BoundingBox::GetCorners(std::vector& corners) const { + if (corners.size() < 8) + corners.resize(CornerCount); + + corners[0].X = Min.X; + corners[0].Y = Max.Y; + corners[0].Z = Max.Z; + corners[1].X = Max.X; + corners[1].Y = Max.Y; + corners[1].Z = Max.Z; + corners[2].X = Max.X; + corners[2].Y = Min.Y; + corners[2].Z = Max.Z; + corners[3].X = Min.X; + corners[3].Y = Min.Y; + corners[3].Z = Max.Z; + corners[4].X = Min.X; + corners[4].Y = Max.Y; + corners[4].Z = Min.Z; + corners[5].X = Max.X; + corners[5].Y = Max.Y; + corners[5].Z = Min.Z; + corners[6].X = Max.X; + corners[6].Y = Min.Y; + corners[6].Z = Min.Z; + corners[7].X = Min.X; + corners[7].Y = Min.Y; + corners[7].Z = Min.Z; + } + + constexpr BoundingBox BoundingBox::CreateMerged(BoundingBox const& original, BoundingBox const& additional) { + BoundingBox merged; + merged.Min = Vector3::Min(original.Min, additional.Min); + merged.Max = Vector3::Max(original.Max, additional.Max); + return merged; + } + + constexpr BoundingBox BoundingBox::CreateFromSphere(BoundingSphere const& sphere) { + BoundingBox fromSphere; + fromSphere.Min.X = sphere.Center.X - sphere.Radius; + fromSphere.Min.Y = sphere.Center.Y - sphere.Radius; + fromSphere.Min.Z = sphere.Center.Z - sphere.Radius; + fromSphere.Max.X = sphere.Center.X + sphere.Radius; + fromSphere.Max.Y = sphere.Center.Y + sphere.Radius; + fromSphere.Max.Z = sphere.Center.Z + sphere.Radius; + return fromSphere; + } + + constexpr BoundingBox BoundingBox::CreateFromPoints(std::vector const& points) { + Vector3 result1 = Vector3(FloatMaxValue); + Vector3 result2 = Vector3(FloatMinValue); + + for (size_t i = 0; i < points.size(); ++i) { + const auto& point = points[i]; + result1 = Vector3::Min(result1, point); + result2 = Vector3::Max(result2, point); + } + + return BoundingBox(result1, result2); + } + + constexpr bool BoundingBox::Intersects(BoundingBox const& box) const { + return Max.X >= box.Min.X + && Min.X <= box.Max.X + && Max.Y >= box.Min.Y + && Min.Y <= box.Max.Y + && Max.Z >= box.Min.Z + && Min.Z <= box.Max.Z; + } + + inline bool BoundingBox::Intersects(BoundingFrustum& frustum) const { + return frustum.Intersects(*this); + } + + constexpr PlaneIntersectionType BoundingBox::Intersects(Plane const& plane) const { + Vector3 vector3_1; + vector3_1.X = plane.Normal.X >= 0.0 ? Min.X : Max.X; + vector3_1.Y = plane.Normal.Y >= 0.0 ? Min.Y : Max.Y; + vector3_1.Z = plane.Normal.Z >= 0.0 ? Min.Z : Max.Z; + Vector3 vector3_2; + vector3_2.X = plane.Normal.X >= 0.0 ? Max.X : Min.X; + vector3_2.Y = plane.Normal.Y >= 0.0 ? Max.Y : Min.Y; + vector3_2.Z = plane.Normal.Z >= 0.0 ? Max.Z : Min.Z; + if (plane.Normal.X * vector3_1.X + plane.Normal.Y * vector3_1.Y + plane.Normal.Z * vector3_1.Z + plane.D > 0.0) + return PlaneIntersectionType::Front; + + return plane.Normal.X * vector3_2.X + plane.Normal.Y * vector3_2.Y + plane.Normal.Z * vector3_2.Z + plane.D < 0.0 + ? PlaneIntersectionType::Back + : PlaneIntersectionType::Intersecting; + } + + constexpr bool BoundingBox::Intersects(BoundingSphere const& sphere) const { + const auto result1 = Vector3::Clamp(sphere.Center, Min, Max); + const auto result2 = Vector3::DistanceSquared(sphere.Center, result1); + return result2 <= sphere.Radius * sphere.Radius; + } + + constexpr ContainmentType BoundingBox::Contains(BoundingBox const& box) const { + if (Max.X < box.Min.X || Min.X > box.Max.X || Max.Y < box.Min.Y || Min.Y > box.Max.Y || Max.Z < box.Min.Z || Min.Z > box.Max.Z) + return ContainmentType::Disjoint; + return Min.X > box.Min.X || box.Max.X > Max.X || Min.Y > box.Min.Y || box.Max.Y > Max.Y || Min.Z > box.Min.Z || box.Max.Z > Max.Z + ? ContainmentType::Intersects + : ContainmentType::Contains; + } + + constexpr ContainmentType BoundingBox::Contains(Vector3 const& point) const { + return Min.X > point.X || point.X > Max.X || Min.Y > point.Y || point.Y > Max.Y || Min.Z > point.Z || point.Z > Max.Z + ? ContainmentType::Disjoint + : ContainmentType::Contains; + } + + constexpr ContainmentType BoundingBox::Contains(BoundingSphere const& sphere) const { + Vector3 result1 = Vector3::Clamp(sphere.Center, Min, Max); + float result2 = Vector3::DistanceSquared(sphere.Center, result1); + float radius = sphere.Radius; + + if (result2 > radius * radius) + return ContainmentType::Disjoint; + + return Min.X + radius > sphere.Center.X || sphere.Center.X > Max.X - radius || Max.X - Min.X <= radius || Min.Y + radius > sphere.Center.Y || sphere.Center.Y > Max.Y - radius || Max.Y - Min.Y <= radius || Min.Z + radius > sphere.Center.Z || sphere.Center.Z > Max.Z - radius || Max.X - Min.X <= radius + ? ContainmentType::Intersects + : ContainmentType::Contains; + } + + constexpr void BoundingBox::SupportMapping(Vector3 const& v, Vector3& result) const { + result.X = v.X >= 0.0 ? Max.X : Min.X; + result.Y = v.Y >= 0.0 ? Max.Y : Min.Y; + result.Z = v.Z >= 0.0 ? Max.Z : Min.Z; + } } #endif \ No newline at end of file