2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-11-24 21:52:06 +00:00

Fixed a crash related to AABB Tree children counts exceeding the maximum limit

This commit is contained in:
LJW-Dev
2025-11-04 18:13:31 +08:00
parent 6cd89a31b2
commit 0f70c29532
3 changed files with 92 additions and 65 deletions

View File

@@ -63,6 +63,8 @@ namespace BSP
{ {
constexpr unsigned int MAX_COLLISION_VERTS = UINT16_MAX; constexpr unsigned int MAX_COLLISION_VERTS = UINT16_MAX;
constexpr size_t MAX_AABB_TREE_CHILDREN = 128;
enum BSPDefaultLights enum BSPDefaultLights
{ {
STATIC_LIGHT_INDEX = 0, STATIC_LIGHT_INDEX = 0,

View File

@@ -209,24 +209,41 @@ namespace BSP
*/ */
} }
int ClipMapLinker::addAABBTreeFromLeaf(BSPTree* node, clipMap_t* clipMap) void ClipMapLinker::addAABBTreeFromLeaf(clipMap_t* clipMap, BSPTree* tree, size_t* out_parentCount, size_t* out_parentStartIndex)
{ {
assert(node->isLeaf); assert(tree->isLeaf);
size_t objectCount = node->leaf->getObjectCount(); size_t leafObjectCount = tree->leaf->getObjectCount();
size_t parentAABBIndex = AABBTreeVec.size(); assert(leafObjectCount > 0);
if (leafObjectCount > highestLeafObjectCount)
highestLeafObjectCount = leafObjectCount;
assert(objectCount > 0); // BO2 has a maximum limit of 128 children per AABB tree (essentially),
// so this is fixed by adding multiple parent AABB trees that hold 128 children each
size_t result = leafObjectCount / BSPGameConstants::MAX_AABB_TREE_CHILDREN;
size_t remainder = leafObjectCount % BSPGameConstants::MAX_AABB_TREE_CHILDREN;
size_t parentCount = result;
if (remainder > 0)
parentCount++;
if (objectCount > highestLeafObjectCount) size_t parentAABBArrayIndex = AABBTreeVec.size();
highestLeafObjectCount = objectCount; AABBTreeVec.resize(AABBTreeVec.size() + parentCount);
size_t unaddedObjectCount = leafObjectCount;
size_t addedObjectCount = 0;
for (size_t parentIdx = 0; parentIdx < parentCount; parentIdx++)
{
size_t childObjectCount = BSPGameConstants::MAX_AABB_TREE_CHILDREN;
if (unaddedObjectCount <= BSPGameConstants::MAX_AABB_TREE_CHILDREN)
childObjectCount = unaddedObjectCount;
else
unaddedObjectCount -= BSPGameConstants::MAX_AABB_TREE_CHILDREN;
// add the parent AABB node // add the parent AABB
vec3_t parentMins; vec3_t parentMins;
vec3_t parentMaxs; vec3_t parentMaxs;
for (size_t objectIdx = 0; objectIdx < objectCount; objectIdx++) for (size_t objectIdx = 0; objectIdx < childObjectCount; objectIdx++)
{ {
int partitionIndex = node->leaf->getObject(objectIdx)->partitionIndex; int partitionIndex = tree->leaf->getObject(addedObjectCount + objectIdx)->partitionIndex;
CollisionPartition* partition = &clipMap->partitions[partitionIndex]; CollisionPartition* partition = &clipMap->partitions[partitionIndex];
for (int uindIdx = 0; uindIdx < partition->nuinds; uindIdx++) for (int uindIdx = 0; uindIdx < partition->nuinds; uindIdx++)
{ {
@@ -243,19 +260,20 @@ namespace BSP
BSPUtil::updateAABBWithPoint(vert, parentMins, parentMaxs); BSPUtil::updateAABBWithPoint(vert, parentMins, parentMaxs);
} }
} }
size_t childObjectStartIndex = AABBTreeVec.size();
CollisionAabbTree parentAABB; CollisionAabbTree parentAABB;
parentAABB.origin = BSPUtil::calcMiddleOfAABB(parentMins, parentMaxs); parentAABB.origin = BSPUtil::calcMiddleOfAABB(parentMins, parentMaxs);
parentAABB.halfSize = BSPUtil::calcHalfSizeOfAABB(parentMins, parentMaxs); parentAABB.halfSize = BSPUtil::calcHalfSizeOfAABB(parentMins, parentMaxs);
parentAABB.materialIndex = 0; // always use the first material parentAABB.materialIndex = 0; // always use the first material
parentAABB.childCount = static_cast<uint16_t>(objectCount); parentAABB.childCount = static_cast<uint16_t>(childObjectCount);
parentAABB.u.firstChildIndex = static_cast<int>(parentAABBIndex + 1); parentAABB.u.firstChildIndex = static_cast<int>(childObjectStartIndex);
AABBTreeVec.emplace_back(parentAABB); AABBTreeVec.at(parentAABBArrayIndex + parentIdx) = parentAABB;
// add child AABB nodes // add child AABBs
for (size_t objectIdx = 0; objectIdx < objectCount; objectIdx++) for (size_t objectIdx = 0; objectIdx < childObjectCount; objectIdx++)
{ {
int partitionIndex = node->leaf->getObject(objectIdx)->partitionIndex; int partitionIndex = tree->leaf->getObject(addedObjectCount + objectIdx)->partitionIndex;
CollisionPartition* partition = &clipMap->partitions[partitionIndex]; CollisionPartition* partition = &clipMap->partitions[partitionIndex];
vec3_t childMins; vec3_t childMins;
vec3_t childMaxs; vec3_t childMaxs;
@@ -283,7 +301,11 @@ namespace BSP
AABBTreeVec.emplace_back(childAABBTree); AABBTreeVec.emplace_back(childAABBTree);
} }
return static_cast<int>(parentAABBIndex); addedObjectCount += childObjectCount;
}
*out_parentCount = parentCount;
*out_parentStartIndex = parentAABBArrayIndex;
} }
constexpr vec3_t normalX = {1.0f, 0.0f, 0.0f}; constexpr vec3_t normalX = {1.0f, 0.0f, 0.0f};
@@ -315,8 +337,11 @@ namespace BSP
if (tree->leaf->getObjectCount() > 0) if (tree->leaf->getObjectCount() > 0)
{ {
leaf.firstCollAabbIndex = addAABBTreeFromLeaf(tree, clipMap); size_t parentCount = 0;
leaf.collAabbCount = 1; // 1 as it is the parent of all object AABBs size_t parentStartIndex = 0;
addAABBTreeFromLeaf(clipMap, tree, &parentCount, &parentStartIndex);
leaf.collAabbCount = static_cast<uint16_t>(parentCount);
leaf.firstCollAabbIndex = static_cast<uint16_t>(parentStartIndex);
} }
else else
{ {

View File

@@ -31,7 +31,7 @@ namespace BSP
std::vector<cLeaf_s> leafVec; std::vector<cLeaf_s> leafVec;
std::vector<CollisionAabbTree> AABBTreeVec; std::vector<CollisionAabbTree> AABBTreeVec;
size_t highestLeafObjectCount = 0; size_t highestLeafObjectCount = 0;
int addAABBTreeFromLeaf(BSPTree* node, clipMap_t* clipMap); void addAABBTreeFromLeaf(clipMap_t* clipMap, BSPTree* tree, size_t* out_parentCount, size_t* out_parentStartIndex);
int16_t loadBSPNode(clipMap_t* clipMap, BSPTree* tree); int16_t loadBSPNode(clipMap_t* clipMap, BSPTree* tree);
void loadBSPTree(clipMap_t* clipMap, BSPData* bsp); void loadBSPTree(clipMap_t* clipMap, BSPData* bsp);
bool loadPartitions(clipMap_t* clipMap, BSPData* bsp); bool loadPartitions(clipMap_t* clipMap, BSPData* bsp);