diff --git a/src/ObjLoading/XModel/CollisionTreeCreator.cpp b/src/ObjLoading/XModel/CollisionTreeCreator.cpp index 55065b55..4e9ec646 100644 --- a/src/ObjLoading/XModel/CollisionTreeCreator.cpp +++ b/src/ObjLoading/XModel/CollisionTreeCreator.cpp @@ -4,32 +4,9 @@ #include #include -#include namespace { - struct GenericAabbTree - { - int firstItem; - int itemCount; - int firstChild; - int childCount; - }; - - struct GenericAabbTreeOptions - { - void* items; - int itemCount; - int itemSize; - int maintainValidBounds; - float (*mins)[3]; - float (*maxs)[3]; - GenericAabbTree* treeNodePool; - int treeNodeLimit; - int minItemsPerLeaf; - int maxItemsPerLeaf; - }; - class Bounds { public: @@ -62,16 +39,6 @@ namespace m_maxs[2] = std::max(m_maxs[2], otherBounds.m_maxs[2]); } - void ExpandFromBounds(const float (&otherMins)[3], const float (&otherMaxs)[3]) - { - m_mins[0] = std::min(m_mins[0], otherMins[0]); - m_mins[1] = std::min(m_mins[1], otherMins[1]); - m_mins[2] = std::min(m_mins[2], otherMins[2]); - m_maxs[0] = std::max(m_maxs[0], otherMaxs[0]); - m_maxs[1] = std::max(m_maxs[1], otherMaxs[1]); - m_maxs[2] = std::max(m_maxs[2], otherMaxs[2]); - } - [[nodiscard]] Eigen::Vector3f GetDelta() const { return m_maxs - m_mins; @@ -82,237 +49,152 @@ namespace return GetDelta().prod(); } + [[nodiscard]] float AddedVolume(const Bounds& addedBounds) const + { + Bounds expandedBounds(*this); + expandedBounds.ExpandFromBounds(addedBounds); + + return expandedBounds.GetVolume() - GetVolume(); + } + Eigen::Vector3f m_mins; Eigen::Vector3f m_maxs; }; - void ClearBounds(float* mins, float* maxs) + constexpr auto MIN_ITEMS_PER_LEAF = 1u; + constexpr auto MAX_ITEMS_PER_LEAF = 16u; + + struct GenericAabbTree { - mins[0] = FLT_MAX; - mins[1] = FLT_MAX; - mins[2] = FLT_MAX; - maxs[0] = -FLT_MAX; - maxs[1] = -FLT_MAX; - maxs[2] = -FLT_MAX; - } - - void ExpandBounds(const float* addedmins, const float* addedmaxs, float* mins, float* maxs) - { - *mins = std::min(*mins, *addedmins); - *maxs = std::max(*addedmaxs, *maxs); - mins[1] = std::min(mins[1], addedmins[1]); - maxs[1] = std::max(addedmaxs[1], maxs[1]); - mins[2] = std::min(mins[2], addedmins[2]); - maxs[2] = std::max(addedmaxs[2], maxs[2]); - } - - float AddedVolume(const float* addedmins, const float* addedmaxs, const float* mins, const float* maxs) - { - float expandedMins; // [esp+0h] [ebp-20h] BYREF - float v6; // [esp+4h] [ebp-1Ch] - float v7; // [esp+8h] [ebp-18h] - float expandedVolume; // [esp+Ch] [ebp-14h] - float expandedMaxs; // [esp+14h] [ebp-Ch] BYREF - float v10; // [esp+18h] [ebp-8h] - float v11; // [esp+1Ch] [ebp-4h] - - expandedMins = *mins; - v6 = mins[1]; - v7 = mins[2]; - expandedMaxs = *maxs; - v10 = maxs[1]; - v11 = maxs[2]; - ExpandBounds(addedmins, addedmaxs, &expandedMins, &expandedMaxs); - expandedVolume = (expandedMaxs - expandedMins) * (v10 - v6) * (v11 - v7); - - return expandedVolume - (*maxs - *mins) * (maxs[1] - mins[1]) * (maxs[2] - mins[2]); - } - - int compare_floats(const void* e0, const void* e1) - { - float diff; // [esp+4h] [ebp-4h] - - diff = *static_cast(e0) - *static_cast(e1); - if (diff >= 0.0) - return diff > 0.0; - else - return -1; - } + size_t firstItem; + size_t itemCount; + size_t firstChild; + size_t childCount; + }; class AabbTreeBuilder { public: - AabbTreeBuilder() - : sortedMins(nullptr), - sortedMaxs(nullptr), - sortedCoplanar(nullptr), - aabbTreeCount(0) + AabbTreeBuilder(std::vector& nodes, std::vector& items, std::vector& itemBounds) + : m_nodes(nodes), + m_items(items), + m_item_bounds(itemBounds) { } - int BuildAabbTree(GenericAabbTreeOptions* options) + size_t BuildAabbTree() { - static constexpr size_t STACK_BUFFER_SIZE = 64; + if (m_items.empty()) + return 0; - float* v2; // [esp+4h] [ebp-454h] - float* v3; // [esp+8h] [ebp-450h] - float* v4; // [esp+Ch] [ebp-44Ch] - float* v5; // [esp+10h] [ebp-448h] - float (*boundCopies)[3]; // [esp+44h] [ebp-414h] - int* remap; // [esp+48h] [ebp-410h] - int itemIndex; // [esp+4Ch] [ebp-40Ch] - int itemIndexa; // [esp+4Ch] [ebp-40Ch] - int itemIndexb; // [esp+4Ch] [ebp-40Ch] - int itemIndexc; // [esp+4Ch] [ebp-40Ch] - int remapBuffer[STACK_BUFFER_SIZE]; // [esp+50h] [ebp-408h] BYREF - float sortedBounds[3][STACK_BUFFER_SIZE]; // [esp+150h] [ebp-308h] BYREF - char* itemCopies; // [esp+454h] [ebp-4h] + const auto itemCount = m_items.size(); - if (options->itemCount > STACK_BUFFER_SIZE) - { - remap = (int*)operator new(4 * options->itemCount); - sortedMins = (float*)operator new(4 * options->itemCount); - sortedMaxs = (float*)operator new(4 * options->itemCount); - sortedCoplanar = (float*)operator new(4 * options->itemCount); - } - else - { - remap = remapBuffer; - sortedMins = sortedBounds[0]; - sortedMaxs = sortedBounds[1]; - sortedCoplanar = sortedBounds[2]; - } + std::vector remap(m_items.size()); + m_sorted_mins = std::vector(m_items.size()); + m_sorted_maxs = std::vector(m_items.size()); + m_sorted_coplanar = std::vector(m_items.size()); - for (itemIndex = 0; itemIndex < options->itemCount; ++itemIndex) - remap[itemIndex] = itemIndex; + std::ranges::iota(remap, 0); - options->treeNodePool->firstItem = 0; - options->treeNodePool->itemCount = options->itemCount; + // Insert root node + m_nodes.emplace_back(GenericAabbTree{ + .firstItem = 0, + .itemCount = itemCount, + .firstChild = 0, + .childCount = 0, + }); - aabbTreeCount = 1; - BuildAabbTree_r(options->treeNodePool, options, remap); + BuildAabbTree_r(0, remap.data()); - itemCopies = (char*)operator new(options->itemSize * options->itemCount); - memcpy(itemCopies, options->items, options->itemSize * options->itemCount); - for (itemIndexa = 0; itemIndexa < options->itemCount; ++itemIndexa) - memcpy((char*)options->items + options->itemSize * itemIndexa, &itemCopies[options->itemSize * remap[itemIndexa]], options->itemSize); - operator delete(itemCopies); + // Reorder items + std::vector itemCopies(itemCount); + memcpy(itemCopies.data(), m_items.data(), sizeof(xmodel::CommonCollisionLeaf) * itemCount); + for (size_t itemIndex = 0; itemIndex < itemCount; ++itemIndex) + m_items[itemIndex] = itemCopies[remap[itemIndex]]; - if (options->maintainValidBounds) - { - boundCopies = - (float (*)[3]) operator new(4 * ((3 * (unsigned __int64)(unsigned int)options->itemCount) >> 32 != 0 ? -1 : 3 * options->itemCount)); - memcpy(boundCopies, options->mins, 12 * options->itemCount); - for (itemIndexb = 0; itemIndexb < options->itemCount; ++itemIndexb) - { - v4 = options->mins[itemIndexb]; - v5 = boundCopies[remap[itemIndexb]]; - *v4 = *v5; - v4[1] = v5[1]; - v4[2] = v5[2]; - } - memcpy(boundCopies, options->maxs, 12 * options->itemCount); - for (itemIndexc = 0; itemIndexc < options->itemCount; ++itemIndexc) - { - v2 = options->maxs[itemIndexc]; - v3 = boundCopies[remap[itemIndexc]]; - *v2 = *v3; - v2[1] = v3[1]; - v2[2] = v3[2]; - } - operator delete(boundCopies); - } - if (remap != remapBuffer) - { - operator delete(remap); - operator delete(sortedMins); - operator delete(sortedMaxs); - operator delete(sortedCoplanar); - } + // Always trying to maintain valid bounds + std::vector boundCopies(itemCount); + std::ranges::copy(m_item_bounds, boundCopies.begin()); + for (size_t itemIndex = 0; itemIndex < itemCount; ++itemIndex) + m_item_bounds[itemIndex] = boundCopies[remap[itemIndex]]; - return aabbTreeCount; + return m_nodes.size(); } private: - void BuildAabbTree_r(GenericAabbTree* tree, GenericAabbTreeOptions* options, int* remap) + void BuildAabbTree_r(size_t treeIndex, size_t* remap) { - int midStart; // [esp+0h] [ebp-10h] BYREF - int childIndex; // [esp+4h] [ebp-Ch] - int lastStart; // [esp+8h] [ebp-8h] BYREF - GenericAabbTree* subtree; // [esp+Ch] [ebp-4h] + assert(m_nodes[treeIndex].itemCount); - assert(tree->itemCount); + m_nodes[treeIndex].firstChild = m_nodes.size(); + m_nodes[treeIndex].childCount = 0; - tree->firstChild = aabbTreeCount; - tree->childCount = 0; - if (tree->itemCount > options->maxItemsPerLeaf && SplitAabbTree(tree->itemCount, options, remap, &midStart, &lastStart)) + size_t midStart, lastStart; + if (m_nodes[treeIndex].itemCount > MAX_ITEMS_PER_LEAF && SplitAabbTree(m_nodes[treeIndex].itemCount, remap, &midStart, &lastStart)) { - subtree = &options->treeNodePool[aabbTreeCount]; + const auto subTreeStartIndex = m_nodes.size(); + assert(m_nodes[treeIndex].firstChild == subTreeStartIndex); - assert(tree->firstChild == aabbTreeCount); + CreateAabbSubTrees(treeIndex, remap, 0, midStart); - CreateAabbSubTrees(tree, options, remap, 0, midStart); if (midStart < lastStart) - CreateAabbSubTrees(tree, options, remap, midStart, lastStart - midStart); - CreateAabbSubTrees(tree, options, remap, lastStart, tree->itemCount - lastStart); - tree->childCount = aabbTreeCount - tree->firstChild; - for (childIndex = 0; childIndex < tree->childCount; ++childIndex) - BuildAabbTree_r(&subtree[childIndex], options, &remap[subtree[childIndex].firstItem - tree->firstItem]); + CreateAabbSubTrees(treeIndex, remap, midStart, lastStart - midStart); + + CreateAabbSubTrees(treeIndex, remap, lastStart, m_nodes[treeIndex].itemCount - lastStart); + + m_nodes[treeIndex].childCount = m_nodes.size() - m_nodes[treeIndex].firstChild; + for (size_t childIndex = 0; childIndex < m_nodes[treeIndex].childCount; ++childIndex) + { + const auto subTreeIndex = subTreeStartIndex + childIndex; + BuildAabbTree_r(subTreeIndex, &remap[m_nodes[subTreeIndex].firstItem - m_nodes[treeIndex].firstItem]); + } } } - int SplitAabbTree(int count, GenericAabbTreeOptions* options, int* remap, int* midStart, int* lastStart) + int SplitAabbTree(const size_t count, size_t* remap, size_t* midStart, size_t* lastStart) { - float v6; // [esp+4h] [ebp-58h] - float v7; // [esp+8h] [ebp-54h] - int top; // [esp+Ch] [ebp-50h] - float (*mins)[3]; // [esp+10h] [ebp-4Ch] - int splitAxis; // [esp+14h] [ebp-48h] BYREF - int bot; // [esp+18h] [ebp-44h] - float bounds[3]; // [esp+1Ch] [ebp-40h] BYREF - float v13[3]; // [esp+28h] [ebp-34h] BYREF - float v14[3]; // [esp+34h] [ebp-28h] BYREF - float v15[3]; // [esp+40h] [ebp-1Ch] BYREF - float (*maxs)[3]; // [esp+4Ch] [ebp-10h] - float splitDist; // [esp+50h] [ebp-Ch] BYREF - int swapCache; // [esp+54h] [ebp-8h] - int mid; // [esp+58h] [ebp-4h] + size_t swapCache; - mins = options->mins; - maxs = options->maxs; - if (!PickAabbSplitPlane(mins, maxs, remap, count, &splitAxis, &splitDist)) + int splitAxis; + float splitDist; + if (!PickAabbSplitPlane(m_item_bounds.data(), remap, count, splitAxis, splitDist)) return 0; - ClearBounds(bounds, v13); - ClearBounds(v14, v15); - bot = 0; - top = count - 1; + + int bot = 0; + int top = static_cast(count - 1); + Bounds bounds[2]; while (bot <= top) { - while (bot <= top && splitDist >= maxs[remap[bot]][splitAxis] && splitDist > mins[remap[bot]][splitAxis]) + while (bot <= top && splitDist >= m_item_bounds[remap[bot]].m_maxs[splitAxis] && splitDist > m_item_bounds[remap[bot]].m_mins[splitAxis]) { - ExpandBounds(mins[remap[bot]], maxs[remap[bot]], bounds, v13); + bounds[0].ExpandFromBounds(m_item_bounds[remap[bot]]); ++bot; } - while (bot <= top && mins[remap[top]][splitAxis] >= splitDist && maxs[remap[top]][splitAxis] > splitDist) + + while (bot <= top && m_item_bounds[remap[top]].m_mins[splitAxis] >= splitDist && m_item_bounds[remap[top]].m_maxs[splitAxis] > splitDist) { - ExpandBounds(mins[remap[top]], maxs[remap[top]], v14, v15); + bounds[1].ExpandFromBounds(m_item_bounds[remap[top]]); --top; } + if (bot > top) break; - if ((mins[remap[bot]][splitAxis] < splitDist || maxs[remap[bot]][splitAxis] <= splitDist) - && (splitDist < maxs[remap[top]][splitAxis] || splitDist <= mins[remap[top]][splitAxis])) + + if ((m_item_bounds[remap[bot]].m_mins[splitAxis] < splitDist || m_item_bounds[remap[bot]].m_maxs[splitAxis] <= splitDist) + && (splitDist < m_item_bounds[remap[top]].m_maxs[splitAxis] || splitDist <= m_item_bounds[remap[top]].m_mins[splitAxis])) { + int mid; for (mid = bot; mid < top; ++mid) { - if (mins[remap[mid]][splitAxis] >= splitDist && maxs[remap[mid]][splitAxis] > splitDist) + if (m_item_bounds[remap[mid]].m_mins[splitAxis] >= splitDist && m_item_bounds[remap[mid]].m_maxs[splitAxis] > splitDist) { swapCache = remap[mid]; remap[mid] = remap[top]; remap[top] = swapCache; break; } - if (splitDist >= maxs[remap[mid]][splitAxis] && splitDist > mins[remap[mid]][splitAxis]) + + if (splitDist >= m_item_bounds[remap[mid]].m_maxs[splitAxis] && splitDist > m_item_bounds[remap[mid]].m_mins[splitAxis]) { swapCache = remap[mid]; remap[mid] = remap[bot]; @@ -320,6 +202,7 @@ namespace break; } } + if (mid == top) break; } @@ -330,31 +213,34 @@ namespace remap[top] = swapCache; } } - if (bot <= top && (bot < options->minItemsPerLeaf || top - bot + 1 < options->minItemsPerLeaf || count - top - 1 < options->minItemsPerLeaf)) + + if (bot <= top && (bot < MIN_ITEMS_PER_LEAF || top - bot + 1 < MIN_ITEMS_PER_LEAF || count - top - 1 < MIN_ITEMS_PER_LEAF)) { while (bot <= top) { while (bot <= top) { - v7 = AddedVolume(mins[remap[bot]], maxs[remap[bot]], bounds, v13); - if (AddedVolume(mins[remap[bot]], maxs[remap[bot]], v14, v15) < (double)v7) + if (bounds[1].AddedVolume(m_item_bounds[remap[bot]]) < bounds[0].AddedVolume(m_item_bounds[remap[bot]])) break; - ExpandBounds(mins[remap[bot]], maxs[remap[bot]], bounds, v13); + + bounds[0].ExpandFromBounds(m_item_bounds[remap[bot]]); ++bot; } + while (bot <= top) { - v6 = AddedVolume(mins[remap[top]], maxs[remap[top]], v14, v15); - if (AddedVolume(mins[remap[top]], maxs[remap[top]], bounds, v13) < (double)v6) + if (bounds[0].AddedVolume(m_item_bounds[remap[top]]) < bounds[1].AddedVolume(m_item_bounds[remap[top]])) break; - ExpandBounds(mins[remap[top]], maxs[remap[top]], v14, v15); + + bounds[1].ExpandFromBounds(m_item_bounds[remap[top]]); --top; } + if (bot >= top) { if (bot == top) { - if (2 * bot >= count) + if (static_cast(2 * bot) >= count) --top; else ++bot; @@ -370,126 +256,107 @@ namespace } } } + if (!bot || bot == count) return 0; + *midStart = bot; *lastStart = top + 1; + return 1; } - bool PickAabbSplitPlane(float (*mins)[3], float (*maxs)[3], int* remap, int count, int* chosenAxis, float* chosenDist) + bool PickAabbSplitPlane(const Bounds* bounds, const size_t* remap, const size_t count, int& chosenAxis, float& chosenDist) { - float v7; // [esp+4h] [ebp-A0h] - int sideSplitCount; // [esp+38h] [ebp-6Ch] - float nextDist; // [esp+3Ch] [ebp-68h] - int prevMinCount; // [esp+40h] [ebp-64h] - int prevOnCount; // [esp+44h] [ebp-60h] - float dist; // [esp+48h] [ebp-5Ch] - signed int minMaxCount; // [esp+4Ch] [ebp-58h] - signed int coplanarCount; // [esp+50h] [ebp-54h] - int axisIndex; // [esp+54h] [ebp-50h] - signed int bestHeuristic; // [esp+58h] [ebp-4Ch] - int smallestAxis; // [esp+5Ch] [ebp-48h] - int maxIndex; // [esp+60h] [ebp-44h] - float globalMaxs[3]; // [esp+64h] [ebp-40h] BYREF - int sideFrontCount; // [esp+70h] [ebp-34h] - int i; // [esp+74h] [ebp-30h] - int sideOnCount; // [esp+78h] [ebp-2Ch] - float globalMins[3]; // [esp+7Ch] [ebp-28h] BYREF - int axisBias[3]; // [esp+88h] [ebp-1Ch] - int minIndex; // [esp+94h] [ebp-10h] - int onIndex; // [esp+98h] [ebp-Ch] - int heuristic; // [esp+9Ch] [ebp-8h] - int sideBackCount; // [esp+A0h] [ebp-4h] + Bounds globalBounds; - ClearBounds(globalMins, globalMaxs); + for (size_t i = 0; i < count; ++i) + globalBounds.ExpandFromBounds(bounds[remap[i]]); - for (i = 0; i < count; ++i) - ExpandBounds(mins[remap[i]], maxs[remap[i]], globalMins, globalMaxs); - - smallestAxis = globalMaxs[0] - globalMins[0] > globalMaxs[1] - globalMins[1]; - if (globalMaxs[smallestAxis] - globalMins[smallestAxis] > globalMaxs[2] - globalMins[2]) + size_t smallestAxis = globalBounds.m_maxs[0] - globalBounds.m_mins[0] > globalBounds.m_maxs[1] - globalBounds.m_mins[1]; + if (globalBounds.m_maxs[smallestAxis] - globalBounds.m_mins[smallestAxis] > globalBounds.m_maxs[2] - globalBounds.m_mins[2]) smallestAxis = 2; - for (i = 0; i < 3; ++i) + int axisBias[3]; + for (size_t i = 0; i < 3u; ++i) { - axisBias[i] = static_cast((globalMaxs[i] - globalMins[i] + 1.0f) * 10.0f / (globalMaxs[smallestAxis] - globalMins[smallestAxis] + 1.0f) + axisBias[i] = static_cast((globalBounds.m_maxs[i] - globalBounds.m_mins[i] + 1.0f) * 10.0f + / (globalBounds.m_maxs[smallestAxis] - globalBounds.m_mins[smallestAxis] + 1.0f) + 0.4999999990686774); } - bestHeuristic = -1; - - for (axisIndex = 0; axisIndex < 3; ++axisIndex) + auto bestHeuristic = -1; + for (int axisIndex = 0; axisIndex < 3; ++axisIndex) { - minMaxCount = 0; - coplanarCount = 0; + size_t minMaxCount = 0; + size_t coplanarCount = 0; - for (i = 0; i < count; ++i) + for (size_t i = 0; i < count; ++i) { - if (mins[remap[i]][axisIndex] == maxs[remap[i]][axisIndex]) + if (bounds[remap[i]].m_mins[axisIndex] == bounds[remap[i]].m_maxs[axisIndex]) { - sortedCoplanar[coplanarCount++] = mins[remap[i]][axisIndex]; + m_sorted_coplanar[coplanarCount++] = bounds[remap[i]].m_mins[axisIndex]; } else { - sortedMins[minMaxCount] = mins[remap[i]][axisIndex]; - sortedMaxs[minMaxCount++] = maxs[remap[i]][axisIndex]; + m_sorted_mins[minMaxCount] = bounds[remap[i]].m_mins[axisIndex]; + m_sorted_maxs[minMaxCount++] = bounds[remap[i]].m_maxs[axisIndex]; } } - qsort(sortedMins, minMaxCount, 4u, compare_floats); - qsort(sortedMaxs, minMaxCount, 4u, compare_floats); - qsort(sortedCoplanar, coplanarCount, 4u, compare_floats); + std::sort(&m_sorted_mins[0], &m_sorted_mins[minMaxCount], std::greater()); + std::sort(&m_sorted_maxs[0], &m_sorted_maxs[minMaxCount], std::greater()); + std::sort(&m_sorted_coplanar[0], &m_sorted_coplanar[coplanarCount], std::greater()); - sideFrontCount = 0; - sideBackCount = count; - sideSplitCount = 0; - sideOnCount = 0; - minIndex = 0; - maxIndex = 0; - onIndex = 0; - prevMinCount = 0; - prevOnCount = 0; + int sideFrontCount = 0; + int sideBackCount = static_cast(count); + int sideSplitCount = 0; + int sideOnCount = 0; + int prevMinCount = 0; + int prevOnCount = 0; - // if (*sortedCoplanar - *sortedMins < 0.0f) - if (coplanarCount && *sortedCoplanar - *sortedMins < 0.0f) - v7 = *sortedCoplanar; + float nextDist; + if (coplanarCount && m_sorted_coplanar[0] - m_sorted_mins[0] < 0.0f) + nextDist = m_sorted_coplanar[0]; else - v7 = *sortedMins; + nextDist = m_sorted_mins[0]; - nextDist = v7; - while (nextDist < FLT_MAX) + size_t minIndex = 0; + size_t maxIndex = 0; + size_t onIndex = 0; + while (nextDist < std::numeric_limits::max()) { - dist = nextDist; - nextDist = FLT_MAX; + const auto dist = nextDist; + nextDist = std::numeric_limits::max(); + sideSplitCount += prevMinCount; sideBackCount -= prevMinCount; prevMinCount = 0; - while (minIndex < minMaxCount && sortedMins[minIndex] == dist) + while (minIndex < minMaxCount && m_sorted_mins[minIndex] == dist) { ++prevMinCount; ++minIndex; } - if (minIndex < minMaxCount && sortedMins[minIndex] < nextDist) - nextDist = sortedMins[minIndex]; + if (minIndex < minMaxCount && m_sorted_mins[minIndex] < nextDist) + nextDist = m_sorted_mins[minIndex]; - while (maxIndex < minMaxCount && sortedMaxs[maxIndex] == dist) + while (maxIndex < minMaxCount && m_sorted_maxs[maxIndex] == dist) { ++sideFrontCount; --sideSplitCount; ++maxIndex; } - if (maxIndex < minMaxCount && nextDist > sortedMaxs[maxIndex]) - nextDist = sortedMaxs[maxIndex]; + if (maxIndex < minMaxCount && nextDist > m_sorted_maxs[maxIndex]) + nextDist = m_sorted_maxs[maxIndex]; sideFrontCount += prevOnCount; sideOnCount -= prevOnCount; prevOnCount = 0; - while (onIndex < coplanarCount && sortedCoplanar[onIndex] == dist) + while (onIndex < coplanarCount && m_sorted_coplanar[onIndex] == dist) { ++prevOnCount; ++onIndex; @@ -498,8 +365,8 @@ namespace sideOnCount += prevOnCount; sideBackCount -= prevOnCount; - if (onIndex < coplanarCount && nextDist > sortedCoplanar[onIndex]) - nextDist = sortedCoplanar[onIndex]; + if (onIndex < coplanarCount && nextDist > m_sorted_coplanar[onIndex]) + nextDist = m_sorted_coplanar[onIndex]; assert(sideFrontCount + sideBackCount + sideSplitCount + sideOnCount == count); assert(sideFrontCount >= 0); @@ -509,21 +376,20 @@ namespace if (sideFrontCount > 1 && sideBackCount > 1) { - heuristic = axisBias[axisIndex] + count - std::abs(sideFrontCount - sideBackCount) - sideOnCount - 4 * sideSplitCount; + int heuristic = + axisBias[axisIndex] + static_cast(count) - std::abs(sideFrontCount - sideBackCount) - sideOnCount - 4 * sideSplitCount; + if (!sideOnCount && !sideSplitCount && !prevMinCount) - { - // heuristic += (int)((float)(nextDist - dist) + 9.313225746154785e-10); heuristic += static_cast(nextDist - dist); - } if (heuristic > bestHeuristic) { bestHeuristic = heuristic; - *chosenAxis = axisIndex; + chosenAxis = axisIndex; if (sideOnCount || sideSplitCount || prevMinCount) - *chosenDist = dist; + chosenDist = dist; else - *chosenDist = (dist + nextDist) * 0.5f; + chosenDist = (dist + nextDist) * 0.5f; } } } @@ -532,51 +398,55 @@ namespace return bestHeuristic != -1; } - void CreateAabbSubTrees(GenericAabbTree* tree, GenericAabbTreeOptions* options, int* remap, int firstIndex, int count) + void CreateAabbSubTrees(const size_t treeIndex, size_t* remap, const size_t firstIndex, const size_t count) { - int midStart; // [esp+0h] [ebp-Ch] BYREF - int lastStart; // [esp+4h] [ebp-8h] BYREF - GenericAabbTree* subtree; // [esp+8h] [ebp-4h] - - if (count > options->maxItemsPerLeaf && SplitAabbTree(count, options, &remap[firstIndex], &midStart, &lastStart)) + size_t midStart, lastStart; + if (count > MAX_ITEMS_PER_LEAF && SplitAabbTree(count, &remap[firstIndex], &midStart, &lastStart)) { - subtree = AllocAabbTreeNode(options); - subtree->firstItem = firstIndex + tree->firstItem; - subtree->itemCount = midStart; + m_nodes.emplace_back(GenericAabbTree{ + .firstItem = firstIndex + m_nodes[treeIndex].firstItem, + .itemCount = midStart, + .firstChild = 0, + .childCount = 0, + }); + if (midStart < lastStart) { - subtree = AllocAabbTreeNode(options); - subtree->firstItem = midStart + firstIndex + tree->firstItem; - subtree->itemCount = lastStart - midStart; + m_nodes.emplace_back(GenericAabbTree{ + .firstItem = midStart + firstIndex + m_nodes[treeIndex].firstItem, + .itemCount = lastStart - midStart, + .firstChild = 0, + .childCount = 0, + }); } - subtree = AllocAabbTreeNode(options); - subtree->firstItem = lastStart + firstIndex + tree->firstItem; - subtree->itemCount = count - lastStart; + + m_nodes.emplace_back(GenericAabbTree{ + .firstItem = lastStart + firstIndex + m_nodes[treeIndex].firstItem, + .itemCount = count - lastStart, + .firstChild = 0, + .childCount = 0, + }); } else { - subtree = AllocAabbTreeNode(options); - subtree->firstItem = firstIndex + tree->firstItem; - subtree->itemCount = count; + m_nodes.emplace_back(GenericAabbTree{ + .firstItem = firstIndex + m_nodes[treeIndex].firstItem, + .itemCount = count, + .firstChild = 0, + .childCount = 0, + }); } } - GenericAabbTree* AllocAabbTreeNode(GenericAabbTreeOptions* options) - { - if (aabbTreeCount == options->treeNodeLimit) - { - con::error("More than {} AABB nodes needed", options->treeNodeLimit); - throw std::runtime_error("More than {} AABB nodes needed"); - } - - return &options->treeNodePool[aabbTreeCount++]; - } + // Options + std::vector& m_nodes; + std::vector& m_items; + std::vector& m_item_bounds; // State - float* sortedMins; - float* sortedMaxs; - float* sortedCoplanar; - int aabbTreeCount; + std::vector m_sorted_mins; + std::vector m_sorted_maxs; + std::vector m_sorted_coplanar; }; } // namespace @@ -638,43 +508,22 @@ namespace xmodel tree->scale = Eigen::Vector3f(std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()) .cwiseQuotient(globalDelta); - AabbTreeBuilder aabbTreeBuilder; - GenericAabbTreeOptions options{}; - options.maintainValidBounds = 1; - options.treeNodePool = (GenericAabbTree*)malloc(sizeof(GenericAabbTree) * 0x2000); - options.treeNodeLimit = 0x2000; - options.minItemsPerLeaf = 1; - options.maxItemsPerLeaf = 16; - options.mins = (float (*)[3])malloc(12 * leafBounds.size()); - options.maxs = (float (*)[3])malloc(12 * leafBounds.size()); - options.items = tree->leafs.data(); - options.itemCount = static_cast(leafBounds.size()); - options.itemSize = 2; - - for (size_t leafIndex = 0; leafIndex < leafBounds.size(); ++leafIndex) - { - const auto& bounds = leafBounds[leafIndex]; - options.mins[leafIndex][0] = bounds.m_mins.x(); - options.mins[leafIndex][1] = bounds.m_mins.y(); - options.mins[leafIndex][2] = bounds.m_mins.z(); - options.maxs[leafIndex][0] = bounds.m_maxs.x(); - options.maxs[leafIndex][1] = bounds.m_maxs.y(); - options.maxs[leafIndex][2] = bounds.m_maxs.z(); - } - - const auto nodeCount = options.itemCount > 0 ? aabbTreeBuilder.BuildAabbTree(&options) : 0; + std::vector nodes; + AabbTreeBuilder aabbTreeBuilder(nodes, tree->leafs, leafBounds); + aabbTreeBuilder.BuildAabbTree(); + const auto nodeCount = nodes.size(); tree->nodes.resize(nodeCount); - for (auto nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex) + for (size_t nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex) { auto& outNode = tree->nodes[nodeIndex]; - const auto& builtNode = options.treeNodePool[nodeIndex]; + const auto& builtNode = nodes[nodeIndex]; const auto leafEnd = builtNode.itemCount + builtNode.firstItem; Bounds nodeBounds; for (auto leafIndex = builtNode.firstItem; leafIndex < leafEnd; ++leafIndex) - nodeBounds.ExpandFromBounds(options.mins[leafIndex], options.maxs[leafIndex]); + nodeBounds.ExpandFromBounds(leafBounds[leafIndex]); outNode.aabb.mins[0] = static_cast(std::clamp( (nodeBounds.m_mins.x() + tree->trans[0]) * tree->scale[0] - 0.5f, std::numeric_limits::min(), std::numeric_limits::max())); @@ -692,28 +541,25 @@ namespace xmodel if (builtNode.childCount) { - outNode.childBeginIndex = builtNode.firstChild; - assert(outNode.childBeginIndex == builtNode.firstChild); + assert(builtNode.firstChild <= std::numeric_limits::max()); + outNode.childBeginIndex = static_cast(builtNode.firstChild); - outNode.childCount = builtNode.childCount; - assert(outNode.childCount == builtNode.childCount); + assert(builtNode.childCount <= std::numeric_limits::max()); + outNode.childCount = static_cast(builtNode.childCount); } else { assert(builtNode.itemCount); - outNode.childBeginIndex = builtNode.firstItem; - assert(outNode.childBeginIndex == builtNode.firstItem); + assert(builtNode.firstItem <= std::numeric_limits::max()); + outNode.childBeginIndex = static_cast(builtNode.firstItem); - outNode.childCount = builtNode.itemCount; - assert(outNode.childCount == builtNode.itemCount); + assert(builtNode.itemCount <= std::numeric_limits::max()); + outNode.childCount = static_cast(builtNode.itemCount); outNode.childrenAreLeafs = true; } } - free(options.mins); - free(options.maxs); - free(options.treeNodePool); return std::move(tree); } diff --git a/src/ObjLoading/XModel/LoaderXModel.cpp.template b/src/ObjLoading/XModel/LoaderXModel.cpp.template index 923a1a13..c5efdd94 100644 --- a/src/ObjLoading/XModel/LoaderXModel.cpp.template +++ b/src/ObjLoading/XModel/LoaderXModel.cpp.template @@ -576,7 +576,7 @@ namespace node.childCount |= XSURFACE_COLLISION_NODE_HAS_LEAFS; } - tree->leafCount = commonTree.leafs.size(); + tree->leafCount = static_castleafCount)>(commonTree.leafs.size()); tree->leafs = m_memory.Alloc(tree->leafCount); for (auto leafIndex = 0u; leafIndex < tree->leafCount; leafIndex++) {