Skip to content

Commit

Permalink
Changed bmin/bmax from int[] to RcVec3i for improved memory efficiency
Browse files Browse the repository at this point in the history
  • Loading branch information
ikpil committed Oct 13, 2024
1 parent ecc02f1 commit ea437ef
Show file tree
Hide file tree
Showing 16 changed files with 132 additions and 141 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Changed new RcVec3f[3] to stackalloc RcVec3f[3] in DtNavMesh.GetPolyHeight() to reduce heap allocation
- Changed memory handling to use stackalloc in DtNavMeshQuery.GetPolyWallSegments for reducing SOH
- Changed DtNavMeshQuery.GetPolyWallSegments() to use Span<T> for enhanced performance, memory efficiency.
- Changed bmin/bmax from int[] to RcVec3i for improved memory efficiency

### Removed
- Nothing
Expand Down
9 changes: 9 additions & 0 deletions src/DotRecast.Core/Numerics/RcVec3i.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace DotRecast.Core.Numerics
{
public struct RcVec3i
{
public int X;
public int Y;
public int Z;
}
}
12 changes: 6 additions & 6 deletions src/DotRecast.Detour.Extras/BVTreeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ private static int CreateBVTree(DtMeshData data, DtBVNode[] nodes, float quantFa
bmax = RcVec3f.Max(bmax, RcVec.Create(data.verts, data.polys[i].verts[j] * 3));
}

it.bmin[0] = Math.Clamp((int)((bmin.X - data.header.bmin.X) * quantFactor), 0, 0x7fffffff);
it.bmin[1] = Math.Clamp((int)((bmin.Y - data.header.bmin.Y) * quantFactor), 0, 0x7fffffff);
it.bmin[2] = Math.Clamp((int)((bmin.Z - data.header.bmin.Z) * quantFactor), 0, 0x7fffffff);
it.bmax[0] = Math.Clamp((int)((bmax.X - data.header.bmin.X) * quantFactor), 0, 0x7fffffff);
it.bmax[1] = Math.Clamp((int)((bmax.Y - data.header.bmin.Y) * quantFactor), 0, 0x7fffffff);
it.bmax[2] = Math.Clamp((int)((bmax.Z - data.header.bmin.Z) * quantFactor), 0, 0x7fffffff);
it.bmin.X = Math.Clamp((int)((bmin.X - data.header.bmin.X) * quantFactor), 0, 0x7fffffff);
it.bmin.Y = Math.Clamp((int)((bmin.Y - data.header.bmin.Y) * quantFactor), 0, 0x7fffffff);
it.bmin.Z = Math.Clamp((int)((bmin.Z - data.header.bmin.Z) * quantFactor), 0, 0x7fffffff);
it.bmax.X = Math.Clamp((int)((bmax.X - data.header.bmin.X) * quantFactor), 0, 0x7fffffff);
it.bmax.Y = Math.Clamp((int)((bmax.Y - data.header.bmin.Y) * quantFactor), 0, 0x7fffffff);
it.bmax.Z = Math.Clamp((int)((bmax.Z - data.header.bmin.Z) * quantFactor), 0, 0x7fffffff);
}

return DtNavMeshBuilder.Subdivide(items, data.header.polyCount, 0, data.header.polyCount, 0, nodes);
Expand Down
6 changes: 4 additions & 2 deletions src/DotRecast.Detour/BVItem.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using DotRecast.Core.Numerics;

namespace DotRecast.Detour
{
public class BVItem
{
public readonly int[] bmin = new int[3];
public readonly int[] bmax = new int[3];
public RcVec3i bmin;
public RcVec3i bmax;
public int i;
};
}
2 changes: 1 addition & 1 deletion src/DotRecast.Detour/BVItemXComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private BVItemXComparer()

public int Compare(BVItem a, BVItem b)
{
return a.bmin[0].CompareTo(b.bmin[0]);
return a.bmin.X.CompareTo(b.bmin.X);
}
}
}
2 changes: 1 addition & 1 deletion src/DotRecast.Detour/BVItemYComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private BVItemYComparer()

public int Compare(BVItem a, BVItem b)
{
return a.bmin[1].CompareTo(b.bmin[1]);
return a.bmin.Y.CompareTo(b.bmin.Y);
}
}
}
2 changes: 1 addition & 1 deletion src/DotRecast.Detour/BVItemZComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private BVItemZComparer()

public int Compare(BVItem a, BVItem b)
{
return a.bmin[2].CompareTo(b.bmin[2]);
return a.bmin.Z.CompareTo(b.bmin.Z);
}
}
}
6 changes: 4 additions & 2 deletions src/DotRecast.Detour/DtBVNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/

using DotRecast.Core.Numerics;

namespace DotRecast.Detour
{
/// Bounding volume node.
/// @note This structure is rarely if ever used by the end user.
/// @see dtMeshTile
public class DtBVNode
{
public int[] bmin = new int[3]; //< Minimum bounds of the node's AABB. [(x, y, z)]
public int[] bmax = new int[3]; //< Maximum bounds of the node's AABB. [(x, y, z)]
public RcVec3i bmin; //< Minimum bounds of the node's AABB. [(x, y, z)]
public RcVec3i bmax; //< Maximum bounds of the node's AABB. [(x, y, z)]
public int i; //< The node's index. (Negative for escape sequence.)
}
}
18 changes: 9 additions & 9 deletions src/DotRecast.Detour/DtNavMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,8 @@ List<long> QueryPolygonsInTile(DtMeshTile tile, RcVec3f qmin, RcVec3f qmax)
var tbmax = tile.data.header.bmax;
float qfac = tile.data.header.bvQuantFactor;
// Calculate quantized box
Span<int> bmin = stackalloc int[3];
Span<int> bmax = stackalloc int[3];
RcVec3i bmin;
RcVec3i bmax;
// dtClamp query box to world box.
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
Expand All @@ -269,20 +269,20 @@ List<long> QueryPolygonsInTile(DtMeshTile tile, RcVec3f qmin, RcVec3f qmax)
float maxy = Math.Clamp(qmax.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
float maxz = Math.Clamp(qmax.Z, tbmin.Z, tbmax.Z) - tbmin.Z;
// Quantize
bmin[0] = (int)(qfac * minx) & 0x7ffffffe;
bmin[1] = (int)(qfac * miny) & 0x7ffffffe;
bmin[2] = (int)(qfac * minz) & 0x7ffffffe;
bmax[0] = (int)(qfac * maxx + 1) | 1;
bmax[1] = (int)(qfac * maxy + 1) | 1;
bmax[2] = (int)(qfac * maxz + 1) | 1;
bmin.X = (int)(qfac * minx) & 0x7ffffffe;
bmin.Y = (int)(qfac * miny) & 0x7ffffffe;
bmin.Z = (int)(qfac * minz) & 0x7ffffffe;
bmax.X = (int)(qfac * maxx + 1) | 1;
bmax.Y = (int)(qfac * maxy + 1) | 1;
bmax.Z = (int)(qfac * maxz + 1) | 1;

// Traverse tree
long @base = GetPolyRefBase(tile);
int end = tile.data.header.bvNodeCount;
while (nodeIndex < end)
{
DtBVNode node = tile.data.bvTree[nodeIndex];
bool overlap = DtUtils.OverlapQuantBounds(bmin, bmax, node.bmin, node.bmax);
bool overlap = DtUtils.OverlapQuantBounds(ref bmin, ref bmax, ref node.bmin, ref node.bmax);
bool isLeafNode = node.i >= 0;

if (isLeafNode && overlap)
Expand Down
108 changes: 46 additions & 62 deletions src/DotRecast.Detour/DtNavMeshBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,37 +31,28 @@ public static class DtNavMeshBuilder
const int MESH_NULL_IDX = 0xffff;


private static int[][] CalcExtends(BVItem[] items, int nitems, int imin, int imax)
private static void CalcExtends(BVItem[] items, int nitems, int imin, int imax, ref RcVec3i bmin, ref RcVec3i bmax)
{
int[] bmin = new int[3];
int[] bmax = new int[3];
bmin[0] = items[imin].bmin[0];
bmin[1] = items[imin].bmin[1];
bmin[2] = items[imin].bmin[2];

bmax[0] = items[imin].bmax[0];
bmax[1] = items[imin].bmax[1];
bmax[2] = items[imin].bmax[2];
bmin = items[imin].bmin;
bmax = items[imin].bmax;

for (int i = imin + 1; i < imax; ++i)
{
BVItem it = items[i];
if (it.bmin[0] < bmin[0])
bmin[0] = it.bmin[0];
if (it.bmin[1] < bmin[1])
bmin[1] = it.bmin[1];
if (it.bmin[2] < bmin[2])
bmin[2] = it.bmin[2];

if (it.bmax[0] > bmax[0])
bmax[0] = it.bmax[0];
if (it.bmax[1] > bmax[1])
bmax[1] = it.bmax[1];
if (it.bmax[2] > bmax[2])
bmax[2] = it.bmax[2];
if (it.bmin.X < bmin.X)
bmin.X = it.bmin.X;
if (it.bmin.Y < bmin.Y)
bmin.Y = it.bmin.Y;
if (it.bmin.Z < bmin.Z)
bmin.Z = it.bmin.Z;

if (it.bmax.X > bmax.X)
bmax.X = it.bmax.X;
if (it.bmax.Y > bmax.Y)
bmax.Y = it.bmax.Y;
if (it.bmax.Z > bmax.Z)
bmax.Z = it.bmax.Z;
}

return new int[][] { bmin, bmax };
}

private static int LongestAxis(int x, int y, int z)
Expand Down Expand Up @@ -94,27 +85,20 @@ public static int Subdivide(BVItem[] items, int nitems, int imin, int imax, int
if (inum == 1)
{
// Leaf
node.bmin[0] = items[imin].bmin[0];
node.bmin[1] = items[imin].bmin[1];
node.bmin[2] = items[imin].bmin[2];

node.bmax[0] = items[imin].bmax[0];
node.bmax[1] = items[imin].bmax[1];
node.bmax[2] = items[imin].bmax[2];
node.bmin = items[imin].bmin;
node.bmax = items[imin].bmax;

node.i = items[imin].i;
}
else
{
// Split
int[][] minmax = CalcExtends(items, nitems, imin, imax);
node.bmin = minmax[0];
node.bmax = minmax[1];
CalcExtends(items, nitems, imin, imax, ref node.bmin, ref node.bmax);

int axis = LongestAxis(
node.bmax[0] - node.bmin[0],
node.bmax[1] - node.bmin[1],
node.bmax[2] - node.bmin[2]
node.bmax.X - node.bmin.X,
node.bmax.Y - node.bmin.Y,
node.bmax.Z - node.bmin.Z
);

if (axis == 0)
Expand Down Expand Up @@ -173,20 +157,20 @@ private static int CreateBVTree(DtNavMeshCreateParams option, DtBVNode[] nodes)
}

// BV-tree uses cs for all dimensions
it.bmin[0] = Math.Clamp((int)((bmin.X - option.bmin.X) * quantFactor), 0, int.MaxValue);
it.bmin[1] = Math.Clamp((int)((bmin.Y - option.bmin.Y) * quantFactor), 0, int.MaxValue);
it.bmin[2] = Math.Clamp((int)((bmin.Z - option.bmin.Z) * quantFactor), 0, int.MaxValue);
it.bmin.X = Math.Clamp((int)((bmin.X - option.bmin.X) * quantFactor), 0, int.MaxValue);
it.bmin.Y = Math.Clamp((int)((bmin.Y - option.bmin.Y) * quantFactor), 0, int.MaxValue);
it.bmin.Z = Math.Clamp((int)((bmin.Z - option.bmin.Z) * quantFactor), 0, int.MaxValue);

it.bmax[0] = Math.Clamp((int)((bmax.X - option.bmin.X) * quantFactor), 0, int.MaxValue);
it.bmax[1] = Math.Clamp((int)((bmax.Y - option.bmin.Y) * quantFactor), 0, int.MaxValue);
it.bmax[2] = Math.Clamp((int)((bmax.Z - option.bmin.Z) * quantFactor), 0, int.MaxValue);
it.bmax.X = Math.Clamp((int)((bmax.X - option.bmin.X) * quantFactor), 0, int.MaxValue);
it.bmax.Y = Math.Clamp((int)((bmax.Y - option.bmin.Y) * quantFactor), 0, int.MaxValue);
it.bmax.Z = Math.Clamp((int)((bmax.Z - option.bmin.Z) * quantFactor), 0, int.MaxValue);
}
else
{
int p = i * option.nvp * 2;
it.bmin[0] = it.bmax[0] = option.verts[option.polys[p] * 3 + 0];
it.bmin[1] = it.bmax[1] = option.verts[option.polys[p] * 3 + 1];
it.bmin[2] = it.bmax[2] = option.verts[option.polys[p] * 3 + 2];
it.bmin.X = it.bmax.X = option.verts[option.polys[p] * 3 + 0];
it.bmin.Y = it.bmax.Y = option.verts[option.polys[p] * 3 + 1];
it.bmin.Z = it.bmax.Z = option.verts[option.polys[p] * 3 + 2];

for (int j = 1; j < option.nvp; ++j)
{
Expand All @@ -196,24 +180,24 @@ private static int CreateBVTree(DtNavMeshCreateParams option, DtBVNode[] nodes)
int y = option.verts[option.polys[p + j] * 3 + 1];
int z = option.verts[option.polys[p + j] * 3 + 2];

if (x < it.bmin[0])
it.bmin[0] = x;
if (y < it.bmin[1])
it.bmin[1] = y;
if (z < it.bmin[2])
it.bmin[2] = z;

if (x > it.bmax[0])
it.bmax[0] = x;
if (y > it.bmax[1])
it.bmax[1] = y;
if (z > it.bmax[2])
it.bmax[2] = z;
if (x < it.bmin.X)
it.bmin.X = x;
if (y < it.bmin.Y)
it.bmin.Y = y;
if (z < it.bmin.Z)
it.bmin.Z = z;

if (x > it.bmax.X)
it.bmax.X = x;
if (y > it.bmax.Y)
it.bmax.Y = y;
if (z > it.bmax.Z)
it.bmax.Z = z;
}

// Remap y
it.bmin[1] = (int)MathF.Floor(it.bmin[1] * option.ch * quantFactor);
it.bmax[1] = (int)MathF.Ceiling(it.bmax[1] * option.ch * quantFactor);
it.bmin.Y = (int)MathF.Floor(it.bmin.Y * option.ch * quantFactor);
it.bmax.Y = (int)MathF.Ceiling(it.bmax.Y * option.ch * quantFactor);
}
}

Expand Down
18 changes: 9 additions & 9 deletions src/DotRecast.Detour/DtNavMeshQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -609,8 +609,8 @@ protected void QueryPolygonsInTile(DtMeshTile tile, RcVec3f qmin, RcVec3f qmax,
float qfac = tile.data.header.bvQuantFactor;

// Calculate quantized box
Span<int> bmin = stackalloc int[3];
Span<int> bmax = stackalloc int[3];
RcVec3i bmin;
RcVec3i bmax;
// dtClamp query box to world box.
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
Expand All @@ -619,19 +619,19 @@ protected void QueryPolygonsInTile(DtMeshTile tile, RcVec3f qmin, RcVec3f qmax,
float maxy = Math.Clamp(qmax.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
float maxz = Math.Clamp(qmax.Z, tbmin.Z, tbmax.Z) - tbmin.Z;
// Quantize
bmin[0] = (int)(qfac * minx) & 0x7ffffffe;
bmin[1] = (int)(qfac * miny) & 0x7ffffffe;
bmin[2] = (int)(qfac * minz) & 0x7ffffffe;
bmax[0] = (int)(qfac * maxx + 1) | 1;
bmax[1] = (int)(qfac * maxy + 1) | 1;
bmax[2] = (int)(qfac * maxz + 1) | 1;
bmin.X = (int)(qfac * minx) & 0x7ffffffe;
bmin.Y = (int)(qfac * miny) & 0x7ffffffe;
bmin.Z = (int)(qfac * minz) & 0x7ffffffe;
bmax.X = (int)(qfac * maxx + 1) | 1;
bmax.Y = (int)(qfac * maxy + 1) | 1;
bmax.Z = (int)(qfac * maxz + 1) | 1;

// Traverse tree
long @base = m_nav.GetPolyRefBase(tile);
while (nodeIndex < end)
{
DtBVNode node = tile.data.bvTree[nodeIndex];
bool overlap = DtUtils.OverlapQuantBounds(bmin, bmax, node.bmin, node.bmax);
bool overlap = DtUtils.OverlapQuantBounds(ref bmin, ref bmax, ref node.bmin, ref node.bmax);
bool isLeafNode = node.i >= 0;

if (isLeafNode && overlap)
Expand Down
8 changes: 4 additions & 4 deletions src/DotRecast.Detour/DtUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ public static int Ilog2(int v)
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
/// @return True if the two AABB's overlap.
/// @see dtOverlapBounds
public static bool OverlapQuantBounds(Span<int> amin, Span<int> amax, Span<int> bmin, Span<int> bmax)
public static bool OverlapQuantBounds(ref RcVec3i amin, ref RcVec3i amax, ref RcVec3i bmin, ref RcVec3i bmax)
{
bool overlap = true;
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
overlap = (amin.X > bmax.X || amax.X < bmin.X) ? false : overlap;
overlap = (amin.Y > bmax.Y || amax.Y < bmin.Y) ? false : overlap;
overlap = (amin.Z > bmax.Z || amax.Z < bmin.Z) ? false : overlap;
return overlap;
}

Expand Down
32 changes: 14 additions & 18 deletions src/DotRecast.Detour/Io/DtMeshDataReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,27 +204,23 @@ private DtBVNode[] ReadBVTree(RcByteBuffer buf, DtMeshHeader header)
nodes[i] = new DtBVNode();
if (header.version < DT_NAVMESH_VERSION_RECAST4J_32BIT_BVTREE)
{
for (int j = 0; j < 3; j++)
{
nodes[i].bmin[j] = buf.GetShort() & 0xFFFF;
}

for (int j = 0; j < 3; j++)
{
nodes[i].bmax[j] = buf.GetShort() & 0xFFFF;
}
nodes[i].bmin.X = buf.GetShort() & 0xFFFF;
nodes[i].bmin.Y = buf.GetShort() & 0xFFFF;
nodes[i].bmin.Z = buf.GetShort() & 0xFFFF;

nodes[i].bmax.X = buf.GetShort() & 0xFFFF;
nodes[i].bmax.Y = buf.GetShort() & 0xFFFF;
nodes[i].bmax.Z = buf.GetShort() & 0xFFFF;
}
else
{
for (int j = 0; j < 3; j++)
{
nodes[i].bmin[j] = buf.GetInt();
}

for (int j = 0; j < 3; j++)
{
nodes[i].bmax[j] = buf.GetInt();
}
nodes[i].bmin.X = buf.GetInt();
nodes[i].bmin.Y = buf.GetInt();
nodes[i].bmin.Z = buf.GetInt();

nodes[i].bmax.X = buf.GetInt();
nodes[i].bmax.Y = buf.GetInt();
nodes[i].bmax.Z = buf.GetInt();
}

nodes[i].i = buf.GetInt();
Expand Down
Loading

0 comments on commit ea437ef

Please sign in to comment.