refactor: rename

This commit is contained in:
ikpil 2023-09-22 23:42:21 +09:00
parent 087582c42e
commit 07e6b08517
54 changed files with 589 additions and 639 deletions

View File

@ -63,7 +63,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry) public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
{ {
RecastFilledVolumeRasterization.RasterizeBox( RcFilledVolumeRasterization.RasterizeBox(
hf, center, halfEdges, area, (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry); hf, center, halfEdges, area, (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry);
} }

View File

@ -39,8 +39,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry) public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
{ {
RecastFilledVolumeRasterization.RasterizeCapsule(hf, start, end, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch), RcFilledVolumeRasterization.RasterizeCapsule(hf, start, end, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry);
telemetry);
} }
private static float[] Bounds(RcVec3f start, RcVec3f end, float radius) private static float[] Bounds(RcVec3f start, RcVec3f end, float radius)

View File

@ -44,7 +44,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry) public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
{ {
RecastFilledVolumeRasterization.RasterizeConvex(hf, vertices, triangles, area, RcFilledVolumeRasterization.RasterizeConvex(hf, vertices, triangles, area,
(int)Math.Floor(flagMergeThreshold / hf.ch), telemetry); (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry);
} }
} }

View File

@ -39,7 +39,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry) public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
{ {
RecastFilledVolumeRasterization.RasterizeCylinder(hf, start, end, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch), RcFilledVolumeRasterization.RasterizeCylinder(hf, start, end, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch),
telemetry); telemetry);
} }

View File

@ -37,7 +37,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry) public override void Rasterize(RcHeightfield hf, RcTelemetry telemetry)
{ {
RecastFilledVolumeRasterization.RasterizeSphere(hf, center, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch), RcFilledVolumeRasterization.RasterizeSphere(hf, center, radius, area, (int)Math.Floor(flagMergeThreshold / hf.ch),
telemetry); telemetry);
} }

View File

@ -62,7 +62,7 @@ namespace DotRecast.Detour.Dynamic.Colliders
{ {
for (int i = 0; i < triangles.Length; i += 3) for (int i = 0; i < triangles.Length; i += 3)
{ {
RecastRasterization.RasterizeTriangle(hf, vertices, triangles[i], triangles[i + 1], triangles[i + 2], area, RcRasterizations.RasterizeTriangle(hf, vertices, triangles[i], triangles[i + 1], triangles[i + 2], area,
(int)Math.Floor(flagMergeThreshold / hf.ch), telemetry); (int)Math.Floor(flagMergeThreshold / hf.ch), telemetry);
} }
} }

View File

@ -33,7 +33,7 @@ namespace DotRecast.Detour.Dynamic
{ {
public const int MAX_VERTS_PER_POLY = 6; public const int MAX_VERTS_PER_POLY = 6;
public readonly DtDynamicNavMeshConfig config; public readonly DtDynamicNavMeshConfig config;
private readonly RecastBuilder builder; private readonly RcBuilder builder;
private readonly Dictionary<long, DtDynamicTile> _tiles = new Dictionary<long, DtDynamicTile>(); private readonly Dictionary<long, DtDynamicTile> _tiles = new Dictionary<long, DtDynamicTile>();
private readonly RcTelemetry telemetry; private readonly RcTelemetry telemetry;
private readonly DtNavMeshParams navMeshParams; private readonly DtNavMeshParams navMeshParams;
@ -57,7 +57,7 @@ namespace DotRecast.Detour.Dynamic
config.buildDetailMesh = voxelFile.buildMeshDetail; config.buildDetailMesh = voxelFile.buildMeshDetail;
config.detailSampleDistance = voxelFile.detailSampleDistance; config.detailSampleDistance = voxelFile.detailSampleDistance;
config.detailSampleMaxError = voxelFile.detailSampleMaxError; config.detailSampleMaxError = voxelFile.detailSampleMaxError;
builder = new RecastBuilder(); builder = new RcBuilder();
navMeshParams = new DtNavMeshParams(); navMeshParams = new DtNavMeshParams();
navMeshParams.orig.x = voxelFile.bounds[0]; navMeshParams.orig.x = voxelFile.bounds[0];
navMeshParams.orig.y = voxelFile.bounds[1]; navMeshParams.orig.y = voxelFile.bounds[1];
@ -254,7 +254,7 @@ namespace DotRecast.Detour.Dynamic
return _tiles.Values.Select(t => t.voxelTile).ToList(); return _tiles.Values.Select(t => t.voxelTile).ToList();
} }
public List<RecastBuilderResult> RecastResults() public List<RcBuilderResult> RecastResults()
{ {
return _tiles.Values.Select(t => t.recastResult).ToList(); return _tiles.Values.Select(t => t.recastResult).ToList();
} }

View File

@ -33,7 +33,7 @@ namespace DotRecast.Detour.Dynamic
{ {
public readonly DtVoxelTile voxelTile; public readonly DtVoxelTile voxelTile;
public DtDynamicTileCheckpoint checkpoint; public DtDynamicTileCheckpoint checkpoint;
public RecastBuilderResult recastResult; public RcBuilderResult recastResult;
private DtMeshData meshData; private DtMeshData meshData;
private readonly ConcurrentDictionary<long, IDtCollider> colliders = new ConcurrentDictionary<long, IDtCollider>(); private readonly ConcurrentDictionary<long, IDtCollider> colliders = new ConcurrentDictionary<long, IDtCollider>();
private bool dirty = true; private bool dirty = true;
@ -44,12 +44,12 @@ namespace DotRecast.Detour.Dynamic
this.voxelTile = voxelTile; this.voxelTile = voxelTile;
} }
public bool Build(RecastBuilder builder, DtDynamicNavMeshConfig config, RcTelemetry telemetry) public bool Build(RcBuilder builder, DtDynamicNavMeshConfig config, RcTelemetry telemetry)
{ {
if (dirty) if (dirty)
{ {
RcHeightfield heightfield = BuildHeightfield(config, telemetry); RcHeightfield heightfield = BuildHeightfield(config, telemetry);
RecastBuilderResult r = BuildRecast(builder, config, voxelTile, heightfield, telemetry); RcBuilderResult r = BuildRecast(builder, config, voxelTile, heightfield, telemetry);
DtNavMeshCreateParams option = NavMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize, DtNavMeshCreateParams option = NavMeshCreateParams(voxelTile.tileX, voxelTile.tileZ, voxelTile.cellSize,
voxelTile.cellHeight, config, r); voxelTile.cellHeight, config, r);
meshData = DtNavMeshBuilder.CreateNavMeshData(option); meshData = DtNavMeshBuilder.CreateNavMeshData(option);
@ -86,7 +86,7 @@ namespace DotRecast.Detour.Dynamic
return heightfield; return heightfield;
} }
private RecastBuilderResult BuildRecast(RecastBuilder builder, DtDynamicNavMeshConfig config, DtVoxelTile vt, private RcBuilderResult BuildRecast(RcBuilder builder, DtDynamicNavMeshConfig config, DtVoxelTile vt,
RcHeightfield heightfield, RcTelemetry telemetry) RcHeightfield heightfield, RcTelemetry telemetry)
{ {
RcConfig rcConfig = new RcConfig( RcConfig rcConfig = new RcConfig(
@ -100,7 +100,7 @@ namespace DotRecast.Detour.Dynamic
Math.Min(DtDynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly), Math.Min(DtDynamicNavMesh.MAX_VERTS_PER_POLY, config.vertsPerPoly),
config.detailSampleDistance, config.detailSampleMaxError, config.detailSampleDistance, config.detailSampleMaxError,
true, true, true, null, true); true, true, true, null, true);
RecastBuilderResult r = builder.Build(vt.tileX, vt.tileZ, null, rcConfig, heightfield, telemetry); RcBuilderResult r = builder.Build(vt.tileX, vt.tileZ, null, rcConfig, heightfield, telemetry);
if (config.keepIntermediateResults) if (config.keepIntermediateResults)
{ {
recastResult = r; recastResult = r;
@ -130,7 +130,7 @@ namespace DotRecast.Detour.Dynamic
} }
private DtNavMeshCreateParams NavMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight, private DtNavMeshCreateParams NavMeshCreateParams(int tilex, int tileZ, float cellSize, float cellHeight,
DtDynamicNavMeshConfig config, RecastBuilderResult rcResult) DtDynamicNavMeshConfig config, RcBuilderResult rcResult)
{ {
RcPolyMesh m_pmesh = rcResult.GetMesh(); RcPolyMesh m_pmesh = rcResult.GetMesh();
RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail(); RcPolyMeshDetail m_dmesh = rcResult.GetMeshDetail();

View File

@ -77,7 +77,7 @@ namespace DotRecast.Detour.Dynamic.Io
walkbableAreaMod, buildMeshDetail); walkbableAreaMod, buildMeshDetail);
} }
public static DtVoxelFile From(RcConfig config, List<RecastBuilderResult> results) public static DtVoxelFile From(RcConfig config, List<RcBuilderResult> results)
{ {
DtVoxelFile f = new DtVoxelFile(); DtVoxelFile f = new DtVoxelFile();
f.version = 1; f.version = 1;
@ -106,7 +106,7 @@ namespace DotRecast.Detour.Dynamic.Io
float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity,
float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity
}; };
foreach (RecastBuilderResult r in results) foreach (RcBuilderResult r in results)
{ {
f.tiles.Add(new DtVoxelTile(r.tileX, r.tileZ, r.GetSolidHeightfield())); 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[0] = Math.Min(f.bounds[0], r.GetSolidHeightfield().bmin.x);

View File

@ -1,7 +1,6 @@
using System; using System;
using DotRecast.Core; using DotRecast.Core;
using DotRecast.Recast; using DotRecast.Recast;
using static DotRecast.Core.RcMath;
namespace DotRecast.Detour.Extras.Jumplink namespace DotRecast.Detour.Extras.Jumplink
{ {
@ -22,7 +21,7 @@ namespace DotRecast.Detour.Extras.Jumplink
} }
} }
public abstract void Sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es); public abstract void Sample(JumpLinkBuilderConfig acfg, RcBuilderResult result, EdgeSampler es);
protected void SampleGroundSegment(ComputeNavMeshHeight heightFunc, GroundSegment seg, int nsamples) protected void SampleGroundSegment(ComputeNavMeshHeight heightFunc, GroundSegment seg, int nsamples)
{ {

View File

@ -4,6 +4,6 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
public interface IGroundSampler public interface IGroundSampler
{ {
void Sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es); void Sample(JumpLinkBuilderConfig acfg, RcBuilderResult result, EdgeSampler es);
} }
} }

View File

@ -15,9 +15,9 @@ namespace DotRecast.Detour.Extras.Jumplink
private readonly JumpSegmentBuilder jumpSegmentBuilder = new JumpSegmentBuilder(); private readonly JumpSegmentBuilder jumpSegmentBuilder = new JumpSegmentBuilder();
private readonly List<JumpEdge[]> edges; private readonly List<JumpEdge[]> edges;
private readonly IList<RecastBuilderResult> results; private readonly IList<RcBuilderResult> results;
public JumpLinkBuilder(IList<RecastBuilderResult> results) public JumpLinkBuilder(IList<RcBuilderResult> results)
{ {
this.results = results; this.results = results;
edges = results.Select(r => edgeExtractor.ExtractEdges(r.GetMesh())).ToList(); edges = results.Select(r => edgeExtractor.ExtractEdges(r.GetMesh())).ToList();
@ -38,7 +38,7 @@ namespace DotRecast.Detour.Extras.Jumplink
return links; return links;
} }
private List<JumpLink> ProcessEdge(JumpLinkBuilderConfig acfg, RecastBuilderResult result, JumpLinkType type, JumpEdge edge) private List<JumpLink> ProcessEdge(JumpLinkBuilderConfig acfg, RcBuilderResult result, JumpLinkType type, JumpEdge edge)
{ {
EdgeSampler es = edgeSamplerFactory.Get(acfg, type, edge); EdgeSampler es = edgeSamplerFactory.Get(acfg, type, edge);
groundSampler.Sample(acfg, result, es); groundSampler.Sample(acfg, result, es);

View File

@ -7,13 +7,13 @@ namespace DotRecast.Detour.Extras.Jumplink
{ {
class NavMeshGroundSampler : AbstractGroundSampler class NavMeshGroundSampler : AbstractGroundSampler
{ {
public override void Sample(JumpLinkBuilderConfig acfg, RecastBuilderResult result, EdgeSampler es) public override void Sample(JumpLinkBuilderConfig acfg, RcBuilderResult result, EdgeSampler es)
{ {
DtNavMeshQuery navMeshQuery = CreateNavMesh(result, acfg.agentRadius, acfg.agentHeight, acfg.agentClimb); DtNavMeshQuery navMeshQuery = CreateNavMesh(result, acfg.agentRadius, acfg.agentHeight, acfg.agentClimb);
SampleGround(acfg, es, (RcVec3f pt, float heightRange, out float height) => GetNavMeshHeight(navMeshQuery, pt, acfg.cellSize, heightRange, out height)); SampleGround(acfg, es, (RcVec3f pt, float heightRange, out float height) => GetNavMeshHeight(navMeshQuery, pt, acfg.cellSize, heightRange, out height));
} }
private DtNavMeshQuery CreateNavMesh(RecastBuilderResult r, float agentRadius, float agentHeight, float agentClimb) private DtNavMeshQuery CreateNavMesh(RcBuilderResult r, float agentRadius, float agentHeight, float agentClimb)
{ {
DtNavMeshCreateParams option = new DtNavMeshCreateParams(); DtNavMeshCreateParams option = new DtNavMeshCreateParams();
option.verts = r.GetMesh().verts; option.verts = r.GetMesh().verts;

View File

@ -86,10 +86,10 @@ namespace DotRecast.Detour.TileCache
protected virtual RcHeightfieldLayerSet BuildHeightfieldLayerSet(IInputGeomProvider geom, RcConfig cfg, int tx, int ty) protected virtual RcHeightfieldLayerSet BuildHeightfieldLayerSet(IInputGeomProvider geom, RcConfig cfg, int tx, int ty)
{ {
RecastBuilder rcBuilder = new RecastBuilder(); RcBuilder rcBuilder = new RcBuilder();
RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax(); RcVec3f bmax = geom.GetMeshBoundsMax();
RecastBuilderConfig builderCfg = new RecastBuilderConfig(cfg, bmin, bmax, tx, ty); RcBuilderConfig builderCfg = new RcBuilderConfig(cfg, bmin, bmax, tx, ty);
RcHeightfieldLayerSet lset = rcBuilder.BuildLayers(geom, builderCfg); RcHeightfieldLayerSet lset = rcBuilder.BuildLayers(geom, builderCfg);
return lset; return lset;
} }

View File

@ -32,10 +32,10 @@ namespace DotRecast.Recast.Demo
private DtNavMesh _navMesh; private DtNavMesh _navMesh;
private DtNavMeshQuery _navMeshQuery; private DtNavMeshQuery _navMeshQuery;
private readonly RcNavMeshBuildSettings _settings; private readonly RcNavMeshBuildSettings _settings;
private IList<RecastBuilderResult> _recastResults; private IList<RcBuilderResult> _recastResults;
private bool _changed; private bool _changed;
public DemoSample(DemoInputGeomProvider geom, IList<RecastBuilderResult> recastResults, DtNavMesh navMesh) public DemoSample(DemoInputGeomProvider geom, IList<RcBuilderResult> recastResults, DtNavMesh navMesh)
{ {
_geom = geom; _geom = geom;
_recastResults = recastResults; _recastResults = recastResults;
@ -56,7 +56,7 @@ namespace DotRecast.Recast.Demo
return _geom; return _geom;
} }
public IList<RecastBuilderResult> GetRecastResults() public IList<RcBuilderResult> GetRecastResults()
{ {
return _recastResults; return _recastResults;
} }
@ -86,7 +86,7 @@ namespace DotRecast.Recast.Demo
_changed = changed; _changed = changed;
} }
public void Update(DemoInputGeomProvider geom, IList<RecastBuilderResult> recastResults, DtNavMesh navMesh) public void Update(DemoInputGeomProvider geom, IList<RcBuilderResult> recastResults, DtNavMesh navMesh)
{ {
_geom = geom; _geom = geom;
_recastResults = recastResults; _recastResults = recastResults;

View File

@ -23,6 +23,7 @@ using DotRecast.Core;
using DotRecast.Detour; using DotRecast.Detour;
using DotRecast.Recast.Toolset.Builder; using DotRecast.Recast.Toolset.Builder;
using DotRecast.Recast.Toolset.Geom; using DotRecast.Recast.Toolset.Geom;
using static DotRecast.Recast.RcCommons;
namespace DotRecast.Recast.Demo.Draw; namespace DotRecast.Recast.Demo.Draw;
@ -50,7 +51,7 @@ public class NavMeshRenderer
DtNavMeshQuery navQuery = sample.GetNavMeshQuery(); DtNavMeshQuery navQuery = sample.GetNavMeshQuery();
DemoInputGeomProvider geom = sample.GetInputGeom(); DemoInputGeomProvider geom = sample.GetInputGeom();
IList<RecastBuilderResult> rcBuilderResults = sample.GetRecastResults(); IList<RcBuilderResult> rcBuilderResults = sample.GetRecastResults();
DtNavMesh navMesh = sample.GetNavMesh(); DtNavMesh navMesh = sample.GetNavMesh();
var settings = sample.GetSettings(); var settings = sample.GetSettings();
_debugDraw.Fog(true); _debugDraw.Fog(true);
@ -81,7 +82,7 @@ public class NavMeshRenderer
int gw = 0, gh = 0; int gw = 0, gh = 0;
RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax(); RcVec3f bmax = geom.GetMeshBoundsMax();
RcUtils.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh); CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
int tw = (gw + settings.tileSize - 1) / settings.tileSize; int tw = (gw + settings.tileSize - 1) / settings.tileSize;
int th = (gh + settings.tileSize - 1) / settings.tileSize; int th = (gh + settings.tileSize - 1) / settings.tileSize;
float s = settings.tileSize * settings.cellSize; float s = settings.tileSize * settings.cellSize;
@ -120,7 +121,7 @@ public class NavMeshRenderer
_debugDraw.DepthMask(true); _debugDraw.DepthMask(true);
foreach (RecastBuilderResult rcBuilderResult in rcBuilderResults) foreach (RcBuilderResult rcBuilderResult in rcBuilderResults)
{ {
if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT) if (rcBuilderResult.GetCompactHeightfield() != null && drawMode == DrawMode.DRAWMODE_COMPACT)
{ {

View File

@ -324,7 +324,7 @@ public class RecastDemo : IRecastDemoChannel
if (null != mesh) if (null != mesh)
{ {
_sample.Update(_sample.GetInputGeom(), ImmutableArray<RecastBuilderResult>.Empty, mesh); _sample.Update(_sample.GetInputGeom(), ImmutableArray<RcBuilderResult>.Empty, mesh);
toolset.SetEnabled(true); toolset.SetEnabled(true);
} }
} }
@ -375,7 +375,7 @@ public class RecastDemo : IRecastDemoChannel
_imgui = new ImGuiController(_gl, window, _input, imGuiFontConfig); _imgui = new ImGuiController(_gl, window, _input, imGuiFontConfig);
DemoInputGeomProvider geom = LoadInputMesh("nav_test.obj"); DemoInputGeomProvider geom = LoadInputMesh("nav_test.obj");
_sample = new DemoSample(geom, ImmutableArray<RecastBuilderResult>.Empty, null); _sample = new DemoSample(geom, ImmutableArray<RcBuilderResult>.Empty, null);
settingsView = new RcSettingsView(this); settingsView = new RcSettingsView(this);
settingsView.SetSample(_sample); settingsView.SetSample(_sample);
@ -454,7 +454,7 @@ public class RecastDemo : IRecastDemoChannel
var settings = _sample.GetSettings(); var settings = _sample.GetSettings();
RcVec3f bmin = _sample.GetInputGeom().GetMeshBoundsMin(); RcVec3f bmin = _sample.GetInputGeom().GetMeshBoundsMin();
RcVec3f bmax = _sample.GetInputGeom().GetMeshBoundsMax(); RcVec3f bmax = _sample.GetInputGeom().GetMeshBoundsMax();
RcUtils.CalcGridSize(bmin, bmax, settings.cellSize, out var gw, out var gh); RcCommons.CalcGridSize(bmin, bmax, settings.cellSize, out var gw, out var gh);
settingsView.SetVoxels(gw, gh); settingsView.SetVoxels(gw, gh);
settingsView.SetTiles(tileNavMeshBuilder.GetTiles(_sample.GetInputGeom(), settings.cellSize, settings.tileSize)); settingsView.SetTiles(tileNavMeshBuilder.GetTiles(_sample.GetInputGeom(), settings.cellSize, settings.tileSize));
settingsView.SetMaxTiles(tileNavMeshBuilder.GetMaxTiles(_sample.GetInputGeom(), settings.cellSize, settings.tileSize)); settingsView.SetMaxTiles(tileNavMeshBuilder.GetMaxTiles(_sample.GetInputGeom(), settings.cellSize, settings.tileSize));
@ -542,7 +542,7 @@ public class RecastDemo : IRecastDemoChannel
} }
else if (0 < _sample.GetRecastResults().Count) else if (0 < _sample.GetRecastResults().Count)
{ {
foreach (RecastBuilderResult result in _sample.GetRecastResults()) foreach (RcBuilderResult result in _sample.GetRecastResults())
{ {
if (result.GetSolidHeightfield() != null) if (result.GetSolidHeightfield() != null)
{ {
@ -662,7 +662,7 @@ public class RecastDemo : IRecastDemoChannel
{ {
var geom = LoadInputMesh(args.FilePath); var geom = LoadInputMesh(args.FilePath);
_sample.Update(geom, ImmutableArray<RecastBuilderResult>.Empty, null); _sample.Update(geom, ImmutableArray<RcBuilderResult>.Empty, null);
} }
private void OnNavMeshBuildBegan(NavMeshBuildBeganEvent args) private void OnNavMeshBuildBegan(NavMeshBuildBeganEvent args)

View File

@ -8,7 +8,7 @@ namespace DotRecast.Recast.Toolset.Builder
{ {
public static DtNavMeshCreateParams GetNavMeshCreateParams(IInputGeomProvider geom, float cellSize, public static DtNavMeshCreateParams GetNavMeshCreateParams(IInputGeomProvider geom, float cellSize,
float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb, float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
RecastBuilderResult rcResult) RcBuilderResult rcResult)
{ {
RcPolyMesh pmesh = rcResult.GetMesh(); RcPolyMesh pmesh = rcResult.GetMesh();
RcPolyMeshDetail dmesh = rcResult.GetMeshDetail(); RcPolyMeshDetail dmesh = rcResult.GetMeshDetail();

View File

@ -7,17 +7,17 @@ namespace DotRecast.Recast.Toolset.Builder
public class NavMeshBuildResult public class NavMeshBuildResult
{ {
public readonly bool Success; public readonly bool Success;
public readonly IList<RecastBuilderResult> RecastBuilderResults; public readonly IList<RcBuilderResult> RecastBuilderResults;
public readonly DtNavMesh NavMesh; public readonly DtNavMesh NavMesh;
public NavMeshBuildResult() public NavMeshBuildResult()
{ {
Success = false; Success = false;
RecastBuilderResults = Array.Empty<RecastBuilderResult>(); RecastBuilderResults = Array.Empty<RcBuilderResult>();
NavMesh = null; NavMesh = null;
} }
public NavMeshBuildResult(IList<RecastBuilderResult> recastBuilderResults, DtNavMesh navMesh) public NavMeshBuildResult(IList<RcBuilderResult> recastBuilderResults, DtNavMesh navMesh)
{ {
Success = true; Success = true;
RecastBuilderResults = recastBuilderResults; RecastBuilderResults = recastBuilderResults;

View File

@ -60,7 +60,7 @@ namespace DotRecast.Recast.Toolset.Builder
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
RecastBuilderResult rcResult = BuildRecastResult(geom, cfg); RcBuilderResult rcResult = BuildRecastResult(geom, cfg);
var meshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult); var meshData = BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult);
if (null == meshData) if (null == meshData)
{ {
@ -76,17 +76,17 @@ namespace DotRecast.Recast.Toolset.Builder
return new DtNavMesh(meshData, vertsPerPoly, 0); return new DtNavMesh(meshData, vertsPerPoly, 0);
} }
private RecastBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg) private RcBuilderResult BuildRecastResult(DemoInputGeomProvider geom, RcConfig cfg)
{ {
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
RecastBuilder rcBuilder = new RecastBuilder(); RcBuilder rcBuilder = new RcBuilder();
return rcBuilder.Build(geom, bcfg); return rcBuilder.Build(geom, bcfg);
} }
public DtMeshData BuildMeshData(DemoInputGeomProvider geom, public DtMeshData BuildMeshData(DemoInputGeomProvider geom,
float cellSize, float cellHeight, float cellSize, float cellHeight,
float agentHeight, float agentRadius, float agentMaxClimb, float agentHeight, float agentRadius, float agentMaxClimb,
RecastBuilderResult result) RcBuilderResult result)
{ {
DtNavMeshCreateParams option = DemoNavMeshBuilder DtNavMeshCreateParams option = DemoNavMeshBuilder
.GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result); .GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, result);

View File

@ -55,7 +55,7 @@ namespace DotRecast.Recast.Toolset.Builder
float detailSampleDist, float detailSampleMaxError, float detailSampleDist, float detailSampleMaxError,
bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans) bool filterLowHangingObstacles, bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
{ {
List<RecastBuilderResult> results = BuildRecastResult( List<RcBuilderResult> results = BuildRecastResult(
geom, geom,
tileSize, tileSize,
partitionType, partitionType,
@ -73,7 +73,7 @@ namespace DotRecast.Recast.Toolset.Builder
return new NavMeshBuildResult(results, tileNavMesh); return new NavMeshBuildResult(results, tileNavMesh);
} }
public List<RecastBuilderResult> BuildRecastResult(IInputGeomProvider geom, public List<RcBuilderResult> BuildRecastResult(IInputGeomProvider geom,
int tileSize, int tileSize,
RcPartition partitionType, RcPartition partitionType,
float cellSize, float cellHeight, float cellSize, float cellHeight,
@ -96,7 +96,7 @@ namespace DotRecast.Recast.Toolset.Builder
detailSampleDist, detailSampleMaxError, detailSampleDist, detailSampleMaxError,
filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans, filterLowHangingObstacles, filterLedgeSpans, filterWalkableLowHeightSpans,
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true); SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
RecastBuilder rcBuilder = new RecastBuilder(); RcBuilder rcBuilder = new RcBuilder();
return rcBuilder.BuildTiles(geom, cfg, Task.Factory); return rcBuilder.BuildTiles(geom, cfg, Task.Factory);
} }
@ -117,11 +117,11 @@ namespace DotRecast.Recast.Toolset.Builder
} }
public List<DtMeshData> BuildMeshData(IInputGeomProvider geom, float cellSize, float cellHeight, float agentHeight, public List<DtMeshData> BuildMeshData(IInputGeomProvider geom, float cellSize, float cellHeight, float agentHeight,
float agentRadius, float agentMaxClimb, IList<RecastBuilderResult> results) float agentRadius, float agentMaxClimb, IList<RcBuilderResult> results)
{ {
// Add tiles to nav mesh // Add tiles to nav mesh
List<DtMeshData> meshData = new List<DtMeshData>(); List<DtMeshData> meshData = new List<DtMeshData>();
foreach (RecastBuilderResult result in results) foreach (RcBuilderResult result in results)
{ {
int x = result.tileX; int x = result.tileX;
int z = result.tileZ; int z = result.tileZ;
@ -155,7 +155,7 @@ namespace DotRecast.Recast.Toolset.Builder
private int GetTileBits(IInputGeomProvider geom, float cellSize, int tileSize) private int GetTileBits(IInputGeomProvider geom, float cellSize, int tileSize)
{ {
RcUtils.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh); RcCommons.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
int tw = (gw + tileSize - 1) / tileSize; int tw = (gw + tileSize - 1) / tileSize;
int th = (gh + tileSize - 1) / tileSize; int th = (gh + tileSize - 1) / tileSize;
int tileBits = Math.Min(DtUtils.Ilog2(DtUtils.NextPow2(tw * th)), 14); int tileBits = Math.Min(DtUtils.Ilog2(DtUtils.NextPow2(tw * th)), 14);
@ -164,7 +164,7 @@ namespace DotRecast.Recast.Toolset.Builder
public int[] GetTiles(DemoInputGeomProvider geom, float cellSize, int tileSize) public int[] GetTiles(DemoInputGeomProvider geom, float cellSize, int tileSize)
{ {
RcUtils.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh); RcCommons.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
int tw = (gw + tileSize - 1) / tileSize; int tw = (gw + tileSize - 1) / tileSize;
int th = (gh + tileSize - 1) / tileSize; int th = (gh + tileSize - 1) / tileSize;
return new int[] { tw, th }; return new int[] { tw, th };

View File

@ -80,7 +80,7 @@ namespace DotRecast.Recast.Toolset.Tools
IList<RcConvexVolume> vols = geom.ConvexVolumes(); IList<RcConvexVolume> vols = geom.ConvexVolumes();
for (int i = 0; i < vols.Count; ++i) for (int i = 0; i < vols.Count; ++i)
{ {
if (PolyUtils.PointInPoly(vols[i].verts, pos) && pos.y >= vols[i].hmin if (RcAreas.PointInPoly(vols[i].verts, pos) && pos.y >= vols[i].hmin
&& pos.y <= vols[i].hmax) && pos.y <= vols[i].hmax)
{ {
nearestIndex = i; nearestIndex = i;
@ -130,7 +130,7 @@ namespace DotRecast.Recast.Toolset.Tools
if (polyOffset > 0.01f) if (polyOffset > 0.01f)
{ {
float[] offset = new float[verts.Length * 2]; float[] offset = new float[verts.Length * 2];
int noffset = PolyUtils.OffsetPoly(verts, hull.Count, polyOffset, offset, offset.Length); int noffset = RcAreas.OffsetPoly(verts, hull.Count, polyOffset, offset, offset.Length);
if (noffset > 0) if (noffset > 0)
{ {
verts = RcArrayUtils.CopyOf(offset, 0, noffset * 3); verts = RcArrayUtils.CopyOf(offset, 0, noffset * 3);

View File

@ -44,7 +44,7 @@ namespace DotRecast.Recast.Toolset.Tools
return _links; return _links;
} }
public void Build(IInputGeomProvider geom, RcNavMeshBuildSettings settings, IList<RecastBuilderResult> results, RcJumpLinkBuilderToolConfig cfg) public void Build(IInputGeomProvider geom, RcNavMeshBuildSettings settings, IList<RcBuilderResult> results, RcJumpLinkBuilderToolConfig cfg)
{ {
if (_annotationBuilder == null) if (_annotationBuilder == null)
{ {

View File

@ -41,7 +41,7 @@ namespace DotRecast.Recast.Toolset.Tools
// Init cache // Init cache
var bmin = geom.GetMeshBoundsMin(); var bmin = geom.GetMeshBoundsMin();
var bmax = geom.GetMeshBoundsMax(); var bmax = geom.GetMeshBoundsMax();
RcUtils.CalcGridSize(bmin, bmax, setting.cellSize, out var gw, out var gh); RcCommons.CalcGridSize(bmin, bmax, setting.cellSize, out var gw, out var gh);
int ts = setting.tileSize; int ts = setting.tileSize;
int tw = (gw + ts - 1) / ts; int tw = (gw + ts - 1) / ts;
int th = (gh + ts - 1) / ts; int th = (gh + ts - 1) / ts;
@ -77,7 +77,7 @@ namespace DotRecast.Recast.Toolset.Tools
_tc.BuildNavMeshTile(refs); _tc.BuildNavMeshTile(refs);
} }
return new NavMeshBuildResult(RcImmutableArray<RecastBuilderResult>.Empty, _tc.GetNavMesh()); return new NavMeshBuildResult(RcImmutableArray<RcBuilderResult>.Empty, _tc.GetNavMesh());
} }
public void ClearAllTempObstacles() public void ClearAllTempObstacles()

View File

@ -21,7 +21,7 @@ namespace DotRecast.Recast.Toolset.Tools
var bmin = geom.GetMeshBoundsMin(); var bmin = geom.GetMeshBoundsMin();
var bmax = geom.GetMeshBoundsMax(); var bmax = geom.GetMeshBoundsMax();
int gw = 0, gh = 0; int gw = 0, gh = 0;
RcUtils.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh); RcCommons.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
int ts = settings.tileSize; int ts = settings.tileSize;
int tw = (gw + ts - 1) / ts; int tw = (gw + ts - 1) / ts;
@ -45,7 +45,7 @@ namespace DotRecast.Recast.Toolset.Tools
var bmin = geom.GetMeshBoundsMin(); var bmin = geom.GetMeshBoundsMin();
var bmax = geom.GetMeshBoundsMax(); var bmax = geom.GetMeshBoundsMax();
int gw = 0, gh = 0; int gw = 0, gh = 0;
RcUtils.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh); RcCommons.CalcGridSize(bmin, bmax, settings.cellSize, out gw, out gh);
int ts = settings.tileSize; int ts = settings.tileSize;
int tw = (gw + ts - 1) / ts; int tw = (gw + ts - 1) / ts;
@ -91,7 +91,7 @@ namespace DotRecast.Recast.Toolset.Tools
); );
var beginTick = RcFrequency.Ticks; var beginTick = RcFrequency.Ticks;
var rb = new RecastBuilder(); 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);
var tb = new TileNavMeshBuilder(); var tb = new TileNavMeshBuilder();

View File

@ -1,187 +0,0 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.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.
*/
using System;
using DotRecast.Core;
namespace DotRecast.Recast
{
public static class PolyUtils
{
// public static bool PointInPoly(float[] verts, RcVec3f p)
// {
// bool c = false;
// int i, j;
// for (i = 0, j = verts.Length - 3; i < verts.Length; j = i, i += 3)
// {
// int vi = i;
// int vj = j;
// if (((verts[vi + 2] > p.z) != (verts[vj + 2] > p.z))
// && (p.x < (verts[vj] - verts[vi]) * (p.z - verts[vi + 2]) / (verts[vj + 2] - verts[vi + 2])
// + verts[vi]))
// c = !c;
// }
//
// return c;
// }
// TODO (graham): This is duplicated in the ConvexVolumeTool in RecastDemo
/// Checks if a point is contained within a polygon
///
/// @param[in] numVerts Number of vertices in the polygon
/// @param[in] verts The polygon vertices
/// @param[in] point The point to check
/// @returns true if the point lies within the polygon, false otherwise.
public static bool PointInPoly(float[] verts, RcVec3f point)
{
bool inPoly = false;
for (int i = 0, j = verts.Length / 3 - 1; i < verts.Length / 3; j = i++)
{
RcVec3f vi = RcVec3f.Of(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]);
RcVec3f vj = RcVec3f.Of(verts[j * 3], verts[j * 3 + 1], verts[j * 3 + 2]);
if (vi.z > point.z == vj.z > point.z)
{
continue;
}
if (point.x >= (vj.x - vi.x) * (point.z - vi.z) / (vj.z - vi.z) + vi.x)
{
continue;
}
inPoly = !inPoly;
}
return inPoly;
}
/// Expands a convex polygon along its vertex normals by the given offset amount.
/// Inserts extra vertices to bevel sharp corners.
///
/// Helper function to offset convex polygons for rcMarkConvexPolyArea.
///
/// @ingroup recast
///
/// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p numVerts]
/// @param[in] numVerts The number of vertices in the polygon.
/// @param[in] offset How much to offset the polygon by. [Units: wu]
/// @param[out] outVerts The offset vertices (should hold up to 2 * @p numVerts) [Form: (x, y, z) * return value]
/// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts.
/// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts.
public static int OffsetPoly(float[] verts, int numVerts, float offset, float[] outVerts, int maxOutVerts)
{
// Defines the limit at which a miter becomes a bevel.
// Similar in behavior to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit
const float MITER_LIMIT = 1.20f;
int numOutVerts = 0;
for (int vertIndex = 0; vertIndex < numVerts; vertIndex++)
{
int vertIndexA = (vertIndex + numVerts - 1) % numVerts;
int vertIndexB = vertIndex;
int vertIndexC = (vertIndex + 1) % numVerts;
RcVec3f vertA = RcVec3f.Of(verts, vertIndexA * 3);
RcVec3f vertB = RcVec3f.Of(verts, vertIndexB * 3);
RcVec3f vertC = RcVec3f.Of(verts, vertIndexC * 3);
// From A to B on the x/z plane
RcVec3f prevSegmentDir = vertB.Subtract(vertA);
prevSegmentDir.y = 0; // Squash onto x/z plane
prevSegmentDir.SafeNormalize();
// From B to C on the x/z plane
RcVec3f currSegmentDir = vertC.Subtract(vertB);
currSegmentDir.y = 0; // Squash onto x/z plane
currSegmentDir.SafeNormalize();
// The y component of the cross product of the two normalized segment directions.
// The X and Z components of the cross product are both zero because the two
// segment direction vectors fall within the x/z plane.
float cross = currSegmentDir.x * prevSegmentDir.z - prevSegmentDir.x * currSegmentDir.z;
// CCW perpendicular vector to AB. The segment normal.
float prevSegmentNormX = -prevSegmentDir.z;
float prevSegmentNormZ = prevSegmentDir.x;
// CCW perpendicular vector to BC. The segment normal.
float currSegmentNormX = -currSegmentDir.z;
float currSegmentNormZ = currSegmentDir.x;
// Average the two segment normals to get the proportional miter offset for B.
// This isn't normalized because it's defining the distance and direction the corner will need to be
// adjusted proportionally to the edge offsets to properly miter the adjoining edges.
float cornerMiterX = (prevSegmentNormX + currSegmentNormX) * 0.5f;
float cornerMiterZ = (prevSegmentNormZ + currSegmentNormZ) * 0.5f;
float cornerMiterSqMag = RcMath.Sqr(cornerMiterX) + RcMath.Sqr(cornerMiterZ);
// If the magnitude of the segment normal average is less than about .69444,
// the corner is an acute enough angle that the result should be beveled.
bool bevel = cornerMiterSqMag * MITER_LIMIT * MITER_LIMIT < 1.0f;
// Scale the corner miter so it's proportional to how much the corner should be offset compared to the edges.
if (cornerMiterSqMag > RcVec3f.EPSILON)
{
float scale = 1.0f / cornerMiterSqMag;
cornerMiterX *= scale;
cornerMiterZ *= scale;
}
if (bevel && cross < 0.0f) // If the corner is convex and an acute enough angle, generate a bevel.
{
if (numOutVerts + 2 > maxOutVerts)
{
return 0;
}
// Generate two bevel vertices at a distances from B proportional to the angle between the two segments.
// Move each bevel vertex out proportional to the given offset.
float d = (1.0f - (prevSegmentDir.x * currSegmentDir.x + prevSegmentDir.z * currSegmentDir.z)) * 0.5f;
outVerts[numOutVerts * 3 + 0] = vertB.x + (-prevSegmentNormX + prevSegmentDir.x * d) * offset;
outVerts[numOutVerts * 3 + 1] = vertB.y;
outVerts[numOutVerts * 3 + 2] = vertB.z + (-prevSegmentNormZ + prevSegmentDir.z * d) * offset;
numOutVerts++;
outVerts[numOutVerts * 3 + 0] = vertB.x + (-currSegmentNormX - currSegmentDir.x * d) * offset;
outVerts[numOutVerts * 3 + 1] = vertB.y;
outVerts[numOutVerts * 3 + 2] = vertB.z + (-currSegmentNormZ - currSegmentDir.z * d) * offset;
numOutVerts++;
}
else
{
if (numOutVerts + 1 > maxOutVerts)
{
return 0;
}
// Move B along the miter direction by the specified offset.
outVerts[numOutVerts * 3 + 0] = vertB.x - cornerMiterX * offset;
outVerts[numOutVerts * 3 + 1] = vertB.y;
outVerts[numOutVerts * 3 + 2] = vertB.z - cornerMiterZ * offset;
numOutVerts++;
}
}
return numOutVerts;
}
}
}

View File

@ -24,8 +24,9 @@ using DotRecast.Core;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
using static RcConstants; using static RcConstants;
using static RcCommons;
public static class RecastArea public static class RcAreas
{ {
/// Erodes the walkable area within the heightfield by the specified radius. /// Erodes the walkable area within the heightfield by the specified radius.
/// ///
@ -72,15 +73,15 @@ namespace DotRecast.Recast
int neighborCount = 0; int neighborCount = 0;
for (int direction = 0; direction < 4; ++direction) for (int direction = 0; direction < 4; ++direction)
{ {
int neighborConnection = RecastCommon.GetCon(span, direction); int neighborConnection = GetCon(span, direction);
if (neighborConnection == RC_NOT_CONNECTED) if (neighborConnection == RC_NOT_CONNECTED)
{ {
break; break;
} }
int neighborX = x + RecastCommon.GetDirOffsetX(direction); int neighborX = x + GetDirOffsetX(direction);
int neighborZ = z + RecastCommon.GetDirOffsetY(direction); int neighborZ = z + GetDirOffsetY(direction);
int neighborSpanIndex = compactHeightfield.cells[neighborX + neighborZ * zStride].index + RecastCommon.GetCon(span, direction); int neighborSpanIndex = compactHeightfield.cells[neighborX + neighborZ * zStride].index + GetCon(span, direction);
if (compactHeightfield.areas[neighborSpanIndex] == RC_NULL_AREA) if (compactHeightfield.areas[neighborSpanIndex] == RC_NULL_AREA)
{ {
break; break;
@ -112,12 +113,12 @@ namespace DotRecast.Recast
{ {
RcCompactSpan span = compactHeightfield.spans[spanIndex]; RcCompactSpan span = compactHeightfield.spans[spanIndex];
if (RecastCommon.GetCon(span, 0) != RC_NOT_CONNECTED) if (GetCon(span, 0) != RC_NOT_CONNECTED)
{ {
// (-1,0) // (-1,0)
int aX = x + RecastCommon.GetDirOffsetX(0); int aX = x + GetDirOffsetX(0);
int aY = z + RecastCommon.GetDirOffsetY(0); int aY = z + GetDirOffsetY(0);
int aIndex = compactHeightfield.cells[aX + aY * xSize].index + RecastCommon.GetCon(span, 0); int aIndex = compactHeightfield.cells[aX + aY * xSize].index + GetCon(span, 0);
RcCompactSpan aSpan = compactHeightfield.spans[aIndex]; RcCompactSpan aSpan = compactHeightfield.spans[aIndex];
newDistance = Math.Min(distanceToBoundary[aIndex] + 2, 255); newDistance = Math.Min(distanceToBoundary[aIndex] + 2, 255);
if (newDistance < distanceToBoundary[spanIndex]) if (newDistance < distanceToBoundary[spanIndex])
@ -126,11 +127,11 @@ namespace DotRecast.Recast
} }
// (-1,-1) // (-1,-1)
if (RecastCommon.GetCon(aSpan, 3) != RC_NOT_CONNECTED) if (GetCon(aSpan, 3) != RC_NOT_CONNECTED)
{ {
int bX = aX + RecastCommon.GetDirOffsetX(3); int bX = aX + GetDirOffsetX(3);
int bY = aY + RecastCommon.GetDirOffsetY(3); int bY = aY + GetDirOffsetY(3);
int bIndex = compactHeightfield.cells[bX + bY * xSize].index + RecastCommon.GetCon(aSpan, 3); int bIndex = compactHeightfield.cells[bX + bY * xSize].index + GetCon(aSpan, 3);
newDistance = Math.Min(distanceToBoundary[bIndex] + 3, 255); newDistance = Math.Min(distanceToBoundary[bIndex] + 3, 255);
if (newDistance < distanceToBoundary[spanIndex]) if (newDistance < distanceToBoundary[spanIndex])
{ {
@ -139,12 +140,12 @@ namespace DotRecast.Recast
} }
} }
if (RecastCommon.GetCon(span, 3) != RC_NOT_CONNECTED) if (GetCon(span, 3) != RC_NOT_CONNECTED)
{ {
// (0,-1) // (0,-1)
int aX = x + RecastCommon.GetDirOffsetX(3); int aX = x + GetDirOffsetX(3);
int aY = z + RecastCommon.GetDirOffsetY(3); int aY = z + GetDirOffsetY(3);
int aIndex = compactHeightfield.cells[aX + aY * xSize].index + RecastCommon.GetCon(span, 3); int aIndex = compactHeightfield.cells[aX + aY * xSize].index + GetCon(span, 3);
RcCompactSpan aSpan = compactHeightfield.spans[aIndex]; RcCompactSpan aSpan = compactHeightfield.spans[aIndex];
newDistance = Math.Min(distanceToBoundary[aIndex] + 2, 255); newDistance = Math.Min(distanceToBoundary[aIndex] + 2, 255);
if (newDistance < distanceToBoundary[spanIndex]) if (newDistance < distanceToBoundary[spanIndex])
@ -153,11 +154,11 @@ namespace DotRecast.Recast
} }
// (1,-1) // (1,-1)
if (RecastCommon.GetCon(aSpan, 2) != RC_NOT_CONNECTED) if (GetCon(aSpan, 2) != RC_NOT_CONNECTED)
{ {
int bX = aX + RecastCommon.GetDirOffsetX(2); int bX = aX + GetDirOffsetX(2);
int bY = aY + RecastCommon.GetDirOffsetY(2); int bY = aY + GetDirOffsetY(2);
int bIndex = compactHeightfield.cells[bX + bY * xSize].index + RecastCommon.GetCon(aSpan, 2); int bIndex = compactHeightfield.cells[bX + bY * xSize].index + GetCon(aSpan, 2);
newDistance = Math.Min(distanceToBoundary[bIndex] + 3, 255); newDistance = Math.Min(distanceToBoundary[bIndex] + 3, 255);
if (newDistance < distanceToBoundary[spanIndex]) if (newDistance < distanceToBoundary[spanIndex])
{ {
@ -180,12 +181,12 @@ namespace DotRecast.Recast
{ {
RcCompactSpan span = compactHeightfield.spans[i]; RcCompactSpan span = compactHeightfield.spans[i];
if (RecastCommon.GetCon(span, 2) != RC_NOT_CONNECTED) if (GetCon(span, 2) != RC_NOT_CONNECTED)
{ {
// (1,0) // (1,0)
int aX = x + RecastCommon.GetDirOffsetX(2); int aX = x + GetDirOffsetX(2);
int aY = z + RecastCommon.GetDirOffsetY(2); int aY = z + GetDirOffsetY(2);
int aIndex = compactHeightfield.cells[aX + aY * xSize].index + RecastCommon.GetCon(span, 2); int aIndex = compactHeightfield.cells[aX + aY * xSize].index + GetCon(span, 2);
RcCompactSpan aSpan = compactHeightfield.spans[aIndex]; RcCompactSpan aSpan = compactHeightfield.spans[aIndex];
newDistance = Math.Min(distanceToBoundary[aIndex] + 2, 255); newDistance = Math.Min(distanceToBoundary[aIndex] + 2, 255);
if (newDistance < distanceToBoundary[i]) if (newDistance < distanceToBoundary[i])
@ -194,11 +195,11 @@ namespace DotRecast.Recast
} }
// (1,1) // (1,1)
if (RecastCommon.GetCon(aSpan, 1) != RC_NOT_CONNECTED) if (GetCon(aSpan, 1) != RC_NOT_CONNECTED)
{ {
int bX = aX + RecastCommon.GetDirOffsetX(1); int bX = aX + GetDirOffsetX(1);
int bY = aY + RecastCommon.GetDirOffsetY(1); int bY = aY + GetDirOffsetY(1);
int bIndex = compactHeightfield.cells[bX + bY * xSize].index + RecastCommon.GetCon(aSpan, 1); int bIndex = compactHeightfield.cells[bX + bY * xSize].index + GetCon(aSpan, 1);
newDistance = Math.Min(distanceToBoundary[bIndex] + 3, 255); newDistance = Math.Min(distanceToBoundary[bIndex] + 3, 255);
if (newDistance < distanceToBoundary[i]) if (newDistance < distanceToBoundary[i])
{ {
@ -207,12 +208,12 @@ namespace DotRecast.Recast
} }
} }
if (RecastCommon.GetCon(span, 1) != RC_NOT_CONNECTED) if (GetCon(span, 1) != RC_NOT_CONNECTED)
{ {
// (0,1) // (0,1)
int aX = x + RecastCommon.GetDirOffsetX(1); int aX = x + GetDirOffsetX(1);
int aY = z + RecastCommon.GetDirOffsetY(1); int aY = z + GetDirOffsetY(1);
int aIndex = compactHeightfield.cells[aX + aY * xSize].index + RecastCommon.GetCon(span, 1); int aIndex = compactHeightfield.cells[aX + aY * xSize].index + GetCon(span, 1);
RcCompactSpan aSpan = compactHeightfield.spans[aIndex]; RcCompactSpan aSpan = compactHeightfield.spans[aIndex];
newDistance = Math.Min(distanceToBoundary[aIndex] + 2, 255); newDistance = Math.Min(distanceToBoundary[aIndex] + 2, 255);
if (newDistance < distanceToBoundary[i]) if (newDistance < distanceToBoundary[i])
@ -221,11 +222,11 @@ namespace DotRecast.Recast
} }
// (-1,1) // (-1,1)
if (RecastCommon.GetCon(aSpan, 0) != RC_NOT_CONNECTED) if (GetCon(aSpan, 0) != RC_NOT_CONNECTED)
{ {
int bX = aX + RecastCommon.GetDirOffsetX(0); int bX = aX + GetDirOffsetX(0);
int bY = aY + RecastCommon.GetDirOffsetY(0); int bY = aY + GetDirOffsetY(0);
int bIndex = compactHeightfield.cells[bX + bY * xSize].index + RecastCommon.GetCon(aSpan, 0); int bIndex = compactHeightfield.cells[bX + bY * xSize].index + GetCon(aSpan, 0);
newDistance = Math.Min(distanceToBoundary[bIndex] + 3, 255); newDistance = Math.Min(distanceToBoundary[bIndex] + 3, 255);
if (newDistance < distanceToBoundary[i]) if (newDistance < distanceToBoundary[i])
{ {
@ -291,14 +292,14 @@ namespace DotRecast.Recast
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
if (RecastCommon.GetCon(span, dir) == RC_NOT_CONNECTED) if (GetCon(span, dir) == RC_NOT_CONNECTED)
{ {
continue; continue;
} }
int aX = x + RecastCommon.GetDirOffsetX(dir); int aX = x + GetDirOffsetX(dir);
int aZ = z + RecastCommon.GetDirOffsetY(dir); int aZ = z + GetDirOffsetY(dir);
int aIndex = compactHeightfield.cells[aX + aZ * zStride].index + RecastCommon.GetCon(span, dir); int aIndex = compactHeightfield.cells[aX + aZ * zStride].index + GetCon(span, dir);
if (compactHeightfield.areas[aIndex] != RC_NULL_AREA) if (compactHeightfield.areas[aIndex] != RC_NULL_AREA)
{ {
neighborAreas[dir * 2 + 0] = compactHeightfield.areas[aIndex]; neighborAreas[dir * 2 + 0] = compactHeightfield.areas[aIndex];
@ -306,12 +307,12 @@ namespace DotRecast.Recast
RcCompactSpan aSpan = compactHeightfield.spans[aIndex]; RcCompactSpan aSpan = compactHeightfield.spans[aIndex];
int dir2 = (dir + 1) & 0x3; int dir2 = (dir + 1) & 0x3;
int neighborConnection2 = RecastCommon.GetCon(aSpan, dir2); int neighborConnection2 = GetCon(aSpan, dir2);
if (neighborConnection2 != RC_NOT_CONNECTED) if (neighborConnection2 != RC_NOT_CONNECTED)
{ {
int bX = aX + RecastCommon.GetDirOffsetX(dir2); int bX = aX + GetDirOffsetX(dir2);
int bZ = aZ + RecastCommon.GetDirOffsetY(dir2); int bZ = aZ + GetDirOffsetY(dir2);
int bIndex = compactHeightfield.cells[bX + bZ * zStride].index + RecastCommon.GetCon(aSpan, dir2); int bIndex = compactHeightfield.cells[bX + bZ * zStride].index + GetCon(aSpan, dir2);
if (compactHeightfield.areas[bIndex] != RC_NULL_AREA) if (compactHeightfield.areas[bIndex] != RC_NULL_AREA)
{ {
neighborAreas[dir * 2 + 1] = compactHeightfield.areas[bIndex]; neighborAreas[dir * 2 + 1] = compactHeightfield.areas[bIndex];
@ -544,7 +545,7 @@ namespace DotRecast.Recast
compactHeightfield.bmin.z + (z + 0.5f) * compactHeightfield.cs compactHeightfield.bmin.z + (z + 0.5f) * compactHeightfield.cs
); );
if (PolyUtils.PointInPoly(verts, point)) if (PointInPoly(verts, point))
{ {
compactHeightfield.areas[spanIndex] = areaId.Apply(compactHeightfield.areas[spanIndex]); compactHeightfield.areas[spanIndex] = areaId.Apply(compactHeightfield.areas[spanIndex]);
} }
@ -677,5 +678,164 @@ namespace DotRecast.Recast
} }
} }
} }
// public static bool PointInPoly(float[] verts, RcVec3f p)
// {
// bool c = false;
// int i, j;
// for (i = 0, j = verts.Length - 3; i < verts.Length; j = i, i += 3)
// {
// int vi = i;
// int vj = j;
// if (((verts[vi + 2] > p.z) != (verts[vj + 2] > p.z))
// && (p.x < (verts[vj] - verts[vi]) * (p.z - verts[vi + 2]) / (verts[vj + 2] - verts[vi + 2])
// + verts[vi]))
// c = !c;
// }
//
// return c;
// }
// TODO (graham): This is duplicated in the ConvexVolumeTool in RecastDemo
/// Checks if a point is contained within a polygon
///
/// @param[in] numVerts Number of vertices in the polygon
/// @param[in] verts The polygon vertices
/// @param[in] point The point to check
/// @returns true if the point lies within the polygon, false otherwise.
public static bool PointInPoly(float[] verts, RcVec3f point)
{
bool inPoly = false;
for (int i = 0, j = verts.Length / 3 - 1; i < verts.Length / 3; j = i++)
{
RcVec3f vi = RcVec3f.Of(verts[i * 3], verts[i * 3 + 1], verts[i * 3 + 2]);
RcVec3f vj = RcVec3f.Of(verts[j * 3], verts[j * 3 + 1], verts[j * 3 + 2]);
if (vi.z > point.z == vj.z > point.z)
{
continue;
}
if (point.x >= (vj.x - vi.x) * (point.z - vi.z) / (vj.z - vi.z) + vi.x)
{
continue;
}
inPoly = !inPoly;
}
return inPoly;
}
/// Expands a convex polygon along its vertex normals by the given offset amount.
/// Inserts extra vertices to bevel sharp corners.
///
/// Helper function to offset convex polygons for rcMarkConvexPolyArea.
///
/// @ingroup recast
///
/// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p numVerts]
/// @param[in] numVerts The number of vertices in the polygon.
/// @param[in] offset How much to offset the polygon by. [Units: wu]
/// @param[out] outVerts The offset vertices (should hold up to 2 * @p numVerts) [Form: (x, y, z) * return value]
/// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts.
/// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts.
public static int OffsetPoly(float[] verts, int numVerts, float offset, float[] outVerts, int maxOutVerts)
{
// Defines the limit at which a miter becomes a bevel.
// Similar in behavior to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit
const float MITER_LIMIT = 1.20f;
int numOutVerts = 0;
for (int vertIndex = 0; vertIndex < numVerts; vertIndex++)
{
int vertIndexA = (vertIndex + numVerts - 1) % numVerts;
int vertIndexB = vertIndex;
int vertIndexC = (vertIndex + 1) % numVerts;
RcVec3f vertA = RcVec3f.Of(verts, vertIndexA * 3);
RcVec3f vertB = RcVec3f.Of(verts, vertIndexB * 3);
RcVec3f vertC = RcVec3f.Of(verts, vertIndexC * 3);
// From A to B on the x/z plane
RcVec3f prevSegmentDir = vertB.Subtract(vertA);
prevSegmentDir.y = 0; // Squash onto x/z plane
prevSegmentDir.SafeNormalize();
// From B to C on the x/z plane
RcVec3f currSegmentDir = vertC.Subtract(vertB);
currSegmentDir.y = 0; // Squash onto x/z plane
currSegmentDir.SafeNormalize();
// The y component of the cross product of the two normalized segment directions.
// The X and Z components of the cross product are both zero because the two
// segment direction vectors fall within the x/z plane.
float cross = currSegmentDir.x * prevSegmentDir.z - prevSegmentDir.x * currSegmentDir.z;
// CCW perpendicular vector to AB. The segment normal.
float prevSegmentNormX = -prevSegmentDir.z;
float prevSegmentNormZ = prevSegmentDir.x;
// CCW perpendicular vector to BC. The segment normal.
float currSegmentNormX = -currSegmentDir.z;
float currSegmentNormZ = currSegmentDir.x;
// Average the two segment normals to get the proportional miter offset for B.
// This isn't normalized because it's defining the distance and direction the corner will need to be
// adjusted proportionally to the edge offsets to properly miter the adjoining edges.
float cornerMiterX = (prevSegmentNormX + currSegmentNormX) * 0.5f;
float cornerMiterZ = (prevSegmentNormZ + currSegmentNormZ) * 0.5f;
float cornerMiterSqMag = RcMath.Sqr(cornerMiterX) + RcMath.Sqr(cornerMiterZ);
// If the magnitude of the segment normal average is less than about .69444,
// the corner is an acute enough angle that the result should be beveled.
bool bevel = cornerMiterSqMag * MITER_LIMIT * MITER_LIMIT < 1.0f;
// Scale the corner miter so it's proportional to how much the corner should be offset compared to the edges.
if (cornerMiterSqMag > RcVec3f.EPSILON)
{
float scale = 1.0f / cornerMiterSqMag;
cornerMiterX *= scale;
cornerMiterZ *= scale;
}
if (bevel && cross < 0.0f) // If the corner is convex and an acute enough angle, generate a bevel.
{
if (numOutVerts + 2 > maxOutVerts)
{
return 0;
}
// Generate two bevel vertices at a distances from B proportional to the angle between the two segments.
// Move each bevel vertex out proportional to the given offset.
float d = (1.0f - (prevSegmentDir.x * currSegmentDir.x + prevSegmentDir.z * currSegmentDir.z)) * 0.5f;
outVerts[numOutVerts * 3 + 0] = vertB.x + (-prevSegmentNormX + prevSegmentDir.x * d) * offset;
outVerts[numOutVerts * 3 + 1] = vertB.y;
outVerts[numOutVerts * 3 + 2] = vertB.z + (-prevSegmentNormZ + prevSegmentDir.z * d) * offset;
numOutVerts++;
outVerts[numOutVerts * 3 + 0] = vertB.x + (-currSegmentNormX - currSegmentDir.x * d) * offset;
outVerts[numOutVerts * 3 + 1] = vertB.y;
outVerts[numOutVerts * 3 + 2] = vertB.z + (-currSegmentNormZ - currSegmentDir.z * d) * offset;
numOutVerts++;
}
else
{
if (numOutVerts + 1 > maxOutVerts)
{
return 0;
}
// Move B along the miter direction by the specified offset.
outVerts[numOutVerts * 3 + 0] = vertB.x - cornerMiterX * offset;
outVerts[numOutVerts * 3 + 1] = vertB.y;
outVerts[numOutVerts * 3 + 2] = vertB.z - cornerMiterZ * offset;
numOutVerts++;
}
}
return numOutVerts;
}
} }
} }

View File

@ -27,26 +27,29 @@ using DotRecast.Recast.Geom;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public class RecastBuilder using static RcCommons;
using static RcAreas;
public class RcBuilder
{ {
private readonly IRecastBuilderProgressListener progressListener; private readonly IRecastBuilderProgressListener progressListener;
public RecastBuilder() public RcBuilder()
{ {
progressListener = null; progressListener = null;
} }
public RecastBuilder(IRecastBuilderProgressListener progressListener) public RcBuilder(IRecastBuilderProgressListener progressListener)
{ {
this.progressListener = progressListener; this.progressListener = progressListener;
} }
public List<RecastBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory) public List<RcBuilderResult> BuildTiles(IInputGeomProvider geom, RcConfig cfg, TaskFactory taskFactory)
{ {
RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax(); RcVec3f bmax = geom.GetMeshBoundsMax();
RcUtils.CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th); CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
List<RecastBuilderResult> results = new List<RecastBuilderResult>(); List<RcBuilderResult> results = new List<RcBuilderResult>();
if (null != taskFactory) if (null != taskFactory)
{ {
BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default); BuildMultiThreadAsync(geom, cfg, bmin, bmax, tw, th, results, taskFactory, default);
@ -60,11 +63,11 @@ namespace DotRecast.Recast
} }
public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List<RecastBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken) public Task BuildTilesAsync(IInputGeomProvider geom, RcConfig cfg, int threads, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
{ {
RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax(); RcVec3f bmax = geom.GetMeshBoundsMax();
RcUtils.CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th); CalcTileCount(bmin, bmax, cfg.Cs, cfg.TileSizeX, cfg.TileSizeZ, out var tw, out var th);
Task task; Task task;
if (1 < threads) if (1 < threads)
{ {
@ -79,7 +82,7 @@ namespace DotRecast.Recast
} }
private Task BuildSingleThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, private Task BuildSingleThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
int tw, int th, List<RecastBuilderResult> results) int tw, int th, List<RcBuilderResult> results)
{ {
RcAtomicInteger counter = new RcAtomicInteger(0); RcAtomicInteger counter = new RcAtomicInteger(0);
for (int y = 0; y < th; ++y) for (int y = 0; y < th; ++y)
@ -94,7 +97,7 @@ namespace DotRecast.Recast
} }
private Task BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, private Task BuildMultiThreadAsync(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax,
int tw, int th, List<RecastBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken) int tw, int th, List<RcBuilderResult> results, TaskFactory taskFactory, CancellationToken cancellationToken)
{ {
RcAtomicInteger counter = new RcAtomicInteger(0); RcAtomicInteger counter = new RcAtomicInteger(0);
CountdownEvent latch = new CountdownEvent(tw * th); CountdownEvent latch = new CountdownEvent(tw * th);
@ -113,7 +116,7 @@ namespace DotRecast.Recast
try try
{ {
RecastBuilderResult tile = BuildTile(geom, cfg, bmin, bmax, tx, ty, counter, tw * th); RcBuilderResult tile = BuildTile(geom, cfg, bmin, bmax, tx, ty, counter, tw * th);
lock (results) lock (results)
{ {
results.Add(tile); results.Add(tile);
@ -143,10 +146,10 @@ namespace DotRecast.Recast
return Task.WhenAll(tasks.ToArray()); return Task.WhenAll(tasks.ToArray());
} }
public RecastBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx, public RcBuilderResult BuildTile(IInputGeomProvider geom, RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tx,
int ty, RcAtomicInteger counter, int total) int ty, RcAtomicInteger counter, int total)
{ {
RecastBuilderResult result = Build(geom, new RecastBuilderConfig(cfg, bmin, bmax, tx, ty)); RcBuilderResult result = Build(geom, new RcBuilderConfig(cfg, bmin, bmax, tx, ty));
if (progressListener != null) if (progressListener != null)
{ {
progressListener.OnProgress(counter.IncrementAndGet(), total); progressListener.OnProgress(counter.IncrementAndGet(), total);
@ -155,18 +158,18 @@ namespace DotRecast.Recast
return result; return result;
} }
public RecastBuilderResult Build(IInputGeomProvider geom, RecastBuilderConfig builderCfg) public RcBuilderResult Build(IInputGeomProvider geom, RcBuilderConfig builderCfg)
{ {
RcConfig cfg = builderCfg.cfg; RcConfig cfg = builderCfg.cfg;
RcTelemetry ctx = new RcTelemetry(); RcTelemetry ctx = new RcTelemetry();
// //
// Step 1. Rasterize input polygon soup. // Step 1. Rasterize input polygon soup.
// //
RcHeightfield solid = RecastVoxelization.BuildSolidHeightfield(geom, builderCfg, ctx); RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(geom, builderCfg, ctx);
return Build(builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid, ctx); return Build(builderCfg.tileX, builderCfg.tileZ, geom, cfg, solid, ctx);
} }
public RecastBuilderResult Build(int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid, RcTelemetry ctx) public RcBuilderResult Build(int tileX, int tileZ, IInputGeomProvider geom, RcConfig cfg, RcHeightfield solid, RcTelemetry ctx)
{ {
FilterHeightfield(solid, cfg, ctx); FilterHeightfield(solid, cfg, ctx);
RcCompactHeightfield chf = BuildCompactHeightfield(geom, cfg, ctx, solid); RcCompactHeightfield chf = BuildCompactHeightfield(geom, cfg, ctx, solid);
@ -213,20 +216,20 @@ namespace DotRecast.Recast
{ {
// Prepare for region partitioning, by calculating distance field // Prepare for region partitioning, by calculating distance field
// along the walkable surface. // along the walkable surface.
RecastRegion.BuildDistanceField(ctx, chf); RcRegions.BuildDistanceField(ctx, chf);
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RecastRegion.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea); RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
} }
else if (cfg.Partition == RcPartitionType.MONOTONE.Value) else if (cfg.Partition == RcPartitionType.MONOTONE.Value)
{ {
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
// Monotone partitioning does not need distancefield. // Monotone partitioning does not need distancefield.
RecastRegion.BuildRegionsMonotone(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea); RcRegions.BuildRegionsMonotone(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
} }
else else
{ {
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RecastRegion.BuildLayerRegions(ctx, chf, cfg.MinRegionArea); RcRegions.BuildLayerRegions(ctx, chf, cfg.MinRegionArea);
} }
// //
@ -234,23 +237,23 @@ namespace DotRecast.Recast
// //
// Create contours. // Create contours.
RcContourSet cset = RecastContour.BuildContours(ctx, chf, cfg.MaxSimplificationError, cfg.MaxEdgeLen, RcContourSet cset = RcContours.BuildContours(ctx, chf, cfg.MaxSimplificationError, cfg.MaxEdgeLen,
RcConstants.RC_CONTOUR_TESS_WALL_EDGES); RcConstants.RC_CONTOUR_TESS_WALL_EDGES);
// //
// Step 6. Build polygons mesh from contours. // Step 6. Build polygons mesh from contours.
// //
RcPolyMesh pmesh = RecastMesh.BuildPolyMesh(ctx, cset, cfg.MaxVertsPerPoly); RcPolyMesh pmesh = RcMeshs.BuildPolyMesh(ctx, cset, cfg.MaxVertsPerPoly);
// //
// Step 7. Create detail mesh which allows to access approximate height // Step 7. Create detail mesh which allows to access approximate height
// on each polygon. // on each polygon.
// //
RcPolyMeshDetail dmesh = cfg.BuildMeshDetail RcPolyMeshDetail dmesh = cfg.BuildMeshDetail
? RecastMeshDetail.BuildPolyMeshDetail(ctx, pmesh, chf, cfg.DetailSampleDist, cfg.DetailSampleMaxError) ? RcMeshDetails.BuildPolyMeshDetail(ctx, pmesh, chf, cfg.DetailSampleDist, cfg.DetailSampleMaxError)
: null; : null;
return new RecastBuilderResult(tileX, tileZ, solid, chf, cset, pmesh, dmesh, ctx); return new RcBuilderResult(tileX, tileZ, solid, chf, cset, pmesh, dmesh, ctx);
} }
/* /*
@ -263,17 +266,17 @@ namespace DotRecast.Recast
// as well as filter spans where the character cannot possibly stand. // as well as filter spans where the character cannot possibly stand.
if (cfg.FilterLowHangingObstacles) if (cfg.FilterLowHangingObstacles)
{ {
RecastFilter.FilterLowHangingWalkableObstacles(ctx, cfg.WalkableClimb, solid); RcFilters.FilterLowHangingWalkableObstacles(ctx, cfg.WalkableClimb, solid);
} }
if (cfg.FilterLedgeSpans) if (cfg.FilterLedgeSpans)
{ {
RecastFilter.FilterLedgeSpans(ctx, cfg.WalkableHeight, cfg.WalkableClimb, solid); RcFilters.FilterLedgeSpans(ctx, cfg.WalkableHeight, cfg.WalkableClimb, solid);
} }
if (cfg.FilterWalkableLowHeightSpans) if (cfg.FilterWalkableLowHeightSpans)
{ {
RecastFilter.FilterWalkableLowHeightSpans(ctx, cfg.WalkableHeight, solid); RcFilters.FilterWalkableLowHeightSpans(ctx, cfg.WalkableHeight, solid);
} }
} }
@ -286,29 +289,29 @@ namespace DotRecast.Recast
// Compact the heightfield so that it is faster to handle from now on. // Compact the heightfield so that it is faster to handle from now on.
// This will result more cache coherent data as well as the neighbours // This will result more cache coherent data as well as the neighbours
// between walkable cells will be calculated. // between walkable cells will be calculated.
RcCompactHeightfield chf = RecastCompact.BuildCompactHeightfield(ctx, cfg.WalkableHeight, cfg.WalkableClimb, solid); RcCompactHeightfield chf = RcCompacts.BuildCompactHeightfield(ctx, cfg.WalkableHeight, cfg.WalkableClimb, solid);
// Erode the walkable area by agent radius. // Erode the walkable area by agent radius.
RecastArea.ErodeWalkableArea(ctx, cfg.WalkableRadius, chf); ErodeWalkableArea(ctx, cfg.WalkableRadius, chf);
// (Optional) Mark areas. // (Optional) Mark areas.
if (geom != null) if (geom != null)
{ {
foreach (RcConvexVolume vol in geom.ConvexVolumes()) foreach (RcConvexVolume vol in geom.ConvexVolumes())
{ {
RecastArea.MarkConvexPolyArea(ctx, vol.verts, vol.hmin, vol.hmax, vol.areaMod, chf); MarkConvexPolyArea(ctx, vol.verts, vol.hmin, vol.hmax, vol.areaMod, chf);
} }
} }
return chf; return chf;
} }
public RcHeightfieldLayerSet BuildLayers(IInputGeomProvider geom, RecastBuilderConfig builderCfg) public RcHeightfieldLayerSet BuildLayers(IInputGeomProvider geom, RcBuilderConfig builderCfg)
{ {
RcTelemetry ctx = new RcTelemetry(); RcTelemetry ctx = new RcTelemetry();
RcHeightfield solid = RecastVoxelization.BuildSolidHeightfield(geom, builderCfg, ctx); RcHeightfield solid = RcVoxelizations.BuildSolidHeightfield(geom, builderCfg, ctx);
FilterHeightfield(solid, builderCfg.cfg, ctx); FilterHeightfield(solid, builderCfg.cfg, ctx);
RcCompactHeightfield chf = BuildCompactHeightfield(geom, builderCfg.cfg, ctx, solid); RcCompactHeightfield chf = BuildCompactHeightfield(geom, builderCfg.cfg, ctx, solid);
return RecastLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.WalkableHeight); return RcLayers.BuildHeightfieldLayers(ctx, chf, builderCfg.cfg.WalkableHeight);
} }
} }
} }

View File

@ -22,7 +22,7 @@ using DotRecast.Core;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public class RecastBuilderConfig public class RcBuilderConfig
{ {
public readonly RcConfig cfg; public readonly RcConfig cfg;
@ -41,11 +41,11 @@ namespace DotRecast.Recast
/** The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] **/ /** The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] **/
public readonly RcVec3f bmax = new RcVec3f(); public readonly RcVec3f bmax = new RcVec3f();
public RecastBuilderConfig(RcConfig cfg, RcVec3f bmin, RcVec3f bmax) : this(cfg, bmin, bmax, 0, 0) public RcBuilderConfig(RcConfig cfg, RcVec3f bmin, RcVec3f bmax) : this(cfg, bmin, bmax, 0, 0)
{ {
} }
public RecastBuilderConfig(RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tileX, int tileZ) public RcBuilderConfig(RcConfig cfg, RcVec3f bmin, RcVec3f bmax, int tileX, int tileZ)
{ {
this.tileX = tileX; this.tileX = tileX;
this.tileZ = tileZ; this.tileZ = tileZ;
@ -92,7 +92,7 @@ namespace DotRecast.Recast
} }
else else
{ {
RcUtils.CalcGridSize(this.bmin, this.bmax, cfg.Cs, out width, out height); RcCommons.CalcGridSize(this.bmin, this.bmax, cfg.Cs, out width, out height);
} }
} }
} }

View File

@ -2,7 +2,7 @@
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public class RecastBuilderResult public class RcBuilderResult
{ {
public readonly int tileX; public readonly int tileX;
public readonly int tileZ; public readonly int tileZ;
@ -14,7 +14,7 @@ namespace DotRecast.Recast
private readonly RcHeightfield solid; private readonly RcHeightfield solid;
private readonly RcTelemetry telemetry; private readonly RcTelemetry telemetry;
public RecastBuilderResult(int tileX, int tileZ, RcHeightfield solid, RcCompactHeightfield chf, RcContourSet cs, RcPolyMesh pmesh, RcPolyMeshDetail dmesh, RcTelemetry ctx) public RcBuilderResult(int tileX, int tileZ, RcHeightfield solid, RcCompactHeightfield chf, RcContourSet cs, RcPolyMesh pmesh, RcPolyMeshDetail dmesh, RcTelemetry ctx)
{ {
this.tileX = tileX; this.tileX = tileX;
this.tileZ = tileZ; this.tileZ = tileZ;

View File

@ -23,10 +23,61 @@ using DotRecast.Core;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
using static DotRecast.Recast.RcConstants; using static RcConstants;
public static class RcUtils public static class RcCommons
{ {
private static readonly int[] DirOffsetX = { -1, 0, 1, 0, };
private static readonly int[] DirOffsetY = { 0, 1, 0, -1 };
private static readonly int[] DirForOffset = { 3, 0, -1, 2, 1 };
/// Sets the neighbor connection data for the specified direction.
/// @param[in] span The span to update.
/// @param[in] direction The direction to set. [Limits: 0 <= value < 4]
/// @param[in] neighborIndex The index of the neighbor span.
public static void SetCon(RcCompactSpan span, int direction, int neighborIndex)
{
int shift = direction * 6;
int con = span.con;
span.con = (con & ~(0x3f << shift)) | ((neighborIndex & 0x3f) << shift);
}
/// Gets neighbor connection data for the specified direction.
/// @param[in] span The span to check.
/// @param[in] direction The direction to check. [Limits: 0 <= value < 4]
/// @return The neighbor connection data for the specified direction, or #RC_NOT_CONNECTED if there is no connection.
public static int GetCon(RcCompactSpan s, int dir)
{
int shift = dir * 6;
return (s.con >> shift) & 0x3f;
}
/// Gets the standard width (x-axis) offset for the specified direction.
/// @param[in] direction The direction. [Limits: 0 <= value < 4]
/// @return The width offset to apply to the current cell position to move in the direction.
public static int GetDirOffsetX(int dir)
{
return DirOffsetX[dir & 0x03];
}
// TODO (graham): Rename this to rcGetDirOffsetZ
/// Gets the standard height (z-axis) offset for the specified direction.
/// @param[in] direction The direction. [Limits: 0 <= value < 4]
/// @return The height offset to apply to the current cell position to move in the direction.
public static int GetDirOffsetY(int dir)
{
return DirOffsetY[dir & 0x03];
}
/// Gets the direction for the specified offset. One of x and y should be 0.
/// @param[in] offsetX The x offset. [Limits: -1 <= value <= 1]
/// @param[in] offsetZ The z offset. [Limits: -1 <= value <= 1]
/// @return The direction that represents the offset.
public static int GetDirForOffset(int x, int y)
{
return DirForOffset[((y + 1) << 1) + x];
}
public static void CalcBounds(float[] verts, int nv, float[] bmin, float[] bmax) public static void CalcBounds(float[] verts, int nv, float[] bmin, float[] bmax)
{ {
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)

View File

@ -25,7 +25,9 @@ using static DotRecast.Recast.RcConstants;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public static class RecastCompact using static RcCommons;
public static class RcCompacts
{ {
private const int MAX_LAYERS = RC_NOT_CONNECTED - 1; private const int MAX_LAYERS = RC_NOT_CONNECTED - 1;
private const int MAX_HEIGHT = RcConstants.SPAN_MAX_HEIGHT; private const int MAX_HEIGHT = RcConstants.SPAN_MAX_HEIGHT;
@ -117,9 +119,9 @@ namespace DotRecast.Recast
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
RecastCommon.SetCon(s, dir, RC_NOT_CONNECTED); SetCon(s, dir, RC_NOT_CONNECTED);
int nx = x + RecastCommon.GetDirOffsetX(dir); int nx = x + GetDirOffsetX(dir);
int ny = y + RecastCommon.GetDirOffsetY(dir); int ny = y + GetDirOffsetY(dir);
// First check that the neighbour cell is in bounds. // First check that the neighbour cell is in bounds.
if (nx < 0 || ny < 0 || nx >= w || ny >= h) if (nx < 0 || ny < 0 || nx >= w || ny >= h)
continue; continue;
@ -145,7 +147,7 @@ namespace DotRecast.Recast
continue; continue;
} }
RecastCommon.SetCon(s, dir, lidx); SetCon(s, dir, lidx);
break; break;
} }
} }

View File

@ -25,8 +25,9 @@ using DotRecast.Core;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
using static RcConstants; using static RcConstants;
using static RcCommons;
public static class RecastContour public static class RcContours
{ {
private static int GetCornerHeight(int x, int y, int i, int dir, RcCompactHeightfield chf, out bool isBorderVertex) private static int GetCornerHeight(int x, int y, int i, int dir, RcCompactHeightfield chf, out bool isBorderVertex)
{ {
@ -45,38 +46,38 @@ namespace DotRecast.Recast
// border vertices which are in between two areas to be removed. // border vertices which are in between two areas to be removed.
regs[0] = chf.spans[i].reg | (chf.areas[i] << 16); regs[0] = chf.spans[i].reg | (chf.areas[i] << 16);
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * chf.width].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * chf.width].index + GetCon(s, dir);
RcCompactSpan @as = chf.spans[ai]; RcCompactSpan @as = chf.spans[ai];
ch = Math.Max(ch, @as.y); ch = Math.Max(ch, @as.y);
regs[1] = chf.spans[ai].reg | (chf.areas[ai] << 16); regs[1] = chf.spans[ai].reg | (chf.areas[ai] << 16);
if (RecastCommon.GetCon(@as, dirp) != RC_NOT_CONNECTED) if (GetCon(@as, dirp) != RC_NOT_CONNECTED)
{ {
int ax2 = ax + RecastCommon.GetDirOffsetX(dirp); int ax2 = ax + GetDirOffsetX(dirp);
int ay2 = ay + RecastCommon.GetDirOffsetY(dirp); int ay2 = ay + GetDirOffsetY(dirp);
int ai2 = chf.cells[ax2 + ay2 * chf.width].index + RecastCommon.GetCon(@as, dirp); int ai2 = chf.cells[ax2 + ay2 * chf.width].index + GetCon(@as, dirp);
RcCompactSpan as2 = chf.spans[ai2]; RcCompactSpan as2 = chf.spans[ai2];
ch = Math.Max(ch, as2.y); ch = Math.Max(ch, as2.y);
regs[2] = chf.spans[ai2].reg | (chf.areas[ai2] << 16); regs[2] = chf.spans[ai2].reg | (chf.areas[ai2] << 16);
} }
} }
if (RecastCommon.GetCon(s, dirp) != RC_NOT_CONNECTED) if (GetCon(s, dirp) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dirp); int ax = x + GetDirOffsetX(dirp);
int ay = y + RecastCommon.GetDirOffsetY(dirp); int ay = y + GetDirOffsetY(dirp);
int ai = chf.cells[ax + ay * chf.width].index + RecastCommon.GetCon(s, dirp); int ai = chf.cells[ax + ay * chf.width].index + GetCon(s, dirp);
RcCompactSpan @as = chf.spans[ai]; RcCompactSpan @as = chf.spans[ai];
ch = Math.Max(ch, @as.y); ch = Math.Max(ch, @as.y);
regs[3] = chf.spans[ai].reg | (chf.areas[ai] << 16); regs[3] = chf.spans[ai].reg | (chf.areas[ai] << 16);
if (RecastCommon.GetCon(@as, dir) != RC_NOT_CONNECTED) if (GetCon(@as, dir) != RC_NOT_CONNECTED)
{ {
int ax2 = ax + RecastCommon.GetDirOffsetX(dir); int ax2 = ax + GetDirOffsetX(dir);
int ay2 = ay + RecastCommon.GetDirOffsetY(dir); int ay2 = ay + GetDirOffsetY(dir);
int ai2 = chf.cells[ax2 + ay2 * chf.width].index + RecastCommon.GetCon(@as, dir); int ai2 = chf.cells[ax2 + ay2 * chf.width].index + GetCon(@as, dir);
RcCompactSpan as2 = chf.spans[ai2]; RcCompactSpan as2 = chf.spans[ai2];
ch = Math.Max(ch, as2.y); ch = Math.Max(ch, as2.y);
regs[2] = chf.spans[ai2].reg | (chf.areas[ai2] << 16); regs[2] = chf.spans[ai2].reg | (chf.areas[ai2] << 16);
@ -146,11 +147,11 @@ namespace DotRecast.Recast
int r = 0; int r = 0;
RcCompactSpan s = chf.spans[i]; RcCompactSpan s = chf.spans[i];
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * chf.width].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * chf.width].index + GetCon(s, dir);
r = chf.spans[ai].reg; r = chf.spans[ai].reg;
if (area != chf.areas[ai]) if (area != chf.areas[ai])
isAreaBorder = true; isAreaBorder = true;
@ -171,13 +172,13 @@ namespace DotRecast.Recast
else else
{ {
int ni = -1; int ni = -1;
int nx = x + RecastCommon.GetDirOffsetX(dir); int nx = x + GetDirOffsetX(dir);
int ny = y + RecastCommon.GetDirOffsetY(dir); int ny = y + GetDirOffsetY(dir);
RcCompactSpan s = chf.spans[i]; RcCompactSpan s = chf.spans[i];
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
RcCompactCell nc = chf.cells[nx + ny * chf.width]; RcCompactCell nc = chf.cells[nx + ny * chf.width];
ni = nc.index + RecastCommon.GetCon(s, dir); ni = nc.index + GetCon(s, dir);
} }
if (ni == -1) if (ni == -1)
@ -475,7 +476,7 @@ namespace DotRecast.Recast
d1 = 4; d1 = 4;
for (int k = 0; k < n; k++) for (int k = 0; k < n; k++)
{ {
int k1 = RecastMesh.Next(k, n); int k1 = RcMeshs.Next(k, n);
// Skip edges incident to i. // Skip edges incident to i.
if (i == k || i == k1) if (i == k || i == k1)
continue; continue;
@ -489,11 +490,11 @@ namespace DotRecast.Recast
p0 = 8; p0 = 8;
p1 = 12; p1 = 12;
if (RecastMesh.VEqual(pverts, d0, p0) || RecastMesh.VEqual(pverts, d1, p0) || if (RcMeshs.VEqual(pverts, d0, p0) || RcMeshs.VEqual(pverts, d1, p0) ||
RecastMesh.VEqual(pverts, d0, p1) || RecastMesh.VEqual(pverts, d1, p1)) RcMeshs.VEqual(pverts, d0, p1) || RcMeshs.VEqual(pverts, d1, p1))
continue; continue;
if (RecastMesh.Intersect(pverts, d0, d1, p0, p1)) if (RcMeshs.Intersect(pverts, d0, d1, p0, p1))
return true; return true;
} }
@ -503,8 +504,8 @@ namespace DotRecast.Recast
private static bool InCone(int i, int n, int[] verts, int pj, int[] vertpj) private static bool InCone(int i, int n, int[] verts, int pj, int[] vertpj)
{ {
int pi = i * 4; int pi = i * 4;
int pi1 = RecastMesh.Next(i, n) * 4; int pi1 = RcMeshs.Next(i, n) * 4;
int pin1 = RecastMesh.Prev(i, n) * 4; int pin1 = RcMeshs.Prev(i, n) * 4;
int[] pverts = new int[4 * 4]; int[] pverts = new int[4 * 4];
for (int g = 0; g < 4; g++) for (int g = 0; g < 4; g++)
{ {
@ -519,11 +520,11 @@ namespace DotRecast.Recast
pin1 = 8; pin1 = 8;
pj = 12; pj = 12;
// If P[i] is a convex vertex [ i+1 left or on (i-1,i) ]. // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
if (RecastMesh.LeftOn(pverts, pin1, pi, pi1)) if (RcMeshs.LeftOn(pverts, pin1, pi, pi1))
return RecastMesh.Left(pverts, pi, pj, pin1) && RecastMesh.Left(pverts, pj, pi, pi1); return RcMeshs.Left(pverts, pi, pj, pin1) && RcMeshs.Left(pverts, pj, pi, pi1);
// Assume (i-1,i,i+1) not collinear. // Assume (i-1,i,i+1) not collinear.
// else P[i] is reflex. // else P[i] is reflex.
return !(RecastMesh.LeftOn(pverts, pi, pj, pi1) && RecastMesh.LeftOn(pverts, pj, pi, pin1)); return !(RcMeshs.LeftOn(pverts, pi, pj, pi1) && RcMeshs.LeftOn(pverts, pj, pi, pin1));
} }
private static void RemoveDegenerateSegments(List<int> simplified) private static void RemoveDegenerateSegments(List<int> simplified)
@ -533,7 +534,7 @@ namespace DotRecast.Recast
int npts = simplified.Count / 4; int npts = simplified.Count / 4;
for (int i = 0; i < npts; ++i) for (int i = 0; i < npts; ++i)
{ {
int ni = RecastMesh.Next(i, npts); int ni = RcMeshs.Next(i, npts);
// if (Vequal(&simplified[i*4], &simplified[ni*4])) // if (Vequal(&simplified[i*4], &simplified[ni*4]))
if (simplified[i * 4] == simplified[ni * 4] if (simplified[i * 4] == simplified[ni * 4]
@ -766,11 +767,11 @@ namespace DotRecast.Recast
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
int r = 0; int r = 0;
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * w].index + GetCon(s, dir);
r = chf.spans[ai].reg; r = chf.spans[ai].reg;
} }

View File

@ -25,7 +25,7 @@ using static DotRecast.Recast.RcConstants;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public static class RecastFilledVolumeRasterization public static class RcFilledVolumeRasterization
{ {
private const float EPSILON = 0.00001f; private const float EPSILON = 0.00001f;
private static readonly int[] BOX_EDGES = new[] { 0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7 }; private static readonly int[] BOX_EDGES = new[] { 0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7 };
@ -56,8 +56,7 @@ namespace DotRecast.Recast
rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius)); rectangle => IntersectCapsule(rectangle, start, end, axis, radius * radius));
} }
public static void RasterizeCylinder(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr, public static void RasterizeCylinder(RcHeightfield hf, RcVec3f start, RcVec3f end, float radius, int area, int flagMergeThr, RcTelemetry ctx)
RcTelemetry ctx)
{ {
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CYLINDER); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CYLINDER);
float[] bounds = float[] bounds =
@ -71,8 +70,7 @@ namespace DotRecast.Recast
rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius)); rectangle => IntersectCylinder(rectangle, start, end, axis, radius * radius));
} }
public static void RasterizeBox(RcHeightfield hf, RcVec3f center, RcVec3f[] halfEdges, int area, int flagMergeThr, public static void RasterizeBox(RcHeightfield hf, RcVec3f center, RcVec3f[] halfEdges, int area, int flagMergeThr, RcTelemetry ctx)
RcTelemetry ctx)
{ {
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_BOX); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_BOX);
RcVec3f[] normals = RcVec3f[] normals =
@ -122,8 +120,7 @@ namespace DotRecast.Recast
RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes)); RasterizationFilledShape(hf, bounds, area, flagMergeThr, rectangle => IntersectBox(rectangle, vertices, planes));
} }
public static void RasterizeConvex(RcHeightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr, public static void RasterizeConvex(RcHeightfield hf, float[] vertices, int[] triangles, int area, int flagMergeThr, RcTelemetry ctx)
RcTelemetry ctx)
{ {
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CONVEX); using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_RASTERIZE_CONVEX);
float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] }; float[] bounds = new float[] { vertices[0], vertices[1], vertices[2], vertices[0], vertices[1], vertices[2] };
@ -226,7 +223,7 @@ namespace DotRecast.Recast
{ {
int ismin = Clamp(smin, 0, SPAN_MAX_HEIGHT); int ismin = Clamp(smin, 0, SPAN_MAX_HEIGHT);
int ismax = Clamp(smax, ismin + 1, SPAN_MAX_HEIGHT); int ismax = Clamp(smax, ismin + 1, SPAN_MAX_HEIGHT);
RecastRasterization.AddSpan(hf, x, z, ismin, ismax, area, flagMergeThr); RcRasterizations.AddSpan(hf, x, z, ismin, ismax, area, flagMergeThr);
} }
} }
} }

View File

@ -24,8 +24,9 @@ using DotRecast.Core;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
using static RcConstants; using static RcConstants;
using static RcCommons;
public static class RecastFilter public static class RcFilters
{ {
/// @par /// @par
/// ///
@ -113,8 +114,8 @@ namespace DotRecast.Recast
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
int dx = x + RecastCommon.GetDirOffsetX(dir); int dx = x + GetDirOffsetX(dir);
int dy = y + RecastCommon.GetDirOffsetY(dir); int dy = y + GetDirOffsetY(dir);
// Skip neighbours which are out of bounds. // Skip neighbours which are out of bounds.
if (dx < 0 || dy < 0 || dx >= w || dy >= h) if (dx < 0 || dy < 0 || dx >= w || dy >= h)
{ {

View File

@ -24,10 +24,10 @@ using DotRecast.Core;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
using static RecastCommon;
using static RcConstants; using static RcConstants;
using static RcCommons;
public static class RecastLayers public static class RcLayers
{ {
const int RC_MAX_LAYERS = RcConstants.RC_NOT_CONNECTED; const int RC_MAX_LAYERS = RcConstants.RC_NOT_CONNECTED;
const int RC_MAX_NEIS = 16; const int RC_MAX_NEIS = 16;

View File

@ -22,12 +22,13 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using DotRecast.Core; using DotRecast.Core;
using static DotRecast.Core.RcMath; using static DotRecast.Core.RcMath;
using static DotRecast.Recast.RecastCommon;
using static DotRecast.Recast.RcConstants; using static DotRecast.Recast.RcConstants;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public static class RecastMeshDetail using static RcCommons;
public static class RcMeshDetails
{ {
public const int MAX_VERTS = 127; public const int MAX_VERTS = 127;
public const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts). public const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
@ -764,8 +765,8 @@ namespace DotRecast.Recast
} }
// segments on edges // segments on edges
int pi = RecastMesh.Prev(i, nhull); int pi = RcMeshs.Prev(i, nhull);
int ni = RecastMesh.Next(i, nhull); int ni = RcMeshs.Next(i, nhull);
int pv = hull[pi] * 3; int pv = hull[pi] * 3;
int cv = hull[i] * 3; int cv = hull[i] * 3;
int nv = hull[ni] * 3; int nv = hull[ni] * 3;
@ -789,11 +790,11 @@ namespace DotRecast.Recast
// depending on which triangle has shorter perimeter. // depending on which triangle has shorter perimeter.
// This heuristic was chose empirically, since it seems // This heuristic was chose empirically, since it seems
// handle tessellated straight edges well. // handle tessellated straight edges well.
while (RecastMesh.Next(left, nhull) != right) while (RcMeshs.Next(left, nhull) != right)
{ {
// Check to see if se should advance left or right. // Check to see if se should advance left or right.
int nleft = RecastMesh.Next(left, nhull); int nleft = RcMeshs.Next(left, nhull);
int nright = RecastMesh.Prev(right, nhull); int nright = RcMeshs.Prev(right, nhull);
int cvleft = hull[left] * 3; int cvleft = hull[left] * 3;
int nvleft = hull[nleft] * 3; int nvleft = hull[nleft] * 3;

View File

@ -25,7 +25,7 @@ namespace DotRecast.Recast
{ {
using static RcConstants; using static RcConstants;
public static class RecastMesh public static class RcMeshs
{ {
public const int MAX_MESH_VERTS_POLY = 0xffff; public const int MAX_MESH_VERTS_POLY = 0xffff;
public const int VERTEX_BUCKET_COUNT = (1 << 12); public const int VERTEX_BUCKET_COUNT = (1 << 12);

View File

@ -24,10 +24,10 @@ namespace DotRecast.Recast
{ {
public static class RcPolyMeshRaycast public static class RcPolyMeshRaycast
{ {
public static bool Raycast(IList<RecastBuilderResult> results, RcVec3f src, RcVec3f dst, out float hitTime) public static bool Raycast(IList<RcBuilderResult> results, RcVec3f src, RcVec3f dst, out float hitTime)
{ {
hitTime = 0.0f; hitTime = 0.0f;
foreach (RecastBuilderResult result in results) foreach (RcBuilderResult result in results)
{ {
if (result.GetMeshDetail() != null) if (result.GetMeshDetail() != null)
{ {

View File

@ -25,7 +25,7 @@ using static DotRecast.Recast.RcConstants;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public static class RecastRasterization public static class RcRasterizations
{ {
/** /**
* Check whether two bounding boxes overlap * Check whether two bounding boxes overlap

View File

@ -26,12 +26,12 @@ using DotRecast.Core;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
using static RcConstants; using static RcConstants;
using static RcCommons;
public static class RecastRegion public static class RcRegions
{ {
const int RC_NULL_NEI = 0xffff; const int RC_NULL_NEI = 0xffff;
public static int CalculateDistanceField(RcCompactHeightfield chf, int[] src) public static int CalculateDistanceField(RcCompactHeightfield chf, int[] src)
{ {
int maxDist; int maxDist;
@ -58,11 +58,11 @@ namespace DotRecast.Recast
int nc = 0; int nc = 0;
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * w].index + GetCon(s, dir);
if (area == chf.areas[ai]) if (area == chf.areas[ai])
{ {
nc++; nc++;
@ -88,12 +88,12 @@ namespace DotRecast.Recast
{ {
RcCompactSpan s = chf.spans[i]; RcCompactSpan s = chf.spans[i];
if (RecastCommon.GetCon(s, 0) != RC_NOT_CONNECTED) if (GetCon(s, 0) != RC_NOT_CONNECTED)
{ {
// (-1,0) // (-1,0)
int ax = x + RecastCommon.GetDirOffsetX(0); int ax = x + GetDirOffsetX(0);
int ay = y + RecastCommon.GetDirOffsetY(0); int ay = y + GetDirOffsetY(0);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, 0); int ai = chf.cells[ax + ay * w].index + GetCon(s, 0);
RcCompactSpan @as = chf.spans[ai]; RcCompactSpan @as = chf.spans[ai];
if (src[ai] + 2 < src[i]) if (src[ai] + 2 < src[i])
{ {
@ -101,11 +101,11 @@ namespace DotRecast.Recast
} }
// (-1,-1) // (-1,-1)
if (RecastCommon.GetCon(@as, 3) != RC_NOT_CONNECTED) if (GetCon(@as, 3) != RC_NOT_CONNECTED)
{ {
int aax = ax + RecastCommon.GetDirOffsetX(3); int aax = ax + GetDirOffsetX(3);
int aay = ay + RecastCommon.GetDirOffsetY(3); int aay = ay + GetDirOffsetY(3);
int aai = chf.cells[aax + aay * w].index + RecastCommon.GetCon(@as, 3); int aai = chf.cells[aax + aay * w].index + GetCon(@as, 3);
if (src[aai] + 3 < src[i]) if (src[aai] + 3 < src[i])
{ {
src[i] = src[aai] + 3; src[i] = src[aai] + 3;
@ -113,12 +113,12 @@ namespace DotRecast.Recast
} }
} }
if (RecastCommon.GetCon(s, 3) != RC_NOT_CONNECTED) if (GetCon(s, 3) != RC_NOT_CONNECTED)
{ {
// (0,-1) // (0,-1)
int ax = x + RecastCommon.GetDirOffsetX(3); int ax = x + GetDirOffsetX(3);
int ay = y + RecastCommon.GetDirOffsetY(3); int ay = y + GetDirOffsetY(3);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, 3); int ai = chf.cells[ax + ay * w].index + GetCon(s, 3);
RcCompactSpan @as = chf.spans[ai]; RcCompactSpan @as = chf.spans[ai];
if (src[ai] + 2 < src[i]) if (src[ai] + 2 < src[i])
{ {
@ -126,11 +126,11 @@ namespace DotRecast.Recast
} }
// (1,-1) // (1,-1)
if (RecastCommon.GetCon(@as, 2) != RC_NOT_CONNECTED) if (GetCon(@as, 2) != RC_NOT_CONNECTED)
{ {
int aax = ax + RecastCommon.GetDirOffsetX(2); int aax = ax + GetDirOffsetX(2);
int aay = ay + RecastCommon.GetDirOffsetY(2); int aay = ay + GetDirOffsetY(2);
int aai = chf.cells[aax + aay * w].index + RecastCommon.GetCon(@as, 2); int aai = chf.cells[aax + aay * w].index + GetCon(@as, 2);
if (src[aai] + 3 < src[i]) if (src[aai] + 3 < src[i])
{ {
src[i] = src[aai] + 3; src[i] = src[aai] + 3;
@ -151,12 +151,12 @@ namespace DotRecast.Recast
{ {
RcCompactSpan s = chf.spans[i]; RcCompactSpan s = chf.spans[i];
if (RecastCommon.GetCon(s, 2) != RC_NOT_CONNECTED) if (GetCon(s, 2) != RC_NOT_CONNECTED)
{ {
// (1,0) // (1,0)
int ax = x + RecastCommon.GetDirOffsetX(2); int ax = x + GetDirOffsetX(2);
int ay = y + RecastCommon.GetDirOffsetY(2); int ay = y + GetDirOffsetY(2);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, 2); int ai = chf.cells[ax + ay * w].index + GetCon(s, 2);
RcCompactSpan @as = chf.spans[ai]; RcCompactSpan @as = chf.spans[ai];
if (src[ai] + 2 < src[i]) if (src[ai] + 2 < src[i])
{ {
@ -164,11 +164,11 @@ namespace DotRecast.Recast
} }
// (1,1) // (1,1)
if (RecastCommon.GetCon(@as, 1) != RC_NOT_CONNECTED) if (GetCon(@as, 1) != RC_NOT_CONNECTED)
{ {
int aax = ax + RecastCommon.GetDirOffsetX(1); int aax = ax + GetDirOffsetX(1);
int aay = ay + RecastCommon.GetDirOffsetY(1); int aay = ay + GetDirOffsetY(1);
int aai = chf.cells[aax + aay * w].index + RecastCommon.GetCon(@as, 1); int aai = chf.cells[aax + aay * w].index + GetCon(@as, 1);
if (src[aai] + 3 < src[i]) if (src[aai] + 3 < src[i])
{ {
src[i] = src[aai] + 3; src[i] = src[aai] + 3;
@ -176,12 +176,12 @@ namespace DotRecast.Recast
} }
} }
if (RecastCommon.GetCon(s, 1) != RC_NOT_CONNECTED) if (GetCon(s, 1) != RC_NOT_CONNECTED)
{ {
// (0,1) // (0,1)
int ax = x + RecastCommon.GetDirOffsetX(1); int ax = x + GetDirOffsetX(1);
int ay = y + RecastCommon.GetDirOffsetY(1); int ay = y + GetDirOffsetY(1);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, 1); int ai = chf.cells[ax + ay * w].index + GetCon(s, 1);
RcCompactSpan @as = chf.spans[ai]; RcCompactSpan @as = chf.spans[ai];
if (src[ai] + 2 < src[i]) if (src[ai] + 2 < src[i])
{ {
@ -189,11 +189,11 @@ namespace DotRecast.Recast
} }
// (-1,1) // (-1,1)
if (RecastCommon.GetCon(@as, 0) != RC_NOT_CONNECTED) if (GetCon(@as, 0) != RC_NOT_CONNECTED)
{ {
int aax = ax + RecastCommon.GetDirOffsetX(0); int aax = ax + GetDirOffsetX(0);
int aay = ay + RecastCommon.GetDirOffsetY(0); int aay = ay + GetDirOffsetY(0);
int aai = chf.cells[aax + aay * w].index + RecastCommon.GetCon(@as, 0); int aai = chf.cells[aax + aay * w].index + GetCon(@as, 0);
if (src[aai] + 3 < src[i]) if (src[aai] + 3 < src[i])
{ {
src[i] = src[aai] + 3; src[i] = src[aai] + 3;
@ -239,20 +239,20 @@ namespace DotRecast.Recast
int d = cd; int d = cd;
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * w].index + GetCon(s, dir);
d += src[ai]; d += src[ai];
RcCompactSpan @as = chf.spans[ai]; RcCompactSpan @as = chf.spans[ai];
int dir2 = (dir + 1) & 0x3; int dir2 = (dir + 1) & 0x3;
if (RecastCommon.GetCon(@as, dir2) != RC_NOT_CONNECTED) if (GetCon(@as, dir2) != RC_NOT_CONNECTED)
{ {
int ax2 = ax + RecastCommon.GetDirOffsetX(dir2); int ax2 = ax + GetDirOffsetX(dir2);
int ay2 = ay + RecastCommon.GetDirOffsetY(dir2); int ay2 = ay + GetDirOffsetY(dir2);
int ai2 = chf.cells[ax2 + ay2 * w].index + RecastCommon.GetCon(@as, dir2); int ai2 = chf.cells[ax2 + ay2 * w].index + GetCon(@as, dir2);
d += src[ai2]; d += src[ai2];
} }
else else
@ -311,11 +311,11 @@ namespace DotRecast.Recast
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
// 8 connected // 8 connected
if (RecastCommon.GetCon(cs, dir) != RC_NOT_CONNECTED) if (GetCon(cs, dir) != RC_NOT_CONNECTED)
{ {
int ax = cx + RecastCommon.GetDirOffsetX(dir); int ax = cx + GetDirOffsetX(dir);
int ay = cy + RecastCommon.GetDirOffsetY(dir); int ay = cy + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(cs, dir); int ai = chf.cells[ax + ay * w].index + GetCon(cs, dir);
if (chf.areas[ai] != area) if (chf.areas[ai] != area)
{ {
continue; continue;
@ -336,11 +336,11 @@ namespace DotRecast.Recast
RcCompactSpan @as = chf.spans[ai]; RcCompactSpan @as = chf.spans[ai];
int dir2 = (dir + 1) & 0x3; int dir2 = (dir + 1) & 0x3;
if (RecastCommon.GetCon(@as, dir2) != RC_NOT_CONNECTED) if (GetCon(@as, dir2) != RC_NOT_CONNECTED)
{ {
int ax2 = ax + RecastCommon.GetDirOffsetX(dir2); int ax2 = ax + GetDirOffsetX(dir2);
int ay2 = ay + RecastCommon.GetDirOffsetY(dir2); int ay2 = ay + GetDirOffsetY(dir2);
int ai2 = chf.cells[ax2 + ay2 * w].index + RecastCommon.GetCon(@as, dir2); int ai2 = chf.cells[ax2 + ay2 * w].index + GetCon(@as, dir2);
if (chf.areas[ai2] != area) if (chf.areas[ai2] != area)
{ {
continue; continue;
@ -367,11 +367,11 @@ namespace DotRecast.Recast
// Expand neighbours. // Expand neighbours.
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
if (RecastCommon.GetCon(cs, dir) != RC_NOT_CONNECTED) if (GetCon(cs, dir) != RC_NOT_CONNECTED)
{ {
int ax = cx + RecastCommon.GetDirOffsetX(dir); int ax = cx + GetDirOffsetX(dir);
int ay = cy + RecastCommon.GetDirOffsetY(dir); int ay = cy + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(cs, dir); int ai = chf.cells[ax + ay * w].index + GetCon(cs, dir);
if (chf.areas[ai] != area) if (chf.areas[ai] != area)
{ {
continue; continue;
@ -456,14 +456,14 @@ namespace DotRecast.Recast
RcCompactSpan s = chf.spans[i]; RcCompactSpan s = chf.spans[i];
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
if (RecastCommon.GetCon(s, dir) == RC_NOT_CONNECTED) if (GetCon(s, dir) == RC_NOT_CONNECTED)
{ {
continue; continue;
} }
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * w].index + GetCon(s, dir);
if (chf.areas[ai] != area) if (chf.areas[ai] != area)
{ {
continue; continue;
@ -741,11 +741,11 @@ namespace DotRecast.Recast
{ {
RcCompactSpan s = chf.spans[i]; RcCompactSpan s = chf.spans[i];
int r = 0; int r = 0;
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * chf.width].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * chf.width].index + GetCon(s, dir);
r = srcReg[ai]; r = srcReg[ai];
} }
@ -765,11 +765,11 @@ namespace DotRecast.Recast
RcCompactSpan ss = chf.spans[i]; RcCompactSpan ss = chf.spans[i];
int curReg = 0; int curReg = 0;
if (RecastCommon.GetCon(ss, dir) != RC_NOT_CONNECTED) if (GetCon(ss, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * chf.width].index + RecastCommon.GetCon(ss, dir); int ai = chf.cells[ax + ay * chf.width].index + GetCon(ss, dir);
curReg = srcReg[ai]; curReg = srcReg[ai];
} }
@ -784,11 +784,11 @@ namespace DotRecast.Recast
{ {
// Choose the edge corner // Choose the edge corner
int r = 0; int r = 0;
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * chf.width].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * chf.width].index + GetCon(s, dir);
r = srcReg[ai]; r = srcReg[ai];
} }
@ -803,12 +803,12 @@ namespace DotRecast.Recast
else else
{ {
int ni = -1; int ni = -1;
int nx = x + RecastCommon.GetDirOffsetX(dir); int nx = x + GetDirOffsetX(dir);
int ny = y + RecastCommon.GetDirOffsetY(dir); int ny = y + GetDirOffsetY(dir);
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
RcCompactCell nc = chf.cells[nx + ny * chf.width]; RcCompactCell nc = chf.cells[nx + ny * chf.width];
ni = nc.index + RecastCommon.GetCon(s, dir); ni = nc.index + GetCon(s, dir);
} }
if (ni == -1) if (ni == -1)
@ -1215,11 +1215,11 @@ namespace DotRecast.Recast
// Update neighbours // Update neighbours
for (int dir = 0; dir < 4; ++dir) for (int dir = 0; dir < 4; ++dir)
{ {
if (RecastCommon.GetCon(s, dir) != RC_NOT_CONNECTED) if (GetCon(s, dir) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(dir); int ax = x + GetDirOffsetX(dir);
int ay = y + RecastCommon.GetDirOffsetY(dir); int ay = y + GetDirOffsetY(dir);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, dir); int ai = chf.cells[ax + ay * w].index + GetCon(s, dir);
int rai = srcReg[ai]; int rai = srcReg[ai];
if (rai > 0 && rai < nreg && rai != ri) if (rai > 0 && rai < nreg && rai != ri)
{ {
@ -1543,11 +1543,11 @@ namespace DotRecast.Recast
// -x // -x
int previd = 0; int previd = 0;
if (RecastCommon.GetCon(s, 0) != RC_NOT_CONNECTED) if (GetCon(s, 0) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(0); int ax = x + GetDirOffsetX(0);
int ay = y + RecastCommon.GetDirOffsetY(0); int ay = y + GetDirOffsetY(0);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, 0); int ai = chf.cells[ax + ay * w].index + GetCon(s, 0);
if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai]) if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
{ {
previd = srcReg[ai]; previd = srcReg[ai];
@ -1563,11 +1563,11 @@ namespace DotRecast.Recast
} }
// -y // -y
if (RecastCommon.GetCon(s, 3) != RC_NOT_CONNECTED) if (GetCon(s, 3) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(3); int ax = x + GetDirOffsetX(3);
int ay = y + RecastCommon.GetDirOffsetY(3); int ay = y + GetDirOffsetY(3);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, 3); int ai = chf.cells[ax + ay * w].index + GetCon(s, 3);
if (srcReg[ai] != 0 && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai]) if (srcReg[ai] != 0 && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
{ {
int nr = srcReg[ai]; int nr = srcReg[ai];
@ -1843,11 +1843,11 @@ namespace DotRecast.Recast
// -x // -x
int previd = 0; int previd = 0;
if (RecastCommon.GetCon(s, 0) != RC_NOT_CONNECTED) if (GetCon(s, 0) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(0); int ax = x + GetDirOffsetX(0);
int ay = y + RecastCommon.GetDirOffsetY(0); int ay = y + GetDirOffsetY(0);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, 0); int ai = chf.cells[ax + ay * w].index + GetCon(s, 0);
if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai]) if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
{ {
previd = srcReg[ai]; previd = srcReg[ai];
@ -1863,11 +1863,11 @@ namespace DotRecast.Recast
} }
// -y // -y
if (RecastCommon.GetCon(s, 3) != RC_NOT_CONNECTED) if (GetCon(s, 3) != RC_NOT_CONNECTED)
{ {
int ax = x + RecastCommon.GetDirOffsetX(3); int ax = x + GetDirOffsetX(3);
int ay = y + RecastCommon.GetDirOffsetY(3); int ay = y + GetDirOffsetY(3);
int ai = chf.cells[ax + ay * w].index + RecastCommon.GetCon(s, 3); int ai = chf.cells[ax + ay * w].index + GetCon(s, 3);
if (srcReg[ai] != 0 && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai]) if (srcReg[ai] != 0 && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
{ {
int nr = srcReg[ai]; int nr = srcReg[ai];

View File

@ -23,9 +23,9 @@ using DotRecast.Recast.Geom;
namespace DotRecast.Recast namespace DotRecast.Recast
{ {
public static class RecastVoxelization public static class RcVoxelizations
{ {
public static RcHeightfield BuildSolidHeightfield(IInputGeomProvider geomProvider, RecastBuilderConfig builderCfg, RcTelemetry ctx) public static RcHeightfield BuildSolidHeightfield(IInputGeomProvider geomProvider, RcBuilderConfig builderCfg, RcTelemetry ctx)
{ {
RcConfig cfg = builderCfg.cfg; RcConfig cfg = builderCfg.cfg;
@ -58,16 +58,16 @@ namespace DotRecast.Recast
{ {
int[] tris = node.tris; int[] tris = node.tris;
int ntris = tris.Length / 3; int ntris = tris.Length / 3;
int[] m_triareas = RcUtils.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod); int[] m_triareas = RcCommons.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
RecastRasterization.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, ctx); RcRasterizations.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, ctx);
} }
} }
else else
{ {
int[] tris = geom.GetTris(); int[] tris = geom.GetTris();
int ntris = tris.Length / 3; int ntris = tris.Length / 3;
int[] m_triareas = RcUtils.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod); int[] m_triareas = RcCommons.MarkWalkableTriangles(ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
RecastRasterization.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, ctx); RcRasterizations.RasterizeTriangles(solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, ctx);
} }
} }

View File

@ -1,78 +0,0 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.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.
*/
using System;
namespace DotRecast.Recast
{
public static class RecastCommon
{
private static readonly int[] DirOffsetX = { -1, 0, 1, 0, };
private static readonly int[] DirOffsetY = { 0, 1, 0, -1 };
private static readonly int[] DirForOffset = { 3, 0, -1, 2, 1 };
/// Sets the neighbor connection data for the specified direction.
/// @param[in] span The span to update.
/// @param[in] direction The direction to set. [Limits: 0 <= value < 4]
/// @param[in] neighborIndex The index of the neighbor span.
public static void SetCon(RcCompactSpan span, int direction, int neighborIndex)
{
int shift = direction * 6;
int con = span.con;
span.con = (con & ~(0x3f << shift)) | ((neighborIndex & 0x3f) << shift);
}
/// Gets neighbor connection data for the specified direction.
/// @param[in] span The span to check.
/// @param[in] direction The direction to check. [Limits: 0 <= value < 4]
/// @return The neighbor connection data for the specified direction, or #RC_NOT_CONNECTED if there is no connection.
public static int GetCon(RcCompactSpan s, int dir)
{
int shift = dir * 6;
return (s.con >> shift) & 0x3f;
}
/// Gets the standard width (x-axis) offset for the specified direction.
/// @param[in] direction The direction. [Limits: 0 <= value < 4]
/// @return The width offset to apply to the current cell position to move in the direction.
public static int GetDirOffsetX(int dir)
{
return DirOffsetX[dir & 0x03];
}
// TODO (graham): Rename this to rcGetDirOffsetZ
/// Gets the standard height (z-axis) offset for the specified direction.
/// @param[in] direction The direction. [Limits: 0 <= value < 4]
/// @return The height offset to apply to the current cell position to move in the direction.
public static int GetDirOffsetY(int dir)
{
return DirOffsetY[dir & 0x03];
}
/// Gets the direction for the specified offset. One of x and y should be 0.
/// @param[in] offsetX The x offset. [Limits: -1 <= value <= 1]
/// @param[in] offsetZ The z offset. [Limits: -1 <= value <= 1]
/// @return The direction that represents the offset.
public static int GetDirForOffset(int x, int y)
{
return DirForOffset[((y + 1) << 1) + x];
}
}
}

View File

@ -70,9 +70,9 @@ public class RecastTestMeshBuilder
detailSampleDist, detailSampleMaxError, detailSampleDist, detailSampleMaxError,
true, true, true, true, true, true,
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
RecastBuilder rcBuilder = new RecastBuilder(); RcBuilder rcBuilder = new RcBuilder();
RecastBuilderResult rcResult = rcBuilder.Build(geom, bcfg); RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg);
RcPolyMesh m_pmesh = rcResult.GetMesh(); RcPolyMesh m_pmesh = rcResult.GetMesh();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {

View File

@ -69,7 +69,7 @@ public class MeshSetReaderWriterTest
RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax(); RcVec3f bmax = geom.GetMeshBoundsMax();
RcUtils.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize, out var tw, out var th); RcCommons.CalcTileCount(bmin, bmax, m_cellSize, m_tileSize, m_tileSize, out var tw, out var th);
for (int y = 0; y < th; ++y) for (int y = 0; y < th; ++y)
{ {
for (int x = 0; x < tw; ++x) for (int x = 0; x < tw; ++x)
@ -85,7 +85,7 @@ public class MeshSetReaderWriterTest
m_detailSampleDist, m_detailSampleMaxError, m_detailSampleDist, m_detailSampleMaxError,
true, true, true, true, true, true,
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, bmin, bmax, x, y); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, bmin, bmax, x, y);
TestDetourBuilder db = new TestDetourBuilder(); TestDetourBuilder db = new TestDetourBuilder();
DtMeshData data = db.Build(geom, bcfg, m_agentHeight, m_agentRadius, m_agentMaxClimb, x, y, true); DtMeshData data = db.Build(geom, bcfg, m_agentHeight, m_agentRadius, m_agentMaxClimb, x, y, true);
if (data != null) if (data != null)

View File

@ -70,9 +70,9 @@ public class RecastTestMeshBuilder
detailSampleDist, detailSampleMaxError, detailSampleDist, detailSampleMaxError,
true, true, true, true, true, true,
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax()); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
RecastBuilder rcBuilder = new RecastBuilder(); RcBuilder rcBuilder = new RcBuilder();
RecastBuilderResult rcResult = rcBuilder.Build(geom, bcfg); RcBuilderResult rcResult = rcBuilder.Build(geom, bcfg);
RcPolyMesh m_pmesh = rcResult.GetMesh(); RcPolyMesh m_pmesh = rcResult.GetMesh();
for (int i = 0; i < m_pmesh.npolys; ++i) for (int i = 0; i < m_pmesh.npolys; ++i)
{ {

View File

@ -23,11 +23,11 @@ namespace DotRecast.Detour.Test;
public class TestDetourBuilder : DetourBuilder public class TestDetourBuilder : DetourBuilder
{ {
public DtMeshData Build(IInputGeomProvider geom, RecastBuilderConfig rcConfig, float agentHeight, float agentRadius, public DtMeshData Build(IInputGeomProvider geom, RcBuilderConfig rcConfig, float agentHeight, float agentRadius,
float agentMaxClimb, int x, int y, bool applyRecastDemoFlags) float agentMaxClimb, int x, int y, bool applyRecastDemoFlags)
{ {
RecastBuilder rcBuilder = new RecastBuilder(); RcBuilder rcBuilder = new RcBuilder();
RecastBuilderResult rcResult = rcBuilder.Build(geom, rcConfig); RcBuilderResult rcResult = rcBuilder.Build(geom, rcConfig);
RcPolyMesh pmesh = rcResult.GetMesh(); RcPolyMesh pmesh = rcResult.GetMesh();
if (applyRecastDemoFlags) if (applyRecastDemoFlags)

View File

@ -77,12 +77,12 @@ public class TestTiledNavMeshBuilder
detailSampleDist, detailSampleMaxError, detailSampleDist, detailSampleMaxError,
true, true, true, true, true, true,
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RecastBuilder rcBuilder = new RecastBuilder(); RcBuilder rcBuilder = new RcBuilder();
List<RecastBuilderResult> rcResult = rcBuilder.BuildTiles(geom, cfg, null); List<RcBuilderResult> rcResult = rcBuilder.BuildTiles(geom, cfg, null);
// Add tiles to nav mesh // Add tiles to nav mesh
foreach (RecastBuilderResult result in rcResult) foreach (RcBuilderResult result in rcResult)
{ {
RcPolyMesh pmesh = result.GetMesh(); RcPolyMesh pmesh = result.GetMesh();
if (pmesh.npolys == 0) if (pmesh.npolys == 0)

View File

@ -46,7 +46,7 @@ public class AbstractTileCacheTest
public DtTileCache GetTileCache(IInputGeomProvider geom, RcByteOrder order, bool cCompatibility) public DtTileCache GetTileCache(IInputGeomProvider geom, RcByteOrder order, bool cCompatibility)
{ {
DtTileCacheParams option = new DtTileCacheParams(); DtTileCacheParams option = new DtTileCacheParams();
RcUtils.CalcTileCount(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), m_cellSize, m_tileSize, m_tileSize, out var tw, out var th); RcCommons.CalcTileCount(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), m_cellSize, m_tileSize, m_tileSize, out var tw, out var th);
option.ch = m_cellHeight; option.ch = m_cellHeight;
option.cs = m_cellSize; option.cs = m_cellSize;
option.orig = geom.GetMeshBoundsMin(); option.orig = geom.GetMeshBoundsMin();

View File

@ -73,7 +73,7 @@ public class TestTileLayerBuilder : DtTileCacheLayerBuilder
RcVec3f bmin = geom.GetMeshBoundsMin(); RcVec3f bmin = geom.GetMeshBoundsMin();
RcVec3f bmax = geom.GetMeshBoundsMax(); RcVec3f bmax = geom.GetMeshBoundsMax();
RcUtils.CalcTileCount(bmin, bmax, CellSize, m_tileSize, m_tileSize, out tw, out th); RcCommons.CalcTileCount(bmin, bmax, CellSize, m_tileSize, m_tileSize, out tw, out th);
} }
public List<byte[]> Build(RcByteOrder order, bool cCompatibility, int threads) public List<byte[]> Build(RcByteOrder order, bool cCompatibility, int threads)

View File

@ -146,7 +146,7 @@ public class RecastLayersTest
private RcHeightfieldLayerSet Build(string filename, int x, int y) private RcHeightfieldLayerSet Build(string filename, int x, int y)
{ {
IInputGeomProvider geom = ObjImporter.Load(RcResources.Load(filename)); IInputGeomProvider geom = ObjImporter.Load(RcResources.Load(filename));
RecastBuilder builder = new RecastBuilder(); RcBuilder builder = new RcBuilder();
RcConfig cfg = new RcConfig(true, m_tileSize, m_tileSize, RcConfig cfg = new RcConfig(true, m_tileSize, m_tileSize,
RcConfig.CalcBorder(m_agentRadius, m_cellSize), RcConfig.CalcBorder(m_agentRadius, m_cellSize),
RcPartitionType.OfValue(m_partitionType), RcPartitionType.OfValue(m_partitionType),
@ -158,7 +158,7 @@ public class RecastLayersTest
m_detailSampleDist, m_detailSampleMaxError, m_detailSampleDist, m_detailSampleMaxError,
true, true, true, true, true, true,
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), x, y); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), x, y);
RcHeightfieldLayerSet lset = builder.BuildLayers(geom, bcfg); RcHeightfieldLayerSet lset = builder.BuildLayers(geom, bcfg);
return lset; return lset;
} }

View File

@ -26,6 +26,7 @@ using NUnit.Framework;
namespace DotRecast.Recast.Test; namespace DotRecast.Recast.Test;
using static RcConstants; using static RcConstants;
using static RcAreas;
[Parallelizable] [Parallelizable]
public class RecastSoloMeshTest public class RecastSoloMeshTest
@ -116,7 +117,7 @@ public class RecastSoloMeshTest
m_detailSampleDist, m_detailSampleMaxError, m_detailSampleDist, m_detailSampleMaxError,
true, true, true, true, true, true,
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, bmin, bmax); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, bmin, bmax);
// //
// Step 2. Rasterize input polygon soup. // Step 2. Rasterize input polygon soup.
@ -138,8 +139,8 @@ public class RecastSoloMeshTest
// Find triangles which are walkable based on their slope and rasterize them. // Find triangles which are walkable based on their slope and rasterize them.
// If your input data is multiple meshes, you can transform them here, calculate // If your input data is multiple meshes, you can transform them here, calculate
// the are type for each of the meshes and rasterize them. // the are type for each of the meshes and rasterize them.
int[] m_triareas = RcUtils.MarkWalkableTriangles(m_ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod); int[] m_triareas = RcCommons.MarkWalkableTriangles(m_ctx, cfg.WalkableSlopeAngle, verts, tris, ntris, cfg.WalkableAreaMod);
RecastRasterization.RasterizeTriangles(m_solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, m_ctx); RcRasterizations.RasterizeTriangles(m_solid, verts, tris, m_triareas, ntris, cfg.WalkableClimb, m_ctx);
} }
// //
@ -149,9 +150,9 @@ public class RecastSoloMeshTest
// Once all geometry is rasterized, we do initial pass of filtering to // Once all geometry is rasterized, we do initial pass of filtering to
// remove unwanted overhangs caused by the conservative rasterization // remove unwanted overhangs caused by the conservative rasterization
// as well as filter spans where the character cannot possibly stand. // as well as filter spans where the character cannot possibly stand.
RecastFilter.FilterLowHangingWalkableObstacles(m_ctx, cfg.WalkableClimb, m_solid); RcFilters.FilterLowHangingWalkableObstacles(m_ctx, cfg.WalkableClimb, m_solid);
RecastFilter.FilterLedgeSpans(m_ctx, cfg.WalkableHeight, cfg.WalkableClimb, m_solid); RcFilters.FilterLedgeSpans(m_ctx, cfg.WalkableHeight, cfg.WalkableClimb, m_solid);
RecastFilter.FilterWalkableLowHeightSpans(m_ctx, cfg.WalkableHeight, m_solid); RcFilters.FilterWalkableLowHeightSpans(m_ctx, cfg.WalkableHeight, m_solid);
// //
// Step 4. Partition walkable surface to simple regions. // Step 4. Partition walkable surface to simple regions.
@ -160,11 +161,10 @@ public class RecastSoloMeshTest
// Compact the heightfield so that it is faster to handle from now on. // Compact the heightfield so that it is faster to handle from now on.
// This will result more cache coherent data as well as the neighbours // This will result more cache coherent data as well as the neighbours
// between walkable cells will be calculated. // between walkable cells will be calculated.
RcCompactHeightfield m_chf = RecastCompact.BuildCompactHeightfield(m_ctx, cfg.WalkableHeight, cfg.WalkableClimb, RcCompactHeightfield m_chf = RcCompacts.BuildCompactHeightfield(m_ctx, cfg.WalkableHeight, cfg.WalkableClimb, m_solid);
m_solid);
// Erode the walkable area by agent radius. // Erode the walkable area by agent radius.
RecastArea.ErodeWalkableArea(m_ctx, cfg.WalkableRadius, m_chf); ErodeWalkableArea(m_ctx, cfg.WalkableRadius, m_chf);
// (Optional) Mark areas. // (Optional) Mark areas.
/* /*
@ -216,20 +216,20 @@ public class RecastSoloMeshTest
{ {
// Prepare for region partitioning, by calculating distance field // Prepare for region partitioning, by calculating distance field
// along the walkable surface. // along the walkable surface.
RecastRegion.BuildDistanceField(m_ctx, m_chf); RcRegions.BuildDistanceField(m_ctx, m_chf);
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RecastRegion.BuildRegions(m_ctx, m_chf, cfg.MinRegionArea, cfg.MergeRegionArea); RcRegions.BuildRegions(m_ctx, m_chf, cfg.MinRegionArea, cfg.MergeRegionArea);
} }
else if (m_partitionType == RcPartition.MONOTONE) else if (m_partitionType == RcPartition.MONOTONE)
{ {
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
// Monotone partitioning does not need distancefield. // Monotone partitioning does not need distancefield.
RecastRegion.BuildRegionsMonotone(m_ctx, m_chf, cfg.MinRegionArea, cfg.MergeRegionArea); RcRegions.BuildRegionsMonotone(m_ctx, m_chf, cfg.MinRegionArea, cfg.MergeRegionArea);
} }
else else
{ {
// Partition the walkable surface into simple regions without holes. // Partition the walkable surface into simple regions without holes.
RecastRegion.BuildLayerRegions(m_ctx, m_chf, cfg.MinRegionArea); RcRegions.BuildLayerRegions(m_ctx, m_chf, cfg.MinRegionArea);
} }
Assert.That(m_chf.maxDistance, Is.EqualTo(expDistance), "maxDistance"); Assert.That(m_chf.maxDistance, Is.EqualTo(expDistance), "maxDistance");
@ -239,7 +239,7 @@ public class RecastSoloMeshTest
// //
// Create contours. // Create contours.
RcContourSet m_cset = RecastContour.BuildContours(m_ctx, m_chf, cfg.MaxSimplificationError, cfg.MaxEdgeLen, RcContourSet m_cset = RcContours.BuildContours(m_ctx, m_chf, cfg.MaxSimplificationError, cfg.MaxEdgeLen,
RcConstants.RC_CONTOUR_TESS_WALL_EDGES); RcConstants.RC_CONTOUR_TESS_WALL_EDGES);
Assert.That(m_cset.conts.Count, Is.EqualTo(expContours), "Contours"); Assert.That(m_cset.conts.Count, Is.EqualTo(expContours), "Contours");
@ -248,7 +248,7 @@ public class RecastSoloMeshTest
// //
// Build polygon navmesh from the contours. // Build polygon navmesh from the contours.
RcPolyMesh m_pmesh = RecastMesh.BuildPolyMesh(m_ctx, m_cset, cfg.MaxVertsPerPoly); RcPolyMesh m_pmesh = RcMeshs.BuildPolyMesh(m_ctx, m_cset, cfg.MaxVertsPerPoly);
Assert.That(m_pmesh.nverts, Is.EqualTo(expVerts), "Mesh Verts"); Assert.That(m_pmesh.nverts, Is.EqualTo(expVerts), "Mesh Verts");
Assert.That(m_pmesh.npolys, Is.EqualTo(expPolys), "Mesh Polys"); Assert.That(m_pmesh.npolys, Is.EqualTo(expPolys), "Mesh Polys");
@ -257,7 +257,7 @@ public class RecastSoloMeshTest
// on each polygon. // on each polygon.
// //
RcPolyMeshDetail m_dmesh = RecastMeshDetail.BuildPolyMeshDetail(m_ctx, m_pmesh, m_chf, cfg.DetailSampleDist, RcPolyMeshDetail m_dmesh = RcMeshDetails.BuildPolyMeshDetail(m_ctx, m_pmesh, m_chf, cfg.DetailSampleDist,
cfg.DetailSampleMaxError); cfg.DetailSampleMaxError);
Assert.That(m_dmesh.nmeshes, Is.EqualTo(expDetMeshes), "Mesh Detail Meshes"); Assert.That(m_dmesh.nmeshes, Is.EqualTo(expDetMeshes), "Mesh Detail Meshes");
Assert.That(m_dmesh.nverts, Is.EqualTo(expDetVerts), "Mesh Detail Verts"); Assert.That(m_dmesh.nverts, Is.EqualTo(expDetVerts), "Mesh Detail Verts");

View File

@ -39,18 +39,18 @@ public class RecastTest
RcTelemetry ctx = new RcTelemetry(); RcTelemetry ctx = new RcTelemetry();
{ {
int[] areas = { 42 }; int[] areas = { 42 };
RcUtils.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas); RcCommons.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, unwalkable_tri, nt, areas);
Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Sets area ID of unwalkable triangle to RC_NULL_AREA"); Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Sets area ID of unwalkable triangle to RC_NULL_AREA");
} }
{ {
int[] areas = { 42 }; int[] areas = { 42 };
RcUtils.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas); RcCommons.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas);
Assert.That(areas[0], Is.EqualTo(42), "Does not modify walkable triangle aread ID's"); Assert.That(areas[0], Is.EqualTo(42), "Does not modify walkable triangle aread ID's");
} }
{ {
int[] areas = { 42 }; int[] areas = { 42 };
walkableSlopeAngle = 0; walkableSlopeAngle = 0;
RcUtils.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas); RcCommons.ClearUnwalkableTriangles(ctx, walkableSlopeAngle, verts, nv, walkable_tri, nt, areas);
Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Slopes equal to the max slope are considered unwalkable."); Assert.That(areas[0], Is.EqualTo(RC_NULL_AREA), "Slopes equal to the max slope are considered unwalkable.");
} }
} }

View File

@ -59,7 +59,7 @@ public class RecastTileMeshTest
public void TestBuild(string filename) public void TestBuild(string filename)
{ {
IInputGeomProvider geom = ObjImporter.Load(RcResources.Load(filename)); IInputGeomProvider geom = ObjImporter.Load(RcResources.Load(filename));
RecastBuilder builder = new RecastBuilder(); RcBuilder builder = new RcBuilder();
RcConfig cfg = new RcConfig( RcConfig cfg = new RcConfig(
true, m_tileSize, m_tileSize, RcConfig.CalcBorder(m_agentRadius, m_cellSize), true, m_tileSize, m_tileSize, RcConfig.CalcBorder(m_agentRadius, m_cellSize),
m_partitionType, m_partitionType,
@ -71,27 +71,27 @@ public class RecastTileMeshTest
m_detailSampleDist, m_detailSampleMaxError, m_detailSampleDist, m_detailSampleMaxError,
true, true, true, true, true, true,
SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true); SampleAreaModifications.SAMPLE_AREAMOD_GROUND, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8); RcBuilderConfig bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 7, 8);
RecastBuilderResult rcResult = builder.Build(geom, bcfg); RcBuilderResult rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 6, 9);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(7));
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 9);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(2));
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(9));
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 4, 3);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(3));
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(6));
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 2, 8);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(5));
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(17));
bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8); bcfg = new RcBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), 0, 8);
rcResult = builder.Build(geom, bcfg); rcResult = builder.Build(geom, bcfg);
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(6));
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(15));
@ -101,7 +101,7 @@ public class RecastTileMeshTest
public void TestPerformance() public void TestPerformance()
{ {
IInputGeomProvider geom = ObjImporter.Load(RcResources.Load("dungeon.obj")); IInputGeomProvider geom = ObjImporter.Load(RcResources.Load("dungeon.obj"));
RecastBuilder builder = new RecastBuilder(); RcBuilder builder = new RcBuilder();
RcConfig cfg = new RcConfig( RcConfig cfg = new RcConfig(
true, m_tileSize, m_tileSize, true, m_tileSize, m_tileSize,
RcConfig.CalcBorder(m_agentRadius, m_cellSize), RcConfig.CalcBorder(m_agentRadius, m_cellSize),
@ -137,14 +137,14 @@ public class RecastTileMeshTest
Console.WriteLine(" Time MT : " + (t3 - t2) / TimeSpan.TicksPerMillisecond); Console.WriteLine(" Time MT : " + (t3 - t2) / TimeSpan.TicksPerMillisecond);
} }
private void Build(IInputGeomProvider geom, RecastBuilder builder, RcConfig cfg, int threads, bool validate) private void Build(IInputGeomProvider geom, RcBuilder builder, RcConfig cfg, int threads, bool validate)
{ {
CancellationTokenSource cts = new CancellationTokenSource(); CancellationTokenSource cts = new CancellationTokenSource();
List<RecastBuilderResult> tiles = new(); List<RcBuilderResult> tiles = new();
var task = builder.BuildTilesAsync(geom, cfg, threads, tiles, Task.Factory, cts.Token); var task = builder.BuildTilesAsync(geom, cfg, threads, tiles, Task.Factory, cts.Token);
if (validate) if (validate)
{ {
RecastBuilderResult rcResult = GetTile(tiles, 7, 8); RcBuilderResult rcResult = GetTile(tiles, 7, 8);
Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1)); Assert.That(rcResult.GetMesh().npolys, Is.EqualTo(1));
Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5)); Assert.That(rcResult.GetMesh().nverts, Is.EqualTo(5));
rcResult = GetTile(tiles, 6, 9); rcResult = GetTile(tiles, 6, 9);
@ -175,7 +175,7 @@ public class RecastTileMeshTest
} }
} }
private RecastBuilderResult GetTile(List<RecastBuilderResult> tiles, int x, int z) private RcBuilderResult GetTile(List<RcBuilderResult> tiles, int x, int z)
{ {
return tiles.FirstOrDefault(tile => tile.tileX == x && tile.tileZ == z); return tiles.FirstOrDefault(tile => tile.tileX == x && tile.tileZ == z);
} }