diff --git a/Runtime/World/CPathFindArea.cpp b/Runtime/World/CPathFindArea.cpp index 85a0dad32..fe3df8c87 100644 --- a/Runtime/World/CPathFindArea.cpp +++ b/Runtime/World/CPathFindArea.cpp @@ -48,6 +48,36 @@ int CPFAreaOctree::GetChildIndex(const zeus::CVector3f& point) const return idx; } +void CPFAreaOctree::GetRegionListList(rstl::reserved_vector*, 32>& listOut, + const zeus::CVector3f& point, float padding) +{ + if (listOut.size() >= listOut.capacity()) + return; + + if (x0_isLeaf) + { + listOut.push_back(&x48_regions); + return; + } + + for (int i=0 ; i<8 ; ++i) + { + CPFAreaOctree* ch = x28_children[i]; + if (ch->IsPointInsidePaddedAABox(point, padding)) + ch->GetRegionListList(listOut, point, padding); + } +} + +bool CPFAreaOctree::IsPointInsidePaddedAABox(const zeus::CVector3f& point, float padding) const +{ + return point.x >= x4_aabb.min.x - padding && + point.x <= x4_aabb.max.x + padding && + point.y >= x4_aabb.min.y - padding && + point.y <= x4_aabb.max.y + padding && + point.z >= x4_aabb.min.z - padding && + point.z <= x4_aabb.max.z + padding; +} + CPFOpenList::CPFOpenList() { @@ -84,7 +114,7 @@ CPFArea::CPFArea(std::unique_ptr&& buf, u32 len) region.Fixup(*this, maxRegionNodes); maxRegionNodes = std::max(maxRegionNodes, 4u); - x10_.reserve(maxRegionNodes); + x10_tmpPolyPoints.reserve(maxRegionNodes); u32 numBitfieldWords = (numRegions * (numRegions - 1) / 2 + 31) / 32; x168_connectionsGround.reserve(numBitfieldWords); @@ -113,6 +143,39 @@ CPFArea::CPFArea(std::unique_ptr&& buf, u32 len) node.Fixup(*this); } +CPFRegion* CPFArea::FindClosestRegion(const zeus::CVector3f& point, u32 flags, u32 indexMask, float padding) +{ + rstl::reserved_vector*, 32> regionListList; + x158_octree.back().GetRegionListList(regionListList, point, padding); + bool isFlyer = (flags & 0x2) != 0; + for (rstl::prereserved_vector* list : regionListList) + { + for (CPFRegion* region : *list) + { + if (region->Data()->GetCookie() != x34_curRegionCookie) + { + if (region->GetFlags() & 0xff & flags && + (region->GetFlags() >> 16) & 0xff & indexMask && + region->IsPointInsidePaddedAABox(point, padding) && + (isFlyer || region->PointHeight(point) < 3.f)) + { + if (region->FindBestPoint(x10_tmpPolyPoints, point, flags, padding * padding)) + { + // TODO: Finish + } + } + region->Data()->SetCookie(x34_curRegionCookie); + } + } + } + return nullptr; +} + +void CPFArea::FindClosestReachablePoint(rstl::reserved_vector&, const zeus::CVector3f&, u32) +{ + +} + bool CPFArea::PathExists(const CPFRegion* r1, const CPFRegion* r2, u32 flags) const { if (r1 == r2 || (flags & 0x4) != 0) diff --git a/Runtime/World/CPathFindArea.hpp b/Runtime/World/CPathFindArea.hpp index c21ac4625..062600116 100644 --- a/Runtime/World/CPathFindArea.hpp +++ b/Runtime/World/CPathFindArea.hpp @@ -34,8 +34,9 @@ public: void Fixup(CPFArea& area); int GetChildIndex(const zeus::CVector3f& point) const; void GetRegionList(const zeus::CVector3f&) const; - void GetRegionListList(rstl::reserved_vector*, 32>, const zeus::CVector3f&, float); - bool IsPointInPaddedAABox(const zeus::CVector3f&, float); + void GetRegionListList(rstl::reserved_vector*, 32>& listOut, + const zeus::CVector3f& point, float padding); + bool IsPointInsidePaddedAABox(const zeus::CVector3f& point, float padding) const; void Render(); }; @@ -75,14 +76,15 @@ class CPFArea { friend class CPFRegion; friend class CPFAreaOctree; + friend class CPathFindSearch; float x0_ = FLT_MAX; zeus::CVector3f x4_; - std::vector x10_; + std::vector x10_tmpPolyPoints; u32 x20_ = 0; zeus::CVector3f x24_; bool x30_ = false; - u32 x34_ = 0; + s32 x34_curRegionCookie = 0; u32 x38_ = 0; u32 x3c_ = 0; u32 x40_ = 0; @@ -129,8 +131,9 @@ public: const CPFAreaOctree& GetOctree(s32 i) const { return x158_octree[i]; } const CPFRegion* GetOctreeRegionPtrs(s32 i) const { return x160_octreeRegionLookup[i]; } void GetOctreeRegionList(const zeus::CVector3f&); - void FindRegions(rstl::reserved_vector&, const zeus::CVector3f&, u32); - void FindClosestRegion(const zeus::CVector3f&, u32, float); + u32 FindRegions(rstl::reserved_vector& regions, const zeus::CVector3f& point, + u32 flags, u32 indexMask); + CPFRegion* FindClosestRegion(const zeus::CVector3f& point, u32 flags, u32 indexMask, float padding); void FindClosestReachablePoint(rstl::reserved_vector&, const zeus::CVector3f&, u32); bool PathExists(const CPFRegion* r1, const CPFRegion* r2, u32 flags) const; }; diff --git a/Runtime/World/CPathFindRegion.cpp b/Runtime/World/CPathFindRegion.cpp index c21d3e898..37fa8bca2 100644 --- a/Runtime/World/CPathFindRegion.cpp +++ b/Runtime/World/CPathFindRegion.cpp @@ -48,6 +48,128 @@ void CPFRegion::Fixup(CPFArea& area, u32& maxRegionNodes) maxRegionNodes = x0_numNodes; } +float CPFRegion::PointHeight(const zeus::CVector3f& point) const +{ + return (point - x4_startNode->GetPos()).dot(x18_normal); +} + +bool CPFRegion::FindClosestPointOnPolygon(const std::vector& polyPoints, + const zeus::CVector3f& normal, + const zeus::CVector3f& point, bool excludePolyPoints) +{ + bool found = false; + int i; + for (i=0 ; iGetBestPointDistanceSquared()) + { + found = true; + x4c_regionData->SetBestPointDistanceSquared(distToPolySq); + x4c_regionData->SetBestPoint(normal * distToPoly + point); + } + } + else + { + bool projected = false; + for (i=0 ; i= 0.f) + { + projected = true; + p0ToP1.normalize(); + sum -= p0ToP1.dot(sum) * p0ToP1; + float distSq = sum.magSquared(); + if (distSq < x4c_regionData->GetBestPointDistanceSquared()) + { + found = true; + x4c_regionData->SetBestPointDistanceSquared(distSq); + x4c_regionData->SetBestPoint(point - sum); + } + break; + } + } + + if (!projected && !excludePolyPoints) + { + for (i=0 ; iGetBestPointDistanceSquared()) + { + found = true; + x4c_regionData->SetBestPointDistanceSquared(distSq); + x4c_regionData->SetBestPoint(p0); + } + } + } + } + return found; +} + +bool CPFRegion::FindBestPoint(std::vector& polyPoints, const zeus::CVector3f& point, + u32 flags, float paddingSq) +{ + bool found = false; + bool isFlyer = (flags & 0x2) != 0; + x4c_regionData->SetBestPointDistanceSquared(paddingSq); + if (!isFlyer) + { + for (int i=0 ; i=0 ; --i) + { + CPFNode& node = x4_startNode[i]; + polyPoints.push_back(node.GetPos()); + polyPoints.back().z += x14_height; + } + found |= FindClosestPointOnPolygon(polyPoints, -x18_normal, point, false); + } + + return found; +} + zeus::CVector3f CPFRegion::FitThroughLink2d(const zeus::CVector3f& p1, const CPFLink& link, const zeus::CVector3f& p2, float f1) const { @@ -113,4 +235,14 @@ zeus::CVector3f CPFRegion::FitThroughLink3d(const zeus::CVector3f& p1, const CPF return {midPoint.x, midPoint.y, z}; } +bool CPFRegion::IsPointInsidePaddedAABox(const zeus::CVector3f& point, float padding) const +{ + return point.x >= x34_aabb.min.x - padding && + point.x <= x34_aabb.max.x + padding && + point.y >= x34_aabb.min.y - padding && + point.y <= x34_aabb.max.y + padding && + point.z >= x34_aabb.min.z - padding && + point.z <= x34_aabb.max.z + padding; +} + } diff --git a/Runtime/World/CPathFindRegion.hpp b/Runtime/World/CPathFindRegion.hpp index 36bba5712..c97a5449a 100644 --- a/Runtime/World/CPathFindRegion.hpp +++ b/Runtime/World/CPathFindRegion.hpp @@ -65,22 +65,22 @@ public: const zeus::CVector3f& GetNormal() const { return x18_normal; } u32 GetNumNodes() const { return x0_numNodes; } const CPFNode* GetNode(u32 i) const { return x4_startNode + i; } - void PointHeight(const zeus::CVector3f&); - void FindClosestPointOnPolygon(const std::vector&, const zeus::CVector3f&, + float PointHeight(const zeus::CVector3f& point) const; + bool FindClosestPointOnPolygon(const std::vector&, const zeus::CVector3f&, const zeus::CVector3f&, bool); - void FindBestPoint(std::vector&, const zeus::CVector3f&, u32, float); + bool FindBestPoint(std::vector& polyPoints, const zeus::CVector3f& point, u32 flags, float paddingSq); void SetLinkTo(s32); void DropToGround(zeus::CVector3f&) const; void GetLinkMidPoint(const CPFLink&); zeus::CVector3f FitThroughLink2d(const zeus::CVector3f&, const CPFLink&, const zeus::CVector3f&, float) const; zeus::CVector3f FitThroughLink3d(const zeus::CVector3f&, const CPFLink&, float, const zeus::CVector3f&, float, float) const; - void IsPointInsidePaddedAABox(const zeus::CVector3f&, float) const; + bool IsPointInsidePaddedAABox(const zeus::CVector3f& point, float padding) const; }; class CPFRegionData { - float x0_ = 0.f; - zeus::CVector3f x4_; + float x0_bestPointDistSq = 0.f; + zeus::CVector3f x4_bestPoint; s32 x10_cookie = -1; zeus::CVector3f x14_; s32 x20_ = 0; @@ -99,10 +99,10 @@ public: void SetPathLink(s32 l) { x2c_pathLink = l; } void GetParent() const; void Setup(CPFRegion*, float, float); - void SetBestPoint(const zeus::CVector3f&); - void SetBestPointDistanceSquared(float); - float GetBestPointDistanceSquared() const; - zeus::CVector3f GetBestPoint() const; + void SetBestPoint(const zeus::CVector3f& bestPoint) { x4_bestPoint = bestPoint; } + const zeus::CVector3f& GetBestPoint() const { return x4_bestPoint; } + void SetBestPointDistanceSquared(float distSq) { x0_bestPointDistSq = distSq; } + float GetBestPointDistanceSquared() const { return x0_bestPointDistSq; } void SetCookie(s32 c) { x10_cookie = c; } s32 GetCookie() const { return x10_cookie; } }; diff --git a/Runtime/World/CPathFindSearch.cpp b/Runtime/World/CPathFindSearch.cpp index c7aee4c88..b65e328bd 100644 --- a/Runtime/World/CPathFindSearch.cpp +++ b/Runtime/World/CPathFindSearch.cpp @@ -4,16 +4,46 @@ namespace urde { CPathFindSearch::CPathFindSearch(CPFArea* area, u32 flags, u32 w2, float f1, float f2) -: x0_area(area), xd0_f2(f2), xd4_f1(f1), xdc_flags(flags), xe0_w2(1u << w2) +: x0_area(area), xd0_f2(f2), xd4_f1(f1), xdc_flags(flags), xe0_indexMask(1u << w2) { } -void CPathFindSearch::Search(const zeus::CVector3f& p1, const zeus::CVector3f& p2) +CPathFindSearch::EResult CPathFindSearch::Search(const zeus::CVector3f& p1, const zeus::CVector3f& p2) { x4_.clear(); xc8_ = 0; + if (!x0_area || x0_area->x150_regions.size() > 512) + { + xcc_result = EResult::One; + return xcc_result; + } + + if (zeus::close_enough(p1, p2)) + { + x4_.push_back(p1); + xcc_result = EResult::Zero; + return xcc_result; + } + + zeus::CVector3f localP1 = x0_area->x188_transform.transposeRotate(p1 - x0_area->x188_transform.origin); + zeus::CVector3f localP2 = x0_area->x188_transform.transposeRotate(p2 - x0_area->x188_transform.origin); + + if (!(xdc_flags & 0x2) && !(xdc_flags & 0x4)) + { + localP2.z += 0.3f; + localP1.z += 0.3f; + } + + rstl::reserved_vector regions; + if (x0_area->FindRegions(regions, localP1, xdc_flags, xe0_indexMask) == 0) + { + x0_area->FindClosestRegion(localP1, xdc_flags, xe0_indexMask, xd8_); + } + + // TODO: Finish + return EResult::Zero; } } diff --git a/Runtime/World/CPathFindSearch.hpp b/Runtime/World/CPathFindSearch.hpp index 47cd4e65e..84d72f71e 100644 --- a/Runtime/World/CPathFindSearch.hpp +++ b/Runtime/World/CPathFindSearch.hpp @@ -9,17 +9,28 @@ namespace urde class CPathFindSearch { +public: + enum class EResult + { + Zero, + One, + Two, + Three, + Four + }; +private: CPFArea* x0_area; rstl::reserved_vector x4_; u32 xc8_ = 0; + EResult xcc_result; float xd0_f2; float xd4_f1; float xd8_ = 10.f; u32 xdc_flags; // 0x2: flyer, 0x4: path-always-exists - u32 xe0_w2; + u32 xe0_indexMask; public: CPathFindSearch(CPFArea* area, u32 flags, u32 w2, float f1, float f2); - void Search(const zeus::CVector3f& p1, const zeus::CVector3f& p2); + EResult Search(const zeus::CVector3f& p1, const zeus::CVector3f& p2); }; }