2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-06 16:52:35 +00:00

Clipmap linker refactor, and AABB trees are seperated by material now.

This commit is contained in:
LJW-Dev
2026-02-16 18:32:20 +08:00
committed by Jan Laupetin
parent 4d822d392d
commit 6ce1f96ff9
@@ -133,7 +133,8 @@ namespace BSP
clipMap->cmodels[0].mins = vertex;
clipMap->cmodels[0].maxs = vertex;
}
BSPUtil::updateAABBWithPoint(vertex, clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs);
else
BSPUtil::updateAABBWithPoint(vertex, clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs);
}
clipMap->cmodels[0].radius = BSPUtil::distBetweenPoints(clipMap->cmodels[0].mins, clipMap->cmodels[0].maxs) / 2;
@@ -203,125 +204,147 @@ namespace BSP
*/
}
// out_mins and out_maxs are initialised in the function
void calculatePartitionAABB(clipMap_t* clipMap, CollisionPartition* partition, vec3_t& out_mins, vec3_t& out_maxs)
{
for (int uindIdx = 0; uindIdx < partition->nuinds; uindIdx++)
{
uint16_t uind = clipMap->info.uinds[partition->fuind + uindIdx];
vec3_t vert = clipMap->verts[uind];
// initalise the AABB with the first vertex
if (uindIdx == 0)
{
out_mins = vert;
out_maxs = vert;
}
else
BSPUtil::updateAABBWithPoint(vert, out_mins, out_maxs);
}
}
struct uniqueMatData
{
unsigned int materialIndex;
std::vector<size_t> objectIndexes;
};
void ClipMapLinker::addAABBTreeFromLeaf(clipMap_t* clipMap, BSPTree* tree, size_t* out_parentCount, size_t* out_parentStartIndex)
{
assert(tree->isLeaf);
BSPLeaf* bspLeaf = tree->leaf.get();
size_t leafObjectCount = tree->leaf->getObjectCount();
size_t leafObjectCount = bspLeaf->getObjectCount();
assert(leafObjectCount > 0);
if (leafObjectCount > highestLeafObjectCount)
highestLeafObjectCount = leafObjectCount;
std::vector<unsigned int> uniqueMaterials;
// the material index of the AABB tree is only checked for the parent node, so each parent has only children with the same material
std::vector<uniqueMatData> uniqueMaterials;
for (size_t objIdx = 0; objIdx < leafObjectCount; objIdx++)
{
int partitionIdx = tree->leaf->getObject(objIdx)->partitionIndex;
int partitionIdx = bspLeaf->getObject(objIdx)->partitionIndex;
unsigned materialIndex = partitionToMaterialMap[partitionIdx];
bool foundIdx = false;
for (unsigned int uniqueMat : uniqueMaterials)
for (auto& uniqueMat : uniqueMaterials)
{
if (uniqueMat == materialIndex)
if (uniqueMat.materialIndex == materialIndex)
{
uniqueMat.objectIndexes.emplace_back(objIdx);
foundIdx = true;
break;
}
}
if (!foundIdx)
uniqueMaterials.emplace_back(materialIndex);
{
uniqueMatData data;
data.materialIndex = materialIndex;
data.objectIndexes = std::vector<size_t>();
uniqueMaterials.emplace_back(data);
}
}
con::info("{} {}", uniqueMaterials.size(), uniqueMaterials[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++;
// the material index of the AABB tree is only checked for the parent node, so
size_t parentAABBArrayIndex = AABBTreeVec.size();
AABBTreeVec.resize(AABBTreeVec.size() + parentCount);
size_t unaddedObjectCount = leafObjectCount;
size_t addedObjectCount = 0;
for (size_t parentIdx = 0; parentIdx < parentCount; parentIdx++)
size_t totalParentCount = 0;
for (auto& matData : uniqueMaterials)
{
size_t childObjectCount = BSPGameConstants::MAX_AABB_TREE_CHILDREN;
if (unaddedObjectCount <= BSPGameConstants::MAX_AABB_TREE_CHILDREN)
childObjectCount = unaddedObjectCount;
else
unaddedObjectCount -= BSPGameConstants::MAX_AABB_TREE_CHILDREN;
// calculate parent AABB mins and maxs
vec3_t parentMins;
vec3_t parentMaxs;
for (size_t objectIdx = 0; objectIdx < childObjectCount; objectIdx++)
{
int partitionIndex = tree->leaf->getObject(addedObjectCount + objectIdx)->partitionIndex;
CollisionPartition* partition = &clipMap->partitions[partitionIndex];
for (int uindIdx = 0; uindIdx < partition->nuinds; uindIdx++)
{
uint16_t uind = clipMap->info.uinds[partition->fuind + uindIdx];
vec3_t vert = clipMap->verts[uind];
// initalise the parent AABB with the first vertex
if (objectIdx == 0 && uindIdx == 0)
{
parentMins = vert;
parentMaxs = vert;
}
BSPUtil::updateAABBWithPoint(vert, parentMins, parentMaxs);
}
}
size_t childObjectStartIndex = AABBTreeVec.size();
CollisionAabbTree parentAABB;
parentAABB.origin = BSPUtil::calcMiddleOfAABB(parentMins, parentMaxs);
parentAABB.halfSize = BSPUtil::calcHalfSizeOfAABB(parentMins, parentMaxs);
parentAABB.materialIndex = 0;
parentAABB.childCount = static_cast<uint16_t>(childObjectCount);
parentAABB.u.firstChildIndex = static_cast<int>(childObjectStartIndex);
AABBTreeVec.at(parentAABBArrayIndex + parentIdx) = parentAABB;
// add child AABBs
for (size_t objectIdx = 0; objectIdx < childObjectCount; objectIdx++)
{
int partitionIndex = tree->leaf->getObject(addedObjectCount + objectIdx)->partitionIndex;
CollisionPartition* partition = &clipMap->partitions[partitionIndex];
vec3_t childMins;
vec3_t childMaxs;
for (int uindIdx = 0; uindIdx < partition->nuinds; uindIdx++)
{
uint16_t uind = clipMap->info.uinds[partition->fuind + uindIdx];
vec3_t vert = clipMap->verts[uind];
// initalise the child AABB with the first vertex
if (uindIdx == 0)
{
childMins = vert;
childMaxs = vert;
}
BSPUtil::updateAABBWithPoint(vert, childMins, childMaxs);
}
CollisionAabbTree childAABBTree;
childAABBTree.materialIndex = 0; // always use the first material
childAABBTree.childCount = 0;
childAABBTree.u.partitionIndex = partitionIndex;
childAABBTree.origin = BSPUtil::calcMiddleOfAABB(childMins, childMaxs);
childAABBTree.halfSize = BSPUtil::calcHalfSizeOfAABB(childMins, childMaxs);
AABBTreeVec.emplace_back(childAABBTree);
}
addedObjectCount += childObjectCount;
size_t objCount = matData.objectIndexes.size();
size_t result = objCount / BSPGameConstants::MAX_AABB_TREE_CHILDREN;
size_t remainder = objCount % BSPGameConstants::MAX_AABB_TREE_CHILDREN;
if (remainder > 0)
result++;
totalParentCount += result;
}
*out_parentCount = parentCount;
// every parent node needs to be contiguous in memory
size_t parentAABBArrayIndex = AABBTreeVec.size();
AABBTreeVec.resize(AABBTreeVec.size() + totalParentCount);
*out_parentCount = totalParentCount;
*out_parentStartIndex = parentAABBArrayIndex;
for (auto& matData : uniqueMaterials)
{
size_t* objIndexes = matData.objectIndexes.data();
size_t objCount = matData.objectIndexes.size();
size_t parentCount = objCount / BSPGameConstants::MAX_AABB_TREE_CHILDREN;
size_t remainder = objCount % BSPGameConstants::MAX_AABB_TREE_CHILDREN;
if (remainder > 0)
parentCount++;
size_t unaddedObjectCount = objCount;
size_t addedObjectCount = 0;
for (size_t parentIdx = 0; parentIdx < parentCount; parentIdx++)
{
size_t currChildObjectCount = BSPGameConstants::MAX_AABB_TREE_CHILDREN;
if (unaddedObjectCount <= BSPGameConstants::MAX_AABB_TREE_CHILDREN)
currChildObjectCount = unaddedObjectCount;
else
unaddedObjectCount -= BSPGameConstants::MAX_AABB_TREE_CHILDREN;
vec3_t parentMins;
vec3_t parentMaxs;
size_t childObjectStartIndex = AABBTreeVec.size();
for (size_t objectIdx = 0; objectIdx < currChildObjectCount; objectIdx++)
{
// create a child AABBTree with the partition and add it to AABBTreeVec
int partitionIndex = bspLeaf->getObject(objIndexes[addedObjectCount + objectIdx])->partitionIndex;
CollisionPartition* partition = &clipMap->partitions[partitionIndex];
vec3_t childMins;
vec3_t childMaxs;
calculatePartitionAABB(clipMap, partition, childMins, childMaxs);
CollisionAabbTree childAABBTree;
childAABBTree.materialIndex = matData.materialIndex;
childAABBTree.childCount = 0;
childAABBTree.u.partitionIndex = partitionIndex;
childAABBTree.origin = BSPUtil::calcMiddleOfAABB(childMins, childMaxs);
childAABBTree.halfSize = BSPUtil::calcHalfSizeOfAABB(childMins, childMaxs);
AABBTreeVec.emplace_back(childAABBTree);
// update the parent AABB with the child AABB
if (objectIdx == 0)
{
parentMins = childMins;
parentMaxs = childMaxs;
}
else
BSPUtil::updateAABB(childMins, childMaxs, parentMins, parentMaxs);
}
CollisionAabbTree parentAABB;
parentAABB.materialIndex = matData.materialIndex;
parentAABB.origin = BSPUtil::calcMiddleOfAABB(parentMins, parentMaxs);
parentAABB.halfSize = BSPUtil::calcHalfSizeOfAABB(parentMins, parentMaxs);
parentAABB.childCount = static_cast<uint16_t>(currChildObjectCount);
parentAABB.u.firstChildIndex = static_cast<int>(childObjectStartIndex);
AABBTreeVec.at(parentAABBArrayIndex + parentIdx) = parentAABB;
addedObjectCount += currChildObjectCount;
}
parentAABBArrayIndex += parentCount;
}
}
constexpr vec3_t normalX = {1.0f, 0.0f, 0.0f};
@@ -350,8 +373,7 @@ namespace BSP
leaf.maxs.z = 0.0f;
leaf.leafBrushNode = 0;
// -1 as it uses tris
leaf.terrainContents = 1;
leaf.terrainContents = 1; // todo: use correct contents
if (tree->leaf->getObjectCount() > 0)
{
size_t parentCount = 0;
@@ -446,18 +468,7 @@ namespace BSP
vec3_t partitionMins;
vec3_t partitionMaxs;
CollisionPartition* partition = &clipMap->partitions[partitionIdx];
for (int uindIdx = 0; uindIdx < partition->nuinds; uindIdx++)
{
uint16_t uind = clipMap->info.uinds[partition->fuind + uindIdx];
vec3_t vert = clipMap->verts[uind];
// initalise the AABB with the first vertex
if (uindIdx == 0)
{
partitionMins = vert;
partitionMaxs = vert;
}
BSPUtil::updateAABBWithPoint(vert, partitionMins, partitionMaxs);
}
calculatePartitionAABB(clipMap, partition, partitionMins, partitionMaxs);
std::shared_ptr<BSPObject> currObject =
std::make_shared<BSPObject>(partitionMins.x, partitionMins.y, partitionMins.z, partitionMaxs.x, partitionMaxs.y, partitionMaxs.z, partitionIdx);
tree->addObjectToTree(std::move(currObject));