From 20e3afbb0364de2fc307e2efd4739a8048c12f8e Mon Sep 17 00:00:00 2001 From: Graham Pentheny Date: Mon, 5 May 2025 15:34:18 -0400 Subject: [PATCH] Use vectors and methods in ChunkyTriMesh to simplify things --- RecastDemo/Include/ChunkyTriMesh.h | 35 +-- RecastDemo/Source/ChunkyTriMesh.cpp | 250 ++++++++++----------- RecastDemo/Source/InputGeom.cpp | 2 +- RecastDemo/Source/Sample_TempObstacles.cpp | 2 +- RecastDemo/Source/Sample_TileMesh.cpp | 2 +- 5 files changed, 136 insertions(+), 155 deletions(-) diff --git a/RecastDemo/Include/ChunkyTriMesh.h b/RecastDemo/Include/ChunkyTriMesh.h index 8fd19fbd..78a7d745 100644 --- a/RecastDemo/Include/ChunkyTriMesh.h +++ b/RecastDemo/Include/ChunkyTriMesh.h @@ -18,6 +18,8 @@ #pragma once +#include + struct rcChunkyTriMeshNode { float bmin[2]; @@ -28,35 +30,18 @@ struct rcChunkyTriMeshNode struct rcChunkyTriMesh { - rcChunkyTriMesh() = default; - rcChunkyTriMesh(const rcChunkyTriMesh&) = delete; - rcChunkyTriMesh(const rcChunkyTriMesh&&) = delete; - rcChunkyTriMesh& operator=(const rcChunkyTriMesh&) = delete; - rcChunkyTriMesh& operator=(const rcChunkyTriMesh&&) = delete; - ~rcChunkyTriMesh() - { - delete[] nodes; - delete[] tris; - } - - rcChunkyTriMeshNode* nodes = nullptr; + std::vector nodes{}; int nnodes = 0; - int* tris = nullptr; - int ntris = 0; + std::vector tris{}; int maxTrisPerChunk = 0; + + /// Finds the chunk indices that overlap the input rectangle. + int GetChunksOverlappingRect(float bmin[2], float bmax[2], int* ids, int maxIds) const; + + /// Returns the chunk indices which overlap the input segment. + int GetChunksOverlappingSegment(float segmentStart[2], float segmentEnd[2], int* ids, int maxIds) const; }; /// Creates partitioned triangle mesh (AABB tree), /// where each node contains at max trisPerChunk triangles. bool rcCreateChunkyTriMesh(const float* verts, const int* tris, int ntris, int trisPerChunk, rcChunkyTriMesh* triMesh); - -/// Finds the chunk indices that overlap the input rectangle. -int rcGetChunksOverlappingRect(const rcChunkyTriMesh* triMesh, float bmin[2], float bmax[2], int* ids, int maxIds); - -/// Returns the chunk indices which overlap the input segment. -int rcGetChunksOverlappingSegment( - const rcChunkyTriMesh* triMesh, - float segmentStart[2], - float segmentEnd[2], - int* ids, - int maxIds); diff --git a/RecastDemo/Source/ChunkyTriMesh.cpp b/RecastDemo/Source/ChunkyTriMesh.cpp index 781d4399..8bc95a86 100644 --- a/RecastDemo/Source/ChunkyTriMesh.cpp +++ b/RecastDemo/Source/ChunkyTriMesh.cpp @@ -160,128 +160,10 @@ void subdivide( } } -inline bool checkOverlapRect(const float amin[2], const float amax[2], const float bmin[2], const float bmax[2]) +bool checkOverlapRect(const float amin[2], const float amax[2], const float bmin[2], const float bmax[2]) { return amin[0] <= bmax[0] && amax[0] >= bmin[0] && amin[1] <= bmax[1] && amax[1] >= bmin[1]; } -} // namespace - -bool rcCreateChunkyTriMesh(const float* verts, const int* tris, int ntris, int trisPerChunk, rcChunkyTriMesh* triMesh) -{ - int nchunks = (ntris + trisPerChunk - 1) / trisPerChunk; - - triMesh->nodes = new rcChunkyTriMeshNode[nchunks * 4]; - if (!triMesh->nodes) - { - return false; - } - - triMesh->tris = new int[ntris * 3]; - if (!triMesh->tris) - { - return false; - } - - triMesh->ntris = ntris; - - // Build tree - BoundsItem* items = new BoundsItem[ntris]; - if (!items) - { - return false; - } - - for (int i = 0; i < ntris; i++) - { - const int* t = &tris[i * 3]; - BoundsItem& it = items[i]; - it.i = i; - // Calc triangle XZ bounds. - it.bmin[0] = it.bmax[0] = verts[t[0] * 3 + 0]; - it.bmin[1] = it.bmax[1] = verts[t[0] * 3 + 2]; - for (int j = 1; j < 3; ++j) - { - const float* v = &verts[t[j] * 3]; - if (v[0] < it.bmin[0]) - { - it.bmin[0] = v[0]; - } - if (v[2] < it.bmin[1]) - { - it.bmin[1] = v[2]; - } - - if (v[0] > it.bmax[0]) - { - it.bmax[0] = v[0]; - } - if (v[2] > it.bmax[1]) - { - it.bmax[1] = v[2]; - } - } - } - - int curTri = 0; - int curNode = 0; - subdivide(items, ntris, 0, ntris, trisPerChunk, curNode, triMesh->nodes, nchunks * 4, curTri, triMesh->tris, tris); - - delete[] items; - - triMesh->nnodes = curNode; - - // Calc max tris per node. - triMesh->maxTrisPerChunk = 0; - for (int i = 0; i < triMesh->nnodes; ++i) - { - rcChunkyTriMeshNode& node = triMesh->nodes[i]; - const bool isLeaf = node.i >= 0; - if (!isLeaf) - { - continue; - } - if (node.n > triMesh->maxTrisPerChunk) - { - triMesh->maxTrisPerChunk = node.n; - } - } - - return true; -} - -int rcGetChunksOverlappingRect(const rcChunkyTriMesh* triMesh, float bmin[2], float bmax[2], int* ids, const int maxIds) -{ - // Traverse tree - int i = 0; - int n = 0; - while (i < triMesh->nnodes) - { - const rcChunkyTriMeshNode* node = &triMesh->nodes[i]; - const bool overlap = checkOverlapRect(bmin, bmax, node->bmin, node->bmax); - const bool isLeafNode = node->i >= 0; - - if (isLeafNode && overlap) - { - if (n < maxIds) - { - ids[n] = i; - n++; - } - } - - if (overlap || isLeafNode) - { - i++; - } - else - { - const int escapeIndex = -node->i; - i += escapeIndex; - } - } - - return n; -} bool checkOverlapSegment(const float p[2], const float q[2], const float bmin[2], const float bmax[2]) { @@ -330,19 +212,133 @@ bool checkOverlapSegment(const float p[2], const float q[2], const float bmin[2] return true; } -int rcGetChunksOverlappingSegment( - const rcChunkyTriMesh* triMesh, - float segmentStart[2], - float segmentEnd[2], - int* ids, - const int maxIds) +} + +bool rcCreateChunkyTriMesh(const float* verts, const int* tris, int ntris, int trisPerChunk, rcChunkyTriMesh* triMesh) +{ + int nchunks = (ntris + trisPerChunk - 1) / trisPerChunk; + + triMesh->nodes.resize(nchunks * 4); + triMesh->tris.resize(ntris * 3); + + // Build tree + BoundsItem* items = new BoundsItem[ntris]; + if (!items) + { + return false; + } + + for (int i = 0; i < ntris; i++) + { + const int* t = &tris[i * 3]; + BoundsItem& it = items[i]; + it.i = i; + // Calc triangle XZ bounds. + it.bmin[0] = it.bmax[0] = verts[t[0] * 3 + 0]; + it.bmin[1] = it.bmax[1] = verts[t[0] * 3 + 2]; + for (int j = 1; j < 3; ++j) + { + const float* v = &verts[t[j] * 3]; + if (v[0] < it.bmin[0]) + { + it.bmin[0] = v[0]; + } + if (v[2] < it.bmin[1]) + { + it.bmin[1] = v[2]; + } + + if (v[0] > it.bmax[0]) + { + it.bmax[0] = v[0]; + } + if (v[2] > it.bmax[1]) + { + it.bmax[1] = v[2]; + } + } + } + + int curTri = 0; + int curNode = 0; + subdivide( + items, + ntris, + 0, + ntris, + trisPerChunk, + curNode, + triMesh->nodes.data(), + nchunks * 4, + curTri, + triMesh->tris.data(), + tris); + + delete[] items; + + triMesh->nnodes = curNode; + + // Calc max tris per node. + triMesh->maxTrisPerChunk = 0; + for (int i = 0; i < triMesh->nnodes; ++i) + { + rcChunkyTriMeshNode& node = triMesh->nodes[i]; + const bool isLeaf = node.i >= 0; + if (!isLeaf) + { + continue; + } + if (node.n > triMesh->maxTrisPerChunk) + { + triMesh->maxTrisPerChunk = node.n; + } + } + + return true; +} + +int rcChunkyTriMesh::GetChunksOverlappingRect(float bmin[2], float bmax[2], int* ids, const int maxIds) const { // Traverse tree int i = 0; int n = 0; - while (i < triMesh->nnodes) + while (i < this->nnodes) { - const rcChunkyTriMeshNode* node = &triMesh->nodes[i]; + const rcChunkyTriMeshNode* node = &this->nodes[i]; + const bool overlap = checkOverlapRect(bmin, bmax, node->bmin, node->bmax); + const bool isLeafNode = node->i >= 0; + + if (isLeafNode && overlap) + { + if (n < maxIds) + { + ids[n] = i; + n++; + } + } + + if (overlap || isLeafNode) + { + i++; + } + else + { + const int escapeIndex = -node->i; + i += escapeIndex; + } + } + + return n; +} + +int rcChunkyTriMesh::GetChunksOverlappingSegment(float segmentStart[2], float segmentEnd[2], int* ids, const int maxIds) const +{ + // Traverse tree + int i = 0; + int n = 0; + while (i < this->nnodes) + { + const rcChunkyTriMeshNode* node = &this->nodes[i]; const bool overlap = checkOverlapSegment(segmentStart, segmentEnd, node->bmin, node->bmax); const bool isLeafNode = node->i >= 0; diff --git a/RecastDemo/Source/InputGeom.cpp b/RecastDemo/Source/InputGeom.cpp index d066db18..5f8ccb7c 100644 --- a/RecastDemo/Source/InputGeom.cpp +++ b/RecastDemo/Source/InputGeom.cpp @@ -443,7 +443,7 @@ bool InputGeom::raycastMesh(float* src, float* dst, float& tmin) }; int cid[512]; - const int ncid = rcGetChunksOverlappingSegment(m_chunkyMesh, p, q, cid, 512); + const int ncid = m_chunkyMesh->GetChunksOverlappingSegment(p, q, cid, 512); if (!ncid) { return false; } tmin = 1.0f; diff --git a/RecastDemo/Source/Sample_TempObstacles.cpp b/RecastDemo/Source/Sample_TempObstacles.cpp index 1cde6d2e..b9286799 100644 --- a/RecastDemo/Source/Sample_TempObstacles.cpp +++ b/RecastDemo/Source/Sample_TempObstacles.cpp @@ -315,7 +315,7 @@ int Sample_TempObstacles::rasterizeTileLayers(const int tileX, const int tileY, tbmax[0] = tcfg.bmax[0]; tbmax[1] = tcfg.bmax[2]; int cid[512];// TODO: Make grow when returning too many items. - const int ncid = rcGetChunksOverlappingRect(chunkyMesh, tbmin, tbmax, cid, 512); + const int ncid = chunkyMesh->GetChunksOverlappingRect(tbmin, tbmax, cid, 512); if (!ncid) { return 0; // empty diff --git a/RecastDemo/Source/Sample_TileMesh.cpp b/RecastDemo/Source/Sample_TileMesh.cpp index 34ce2bdc..787e5c7b 100644 --- a/RecastDemo/Source/Sample_TileMesh.cpp +++ b/RecastDemo/Source/Sample_TileMesh.cpp @@ -851,7 +851,7 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tileX, const int tileY, tbmax[0] = m_config.bmax[0]; tbmax[1] = m_config.bmax[2]; int overlappingChunkIndexes[512];// TODO: Make grow when returning too many items. - const int numOverlappingChunks = rcGetChunksOverlappingRect(chunkyMesh, tbmin, tbmax, overlappingChunkIndexes, 512); + const int numOverlappingChunks = chunkyMesh->GetChunksOverlappingRect(tbmin, tbmax, overlappingChunkIndexes, 512); if (!numOverlappingChunks) { return 0;