From 4b8cd8e31b1574ee1567a49e413b4f979c7def88 Mon Sep 17 00:00:00 2001 From: ikpil Date: Thu, 29 Feb 2024 13:54:36 +0900 Subject: [PATCH 01/24] NUnit 4.1.0 --- test/DotRecast.Core.Test/DotRecast.Core.Test.csproj | 2 +- .../DotRecast.Detour.Crowd.Test.csproj | 2 +- .../DotRecast.Detour.Dynamic.Test.csproj | 2 +- .../DotRecast.Detour.Extras.Test.csproj | 2 +- test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj | 2 +- .../DotRecast.Detour.TileCache.Test.csproj | 2 +- test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj b/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj index 5713888..1cc6f1e 100644 --- a/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj +++ b/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj @@ -9,7 +9,7 @@ - + all 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..57a0a61 100644 --- a/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj +++ b/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj @@ -9,7 +9,7 @@ - + all 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..76784ba 100644 --- a/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj +++ b/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj @@ -9,7 +9,7 @@ - + all 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..c53c7da 100644 --- a/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj +++ b/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj @@ -9,7 +9,7 @@ - + all diff --git a/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj b/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj index 38a6c6d..6aa828d 100644 --- a/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj +++ b/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj @@ -9,7 +9,7 @@ - + all 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..62edc80 100644 --- a/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj +++ b/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj @@ -9,7 +9,7 @@ - + all diff --git a/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj b/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj index 9988078..d8dced6 100644 --- a/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj +++ b/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj @@ -9,7 +9,7 @@ - + all From 7dfac39408c62443e9103b393042c7abad39b838 Mon Sep 17 00:00:00 2001 From: Andrew Gilewsky Date: Tue, 5 Mar 2024 00:21:24 +0000 Subject: [PATCH 02/24] Optimization: reduce number of allocations on hot path. --- src/DotRecast.Recast/RcRasterizations.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotRecast.Recast/RcRasterizations.cs b/src/DotRecast.Recast/RcRasterizations.cs index afa6a4e..9b1f638 100644 --- a/src/DotRecast.Recast/RcRasterizations.cs +++ b/src/DotRecast.Recast/RcRasterizations.cs @@ -156,7 +156,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]; From b67ebeaec38e9a6af250ef7e482a96efc621befc Mon Sep 17 00:00:00 2001 From: wreng Date: Wed, 21 Feb 2024 14:40:22 +0300 Subject: [PATCH 03/24] Added stackalloc where it's acceptable --- src/DotRecast.Detour/DtNavMesh.cs | 4 ++-- src/DotRecast.Detour/DtNavMeshQuery.cs | 9 +++++---- src/DotRecast.Detour/DtUtils.cs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/DotRecast.Detour/DtNavMesh.cs b/src/DotRecast.Detour/DtNavMesh.cs index a10cf07..4b5f49d 100644 --- a/src/DotRecast.Detour/DtNavMesh.cs +++ b/src/DotRecast.Detour/DtNavMesh.cs @@ -358,8 +358,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 fae330c..c4dd060 100644 --- a/src/DotRecast.Detour/DtNavMeshQuery.cs +++ b/src/DotRecast.Detour/DtNavMeshQuery.cs @@ -583,8 +583,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; @@ -1824,6 +1824,9 @@ namespace DotRecast.Detour float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3]; + const int MAX_NEIS = 8; + Span neis = stackalloc long[MAX_NEIS]; + while (0 < stack.Count) { // Pop front. @@ -1854,9 +1857,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; - long[] neis = new long[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; From daf826f5f4e1cadc09fc81429f355be868352c89 Mon Sep 17 00:00:00 2001 From: ikpil Date: Wed, 13 Mar 2024 23:18:18 +0900 Subject: [PATCH 04/24] modify .editorconfig --- .editorconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 From 573386c473939d70d438b40160ebe331a508d4ff Mon Sep 17 00:00:00 2001 From: ikpil Date: Fri, 22 Mar 2024 23:12:55 +0900 Subject: [PATCH 05/24] update library K4os.Compression.LZ4 1.3.8, NUnit.Analyzers 4.1.0, coverlet.collector 6.0.2 --- src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj | 2 +- test/DotRecast.Core.Test/DotRecast.Core.Test.csproj | 4 ++-- .../DotRecast.Detour.Crowd.Test.csproj | 4 ++-- .../DotRecast.Detour.Dynamic.Test.csproj | 6 +++--- .../DotRecast.Detour.Extras.Test.csproj | 4 ++-- test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj | 4 ++-- .../DotRecast.Detour.TileCache.Test.csproj | 6 +++--- test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj index f293537..399aa50 100644 --- a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj +++ b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj @@ -26,7 +26,7 @@ - + diff --git a/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj b/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj index 1cc6f1e..ebef2b5 100644 --- a/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj +++ b/test/DotRecast.Core.Test/DotRecast.Core.Test.csproj @@ -11,11 +11,11 @@ - + 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 57a0a61..e416f45 100644 --- a/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj +++ b/test/DotRecast.Detour.Crowd.Test/DotRecast.Detour.Crowd.Test.csproj @@ -11,11 +11,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive 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 76784ba..153236f 100644 --- a/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj +++ b/test/DotRecast.Detour.Dynamic.Test/DotRecast.Detour.Dynamic.Test.csproj @@ -11,15 +11,15 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + 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 c53c7da..9af54f1 100644 --- a/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj +++ b/test/DotRecast.Detour.Extras.Test/DotRecast.Detour.Extras.Test.csproj @@ -11,11 +11,11 @@ - + 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 6aa828d..aae8db2 100644 --- a/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj +++ b/test/DotRecast.Detour.Test/DotRecast.Detour.Test.csproj @@ -11,11 +11,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive 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 62edc80..d7247b0 100644 --- a/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj +++ b/test/DotRecast.Detour.TileCache.Test/DotRecast.Detour.TileCache.Test.csproj @@ -11,15 +11,15 @@ - + 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 d8dced6..cd9cbc4 100644 --- a/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj +++ b/test/DotRecast.Recast.Test/DotRecast.Recast.Test.csproj @@ -11,11 +11,11 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 82027dffd7cb1192c2e67d8971f16fc8f179ebe8 Mon Sep 17 00:00:00 2001 From: ikpil Date: Wed, 10 Apr 2024 19:52:58 +0900 Subject: [PATCH 06/24] Limiting the number of tasks during build --- .../Builder/TileNavMeshBuilder.cs | 3 +- src/DotRecast.Recast/RcBuilder.cs | 116 ++++++++---------- .../TestTiledNavMeshBuilder.cs | 3 +- .../RecastTileMeshTest.cs | 5 +- 4 files changed, 54 insertions(+), 73 deletions(-) diff --git a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs index f73fbc9..89495b6 100644 --- a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs @@ -97,7 +97,8 @@ namespace DotRecast.Recast.Toolset.Builder filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); RcBuilder rcBuilder = new RcBuilder(); - return rcBuilder.BuildTiles(geom, cfg, Task.Factory); + var task = rcBuilder.BuildTilesAsync(geom, cfg, Environment.ProcessorCount + 1, Task.Factory); + return task.Result; } public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List meshData, float cellSize, int tileSize, int vertsPerPoly) diff --git a/src/DotRecast.Recast/RcBuilder.cs b/src/DotRecast.Recast/RcBuilder.cs index 4c91cf8..129cf2f 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,115 +47,93 @@ namespace DotRecast.Recast _progressListener = progressListener; } - public List BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory) + public Task> BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, + 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 BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation); } - else + + var results = BuildSingleThread(geom, cfg, bmin, bmax, tw, th); + return Task.FromResult(results); + } + + private List BuildSingleThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th) + { + 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); + results.Add(result); + } } return results; } - - public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List results, TaskFactory taskFactory, CancellationToken cancellationToken) + private async Task> BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th, + int threads, TaskFactory taskFactory, CancellationToken cancellation) { - 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); + results.Enqueue(result); } catch (Exception e) { Console.WriteLine(e); } + }, null); - - latch.Signal(); - }, cancellationToken); - - tasks.Add(task); + limits.Add(task); + if (threads <= limits.Count) + { + await Task.WhenAll(limits); + limits.Clear(); + } } } - try - { - latch.Wait(); - } - catch (ThreadInterruptedException) + if (0 < limits.Count) { + await Task.WhenAll(limits); + 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) { RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty)); if (_progressListener != null) { - _progressListener.OnProgress(counter.IncrementAndGet(), total); + _progressListener.OnProgress(progress.IncrementAndGet(), total); } return result; @@ -205,7 +185,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); } @@ -298,7 +278,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/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs index 6baef44..e7bf7fd 100644 --- a/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs @@ -78,7 +78,8 @@ public class TestTiledNavMeshBuilder true, true, true, SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilder rcBuilder = new RcBuilder(); - List rcResult = rcBuilder.BuildTiles(geom, cfg, null); + var task = rcBuilder.BuildTilesAsync(geom, cfg); + List rcResult = task.Result; // Add tiles to nav mesh diff --git a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs index bacb9ae..d8a4fe7 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; @@ -138,8 +137,8 @@ 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); + var task = builder.BuildTilesAsync(geom, cfg, threads, Task.Factory, cts.Token); + List tiles = task.Result; if (validate) { RcBuilderResult rcResult = GetTile(tiles, 7, 8); From 7874b4403ca70cd7073a271634b0d50b49326572 Mon Sep 17 00:00:00 2001 From: ikpil Date: Wed, 10 Apr 2024 20:39:06 +0900 Subject: [PATCH 07/24] Renamed RcBuilderResult class to C# style naming --- src/DotRecast.Detour.Dynamic/DtDynamicTile.cs | 4 +- .../Io/DtVoxelFile.cs | 14 ++-- .../Jumplink/JumpLinkBuilder.cs | 4 +- .../Jumplink/NavMeshGroundSampler.cs | 32 +++++----- .../Draw/NavMeshRenderer.cs | 50 +++++++-------- src/DotRecast.Recast.Demo/RecastDemo.cs | 16 ++--- .../Builder/DemoNavMeshBuilder.cs | 4 +- .../Builder/TileNavMeshBuilder.cs | 4 +- src/DotRecast.Recast/RcBuilderResult.cs | 64 +++++-------------- src/DotRecast.Recast/RcPolyMeshRaycast.cs | 4 +- .../RecastTestMeshBuilder.cs | 4 +- .../RecastTestMeshBuilder.cs | 4 +- .../TestDetourBuilder.cs | 4 +- .../TestTiledNavMeshBuilder.cs | 8 +-- .../RecastTileMeshTest.cs | 50 +++++++-------- 15 files changed, 118 insertions(+), 148 deletions(-) diff --git a/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs b/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs index 82fb905..7712497 100644 --- a/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs +++ b/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs @@ -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.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..4b65e19 100644 --- a/src/DotRecast.Recast.Demo/RecastDemo.cs +++ b/src/DotRecast.Recast.Demo/RecastDemo.cs @@ -552,7 +552,7 @@ public class RecastDemo : IRecastDemoChannel { foreach (RcBuilderResult result in _sample.GetRecastResults()) { - if (result.GetSolidHeightfield() != null) + if (result.SolidHeightfiled != null) { if (!hasBound) { @@ -561,15 +561,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.SolidHeightfiled.bmin.X), + Math.Min(bminN.Y, result.SolidHeightfiled.bmin.Y), + Math.Min(bminN.Z, result.SolidHeightfiled.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.SolidHeightfiled.bmax.X), + Math.Max(bmaxN.Y, result.SolidHeightfiled.bmax.Y), + Math.Max(bmaxN.Z, result.SolidHeightfiled.bmax.Z) ); hasBound = true; @@ -713,7 +713,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.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/TileNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs index 89495b6..836877f 100644 --- a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs @@ -124,8 +124,8 @@ namespace DotRecast.Recast.Toolset.Builder List meshData = new List(); foreach (RcBuilderResult result in results) { - int x = result.tileX; - int z = result.tileZ; + int x = result.TileX; + int z = result.TileZ; DtNavMeshCreateParams option = DemoNavMeshBuilder .GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result); 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/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/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs b/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs index 9a68823..7fd70c3 100644 --- a/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs +++ b/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs @@ -73,13 +73,13 @@ public class RecastTestMeshBuilder RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg); - RcPolyMesh m_pmesh = rcResult.GetMesh(); + 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/RecastTestMeshBuilder.cs b/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs index 4d755a0..b1830bb 100644 --- a/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs @@ -73,13 +73,13 @@ public class RecastTestMeshBuilder RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg); - RcPolyMesh m_pmesh = rcResult.GetMesh(); + 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..d7b9268 100644 --- a/test/DotRecast.Detour.Test/TestDetourBuilder.cs +++ b/test/DotRecast.Detour.Test/TestDetourBuilder.cs @@ -28,7 +28,7 @@ public class TestDetourBuilder : DetourBuilder { RcBuilder rcBuilder = new RcBuilder(); RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig); - RcPolyMesh pmesh = rcResult.GetMesh(); + 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 e7bf7fd..3e29804 100644 --- a/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs @@ -85,7 +85,7 @@ public class TestTiledNavMeshBuilder foreach (RcBuilderResult result in rcResult) { - RcPolyMesh pmesh = result.GetMesh(); + RcPolyMesh pmesh = result.Mesh; if (pmesh.npolys == 0) { continue; @@ -104,7 +104,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; @@ -117,8 +117,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.Recast.Test/RecastTileMeshTest.cs b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs index d8a4fe7..c8d3a96 100644 --- a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs +++ b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs @@ -70,28 +70,28 @@ public class RecastTileMeshTest 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)); + 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)); + 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)); + 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)); + 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)); + 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)); + Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6)); + Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15)); } [Test] @@ -142,23 +142,23 @@ public class RecastTileMeshTest 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 @@ -174,6 +174,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 From 402b25a436a6d08da5caf84b78891d066ade6483 Mon Sep 17 00:00:00 2001 From: ikpil Date: Fri, 12 Apr 2024 00:08:06 +0900 Subject: [PATCH 08/24] fixed an issue where await deadlock could occur in various platform environments. --- .../Builder/TileNavMeshBuilder.cs | 3 +-- src/DotRecast.Recast/RcBuilder.cs | 15 +++++++-------- .../TestTiledNavMeshBuilder.cs | 3 +-- test/DotRecast.Recast.Test/RecastTileMeshTest.cs | 3 +-- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs index 836877f..44a4945 100644 --- a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs @@ -97,8 +97,7 @@ namespace DotRecast.Recast.Toolset.Builder filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); RcBuilder rcBuilder = new RcBuilder(); - var task = rcBuilder.BuildTilesAsync(geom, cfg, Environment.ProcessorCount + 1, Task.Factory); - return task.Result; + return rcBuilder.BuildTiles(geom, cfg, Environment.ProcessorCount + 1, Task.Factory); } public DtNavMesh BuildNavMesh(IInputGeomProvider geom, List meshData, float cellSize, int tileSize, int vertsPerPoly) diff --git a/src/DotRecast.Recast/RcBuilder.cs b/src/DotRecast.Recast/RcBuilder.cs index 129cf2f..9123b92 100644 --- a/src/DotRecast.Recast/RcBuilder.cs +++ b/src/DotRecast.Recast/RcBuilder.cs @@ -47,7 +47,7 @@ namespace DotRecast.Recast _progressListener = progressListener; } - public Task> BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, + public List BuildTiles(IInputGeomProvider geom, RcConfig cfg, int threads = 0, TaskFactory taskFactory = null, CancellationToken cancellation = default) { RcVec3f bmin = geom.GetMeshBoundsMin(); @@ -56,11 +56,10 @@ namespace DotRecast.Recast if (1 < threads) { - return BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation); + return BuildMultiThread(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation); } - var results = BuildSingleThread(geom, cfg, bmin, bmax, tw, th); - return Task.FromResult(results); + return BuildSingleThread(geom, cfg, bmin, bmax, tw, th); } private List BuildSingleThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th) @@ -80,7 +79,7 @@ namespace DotRecast.Recast return results; } - private async Task> BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th, + private List BuildMultiThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th, int threads, TaskFactory taskFactory, CancellationToken cancellation) { var results = new ConcurrentQueue(); @@ -107,12 +106,12 @@ namespace DotRecast.Recast { Console.WriteLine(e); } - }, null); + }, null, cancellation); limits.Add(task); if (threads <= limits.Count) { - await Task.WhenAll(limits); + Task.WaitAll(limits.ToArray()); limits.Clear(); } } @@ -120,7 +119,7 @@ namespace DotRecast.Recast if (0 < limits.Count) { - await Task.WhenAll(limits); + Task.WaitAll(limits.ToArray()); limits.Clear(); } diff --git a/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs index 3e29804..835c247 100644 --- a/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs @@ -78,8 +78,7 @@ public class TestTiledNavMeshBuilder true, true, true, SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilder rcBuilder = new RcBuilder(); - var task = rcBuilder.BuildTilesAsync(geom, cfg); - List rcResult = task.Result; + List rcResult = rcBuilder.BuildTiles(geom, cfg); // Add tiles to nav mesh diff --git a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs index c8d3a96..2abb9df 100644 --- a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs +++ b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs @@ -137,8 +137,7 @@ public class RecastTileMeshTest private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate) { CancellationTokenSource cts = new CancellationTokenSource(); - var task = builder.BuildTilesAsync(geom, cfg, threads, Task.Factory, cts.Token); - List tiles = task.Result; + List tiles = builder.BuildTiles(geom, cfg, threads, Task.Factory, cts.Token); if (validate) { RcBuilderResult rcResult = GetTile(tiles, 7, 8); From 668ebd0128c7961dc877299a87d75e8cba9308f3 Mon Sep 17 00:00:00 2001 From: ikpil Date: Fri, 12 Apr 2024 02:27:07 +0900 Subject: [PATCH 09/24] update comment --- src/DotRecast.Recast.Demo/RecastDemo.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/DotRecast.Recast.Demo/RecastDemo.cs b/src/DotRecast.Recast.Demo/RecastDemo.cs index 4b65e19..d0421fa 100644 --- a/src/DotRecast.Recast.Demo/RecastDemo.cs +++ b/src/DotRecast.Recast.Demo/RecastDemo.cs @@ -577,12 +577,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; From 26a1dfddeb704a06d7f9d51cc832bba31b9794b1 Mon Sep 17 00:00:00 2001 From: ikpil Date: Sat, 13 Apr 2024 12:43:54 +0900 Subject: [PATCH 10/24] fix bug where return value of dynamic update result is reversed --- src/DotRecast.Core/IRcRand.cs | 2 + src/DotRecast.Core/RcRand.cs | 13 +++- .../DtDynamicNavMesh.cs | 77 +++++++++---------- .../Tools/DynamicUpdateSampleTool.cs | 6 +- .../Tools/RcDynamicUpdateTool.cs | 14 +--- .../DynamicNavMeshTest.cs | 14 +--- .../VoxelQueryTest.cs | 7 +- 7 files changed, 65 insertions(+), 68 deletions(-) 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.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.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/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 From da82d6ba4d349c26ae33f53056c3bfbfae0d52d2 Mon Sep 17 00:00:00 2001 From: ikpil Date: Sat, 13 Apr 2024 12:53:58 +0900 Subject: [PATCH 11/24] reduced usability of SolidHeightfield in recast build results --- src/DotRecast.Recast.Demo/RecastDemo.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/DotRecast.Recast.Demo/RecastDemo.cs b/src/DotRecast.Recast.Demo/RecastDemo.cs index d0421fa..270bfef 100644 --- a/src/DotRecast.Recast.Demo/RecastDemo.cs +++ b/src/DotRecast.Recast.Demo/RecastDemo.cs @@ -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(); @@ -561,15 +562,15 @@ public class RecastDemo : IRecastDemoChannel } bminN = new RcVec3f( - Math.Min(bminN.X, result.SolidHeightfiled.bmin.X), - Math.Min(bminN.Y, result.SolidHeightfiled.bmin.Y), - Math.Min(bminN.Z, result.SolidHeightfiled.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.SolidHeightfiled.bmax.X), - Math.Max(bmaxN.Y, result.SolidHeightfiled.bmax.Y), - Math.Max(bmaxN.Z, result.SolidHeightfiled.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; From 9210eb58fee6ab648f38f5a5dc958cc401f1eec5 Mon Sep 17 00:00:00 2001 From: ikpil Date: Sun, 14 Apr 2024 00:43:03 +0900 Subject: [PATCH 12/24] changed to use `CompactHeightfield` instead of `Heightfield` when finding bmin/bmax --- src/DotRecast.Recast.Demo/RecastDemo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DotRecast.Recast.Demo/RecastDemo.cs b/src/DotRecast.Recast.Demo/RecastDemo.cs index 270bfef..b6926e9 100644 --- a/src/DotRecast.Recast.Demo/RecastDemo.cs +++ b/src/DotRecast.Recast.Demo/RecastDemo.cs @@ -553,7 +553,7 @@ public class RecastDemo : IRecastDemoChannel { foreach (RcBuilderResult result in _sample.GetRecastResults()) { - if (result.SolidHeightfiled != null) + if (result.CompactHeightfield != null) { if (!hasBound) { From 17c1c18372220f49022c5127cdd609d892b8188d Mon Sep 17 00:00:00 2001 From: ikpil Date: Mon, 15 Apr 2024 23:42:55 +0900 Subject: [PATCH 13/24] added "Keep Itermediate Results" flag --- src/DotRecast.Recast.Demo/UI/RcSettingsView.cs | 4 ++++ src/DotRecast.Recast.Toolset/RcNavMeshBuildSettings.cs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs b/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs index 50f69c0..8ecc8c8 100644 --- a/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs +++ b/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs @@ -165,6 +165,10 @@ public class RcSettingsView : IRcView ImGui.SliderFloat("Sample Distance", ref settings.detailSampleDist, 0f, 16f, "%.1f"); 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(); 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 From 97ffaf87003ce739e98f908fc43bd57b7226fa97 Mon Sep 17 00:00:00 2001 From: ikpil Date: Tue, 16 Apr 2024 23:24:48 +0900 Subject: [PATCH 14/24] add comment "Tick 'Keep Itermediate Results'" --- src/DotRecast.Recast.Demo/UI/RcSettingsView.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs b/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs index 8ecc8c8..5ca0de5 100644 --- a/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs +++ b/src/DotRecast.Recast.Demo/UI/RcSettingsView.cs @@ -165,7 +165,7 @@ public class RcSettingsView : IRcView ImGui.SliderFloat("Sample Distance", ref settings.detailSampleDist, 0f, 16f, "%.1f"); 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(); @@ -232,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(); } @@ -266,4 +272,4 @@ public class RcSettingsView : IRcView { this.maxPolys = maxPolys; } -} +} \ No newline at end of file From 80e07ebb3c18a4963aeba101b575a4cb5522faf3 Mon Sep 17 00:00:00 2001 From: ikpil Date: Wed, 17 Apr 2024 23:50:48 +0900 Subject: [PATCH 15/24] Tick 'Keep Intermediate Results' option. --- src/DotRecast.Recast.Demo/RecastDemo.cs | 15 ++++--- .../Builder/SoloNavMeshBuilder.cs | 27 +++++++++--- .../Builder/TileNavMeshBuilder.cs | 15 ++++--- .../Tools/RcTileTool.cs | 2 +- src/DotRecast.Recast/RcBuilder.cs | 44 +++++++++++++------ 5 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/DotRecast.Recast.Demo/RecastDemo.cs b/src/DotRecast.Recast.Demo/RecastDemo.cs index b6926e9..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,7 +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(); @@ -584,8 +584,8 @@ public class RecastDemo : IRecastDemoChannel RcVec3f bmin = bminN; RcVec3f bmax = bmaxN; - camr = (float)(Math.Sqrt(RcMath.Sqr(bmax.X - bmin.X) + - RcMath.Sqr(bmax.Y - bmin.Y) + + 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; @@ -692,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) diff --git a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs index ab145f6..ced313d 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,26 @@ 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); + var result = rcBuilder.Build(geom, bcfg); + if (!keepInterResults) + { + return new RcBuilderResult( + result.TileX, + result.TileZ, + null, + result.CompactHeightfield, + result.ContourSet, + result.Mesh, + result.MeshDetail, + result.Context + ); + } + + return result; } public DtMeshData BuildMeshData(DemoInputGeomProvider geom, diff --git a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs index 44a4945..15a431e 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, @@ -125,8 +129,7 @@ namespace DotRecast.Recast.Toolset.Builder { int x = result.TileX; 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.tileZ = z; 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 9123b92..f0c6ed2 100644 --- a/src/DotRecast.Recast/RcBuilder.cs +++ b/src/DotRecast.Recast/RcBuilder.cs @@ -48,7 +48,8 @@ namespace DotRecast.Recast } public List BuildTiles(IInputGeomProvider geom, RcConfig cfg, - int threads = 0, TaskFactory taskFactory = null, CancellationToken cancellation = default) + int threads = 0, TaskFactory taskFactory = null, CancellationToken cancellation = default, + bool keepInterResults = false, bool buildAll = true) { RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmax = geom.GetMeshBoundsMax(); @@ -56,13 +57,14 @@ namespace DotRecast.Recast if (1 < threads) { - return BuildMultiThread(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation); + return BuildMultiThread(geom, cfg, bmin, bmax, tw, th, threads, taskFactory ?? Task.Factory, cancellation, keepInterResults, buildAll); } - return BuildSingleThread(geom, cfg, bmin, bmax, tw, th); + 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) + 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); @@ -71,7 +73,7 @@ namespace DotRecast.Recast { for (int x = 0; x < tw; ++x) { - var result = BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th); + var result = BuildTile(geom, cfg, bmin, bmax, x, y, counter, tw * th, keepInterResults); results.Add(result); } } @@ -80,7 +82,8 @@ namespace DotRecast.Recast } private List BuildMultiThread(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tw, int th, - int threads, TaskFactory taskFactory, CancellationToken cancellation) + int threads, TaskFactory taskFactory, CancellationToken cancellation, + bool keepInterResults, bool buildAll) { var results = new ConcurrentQueue(); RcAtomicInteger progress = new RcAtomicInteger(0); @@ -99,7 +102,7 @@ namespace DotRecast.Recast try { - RcBuilderResult result = BuildTile(geom, cfg, bmin, bmax, tx, ty, progress, tw * th); + RcBuilderResult result = BuildTile(geom, cfg, bmin, bmax, tx, ty, progress, tw * th, keepInterResults); results.Enqueue(result); } catch (Exception e) @@ -127,26 +130,41 @@ namespace DotRecast.Recast return list; } - public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, int ty, RcAtomicInteger progress, 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); if (_progressListener != null) { _progressListener.OnProgress(progress.IncrementAndGet(), total); } + if (!keepInterResults) + { + return new RcBuilderResult( + result.TileX, + result.TileZ, + null, + result.CompactHeightfield, + result.ContourSet, + result.Mesh, + result.MeshDetail, + result.Context + ); + } + return result; } - public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig builderCfg) + public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig bcfg) { - 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); } public RcBuilderResult Build(RcContext ctx, int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid) From 8fe46a64504a0c6cb6b419178bdf04002dc74b0c Mon Sep 17 00:00:00 2001 From: ikpil Date: Thu, 18 Apr 2024 00:10:06 +0900 Subject: [PATCH 16/24] Keep Itermediate Results in JumpLinkBuilderSampleTools --- .../Tools/JumpLinkBuilderSampleTool.cs | 17 +++++++++++++++-- .../Builder/TileNavMeshBuilder.cs | 2 +- src/DotRecast.Recast/RcBuilder.cs | 5 ++--- .../TestTiledNavMeshBuilder.cs | 2 +- .../DotRecast.Recast.Test/RecastTileMeshTest.cs | 2 +- 5 files changed, 20 insertions(+), 8 deletions(-) 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.Toolset/Builder/TileNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs index 15a431e..5542c25 100644 --- a/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/TileNavMeshBuilder.cs @@ -101,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, Environment.ProcessorCount + 1, 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) diff --git a/src/DotRecast.Recast/RcBuilder.cs b/src/DotRecast.Recast/RcBuilder.cs index f0c6ed2..5583f42 100644 --- a/src/DotRecast.Recast/RcBuilder.cs +++ b/src/DotRecast.Recast/RcBuilder.cs @@ -47,9 +47,8 @@ namespace DotRecast.Recast _progressListener = progressListener; } - public List BuildTiles(IInputGeomProvider geom, RcConfig cfg, - int threads = 0, TaskFactory taskFactory = null, CancellationToken cancellation = default, - bool keepInterResults = false, bool buildAll = true) + 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(); diff --git a/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs index 835c247..c03623e 100644 --- a/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/TestTiledNavMeshBuilder.cs @@ -78,7 +78,7 @@ public class TestTiledNavMeshBuilder true, true, true, SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); RcBuilder rcBuilder = new RcBuilder(); - List rcResult = rcBuilder.BuildTiles(geom, cfg); + List rcResult = rcBuilder.BuildTiles(geom, cfg, false, true); // Add tiles to nav mesh diff --git a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs index 2abb9df..8d98546 100644 --- a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs +++ b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs @@ -137,7 +137,7 @@ public class RecastTileMeshTest private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate) { CancellationTokenSource cts = new CancellationTokenSource(); - List tiles = builder.BuildTiles(geom, cfg, threads, 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); From 50ea674ccebb78a707f12d713fdadfe67d3fdf1f Mon Sep 17 00:00:00 2001 From: ikpil Date: Sat, 20 Apr 2024 12:59:34 +0900 Subject: [PATCH 17/24] used option `keepInterResults` to save memory - https://github.com/ikpil/DotRecast/issues/66 - https://github.com/ikpil/DotRecast/issues/61 --- src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs | 4 ++-- src/DotRecast.Recast/RcBuilder.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs index ced313d..71d2c0f 100644 --- a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs @@ -87,8 +87,8 @@ namespace DotRecast.Recast.Toolset.Builder result.TileX, result.TileZ, null, - result.CompactHeightfield, - result.ContourSet, + null, + null, result.Mesh, result.MeshDetail, result.Context diff --git a/src/DotRecast.Recast/RcBuilder.cs b/src/DotRecast.Recast/RcBuilder.cs index 5583f42..8cad533 100644 --- a/src/DotRecast.Recast/RcBuilder.cs +++ b/src/DotRecast.Recast/RcBuilder.cs @@ -144,8 +144,8 @@ namespace DotRecast.Recast result.TileX, result.TileZ, null, - result.CompactHeightfield, - result.ContourSet, + null, + null, result.Mesh, result.MeshDetail, result.Context From 6b2bd27b71179c65e3fedc73d52d7e2b2e221438 Mon Sep 17 00:00:00 2001 From: ikpil Date: Mon, 22 Apr 2024 23:52:01 +0900 Subject: [PATCH 18/24] added RcSpanPool class --- src/DotRecast.Recast/RcHeightfield.cs | 30 +++++++-------------- src/DotRecast.Recast/RcSpanPool.cs | 38 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 src/DotRecast.Recast/RcSpanPool.cs diff --git a/src/DotRecast.Recast/RcHeightfield.cs b/src/DotRecast.Recast/RcHeightfield.cs index dd8b5fc..b46cc99 100644 --- a/src/DotRecast.Recast/RcHeightfield.cs +++ b/src/DotRecast.Recast/RcHeightfield.cs @@ -22,29 +22,17 @@ 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; - - /** 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; + 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). /** Border size in cell units */ public readonly int borderSize; 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 From f49f9eb558d341ac581831c0dd576b643f5b8e26 Mon Sep 17 00:00:00 2001 From: ikpil Date: Mon, 22 Apr 2024 23:57:13 +0900 Subject: [PATCH 19/24] addedd AllocSpan/FreeSpan API --- src/DotRecast.Recast/RcHeightfield.cs | 4 ++ src/DotRecast.Recast/RcRasterizations.cs | 57 ++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/DotRecast.Recast/RcHeightfield.cs b/src/DotRecast.Recast/RcHeightfield.cs index b46cc99..b5eaba9 100644 --- a/src/DotRecast.Recast/RcHeightfield.cs +++ b/src/DotRecast.Recast/RcHeightfield.cs @@ -34,6 +34,10 @@ namespace DotRecast.Recast 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. + 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/RcRasterizations.cs b/src/DotRecast.Recast/RcRasterizations.cs index 9b1f638..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, From bf6ee495d24c4321f9eb649202777aeebb687b0f Mon Sep 17 00:00:00 2001 From: ikpil Date: Wed, 24 Apr 2024 23:40:11 +0900 Subject: [PATCH 20/24] upgrade Silk.NET 2.20.0 -> 2.21.0 --- src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj index 399aa50..15c6da7 100644 --- a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj +++ b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj @@ -2,7 +2,7 @@ Exe - net6.0;net7.0;net8.0 + net8.0 true DotRecast.Recast.Demo README.md @@ -27,8 +27,8 @@ - - + + From 4a80473e2f9125ac3813bb3bacfd0a31bdb045e5 Mon Sep 17 00:00:00 2001 From: ikpil Date: Thu, 25 Apr 2024 00:02:27 +0900 Subject: [PATCH 21/24] fix workflow --- .github/workflows/dotnet.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 972fa7a..aac3f76 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -45,7 +45,9 @@ jobs: run: dotnet restore - name: Build - run: dotnet build -c Release --no-restore --framework net${{ matrix.dotnet-version }}.0 + run: | + dotnet restore + dotnet build -c Release --no-restore --framework net${{ matrix.dotnet-version }}.0 - name: Test run: dotnet test -c Release --no-build --verbosity normal --framework net${{ matrix.dotnet-version }}.0 From f22ec940389df80779c7ba034d0c2fc5f7d8be26 Mon Sep 17 00:00:00 2001 From: ikpil Date: Thu, 25 Apr 2024 00:59:02 +0900 Subject: [PATCH 22/24] support C# 10, 11 in DotRecast.Recast.Demo --- .github/workflows/codeql.yml | 2 +- .github/workflows/dotnet.yml | 6 ++---- .github/workflows/publish.yml | 2 +- .github/workflows/release.yml | 2 +- .../DotRecast.Recast.Demo.csproj | 2 +- .../Draw/GLCheckerTexture.cs | 21 +++++++++++++------ 6 files changed, 21 insertions(+), 14 deletions(-) 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 aac3f76..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 @@ -45,9 +45,7 @@ jobs: run: dotnet restore - name: Build - run: | - dotnet restore - dotnet build -c Release --no-restore --framework net${{ matrix.dotnet-version }}.0 + run: dotnet build -c Release --no-restore --framework net${{ matrix.dotnet-version }}.0 - name: Test run: dotnet test -c Release --no-build --verbosity normal --framework net${{ matrix.dotnet-version }}.0 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.Recast.Demo/DotRecast.Recast.Demo.csproj b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj index 15c6da7..b231327 100644 --- a/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj +++ b/src/DotRecast.Recast.Demo/DotRecast.Recast.Demo.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net6.0;net7.0;net8.0 true DotRecast.Recast.Demo README.md 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 { From 97777511a7e82f679942b22745c22916cc37a376 Mon Sep 17 00:00:00 2001 From: ikpil Date: Thu, 25 Apr 2024 01:18:04 +0900 Subject: [PATCH 23/24] Added the keepInterResults option to RcBuilder.Build() - https://github.com/ikpil/DotRecast/issues/66 --- src/DotRecast.Detour.Dynamic/DtDynamicTile.cs | 2 +- .../Builder/SoloNavMeshBuilder.cs | 17 +--------- src/DotRecast.Recast/RcBuilder.cs | 33 +++++++++---------- .../RecastTestMeshBuilder.cs | 2 +- .../RecastTestMeshBuilder.cs | 2 +- .../TestDetourBuilder.cs | 2 +- .../RecastTileMeshTest.cs | 12 +++---- 7 files changed, 26 insertions(+), 44 deletions(-) diff --git a/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs b/src/DotRecast.Detour.Dynamic/DtDynamicTile.cs index 7712497..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; diff --git a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs index 71d2c0f..10b4c09 100644 --- a/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs +++ b/src/DotRecast.Recast.Toolset/Builder/SoloNavMeshBuilder.cs @@ -80,22 +80,7 @@ namespace DotRecast.Recast.Toolset.Builder { RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilder rcBuilder = new RcBuilder(); - var result = rcBuilder.Build(geom, bcfg); - if (!keepInterResults) - { - return new RcBuilderResult( - result.TileX, - result.TileZ, - null, - null, - null, - result.Mesh, - result.MeshDetail, - result.Context - ); - } - - return result; + return rcBuilder.Build(geom, bcfg, keepInterResults); } public DtMeshData BuildMeshData(DemoInputGeomProvider geom, diff --git a/src/DotRecast.Recast/RcBuilder.cs b/src/DotRecast.Recast/RcBuilder.cs index 8cad533..0620809 100644 --- a/src/DotRecast.Recast/RcBuilder.cs +++ b/src/DotRecast.Recast/RcBuilder.cs @@ -132,30 +132,17 @@ namespace DotRecast.Recast public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, int ty, RcAtomicInteger progress, int total, bool keepInterResults) { var bcfg = new RcBuilderConfig(cfg, bmin, bmax, tx, ty); - RcBuilderResult result = Build(geom, bcfg); + RcBuilderResult result = Build(geom, bcfg, keepInterResults); if (_progressListener != null) { _progressListener.OnProgress(progress.IncrementAndGet(), total); } - if (!keepInterResults) - { - return new RcBuilderResult( - result.TileX, - result.TileZ, - null, - null, - null, - result.Mesh, - result.MeshDetail, - result.Context - ); - } return result; } - public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig bcfg) + public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig bcfg, bool keepInterResults) { RcConfig cfg = bcfg.cfg; RcContext ctx = new RcContext(); @@ -163,10 +150,10 @@ namespace DotRecast.Recast // Step 1. Rasterize input polygon soup. // RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(ctx, geom, bcfg); - return Build(ctx, bcfg.tileX, bcfg.tileZ, geom, cfg, solid); + 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); @@ -237,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 + ); } /* diff --git a/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs b/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs index 7fd70c3..bacecb9 100644 --- a/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs +++ b/test/DotRecast.Detour.Crowd.Test/RecastTestMeshBuilder.cs @@ -72,7 +72,7 @@ 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); + RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg, false); RcPolyMesh m_pmesh = rcResult.Mesh; for (int i = 0; i < m_pmesh.npolys; ++i) { diff --git a/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs b/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs index b1830bb..12c618e 100644 --- a/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs +++ b/test/DotRecast.Detour.Test/RecastTestMeshBuilder.cs @@ -72,7 +72,7 @@ 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); + RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg, false); RcPolyMesh m_pmesh = rcResult.Mesh; for (int i = 0; i < m_pmesh.npolys; ++i) { diff --git a/test/DotRecast.Detour.Test/TestDetourBuilder.cs b/test/DotRecast.Detour.Test/TestDetourBuilder.cs index d7b9268..4df7c6d 100644 --- a/test/DotRecast.Detour.Test/TestDetourBuilder.cs +++ b/test/DotRecast.Detour.Test/TestDetourBuilder.cs @@ -27,7 +27,7 @@ public class TestDetourBuilder : DetourBuilder float agentMaxClimb, int x, int y, bool applyRecastDemoFlags) { RcBuilder rcBuilder = new RcBuilder(); - RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig); + RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig, false); RcPolyMesh pmesh = rcResult.Mesh; if (applyRecastDemoFlags) diff --git a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs index 8d98546..6fa4676 100644 --- a/test/DotRecast.Recast.Test/RecastTileMeshTest.cs +++ b/test/DotRecast.Recast.Test/RecastTileMeshTest.cs @@ -69,27 +69,27 @@ 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); + 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); + 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); + 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); + 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); + 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); + rcResult = builder.Build(geom, bcfg, false); Assert.That(rcResult.Mesh.npolys, Is.EqualTo(6)); Assert.That(rcResult.Mesh.nverts, Is.EqualTo(15)); } From 94e66ed3185486b480737670d1dbd3d8cf51aae9 Mon Sep 17 00:00:00 2001 From: ikpil Date: Tue, 23 Jan 2024 22:49:36 +0900 Subject: [PATCH 24/24] fix: SOH issue (#41) fix: SOH issue step2 (#41) https://github.com/ikpil/DotRecast/issues/41 fix: SOH issue step3 (#41) - https://github.com/ikpil/DotRecast/issues/41 fix : SOH issue (#41) - https://github.com/ikpil/DotRecast/issues/41#issuecomment-1908359895 fix: SOH issue (#41) - https://github.com/ikpil/DotRecast/issues/41#issuecomment-1908365394 fix: SOH issue(#41) https://github.com/ikpil/DotRecast/issues/41#issuecomment-1908367226 array benchmark benchmark array test step2 test ss --- src/DotRecast.Detour.Crowd/DtCrowd.cs | 1 + .../DtObstacleAvoidanceQuery.cs | 3 +- src/DotRecast.Detour/DtNavMesh.cs | 7 ++- src/DotRecast.Detour/DtNavMeshQuery.cs | 57 ++++++++++--------- test/DotRecast.Core.Test/RcRentedArrayTest.cs | 49 ++++++++++++++++ 5 files changed, 86 insertions(+), 31 deletions(-) diff --git a/src/DotRecast.Detour.Crowd/DtCrowd.cs b/src/DotRecast.Detour.Crowd/DtCrowd.cs index 892c4b3..4afc826 100644 --- a/src/DotRecast.Detour.Crowd/DtCrowd.cs +++ b/src/DotRecast.Detour.Crowd/DtCrowd.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using DotRecast.Core; +using DotRecast.Core.Buffers; using DotRecast.Core.Collections; using DotRecast.Core.Numerics; diff --git a/src/DotRecast.Detour.Crowd/DtObstacleAvoidanceQuery.cs b/src/DotRecast.Detour.Crowd/DtObstacleAvoidanceQuery.cs index 1b6e240..c06b210 100644 --- a/src/DotRecast.Detour.Crowd/DtObstacleAvoidanceQuery.cs +++ b/src/DotRecast.Detour.Crowd/DtObstacleAvoidanceQuery.cs @@ -20,6 +20,7 @@ freely, subject to the following restrictions: using System; using DotRecast.Core; +using DotRecast.Core.Buffers; using DotRecast.Core.Numerics; @@ -402,7 +403,7 @@ namespace DotRecast.Detour.Crowd debug.Reset(); // Build sampling pattern aligned to desired velocity. - float[] pat = new float[(DT_MAX_PATTERN_DIVS * DT_MAX_PATTERN_RINGS + 1) * 2]; + using var pat = RcRentedArray.Rent((DT_MAX_PATTERN_DIVS * DT_MAX_PATTERN_RINGS + 1) * 2); int npat = 0; int ndivs = m_params.adaptiveDivs; diff --git a/src/DotRecast.Detour/DtNavMesh.cs b/src/DotRecast.Detour/DtNavMesh.cs index 4b5f49d..a0a162f 100644 --- a/src/DotRecast.Detour/DtNavMesh.cs +++ b/src/DotRecast.Detour/DtNavMesh.cs @@ -21,6 +21,7 @@ freely, subject to the following restrictions: using System; using System.Collections.Generic; using DotRecast.Core; +using DotRecast.Core.Buffers; using DotRecast.Core.Numerics; namespace DotRecast.Detour @@ -1246,14 +1247,14 @@ namespace DotRecast.Detour int ip = poly.index; - float[] verts = new float[m_maxVertPerPoly * 3]; + using var verts = RcRentedArray.Rent(m_maxVertPerPoly * 3); int nv = poly.vertCount; for (int i = 0; i < nv; ++i) { - RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts, i * 3, 3); + RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts.AsArray(), i * 3, 3); } - if (!DtUtils.PointInPolygon(pos, verts, nv)) + if (!DtUtils.PointInPolygon(pos, verts.AsArray(), nv)) { return false; } diff --git a/src/DotRecast.Detour/DtNavMeshQuery.cs b/src/DotRecast.Detour/DtNavMeshQuery.cs index c4dd060..5eb8e92 100644 --- a/src/DotRecast.Detour/DtNavMeshQuery.cs +++ b/src/DotRecast.Detour/DtNavMeshQuery.cs @@ -21,6 +21,7 @@ freely, subject to the following restrictions: using System; using System.Collections.Generic; using DotRecast.Core; +using DotRecast.Core.Buffers; using DotRecast.Core.Collections; using DotRecast.Core.Numerics; @@ -41,9 +42,9 @@ namespace DotRecast.Detour public DtNavMeshQuery(DtNavMesh nav) { m_nav = nav; - m_tinyNodePool = new DtNodePool(); m_nodePool = new DtNodePool(); m_openList = new DtNodeQueue(); + m_tinyNodePool = new DtNodePool(); } /// Returns random location on navmesh. @@ -137,18 +138,18 @@ namespace DotRecast.Detour } // Randomly pick point on polygon. - float[] verts = new float[3 * m_nav.GetMaxVertsPerPoly()]; - float[] areas = new float[m_nav.GetMaxVertsPerPoly()]; - RcArrays.Copy(tile.data.verts, poly.verts[0] * 3, verts, 0, 3); + using var verts = RcRentedArray.Rent(3 * m_nav.GetMaxVertsPerPoly()); + using var areas = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly()); + RcArrays.Copy(tile.data.verts, poly.verts[0] * 3, verts.AsArray(), 0, 3); for (int j = 1; j < poly.vertCount; ++j) { - RcArrays.Copy(tile.data.verts, poly.verts[j] * 3, verts, j * 3, 3); + RcArrays.Copy(tile.data.verts, poly.verts[j] * 3, verts.AsArray(), j * 3, 3); } float s = frand.Next(); float t = frand.Next(); - var pt = DtUtils.RandomPointInConvexPoly(verts, poly.vertCount, areas, s, t); + var pt = DtUtils.RandomPointInConvexPoly(verts.AsArray(), poly.vertCount, areas.AsArray(), s, t); ClosestPointOnPoly(polyRef, pt, out var closest, out var _); randomRef = polyRef; @@ -386,8 +387,8 @@ namespace DotRecast.Detour float s = frand.Next(); float t = frand.Next(); - float[] areas = new float[randomPolyVerts.Length / 3]; - RcVec3f pt = DtUtils.RandomPointInConvexPoly(randomPolyVerts, randomPolyVerts.Length / 3, areas, s, t); + using var areas = RcRentedArray.Rent(randomPolyVerts.Length / 3); + RcVec3f pt = DtUtils.RandomPointInConvexPoly(randomPolyVerts, randomPolyVerts.Length / 3, areas.AsArray(), s, t); ClosestPointOnPoly(randomPolyRef, pt, out var closest, out var _); randomRef = randomPolyRef; @@ -457,16 +458,16 @@ namespace DotRecast.Detour } // Collect vertices. - float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3]; - float[] edged = new float[m_nav.GetMaxVertsPerPoly()]; - float[] edget = new float[m_nav.GetMaxVertsPerPoly()]; + using var verts = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly() * 3); + using var edged = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly()); + using var edget = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly()); int nv = poly.vertCount; for (int i = 0; i < nv; ++i) { - RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts, i * 3, 3); + RcArrays.Copy(tile.data.verts, poly.verts[i] * 3, verts.AsArray(), i * 3, 3); } - if (DtUtils.DistancePtPolyEdgesSqr(pos, verts, nv, edged, edget)) + if (DtUtils.DistancePtPolyEdgesSqr(pos, verts.AsArray(), nv, edged.AsArray(), edget.AsArray())) { closest = pos; } @@ -486,7 +487,7 @@ namespace DotRecast.Detour int va = imin * 3; int vb = ((imin + 1) % nv) * 3; - closest = RcVecUtils.Lerp(verts, va, vb, edget[imin]); + closest = RcVecUtils.Lerp(verts.AsArray(), va, vb, edget[imin]); } return DtStatus.DT_SUCCESS; @@ -1793,7 +1794,9 @@ namespace DotRecast.Detour resultPos = RcVec3f.Zero; if (null != visited) + { visited.Clear(); + } // Validate input if (!m_nav.IsValidPolyRef(startRef) || !startPos.IsFinite() @@ -1822,7 +1825,7 @@ namespace DotRecast.Detour var searchPos = RcVec3f.Lerp(startPos, endPos, 0.5f); float searchRadSqr = RcMath.Sqr(RcVec3f.Distance(startPos, endPos) / 2.0f + 0.001f); - float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3]; + using var verts = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly() * 3); const int MAX_NEIS = 8; Span neis = stackalloc long[MAX_NEIS]; @@ -1842,11 +1845,11 @@ namespace DotRecast.Detour int nverts = curPoly.vertCount; for (int i = 0; i < nverts; ++i) { - RcArrays.Copy(curTile.data.verts, curPoly.verts[i] * 3, verts, i * 3, 3); + RcArrays.Copy(curTile.data.verts, curPoly.verts[i] * 3, verts.AsArray(), i * 3, 3); } // If target is inside the poly, stop search. - if (DtUtils.PointInPolygon(endPos, verts, nverts)) + if (DtUtils.PointInPolygon(endPos, verts.AsArray(), nverts)) { bestNode = curNode; bestPos = endPos; @@ -1897,11 +1900,11 @@ namespace DotRecast.Detour // Wall edge, calc distance. int vj = j * 3; int vi = i * 3; - var distSqr = DtUtils.DistancePtSegSqr2D(endPos, verts, vj, vi, out var tseg); + var distSqr = DtUtils.DistancePtSegSqr2D(endPos, verts.AsArray(), vj, vi, out var tseg); if (distSqr < bestDist) { // Update nearest distance. - bestPos = RcVecUtils.Lerp(verts, vj, vi, tseg); + bestPos = RcVecUtils.Lerp(verts.AsArray(), vj, vi, tseg); bestDist = distSqr; bestNode = curNode; } @@ -1921,7 +1924,7 @@ namespace DotRecast.Detour // TODO: Maybe should use GetPortalPoints(), but this one is way faster. int vj = j * 3; int vi = i * 3; - var distSqr = DtUtils.DistancePtSegSqr2D(searchPos, verts, vj, vi, out var _); + var distSqr = DtUtils.DistancePtSegSqr2D(searchPos, verts.AsArray(), vj, vi, out var _); if (distSqr > searchRadSqr) { continue; @@ -2245,7 +2248,7 @@ namespace DotRecast.Detour hit.path.Clear(); hit.pathCost = 0; - RcVec3f[] verts = new RcVec3f[m_nav.GetMaxVertsPerPoly() + 1]; + using var verts = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly() + 1); RcVec3f curPos = RcVec3f.Zero; RcVec3f lastPos = RcVec3f.Zero; @@ -2279,7 +2282,7 @@ namespace DotRecast.Detour nv++; } - bool intersects = DtUtils.IntersectSegmentPoly2D(startPos, endPos, verts, nv, out var tmin, out var tmax, out var segMin, out var segMax); + bool intersects = DtUtils.IntersectSegmentPoly2D(startPos, endPos, verts.AsArray(), nv, out var tmin, out var tmax, out var segMin, out var segMax); if (!intersects) { // Could not hit the polygon, keep the old t and report hit. @@ -2874,8 +2877,8 @@ namespace DotRecast.Detour float radiusSqr = RcMath.Sqr(radius); - float[] pa = new float[m_nav.GetMaxVertsPerPoly() * 3]; - float[] pb = new float[m_nav.GetMaxVertsPerPoly() * 3]; + using var pa = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly() * 3); + using var pb = RcRentedArray.Rent(m_nav.GetMaxVertsPerPoly() * 3); while (0 < stack.Count) { @@ -2946,7 +2949,7 @@ namespace DotRecast.Detour int npa = neighbourPoly.vertCount; for (int k = 0; k < npa; ++k) { - RcArrays.Copy(neighbourTile.data.verts, neighbourPoly.verts[k] * 3, pa, k * 3, 3); + RcArrays.Copy(neighbourTile.data.verts, neighbourPoly.verts[k] * 3, pa.AsArray(), k * 3, 3); } bool overlap = false; @@ -2977,10 +2980,10 @@ namespace DotRecast.Detour int npb = pastPoly.vertCount; for (int k = 0; k < npb; ++k) { - RcArrays.Copy(pastTile.data.verts, pastPoly.verts[k] * 3, pb, k * 3, 3); + RcArrays.Copy(pastTile.data.verts, pastPoly.verts[k] * 3, pb.AsArray(), k * 3, 3); } - if (DtUtils.OverlapPolyPoly2D(pa, npa, pb, npb)) + if (DtUtils.OverlapPolyPoly2D(pa.AsArray(), npa, pb.AsArray(), npb)) { overlap = true; break; diff --git a/test/DotRecast.Core.Test/RcRentedArrayTest.cs b/test/DotRecast.Core.Test/RcRentedArrayTest.cs index 07d1f1b..50007f2 100644 --- a/test/DotRecast.Core.Test/RcRentedArrayTest.cs +++ b/test/DotRecast.Core.Test/RcRentedArrayTest.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Xml; using DotRecast.Core.Buffers; +using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization; using NUnit.Framework; namespace DotRecast.Core.Test; @@ -56,4 +59,50 @@ public class RcRentedArrayTest Assert.Throws(() => rentedArray[^1] = 0); } } + + [Test] + public void TestSame() + { + // not same + { + using var r1 = RcRentedArray.Rent(1024); + using var r2 = RcRentedArray.Rent(1024); + + Assert.That(r2.AsArray() != r1.AsArray(), Is.EqualTo(true)); + } + + // same + { + // error case + float[] r1Array; + using (var r1 = RcRentedArray.Rent(1024)) + { + r1Array = r1.AsArray(); + for (int i = 0; i < r1.Length; ++i) + { + r1[i] = 123; + } + } + + using var r2 = RcRentedArray.Rent(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(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); + } } \ No newline at end of file