Core/Vmaps: Minor cleanup (formatting) and documentation updates for BIH::build copy vs move choice

This commit is contained in:
Shauren
2024-12-11 19:44:03 +01:00
parent d27abec9e8
commit 62dbb0619b
9 changed files with 90 additions and 82 deletions

View File

@@ -17,27 +17,19 @@
#include "BoundingIntervalHierarchy.h"
#ifdef _MSC_VER
#define isnan _isnan
#else
#define isnan std::isnan
#endif
void BIH::buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats)
void BIH::buildHierarchy(std::vector<uint32>& tempTree, buildData& dat, BuildStats& stats) const
{
// create space for the first node
tempTree.push_back(uint32(3 << 30)); // dummy leaf
tempTree.insert(tempTree.end(), 2, 0);
//tempTree.add(0);
tempTree = { 3u << 30u, 0u, 0u }; // dummy leaf
// seed bbox
AABound gridBox = { bounds.low(), bounds.high() };
AABound gridBox{ .lo = bounds.low(), .hi = bounds.high() };
AABound nodeBox = gridBox;
// seed subdivide function
subdivide(0, dat.numPrims - 1, tempTree, dat, gridBox, nodeBox, 0, 1, stats);
}
void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats)
void BIH::subdivide(int left, int right, std::vector<uint32>& tempTree, buildData& dat, AABound& gridBox, AABound& nodeBox, int nodeIndex, int depth, BuildStats& stats)
{
if ((right - left + 1) <= dat.maxPrims || depth >= MAX_STACK_SIZE)
{
@@ -56,7 +48,7 @@ void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildDat
prevAxis = axis;
prevSplit = split;
// perform quick consistency checks
G3D::Vector3 d( gridBox.hi - gridBox.lo );
G3D::Vector3 d(gridBox.hi - gridBox.lo);
if (d.x < 0 || d.y < 0 || d.z < 0)
throw std::logic_error("negative node extents");
for (int i = 0; i < 3; i++)
@@ -132,13 +124,15 @@ void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildDat
if (right == rightOrig)
{
// all left
if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) {
if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split))
{
// we are stuck here - create a leaf
stats.updateLeaf(depth, right - left + 1);
createNode(tempTree, nodeIndex, left, right);
return;
}
if (clipL <= split) {
if (clipL <= split)
{
// keep looping on left half
gridBox.hi[axis] = split;
prevClip = clipL;
@@ -152,13 +146,15 @@ void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildDat
{
// all right
right = rightOrig;
if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split)) {
if (prevAxis == axis && G3D::fuzzyEq(prevSplit, split))
{
// we are stuck here - create a leaf
stats.updateLeaf(depth, right - left + 1);
createNode(tempTree, nodeIndex, left, right);
return;
}
if (clipR >= split) {
if (clipR >= split)
{
// keep looping on right half
gridBox.lo[axis] = split;
prevClip = clipR;
@@ -171,7 +167,7 @@ void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildDat
else
{
// we are actually splitting stuff
if (prevAxis != -1 && !isnan(prevClip))
if (prevAxis != -1 && !std::isnan(prevClip))
{
// second time through - lets create the previous split
// since it produced empty space
@@ -180,14 +176,17 @@ void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildDat
tempTree.push_back(0);
tempTree.push_back(0);
tempTree.push_back(0);
if (wasLeft) {
if (wasLeft)
{
// create a node with a left child
// write leaf node
stats.updateInner();
tempTree[nodeIndex + 0] = (prevAxis << 30) | nextIndex;
tempTree[nodeIndex + 1] = advstd::bit_cast<uint32>(prevClip);
tempTree[nodeIndex + 2] = advstd::bit_cast<uint32>(G3D::finf());
} else {
}
else
{
// create a node with a right child
// write leaf node
stats.updateInner();
@@ -209,14 +208,17 @@ void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildDat
// allocate left node
int nl = right - left + 1;
int nr = rightOrig - (right + 1) + 1;
if (nl > 0) {
if (nl > 0)
{
tempTree.push_back(0);
tempTree.push_back(0);
tempTree.push_back(0);
} else
}
else
nextIndex -= 3;
// allocate right node
if (nr > 0) {
if (nr > 0)
{
tempTree.push_back(0);
tempTree.push_back(0);
tempTree.push_back(0);
@@ -246,14 +248,14 @@ void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildDat
bool BIH::writeToFile(FILE* wf) const
{
uint32 treeSize = tree.size();
uint32 check=0, count;
uint32 check = 0, count;
check += fwrite(&bounds.low(), sizeof(float), 3, wf);
check += fwrite(&bounds.high(), sizeof(float), 3, wf);
check += fwrite(&treeSize, sizeof(uint32), 1, wf);
check += fwrite(&tree[0], sizeof(uint32), treeSize, wf);
check += fwrite(tree.data(), sizeof(uint32), treeSize, wf);
count = objects.size();
check += fwrite(&count, sizeof(uint32), 1, wf);
check += fwrite(&objects[0], sizeof(uint32), count, wf);
check += fwrite(objects.data(), sizeof(uint32), count, wf);
return check == (3 + 3 + 2 + treeSize + count);
}
@@ -261,16 +263,16 @@ bool BIH::readFromFile(FILE* rf)
{
uint32 treeSize;
G3D::Vector3 lo, hi;
uint32 check=0, count=0;
uint32 check = 0, count = 0;
check += fread(&lo, sizeof(float), 3, rf);
check += fread(&hi, sizeof(float), 3, rf);
bounds = G3D::AABox(lo, hi);
check += fread(&treeSize, sizeof(uint32), 1, rf);
tree.resize(treeSize);
check += fread(&tree[0], sizeof(uint32), treeSize, rf);
check += fread(tree.data(), sizeof(uint32), treeSize, rf);
check += fread(&count, sizeof(uint32), 1, rf);
objects.resize(count); // = new uint32[nObjects];
check += fread(&objects[0], sizeof(uint32), count, rf);
check += fread(objects.data(), sizeof(uint32), count, rf);
return uint64(check) == uint64(3 + 3 + 1 + 1 + uint64(treeSize) + uint64(count));
}
@@ -287,17 +289,17 @@ void BIH::BuildStats::updateLeaf(int depth, int n)
++numLeavesN[nl];
}
void BIH::BuildStats::printStats()
void BIH::BuildStats::printStats() const
{
printf("Tree stats:\n");
printf(" * Nodes: %d\n", numNodes);
printf(" * Leaves: %d\n", numLeaves);
printf(" * Objects: min %d\n", minObjects);
printf(" avg %.2f\n", (float) sumObjects / numLeaves);
printf(" avg(n>0) %.2f\n", (float) sumObjects / (numLeaves - numLeavesN[0]));
printf(" avg %.2f\n", (float)sumObjects / numLeaves);
printf(" avg(n>0) %.2f\n", (float)sumObjects / (numLeaves - numLeavesN[0]));
printf(" max %d\n", maxObjects);
printf(" * Depth: min %d\n", minDepth);
printf(" avg %.2f\n", (float) sumDepth / numLeaves);
printf(" avg %.2f\n", (float)sumDepth / numLeaves);
printf(" max %d\n", maxDepth);
printf(" * Leaves w/: N=0 %3d%%\n", 100 * numLeavesN[0] / numLeaves);
printf(" N=1 %3d%%\n", 100 * numLeavesN[1] / numLeaves);

View File

@@ -15,8 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _BIH_H
#define _BIH_H
#ifndef TRINITYCORE_BOUNDING_INTERVAL_HIERARCHY_H
#define TRINITYCORE_BOUNDING_INTERVAL_HIERARCHY_H
#include "Define.h"
#include "advstd.h"
@@ -51,13 +51,12 @@ class TC_COMMON_API BIH
objects.clear();
bounds = G3D::AABox::empty();
// create space for the first node
tree.push_back(3u << 30u); // dummy leaf
tree.insert(tree.end(), 2, 0);
tree = { 3u << 30u, 0u, 0u }; // dummy leaf
}
public:
BIH() { init_empty(); }
template <class BoundsFunc, class PrimArray>
void build(PrimArray const& primitives, BoundsFunc& getBounds, uint32 leafSize = 3, bool printStats = false)
void build(PrimArray const& primitives, BoundsFunc const& getBounds, uint32 leafSize = 3, bool printStats = false)
{
if (primitives.size() == 0)
{
@@ -69,9 +68,10 @@ class TC_COMMON_API BIH
dat.maxPrims = leafSize;
dat.numPrims = uint32(primitives.size());
dat.indices = new uint32[dat.numPrims];
dat.primBound = new G3D::AABox[dat.numPrims];
dat.primBound = static_cast<G3D::AABox*>(::operator new[](dat.numPrims * sizeof(G3D::AABox)));
std::uninitialized_fill_n(dat.primBound, dat.numPrims, G3D::AABox::empty());
getBounds(primitives[0], bounds);
for (uint32 i=0; i<dat.numPrims; ++i)
for (uint32 i = 0; i < dat.numPrims; ++i)
{
dat.indices[i] = i;
getBounds(primitives[i], dat.primBound[i]);
@@ -84,10 +84,8 @@ class TC_COMMON_API BIH
stats.printStats();
objects.resize(dat.numPrims);
for (uint32 i=0; i<dat.numPrims; ++i)
objects[i] = dat.indices[i];
//nObjects = dat.numPrims;
tree = tempTree;
std::ranges::copy_n(dat.indices, dat.numPrims, objects.begin());
tree = tempTree; // copy instead of move to allocate exactly tempTree.size() elements and avoid shrink_to_fit
delete[] dat.primBound;
delete[] dat.indices;
}
@@ -95,18 +93,18 @@ class TC_COMMON_API BIH
G3D::AABox const& bound() const { return bounds; }
template<typename RayCallback>
void intersectRay(const G3D::Ray &r, RayCallback& intersectCallback, float &maxDist, bool stopAtFirst = false) const
void intersectRay(G3D::Ray const& r, RayCallback& intersectCallback, float& maxDist, bool stopAtFirst = false) const
{
float intervalMin = -1.f;
float intervalMax = -1.f;
G3D::Vector3 const& org = r.origin();
G3D::Vector3 const& dir = r.direction();
G3D::Vector3 const& invDir = r.invDirection();
for (int i=0; i<3; ++i)
for (int i = 0; i < 3; ++i)
{
if (G3D::fuzzyNe(dir[i], 0.0f))
{
float t1 = (bounds.low()[i] - org[i]) * invDir[i];
float t1 = (bounds.low()[i] - org[i]) * invDir[i];
float t2 = (bounds.high()[i] - org[i]) * invDir[i];
if (t1 > t2)
std::swap(t1, t2);
@@ -132,7 +130,7 @@ class TC_COMMON_API BIH
uint32 offsetBack3[3];
// compute custom offsets from direction sign bit
for (int i=0; i<3; ++i)
for (int i = 0; i < 3; ++i)
{
offsetFront[i] = advstd::bit_cast<uint32>(dir[i]) >> 31;
offsetBack[i] = offsetFront[i] ^ 1;
@@ -148,7 +146,8 @@ class TC_COMMON_API BIH
int stackPos = 0;
int node = 0;
while (true) {
while (true)
{
while (true)
{
uint32 tn = tree[node];
@@ -168,13 +167,15 @@ class TC_COMMON_API BIH
int back = offset + offsetBack3[axis];
node = back;
// ray passes through far node only
if (tf < intervalMin) {
if (tf < intervalMin)
{
intervalMin = (tb >= intervalMin) ? tb : intervalMin;
continue;
}
node = offset + offsetFront3[axis]; // front
// ray passes through near node only
if (tb > intervalMax) {
if (tb > intervalMax)
{
intervalMax = (tf <= intervalMax) ? tf : intervalMax;
continue;
}
@@ -192,7 +193,8 @@ class TC_COMMON_API BIH
{
// leaf - test some objects
int n = tree[node + 1];
while (n > 0) {
while (n > 0)
{
bool hit = intersectCallback(r, objects[offset], maxDist, stopAtFirst);
if (stopAtFirst && hit) return;
--n;
@@ -203,7 +205,7 @@ class TC_COMMON_API BIH
}
else
{
if (axis>2)
if (axis > 2)
return; // should not happen
float tf = (advstd::bit_cast<float>(tree[node + offsetFront[axis]]) - org[axis]) * invDir[axis];
float tb = (advstd::bit_cast<float>(tree[node + offsetBack[axis]]) - org[axis]) * invDir[axis];
@@ -233,7 +235,7 @@ class TC_COMMON_API BIH
}
template<typename IsectCallback>
void intersectPoint(const G3D::Vector3 &p, IsectCallback& intersectCallback) const
void intersectPoint(G3D::Vector3 const& p, IsectCallback& intersectCallback) const
{
if (!bounds.contains(p))
return;
@@ -242,7 +244,8 @@ class TC_COMMON_API BIH
int stackPos = 0;
int node = 0;
while (true) {
while (true)
{
while (true)
{
uint32 tn = tree[node];
@@ -262,12 +265,14 @@ class TC_COMMON_API BIH
int right = offset + 3;
node = right;
// point is in right node only
if (tl < p[axis]) {
if (tl < p[axis])
{
continue;
}
node = offset; // left
// point is in left node only
if (tr > p[axis]) {
if (tr > p[axis])
{
continue;
}
// point is in both nodes
@@ -280,7 +285,8 @@ class TC_COMMON_API BIH
{
// leaf - test some objects
int n = tree[node + 1];
while (n > 0) {
while (n > 0)
{
intersectCallback(p, objects[offset]); // !!!
--n;
++offset;
@@ -290,7 +296,7 @@ class TC_COMMON_API BIH
}
else // BVH2 node (empty space cut off left and right)
{
if (axis>2)
if (axis > 2)
return; // should not happen
float tl = advstd::bit_cast<float>(tree[node + 1]);
float tr = advstd::bit_cast<float>(tree[node + 2]);
@@ -320,8 +326,8 @@ class TC_COMMON_API BIH
struct buildData
{
uint32 *indices;
G3D::AABox *primBound;
uint32* indices;
G3D::AABox* primBound;
uint32 numPrims;
int maxPrims;
};
@@ -347,30 +353,30 @@ class TC_COMMON_API BIH
int numBVH2;
public:
BuildStats():
BuildStats() :
numNodes(0), numLeaves(0), sumObjects(0), minObjects(0x0FFFFFFF),
maxObjects(0xFFFFFFFF), sumDepth(0), minDepth(0x0FFFFFFF),
maxDepth(0xFFFFFFFF), numBVH2(0)
{
for (int i=0; i<6; ++i) numLeavesN[i] = 0;
for (int i = 0; i < 6; ++i) numLeavesN[i] = 0;
}
void updateInner() { numNodes++; }
void updateBVH2() { numBVH2++; }
void updateLeaf(int depth, int n);
void printStats();
void printStats() const;
};
void buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats);
void buildHierarchy(std::vector<uint32>& tempTree, buildData& dat, BuildStats& stats) const;
void createNode(std::vector<uint32> &tempTree, int nodeIndex, uint32 left, uint32 right) const
static void createNode(std::vector<uint32>& tempTree, int nodeIndex, uint32 left, uint32 right)
{
// write leaf node
tempTree[nodeIndex + 0] = (3 << 30) | left;
tempTree[nodeIndex + 1] = right - left + 1;
}
void subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats);
static void subdivide(int left, int right, std::vector<uint32>& tempTree, buildData& dat, AABound& gridBox, AABound& nodeBox, int nodeIndex, int depth, BuildStats& stats);
};
#endif // _BIH_H
#endif // TRINITYCORE_BOUNDING_INTERVAL_HIERARCHY_H

View File

@@ -94,7 +94,7 @@ public:
m_objects_to_push.getMembers(m_objects);
//assert that m_obj2Idx has all the keys
m_tree.build(m_objects, BoundsFunc::getBounds2);
m_tree.build(m_objects, BoundsFunc());
}
template<typename RayCallback>

View File

@@ -29,8 +29,6 @@
#include <G3D/Ray.h>
#include <G3D/Vector3.h>
using VMAP::ModelInstance;
namespace {
int CHECK_TREE_PERIOD = 200;
@@ -47,7 +45,7 @@ template<> struct PositionTrait< GameObjectModel> {
template<> struct BoundsTrait< GameObjectModel> {
static void getBounds(GameObjectModel const& g, G3D::AABox& out) { out = g.getBounds();}
static void getBounds2(GameObjectModel const* g, G3D::AABox& out) { out = g->getBounds();}
void operator()(GameObjectModel const* g, G3D::AABox& out) const { getBounds(*g, out); }
};
/*

View File

@@ -122,7 +122,7 @@ bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> model
iInvRot = iRotation.inverse();
// transform bounding box:
mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale);
AABox rotated_bounds;
AABox rotated_bounds = G3D::AABox::empty();
for (int i = 0; i < 8; ++i)
rotated_bounds.merge(iRotation * mdl_box.corner(i));
@@ -252,7 +252,7 @@ bool GameObjectModel::UpdatePosition()
iInvRot = iRotation.inverse();
// transform bounding box:
mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale);
AABox rotated_bounds;
AABox rotated_bounds = G3D::AABox::empty();
for (int i = 0; i < 8; ++i)
rotated_bounds.merge(iRotation * mdl_box.corner(i));

View File

@@ -26,7 +26,8 @@ using G3D::Vector3;
template<> struct BoundsTrait<VMAP::GroupModel>
{
static void getBounds(const VMAP::GroupModel& obj, G3D::AABox& out) { out = obj.GetBound(); }
static void getBounds(VMAP::GroupModel const& obj, G3D::AABox& out) { out = obj.GetBound(); }
void operator()(VMAP::GroupModel const& obj, G3D::AABox& out) const { getBounds(obj, out); }
};
namespace VMAP
@@ -477,7 +478,7 @@ namespace VMAP
void WorldModel::setGroupModels(std::vector<GroupModel>& models)
{
groupModels.swap(models);
groupTree.build(groupModels, BoundsTrait<GroupModel>::getBounds, 1);
groupTree.build(groupModels, BoundsTrait<GroupModel>(), 1);
}
struct WModelRayCallBack

View File

@@ -80,7 +80,7 @@ namespace VMAP
class TC_COMMON_API GroupModel
{
public:
GroupModel() : iBound(), iMogpFlags(0), iGroupWMOID(0), iLiquid(nullptr) { }
GroupModel() : iBound(G3D::AABox::empty()), iMogpFlags(0), iGroupWMOID(0), iLiquid(nullptr) { }
GroupModel(GroupModel const& other);
GroupModel(uint32 mogpFlags, uint32 groupWMOID, G3D::AABox const& bound):
iBound(bound), iMogpFlags(mogpFlags), iGroupWMOID(groupWMOID), iLiquid(nullptr) { }

View File

@@ -66,7 +66,7 @@ public:
void insert(const T& value)
{
G3D::AABox bounds;
G3D::AABox bounds = G3D::AABox::empty();
BoundsFunc::getBounds(value, bounds);
Cell low = Cell::ComputeCell(bounds.low().x, bounds.low().y);
Cell high = Cell::ComputeCell(bounds.high().x, bounds.high().y);

View File

@@ -32,7 +32,8 @@
template<> struct BoundsTrait<VMAP::ModelSpawn*>
{
static void getBounds(VMAP::ModelSpawn const* const& obj, G3D::AABox& out) { out = obj->getBounds(); }
static void getBounds(VMAP::ModelSpawn const* obj, G3D::AABox& out) { out = obj->getBounds(); }
void operator()(VMAP::ModelSpawn const* obj, G3D::AABox& out) const { getBounds(obj, out); }
};
namespace VMAP
@@ -197,7 +198,7 @@ namespace VMAP
try
{
pTree.build(mapSpawns, BoundsTrait<ModelSpawn*>::getBounds);
pTree.build(mapSpawns, BoundsTrait<ModelSpawn*>());
}
catch (std::exception& e)
{
@@ -348,7 +349,7 @@ namespace VMAP
if (groups != 1)
printf("Warning: '%s' does not seem to be a M2 model!\n", modelFilename.string().c_str());
G3D::AABox rotated_bounds;
G3D::AABox rotated_bounds = G3D::AABox::empty();
for (int i = 0; i < 8; ++i)
rotated_bounds.merge(modelPosition.transform(raw_model.groupsArray[0].bounds.corner(i)));
@@ -440,7 +441,7 @@ namespace VMAP
continue;
spawnedModelFiles.insert(model_name);
G3D::AABox bounds;
G3D::AABox bounds = G3D::AABox::empty();
for (GroupModel_Raw const& groupModel : raw_model.groupsArray)
for (G3D::Vector3 const& vertice : groupModel.vertexArray)
bounds.merge(vertice);