mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-05-25 02:51:43 +00:00
chore: modernize collision tree code
This commit is contained in:
@@ -4,32 +4,9 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace
|
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
|
class Bounds
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -62,16 +39,6 @@ namespace
|
|||||||
m_maxs[2] = std::max(m_maxs[2], otherBounds.m_maxs[2]);
|
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
|
[[nodiscard]] Eigen::Vector3f GetDelta() const
|
||||||
{
|
{
|
||||||
return m_maxs - m_mins;
|
return m_maxs - m_mins;
|
||||||
@@ -82,237 +49,152 @@ namespace
|
|||||||
return GetDelta().prod();
|
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_mins;
|
||||||
Eigen::Vector3f m_maxs;
|
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;
|
size_t firstItem;
|
||||||
mins[1] = FLT_MAX;
|
size_t itemCount;
|
||||||
mins[2] = FLT_MAX;
|
size_t firstChild;
|
||||||
maxs[0] = -FLT_MAX;
|
size_t childCount;
|
||||||
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<const float*>(e0) - *static_cast<const float*>(e1);
|
|
||||||
if (diff >= 0.0)
|
|
||||||
return diff > 0.0;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AabbTreeBuilder
|
class AabbTreeBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AabbTreeBuilder()
|
AabbTreeBuilder(std::vector<GenericAabbTree>& nodes, std::vector<xmodel::CommonCollisionLeaf>& items, std::vector<Bounds>& itemBounds)
|
||||||
: sortedMins(nullptr),
|
: m_nodes(nodes),
|
||||||
sortedMaxs(nullptr),
|
m_items(items),
|
||||||
sortedCoplanar(nullptr),
|
m_item_bounds(itemBounds)
|
||||||
aabbTreeCount(0)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
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]
|
const auto itemCount = m_items.size();
|
||||||
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]
|
|
||||||
|
|
||||||
if (options->itemCount > STACK_BUFFER_SIZE)
|
std::vector<size_t> remap(m_items.size());
|
||||||
{
|
m_sorted_mins = std::vector<float>(m_items.size());
|
||||||
remap = (int*)operator new(4 * options->itemCount);
|
m_sorted_maxs = std::vector<float>(m_items.size());
|
||||||
sortedMins = (float*)operator new(4 * options->itemCount);
|
m_sorted_coplanar = std::vector<float>(m_items.size());
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (itemIndex = 0; itemIndex < options->itemCount; ++itemIndex)
|
std::ranges::iota(remap, 0);
|
||||||
remap[itemIndex] = itemIndex;
|
|
||||||
|
|
||||||
options->treeNodePool->firstItem = 0;
|
// Insert root node
|
||||||
options->treeNodePool->itemCount = options->itemCount;
|
m_nodes.emplace_back(GenericAabbTree{
|
||||||
|
.firstItem = 0,
|
||||||
|
.itemCount = itemCount,
|
||||||
|
.firstChild = 0,
|
||||||
|
.childCount = 0,
|
||||||
|
});
|
||||||
|
|
||||||
aabbTreeCount = 1;
|
BuildAabbTree_r(0, remap.data());
|
||||||
BuildAabbTree_r(options->treeNodePool, options, remap);
|
|
||||||
|
|
||||||
itemCopies = (char*)operator new(options->itemSize * options->itemCount);
|
// Reorder items
|
||||||
memcpy(itemCopies, options->items, options->itemSize * options->itemCount);
|
std::vector<xmodel::CommonCollisionLeaf> itemCopies(itemCount);
|
||||||
for (itemIndexa = 0; itemIndexa < options->itemCount; ++itemIndexa)
|
memcpy(itemCopies.data(), m_items.data(), sizeof(xmodel::CommonCollisionLeaf) * itemCount);
|
||||||
memcpy((char*)options->items + options->itemSize * itemIndexa, &itemCopies[options->itemSize * remap[itemIndexa]], options->itemSize);
|
for (size_t itemIndex = 0; itemIndex < itemCount; ++itemIndex)
|
||||||
operator delete(itemCopies);
|
m_items[itemIndex] = itemCopies[remap[itemIndex]];
|
||||||
|
|
||||||
if (options->maintainValidBounds)
|
// Always trying to maintain valid bounds
|
||||||
{
|
std::vector<Bounds> boundCopies(itemCount);
|
||||||
boundCopies =
|
std::ranges::copy(m_item_bounds, boundCopies.begin());
|
||||||
(float (*)[3]) operator new(4 * ((3 * (unsigned __int64)(unsigned int)options->itemCount) >> 32 != 0 ? -1 : 3 * options->itemCount));
|
for (size_t itemIndex = 0; itemIndex < itemCount; ++itemIndex)
|
||||||
memcpy(boundCopies, options->mins, 12 * options->itemCount);
|
m_item_bounds[itemIndex] = boundCopies[remap[itemIndex]];
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return aabbTreeCount;
|
return m_nodes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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
|
assert(m_nodes[treeIndex].itemCount);
|
||||||
int childIndex; // [esp+4h] [ebp-Ch]
|
|
||||||
int lastStart; // [esp+8h] [ebp-8h] BYREF
|
|
||||||
GenericAabbTree* subtree; // [esp+Ch] [ebp-4h]
|
|
||||||
|
|
||||||
assert(tree->itemCount);
|
m_nodes[treeIndex].firstChild = m_nodes.size();
|
||||||
|
m_nodes[treeIndex].childCount = 0;
|
||||||
|
|
||||||
tree->firstChild = aabbTreeCount;
|
size_t midStart, lastStart;
|
||||||
tree->childCount = 0;
|
if (m_nodes[treeIndex].itemCount > MAX_ITEMS_PER_LEAF && SplitAabbTree(m_nodes[treeIndex].itemCount, remap, &midStart, &lastStart))
|
||||||
if (tree->itemCount > options->maxItemsPerLeaf && SplitAabbTree(tree->itemCount, options, 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)
|
if (midStart < lastStart)
|
||||||
CreateAabbSubTrees(tree, options, remap, midStart, lastStart - midStart);
|
CreateAabbSubTrees(treeIndex, 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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SplitAabbTree(int count, GenericAabbTreeOptions* options, int* remap, int* midStart, int* lastStart)
|
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)
|
||||||
{
|
{
|
||||||
float v6; // [esp+4h] [ebp-58h]
|
const auto subTreeIndex = subTreeStartIndex + childIndex;
|
||||||
float v7; // [esp+8h] [ebp-54h]
|
BuildAabbTree_r(subTreeIndex, &remap[m_nodes[subTreeIndex].firstItem - m_nodes[treeIndex].firstItem]);
|
||||||
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]
|
|
||||||
|
|
||||||
mins = options->mins;
|
int SplitAabbTree(const size_t count, size_t* remap, size_t* midStart, size_t* lastStart)
|
||||||
maxs = options->maxs;
|
{
|
||||||
if (!PickAabbSplitPlane(mins, maxs, remap, count, &splitAxis, &splitDist))
|
size_t swapCache;
|
||||||
|
|
||||||
|
int splitAxis;
|
||||||
|
float splitDist;
|
||||||
|
if (!PickAabbSplitPlane(m_item_bounds.data(), remap, count, splitAxis, splitDist))
|
||||||
return 0;
|
return 0;
|
||||||
ClearBounds(bounds, v13);
|
|
||||||
ClearBounds(v14, v15);
|
int bot = 0;
|
||||||
bot = 0;
|
int top = static_cast<int>(count - 1);
|
||||||
top = count - 1;
|
Bounds bounds[2];
|
||||||
while (bot <= top)
|
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;
|
++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;
|
--top;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bot > top)
|
if (bot > top)
|
||||||
break;
|
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)
|
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];
|
swapCache = remap[mid];
|
||||||
remap[mid] = remap[top];
|
remap[mid] = remap[top];
|
||||||
remap[top] = swapCache;
|
remap[top] = swapCache;
|
||||||
break;
|
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];
|
swapCache = remap[mid];
|
||||||
remap[mid] = remap[bot];
|
remap[mid] = remap[bot];
|
||||||
@@ -320,6 +202,7 @@ namespace
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mid == top)
|
if (mid == top)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -330,31 +213,34 @@ namespace
|
|||||||
remap[top] = swapCache;
|
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)
|
||||||
{
|
{
|
||||||
while (bot <= top)
|
while (bot <= top)
|
||||||
{
|
{
|
||||||
v7 = AddedVolume(mins[remap[bot]], maxs[remap[bot]], bounds, v13);
|
if (bounds[1].AddedVolume(m_item_bounds[remap[bot]]) < bounds[0].AddedVolume(m_item_bounds[remap[bot]]))
|
||||||
if (AddedVolume(mins[remap[bot]], maxs[remap[bot]], v14, v15) < (double)v7)
|
|
||||||
break;
|
break;
|
||||||
ExpandBounds(mins[remap[bot]], maxs[remap[bot]], bounds, v13);
|
|
||||||
|
bounds[0].ExpandFromBounds(m_item_bounds[remap[bot]]);
|
||||||
++bot;
|
++bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (bot <= top)
|
while (bot <= top)
|
||||||
{
|
{
|
||||||
v6 = AddedVolume(mins[remap[top]], maxs[remap[top]], v14, v15);
|
if (bounds[0].AddedVolume(m_item_bounds[remap[top]]) < bounds[1].AddedVolume(m_item_bounds[remap[top]]))
|
||||||
if (AddedVolume(mins[remap[top]], maxs[remap[top]], bounds, v13) < (double)v6)
|
|
||||||
break;
|
break;
|
||||||
ExpandBounds(mins[remap[top]], maxs[remap[top]], v14, v15);
|
|
||||||
|
bounds[1].ExpandFromBounds(m_item_bounds[remap[top]]);
|
||||||
--top;
|
--top;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bot >= top)
|
if (bot >= top)
|
||||||
{
|
{
|
||||||
if (bot == top)
|
if (bot == top)
|
||||||
{
|
{
|
||||||
if (2 * bot >= count)
|
if (static_cast<size_t>(2 * bot) >= count)
|
||||||
--top;
|
--top;
|
||||||
else
|
else
|
||||||
++bot;
|
++bot;
|
||||||
@@ -370,126 +256,107 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bot || bot == count)
|
if (!bot || bot == count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
*midStart = bot;
|
*midStart = bot;
|
||||||
*lastStart = top + 1;
|
*lastStart = top + 1;
|
||||||
|
|
||||||
return 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]
|
Bounds globalBounds;
|
||||||
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]
|
|
||||||
|
|
||||||
ClearBounds(globalMins, globalMaxs);
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
globalBounds.ExpandFromBounds(bounds[remap[i]]);
|
||||||
|
|
||||||
for (i = 0; i < count; ++i)
|
size_t smallestAxis = globalBounds.m_maxs[0] - globalBounds.m_mins[0] > globalBounds.m_maxs[1] - globalBounds.m_mins[1];
|
||||||
ExpandBounds(mins[remap[i]], maxs[remap[i]], globalMins, globalMaxs);
|
if (globalBounds.m_maxs[smallestAxis] - globalBounds.m_mins[smallestAxis] > globalBounds.m_maxs[2] - globalBounds.m_mins[2])
|
||||||
|
|
||||||
smallestAxis = globalMaxs[0] - globalMins[0] > globalMaxs[1] - globalMins[1];
|
|
||||||
if (globalMaxs[smallestAxis] - globalMins[smallestAxis] > globalMaxs[2] - globalMins[2])
|
|
||||||
smallestAxis = 2;
|
smallestAxis = 2;
|
||||||
|
|
||||||
for (i = 0; i < 3; ++i)
|
int axisBias[3];
|
||||||
|
for (size_t i = 0; i < 3u; ++i)
|
||||||
{
|
{
|
||||||
axisBias[i] = static_cast<int>((globalMaxs[i] - globalMins[i] + 1.0f) * 10.0f / (globalMaxs[smallestAxis] - globalMins[smallestAxis] + 1.0f)
|
axisBias[i] = static_cast<int>((globalBounds.m_maxs[i] - globalBounds.m_mins[i] + 1.0f) * 10.0f
|
||||||
|
/ (globalBounds.m_maxs[smallestAxis] - globalBounds.m_mins[smallestAxis] + 1.0f)
|
||||||
+ 0.4999999990686774);
|
+ 0.4999999990686774);
|
||||||
}
|
}
|
||||||
|
|
||||||
bestHeuristic = -1;
|
auto bestHeuristic = -1;
|
||||||
|
for (int axisIndex = 0; axisIndex < 3; ++axisIndex)
|
||||||
|
{
|
||||||
|
size_t minMaxCount = 0;
|
||||||
|
size_t coplanarCount = 0;
|
||||||
|
|
||||||
for (axisIndex = 0; axisIndex < 3; ++axisIndex)
|
for (size_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
minMaxCount = 0;
|
if (bounds[remap[i]].m_mins[axisIndex] == bounds[remap[i]].m_maxs[axisIndex])
|
||||||
coplanarCount = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < count; ++i)
|
|
||||||
{
|
{
|
||||||
if (mins[remap[i]][axisIndex] == maxs[remap[i]][axisIndex])
|
m_sorted_coplanar[coplanarCount++] = bounds[remap[i]].m_mins[axisIndex];
|
||||||
{
|
|
||||||
sortedCoplanar[coplanarCount++] = mins[remap[i]][axisIndex];
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sortedMins[minMaxCount] = mins[remap[i]][axisIndex];
|
m_sorted_mins[minMaxCount] = bounds[remap[i]].m_mins[axisIndex];
|
||||||
sortedMaxs[minMaxCount++] = maxs[remap[i]][axisIndex];
|
m_sorted_maxs[minMaxCount++] = bounds[remap[i]].m_maxs[axisIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(sortedMins, minMaxCount, 4u, compare_floats);
|
std::sort(&m_sorted_mins[0], &m_sorted_mins[minMaxCount], std::greater());
|
||||||
qsort(sortedMaxs, minMaxCount, 4u, compare_floats);
|
std::sort(&m_sorted_maxs[0], &m_sorted_maxs[minMaxCount], std::greater());
|
||||||
qsort(sortedCoplanar, coplanarCount, 4u, compare_floats);
|
std::sort(&m_sorted_coplanar[0], &m_sorted_coplanar[coplanarCount], std::greater());
|
||||||
|
|
||||||
sideFrontCount = 0;
|
int sideFrontCount = 0;
|
||||||
sideBackCount = count;
|
int sideBackCount = static_cast<int>(count);
|
||||||
sideSplitCount = 0;
|
int sideSplitCount = 0;
|
||||||
sideOnCount = 0;
|
int sideOnCount = 0;
|
||||||
minIndex = 0;
|
int prevMinCount = 0;
|
||||||
maxIndex = 0;
|
int prevOnCount = 0;
|
||||||
onIndex = 0;
|
|
||||||
prevMinCount = 0;
|
|
||||||
prevOnCount = 0;
|
|
||||||
|
|
||||||
// if (*sortedCoplanar - *sortedMins < 0.0f)
|
float nextDist;
|
||||||
if (coplanarCount && *sortedCoplanar - *sortedMins < 0.0f)
|
if (coplanarCount && m_sorted_coplanar[0] - m_sorted_mins[0] < 0.0f)
|
||||||
v7 = *sortedCoplanar;
|
nextDist = m_sorted_coplanar[0];
|
||||||
else
|
else
|
||||||
v7 = *sortedMins;
|
nextDist = m_sorted_mins[0];
|
||||||
|
|
||||||
nextDist = v7;
|
size_t minIndex = 0;
|
||||||
while (nextDist < FLT_MAX)
|
size_t maxIndex = 0;
|
||||||
|
size_t onIndex = 0;
|
||||||
|
while (nextDist < std::numeric_limits<float>::max())
|
||||||
{
|
{
|
||||||
dist = nextDist;
|
const auto dist = nextDist;
|
||||||
nextDist = FLT_MAX;
|
nextDist = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
sideSplitCount += prevMinCount;
|
sideSplitCount += prevMinCount;
|
||||||
sideBackCount -= prevMinCount;
|
sideBackCount -= prevMinCount;
|
||||||
prevMinCount = 0;
|
prevMinCount = 0;
|
||||||
|
|
||||||
while (minIndex < minMaxCount && sortedMins[minIndex] == dist)
|
while (minIndex < minMaxCount && m_sorted_mins[minIndex] == dist)
|
||||||
{
|
{
|
||||||
++prevMinCount;
|
++prevMinCount;
|
||||||
++minIndex;
|
++minIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minIndex < minMaxCount && sortedMins[minIndex] < nextDist)
|
if (minIndex < minMaxCount && m_sorted_mins[minIndex] < nextDist)
|
||||||
nextDist = sortedMins[minIndex];
|
nextDist = m_sorted_mins[minIndex];
|
||||||
|
|
||||||
while (maxIndex < minMaxCount && sortedMaxs[maxIndex] == dist)
|
while (maxIndex < minMaxCount && m_sorted_maxs[maxIndex] == dist)
|
||||||
{
|
{
|
||||||
++sideFrontCount;
|
++sideFrontCount;
|
||||||
--sideSplitCount;
|
--sideSplitCount;
|
||||||
++maxIndex;
|
++maxIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxIndex < minMaxCount && nextDist > sortedMaxs[maxIndex])
|
if (maxIndex < minMaxCount && nextDist > m_sorted_maxs[maxIndex])
|
||||||
nextDist = sortedMaxs[maxIndex];
|
nextDist = m_sorted_maxs[maxIndex];
|
||||||
|
|
||||||
sideFrontCount += prevOnCount;
|
sideFrontCount += prevOnCount;
|
||||||
sideOnCount -= prevOnCount;
|
sideOnCount -= prevOnCount;
|
||||||
prevOnCount = 0;
|
prevOnCount = 0;
|
||||||
|
|
||||||
while (onIndex < coplanarCount && sortedCoplanar[onIndex] == dist)
|
while (onIndex < coplanarCount && m_sorted_coplanar[onIndex] == dist)
|
||||||
{
|
{
|
||||||
++prevOnCount;
|
++prevOnCount;
|
||||||
++onIndex;
|
++onIndex;
|
||||||
@@ -498,8 +365,8 @@ namespace
|
|||||||
sideOnCount += prevOnCount;
|
sideOnCount += prevOnCount;
|
||||||
sideBackCount -= prevOnCount;
|
sideBackCount -= prevOnCount;
|
||||||
|
|
||||||
if (onIndex < coplanarCount && nextDist > sortedCoplanar[onIndex])
|
if (onIndex < coplanarCount && nextDist > m_sorted_coplanar[onIndex])
|
||||||
nextDist = sortedCoplanar[onIndex];
|
nextDist = m_sorted_coplanar[onIndex];
|
||||||
|
|
||||||
assert(sideFrontCount + sideBackCount + sideSplitCount + sideOnCount == count);
|
assert(sideFrontCount + sideBackCount + sideSplitCount + sideOnCount == count);
|
||||||
assert(sideFrontCount >= 0);
|
assert(sideFrontCount >= 0);
|
||||||
@@ -509,21 +376,20 @@ namespace
|
|||||||
|
|
||||||
if (sideFrontCount > 1 && sideBackCount > 1)
|
if (sideFrontCount > 1 && sideBackCount > 1)
|
||||||
{
|
{
|
||||||
heuristic = axisBias[axisIndex] + count - std::abs(sideFrontCount - sideBackCount) - sideOnCount - 4 * sideSplitCount;
|
int heuristic =
|
||||||
|
axisBias[axisIndex] + static_cast<int>(count) - std::abs(sideFrontCount - sideBackCount) - sideOnCount - 4 * sideSplitCount;
|
||||||
|
|
||||||
if (!sideOnCount && !sideSplitCount && !prevMinCount)
|
if (!sideOnCount && !sideSplitCount && !prevMinCount)
|
||||||
{
|
|
||||||
// heuristic += (int)((float)(nextDist - dist) + 9.313225746154785e-10);
|
|
||||||
heuristic += static_cast<int>(nextDist - dist);
|
heuristic += static_cast<int>(nextDist - dist);
|
||||||
}
|
|
||||||
|
|
||||||
if (heuristic > bestHeuristic)
|
if (heuristic > bestHeuristic)
|
||||||
{
|
{
|
||||||
bestHeuristic = heuristic;
|
bestHeuristic = heuristic;
|
||||||
*chosenAxis = axisIndex;
|
chosenAxis = axisIndex;
|
||||||
if (sideOnCount || sideSplitCount || prevMinCount)
|
if (sideOnCount || sideSplitCount || prevMinCount)
|
||||||
*chosenDist = dist;
|
chosenDist = dist;
|
||||||
else
|
else
|
||||||
*chosenDist = (dist + nextDist) * 0.5f;
|
chosenDist = (dist + nextDist) * 0.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -532,51 +398,55 @@ namespace
|
|||||||
return bestHeuristic != -1;
|
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
|
size_t midStart, lastStart;
|
||||||
int lastStart; // [esp+4h] [ebp-8h] BYREF
|
if (count > MAX_ITEMS_PER_LEAF && SplitAabbTree(count, &remap[firstIndex], &midStart, &lastStart))
|
||||||
GenericAabbTree* subtree; // [esp+8h] [ebp-4h]
|
{
|
||||||
|
m_nodes.emplace_back(GenericAabbTree{
|
||||||
|
.firstItem = firstIndex + m_nodes[treeIndex].firstItem,
|
||||||
|
.itemCount = midStart,
|
||||||
|
.firstChild = 0,
|
||||||
|
.childCount = 0,
|
||||||
|
});
|
||||||
|
|
||||||
if (count > options->maxItemsPerLeaf && SplitAabbTree(count, options, &remap[firstIndex], &midStart, &lastStart))
|
|
||||||
{
|
|
||||||
subtree = AllocAabbTreeNode(options);
|
|
||||||
subtree->firstItem = firstIndex + tree->firstItem;
|
|
||||||
subtree->itemCount = midStart;
|
|
||||||
if (midStart < lastStart)
|
if (midStart < lastStart)
|
||||||
{
|
{
|
||||||
subtree = AllocAabbTreeNode(options);
|
m_nodes.emplace_back(GenericAabbTree{
|
||||||
subtree->firstItem = midStart + firstIndex + tree->firstItem;
|
.firstItem = midStart + firstIndex + m_nodes[treeIndex].firstItem,
|
||||||
subtree->itemCount = lastStart - midStart;
|
.itemCount = lastStart - midStart,
|
||||||
|
.firstChild = 0,
|
||||||
|
.childCount = 0,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
subtree = AllocAabbTreeNode(options);
|
|
||||||
subtree->firstItem = lastStart + firstIndex + tree->firstItem;
|
m_nodes.emplace_back(GenericAabbTree{
|
||||||
subtree->itemCount = count - lastStart;
|
.firstItem = lastStart + firstIndex + m_nodes[treeIndex].firstItem,
|
||||||
|
.itemCount = count - lastStart,
|
||||||
|
.firstChild = 0,
|
||||||
|
.childCount = 0,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
subtree = AllocAabbTreeNode(options);
|
m_nodes.emplace_back(GenericAabbTree{
|
||||||
subtree->firstItem = firstIndex + tree->firstItem;
|
.firstItem = firstIndex + m_nodes[treeIndex].firstItem,
|
||||||
subtree->itemCount = count;
|
.itemCount = count,
|
||||||
|
.firstChild = 0,
|
||||||
|
.childCount = 0,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GenericAabbTree* AllocAabbTreeNode(GenericAabbTreeOptions* options)
|
// Options
|
||||||
{
|
std::vector<GenericAabbTree>& m_nodes;
|
||||||
if (aabbTreeCount == options->treeNodeLimit)
|
std::vector<xmodel::CommonCollisionLeaf>& m_items;
|
||||||
{
|
std::vector<Bounds>& m_item_bounds;
|
||||||
con::error("More than {} AABB nodes needed", options->treeNodeLimit);
|
|
||||||
throw std::runtime_error("More than {} AABB nodes needed");
|
|
||||||
}
|
|
||||||
|
|
||||||
return &options->treeNodePool[aabbTreeCount++];
|
|
||||||
}
|
|
||||||
|
|
||||||
// State
|
// State
|
||||||
float* sortedMins;
|
std::vector<float> m_sorted_mins;
|
||||||
float* sortedMaxs;
|
std::vector<float> m_sorted_maxs;
|
||||||
float* sortedCoplanar;
|
std::vector<float> m_sorted_coplanar;
|
||||||
int aabbTreeCount;
|
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -638,43 +508,22 @@ namespace xmodel
|
|||||||
tree->scale = Eigen::Vector3f(std::numeric_limits<uint16_t>::max(), std::numeric_limits<uint16_t>::max(), std::numeric_limits<uint16_t>::max())
|
tree->scale = Eigen::Vector3f(std::numeric_limits<uint16_t>::max(), std::numeric_limits<uint16_t>::max(), std::numeric_limits<uint16_t>::max())
|
||||||
.cwiseQuotient(globalDelta);
|
.cwiseQuotient(globalDelta);
|
||||||
|
|
||||||
AabbTreeBuilder aabbTreeBuilder;
|
std::vector<GenericAabbTree> nodes;
|
||||||
GenericAabbTreeOptions options{};
|
AabbTreeBuilder aabbTreeBuilder(nodes, tree->leafs, leafBounds);
|
||||||
options.maintainValidBounds = 1;
|
aabbTreeBuilder.BuildAabbTree();
|
||||||
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<int>(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;
|
|
||||||
|
|
||||||
|
const auto nodeCount = nodes.size();
|
||||||
tree->nodes.resize(nodeCount);
|
tree->nodes.resize(nodeCount);
|
||||||
for (auto nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex)
|
for (size_t nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex)
|
||||||
{
|
{
|
||||||
auto& outNode = tree->nodes[nodeIndex];
|
auto& outNode = tree->nodes[nodeIndex];
|
||||||
const auto& builtNode = options.treeNodePool[nodeIndex];
|
const auto& builtNode = nodes[nodeIndex];
|
||||||
|
|
||||||
const auto leafEnd = builtNode.itemCount + builtNode.firstItem;
|
const auto leafEnd = builtNode.itemCount + builtNode.firstItem;
|
||||||
Bounds nodeBounds;
|
Bounds nodeBounds;
|
||||||
|
|
||||||
for (auto leafIndex = builtNode.firstItem; leafIndex < leafEnd; ++leafIndex)
|
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<uint16_t>(std::clamp<float>(
|
outNode.aabb.mins[0] = static_cast<uint16_t>(std::clamp<float>(
|
||||||
(nodeBounds.m_mins.x() + tree->trans[0]) * tree->scale[0] - 0.5f, std::numeric_limits<uint16_t>::min(), std::numeric_limits<uint16_t>::max()));
|
(nodeBounds.m_mins.x() + tree->trans[0]) * tree->scale[0] - 0.5f, std::numeric_limits<uint16_t>::min(), std::numeric_limits<uint16_t>::max()));
|
||||||
@@ -692,28 +541,25 @@ namespace xmodel
|
|||||||
|
|
||||||
if (builtNode.childCount)
|
if (builtNode.childCount)
|
||||||
{
|
{
|
||||||
outNode.childBeginIndex = builtNode.firstChild;
|
assert(builtNode.firstChild <= std::numeric_limits<decltype(outNode.childBeginIndex)>::max());
|
||||||
assert(outNode.childBeginIndex == builtNode.firstChild);
|
outNode.childBeginIndex = static_cast<decltype(outNode.childBeginIndex)>(builtNode.firstChild);
|
||||||
|
|
||||||
outNode.childCount = builtNode.childCount;
|
assert(builtNode.childCount <= std::numeric_limits<decltype(outNode.childCount)>::max());
|
||||||
assert(outNode.childCount == builtNode.childCount);
|
outNode.childCount = static_cast<decltype(outNode.childCount)>(builtNode.childCount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(builtNode.itemCount);
|
assert(builtNode.itemCount);
|
||||||
|
|
||||||
outNode.childBeginIndex = builtNode.firstItem;
|
assert(builtNode.firstItem <= std::numeric_limits<decltype(outNode.childBeginIndex)>::max());
|
||||||
assert(outNode.childBeginIndex == builtNode.firstItem);
|
outNode.childBeginIndex = static_cast<decltype(outNode.childBeginIndex)>(builtNode.firstItem);
|
||||||
|
|
||||||
outNode.childCount = builtNode.itemCount;
|
assert(builtNode.itemCount <= std::numeric_limits<decltype(outNode.childCount)>::max());
|
||||||
assert(outNode.childCount == builtNode.itemCount);
|
outNode.childCount = static_cast<decltype(outNode.childCount)>(builtNode.itemCount);
|
||||||
|
|
||||||
outNode.childrenAreLeafs = true;
|
outNode.childrenAreLeafs = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(options.mins);
|
|
||||||
free(options.maxs);
|
|
||||||
free(options.treeNodePool);
|
|
||||||
|
|
||||||
return std::move(tree);
|
return std::move(tree);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -576,7 +576,7 @@ namespace
|
|||||||
node.childCount |= XSURFACE_COLLISION_NODE_HAS_LEAFS;
|
node.childCount |= XSURFACE_COLLISION_NODE_HAS_LEAFS;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree->leafCount = commonTree.leafs.size();
|
tree->leafCount = static_cast<decltype(tree->leafCount)>(commonTree.leafs.size());
|
||||||
tree->leafs = m_memory.Alloc<XSurfaceCollisionLeaf>(tree->leafCount);
|
tree->leafs = m_memory.Alloc<XSurfaceCollisionLeaf>(tree->leafCount);
|
||||||
for (auto leafIndex = 0u; leafIndex < tree->leafCount; leafIndex++)
|
for (auto leafIndex = 0u; leafIndex < tree->leafCount; leafIndex++)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user