2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-05-13 16:31:21 +00:00
metaforce/Runtime/World/CPathFindArea.cpp
Lioncash 221cc5c6b8 RuntimeCommonB: Normalize cpp file includes
Like the prior changes normalizing the inclusions within headers, this
tackles the cpp files of the RuntimeCommonB target, making these source
files consistent with their headers.
2019-12-22 18:12:04 -05:00

273 lines
9.4 KiB
C++

#include "Runtime/World/CPathFindArea.hpp"
#include "Runtime/CToken.hpp"
#include "Runtime/IVParamObj.hpp"
namespace urde {
static logvisor::Module Log("CPathFindArea");
CPFAreaOctree::CPFAreaOctree(CMemoryInStream& in) {
x0_isLeaf = in.readUint32Big();
x4_aabb.readBoundingBoxBig(in);
x1c_center.readBig(in);
for (auto& ptr : x28_children)
ptr = reinterpret_cast<CPFAreaOctree*>(in.readUint32Big());
x48_regions.set_size(in.readUint32Big());
x48_regions.set_data(reinterpret_cast<CPFRegion**>(in.readUint32Big()));
}
void CPFAreaOctree::Fixup(CPFArea& area) {
x0_isLeaf = x0_isLeaf != 0 ? 1 : 0;
if (x0_isLeaf) {
if (x48_regions.empty())
return;
x48_regions.set_data(&area.x160_octreeRegionLookup[reinterpret_cast<uintptr_t>(x48_regions.data())]);
return;
}
for (auto & ptr : x28_children) {
if ((reinterpret_cast<uintptr_t>(ptr) & 0x80000000) == 0)
ptr = &area.x158_octree[reinterpret_cast<uintptr_t>(ptr)];
else
ptr = nullptr;
}
}
u32 CPFAreaOctree::GetChildIndex(const zeus::CVector3f& point) const {
u32 idx = 0x0u;
if (point.x() > x1c_center.x())
idx = 0x1u;
if (point.y() > x1c_center.y())
idx |= 0x2u;
if (point.z() > x1c_center.z())
idx |= 0x4u;
return idx;
}
rstl::prereserved_vector<CPFRegion*>* CPFAreaOctree::GetRegionList(const zeus::CVector3f& point) {
if (x0_isLeaf)
return &x48_regions;
return x28_children[GetChildIndex(point)]->GetRegionList(point);
}
void CPFAreaOctree::GetRegionListList(rstl::reserved_vector<rstl::prereserved_vector<CPFRegion*>*, 32>& listOut,
const zeus::CVector3f& point, float padding) {
if (listOut.size() >= listOut.capacity())
return;
if (x0_isLeaf) {
listOut.push_back(&x48_regions);
return;
}
for (CPFAreaOctree* ch : x28_children) {
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() {
x40_region.SetData(&x90_regionData);
Clear();
}
void CPFOpenList::Clear() {
x40_region.Data()->SetOpenMore(&x40_region);
x40_region.Data()->SetOpenLess(&x40_region);
x0_bitSet.Clear();
}
void CPFOpenList::Push(CPFRegion* reg) {
x0_bitSet.Add(reg->GetIndex());
CPFRegion* other = x40_region.Data()->GetOpenMore();
while (other != &x40_region && reg->Data()->GetCost() > other->Data()->GetCost())
other = other->Data()->GetOpenMore();
other->Data()->GetOpenLess()->Data()->SetOpenMore(reg);
reg->Data()->SetOpenLess(other->Data()->GetOpenLess());
other->Data()->SetOpenLess(reg);
reg->Data()->SetOpenMore(other);
}
CPFRegion* CPFOpenList::Pop() {
CPFRegion* reg = x40_region.Data()->GetOpenMore();
if (reg != &x40_region) {
x0_bitSet.Rmv(reg->GetIndex());
reg->Data()->GetOpenMore()->Data()->SetOpenLess(reg->Data()->GetOpenLess());
reg->Data()->GetOpenLess()->Data()->SetOpenMore(reg->Data()->GetOpenMore());
reg->Data()->SetOpenMore(nullptr);
reg->Data()->SetOpenLess(nullptr);
return reg;
}
return nullptr;
}
void CPFOpenList::Pop(CPFRegion* reg) {
x0_bitSet.Rmv(reg->GetIndex());
reg->Data()->GetOpenMore()->Data()->SetOpenLess(reg->Data()->GetOpenLess());
reg->Data()->GetOpenLess()->Data()->SetOpenMore(reg->Data()->GetOpenMore());
reg->Data()->SetOpenMore(nullptr);
reg->Data()->SetOpenLess(nullptr);
}
bool CPFOpenList::Test(const CPFRegion* reg) const { return x0_bitSet.Test(reg->GetIndex()); }
CPFArea::CPFArea(std::unique_ptr<u8[]>&& buf, u32 len) {
CMemoryInStream r(buf.get(), len);
u32 version = r.readUint32Big();
if (version != 4)
Log.report(logvisor::Fatal, fmt("Unexpected PATH version {}, should be 4"), version);
u32 numNodes = r.readUint32Big();
x140_nodes.reserve(numNodes);
for (u32 i = 0; i < numNodes; ++i)
x140_nodes.emplace_back(r);
u32 numLinks = r.readUint32Big();
x148_links.reserve(numLinks);
for (u32 i = 0; i < numLinks; ++i)
x148_links.emplace_back(r);
u32 numRegions = r.readUint32Big();
x150_regions.reserve(numRegions);
for (u32 i = 0; i < numRegions; ++i)
x150_regions.emplace_back(r);
x178_regionDatas.resize(numRegions);
u32 maxRegionNodes = 0;
for (CPFRegion& region : x150_regions)
region.Fixup(*this, maxRegionNodes);
maxRegionNodes = std::max(maxRegionNodes, 4u);
x10_tmpPolyPoints.reserve(maxRegionNodes);
u32 numBitfieldWords = (numRegions * (numRegions - 1) / 2 + 31) / 32;
x168_connectionsGround.reserve(numBitfieldWords);
for (u32 i = 0; i < numBitfieldWords; ++i)
x168_connectionsGround.push_back(r.readUint32Big());
x170_connectionsFlyers.reserve(numBitfieldWords);
for (u32 i = 0; i < numBitfieldWords; ++i)
x170_connectionsFlyers.push_back(r.readUint32Big());
r.seek(((((numRegions * numRegions) + 31) / 32) - numBitfieldWords) * 2 * sizeof(u32));
u32 numRegionLookups = r.readUint32Big();
x160_octreeRegionLookup.reserve(numRegionLookups);
for (u32 i = 0; i < numRegionLookups; ++i)
x160_octreeRegionLookup.push_back(reinterpret_cast<CPFRegion*>(r.readUint32Big()));
for (CPFRegion*& rl : x160_octreeRegionLookup)
rl = &x150_regions[reinterpret_cast<uintptr_t>(rl)];
u32 numOctreeNodes = r.readUint32Big();
x158_octree.reserve(numOctreeNodes);
for (u32 i = 0; i < numOctreeNodes; ++i)
x158_octree.emplace_back(r);
for (CPFAreaOctree& node : x158_octree)
node.Fixup(*this);
}
rstl::prereserved_vector<CPFRegion*>* CPFArea::GetOctreeRegionList(const zeus::CVector3f& point) {
if (x30_hasCachedRegionList && zeus::close_enough(point, x24_cachedRegionListPoint))
return x20_cachedRegionList;
return x158_octree.back().GetRegionList(point);
}
u32 CPFArea::FindRegions(rstl::reserved_vector<CPFRegion*, 4>& regions, const zeus::CVector3f& point, u32 flags,
u32 indexMask) {
bool isFlyer = (flags & 0x2u) != 0;
bool isSwimmer = (flags & 0x4u) != 0;
for (CPFRegion* region : *GetOctreeRegionList(point)) {
if (region->GetFlags() & 0xffu & flags && (region->GetFlags() >> 16u) & 0xffu & indexMask &&
region->IsPointInside(point) && (isFlyer || isSwimmer || region->PointHeight(point) < 3.f)) {
regions.push_back(region);
if (regions.size() == regions.capacity())
break;
}
}
return u32(regions.size());
}
CPFRegion* CPFArea::FindClosestRegion(const zeus::CVector3f& point, u32 flags, u32 indexMask, float padding) {
rstl::reserved_vector<rstl::prereserved_vector<CPFRegion*>*, 32> regionListList;
x158_octree.back().GetRegionListList(regionListList, point, padding);
bool isFlyer = (flags & 0x2u) != 0;
CPFRegion* ret = nullptr;
for (rstl::prereserved_vector<CPFRegion*>* list : regionListList) {
for (CPFRegion* region : *list) {
if (region->Data()->GetCookie() != x34_regionFindCookie) {
if (region->GetFlags() & 0xffu & flags && (region->GetFlags() >> 16u) & 0xffu & indexMask &&
region->IsPointInsidePaddedAABox(point, padding) && (isFlyer || region->PointHeight(point) < 3.f)) {
if (region->FindBestPoint(x10_tmpPolyPoints, point, flags, padding * padding)) {
ret = region;
padding = region->Data()->GetBestPointDistanceSquared() == 0.0
? 0.f
: std::sqrt(region->Data()->GetBestPointDistanceSquared());
x4_closestPoint = region->Data()->GetBestPoint();
}
}
region->Data()->SetCookie(x34_regionFindCookie);
}
}
}
++x34_regionFindCookie;
return ret;
}
zeus::CVector3f CPFArea::FindClosestReachablePoint(rstl::reserved_vector<CPFRegion*, 4>& regs,
const zeus::CVector3f& point, u32 flags, u32 indexMask) {
zeus::CVector3f ret;
float closestDistSq = FLT_MAX;
for (CPFRegion& reg : x150_regions) {
if (reg.GetFlags() & 0xffu & flags && (reg.GetFlags() >> 16u) & 0xffu & indexMask) {
for (CPFRegion* oreg : regs) {
if (PathExists(oreg, &reg, flags)) {
float distSq = (reg.GetCentroid() - point).magSquared();
if (distSq < closestDistSq) {
closestDistSq = distSq;
ret = reg.GetCentroid();
break;
}
}
}
}
}
return ret;
}
bool CPFArea::PathExists(const CPFRegion* r1, const CPFRegion* r2, u32 flags) const {
if (r1 == r2 || (flags & 0x4u) != 0)
return true;
u32 i1 = r1->GetIndex();
u32 i2 = r2->GetIndex();
if (i1 > i2)
std::swap(i1, i2);
u32 remRegions = u32(x150_regions.size()) - i1;
u32 remConnections = remRegions * (remRegions - 1) / 2;
u32 totalConnections = u32(x150_regions.size()) * (u32(x150_regions.size()) - 1) / 2;
u32 bit = totalConnections - remConnections + i2 - (i1 + 1);
auto d = std::div(bit, 32);
if ((flags & 0x2u) != 0)
return ((x170_connectionsFlyers[d.quot] >> u32(d.rem)) & 0x1u) != 0;
else
return ((x168_connectionsGround[d.quot] >> u32(d.rem)) & 0x1u) != 0;
}
CFactoryFnReturn FPathFindAreaFactory(const urde::SObjectTag& tag, std::unique_ptr<u8[]>&& in, u32 len,
const urde::CVParamTransfer& vparms, CObjectReference*) {
return TToken<CPFArea>::GetIObjObjectFor(std::make_unique<CPFArea>(std::move(in), len));
}
} // namespace urde