diff --git a/.editorconfig b/.editorconfig index 37ea066..614fb8a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -20,6 +20,7 @@ dotnet_sort_system_directives_first = true csharp_preserve_single_line_statements = false csharp_preserve_single_line_blocks = true -# +# ReSharper properties +resharper_csharp_wrap_lines = false resharper_csharp_space_before_trailing_comment = true resharper_csharp_space_after_operator_keyword = true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1001d74..0093ad1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -49,7 +49,7 @@ jobs: uses: actions/checkout@v4 - name: Set up .NET 8.0 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: 8.x diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 972fa7a..af233a5 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -37,7 +37,7 @@ jobs: fetch-depth: 0 # Get all history to allow automatic versioning using MinVer - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ matrix.dotnet-version }}.x diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index a849a60..f00fc9f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,7 +33,7 @@ jobs: fetch-depth: 0 # Get all history to allow automatic versioning using MinVer - name: Setup Dotnet - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.x' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7f14ed1..2e75fbe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: fetch-depth: 0 # Get all history to allow automatic versioning using MinVer - name: Setup Dotnet - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.x' diff --git a/src/DotRecast.Core/IRcRand.cs b/src/DotRecast.Core/IRcRand.cs index 499e14c..15e810a 100644 --- a/src/DotRecast.Core/IRcRand.cs +++ b/src/DotRecast.Core/IRcRand.cs @@ -3,5 +3,7 @@ public interface IRcRand { float Next(); + double NextDouble(); + int NextInt32(); } } \ No newline at end of file diff --git a/src/DotRecast.Core/RcRand.cs b/src/DotRecast.Core/RcRand.cs index 279590a..6111aff 100644 --- a/src/DotRecast.Core/RcRand.cs +++ b/src/DotRecast.Core/RcRand.cs @@ -6,9 +6,13 @@ namespace DotRecast.Core { private readonly Random _r; - public RcRand() + public RcRand() : this(new Random()) { - _r = new Random(); + } + + public RcRand(Random r) + { + _r = r; } public RcRand(long seed) @@ -21,6 +25,11 @@ namespace DotRecast.Core return (float)_r.NextDouble(); } + public double NextDouble() + { + return _r.NextDouble(); + } + public int NextInt32() { return _r.Next(); diff --git a/src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs b/src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs index a8a4aee..dc40c41 100644 --- a/src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs +++ b/src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs @@ -40,7 +40,7 @@ namespace DotRecast.Detour.Dynamic private readonly BlockingCollection updateQueue = new BlockingCollection(); private readonly RcAtomicLong currentColliderId = new RcAtomicLong(0); private DtNavMesh _navMesh; - private bool dirty = true; + private bool _dirty = true; public DtDynamicNavMesh(DtVoxelFile voxelFile) { @@ -105,29 +105,6 @@ namespace DotRecast.Detour.Dynamic 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 stream) - { - foreach (var dynamicTile in stream) - Rebuild(dynamicTile); - return UpdateNavMesh(); - } private HashSet ProcessQueue() { @@ -159,27 +136,49 @@ namespace DotRecast.Detour.Dynamic } } - /** - * Perform full build concurrently using the given {@link ExecutorService} - */ - public Task Build(TaskFactory executor) + // Perform full build of the navmesh + public void Build() + { + ProcessQueue(); + Rebuild(_tiles.Values); + } + + // Perform full build concurrently using the given {@link ExecutorService} + public bool Build(TaskFactory executor) { ProcessQueue(); return Rebuild(_tiles.Values, executor); } - /** - * Perform incremental update concurrently using the given {@link ExecutorService} - */ - public Task Update(TaskFactory executor) + + // Perform incremental update of the navmesh + public bool Update() + { + return Rebuild(ProcessQueue()); + } + + // Perform incremental update concurrently using the given {@link ExecutorService} + public bool Update(TaskFactory executor) { return Rebuild(ProcessQueue(), executor); } - private Task Rebuild(ICollection tiles, TaskFactory executor) + private bool Rebuild(ICollection tiles) { - var tasks = tiles.Select(tile => executor.StartNew(() => Rebuild(tile))).ToArray(); - return Task.WhenAll(tasks).ContinueWith(k => UpdateNavMesh()); + foreach (var tile in tiles) + Rebuild(tile); + + return UpdateNavMesh(); + } + + private bool Rebuild(ICollection tiles, TaskFactory executor) + { + var tasks = tiles + .Select(tile => executor.StartNew(() => Rebuild(tile))) + .ToArray(); + + Task.WaitAll(tasks); + return UpdateNavMesh(); } private ICollection GetTiles(float[] bounds) @@ -218,19 +217,19 @@ namespace DotRecast.Detour.Dynamic { DtNavMeshCreateParams option = new DtNavMeshCreateParams(); option.walkableHeight = config.walkableHeight; - dirty = dirty | tile.Build(builder, config, _context); + _dirty = _dirty | tile.Build(builder, config, _context); } private bool UpdateNavMesh() { - if (dirty) + if (_dirty) { DtNavMesh navMesh = new DtNavMesh(navMeshParams, MAX_VERTS_PER_POLY); foreach (var t in _tiles.Values) t.AddTo(navMesh); - this._navMesh = navMesh; - dirty = false; + _navMesh = navMesh; + _dirty = false; return true; } diff --git a/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs b/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs index 82fb905..4f31dcd 100644 --- a/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs +++ b/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs @@ -100,7 +100,7 @@ namespace DotRecast.Detour.Dynamic Math.Min(DtDynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly), config.detailSampleDistance, config.detailSampleMaxError, true, true, true, default, true); - RcBuilderResult r = builder.Build(context, vt.tileX, vt.tileZ, null, rcConfig, heightfield); + RcBuilderResult r = builder.Build(context, vt.tileX, vt.tileZ, null, rcConfig, heightfield, false); if (config.keepIntermediateResults) { recastResult = r; @@ -132,8 +132,8 @@ namespace DotRecast.Detour.Dynamic private DtNavMeshCreateParams NavMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight, DtDynamicNavMeshConfig config, RcBuilderResult rcResult) { - RcPolyMesh m_pmesh = rcResult.GetMesh(); - RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail(); + RcPolyMesh m_pmesh = rcResult.Mesh; + RcPolyMeshDetail m_dmesh = rcResult.MeshDetail; DtNavMeshCreateParams option = new DtNavMeshCreateParams(); for (int i = 0; i < m_pmesh.npolys; ++i) { diff --git a/src/DotRecast.Detour.Dynamic/Io/DtVoxelFile.cs b/src/DotRecast.Detour.Dynamic/Io/DtVoxelFile.cs index 9f53c59..70b15c6 100644 --- a/src/DotRecast.Detour.Dynamic/Io/DtVoxelFile.cs +++ b/src/DotRecast.Detour.Dynamic/Io/DtVoxelFile.cs @@ -109,13 +109,13 @@ namespace DotRecast.Detour.Dynamic.Io }; foreach (RcBuilderResult r in results) { - f.tiles.Add(new DtVoxelTile(r.tileX, r.tileZ, r.GetSolidHeightfield())); - f.bounds[0] = Math.Min(f.bounds[0], r.GetSolidHeightfield().bmin.X); - f.bounds[1] = Math.Min(f.bounds[1], r.GetSolidHeightfield().bmin.Y); - f.bounds[2] = Math.Min(f.bounds[2], r.GetSolidHeightfield().bmin.Z); - f.bounds[3] = Math.Max(f.bounds[3], r.GetSolidHeightfield().bmax.X); - f.bounds[4] = Math.Max(f.bounds[4], r.GetSolidHeightfield().bmax.Y); - f.bounds[5] = Math.Max(f.bounds[5], r.GetSolidHeightfield().bmax.Z); + f.tiles.Add(new DtVoxelTile(r.TileX, r.TileZ, r.SolidHeightfiled)); + f.bounds[0] = Math.Min(f.bounds[0], r.SolidHeightfiled.bmin.X); + f.bounds[1] = Math.Min(f.bounds[1], r.SolidHeightfiled.bmin.Y); + f.bounds[2] = Math.Min(f.bounds[2], r.SolidHeightfiled.bmin.Z); + f.bounds[3] = Math.Max(f.bounds[3], r.SolidHeightfiled.bmax.X); + f.bounds[4] = Math.Max(f.bounds[4], r.SolidHeightfiled.bmax.Y); + f.bounds[5] = Math.Max(f.bounds[5], r.SolidHeightfiled.bmax.Z); } return f; diff --git a/src/DotRecast.Detour.Extras/Jumplink/JumpLinkBuilder.cs b/src/DotRecast.Detour.Extras/Jumplink/JumpLinkBuilder.cs index dc8da9c..8550fa6 100644 --- a/src/DotRecast.Detour.Extras/Jumplink/JumpLinkBuilder.cs +++ b/src/DotRecast.Detour.Extras/Jumplink/JumpLinkBuilder.cs @@ -21,7 +21,7 @@ namespace DotRecast.Detour.Extras.Jumplink public JumpLinkBuilder(IList results) { this.results = results; - edges = results.Select(r => edgeExtractor.ExtractEdges(r.GetMesh())).ToList(); + edges = results.Select(r => edgeExtractor.ExtractEdges(r.Mesh)).ToList(); } public List Build(JumpLinkBuilderConfig acfg, JumpLinkType type) @@ -43,7 +43,7 @@ namespace DotRecast.Detour.Extras.Jumplink { EdgeSampler es = edgeSamplerFactory.Get(acfg, type, edge); groundSampler.Sample(acfg, result, es); - trajectorySampler.Sample(acfg, result.GetSolidHeightfield(), es); + trajectorySampler.Sample(acfg, result.SolidHeightfiled, es); JumpSegment[] jumpSegments = jumpSegmentBuilder.Build(acfg, es); return BuildJumpLinks(acfg, es, jumpSegments); } diff --git a/src/DotRecast.Detour.Extras/Jumplink/NavMeshGroundSampler.cs b/src/DotRecast.Detour.Extras/Jumplink/NavMeshGroundSampler.cs index 870a192..a48e819 100644 --- a/src/DotRecast.Detour.Extras/Jumplink/NavMeshGroundSampler.cs +++ b/src/DotRecast.Detour.Extras/Jumplink/NavMeshGroundSampler.cs @@ -16,25 +16,25 @@ namespace DotRecast.Detour.Extras.Jumplink private DtNavMeshQuery CreateNavMesh(RcBuilderResult r, float agentRadius, float agentHeight, float agentClimb) { DtNavMeshCreateParams option = new DtNavMeshCreateParams(); - option.verts = r.GetMesh().verts; - option.vertCount = r.GetMesh().nverts; - option.polys = r.GetMesh().polys; - option.polyAreas = r.GetMesh().areas; - option.polyFlags = r.GetMesh().flags; - option.polyCount = r.GetMesh().npolys; - option.nvp = r.GetMesh().nvp; - option.detailMeshes = r.GetMeshDetail().meshes; - option.detailVerts = r.GetMeshDetail().verts; - option.detailVertsCount = r.GetMeshDetail().nverts; - option.detailTris = r.GetMeshDetail().tris; - option.detailTriCount = r.GetMeshDetail().ntris; + option.verts = r.Mesh.verts; + option.vertCount = r.Mesh.nverts; + option.polys = r.Mesh.polys; + option.polyAreas = r.Mesh.areas; + option.polyFlags = r.Mesh.flags; + option.polyCount = r.Mesh.npolys; + option.nvp = r.Mesh.nvp; + option.detailMeshes = r.MeshDetail.meshes; + option.detailVerts = r.MeshDetail.verts; + option.detailVertsCount = r.MeshDetail.nverts; + option.detailTris = r.MeshDetail.tris; + option.detailTriCount = r.MeshDetail.ntris; option.walkableRadius = agentRadius; option.walkableHeight = agentHeight; option.walkableClimb = agentClimb; - option.bmin = r.GetMesh().bmin; - option.bmax = r.GetMesh().bmax; - option.cs = r.GetMesh().cs; - option.ch = r.GetMesh().ch; + option.bmin = r.Mesh.bmin; + option.bmax = r.Mesh.bmax; + option.cs = r.Mesh.cs; + option.ch = r.Mesh.ch; option.buildBvTree = true; return new DtNavMeshQuery(new DtNavMesh(DtNavMeshBuilder.CreateNavMeshData(option), option.nvp, 0)); } diff --git a/src/DotRecast.Detour/DtNavMesh.cs b/src/DotRecast.Detour/DtNavMesh.cs index 2f0c8d4..a0a162f 100644 --- a/src/DotRecast.Detour/DtNavMesh.cs +++ b/src/DotRecast.Detour/DtNavMesh.cs @@ -359,8 +359,8 @@ namespace DotRecast.Detour var tbmax = tile.data.header.bmax; float qfac = tile.data.header.bvQuantFactor; // Calculate quantized box - int[] bmin = new int[3]; - int[] bmax = new int[3]; + Span bmin = stackalloc int[3]; + Span bmax = stackalloc int[3]; // 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; diff --git a/src/DotRecast.Detour/DtNavMeshQuery.cs b/src/DotRecast.Detour/DtNavMeshQuery.cs index bc7eab5..5eb8e92 100644 --- a/src/DotRecast.Detour/DtNavMeshQuery.cs +++ b/src/DotRecast.Detour/DtNavMeshQuery.cs @@ -584,8 +584,8 @@ namespace DotRecast.Detour var tbmax = tile.data.header.bmax; float qfac = tile.data.header.bvQuantFactor; // Calculate quantized box - int[] bmin = new int[3]; - int[] bmax = new int[3]; + Span bmin = stackalloc int[3]; + Span bmax = stackalloc int[3]; // 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; @@ -1827,6 +1827,9 @@ namespace DotRecast.Detour using var verts = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly() * 3); + const int MAX_NEIS = 8; + Span neis = stackalloc long[MAX_NEIS]; + while (0 < stack.Count) { // Pop front. @@ -1857,9 +1860,7 @@ namespace DotRecast.Detour for (int i = 0, j = curPoly.vertCount - 1; i < curPoly.vertCount; j = i++) { // Find links to neighbours. - int MAX_NEIS = 8; int nneis = 0; - using var neis = RcRentedArray.Rent(MAX_NEIS); if ((curPoly.neis[j] & DtNavMesh.DT_EXT_LINK) != 0) { diff --git a/src/DotRecast.Detour/DtUtils.cs b/src/DotRecast.Detour/DtUtils.cs index 894710b..91644e5 100644 --- a/src/DotRecast.Detour/DtUtils.cs +++ b/src/DotRecast.Detour/DtUtils.cs @@ -64,7 +64,7 @@ namespace DotRecast.Detour /// @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(int[] amin, int[] amax, int[] bmin, int[] bmax) + public static bool OverlapQuantBounds(Span amin, Span amax, Span bmin, Span bmax) { bool overlap = true; overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap; diff --git a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj index f293537..b231327 100644 --- a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj +++ b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj @@ -26,9 +26,9 @@ - - - + + + diff --git a/src/DotRecast.Recast.Demo/Draw/GLCheckerTexture.cs b/src/DotRecast.Recast.Demo/Draw/GLCheckerTexture.cs index 061ab23..e044757 100644 --- a/src/DotRecast.Recast.Demo/Draw/GLCheckerTexture.cs +++ b/src/DotRecast.Recast.Demo/Draw/GLCheckerTexture.cs @@ -32,15 +32,18 @@ public class GLCheckerTexture _gl = gl; } - public void Release() + public unsafe void Release() { if (m_texId != 0) { - _gl.DeleteTextures(1, m_texId); + fixed (uint* p = &m_texId) + { + _gl.DeleteTextures(1, p); + } } } - public void Bind() + public unsafe void Bind() { if (m_texId == 0) { @@ -50,7 +53,11 @@ public class GLCheckerTexture uint TSIZE = 64; int[] data = new int[TSIZE * TSIZE]; - _gl.GenTextures(1, out m_texId); + fixed (uint* p = &m_texId) + { + _gl.GenTextures(1, p); + } + _gl.BindTexture(GLEnum.Texture2D, m_texId); int level = 0; @@ -70,8 +77,10 @@ public class GLCheckerTexture level++; } - _gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMinFilter, (uint)GLEnum.LinearMipmapNearest); - _gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMagFilter, (uint)GLEnum.Linear); + uint linearMipmapNearest = (uint)GLEnum.LinearMipmapNearest; + uint linear = (uint)GLEnum.Linear; + _gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMinFilter, &linearMipmapNearest); + _gl.TexParameterI(GLEnum.Texture2D, GLEnum.TextureMagFilter, &linear); } else { diff --git a/src/DotRecast.Recast.Demo/Draw/NavMeshRenderer.cs b/src/DotRecast.Recast.Demo/Draw/NavMeshRenderer.cs index 352d7bf..14562b0 100644 --- a/src/DotRecast.Recast.Demo/Draw/NavMeshRenderer.cs +++ b/src/DotRecast.Recast.Demo/Draw/NavMeshRenderer.cs @@ -123,80 +123,80 @@ public class NavMeshRenderer foreach (RcBuilderResult rcBuilderResult in rcBuilderResults) { - if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT) + if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT) { - _debugDraw.DebugDrawCompactHeightfieldSolid(rcBuilderResult.GetCompactHeightfield()); + _debugDraw.DebugDrawCompactHeightfieldSolid(rcBuilderResult.CompactHeightfield); } - if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_DISTANCE) + if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT_DISTANCE) { - _debugDraw.DebugDrawCompactHeightfieldDistance(rcBuilderResult.GetCompactHeightfield()); + _debugDraw.DebugDrawCompactHeightfieldDistance(rcBuilderResult.CompactHeightfield); } - if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT_REGIONS) + if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_COMPACT_REGIONS) { - _debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield()); + _debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.CompactHeightfield); } - if (rcBuilderResult.GetSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS) + if (rcBuilderResult.SolidHeightfiled != null && drawMode == DrawMode.DRAWMODE_VOXELS) { _debugDraw.Fog(true); - _debugDraw.DebugDrawHeightfieldSolid(rcBuilderResult.GetSolidHeightfield()); + _debugDraw.DebugDrawHeightfieldSolid(rcBuilderResult.SolidHeightfiled); _debugDraw.Fog(false); } - if (rcBuilderResult.GetSolidHeightfield() != null && drawMode == DrawMode.DRAWMODE_VOXELS_WALKABLE) + if (rcBuilderResult.SolidHeightfiled != null && drawMode == DrawMode.DRAWMODE_VOXELS_WALKABLE) { _debugDraw.Fog(true); - _debugDraw.DebugDrawHeightfieldWalkable(rcBuilderResult.GetSolidHeightfield()); + _debugDraw.DebugDrawHeightfieldWalkable(rcBuilderResult.SolidHeightfiled); _debugDraw.Fog(false); } - if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_RAW_CONTOURS) + if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_RAW_CONTOURS) { _debugDraw.DepthMask(false); - _debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 1f); + _debugDraw.DebugDrawRawContours(rcBuilderResult.ContourSet, 1f); _debugDraw.DepthMask(true); } - if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_BOTH_CONTOURS) + if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_BOTH_CONTOURS) { _debugDraw.DepthMask(false); - _debugDraw.DebugDrawRawContours(rcBuilderResult.GetContourSet(), 0.5f); - _debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet()); + _debugDraw.DebugDrawRawContours(rcBuilderResult.ContourSet, 0.5f); + _debugDraw.DebugDrawContours(rcBuilderResult.ContourSet); _debugDraw.DepthMask(true); } - if (rcBuilderResult.GetContourSet() != null && drawMode == DrawMode.DRAWMODE_CONTOURS) + if (rcBuilderResult.ContourSet != null && drawMode == DrawMode.DRAWMODE_CONTOURS) { _debugDraw.DepthMask(false); - _debugDraw.DebugDrawContours(rcBuilderResult.GetContourSet()); + _debugDraw.DebugDrawContours(rcBuilderResult.ContourSet); _debugDraw.DepthMask(true); } - if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_REGION_CONNECTIONS) + if (rcBuilderResult.CompactHeightfield != null && drawMode == DrawMode.DRAWMODE_REGION_CONNECTIONS) { - _debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.GetCompactHeightfield()); + _debugDraw.DebugDrawCompactHeightfieldRegions(rcBuilderResult.CompactHeightfield); _debugDraw.DepthMask(false); - if (rcBuilderResult.GetContourSet() != null) + if (rcBuilderResult.ContourSet != null) { - _debugDraw.DebugDrawRegionConnections(rcBuilderResult.GetContourSet()); + _debugDraw.DebugDrawRegionConnections(rcBuilderResult.ContourSet); } _debugDraw.DepthMask(true); } - if (rcBuilderResult.GetMesh() != null && drawMode == DrawMode.DRAWMODE_POLYMESH) + if (rcBuilderResult.Mesh != null && drawMode == DrawMode.DRAWMODE_POLYMESH) { _debugDraw.DepthMask(false); - _debugDraw.DebugDrawPolyMesh(rcBuilderResult.GetMesh()); + _debugDraw.DebugDrawPolyMesh(rcBuilderResult.Mesh); _debugDraw.DepthMask(true); } - if (rcBuilderResult.GetMeshDetail() != null && drawMode == DrawMode.DRAWMODE_POLYMESH_DETAIL) + if (rcBuilderResult.MeshDetail != null && drawMode == DrawMode.DRAWMODE_POLYMESH_DETAIL) { _debugDraw.DepthMask(false); - _debugDraw.DebugDrawPolyMeshDetail(rcBuilderResult.GetMeshDetail()); + _debugDraw.DebugDrawPolyMeshDetail(rcBuilderResult.MeshDetail); _debugDraw.DepthMask(true); } } diff --git a/src/DotRecast.Recast.Demo/RecastDemo.cs b/src/DotRecast.Recast.Demo/RecastDemo.cs index e56a5da..fbddfe9 100644 --- a/src/DotRecast.Recast.Demo/RecastDemo.cs +++ b/src/DotRecast.Recast.Demo/RecastDemo.cs @@ -368,7 +368,7 @@ public class RecastDemo : IRecastDemoChannel var scale = (float)_resolution.X / 1920; int fontSize = Math.Max(10, (int)(16 * scale)); - + // for windows : Microsoft Visual C++ Redistributable Package // 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); @@ -379,7 +379,7 @@ public class RecastDemo : IRecastDemoChannel DemoInputGeomProvider geom = LoadInputMesh("nav_test.obj"); _sample = new DemoSample(geom, ImmutableArray.Empty, null); - + _menuView = new RcMenuView(); settingsView = new RcSettingsView(this); settingsView.SetSample(_sample); @@ -537,6 +537,7 @@ public class RecastDemo : IRecastDemoChannel bool hasBound = false; RcVec3f bminN = RcVec3f.Zero; RcVec3f bmaxN = RcVec3f.Zero; + if (_sample.GetInputGeom() != null) { bminN = _sample.GetInputGeom().GetMeshBoundsMin(); @@ -552,7 +553,7 @@ public class RecastDemo : IRecastDemoChannel { foreach (RcBuilderResult result in _sample.GetRecastResults()) { - if (result.GetSolidHeightfield() != null) + if (result.CompactHeightfield != null) { if (!hasBound) { @@ -561,15 +562,15 @@ public class RecastDemo : IRecastDemoChannel } bminN = new RcVec3f( - Math.Min(bminN.X, result.GetSolidHeightfield().bmin.X), - Math.Min(bminN.Y, result.GetSolidHeightfield().bmin.Y), - Math.Min(bminN.Z, result.GetSolidHeightfield().bmin.Z) + Math.Min(bminN.X, result.CompactHeightfield.bmin.X), + Math.Min(bminN.Y, result.CompactHeightfield.bmin.Y), + Math.Min(bminN.Z, result.CompactHeightfield.bmin.Z) ); bmaxN = new RcVec3f( - Math.Max(bmaxN.X, result.GetSolidHeightfield().bmax.X), - Math.Max(bmaxN.Y, result.GetSolidHeightfield().bmax.Y), - Math.Max(bmaxN.Z, result.GetSolidHeightfield().bmax.Z) + Math.Max(bmaxN.X, result.CompactHeightfield.bmax.X), + Math.Max(bmaxN.Y, result.CompactHeightfield.bmax.Y), + Math.Max(bmaxN.Z, result.CompactHeightfield.bmax.Z) ); hasBound = true; @@ -577,12 +578,15 @@ public class RecastDemo : IRecastDemoChannel } } + // Reset camera and fog to match the mesh bounds. if (hasBound) { RcVec3f bmin = bminN; RcVec3f bmax = bmaxN; - camr = (float)(Math.Sqrt(RcMath.Sqr(bmax.X - bmin.X) + RcMath.Sqr(bmax.Y - bmin.Y) + RcMath.Sqr(bmax.Z - bmin.Z)) / 2); + camr = (float)(Math.Sqrt(RcMath.Sqr(bmax.X - bmin.X) + + RcMath.Sqr(bmax.Y - bmin.Y) + + RcMath.Sqr(bmax.Z - bmin.Z)) / 2); cameraPos.X = (bmax.X + bmin.X) / 2 + camr; cameraPos.Y = (bmax.Y + bmin.Y) / 2 + camr; cameraPos.Z = (bmax.Z + bmin.Z) / 2 + camr; @@ -688,14 +692,15 @@ public class RecastDemo : IRecastDemoChannel NavMeshBuildResult buildResult; + var geom = _sample.GetInputGeom(); var settings = _sample.GetSettings(); if (settings.tiled) { - buildResult = tileNavMeshBuilder.Build(_sample.GetInputGeom(), settings); + buildResult = tileNavMeshBuilder.Build(geom, settings); } else { - buildResult = soloNavMeshBuilder.Build(_sample.GetInputGeom(), settings); + buildResult = soloNavMeshBuilder.Build(geom, settings); } if (!buildResult.Success) @@ -713,7 +718,7 @@ public class RecastDemo : IRecastDemoChannel Logger.Information($"build times"); Logger.Information($"-----------------------------------------"); var telemetries = buildResult.RecastBuilderResults - .Select(x => x.GetTelemetry()) + .Select(x => x.Context) .SelectMany(x => x.ToList()) .GroupBy(x => x.Key) .ToImmutableSortedDictionary(x => x.Key, x => x.Sum(y => y.Millis)); diff --git a/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs index 9121213..4d6c3d6 100644 --- a/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs @@ -91,7 +91,7 @@ public class DynamicUpdateSampleTool : ISampleTool var bridgeGeom = DemoInputGeomProvider.LoadFile("bridge.obj"); var houseGeom = DemoInputGeomProvider.LoadFile("house.obj"); var convexGeom = DemoInputGeomProvider.LoadFile("convex.obj"); - _tool = new(Random.Shared, bridgeGeom, houseGeom, convexGeom); + _tool = new(new RcRand(Random.Shared), bridgeGeom, houseGeom, convexGeom); executor = Task.Factory; } @@ -406,7 +406,7 @@ public class DynamicUpdateSampleTool : ISampleTool long t = RcFrequency.Ticks; try { - bool updated = _tool.UpdateDynaMesh(executor); + bool updated = _tool.Update(executor); if (updated) { buildTime = (RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond; @@ -450,7 +450,7 @@ public class DynamicUpdateSampleTool : ISampleTool long t = RcFrequency.Ticks; try { - var _ = dynaMesh.Build(executor).Result; + var _ = dynaMesh.Build(executor); } catch (Exception e) { diff --git a/src/DotRecast.Recast.Demo/Tools/JumpLinkBuilderSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/JumpLinkBuilderSampleTool.cs index 7a33b6b..4b31c47 100644 --- a/src/DotRecast.Recast.Demo/Tools/JumpLinkBuilderSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/JumpLinkBuilderSampleTool.cs @@ -16,6 +16,7 @@ freely, subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ +using System.Linq; using DotRecast.Core.Numerics; using DotRecast.Detour.Extras.Jumplink; using DotRecast.Recast.Demo.Draw; @@ -96,13 +97,25 @@ public class JumpLinkBuilderSampleTool : ISampleTool if (build || _cfg.buildOffMeshConnections) { - if (0 < _sample.GetRecastResults().Count) + do { + 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 settings = _sample.GetSettings(); _tool.Build(geom, settings, _sample.GetRecastResults(), _cfg); - } + } while (false); } ImGui.NewLine(); diff --git a/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs b/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs index 50f69c0..5ca0de5 100644 --- a/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs +++ b/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs @@ -166,6 +166,10 @@ public class RcSettingsView : IRcView ImGui.SliderFloat("Max Sample Error", ref settings.detailSampleMaxError, 0f, 16f, "%.1f"); ImGui.NewLine(); + ImGui.Checkbox("Keep Itermediate Results", ref settings.keepInterResults); + ImGui.Checkbox("Build All Tiles", ref settings.buildAll); + ImGui.NewLine(); + ImGui.Text("Tiling"); ImGui.Separator(); ImGui.Checkbox("Enable", ref settings.tiled); @@ -228,6 +232,12 @@ public class RcSettingsView : IRcView DrawMode.Values.ForEach(dm => { ImGui.RadioButton(dm.Text, ref drawMode, dm.Idx); }); 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(); } @@ -262,4 +272,4 @@ public class RcSettingsView : IRcView { this.maxPolys = maxPolys; } -} +} \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Builder/DemoNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/DemoNavMeshBuilder.cs index 7cb6fe8..6afbd0d 100644 --- a/src/DotRecast.Recast.Toolset/Builder/DemoNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/DemoNavMeshBuilder.cs @@ -10,8 +10,8 @@ namespace DotRecast.Recast.Toolset.Builder float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb, RcBuilderResult rcResult) { - RcPolyMesh pmesh = rcResult.GetMesh(); - RcPolyMeshDetail dmesh = rcResult.GetMeshDetail(); + RcPolyMesh pmesh = rcResult.Mesh; + RcPolyMeshDetail dmesh = rcResult.MeshDetail; DtNavMeshCreateParams option = new DtNavMeshCreateParams(); for (int i = 0; i < pmesh.npolys; ++i) { diff --git a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs index ab145f6..10b4c09 100644 --- a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs @@ -34,7 +34,8 @@ namespace DotRecast.Recast.Toolset.Builder settings.edgeMaxLen, settings.edgeMaxError, settings.vertsPerPoly, settings.detailSampleDist, settings.detailSampleMaxError, - settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans); + settings.filterLowHangingObstacles, settings.filterLedgeSpans, settings.filterWalkableLowHeightSpans, + settings.keepInterResults); } public NavMeshBuildResult Build(DemoInputGeomProvider geom, @@ -45,7 +46,8 @@ namespace DotRecast.Recast.Toolset.Builder float edgeMaxLen, float edgeMaxError, int vertsPerPoly, float detailSampleDist, float detailSampleMaxError, - bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans) + bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans, + bool keepInterResults) { RcConfig cfg = new RcConfig( partitionType, @@ -58,7 +60,7 @@ namespace DotRecast.Recast.Toolset.Builder filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); - RcBuilderResult rcResult = BuildRecastResult(geom, cfg); + RcBuilderResult rcResult = BuildRecastResult(geom, cfg, keepInterResults); var meshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult); if (null == meshData) { @@ -74,11 +76,11 @@ namespace DotRecast.Recast.Toolset.Builder return new DtNavMesh(meshData, vertsPerPoly, 0); } - private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg) + private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg, bool keepInterResults) { RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); - return rcBuilder.Build(geom, bcfg); + return rcBuilder.Build(geom, bcfg, keepInterResults); } public DtMeshData BuildMeshData(DemoInputGeomProvider geom, diff --git a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs index f73fbc9..5542c25 100644 --- a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs @@ -41,7 +41,8 @@ namespace DotRecast.Recast.Toolset.Builder settings.minRegionSize, settings.mergedRegionSize, settings.edgeMaxLen, settings.edgeMaxError, 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, @@ -53,7 +54,8 @@ namespace DotRecast.Recast.Toolset.Builder float edgeMaxLen, float edgeMaxError, int vertsPerPoly, float detailSampleDist, float detailSampleMaxError, - bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans) + bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans, + bool keepInterResults, bool buildAll) { List results = BuildRecastResult( geom, @@ -65,7 +67,8 @@ namespace DotRecast.Recast.Toolset.Builder edgeMaxLen, edgeMaxError, vertsPerPoly, detailSampleDist, detailSampleMaxError, - filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans + filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, + keepInterResults, buildAll ); var tileMeshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, results); @@ -82,7 +85,8 @@ namespace DotRecast.Recast.Toolset.Builder float edgeMaxLen, float edgeMaxError, int vertsPerPoly, 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, @@ -97,7 +101,7 @@ namespace DotRecast.Recast.Toolset.Builder filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); RcBuilder rcBuilder = new RcBuilder(); - return rcBuilder.BuildTiles(geom, cfg, Task.Factory); + return rcBuilder.BuildTiles(geom, cfg, keepInterResults, buildAll, Environment.ProcessorCount + 1, Task.Factory); } public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List meshData, float cellSize, int tileSize, int vertsPerPoly) @@ -123,10 +127,9 @@ namespace DotRecast.Recast.Toolset.Builder List meshData = new List(); foreach (RcBuilderResult result in results) { - int x = result.tileX; - int z = result.tileZ; - DtNavMeshCreateParams option = DemoNavMeshBuilder - .GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result); + int x = result.TileX; + int z = result.TileZ; + DtNavMeshCreateParams option = DemoNavMeshBuilder.GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result); option.tileX = x; option.tileZ = z; diff --git a/src/DotRecast.Recast.Toolset/RcNavMeshBuildSettings.cs b/src/DotRecast.Recast.Toolset/RcNavMeshBuildSettings.cs index e0b6906..86d9df6 100644 --- a/src/DotRecast.Recast.Toolset/RcNavMeshBuildSettings.cs +++ b/src/DotRecast.Recast.Toolset/RcNavMeshBuildSettings.cs @@ -31,5 +31,8 @@ public bool tiled = false; public int tileSize = 32; + + public bool keepInterResults = false; + public bool buildAll = true; } } \ No newline at end of file diff --git a/src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs b/src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs index 6900279..83cc474 100644 --- a/src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs +++ b/src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs @@ -18,12 +18,12 @@ namespace DotRecast.Recast.Toolset.Tools private DtDynamicNavMesh dynaMesh; private readonly Dictionary colliderGizmos; - private readonly Random random; + private readonly IRcRand random; private readonly DemoInputGeomProvider bridgeGeom; private readonly DemoInputGeomProvider houseGeom; private readonly DemoInputGeomProvider convexGeom; - public RcDynamicUpdateTool(Random rand, DemoInputGeomProvider bridgeGeom, DemoInputGeomProvider houseGeom, DemoInputGeomProvider convexGeom) + public RcDynamicUpdateTool(IRcRand rand, DemoInputGeomProvider bridgeGeom, DemoInputGeomProvider houseGeom, DemoInputGeomProvider convexGeom) { this.colliderGizmos = new Dictionary(); this.random = rand; @@ -339,20 +339,14 @@ namespace DotRecast.Recast.Toolset.Tools return resultvector; } - public bool UpdateDynaMesh(TaskFactory executor) + public bool Update(TaskFactory executor) { if (dynaMesh == null) { return false; } - bool updated = dynaMesh.Update(executor).Result; - if (updated) - { - return false; - } - - return true; + return dynaMesh.Update(executor); } public bool Raycast(RcVec3f spos, RcVec3f epos, out float hitPos, out RcVec3f raycastHitPos) diff --git a/src/DotRecast.Recast.Toolset/Tools/RcTileTool.cs b/src/DotRecast.Recast.Toolset/Tools/RcTileTool.cs index 020b6ce..f20f763 100644 --- a/src/DotRecast.Recast.Toolset/Tools/RcTileTool.cs +++ b/src/DotRecast.Recast.Toolset/Tools/RcTileTool.cs @@ -94,7 +94,7 @@ namespace DotRecast.Recast.Toolset.Tools var beginTick = RcFrequency.Ticks; var rb = new RcBuilder(); - var result = rb.BuildTile(geom, cfg, bmin, bmax, tx, ty, new RcAtomicInteger(0), 1); + var result = rb.BuildTile(geom, cfg, bmin, bmax, tx, ty, new RcAtomicInteger(0), 1, settings.keepInterResults); var tb = new TileNavMeshBuilder(); var meshData = tb.BuildMeshData(geom, settings.cellSize, settings.cellHeight, settings.agentHeight, settings.agentRadius, settings.agentMaxClimb, RcImmutableArray.Create(result) diff --git a/src/DotRecast.Recast/RcBuilder.cs b/src/DotRecast.Recast/RcBuilder.cs index 4c91cf8..0620809 100644 --- a/src/DotRecast.Recast/RcBuilder.cs +++ b/src/DotRecast.Recast/RcBuilder.cs @@ -19,7 +19,9 @@ freely, subject to the following restrictions: */ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using DotRecast.Core; @@ -45,132 +47,113 @@ namespace DotRecast.Recast _progressListener = progressListener; } - public List BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory) + public List BuildTiles(IInputGeomProvider geom, RcConfig cfg, bool keepInterResults, bool buildAll, + int threads = 0, TaskFactory taskFactory = null, CancellationToken cancellation = default) { RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmax = geom.GetMeshBoundsMax(); CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th); - List results = new List(); - if (null != taskFactory) + + if (1 < threads) { - BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default); + return BuildMultiThread(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation, keepInterResults, buildAll); } - else + + return BuildSingleThread(geom, cfg, bmin, bmax, tw, th, keepInterResults, buildAll); + } + + private List BuildSingleThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th, + bool keepInterResults, bool buildAll) + { + var results = new List(th * tw); + RcAtomicInteger counter = new RcAtomicInteger(0); + + for (int y = 0; y < th; ++y) { - BuildSingleThreadAsync(geom, cfg, bmin, bmax, tw, th, results); + for (int x = 0; x < tw; ++x) + { + var result = BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th, keepInterResults); + results.Add(result); + } } return results; } - - public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List results, TaskFactory taskFactory, CancellationToken cancellationToken) + private List BuildMultiThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th, + int threads, TaskFactory taskFactory, CancellationToken cancellation, + bool keepInterResults, bool buildAll) { - 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 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 results, TaskFactory taskFactory, CancellationToken cancellationToken) - { - RcAtomicInteger counter = new RcAtomicInteger(0); - CountdownEvent latch = new CountdownEvent(tw * th); - List tasks = new List(); + var results = new ConcurrentQueue(); + RcAtomicInteger progress = new RcAtomicInteger(0); + List limits = new List(threads); for (int x = 0; x < tw; ++x) { for (int y = 0; y < th; ++y) { int tx = x; int ty = y; - var task = taskFactory.StartNew(() => + var task = taskFactory.StartNew(state => { - if (cancellationToken.IsCancellationRequested) + if (cancellation.IsCancellationRequested) return; try { - RcBuilderResult tile = BuildTile(geom, cfg, bmin, bmax, tx, ty, counter, tw * th); - lock (results) - { - results.Add(tile); - } + RcBuilderResult result = BuildTile(geom, cfg, bmin, bmax, tx, ty, progress, tw * th, keepInterResults); + results.Enqueue(result); } catch (Exception e) { Console.WriteLine(e); } + }, null, cancellation); - - latch.Signal(); - }, cancellationToken); - - tasks.Add(task); + limits.Add(task); + if (threads <= limits.Count) + { + Task.WaitAll(limits.ToArray()); + limits.Clear(); + } } } - try - { - latch.Wait(); - } - catch (ThreadInterruptedException) + if (0 < limits.Count) { + Task.WaitAll(limits.ToArray()); + limits.Clear(); } - return Task.WhenAll(tasks.ToArray()); + var list = results.ToList(); + return list; } - public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, - int ty, RcAtomicInteger counter, int total) + public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, int ty, RcAtomicInteger progress, int total, bool keepInterResults) { - RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty)); + var bcfg = new RcBuilderConfig(cfg, bmin, bmax, tx, ty); + RcBuilderResult result = Build(geom, bcfg, keepInterResults); if (_progressListener != null) { - _progressListener.OnProgress(counter.IncrementAndGet(), total); + _progressListener.OnProgress(progress.IncrementAndGet(), total); } + return result; } - public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig builderCfg) + public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig bcfg, bool keepInterResults) { - RcConfig cfg = builderCfg.cfg; + RcConfig cfg = bcfg.cfg; RcContext ctx = new RcContext(); // // Step 1. Rasterize input polygon soup. // - RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg); - return Build(ctx, builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid); + RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, bcfg); + return Build(ctx, bcfg.tileX, bcfg.tileZ, geom, cfg, solid, keepInterResults); } - 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, bool keepInterResults) { FilterHeightfield(ctx, solid, cfg); RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, cfg, solid); @@ -205,7 +188,7 @@ namespace DotRecast.Recast { // Prepare for region partitioning, by calculating distance field along the walkable surface. RcRegions.BuildDistanceField(ctx, chf); - + // Partition the walkable surface into simple regions without holes. RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea); } @@ -241,7 +224,17 @@ namespace DotRecast.Recast RcPolyMeshDetail dmesh = cfg.BuildMeshDetail ? RcMeshDetails.BuildPolyMeshDetail(ctx, pmesh, chf, cfg.DetailSampleDist, cfg.DetailSampleMaxError) : null; - return new RcBuilderResult(tileX, tileZ, solid, chf, cset, pmesh, dmesh, ctx); + + return new RcBuilderResult( + tileX, + tileZ, + keepInterResults ? solid : null, + keepInterResults ? chf : null, + keepInterResults ? cset : null, + pmesh, + dmesh, + ctx + ); } /* @@ -298,7 +291,7 @@ namespace DotRecast.Recast RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, builderCfg); FilterHeightfield(ctx, solid, builderCfg.cfg); RcCompactHeightfield chf = BuildCompactHeightfield(ctx, geom, builderCfg.cfg, solid); - + RcLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.BorderSize, builderCfg.cfg.WalkableHeight, out var lset); return lset; } diff --git a/src/DotRecast.Recast/RcBuilderResult.cs b/src/DotRecast.Recast/RcBuilderResult.cs index b83c1f5..ecb38b7 100644 --- a/src/DotRecast.Recast/RcBuilderResult.cs +++ b/src/DotRecast.Recast/RcBuilderResult.cs @@ -4,56 +4,26 @@ namespace DotRecast.Recast { public class RcBuilderResult { - public readonly int tileX; - 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 int TileX; + public readonly int TileZ; - public RcBuilderResult(int tileX, int tileZ, RcHeightfield solid, RcCompactHeightfield chf, RcContourSet cs, RcPolyMesh pmesh, RcPolyMeshDetail dmesh, RcContext ctx) - { - this.tileX = tileX; - this.tileZ = tileZ; - this.solid = solid; - this.chf = chf; - this.cs = cs; - this.pmesh = pmesh; - this.dmesh = dmesh; - _context = ctx; - } + public readonly RcHeightfield SolidHeightfiled; + public readonly RcCompactHeightfield CompactHeightfield; + public readonly RcContourSet ContourSet; + public readonly RcPolyMesh Mesh; + public readonly RcPolyMeshDetail MeshDetail; + public readonly RcContext Context; - public RcPolyMesh GetMesh() + public RcBuilderResult(int tileX, int tileZ, RcHeightfield solidHeightfiled, RcCompactHeightfield compactHeightfield, RcContourSet contourSet, RcPolyMesh mesh, RcPolyMeshDetail meshDetail, RcContext ctx) { - 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; + TileX = tileX; + TileZ = tileZ; + SolidHeightfiled = solidHeightfiled; + CompactHeightfield = compactHeightfield; + ContourSet = contourSet; + Mesh = mesh; + MeshDetail = meshDetail; + Context = ctx; } } } \ No newline at end of file diff --git a/src/DotRecast.Recast/RcHeightfield.cs b/src/DotRecast.Recast/RcHeightfield.cs index dd8b5fc..b5eaba9 100644 --- a/src/DotRecast.Recast/RcHeightfield.cs +++ b/src/DotRecast.Recast/RcHeightfield.cs @@ -22,29 +22,21 @@ using DotRecast.Core.Numerics; namespace DotRecast.Recast { - /** Represents a heightfield layer within a layer set. */ + /// A dynamic heightfield representing obstructed space. + /// @ingroup recast public class RcHeightfield { - /** The width of the heightfield. (Along the x-axis in cell units.) */ - public readonly int width; + public readonly int width; //< 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 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). - /** The height of the heightfield. (Along the z-axis in cell units.) */ - public readonly int height; - - /** 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; + // memory pool for rcSpan instances. + public RcSpanPool pools; //< Linked list of span pools. + public RcSpan freelist; //< The next free span. /** Border size in cell units */ public readonly int borderSize; diff --git a/src/DotRecast.Recast/RcPolyMeshRaycast.cs b/src/DotRecast.Recast/RcPolyMeshRaycast.cs index 78af411..845b6ec 100644 --- a/src/DotRecast.Recast/RcPolyMeshRaycast.cs +++ b/src/DotRecast.Recast/RcPolyMeshRaycast.cs @@ -30,9 +30,9 @@ namespace DotRecast.Recast hitTime = 0.0f; foreach (RcBuilderResult result in results) { - if (result.GetMeshDetail() != null) + if (result.MeshDetail != null) { - if (Raycast(result.GetMesh(), result.GetMeshDetail(), src, dst, out hitTime)) + if (Raycast(result.Mesh, result.MeshDetail, src, dst, out hitTime)) { return true; } diff --git a/src/DotRecast.Recast/RcRasterizations.cs b/src/DotRecast.Recast/RcRasterizations.cs index afa6a4e..d1cf465 100644 --- a/src/DotRecast.Recast/RcRasterizations.cs +++ b/src/DotRecast.Recast/RcRasterizations.cs @@ -41,6 +41,63 @@ namespace DotRecast.Recast aMin.Y <= bMax.Y && aMax.Y >= bMin.Y && 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, @@ -156,7 +213,7 @@ namespace DotRecast.Recast float axisOffset, int axis) { // How far positive or negative away from the separating axis is each vertex. - float[] inVertAxisDelta = new float[12]; + Span inVertAxisDelta = stackalloc float[12]; for (int inVert = 0; inVert < inVertsCount; ++inVert) { inVertAxisDelta[inVert] = axisOffset - inVerts[inVertsOffset + inVert * 3 + axis]; diff --git a/src/DotRecast.Recast/RcSpanPool.cs b/src/DotRecast.Recast/RcSpanPool.cs new file mode 100644 index 0000000..393ceea --- /dev/null +++ b/src/DotRecast.Recast/RcSpanPool.cs @@ -0,0 +1,38 @@ +/* +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(); + } + } + } +} \ No newline at end of file diff --git a/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj b/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj index 5713888..ebef2b5 100644 --- a/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj +++ b/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj @@ -9,13 +9,13 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj b/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj index 9b94dae..e416f45 100644 --- a/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj +++ b/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj @@ -9,13 +9,13 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs b/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs index 9a68823..bacecb9 100644 --- a/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs +++ b/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs @@ -72,14 +72,14 @@ public class RecastTestMeshBuilder SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); - RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg); - RcPolyMesh m_pmesh = rcResult.GetMesh(); + RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg, false); + RcPolyMesh m_pmesh = rcResult.Mesh; for (int i = 0; i < m_pmesh.npolys; ++i) { m_pmesh.flags[i] = 1; } - RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail(); + RcPolyMeshDetail m_dmesh = rcResult.MeshDetail; DtNavMeshCreateParams option = new DtNavMeshCreateParams(); option.verts = m_pmesh.verts; option.vertCount = m_pmesh.nverts; diff --git a/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj b/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj index 858d69c..153236f 100644 --- a/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj +++ b/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj @@ -9,17 +9,17 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs b/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs index 1215635..cbcaa04 100644 --- a/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs +++ b/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs @@ -10,7 +10,6 @@ using NUnit.Framework; namespace DotRecast.Detour.Dynamic.Test; - public class DynamicNavMeshTest { private static readonly RcVec3f START_POS = new RcVec3f(70.87453f, 0.0010070801f, 86.69021f); @@ -32,9 +31,7 @@ public class DynamicNavMeshTest // create dynamic navmesh DtDynamicNavMesh mesh = new DtDynamicNavMesh(f); // build navmesh asynchronously using multiple threads - Task future = mesh.Build(Task.Factory); - // wait for build to complete - bool _ = future.Result; + mesh.Build(Task.Factory); // create new query DtNavMeshQuery query = new DtNavMeshQuery(mesh.NavMesh()); @@ -54,9 +51,8 @@ public class DynamicNavMeshTest long colliderId = mesh.AddCollider(colldier); // update navmesh asynchronously - future = mesh.Update(Task.Factory); - // wait for update to complete - _ = future.Result; + mesh.Update(Task.Factory); + // create new query query = new DtNavMeshQuery(mesh.NavMesh()); @@ -70,9 +66,7 @@ public class DynamicNavMeshTest // remove obstacle mesh.RemoveCollider(colliderId); // update navmesh asynchronously - future = mesh.Update(Task.Factory); - // wait for update to complete - _ = future.Result; + mesh.Update(Task.Factory); // create new query query = new DtNavMeshQuery(mesh.NavMesh()); diff --git a/test/DotRecast.Detour.Dynamic.Test/VoxelQueryTest.cs b/test/DotRecast.Detour.Dynamic.Test/VoxelQueryTest.cs index fc32f0a..451de65 100644 --- a/test/DotRecast.Detour.Dynamic.Test/VoxelQueryTest.cs +++ b/test/DotRecast.Detour.Dynamic.Test/VoxelQueryTest.cs @@ -31,7 +31,6 @@ using NUnit.Framework; namespace DotRecast.Detour.Dynamic.Test; - public class VoxelQueryTest { private const int TILE_WIDTH = 100; @@ -101,12 +100,12 @@ public class VoxelQueryTest // load voxels from file DtVoxelFileReader reader = new DtVoxelFileReader(DtVoxelTileLZ4ForTestCompressor.Shared); DtVoxelFile f = reader.Read(br); + // create dynamic navmesh var mesh = new DtDynamicNavMesh(f); + // build navmesh asynchronously using multiple threads - Task future = mesh.Build(Task.Factory); - // wait for build to complete - var _ = future.Result; + mesh.Build(Task.Factory); return mesh; } } \ No newline at end of file diff --git a/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj b/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj index 76ba9ec..9af54f1 100644 --- a/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj +++ b/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj @@ -9,13 +9,13 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj b/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj index 38a6c6d..aae8db2 100644 --- a/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj +++ b/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj @@ -9,13 +9,13 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs b/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs index 4d755a0..12c618e 100644 --- a/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs @@ -72,14 +72,14 @@ public class RecastTestMeshBuilder SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); - RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg); - RcPolyMesh m_pmesh = rcResult.GetMesh(); + RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg, false); + RcPolyMesh m_pmesh = rcResult.Mesh; for (int i = 0; i < m_pmesh.npolys; ++i) { m_pmesh.flags[i] = 1; } - RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail(); + RcPolyMeshDetail m_dmesh = rcResult.MeshDetail; DtNavMeshCreateParams option = new DtNavMeshCreateParams(); option.verts = m_pmesh.verts; option.vertCount = m_pmesh.nverts; diff --git a/test/DotRecast.Detour.Test/TestDetourBuilder.cs b/test/DotRecast.Detour.Test/TestDetourBuilder.cs index 0611b8e..4df7c6d 100644 --- a/test/DotRecast.Detour.Test/TestDetourBuilder.cs +++ b/test/DotRecast.Detour.Test/TestDetourBuilder.cs @@ -27,8 +27,8 @@ public class TestDetourBuilder : DetourBuilder float agentMaxClimb, int x, int y, bool applyRecastDemoFlags) { RcBuilder rcBuilder = new RcBuilder(); - RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig); - RcPolyMesh pmesh = rcResult.GetMesh(); + RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig, false); + RcPolyMesh pmesh = rcResult.Mesh; if (applyRecastDemoFlags) { @@ -58,7 +58,7 @@ public class TestDetourBuilder : DetourBuilder } } - RcPolyMeshDetail dmesh = rcResult.GetMeshDetail(); + RcPolyMeshDetail dmesh = rcResult.MeshDetail; DtNavMeshCreateParams option = GetNavMeshCreateParams(rcConfig.cfg, pmesh, dmesh, agentHeight, agentRadius, agentMaxClimb); return Build(option, x, y); diff --git a/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs index 6baef44..c03623e 100644 --- a/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs @@ -78,13 +78,13 @@ public class TestTiledNavMeshBuilder true, true, true, SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilder rcBuilder = new RcBuilder(); - List rcResult = rcBuilder.BuildTiles(geom, cfg, null); + List rcResult = rcBuilder.BuildTiles(geom, cfg, false, true); // Add tiles to nav mesh foreach (RcBuilderResult result in rcResult) { - RcPolyMesh pmesh = result.GetMesh(); + RcPolyMesh pmesh = result.Mesh; if (pmesh.npolys == 0) { continue; @@ -103,7 +103,7 @@ public class TestTiledNavMeshBuilder option.polyFlags = pmesh.flags; option.polyCount = pmesh.npolys; option.nvp = pmesh.nvp; - RcPolyMeshDetail dmesh = result.GetMeshDetail(); + RcPolyMeshDetail dmesh = result.MeshDetail; option.detailMeshes = dmesh.meshes; option.detailVerts = dmesh.verts; option.detailVertsCount = dmesh.nverts; @@ -116,8 +116,8 @@ public class TestTiledNavMeshBuilder option.bmax = pmesh.bmax; option.cs = cellSize; option.ch = cellHeight; - option.tileX = result.tileX; - option.tileZ = result.tileZ; + option.tileX = result.TileX; + option.tileZ = result.TileZ; option.buildBvTree = true; navMesh.AddTile(DtNavMeshBuilder.CreateNavMeshData(option), 0, 0); } diff --git a/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj b/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj index 7b21b5c..d7247b0 100644 --- a/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj +++ b/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj @@ -9,17 +9,17 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj b/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj index 9988078..cd9cbc4 100644 --- a/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj +++ b/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj @@ -9,13 +9,13 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs index bacb9ae..6fa4676 100644 --- a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs +++ b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs @@ -27,7 +27,6 @@ using NUnit.Framework; namespace DotRecast.Recast.Test; - public class RecastTileMeshTest { private const float m_cellSize = 0.3f; @@ -70,29 +69,29 @@ public class RecastTileMeshTest true, true, true, SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8); - RcBuilderResult rcResult = builder.Build(geom, bcfg); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5)); + RcBuilderResult rcResult = builder.Build(geom, bcfg, false); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(1)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(5)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9); - rcResult = builder.Build(geom, bcfg); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7)); + rcResult = builder.Build(geom, bcfg, false); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(7)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9); - rcResult = builder.Build(geom, bcfg); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9)); + rcResult = builder.Build(geom, bcfg, false); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(9)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3); - rcResult = builder.Build(geom, bcfg); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6)); + rcResult = builder.Build(geom, bcfg, false); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(3)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(6)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8); - rcResult = builder.Build(geom, bcfg); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17)); + rcResult = builder.Build(geom, bcfg, false); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(5)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(17)); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8); - rcResult = builder.Build(geom, bcfg); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15)); + rcResult = builder.Build(geom, bcfg, false); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15)); } [Test] @@ -138,28 +137,27 @@ public class RecastTileMeshTest private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate) { CancellationTokenSource cts = new CancellationTokenSource(); - List tiles = new(); - var task = builder.BuildTilesAsync(geom, cfg, threads, tiles, Task.Factory, cts.Token); + List tiles = builder.BuildTiles(geom, cfg, false, true, threads, Task.Factory, cts.Token); if (validate) { RcBuilderResult rcResult = GetTile(tiles, 7, 8); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5)); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(1)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(5)); rcResult = GetTile(tiles, 6, 9); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7)); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(7)); rcResult = GetTile(tiles, 2, 9); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9)); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(2)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(9)); rcResult = GetTile(tiles, 4, 3); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6)); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(3)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(6)); rcResult = GetTile(tiles, 2, 8); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17)); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(5)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(17)); rcResult = GetTile(tiles, 0, 8); - Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6)); - Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15)); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15)); } try @@ -175,6 +173,6 @@ public class RecastTileMeshTest private RcBuilderResult GetTile(List 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); } } \ No newline at end of file