Compare commits

..

No commits in common. "897748285f42a75d0247922f27631e4911648a6b" and "3157c1e7642663bbeb6eb8d2a40cdd5a1181daff" have entirely different histories.

46 changed files with 400 additions and 556 deletions

View File

@ -20,7 +20,6 @@ dotnet_sort_system_directives_first = true
csharp_preserve_single_line_statements = false csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true csharp_preserve_single_line_blocks = true
# ReSharper properties #
resharper_csharp_wrap_lines = false
resharper_csharp_space_before_trailing_comment = true resharper_csharp_space_before_trailing_comment = true
resharper_csharp_space_after_operator_keyword = true resharper_csharp_space_after_operator_keyword = true

View File

@ -3,7 +3,5 @@
public interface IRcRand public interface IRcRand
{ {
float Next(); float Next();
double NextDouble();
int NextInt32();
} }
} }

View File

@ -6,13 +6,9 @@ namespace DotRecast.Core
{ {
private readonly Random _r; private readonly Random _r;
public RcRand() : this(new Random()) public RcRand()
{ {
} _r = new Random();
public RcRand(Random r)
{
_r = r;
} }
public RcRand(long seed) public RcRand(long seed)
@ -25,11 +21,6 @@ namespace DotRecast.Core
return (float)_r.NextDouble(); return (float)_r.NextDouble();
} }
public double NextDouble()
{
return _r.NextDouble();
}
public int NextInt32() public int NextInt32()
{ {
return _r.Next(); return _r.Next();

View File

@ -22,7 +22,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Core.Buffers;
using DotRecast.Core.Collections; using DotRecast.Core.Collections;
using DotRecast.Core.Numerics; using DotRecast.Core.Numerics;

View File

@ -20,7 +20,6 @@ freely, subject to the following restrictions:
using System; using System;
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Core.Buffers;
using DotRecast.Core.Numerics; using DotRecast.Core.Numerics;
@ -403,7 +402,7 @@ namespace DotRecast.Detour.Crowd
debug.Reset(); debug.Reset();
// Build sampling pattern aligned to desired velocity. // Build sampling pattern aligned to desired velocity.
using var pat = RcRentedArray.Rent<float>((DT_MAX_PATTERN_DIVS * DT_MAX_PATTERN_RINGS + 1) * 2); float[] pat = new float[(DT_MAX_PATTERN_DIVS * DT_MAX_PATTERN_RINGS + 1) * 2];
int npat = 0; int npat = 0;
int ndivs = m_params.adaptiveDivs; int ndivs = m_params.adaptiveDivs;

View File

@ -40,7 +40,7 @@ namespace DotRecast.Detour.Dynamic
private readonly BlockingCollection<IDtDaynmicTileJob> updateQueue = new BlockingCollection<IDtDaynmicTileJob>(); private readonly BlockingCollection<IDtDaynmicTileJob> updateQueue = new BlockingCollection<IDtDaynmicTileJob>();
private readonly RcAtomicLong currentColliderId = new RcAtomicLong(0); private readonly RcAtomicLong currentColliderId = new RcAtomicLong(0);
private DtNavMesh _navMesh; private DtNavMesh _navMesh;
private bool _dirty = true; private bool dirty = true;
public DtDynamicNavMesh(DtVoxelFile voxelFile) public DtDynamicNavMesh(DtVoxelFile voxelFile)
{ {
@ -105,6 +105,29 @@ namespace DotRecast.Detour.Dynamic
updateQueue.Add(new DtDynamicTileColliderRemovalJob(colliderId, GetTilesByCollider(colliderId))); updateQueue.Add(new DtDynamicTileColliderRemovalJob(colliderId, GetTilesByCollider(colliderId)));
} }
/**
* Perform full build of the nav mesh
*/
public void Build()
{
ProcessQueue();
Rebuild(_tiles.Values);
}
/**
* Perform incremental update of the nav mesh
*/
public bool Update()
{
return Rebuild(ProcessQueue());
}
private bool Rebuild(ICollection<DtDynamicTile> stream)
{
foreach (var dynamicTile in stream)
Rebuild(dynamicTile);
return UpdateNavMesh();
}
private HashSet<DtDynamicTile> ProcessQueue() private HashSet<DtDynamicTile> ProcessQueue()
{ {
@ -136,49 +159,27 @@ namespace DotRecast.Detour.Dynamic
} }
} }
// Perform full build of the navmesh /**
public void Build() * Perform full build concurrently using the given {@link ExecutorService}
{ */
ProcessQueue(); public Task<bool> Build(TaskFactory executor)
Rebuild(_tiles.Values);
}
// Perform full build concurrently using the given {@link ExecutorService}
public bool Build(TaskFactory executor)
{ {
ProcessQueue(); ProcessQueue();
return Rebuild(_tiles.Values, executor); return Rebuild(_tiles.Values, executor);
} }
/**
// Perform incremental update of the navmesh * Perform incremental update concurrently using the given {@link ExecutorService}
public bool Update() */
{ public Task<bool> Update(TaskFactory executor)
return Rebuild(ProcessQueue());
}
// Perform incremental update concurrently using the given {@link ExecutorService}
public bool Update(TaskFactory executor)
{ {
return Rebuild(ProcessQueue(), executor); return Rebuild(ProcessQueue(), executor);
} }
private bool Rebuild(ICollection<DtDynamicTile> tiles) private Task<bool> Rebuild(ICollection<DtDynamicTile> tiles, TaskFactory executor)
{ {
foreach (var tile in tiles) var tasks = tiles.Select(tile => executor.StartNew(() => Rebuild(tile))).ToArray();
Rebuild(tile); return Task.WhenAll(tasks).ContinueWith(k => UpdateNavMesh());
return UpdateNavMesh();
}
private bool Rebuild(ICollection<DtDynamicTile> tiles, TaskFactory executor)
{
var tasks = tiles
.Select(tile => executor.StartNew(() => Rebuild(tile)))
.ToArray();
Task.WaitAll(tasks);
return UpdateNavMesh();
} }
private ICollection<DtDynamicTile> GetTiles(float[] bounds) private ICollection<DtDynamicTile> GetTiles(float[] bounds)
@ -217,19 +218,19 @@ namespace DotRecast.Detour.Dynamic
{ {
DtNavMeshCreateParams option = new DtNavMeshCreateParams(); DtNavMeshCreateParams option = new DtNavMeshCreateParams();
option.walkableHeight = config.walkableHeight; option.walkableHeight = config.walkableHeight;
_dirty = _dirty | tile.Build(builder, config, _context); dirty = dirty | tile.Build(builder, config, _context);
} }
private bool UpdateNavMesh() private bool UpdateNavMesh()
{ {
if (_dirty) if (dirty)
{ {
DtNavMesh navMesh = new DtNavMesh(navMeshParams, MAX_VERTS_PER_POLY); DtNavMesh navMesh = new DtNavMesh(navMeshParams, MAX_VERTS_PER_POLY);
foreach (var t in _tiles.Values) foreach (var t in _tiles.Values)
t.AddTo(navMesh); t.AddTo(navMesh);
_navMesh = navMesh; this._navMesh = navMesh;
_dirty = false; dirty = false;
return true; return true;
} }

View File

@ -132,8 +132,8 @@ namespace DotRecast.Detour.Dynamic
private DtNavMeshCreateParams NavMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight, private DtNavMeshCreateParams NavMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight,
DtDynamicNavMeshConfig config, RcBuilderResult rcResult) DtDynamicNavMeshConfig config, RcBuilderResult rcResult)
{ {
RcPolyMesh m_pmesh = rcResult.Mesh; RcPolyMesh m_pmesh = rcResult.GetMesh();
RcPolyMeshDetail m_dmesh = rcResult.MeshDetail; RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
DtNavMeshCreateParams option = new DtNavMeshCreateParams(); DtNavMeshCreateParams option = new DtNavMeshCreateParams();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {

View File

@ -109,13 +109,13 @@ namespace DotRecast.Detour.Dynamic.Io
}; };
foreach (RcBuilderResult r in results) foreach (RcBuilderResult r in results)
{ {
f.tiles.Add(new DtVoxelTile(r.TileX, r.TileZ, r.SolidHeightfiled)); f.tiles.Add(new DtVoxelTile(r.tileX, r.tileZ, r.GetSolidHeightfield()));
f.bounds[0] = Math.Min(f.bounds[0], r.SolidHeightfiled.bmin.X); f.bounds[0] = Math.Min(f.bounds[0], r.GetSolidHeightfield().bmin.X);
f.bounds[1] = Math.Min(f.bounds[1], r.SolidHeightfiled.bmin.Y); f.bounds[1] = Math.Min(f.bounds[1], r.GetSolidHeightfield().bmin.Y);
f.bounds[2] = Math.Min(f.bounds[2], r.SolidHeightfiled.bmin.Z); f.bounds[2] = Math.Min(f.bounds[2], r.GetSolidHeightfield().bmin.Z);
f.bounds[3] = Math.Max(f.bounds[3], r.SolidHeightfiled.bmax.X); f.bounds[3] = Math.Max(f.bounds[3], r.GetSolidHeightfield().bmax.X);
f.bounds[4] = Math.Max(f.bounds[4], r.SolidHeightfiled.bmax.Y); f.bounds[4] = Math.Max(f.bounds[4], r.GetSolidHeightfield().bmax.Y);
f.bounds[5] = Math.Max(f.bounds[5], r.SolidHeightfiled.bmax.Z); f.bounds[5] = Math.Max(f.bounds[5], r.GetSolidHeightfield().bmax.Z);
} }
return f; return f;

View File

@ -21,7 +21,7 @@ namespace DotRecast.Detour.Extras.Jumplink
public JumpLinkBuilder(IList<RcBuilderResult> results) public JumpLinkBuilder(IList<RcBuilderResult> results)
{ {
this.results = results; this.results = results;
edges = results.Select(r => edgeExtractor.ExtractEdges(r.Mesh)).ToList(); edges = results.Select(r => edgeExtractor.ExtractEdges(r.GetMesh())).ToList();
} }
public List<JumpLink> Build(JumpLinkBuilderConfig acfg, JumpLinkType type) public List<JumpLink> Build(JumpLinkBuilderConfig acfg, JumpLinkType type)
@ -43,7 +43,7 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
EdgeSampler es = edgeSamplerFactory.Get(acfg, type, edge); EdgeSampler es = edgeSamplerFactory.Get(acfg, type, edge);
groundSampler.Sample(acfg, result, es); groundSampler.Sample(acfg, result, es);
trajectorySampler.Sample(acfg, result.SolidHeightfiled, es); trajectorySampler.Sample(acfg, result.GetSolidHeightfield(), es);
JumpSegment[] jumpSegments = jumpSegmentBuilder.Build(acfg, es); JumpSegment[] jumpSegments = jumpSegmentBuilder.Build(acfg, es);
return BuildJumpLinks(acfg, es, jumpSegments); return BuildJumpLinks(acfg, es, jumpSegments);
} }

View File

@ -16,25 +16,25 @@ namespace DotRecast.Detour.Extras.Jumplink
private DtNavMeshQuery CreateNavMesh(RcBuilderResult r, float agentRadius, float agentHeight, float agentClimb) private DtNavMeshQuery CreateNavMesh(RcBuilderResult r, float agentRadius, float agentHeight, float agentClimb)
{ {
DtNavMeshCreateParams option = new DtNavMeshCreateParams(); DtNavMeshCreateParams option = new DtNavMeshCreateParams();
option.verts = r.Mesh.verts; option.verts = r.GetMesh().verts;
option.vertCount = r.Mesh.nverts; option.vertCount = r.GetMesh().nverts;
option.polys = r.Mesh.polys; option.polys = r.GetMesh().polys;
option.polyAreas = r.Mesh.areas; option.polyAreas = r.GetMesh().areas;
option.polyFlags = r.Mesh.flags; option.polyFlags = r.GetMesh().flags;
option.polyCount = r.Mesh.npolys; option.polyCount = r.GetMesh().npolys;
option.nvp = r.Mesh.nvp; option.nvp = r.GetMesh().nvp;
option.detailMeshes = r.MeshDetail.meshes; option.detailMeshes = r.GetMeshDetail().meshes;
option.detailVerts = r.MeshDetail.verts; option.detailVerts = r.GetMeshDetail().verts;
option.detailVertsCount = r.MeshDetail.nverts; option.detailVertsCount = r.GetMeshDetail().nverts;
option.detailTris = r.MeshDetail.tris; option.detailTris = r.GetMeshDetail().tris;
option.detailTriCount = r.MeshDetail.ntris; option.detailTriCount = r.GetMeshDetail().ntris;
option.walkableRadius = agentRadius; option.walkableRadius = agentRadius;
option.walkableHeight = agentHeight; option.walkableHeight = agentHeight;
option.walkableClimb = agentClimb; option.walkableClimb = agentClimb;
option.bmin = r.Mesh.bmin; option.bmin = r.GetMesh().bmin;
option.bmax = r.Mesh.bmax; option.bmax = r.GetMesh().bmax;
option.cs = r.Mesh.cs; option.cs = r.GetMesh().cs;
option.ch = r.Mesh.ch; option.ch = r.GetMesh().ch;
option.buildBvTree = true; option.buildBvTree = true;
return new DtNavMeshQuery(new DtNavMesh(DtNavMeshBuilder.CreateNavMeshData(option), option.nvp, 0)); return new DtNavMeshQuery(new DtNavMesh(DtNavMeshBuilder.CreateNavMeshData(option), option.nvp, 0));
} }

View File

@ -21,7 +21,6 @@ freely, subject to the following restrictions:
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Core.Buffers;
using DotRecast.Core.Numerics; using DotRecast.Core.Numerics;
namespace DotRecast.Detour namespace DotRecast.Detour
@ -359,8 +358,8 @@ namespace DotRecast.Detour
var tbmax = tile.data.header.bmax; var tbmax = tile.data.header.bmax;
float qfac = tile.data.header.bvQuantFactor; float qfac = tile.data.header.bvQuantFactor;
// Calculate quantized box // Calculate quantized box
Span<int> bmin = stackalloc int[3]; int[] bmin = new int[3];
Span<int> bmax = stackalloc int[3]; int[] bmax = new int[3];
// dtClamp query box to world box. // dtClamp query box to world box.
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X; float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y; float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
@ -1247,14 +1246,14 @@ namespace DotRecast.Detour
int ip = poly.index; int ip = poly.index;
using var verts = RcRentedArray.Rent<float>(m_maxVertPerPoly * 3); float[] verts = new float[m_maxVertPerPoly * 3];
int nv = poly.vertCount; int nv = poly.vertCount;
for (int i = 0; i < nv; ++i) for (int i = 0; i < nv; ++i)
{ {
RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts.AsArray(), i * 3, 3); RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts, i * 3, 3);
} }
if (!DtUtils.PointInPolygon(pos, verts.AsArray(), nv)) if (!DtUtils.PointInPolygon(pos, verts, nv))
{ {
return false; return false;
} }

View File

@ -21,7 +21,6 @@ freely, subject to the following restrictions:
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Core.Buffers;
using DotRecast.Core.Collections; using DotRecast.Core.Collections;
using DotRecast.Core.Numerics; using DotRecast.Core.Numerics;
@ -42,9 +41,9 @@ namespace DotRecast.Detour
public DtNavMeshQuery(DtNavMesh nav) public DtNavMeshQuery(DtNavMesh nav)
{ {
m_nav = nav; m_nav = nav;
m_tinyNodePool = new DtNodePool();
m_nodePool = new DtNodePool(); m_nodePool = new DtNodePool();
m_openList = new DtNodeQueue(); m_openList = new DtNodeQueue();
m_tinyNodePool = new DtNodePool();
} }
/// Returns random location on navmesh. /// Returns random location on navmesh.
@ -138,18 +137,18 @@ namespace DotRecast.Detour
} }
// Randomly pick point on polygon. // Randomly pick point on polygon.
using var verts = RcRentedArray.Rent<float>(3 * m_nav.GetMaxVertsPerPoly()); float[] verts = new float[3 * m_nav.GetMaxVertsPerPoly()];
using var areas = RcRentedArray.Rent<float>(m_nav.GetMaxVertsPerPoly()); float[] areas = new float[m_nav.GetMaxVertsPerPoly()];
RcArrays.Copy(tile.data.verts, poly.verts[0] * 3, verts.AsArray(), 0, 3); RcArrays.Copy(tile.data.verts, poly.verts[0] * 3, verts, 0, 3);
for (int j = 1; j < poly.vertCount; ++j) for (int j = 1; j < poly.vertCount; ++j)
{ {
RcArrays.Copy(tile.data.verts, poly.verts[j] * 3, verts.AsArray(), j * 3, 3); RcArrays.Copy(tile.data.verts, poly.verts[j] * 3, verts, j * 3, 3);
} }
float s = frand.Next(); float s = frand.Next();
float t = frand.Next(); float t = frand.Next();
var pt = DtUtils.RandomPointInConvexPoly(verts.AsArray(), poly.vertCount, areas.AsArray(), s, t); var pt = DtUtils.RandomPointInConvexPoly(verts, poly.vertCount, areas, s, t);
ClosestPointOnPoly(polyRef, pt, out var closest, out var _); ClosestPointOnPoly(polyRef, pt, out var closest, out var _);
randomRef = polyRef; randomRef = polyRef;
@ -387,8 +386,8 @@ namespace DotRecast.Detour
float s = frand.Next(); float s = frand.Next();
float t = frand.Next(); float t = frand.Next();
using var areas = RcRentedArray.Rent<float>(randomPolyVerts.Length / 3); float[] areas = new float[randomPolyVerts.Length / 3];
RcVec3f pt = DtUtils.RandomPointInConvexPoly(randomPolyVerts, randomPolyVerts.Length / 3, areas.AsArray(), s, t); RcVec3f pt = DtUtils.RandomPointInConvexPoly(randomPolyVerts, randomPolyVerts.Length / 3, areas, s, t);
ClosestPointOnPoly(randomPolyRef, pt, out var closest, out var _); ClosestPointOnPoly(randomPolyRef, pt, out var closest, out var _);
randomRef = randomPolyRef; randomRef = randomPolyRef;
@ -458,16 +457,16 @@ namespace DotRecast.Detour
} }
// Collect vertices. // Collect vertices.
using var verts = RcRentedArray.Rent<float>(m_nav.GetMaxVertsPerPoly() * 3); float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3];
using var edged = RcRentedArray.Rent<float>(m_nav.GetMaxVertsPerPoly()); float[] edged = new float[m_nav.GetMaxVertsPerPoly()];
using var edget = RcRentedArray.Rent<float>(m_nav.GetMaxVertsPerPoly()); float[] edget = new float[m_nav.GetMaxVertsPerPoly()];
int nv = poly.vertCount; int nv = poly.vertCount;
for (int i = 0; i < nv; ++i) for (int i = 0; i < nv; ++i)
{ {
RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts.AsArray(), i * 3, 3); RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts, i * 3, 3);
} }
if (DtUtils.DistancePtPolyEdgesSqr(pos, verts.AsArray(), nv, edged.AsArray(), edget.AsArray())) if (DtUtils.DistancePtPolyEdgesSqr(pos, verts, nv, edged, edget))
{ {
closest = pos; closest = pos;
} }
@ -487,7 +486,7 @@ namespace DotRecast.Detour
int va = imin * 3; int va = imin * 3;
int vb = ((imin + 1) % nv) * 3; int vb = ((imin + 1) % nv) * 3;
closest = RcVecUtils.Lerp(verts.AsArray(), va, vb, edget[imin]); closest = RcVecUtils.Lerp(verts, va, vb, edget[imin]);
} }
return DtStatus.DT_SUCCESS; return DtStatus.DT_SUCCESS;
@ -584,8 +583,8 @@ namespace DotRecast.Detour
var tbmax = tile.data.header.bmax; var tbmax = tile.data.header.bmax;
float qfac = tile.data.header.bvQuantFactor; float qfac = tile.data.header.bvQuantFactor;
// Calculate quantized box // Calculate quantized box
Span<int> bmin = stackalloc int[3]; int[] bmin = new int[3];
Span<int> bmax = stackalloc int[3]; int[] bmax = new int[3];
// dtClamp query box to world box. // dtClamp query box to world box.
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X; float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y; float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
@ -1794,9 +1793,7 @@ namespace DotRecast.Detour
resultPos = RcVec3f.Zero; resultPos = RcVec3f.Zero;
if (null != visited) if (null != visited)
{
visited.Clear(); visited.Clear();
}
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !startPos.IsFinite() if (!m_nav.IsValidPolyRef(startRef) || !startPos.IsFinite()
@ -1825,10 +1822,7 @@ namespace DotRecast.Detour
var searchPos = RcVec3f.Lerp(startPos, endPos, 0.5f); var searchPos = RcVec3f.Lerp(startPos, endPos, 0.5f);
float searchRadSqr = RcMath.Sqr(RcVec3f.Distance(startPos, endPos) / 2.0f + 0.001f); float searchRadSqr = RcMath.Sqr(RcVec3f.Distance(startPos, endPos) / 2.0f + 0.001f);
using var verts = RcRentedArray.Rent<float>(m_nav.GetMaxVertsPerPoly() * 3); float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3];
const int MAX_NEIS = 8;
Span<long> neis = stackalloc long[MAX_NEIS];
while (0 < stack.Count) while (0 < stack.Count)
{ {
@ -1845,11 +1839,11 @@ namespace DotRecast.Detour
int nverts = curPoly.vertCount; int nverts = curPoly.vertCount;
for (int i = 0; i < nverts; ++i) for (int i = 0; i < nverts; ++i)
{ {
RcArrays.Copy(curTile.data.verts, curPoly.verts[i] * 3, verts.AsArray(), i * 3, 3); RcArrays.Copy(curTile.data.verts, curPoly.verts[i] * 3, verts, i * 3, 3);
} }
// If target is inside the poly, stop search. // If target is inside the poly, stop search.
if (DtUtils.PointInPolygon(endPos, verts.AsArray(), nverts)) if (DtUtils.PointInPolygon(endPos, verts, nverts))
{ {
bestNode = curNode; bestNode = curNode;
bestPos = endPos; bestPos = endPos;
@ -1860,7 +1854,9 @@ namespace DotRecast.Detour
for (int i = 0, j = curPoly.vertCount - 1; i < curPoly.vertCount; j = i++) for (int i = 0, j = curPoly.vertCount - 1; i < curPoly.vertCount; j = i++)
{ {
// Find links to neighbours. // Find links to neighbours.
int MAX_NEIS = 8;
int nneis = 0; int nneis = 0;
long[] neis = new long[MAX_NEIS];
if ((curPoly.neis[j] & DtNavMesh.DT_EXT_LINK) != 0) if ((curPoly.neis[j] & DtNavMesh.DT_EXT_LINK) != 0)
{ {
@ -1900,11 +1896,11 @@ namespace DotRecast.Detour
// Wall edge, calc distance. // Wall edge, calc distance.
int vj = j * 3; int vj = j * 3;
int vi = i * 3; int vi = i * 3;
var distSqr = DtUtils.DistancePtSegSqr2D(endPos, verts.AsArray(), vj, vi, out var tseg); var distSqr = DtUtils.DistancePtSegSqr2D(endPos, verts, vj, vi, out var tseg);
if (distSqr < bestDist) if (distSqr < bestDist)
{ {
// Update nearest distance. // Update nearest distance.
bestPos = RcVecUtils.Lerp(verts.AsArray(), vj, vi, tseg); bestPos = RcVecUtils.Lerp(verts, vj, vi, tseg);
bestDist = distSqr; bestDist = distSqr;
bestNode = curNode; bestNode = curNode;
} }
@ -1924,7 +1920,7 @@ namespace DotRecast.Detour
// TODO: Maybe should use GetPortalPoints(), but this one is way faster. // TODO: Maybe should use GetPortalPoints(), but this one is way faster.
int vj = j * 3; int vj = j * 3;
int vi = i * 3; int vi = i * 3;
var distSqr = DtUtils.DistancePtSegSqr2D(searchPos, verts.AsArray(), vj, vi, out var _); var distSqr = DtUtils.DistancePtSegSqr2D(searchPos, verts, vj, vi, out var _);
if (distSqr > searchRadSqr) if (distSqr > searchRadSqr)
{ {
continue; continue;
@ -2248,7 +2244,7 @@ namespace DotRecast.Detour
hit.path.Clear(); hit.path.Clear();
hit.pathCost = 0; hit.pathCost = 0;
using var verts = RcRentedArray.Rent<RcVec3f>(m_nav.GetMaxVertsPerPoly() + 1); RcVec3f[] verts = new RcVec3f[m_nav.GetMaxVertsPerPoly() + 1];
RcVec3f curPos = RcVec3f.Zero; RcVec3f curPos = RcVec3f.Zero;
RcVec3f lastPos = RcVec3f.Zero; RcVec3f lastPos = RcVec3f.Zero;
@ -2282,7 +2278,7 @@ namespace DotRecast.Detour
nv++; nv++;
} }
bool intersects = DtUtils.IntersectSegmentPoly2D(startPos, endPos, verts.AsArray(), nv, out var tmin, out var tmax, out var segMin, out var segMax); bool intersects = DtUtils.IntersectSegmentPoly2D(startPos, endPos, verts, nv, out var tmin, out var tmax, out var segMin, out var segMax);
if (!intersects) if (!intersects)
{ {
// Could not hit the polygon, keep the old t and report hit. // Could not hit the polygon, keep the old t and report hit.
@ -2877,8 +2873,8 @@ namespace DotRecast.Detour
float radiusSqr = RcMath.Sqr(radius); float radiusSqr = RcMath.Sqr(radius);
using var pa = RcRentedArray.Rent<float>(m_nav.GetMaxVertsPerPoly() * 3); float[] pa = new float[m_nav.GetMaxVertsPerPoly() * 3];
using var pb = RcRentedArray.Rent<float>(m_nav.GetMaxVertsPerPoly() * 3); float[] pb = new float[m_nav.GetMaxVertsPerPoly() * 3];
while (0 < stack.Count) while (0 < stack.Count)
{ {
@ -2949,7 +2945,7 @@ namespace DotRecast.Detour
int npa = neighbourPoly.vertCount; int npa = neighbourPoly.vertCount;
for (int k = 0; k < npa; ++k) for (int k = 0; k < npa; ++k)
{ {
RcArrays.Copy(neighbourTile.data.verts, neighbourPoly.verts[k] * 3, pa.AsArray(), k * 3, 3); RcArrays.Copy(neighbourTile.data.verts, neighbourPoly.verts[k] * 3, pa, k * 3, 3);
} }
bool overlap = false; bool overlap = false;
@ -2980,10 +2976,10 @@ namespace DotRecast.Detour
int npb = pastPoly.vertCount; int npb = pastPoly.vertCount;
for (int k = 0; k < npb; ++k) for (int k = 0; k < npb; ++k)
{ {
RcArrays.Copy(pastTile.data.verts, pastPoly.verts[k] * 3, pb.AsArray(), k * 3, 3); RcArrays.Copy(pastTile.data.verts, pastPoly.verts[k] * 3, pb, k * 3, 3);
} }
if (DtUtils.OverlapPolyPoly2D(pa.AsArray(), npa, pb.AsArray(), npb)) if (DtUtils.OverlapPolyPoly2D(pa, npa, pb, npb))
{ {
overlap = true; overlap = true;
break; break;

View File

@ -64,7 +64,7 @@ namespace DotRecast.Detour
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)] /// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
/// @return True if the two AABB's overlap. /// @return True if the two AABB's overlap.
/// @see dtOverlapBounds /// @see dtOverlapBounds
public static bool OverlapQuantBounds(Span<int> amin, Span<int> amax, Span<int> bmin, Span<int> bmax) public static bool OverlapQuantBounds(int[] amin, int[] amax, int[] bmin, int[] bmax)
{ {
bool overlap = true; bool overlap = true;
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap; overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;

View File

@ -26,7 +26,7 @@
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0"/> <PackageReference Include="Serilog.Sinks.Async" Version="1.5.0"/>
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" /> <PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" /> <PackageReference Include="K4os.Compression.LZ4" Version="1.3.6"/>
<PackageReference Include="Silk.NET" Version="2.20.0" /> <PackageReference Include="Silk.NET" Version="2.20.0" />
<PackageReference Include="Silk.NET.OpenGL.Extensions.ImGui" Version="2.20.0" /> <PackageReference Include="Silk.NET.OpenGL.Extensions.ImGui" Version="2.20.0" />
</ItemGroup> </ItemGroup>

View File

@ -123,80 +123,80 @@ public class NavMeshRenderer
foreach (RcBuilderResult rcBuilderResult in rcBuilderResults) foreach (RcBuilderResult rcBuilderResult in rcBuilderResults)
{ {
if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT)
{ {
_debugDraw.DebugDrawCompactHeightfieldSolid(rcBuilderResult.CompactHeightfield); _debugDraw.DebugDrawCompactHeightfieldSolid(rcBuilderResult.GetCompactHeightfield());
} }
if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT_DISTANCE) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_DISTANCE)
{ {
_debugDraw.DebugDrawCompactHeightfieldDistance(rcBuilderResult.CompactHeightfield); _debugDraw.DebugDrawCompactHeightfieldDistance(rcBuilderResult.GetCompactHeightfield());
} }
if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT_REGIONS) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_REGIONS)
{ {
_debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.CompactHeightfield); _debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield());
} }
if (rcBuilderResult.SolidHeightfiled != null && drawMode == DrawMode.DRAWMODE_VOXELS) if (rcBuilderResult.GetSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS)
{ {
_debugDraw.Fog(true); _debugDraw.Fog(true);
_debugDraw.DebugDrawHeightfieldSolid(rcBuilderResult.SolidHeightfiled); _debugDraw.DebugDrawHeightfieldSolid(rcBuilderResult.GetSolidHeightfield());
_debugDraw.Fog(false); _debugDraw.Fog(false);
} }
if (rcBuilderResult.SolidHeightfiled != null && drawMode == DrawMode.DRAWMODE_VOXELS_WALKABLE) if (rcBuilderResult.GetSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS_WALKABLE)
{ {
_debugDraw.Fog(true); _debugDraw.Fog(true);
_debugDraw.DebugDrawHeightfieldWalkable(rcBuilderResult.SolidHeightfiled); _debugDraw.DebugDrawHeightfieldWalkable(rcBuilderResult.GetSolidHeightfield());
_debugDraw.Fog(false); _debugDraw.Fog(false);
} }
if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_RAW_CONTOURS) if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_RAW_CONTOURS)
{ {
_debugDraw.DepthMask(false); _debugDraw.DepthMask(false);
_debugDraw.DebugDrawRawContours(rcBuilderResult.ContourSet, 1f); _debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 1f);
_debugDraw.DepthMask(true); _debugDraw.DepthMask(true);
} }
if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_BOTH_CONTOURS) if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_BOTH_CONTOURS)
{ {
_debugDraw.DepthMask(false); _debugDraw.DepthMask(false);
_debugDraw.DebugDrawRawContours(rcBuilderResult.ContourSet, 0.5f); _debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 0.5f);
_debugDraw.DebugDrawContours(rcBuilderResult.ContourSet); _debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet());
_debugDraw.DepthMask(true); _debugDraw.DepthMask(true);
} }
if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_CONTOURS) if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_CONTOURS)
{ {
_debugDraw.DepthMask(false); _debugDraw.DepthMask(false);
_debugDraw.DebugDrawContours(rcBuilderResult.ContourSet); _debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet());
_debugDraw.DepthMask(true); _debugDraw.DepthMask(true);
} }
if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_REGION_CONNECTIONS) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_REGION_CONNECTIONS)
{ {
_debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.CompactHeightfield); _debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield());
_debugDraw.DepthMask(false); _debugDraw.DepthMask(false);
if (rcBuilderResult.ContourSet != null) if (rcBuilderResult.GetContourSet() != null)
{ {
_debugDraw.DebugDrawRegionConnections(rcBuilderResult.ContourSet); _debugDraw.DebugDrawRegionConnections(rcBuilderResult.GetContourSet());
} }
_debugDraw.DepthMask(true); _debugDraw.DepthMask(true);
} }
if (rcBuilderResult.Mesh != null && drawMode == DrawMode.DRAWMODE_POLYMESH) if (rcBuilderResult.GetMesh() != null && drawMode == DrawMode.DRAWMODE_POLYMESH)
{ {
_debugDraw.DepthMask(false); _debugDraw.DepthMask(false);
_debugDraw.DebugDrawPolyMesh(rcBuilderResult.Mesh); _debugDraw.DebugDrawPolyMesh(rcBuilderResult.GetMesh());
_debugDraw.DepthMask(true); _debugDraw.DepthMask(true);
} }
if (rcBuilderResult.MeshDetail != null && drawMode == DrawMode.DRAWMODE_POLYMESH_DETAIL) if (rcBuilderResult.GetMeshDetail() != null && drawMode == DrawMode.DRAWMODE_POLYMESH_DETAIL)
{ {
_debugDraw.DepthMask(false); _debugDraw.DepthMask(false);
_debugDraw.DebugDrawPolyMeshDetail(rcBuilderResult.MeshDetail); _debugDraw.DebugDrawPolyMeshDetail(rcBuilderResult.GetMeshDetail());
_debugDraw.DepthMask(true); _debugDraw.DepthMask(true);
} }
} }

View File

@ -368,7 +368,7 @@ public class RecastDemo : IRecastDemoChannel
var scale = (float)_resolution.X / 1920; var scale = (float)_resolution.X / 1920;
int fontSize = Math.Max(10, (int)(16 * scale)); int fontSize = Math.Max(10, (int)(16 * scale));
// for windows : Microsoft Visual C++ Redistributable Package // for windows : Microsoft Visual C++ Redistributable Package
// link - https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist // link - https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist
var imGuiFontConfig = new ImGuiFontConfig(Path.Combine("resources\\fonts", "DroidSans.ttf"), fontSize, null); var imGuiFontConfig = new ImGuiFontConfig(Path.Combine("resources\\fonts", "DroidSans.ttf"), fontSize, null);
@ -379,7 +379,7 @@ public class RecastDemo : IRecastDemoChannel
DemoInputGeomProvider geom = LoadInputMesh("nav_test.obj"); DemoInputGeomProvider geom = LoadInputMesh("nav_test.obj");
_sample = new DemoSample(geom, ImmutableArray<RcBuilderResult>.Empty, null); _sample = new DemoSample(geom, ImmutableArray<RcBuilderResult>.Empty, null);
_menuView = new RcMenuView(); _menuView = new RcMenuView();
settingsView = new RcSettingsView(this); settingsView = new RcSettingsView(this);
settingsView.SetSample(_sample); settingsView.SetSample(_sample);
@ -537,7 +537,6 @@ public class RecastDemo : IRecastDemoChannel
bool hasBound = false; bool hasBound = false;
RcVec3f bminN = RcVec3f.Zero; RcVec3f bminN = RcVec3f.Zero;
RcVec3f bmaxN = RcVec3f.Zero; RcVec3f bmaxN = RcVec3f.Zero;
if (_sample.GetInputGeom() != null) if (_sample.GetInputGeom() != null)
{ {
bminN = _sample.GetInputGeom().GetMeshBoundsMin(); bminN = _sample.GetInputGeom().GetMeshBoundsMin();
@ -553,7 +552,7 @@ public class RecastDemo : IRecastDemoChannel
{ {
foreach (RcBuilderResult result in _sample.GetRecastResults()) foreach (RcBuilderResult result in _sample.GetRecastResults())
{ {
if (result.CompactHeightfield != null) if (result.GetSolidHeightfield() != null)
{ {
if (!hasBound) if (!hasBound)
{ {
@ -562,15 +561,15 @@ public class RecastDemo : IRecastDemoChannel
} }
bminN = new RcVec3f( bminN = new RcVec3f(
Math.Min(bminN.X, result.CompactHeightfield.bmin.X), Math.Min(bminN.X, result.GetSolidHeightfield().bmin.X),
Math.Min(bminN.Y, result.CompactHeightfield.bmin.Y), Math.Min(bminN.Y, result.GetSolidHeightfield().bmin.Y),
Math.Min(bminN.Z, result.CompactHeightfield.bmin.Z) Math.Min(bminN.Z, result.GetSolidHeightfield().bmin.Z)
); );
bmaxN = new RcVec3f( bmaxN = new RcVec3f(
Math.Max(bmaxN.X, result.CompactHeightfield.bmax.X), Math.Max(bmaxN.X, result.GetSolidHeightfield().bmax.X),
Math.Max(bmaxN.Y, result.CompactHeightfield.bmax.Y), Math.Max(bmaxN.Y, result.GetSolidHeightfield().bmax.Y),
Math.Max(bmaxN.Z, result.CompactHeightfield.bmax.Z) Math.Max(bmaxN.Z, result.GetSolidHeightfield().bmax.Z)
); );
hasBound = true; hasBound = true;
@ -578,15 +577,12 @@ public class RecastDemo : IRecastDemoChannel
} }
} }
// Reset camera and fog to match the mesh bounds.
if (hasBound) if (hasBound)
{ {
RcVec3f bmin = bminN; RcVec3f bmin = bminN;
RcVec3f bmax = bmaxN; RcVec3f bmax = bmaxN;
camr = (float)(Math.Sqrt(RcMath.Sqr(bmax.X - bmin.X) + camr = (float)(Math.Sqrt(RcMath.Sqr(bmax.X - bmin.X) + RcMath.Sqr(bmax.Y - bmin.Y) + RcMath.Sqr(bmax.Z - bmin.Z)) / 2);
RcMath.Sqr(bmax.Y - bmin.Y) +
RcMath.Sqr(bmax.Z - bmin.Z)) / 2);
cameraPos.X = (bmax.X + bmin.X) / 2 + camr; cameraPos.X = (bmax.X + bmin.X) / 2 + camr;
cameraPos.Y = (bmax.Y + bmin.Y) / 2 + camr; cameraPos.Y = (bmax.Y + bmin.Y) / 2 + camr;
cameraPos.Z = (bmax.Z + bmin.Z) / 2 + camr; cameraPos.Z = (bmax.Z + bmin.Z) / 2 + camr;
@ -692,15 +688,14 @@ public class RecastDemo : IRecastDemoChannel
NavMeshBuildResult buildResult; NavMeshBuildResult buildResult;
var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings(); var settings = _sample.GetSettings();
if (settings.tiled) if (settings.tiled)
{ {
buildResult = tileNavMeshBuilder.Build(geom, settings); buildResult = tileNavMeshBuilder.Build(_sample.GetInputGeom(), settings);
} }
else else
{ {
buildResult = soloNavMeshBuilder.Build(geom, settings); buildResult = soloNavMeshBuilder.Build(_sample.GetInputGeom(), settings);
} }
if (!buildResult.Success) if (!buildResult.Success)
@ -718,7 +713,7 @@ public class RecastDemo : IRecastDemoChannel
Logger.Information($"build times"); Logger.Information($"build times");
Logger.Information($"-----------------------------------------"); Logger.Information($"-----------------------------------------");
var telemetries = buildResult.RecastBuilderResults var telemetries = buildResult.RecastBuilderResults
.Select(x => x.Context) .Select(x => x.GetTelemetry())
.SelectMany(x => x.ToList()) .SelectMany(x => x.ToList())
.GroupBy(x => x.Key) .GroupBy(x => x.Key)
.ToImmutableSortedDictionary(x => x.Key, x => x.Sum(y => y.Millis)); .ToImmutableSortedDictionary(x => x.Key, x => x.Sum(y => y.Millis));

View File

@ -91,7 +91,7 @@ public class DynamicUpdateSampleTool : ISampleTool
var bridgeGeom = DemoInputGeomProvider.LoadFile("bridge.obj"); var bridgeGeom = DemoInputGeomProvider.LoadFile("bridge.obj");
var houseGeom = DemoInputGeomProvider.LoadFile("house.obj"); var houseGeom = DemoInputGeomProvider.LoadFile("house.obj");
var convexGeom = DemoInputGeomProvider.LoadFile("convex.obj"); var convexGeom = DemoInputGeomProvider.LoadFile("convex.obj");
_tool = new(new RcRand(Random.Shared), bridgeGeom, houseGeom, convexGeom); _tool = new(Random.Shared, bridgeGeom, houseGeom, convexGeom);
executor = Task.Factory; executor = Task.Factory;
} }
@ -406,7 +406,7 @@ public class DynamicUpdateSampleTool : ISampleTool
long t = RcFrequency.Ticks; long t = RcFrequency.Ticks;
try try
{ {
bool updated = _tool.Update(executor); bool updated = _tool.UpdateDynaMesh(executor);
if (updated) if (updated)
{ {
buildTime = (RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond; buildTime = (RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond;
@ -450,7 +450,7 @@ public class DynamicUpdateSampleTool : ISampleTool
long t = RcFrequency.Ticks; long t = RcFrequency.Ticks;
try try
{ {
var _ = dynaMesh.Build(executor); var _ = dynaMesh.Build(executor).Result;
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -16,7 +16,6 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
using System.Linq;
using DotRecast.Core.Numerics; using DotRecast.Core.Numerics;
using DotRecast.Detour.Extras.Jumplink; using DotRecast.Detour.Extras.Jumplink;
using DotRecast.Recast.Demo.Draw; using DotRecast.Recast.Demo.Draw;
@ -97,25 +96,13 @@ public class JumpLinkBuilderSampleTool : ISampleTool
if (build || _cfg.buildOffMeshConnections) if (build || _cfg.buildOffMeshConnections)
{ {
do if (0 < _sample.GetRecastResults().Count)
{ {
if (0 >= _sample.GetRecastResults().Count)
{
Logger.Error("build navmesh");
break;
}
if (_sample.GetRecastResults().Any(x => null == x.SolidHeightfiled))
{
Logger.Error("Tick 'Keep Itermediate Results' option");
break;
}
var geom = _sample.GetInputGeom(); var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings(); var settings = _sample.GetSettings();
_tool.Build(geom, settings, _sample.GetRecastResults(), _cfg); _tool.Build(geom, settings, _sample.GetRecastResults(), _cfg);
} while (false); }
} }
ImGui.NewLine(); ImGui.NewLine();

View File

@ -166,10 +166,6 @@ public class RcSettingsView : IRcView
ImGui.SliderFloat("Max Sample Error", ref settings.detailSampleMaxError, 0f, 16f, "%.1f"); ImGui.SliderFloat("Max Sample Error", ref settings.detailSampleMaxError, 0f, 16f, "%.1f");
ImGui.NewLine(); ImGui.NewLine();
ImGui.Checkbox("Keep Itermediate Results", ref settings.keepInterResults);
ImGui.Checkbox("Build All Tiles", ref settings.buildAll);
ImGui.NewLine();
ImGui.Text("Tiling"); ImGui.Text("Tiling");
ImGui.Separator(); ImGui.Separator();
ImGui.Checkbox("Enable", ref settings.tiled); ImGui.Checkbox("Enable", ref settings.tiled);
@ -232,12 +228,6 @@ public class RcSettingsView : IRcView
DrawMode.Values.ForEach(dm => { ImGui.RadioButton(dm.Text, ref drawMode, dm.Idx); }); DrawMode.Values.ForEach(dm => { ImGui.RadioButton(dm.Text, ref drawMode, dm.Idx); });
ImGui.NewLine(); ImGui.NewLine();
ImGui.Separator();
ImGui.Text("Tick 'Keep Itermediate Results'");
ImGui.Text("rebuild some tiles to see");
ImGui.Text("more debug mode options.");
ImGui.NewLine();
ImGui.End(); ImGui.End();
} }
@ -272,4 +262,4 @@ public class RcSettingsView : IRcView
{ {
this.maxPolys = maxPolys; this.maxPolys = maxPolys;
} }
} }

View File

@ -10,8 +10,8 @@ namespace DotRecast.Recast.Toolset.Builder
float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb, float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
RcBuilderResult rcResult) RcBuilderResult rcResult)
{ {
RcPolyMesh pmesh = rcResult.Mesh; RcPolyMesh pmesh = rcResult.GetMesh();
RcPolyMeshDetail dmesh = rcResult.MeshDetail; RcPolyMeshDetail dmesh = rcResult.GetMeshDetail();
DtNavMeshCreateParams option = new DtNavMeshCreateParams(); DtNavMeshCreateParams option = new DtNavMeshCreateParams();
for (int i = 0; i < pmesh.npolys; ++i) for (int i = 0; i < pmesh.npolys; ++i)
{ {

View File

@ -34,8 +34,7 @@ namespace DotRecast.Recast.Toolset.Builder
settings.edgeMaxLen, settings.edgeMaxError, settings.edgeMaxLen, settings.edgeMaxError,
settings.vertsPerPoly, settings.vertsPerPoly,
settings.detailSampleDist, settings.detailSampleMaxError, settings.detailSampleDist, settings.detailSampleMaxError,
settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans, settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans);
settings.keepInterResults);
} }
public NavMeshBuildResult Build(DemoInputGeomProvider geom, public NavMeshBuildResult Build(DemoInputGeomProvider geom,
@ -46,8 +45,7 @@ namespace DotRecast.Recast.Toolset.Builder
float edgeMaxLen, float edgeMaxError, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, int vertsPerPoly,
float detailSampleDist, float detailSampleMaxError, float detailSampleDist, float detailSampleMaxError,
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans, bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
bool keepInterResults)
{ {
RcConfig cfg = new RcConfig( RcConfig cfg = new RcConfig(
partitionType, partitionType,
@ -60,7 +58,7 @@ namespace DotRecast.Recast.Toolset.Builder
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
RcBuilderResult rcResult = BuildRecastResult(geom, cfg, keepInterResults); RcBuilderResult rcResult = BuildRecastResult(geom, cfg);
var meshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult); var meshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult);
if (null == meshData) if (null == meshData)
{ {
@ -76,26 +74,11 @@ namespace DotRecast.Recast.Toolset.Builder
return new DtNavMesh(meshData, vertsPerPoly, 0); return new DtNavMesh(meshData, vertsPerPoly, 0);
} }
private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg, bool keepInterResults) private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg)
{ {
RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
RcBuilder rcBuilder = new RcBuilder(); RcBuilder rcBuilder = new RcBuilder();
var result = rcBuilder.Build(geom, bcfg); return rcBuilder.Build(geom, bcfg);
if (!keepInterResults)
{
return new RcBuilderResult(
result.TileX,
result.TileZ,
null,
null,
null,
result.Mesh,
result.MeshDetail,
result.Context
);
}
return result;
} }
public DtMeshData BuildMeshData(DemoInputGeomProvider geom, public DtMeshData BuildMeshData(DemoInputGeomProvider geom,

View File

@ -41,8 +41,7 @@ namespace DotRecast.Recast.Toolset.Builder
settings.minRegionSize, settings.mergedRegionSize, settings.minRegionSize, settings.mergedRegionSize,
settings.edgeMaxLen, settings.edgeMaxError, settings.edgeMaxLen, settings.edgeMaxError,
settings.vertsPerPoly, settings.detailSampleDist, settings.detailSampleMaxError, settings.vertsPerPoly, settings.detailSampleDist, settings.detailSampleMaxError,
settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans, settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans);
settings.keepInterResults, settings.buildAll);
} }
public NavMeshBuildResult Build(IInputGeomProvider geom, public NavMeshBuildResult Build(IInputGeomProvider geom,
@ -54,8 +53,7 @@ namespace DotRecast.Recast.Toolset.Builder
float edgeMaxLen, float edgeMaxError, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, int vertsPerPoly,
float detailSampleDist, float detailSampleMaxError, float detailSampleDist, float detailSampleMaxError,
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans, bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
bool keepInterResults, bool buildAll)
{ {
List<RcBuilderResult> results = BuildRecastResult( List<RcBuilderResult> results = BuildRecastResult(
geom, geom,
@ -67,8 +65,7 @@ namespace DotRecast.Recast.Toolset.Builder
edgeMaxLen, edgeMaxError, edgeMaxLen, edgeMaxError,
vertsPerPoly, vertsPerPoly,
detailSampleDist, detailSampleMaxError, detailSampleDist, detailSampleMaxError,
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans
keepInterResults, buildAll
); );
var tileMeshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, results); var tileMeshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, results);
@ -85,8 +82,7 @@ namespace DotRecast.Recast.Toolset.Builder
float edgeMaxLen, float edgeMaxError, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, int vertsPerPoly,
float detailSampleDist, float detailSampleMaxError, float detailSampleDist, float detailSampleMaxError,
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans, bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
bool keepInterResults, bool buildAll)
{ {
RcConfig cfg = new RcConfig(true, tileSize, tileSize, RcConfig cfg = new RcConfig(true, tileSize, tileSize,
@ -101,7 +97,7 @@ namespace DotRecast.Recast.Toolset.Builder
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
RcBuilder rcBuilder = new RcBuilder(); RcBuilder rcBuilder = new RcBuilder();
return rcBuilder.BuildTiles(geom, cfg, keepInterResults, buildAll, Environment.ProcessorCount + 1, Task.Factory); return rcBuilder.BuildTiles(geom, cfg, Task.Factory);
} }
public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List<DtMeshData> meshData, float cellSize, int tileSize, int vertsPerPoly) public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List<DtMeshData> meshData, float cellSize, int tileSize, int vertsPerPoly)
@ -127,9 +123,10 @@ namespace DotRecast.Recast.Toolset.Builder
List<DtMeshData> meshData = new List<DtMeshData>(); List<DtMeshData> meshData = new List<DtMeshData>();
foreach (RcBuilderResult result in results) foreach (RcBuilderResult result in results)
{ {
int x = result.TileX; int x = result.tileX;
int z = result.TileZ; int z = result.tileZ;
DtNavMeshCreateParams option = DemoNavMeshBuilder.GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result); DtNavMeshCreateParams option = DemoNavMeshBuilder
.GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result);
option.tileX = x; option.tileX = x;
option.tileZ = z; option.tileZ = z;

View File

@ -34,8 +34,5 @@ namespace DotRecast.Recast.Toolset
public bool tiled = false; public bool tiled = false;
public int tileSize = 32; public int tileSize = 32;
public bool keepInterResults = false;
public bool buildAll = true;
} }
} }

View File

@ -18,12 +18,12 @@ namespace DotRecast.Recast.Toolset.Tools
private DtDynamicNavMesh dynaMesh; private DtDynamicNavMesh dynaMesh;
private readonly Dictionary<long, RcGizmo> colliderGizmos; private readonly Dictionary<long, RcGizmo> colliderGizmos;
private readonly IRcRand random; private readonly Random random;
private readonly DemoInputGeomProvider bridgeGeom; private readonly DemoInputGeomProvider bridgeGeom;
private readonly DemoInputGeomProvider houseGeom; private readonly DemoInputGeomProvider houseGeom;
private readonly DemoInputGeomProvider convexGeom; private readonly DemoInputGeomProvider convexGeom;
public RcDynamicUpdateTool(IRcRand rand, DemoInputGeomProvider bridgeGeom, DemoInputGeomProvider houseGeom, DemoInputGeomProvider convexGeom) public RcDynamicUpdateTool(Random rand, DemoInputGeomProvider bridgeGeom, DemoInputGeomProvider houseGeom, DemoInputGeomProvider convexGeom)
{ {
this.colliderGizmos = new Dictionary<long, RcGizmo>(); this.colliderGizmos = new Dictionary<long, RcGizmo>();
this.random = rand; this.random = rand;
@ -339,14 +339,20 @@ namespace DotRecast.Recast.Toolset.Tools
return resultvector; return resultvector;
} }
public bool Update(TaskFactory executor) public bool UpdateDynaMesh(TaskFactory executor)
{ {
if (dynaMesh == null) if (dynaMesh == null)
{ {
return false; return false;
} }
return dynaMesh.Update(executor); bool updated = dynaMesh.Update(executor).Result;
if (updated)
{
return false;
}
return true;
} }
public bool Raycast(RcVec3f spos, RcVec3f epos, out float hitPos, out RcVec3f raycastHitPos) public bool Raycast(RcVec3f spos, RcVec3f epos, out float hitPos, out RcVec3f raycastHitPos)

View File

@ -94,7 +94,7 @@ namespace DotRecast.Recast.Toolset.Tools
var beginTick = RcFrequency.Ticks; var beginTick = RcFrequency.Ticks;
var rb = new RcBuilder(); var rb = new RcBuilder();
var result = rb.BuildTile(geom, cfg, bmin, bmax, tx, ty, new RcAtomicInteger(0), 1, settings.keepInterResults); var result = rb.BuildTile(geom, cfg, bmin, bmax, tx, ty, new RcAtomicInteger(0), 1);
var tb = new TileNavMeshBuilder(); var tb = new TileNavMeshBuilder();
var meshData = tb.BuildMeshData(geom, settings.cellSize, settings.cellHeight, settings.agentHeight, settings.agentRadius, settings.agentMaxClimb, RcImmutableArray.Create(result) var meshData = tb.BuildMeshData(geom, settings.cellSize, settings.cellHeight, settings.agentHeight, settings.agentRadius, settings.agentMaxClimb, RcImmutableArray.Create(result)

View File

@ -19,9 +19,7 @@ freely, subject to the following restrictions:
*/ */
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using DotRecast.Core; using DotRecast.Core;
@ -47,123 +45,129 @@ namespace DotRecast.Recast
_progressListener = progressListener; _progressListener = progressListener;
} }
public List<RcBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, bool keepInterResults, bool buildAll, public List<RcBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory)
int threads = 0, TaskFactory taskFactory = null, CancellationToken cancellation = default)
{ {
RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax(); RcVec3f bmax = geom.GetMeshBoundsMax();
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th); CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
List<RcBuilderResult> results = new List<RcBuilderResult>();
if (1 < threads) if (null != taskFactory)
{ {
return BuildMultiThread(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation, keepInterResults, buildAll); BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default);
} }
else
return BuildSingleThread(geom, cfg, bmin, bmax, tw, th, keepInterResults, buildAll);
}
private List<RcBuilderResult> BuildSingleThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th,
bool keepInterResults, bool buildAll)
{
var results = new List<RcBuilderResult>(th * tw);
RcAtomicInteger counter = new RcAtomicInteger(0);
for (int y = 0; y < th; ++y)
{ {
for (int x = 0; x < tw; ++x) BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
{
var result = BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th, keepInterResults);
results.Add(result);
}
} }
return results; return results;
} }
private List<RcBuilderResult> BuildMultiThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th,
int threads, TaskFactory taskFactory, CancellationToken cancellation,
bool keepInterResults, bool buildAll)
{
var results = new ConcurrentQueue<RcBuilderResult>();
RcAtomicInteger progress = new RcAtomicInteger(0);
List<Task> limits = new List<Task>(threads); public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
{
RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax();
CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
Task task;
if (1 < threads)
{
task = BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, cancellationToken);
}
else
{
task = BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results);
}
return task;
}
private Task BuildSingleThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
int tw, int th, List<RcBuilderResult> results)
{
RcAtomicInteger counter = new RcAtomicInteger(0);
for (int y = 0; y < th; ++y)
{
for (int x = 0; x < tw; ++x)
{
results.Add(BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th));
}
}
return Task.CompletedTask;
}
private Task BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
int tw, int th, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
{
RcAtomicInteger counter = new RcAtomicInteger(0);
CountdownEvent latch = new CountdownEvent(tw * th);
List<Task> tasks = new List<Task>();
for (int x = 0; x < tw; ++x) for (int x = 0; x < tw; ++x)
{ {
for (int y = 0; y < th; ++y) for (int y = 0; y < th; ++y)
{ {
int tx = x; int tx = x;
int ty = y; int ty = y;
var task = taskFactory.StartNew(state => var task = taskFactory.StartNew(() =>
{ {
if (cancellation.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
return; return;
try try
{ {
RcBuilderResult result = BuildTile(geom, cfg, bmin, bmax, tx, ty, progress, tw * th, keepInterResults); RcBuilderResult tile = BuildTile(geom, cfg, bmin, bmax, tx, ty, counter, tw * th);
results.Enqueue(result); lock (results)
{
results.Add(tile);
}
} }
catch (Exception e) catch (Exception e)
{ {
Console.WriteLine(e); Console.WriteLine(e);
} }
}, null, cancellation);
limits.Add(task);
if (threads <= limits.Count) latch.Signal();
{ }, cancellationToken);
Task.WaitAll(limits.ToArray());
limits.Clear(); tasks.Add(task);
}
} }
} }
if (0 < limits.Count) try
{
latch.Wait();
}
catch (ThreadInterruptedException)
{ {
Task.WaitAll(limits.ToArray());
limits.Clear();
} }
var list = results.ToList(); return Task.WhenAll(tasks.ToArray());
return list;
} }
public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, int ty, RcAtomicInteger progress, int total, bool keepInterResults) public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx,
int ty, RcAtomicInteger counter, int total)
{ {
var bcfg = new RcBuilderConfig(cfg, bmin, bmax, tx, ty); RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty));
RcBuilderResult result = Build(geom, bcfg);
if (_progressListener != null) if (_progressListener != null)
{ {
_progressListener.OnProgress(progress.IncrementAndGet(), total); _progressListener.OnProgress(counter.IncrementAndGet(), total);
}
if (!keepInterResults)
{
return new RcBuilderResult(
result.TileX,
result.TileZ,
null,
null,
null,
result.Mesh,
result.MeshDetail,
result.Context
);
} }
return result; return result;
} }
public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig bcfg) public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig builderCfg)
{ {
RcConfig cfg = bcfg.cfg; RcConfig cfg = builderCfg.cfg;
RcContext ctx = new RcContext(); RcContext ctx = new RcContext();
// //
// Step 1. Rasterize input polygon soup. // Step 1. Rasterize input polygon soup.
// //
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, bcfg); RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg);
return Build(ctx, bcfg.tileX, bcfg.tileZ, geom, cfg, solid); return Build(ctx, builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid);
} }
public RcBuilderResult Build(RcContext ctx, int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid) public RcBuilderResult Build(RcContext ctx, int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid)
@ -201,7 +205,7 @@ namespace DotRecast.Recast
{ {
// Prepare for region partitioning, by calculating distance field along the walkable surface. // Prepare for region partitioning, by calculating distance field along the walkable surface.
RcRegions.BuildDistanceField(ctx, chf); RcRegions.BuildDistanceField(ctx, chf);
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea); RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
} }
@ -294,7 +298,7 @@ namespace DotRecast.Recast
RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg); RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg);
FilterHeightfield(ctx, solid, builderCfg.cfg); FilterHeightfield(ctx, solid, builderCfg.cfg);
RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, builderCfg.cfg, solid); RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, builderCfg.cfg, solid);
RcLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.BorderSize, builderCfg.cfg.WalkableHeight, out var lset); RcLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.BorderSize, builderCfg.cfg.WalkableHeight, out var lset);
return lset; return lset;
} }

View File

@ -4,26 +4,56 @@ namespace DotRecast.Recast
{ {
public class RcBuilderResult public class RcBuilderResult
{ {
public readonly int TileX; public readonly int tileX;
public readonly int TileZ; public readonly int tileZ;
private readonly RcCompactHeightfield chf;
private readonly RcContourSet cs;
private readonly RcPolyMesh pmesh;
private readonly RcPolyMeshDetail dmesh;
private readonly RcHeightfield solid;
private readonly RcContext _context;
public readonly RcHeightfield SolidHeightfiled; public RcBuilderResult(int tileX, int tileZ, RcHeightfield solid, RcCompactHeightfield chf, RcContourSet cs, RcPolyMesh pmesh, RcPolyMeshDetail dmesh, RcContext ctx)
public readonly RcCompactHeightfield CompactHeightfield;
public readonly RcContourSet ContourSet;
public readonly RcPolyMesh Mesh;
public readonly RcPolyMeshDetail MeshDetail;
public readonly RcContext Context;
public RcBuilderResult(int tileX, int tileZ, RcHeightfield solidHeightfiled, RcCompactHeightfield compactHeightfield, RcContourSet contourSet, RcPolyMesh mesh, RcPolyMeshDetail meshDetail, RcContext ctx)
{ {
TileX = tileX; this.tileX = tileX;
TileZ = tileZ; this.tileZ = tileZ;
SolidHeightfiled = solidHeightfiled; this.solid = solid;
CompactHeightfield = compactHeightfield; this.chf = chf;
ContourSet = contourSet; this.cs = cs;
Mesh = mesh; this.pmesh = pmesh;
MeshDetail = meshDetail; this.dmesh = dmesh;
Context = ctx; _context = ctx;
}
public RcPolyMesh GetMesh()
{
return pmesh;
}
public RcPolyMeshDetail GetMeshDetail()
{
return dmesh;
}
public RcCompactHeightfield GetCompactHeightfield()
{
return chf;
}
public RcContourSet GetContourSet()
{
return cs;
}
public RcHeightfield GetSolidHeightfield()
{
return solid;
}
public RcContext GetTelemetry()
{
return _context;
} }
} }
} }

View File

@ -22,21 +22,29 @@ using DotRecast.Core.Numerics;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
/// A dynamic heightfield representing obstructed space. /** Represents a heightfield layer within a layer set. */
/// @ingroup recast
public class RcHeightfield public class RcHeightfield
{ {
public readonly int width; //< The width of the heightfield. (Along the x-axis in cell units.) /** The width of the heightfield. (Along the x-axis in cell units.) */
public readonly int height; //< The height of the heightfield. (Along the z-axis in cell units.) public readonly int width;
public readonly RcVec3f bmin; //< The minimum bounds in world space. [(x, y, z)]
public RcVec3f bmax; //< The maximum bounds in world space. [(x, y, z)]
public readonly float cs; //< The size of each cell. (On the xz-plane.)
public readonly float ch; //< The height of each cell. (The minimum increment along the y-axis.)
public readonly RcSpan[] spans; //< Heightfield of spans (width*height).
// memory pool for rcSpan instances. /** The height of the heightfield. (Along the z-axis in cell units.) */
public RcSpanPool pools; //< Linked list of span pools. public readonly int height;
public RcSpan freelist; //< The next free span.
/** The minimum bounds in world space. [(x, y, z)] */
public readonly RcVec3f bmin;
/** The maximum bounds in world space. [(x, y, z)] */
public RcVec3f bmax;
/** The size of each cell. (On the xz-plane.) */
public readonly float cs;
/** The height of each cell. (The minimum increment along the y-axis.) */
public readonly float ch;
/** Heightfield of spans (width*height). */
public readonly RcSpan[] spans;
/** Border size in cell units */ /** Border size in cell units */
public readonly int borderSize; public readonly int borderSize;

View File

@ -30,9 +30,9 @@ namespace DotRecast.Recast
hitTime = 0.0f; hitTime = 0.0f;
foreach (RcBuilderResult result in results) foreach (RcBuilderResult result in results)
{ {
if (result.MeshDetail != null) if (result.GetMeshDetail() != null)
{ {
if (Raycast(result.Mesh, result.MeshDetail, src, dst, out hitTime)) if (Raycast(result.GetMesh(), result.GetMeshDetail(), src, dst, out hitTime))
{ {
return true; return true;
} }

View File

@ -41,63 +41,6 @@ namespace DotRecast.Recast
aMin.Y <= bMax.Y && aMax.Y >= bMin.Y && aMin.Y <= bMax.Y && aMax.Y >= bMin.Y &&
aMin.Z <= bMax.Z && aMax.Z >= bMin.Z; aMin.Z <= bMax.Z && aMax.Z >= bMin.Z;
} }
/// Allocates a new span in the heightfield.
/// Use a memory pool and free list to minimize actual allocations.
///
/// @param[in] heightfield The heightfield
/// @returns A pointer to the allocated or re-used span memory.
private static RcSpan AllocSpan(RcHeightfield heightfield)
{
// If necessary, allocate new page and update the freelist.
if (heightfield.freelist == null || heightfield.freelist.next == null)
{
// Create new page.
// Allocate memory for the new pool.
RcSpanPool spanPool = new RcSpanPool();
if (spanPool == null)
{
return null;
}
// Add the pool into the list of pools.
spanPool.next = heightfield.pools;
heightfield.pools = spanPool;
// Add new spans to the free list.
RcSpan freeList = heightfield.freelist;
int head = 0;
int it = RC_SPANS_PER_POOL;
do
{
--it;
spanPool.items[it].next = freeList;
freeList = spanPool.items[it];
} while (it != head);
heightfield.freelist = spanPool.items[it];
}
// Pop item from the front of the free list.
RcSpan newSpan = heightfield.freelist;
heightfield.freelist = heightfield.freelist.next;
return newSpan;
}
/// Releases the memory used by the span back to the heightfield, so it can be re-used for new spans.
/// @param[in] heightfield The heightfield.
/// @param[in] span A pointer to the span to free
private static void FreeSpan(RcHeightfield heightfield, RcSpan span)
{
if (span == null)
{
return;
}
// Add the span to the front of the free list.
span.next = heightfield.freelist;
heightfield.freelist = span;
}
/// Adds a span to the heightfield. If the new span overlaps existing spans, /// Adds a span to the heightfield. If the new span overlaps existing spans,
@ -213,7 +156,7 @@ namespace DotRecast.Recast
float axisOffset, int axis) float axisOffset, int axis)
{ {
// How far positive or negative away from the separating axis is each vertex. // How far positive or negative away from the separating axis is each vertex.
Span<float> inVertAxisDelta = stackalloc float[12]; float[] inVertAxisDelta = new float[12];
for (int inVert = 0; inVert < inVertsCount; ++inVert) for (int inVert = 0; inVert < inVertsCount; ++inVert)
{ {
inVertAxisDelta[inVert] = axisOffset - inVerts[inVertsOffset + inVert * 3 + axis]; inVertAxisDelta[inVert] = axisOffset - inVerts[inVertsOffset + inVert * 3 + axis];

View File

@ -1,38 +0,0 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
namespace DotRecast.Recast
{
/// A memory pool used for quick allocation of spans within a heightfield.
/// @see rcHeightfield
public class RcSpanPool
{
public RcSpanPool next; //< The next span pool.
public readonly RcSpan[] items; //< Array of spans in the pool.
public RcSpanPool()
{
items = new RcSpan[RcConstants.RC_SPANS_PER_POOL];
for (int i = 0; i < items.Length; ++i)
{
items[i] = new RcSpan();
}
}
}
}

View File

@ -9,13 +9,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Moq" Version="4.20.70" /> <PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NUnit" Version="4.1.0" /> <PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.1.0"> <PackageReference Include="NUnit.Analyzers" Version="4.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2"> <PackageReference Include="coverlet.collector" Version="6.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -1,9 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Xml;
using DotRecast.Core.Buffers; using DotRecast.Core.Buffers;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization;
using NUnit.Framework; using NUnit.Framework;
namespace DotRecast.Core.Test; namespace DotRecast.Core.Test;
@ -59,50 +56,4 @@ public class RcRentedArrayTest
Assert.Throws<NullReferenceException>(() => rentedArray[^1] = 0); Assert.Throws<NullReferenceException>(() => rentedArray[^1] = 0);
} }
} }
[Test]
public void TestSame()
{
// not same
{
using var r1 = RcRentedArray.Rent<float>(1024);
using var r2 = RcRentedArray.Rent<float>(1024);
Assert.That(r2.AsArray() != r1.AsArray(), Is.EqualTo(true));
}
// same
{
// error case
float[] r1Array;
using (var r1 = RcRentedArray.Rent<float>(1024))
{
r1Array = r1.AsArray();
for (int i = 0; i < r1.Length; ++i)
{
r1[i] = 123;
}
}
using var r2 = RcRentedArray.Rent<float>(1024);
Assert.That(r2.AsArray() == r1Array, Is.EqualTo(true));
Assert.That(r2.AsArray().Sum(), Is.EqualTo(0));
}
}
[Test]
public void TestDispose()
{
var r1 = RcRentedArray.Rent<float>(1024);
for (int i = 0; i < r1.Length; ++i)
{
r1[i] = 123;
}
Assert.That(r1.IsDisposed, Is.EqualTo(false));
r1.Dispose();
Assert.That(r1.IsDisposed, Is.EqualTo(true));
Assert.That(r1.AsArray(), Is.Null);
}
} }

View File

@ -9,13 +9,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Moq" Version="4.20.70" /> <PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NUnit" Version="4.1.0" /> <PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.1.0"> <PackageReference Include="NUnit.Analyzers" Version="4.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2"> <PackageReference Include="coverlet.collector" Version="6.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -73,13 +73,13 @@ public class RecastTestMeshBuilder
RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
RcBuilder rcBuilder = new RcBuilder(); RcBuilder rcBuilder = new RcBuilder();
RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg); RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg);
RcPolyMesh m_pmesh = rcResult.Mesh; RcPolyMesh m_pmesh = rcResult.GetMesh();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {
m_pmesh.flags[i] = 1; m_pmesh.flags[i] = 1;
} }
RcPolyMeshDetail m_dmesh = rcResult.MeshDetail; RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
DtNavMeshCreateParams option = new DtNavMeshCreateParams(); DtNavMeshCreateParams option = new DtNavMeshCreateParams();
option.verts = m_pmesh.verts; option.verts = m_pmesh.verts;
option.vertCount = m_pmesh.nverts; option.vertCount = m_pmesh.nverts;

View File

@ -9,17 +9,17 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Moq" Version="4.20.70" /> <PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NUnit" Version="4.1.0" /> <PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.1.0"> <PackageReference Include="NUnit.Analyzers" Version="4.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2"> <PackageReference Include="coverlet.collector" Version="6.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" /> <PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -10,6 +10,7 @@ using NUnit.Framework;
namespace DotRecast.Detour.Dynamic.Test; namespace DotRecast.Detour.Dynamic.Test;
public class DynamicNavMeshTest public class DynamicNavMeshTest
{ {
private static readonly RcVec3f START_POS = new RcVec3f(70.87453f, 0.0010070801f, 86.69021f); private static readonly RcVec3f START_POS = new RcVec3f(70.87453f, 0.0010070801f, 86.69021f);
@ -31,7 +32,9 @@ public class DynamicNavMeshTest
// create dynamic navmesh // create dynamic navmesh
DtDynamicNavMesh mesh = new DtDynamicNavMesh(f); DtDynamicNavMesh mesh = new DtDynamicNavMesh(f);
// build navmesh asynchronously using multiple threads // build navmesh asynchronously using multiple threads
mesh.Build(Task.Factory); Task<bool> future = mesh.Build(Task.Factory);
// wait for build to complete
bool _ = future.Result;
// create new query // create new query
DtNavMeshQuery query = new DtNavMeshQuery(mesh.NavMesh()); DtNavMeshQuery query = new DtNavMeshQuery(mesh.NavMesh());
@ -51,8 +54,9 @@ public class DynamicNavMeshTest
long colliderId = mesh.AddCollider(colldier); long colliderId = mesh.AddCollider(colldier);
// update navmesh asynchronously // update navmesh asynchronously
mesh.Update(Task.Factory); future = mesh.Update(Task.Factory);
// wait for update to complete
_ = future.Result;
// create new query // create new query
query = new DtNavMeshQuery(mesh.NavMesh()); query = new DtNavMeshQuery(mesh.NavMesh());
@ -66,7 +70,9 @@ public class DynamicNavMeshTest
// remove obstacle // remove obstacle
mesh.RemoveCollider(colliderId); mesh.RemoveCollider(colliderId);
// update navmesh asynchronously // update navmesh asynchronously
mesh.Update(Task.Factory); future = mesh.Update(Task.Factory);
// wait for update to complete
_ = future.Result;
// create new query // create new query
query = new DtNavMeshQuery(mesh.NavMesh()); query = new DtNavMeshQuery(mesh.NavMesh());

View File

@ -31,6 +31,7 @@ using NUnit.Framework;
namespace DotRecast.Detour.Dynamic.Test; namespace DotRecast.Detour.Dynamic.Test;
public class VoxelQueryTest public class VoxelQueryTest
{ {
private const int TILE_WIDTH = 100; private const int TILE_WIDTH = 100;
@ -100,12 +101,12 @@ public class VoxelQueryTest
// load voxels from file // load voxels from file
DtVoxelFileReader reader = new DtVoxelFileReader(DtVoxelTileLZ4ForTestCompressor.Shared); DtVoxelFileReader reader = new DtVoxelFileReader(DtVoxelTileLZ4ForTestCompressor.Shared);
DtVoxelFile f = reader.Read(br); DtVoxelFile f = reader.Read(br);
// create dynamic navmesh // create dynamic navmesh
var mesh = new DtDynamicNavMesh(f); var mesh = new DtDynamicNavMesh(f);
// build navmesh asynchronously using multiple threads // build navmesh asynchronously using multiple threads
mesh.Build(Task.Factory); Task<bool> future = mesh.Build(Task.Factory);
// wait for build to complete
var _ = future.Result;
return mesh; return mesh;
} }
} }

View File

@ -9,13 +9,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Moq" Version="4.20.70" /> <PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NUnit" Version="4.1.0" /> <PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.1.0"> <PackageReference Include="NUnit.Analyzers" Version="4.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2"> <PackageReference Include="coverlet.collector" Version="6.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -9,13 +9,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Moq" Version="4.20.70" /> <PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NUnit" Version="4.1.0" /> <PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.1.0"> <PackageReference Include="NUnit.Analyzers" Version="4.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2"> <PackageReference Include="coverlet.collector" Version="6.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -73,13 +73,13 @@ public class RecastTestMeshBuilder
RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
RcBuilder rcBuilder = new RcBuilder(); RcBuilder rcBuilder = new RcBuilder();
RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg); RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg);
RcPolyMesh m_pmesh = rcResult.Mesh; RcPolyMesh m_pmesh = rcResult.GetMesh();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {
m_pmesh.flags[i] = 1; m_pmesh.flags[i] = 1;
} }
RcPolyMeshDetail m_dmesh = rcResult.MeshDetail; RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
DtNavMeshCreateParams option = new DtNavMeshCreateParams(); DtNavMeshCreateParams option = new DtNavMeshCreateParams();
option.verts = m_pmesh.verts; option.verts = m_pmesh.verts;
option.vertCount = m_pmesh.nverts; option.vertCount = m_pmesh.nverts;

View File

@ -28,7 +28,7 @@ public class TestDetourBuilder : DetourBuilder
{ {
RcBuilder rcBuilder = new RcBuilder(); RcBuilder rcBuilder = new RcBuilder();
RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig); RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig);
RcPolyMesh pmesh = rcResult.Mesh; RcPolyMesh pmesh = rcResult.GetMesh();
if (applyRecastDemoFlags) if (applyRecastDemoFlags)
{ {
@ -58,7 +58,7 @@ public class TestDetourBuilder : DetourBuilder
} }
} }
RcPolyMeshDetail dmesh = rcResult.MeshDetail; RcPolyMeshDetail dmesh = rcResult.GetMeshDetail();
DtNavMeshCreateParams option = GetNavMeshCreateParams(rcConfig.cfg, pmesh, dmesh, agentHeight, agentRadius, DtNavMeshCreateParams option = GetNavMeshCreateParams(rcConfig.cfg, pmesh, dmesh, agentHeight, agentRadius,
agentMaxClimb); agentMaxClimb);
return Build(option, x, y); return Build(option, x, y);

View File

@ -78,13 +78,13 @@ public class TestTiledNavMeshBuilder
true, true, true, true, true, true,
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RcBuilder rcBuilder = new RcBuilder(); RcBuilder rcBuilder = new RcBuilder();
List<RcBuilderResult> rcResult = rcBuilder.BuildTiles(geom, cfg, false, true); List<RcBuilderResult> rcResult = rcBuilder.BuildTiles(geom, cfg, null);
// Add tiles to nav mesh // Add tiles to nav mesh
foreach (RcBuilderResult result in rcResult) foreach (RcBuilderResult result in rcResult)
{ {
RcPolyMesh pmesh = result.Mesh; RcPolyMesh pmesh = result.GetMesh();
if (pmesh.npolys == 0) if (pmesh.npolys == 0)
{ {
continue; continue;
@ -103,7 +103,7 @@ public class TestTiledNavMeshBuilder
option.polyFlags = pmesh.flags; option.polyFlags = pmesh.flags;
option.polyCount = pmesh.npolys; option.polyCount = pmesh.npolys;
option.nvp = pmesh.nvp; option.nvp = pmesh.nvp;
RcPolyMeshDetail dmesh = result.MeshDetail; RcPolyMeshDetail dmesh = result.GetMeshDetail();
option.detailMeshes = dmesh.meshes; option.detailMeshes = dmesh.meshes;
option.detailVerts = dmesh.verts; option.detailVerts = dmesh.verts;
option.detailVertsCount = dmesh.nverts; option.detailVertsCount = dmesh.nverts;
@ -116,8 +116,8 @@ public class TestTiledNavMeshBuilder
option.bmax = pmesh.bmax; option.bmax = pmesh.bmax;
option.cs = cellSize; option.cs = cellSize;
option.ch = cellHeight; option.ch = cellHeight;
option.tileX = result.TileX; option.tileX = result.tileX;
option.tileZ = result.TileZ; option.tileZ = result.tileZ;
option.buildBvTree = true; option.buildBvTree = true;
navMesh.AddTile(DtNavMeshBuilder.CreateNavMeshData(option), 0, 0); navMesh.AddTile(DtNavMeshBuilder.CreateNavMeshData(option), 0, 0);
} }

View File

@ -9,17 +9,17 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Moq" Version="4.20.70" /> <PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NUnit" Version="4.1.0" /> <PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.1.0"> <PackageReference Include="NUnit.Analyzers" Version="4.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2"> <PackageReference Include="coverlet.collector" Version="6.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.8" /> <PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -9,13 +9,13 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Moq" Version="4.20.70" /> <PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NUnit" Version="4.1.0" /> <PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/> <PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.1.0"> <PackageReference Include="NUnit.Analyzers" Version="4.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2"> <PackageReference Include="coverlet.collector" Version="6.0.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -27,6 +27,7 @@ using NUnit.Framework;
namespace DotRecast.Recast.Test; namespace DotRecast.Recast.Test;
public class RecastTileMeshTest public class RecastTileMeshTest
{ {
private const float m_cellSize = 0.3f; private const float m_cellSize = 0.3f;
@ -70,28 +71,28 @@ public class RecastTileMeshTest
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8);
RcBuilderResult rcResult = builder.Build(geom, bcfg); RcBuilderResult rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(1)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(7)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(9)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(3)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(17)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
} }
[Test] [Test]
@ -137,27 +138,28 @@ public class RecastTileMeshTest
private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate) private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate)
{ {
CancellationTokenSource cts = new CancellationTokenSource(); CancellationTokenSource cts = new CancellationTokenSource();
List<RcBuilderResult> tiles = builder.BuildTiles(geom, cfg, false, true, threads, Task.Factory, cts.Token); List<RcBuilderResult> tiles = new();
var task = builder.BuildTilesAsync(geom, cfg, threads, tiles, Task.Factory, cts.Token);
if (validate) if (validate)
{ {
RcBuilderResult rcResult = GetTile(tiles, 7, 8); RcBuilderResult rcResult = GetTile(tiles, 7, 8);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(1)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
rcResult = GetTile(tiles, 6, 9); rcResult = GetTile(tiles, 6, 9);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(7)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
rcResult = GetTile(tiles, 2, 9); rcResult = GetTile(tiles, 2, 9);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(9)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
rcResult = GetTile(tiles, 4, 3); rcResult = GetTile(tiles, 4, 3);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(3)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
rcResult = GetTile(tiles, 2, 8); rcResult = GetTile(tiles, 2, 8);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(17)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
rcResult = GetTile(tiles, 0, 8); rcResult = GetTile(tiles, 0, 8);
Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
} }
try try
@ -173,6 +175,6 @@ public class RecastTileMeshTest
private RcBuilderResult GetTile(List<RcBuilderResult> tiles, int x, int z) private RcBuilderResult GetTile(List<RcBuilderResult> tiles, int x, int z)
{ {
return tiles.FirstOrDefault(tile => tile.TileX == x && tile.TileZ == z); return tiles.FirstOrDefault(tile => tile.tileX == x && tile.tileZ == z);
} }
} }