Compare commits

..

No commits in common. "f49f9eb558d341ac581831c0dd576b643f5b8e26" and "b81a5923a3c96e288f2dbc3a8faf45644f2d2868" have entirely different histories.

43 changed files with 369 additions and 470 deletions

View File

@ -20,7 +20,6 @@ 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

View File

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

View File

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

View File

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

View File

@ -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.Mesh;
RcPolyMeshDetail m_dmesh = rcResult.MeshDetail;
RcPolyMesh m_pmesh = rcResult.GetMesh();
RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
for (int i = 0; i < m_pmesh.npolys; ++i)
{

View File

@ -109,13 +109,13 @@ namespace DotRecast.Detour.Dynamic.Io
};
foreach (RcBuilderResult r in results)
{
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);
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);
}
return f;

View File

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

View File

@ -16,25 +16,25 @@ namespace DotRecast.Detour.Extras.Jumplink
private DtNavMeshQuery CreateNavMesh(RcBuilderResult r, float agentRadius, float agentHeight, float agentClimb)
{
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
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.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.walkableRadius = agentRadius;
option.walkableHeight = agentHeight;
option.walkableClimb = agentClimb;
option.bmin = r.Mesh.bmin;
option.bmax = r.Mesh.bmax;
option.cs = r.Mesh.cs;
option.ch = r.Mesh.ch;
option.bmin = r.GetMesh().bmin;
option.bmax = r.GetMesh().bmax;
option.cs = r.GetMesh().cs;
option.ch = r.GetMesh().ch;
option.buildBvTree = true;
return new DtNavMeshQuery(new DtNavMesh(DtNavMeshBuilder.CreateNavMeshData(option), option.nvp, 0));
}

View File

@ -358,8 +358,8 @@ namespace DotRecast.Detour
var tbmax = tile.data.header.bmax;
float qfac = tile.data.header.bvQuantFactor;
// Calculate quantized box
Span<int> bmin = stackalloc int[3];
Span<int> bmax = stackalloc int[3];
int[] bmin = new int[3];
int[] bmax = new 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;

View File

@ -583,8 +583,8 @@ namespace DotRecast.Detour
var tbmax = tile.data.header.bmax;
float qfac = tile.data.header.bvQuantFactor;
// Calculate quantized box
Span<int> bmin = stackalloc int[3];
Span<int> bmax = stackalloc int[3];
int[] bmin = new int[3];
int[] bmax = new 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,9 +1824,6 @@ namespace DotRecast.Detour
float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3];
const int MAX_NEIS = 8;
Span<long> neis = stackalloc long[MAX_NEIS];
while (0 < stack.Count)
{
// Pop front.
@ -1857,7 +1854,9 @@ 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)
{

View File

@ -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(Span<int> amin, Span<int> amax, Span<int> bmin, Span<int> bmax)
public static bool OverlapQuantBounds(int[] amin, int[] amax, int[] bmin, int[] bmax)
{
bool overlap = true;
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;

View File

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

View File

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

View File

@ -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<RcBuilderResult>.Empty, null);
_menuView = new RcMenuView();
settingsView = new RcSettingsView(this);
settingsView.SetSample(_sample);
@ -537,7 +537,6 @@ public class RecastDemo : IRecastDemoChannel
bool hasBound = false;
RcVec3f bminN = RcVec3f.Zero;
RcVec3f bmaxN = RcVec3f.Zero;
if (_sample.GetInputGeom() != null)
{
bminN = _sample.GetInputGeom().GetMeshBoundsMin();
@ -553,7 +552,7 @@ public class RecastDemo : IRecastDemoChannel
{
foreach (RcBuilderResult result in _sample.GetRecastResults())
{
if (result.CompactHeightfield != null)
if (result.GetSolidHeightfield() != null)
{
if (!hasBound)
{
@ -562,15 +561,15 @@ public class RecastDemo : IRecastDemoChannel
}
bminN = new RcVec3f(
Math.Min(bminN.X, result.CompactHeightfield.bmin.X),
Math.Min(bminN.Y, result.CompactHeightfield.bmin.Y),
Math.Min(bminN.Z, result.CompactHeightfield.bmin.Z)
Math.Min(bminN.X, result.GetSolidHeightfield().bmin.X),
Math.Min(bminN.Y, result.GetSolidHeightfield().bmin.Y),
Math.Min(bminN.Z, result.GetSolidHeightfield().bmin.Z)
);
bmaxN = new RcVec3f(
Math.Max(bmaxN.X, result.CompactHeightfield.bmax.X),
Math.Max(bmaxN.Y, result.CompactHeightfield.bmax.Y),
Math.Max(bmaxN.Z, result.CompactHeightfield.bmax.Z)
Math.Max(bmaxN.X, result.GetSolidHeightfield().bmax.X),
Math.Max(bmaxN.Y, result.GetSolidHeightfield().bmax.Y),
Math.Max(bmaxN.Z, result.GetSolidHeightfield().bmax.Z)
);
hasBound = true;
@ -578,15 +577,12 @@ 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;
@ -692,15 +688,14 @@ public class RecastDemo : IRecastDemoChannel
NavMeshBuildResult buildResult;
var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings();
if (settings.tiled)
{
buildResult = tileNavMeshBuilder.Build(geom, settings);
buildResult = tileNavMeshBuilder.Build(_sample.GetInputGeom(), settings);
}
else
{
buildResult = soloNavMeshBuilder.Build(geom, settings);
buildResult = soloNavMeshBuilder.Build(_sample.GetInputGeom(), settings);
}
if (!buildResult.Success)
@ -718,7 +713,7 @@ public class RecastDemo : IRecastDemoChannel
Logger.Information($"build times");
Logger.Information($"-----------------------------------------");
var telemetries = buildResult.RecastBuilderResults
.Select(x => x.Context)
.Select(x => x.GetTelemetry())
.SelectMany(x => x.ToList())
.GroupBy(x => x.Key)
.ToImmutableSortedDictionary(x => x.Key, x => x.Sum(y => y.Millis));

View File

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

View File

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

View File

@ -166,10 +166,6 @@ public class RcSettingsView : IRcView
ImGui.SliderFloat("Max Sample Error", ref settings.detailSampleMaxError, 0f, 16f, "%.1f");
ImGui.NewLine();
ImGui.Checkbox("Keep Itermediate Results", ref settings.keepInterResults);
ImGui.Checkbox("Build All Tiles", ref settings.buildAll);
ImGui.NewLine();
ImGui.Text("Tiling");
ImGui.Separator();
ImGui.Checkbox("Enable", ref settings.tiled);
@ -232,12 +228,6 @@ 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();
}
@ -272,4 +262,4 @@ public class RcSettingsView : IRcView
{
this.maxPolys = maxPolys;
}
}
}

View File

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

View File

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

View File

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

View File

@ -31,8 +31,5 @@
public bool tiled = false;
public int tileSize = 32;
public bool keepInterResults = false;
public bool buildAll = true;
}
}

View File

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

View File

@ -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, settings.keepInterResults);
var result = rb.BuildTile(geom, cfg, bmin, bmax, tx, ty, new RcAtomicInteger(0), 1);
var tb = new TileNavMeshBuilder();
var meshData = tb.BuildMeshData(geom, settings.cellSize, settings.cellHeight, settings.agentHeight, settings.agentRadius, settings.agentMaxClimb, RcImmutableArray.Create(result)

View File

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

View File

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

View File

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

View File

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

View File

@ -41,63 +41,6 @@ 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,
@ -213,7 +156,7 @@ namespace DotRecast.Recast
float axisOffset, int axis)
{
// How far positive or negative away from the separating axis is each vertex.
Span<float> inVertAxisDelta = stackalloc float[12];
float[] inVertAxisDelta = new float[12];
for (int inVert = 0; inVert < inVertsCount; ++inVert)
{
inVertAxisDelta[inVert] = axisOffset - inVerts[inVertsOffset + inVert * 3 + axis];

View File

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

View File

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

View File

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

View File

@ -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.Mesh;
RcPolyMesh m_pmesh = rcResult.GetMesh();
for (int i = 0; i < m_pmesh.npolys; ++i)
{
m_pmesh.flags[i] = 1;
}
RcPolyMeshDetail m_dmesh = rcResult.MeshDetail;
RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
option.verts = m_pmesh.verts;
option.vertCount = m_pmesh.nverts;

View File

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

View File

@ -10,6 +10,7 @@ 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);
@ -31,7 +32,9 @@ public class DynamicNavMeshTest
// create dynamic navmesh
DtDynamicNavMesh mesh = new DtDynamicNavMesh(f);
// build navmesh asynchronously using multiple threads
mesh.Build(Task.Factory);
Task<bool> future = mesh.Build(Task.Factory);
// wait for build to complete
bool _ = future.Result;
// create new query
DtNavMeshQuery query = new DtNavMeshQuery(mesh.NavMesh());
@ -51,8 +54,9 @@ public class DynamicNavMeshTest
long colliderId = mesh.AddCollider(colldier);
// update navmesh asynchronously
mesh.Update(Task.Factory);
future = mesh.Update(Task.Factory);
// wait for update to complete
_ = future.Result;
// create new query
query = new DtNavMeshQuery(mesh.NavMesh());
@ -66,7 +70,9 @@ public class DynamicNavMeshTest
// remove obstacle
mesh.RemoveCollider(colliderId);
// update navmesh asynchronously
mesh.Update(Task.Factory);
future = mesh.Update(Task.Factory);
// wait for update to complete
_ = future.Result;
// create new query
query = new DtNavMeshQuery(mesh.NavMesh());

View File

@ -31,6 +31,7 @@ using NUnit.Framework;
namespace DotRecast.Detour.Dynamic.Test;
public class VoxelQueryTest
{
private const int TILE_WIDTH = 100;
@ -100,12 +101,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
mesh.Build(Task.Factory);
Task<bool> future = mesh.Build(Task.Factory);
// wait for build to complete
var _ = future.Result;
return mesh;
}
}

View File

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

View File

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

View File

@ -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.Mesh;
RcPolyMesh m_pmesh = rcResult.GetMesh();
for (int i = 0; i < m_pmesh.npolys; ++i)
{
m_pmesh.flags[i] = 1;
}
RcPolyMeshDetail m_dmesh = rcResult.MeshDetail;
RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
DtNavMeshCreateParams option = new DtNavMeshCreateParams();
option.verts = m_pmesh.verts;
option.vertCount = m_pmesh.nverts;

View File

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

View File

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

View File

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

View File

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

View File

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