#include "gamelib/aas2/aas2_local.h" #include "idlib/lib_print.h" #include namespace { bool BoundsIntersect(const idBounds& first, const idBounds& second) { for (int axis = 0; axis < 3; ++axis) { if (first[1][axis] < second[0][axis] || first[0][axis] > second[1][axis]) return false; } return true; } float DistanceSqr(const idVec3& first, const idVec3& second) { const idVec3 delta = first - second; return delta.x * delta.x + delta.y * delta.y + delta.z * delta.z; } } // namespace int idAAS2Local::GetNumCoverPoints() const { return file != nullptr ? file->cover.Num() : 0; } const aas2Cover_t* idAAS2Local::GetCoverPoint(const int index) const { return file != nullptr && index >= 0 && index < file->cover.Num() ? &file->cover[index] : nullptr; } int idAAS2Local::GetNumAreaCoverPoints(const int areaNum) const { return file != nullptr && areaNum > 0 && areaNum < file->areas.Num() ? file->areas[areaNum].numCover : 0; } int idAAS2Local::GetAreaCoverPoints(const int areaNum, int* const points, const int maxPoints, int* const numPoints) const { if (numPoints != nullptr) *numPoints = 0; if (file == nullptr || areaNum <= 0 || areaNum >= file->areas.Num() || points == nullptr || numPoints == nullptr) return 0; const aas2Area_t& area = file->areas[areaNum]; for (int index = 0; index < area.numCover; ++index) { if (*numPoints >= maxPoints) { idLibPrint::Warning( "idAAS2Local::GetAreaCoverPoints - search list overflowed."); break; } points[(*numPoints)++] = file->areaCoverIndex[area.firstCover + index]; } return *numPoints; } void idAAS2Local::FindCoverPoints_Internal(const int startAreaNum, const idVec3& origin, const idBounds& bounds, const float maxDistSqr, const int requiredFlags, const int excludeFlags, const int travelFlags, int* const coverPoints, const int maxCover, int& numCover) const { if (file == nullptr || startAreaNum <= 0 || startAreaNum >= file->areas.Num()) return; std::vector visited( static_cast(file->areas.Num()), 0); int queue[1280] = {}; int first = 0; int last = 1; queue[0] = startAreaNum; visited[startAreaNum] = 1; while (first < last) { if (last >= 1280) return; const int areaNum = queue[first++]; const aas2Area_t& area = file->areas[areaNum]; for (int index = 0; index < area.numCover; ++index) { const int coverIndex = file->areaCoverIndex[area.firstCover + index]; if (coverIndex < 0 || coverIndex >= file->cover.Num()) continue; const aas2Cover_t& coverPoint = file->cover[coverIndex]; if ((requiredFlags != 0 && (coverPoint.flags & requiredFlags) == 0) || (coverPoint.flags & excludeFlags) != 0 || DistanceSqr(coverPoint.origin, origin) >= maxDistSqr) { continue; } if (numCover >= maxCover) { idLibPrint::Warning( "idAAS2Local::FindCoverPoints_Internal - search list overflowed."); return; } coverPoints[numCover++] = coverIndex; } for (idIndex reachIndex = area.reach; reachIndex.IsValid();) { const int index = reachIndex.Get(); if (index < 0 || index >= file->reachabilities.Num()) break; const aas2Reachability_t& reach = file->reachabilities[index]; const int nextArea = reach.toAreaNum; if (nextArea > 0 && nextArea < file->areas.Num() && visited[nextArea] == 0 && (reach.travelFlags & travelFlags) != 0) { idBounds areaBounds; if (nextArea < file->areaBounds.Num()) { areaBounds[0].Set( float(file->areaBounds[nextArea].min[0]), float(file->areaBounds[nextArea].min[1]), float(file->areaBounds[nextArea].min[2])); areaBounds[1].Set( float(file->areaBounds[nextArea].max[0]), float(file->areaBounds[nextArea].max[1]), float(file->areaBounds[nextArea].max[2])); } else { areaBounds = file->AreaBounds(nextArea); } if (BoundsIntersect(bounds, areaBounds) && last < 1280) { visited[nextArea] = 1; queue[last++] = nextArea; } } reachIndex = reach.next; } } } int idAAS2Local::FindCoverPoints(const int areaNum, const idVec3& origin, const float radius, const int requiredFlags, const int excludeFlags, const int travelFlags, int* const points, const int maxPoints, int* const numPoints) const { if (numPoints != nullptr) *numPoints = 0; if (areaNum <= 0 || points == nullptr || numPoints == nullptr || maxPoints <= 0) return 0; const idVec3 extent(radius, radius, radius); idBounds bounds; bounds[0] = origin - extent; bounds[1] = origin + extent; FindCoverPoints_Internal(areaNum, origin, bounds, radius * radius, requiredFlags, excludeFlags, travelFlags, points, maxPoints, *numPoints); return *numPoints; } int idAAS2Local::GetNumChokePoints() const { return file != nullptr ? file->chokePoints.Num() : 0; } const aas2ChokePoint_t* idAAS2Local::GetChokePoint(const int index) const { return file != nullptr && index >= 0 && index < file->chokePoints.Num() ? &file->chokePoints[index] : nullptr; } int idAAS2Local::GetNumHintNodes() const { return file != nullptr ? file->hintNodes.Num() : 0; } const aas2HintNode_t* idAAS2Local::GetHintNode(const int index) const { return file != nullptr && index >= 0 && index < file->hintNodes.Num() ? &file->hintNodes[index] : nullptr; }