forked from mirror/DotRecast
Compare commits
2 Commits
master
...
pr/merged-
Author | SHA1 | Date |
---|---|---|
Gabriel Alexandre | 23405ea5a7 | |
Gabriel Alexandre | 70c9adeb2f |
|
@ -99,7 +99,7 @@ namespace DotRecast.Detour.Dynamic
|
||||||
config.maxEdgeLen, config.maxSimplificationError,
|
config.maxEdgeLen, config.maxSimplificationError,
|
||||||
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, default, true);
|
||||||
RcBuilderResult 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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,7 +61,15 @@ namespace DotRecast.Recast.Toolset.Builder
|
||||||
|
|
||||||
public static RcAreaModification OfValue(int value)
|
public static RcAreaModification OfValue(int value)
|
||||||
{
|
{
|
||||||
return Values.FirstOrDefault(x => x.Value == value) ?? SAMPLE_AREAMOD_GRASS;
|
foreach(var v in Values)
|
||||||
|
{
|
||||||
|
if(v.Value == value)
|
||||||
|
{
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SAMPLE_AREAMOD_GRASS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@ freely, subject to the following restrictions:
|
||||||
|
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
public class RcAreaModification
|
public readonly struct RcAreaModification
|
||||||
{
|
{
|
||||||
public const int RC_AREA_FLAGS_MASK = 0x3F;
|
public const int RC_AREA_FLAGS_MASK = 0x3F;
|
||||||
|
|
||||||
|
@ -58,12 +58,12 @@ namespace DotRecast.Recast
|
||||||
Mask = other.Mask;
|
Mask = other.Mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetMaskedValue()
|
public readonly int GetMaskedValue()
|
||||||
{
|
{
|
||||||
return Value & Mask;
|
return Value & Mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Apply(int area)
|
public readonly int Apply(int area)
|
||||||
{
|
{
|
||||||
return ((Value & Mask) | (area & ~Mask));
|
return ((Value & Mask) | (area & ~Mask));
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,20 +218,10 @@ 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.
|
||||||
RcRegions.BuildDistanceField(ctx, chf);
|
RcRegions.BuildDistanceField(ctx, chf);
|
||||||
// Partition the walkable surface into simple regions without holes.
|
|
||||||
RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
|
|
||||||
}
|
}
|
||||||
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.
|
RcRegions.BuildRegions(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea, RcPartitionType.OfValue(cfg.Partition));
|
||||||
RcRegions.BuildRegionsMonotone(ctx, chf, cfg.MinRegionArea, cfg.MergeRegionArea);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Partition the walkable surface into simple regions without holes.
|
|
||||||
RcRegions.BuildLayerRegions(ctx, chf, cfg.MinRegionArea);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Step 5. Trace and simplify region contours.
|
// Step 5. Trace and simplify region contours.
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace DotRecast.Recast
|
||||||
/// @param[in] span The span to update.
|
/// @param[in] span The span to update.
|
||||||
/// @param[in] direction The direction to set. [Limits: 0 <= value < 4]
|
/// @param[in] direction The direction to set. [Limits: 0 <= value < 4]
|
||||||
/// @param[in] neighborIndex The index of the neighbor span.
|
/// @param[in] neighborIndex The index of the neighbor span.
|
||||||
public static void SetCon(RcCompactSpan span, int direction, int neighborIndex)
|
public static void SetCon(ref RcCompactSpan span, int direction, int neighborIndex)
|
||||||
{
|
{
|
||||||
int shift = direction * 6;
|
int shift = direction * 6;
|
||||||
int con = span.con;
|
int con = span.con;
|
||||||
|
|
|
@ -21,7 +21,7 @@ freely, subject to the following restrictions:
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
/** Represents a span of unobstructed space within a compact heightfield. */
|
/** Represents a span of unobstructed space within a compact heightfield. */
|
||||||
public class RcCompactSpan
|
public struct RcCompactSpan
|
||||||
{
|
{
|
||||||
/** The lower extent of the span. (Measured from the heightfield's base.) */
|
/** The lower extent of the span. (Measured from the heightfield's base.) */
|
||||||
public int y;
|
public int y;
|
||||||
|
|
|
@ -115,11 +115,11 @@ namespace DotRecast.Recast
|
||||||
RcCompactCell c = chf.cells[x + y * w];
|
RcCompactCell c = chf.cells[x + y * w];
|
||||||
for (int i = c.index, ni = c.index + c.count; i < ni; ++i)
|
for (int i = c.index, ni = c.index + c.count; i < ni; ++i)
|
||||||
{
|
{
|
||||||
RcCompactSpan s = chf.spans[i];
|
ref RcCompactSpan s = ref chf.spans[i];
|
||||||
|
|
||||||
for (int dir = 0; dir < 4; ++dir)
|
for (int dir = 0; dir < 4; ++dir)
|
||||||
{
|
{
|
||||||
SetCon(s, dir, RC_NOT_CONNECTED);
|
SetCon(ref s, dir, RC_NOT_CONNECTED);
|
||||||
int nx = x + GetDirOffsetX(dir);
|
int nx = x + GetDirOffsetX(dir);
|
||||||
int ny = y + 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.
|
||||||
|
@ -131,7 +131,7 @@ namespace DotRecast.Recast
|
||||||
RcCompactCell nc = chf.cells[nx + ny * w];
|
RcCompactCell nc = chf.cells[nx + ny * w];
|
||||||
for (int k = nc.index, nk = nc.index + nc.count; k < nk; ++k)
|
for (int k = nc.index, nk = nc.index + nc.count; k < nk; ++k)
|
||||||
{
|
{
|
||||||
RcCompactSpan ns = chf.spans[k];
|
ref RcCompactSpan ns = ref chf.spans[k];
|
||||||
int bot = Math.Max(s.y, ns.y);
|
int bot = Math.Max(s.y, ns.y);
|
||||||
int top = Math.Min(s.y + s.h, ns.y + ns.h);
|
int top = Math.Min(s.y + s.h, ns.y + ns.h);
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ namespace DotRecast.Recast
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCon(s, dir, lidx);
|
SetCon(ref s, dir, lidx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -632,10 +632,6 @@ namespace DotRecast.Recast
|
||||||
maxVerts += region.holes[i].contour.nverts;
|
maxVerts += region.holes[i].contour.nverts;
|
||||||
|
|
||||||
RcPotentialDiagonal[] diags = new RcPotentialDiagonal[maxVerts];
|
RcPotentialDiagonal[] diags = new RcPotentialDiagonal[maxVerts];
|
||||||
for (int pd = 0; pd < maxVerts; pd++)
|
|
||||||
{
|
|
||||||
diags[pd] = new RcPotentialDiagonal();
|
|
||||||
}
|
|
||||||
|
|
||||||
RcContour outline = region.outline;
|
RcContour outline = region.outline;
|
||||||
|
|
||||||
|
@ -664,8 +660,7 @@ namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
int dx = outline.verts[j * 4 + 0] - hole.verts[corner + 0];
|
int dx = outline.verts[j * 4 + 0] - hole.verts[corner + 0];
|
||||||
int dz = outline.verts[j * 4 + 2] - hole.verts[corner + 2];
|
int dz = outline.verts[j * 4 + 2] - hole.verts[corner + 2];
|
||||||
diags[ndiags].vert = j;
|
diags[ndiags] = new RcPotentialDiagonal(j, dx * dx + dz * dz);
|
||||||
diags[ndiags].dist = dx * dx + dz * dz;
|
|
||||||
ndiags++;
|
ndiags++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,6 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
public static class RcLayers
|
public static class RcLayers
|
||||||
{
|
{
|
||||||
const int RC_MAX_LAYERS = RcConstants.RC_NOT_CONNECTED;
|
|
||||||
const int RC_MAX_NEIS = 16;
|
|
||||||
|
|
||||||
|
|
||||||
private static void AddUnique(List<int> a, int v)
|
private static void AddUnique(List<int> a, int v)
|
||||||
{
|
{
|
||||||
if (!a.Contains(v))
|
if (!a.Contains(v))
|
||||||
|
@ -63,10 +59,6 @@ namespace DotRecast.Recast
|
||||||
Array.Fill(srcReg, 0xFF);
|
Array.Fill(srcReg, 0xFF);
|
||||||
int nsweeps = chf.width; // Math.Max(chf.width, chf.height);
|
int nsweeps = chf.width; // Math.Max(chf.width, chf.height);
|
||||||
RcSweepSpan[] sweeps = new RcSweepSpan[nsweeps];
|
RcSweepSpan[] sweeps = new RcSweepSpan[nsweeps];
|
||||||
for (int i = 0; i < sweeps.Length; i++)
|
|
||||||
{
|
|
||||||
sweeps[i] = new RcSweepSpan();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Partition walkable area into monotone regions.
|
// Partition walkable area into monotone regions.
|
||||||
int[] prevCount = new int[256];
|
int[] prevCount = new int[256];
|
||||||
|
@ -305,7 +297,7 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
int newId = ri.layerId;
|
int newId = ri.layerId;
|
||||||
|
|
||||||
for (;;)
|
while (true)
|
||||||
{
|
{
|
||||||
int oldId = 0xff;
|
int oldId = 0xff;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
public class RcPotentialDiagonal
|
public readonly struct RcPotentialDiagonal
|
||||||
{
|
{
|
||||||
public int dist;
|
public readonly int vert;
|
||||||
public int vert;
|
public readonly int dist;
|
||||||
|
|
||||||
|
public RcPotentialDiagonal(int vert, int dist)
|
||||||
|
{
|
||||||
|
this.vert = vert;
|
||||||
|
this.dist = dist;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1476,8 +1476,50 @@ namespace DotRecast.Recast
|
||||||
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||||
///
|
///
|
||||||
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
||||||
public static void BuildRegionsMonotone(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea,
|
public static void BuildRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea,
|
||||||
int mergeRegionArea)
|
int mergeRegionArea, RcPartition rcPartitiona)
|
||||||
|
{
|
||||||
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
||||||
|
|
||||||
|
int[] srcReg = new int[chf.spanCount];
|
||||||
|
|
||||||
|
if(rcPartitiona == RcPartition.WATERSHED)
|
||||||
|
{
|
||||||
|
BuildRegionsWatershed(ctx, chf, minRegionArea, mergeRegionArea, srcReg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BuildRegionsMonotoneOrLayered(ctx, chf, minRegionArea, mergeRegionArea, srcReg, rcPartitiona == RcPartition.LAYERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the result out.
|
||||||
|
for (int i = 0; i < chf.spanCount; ++i)
|
||||||
|
{
|
||||||
|
chf.spans[i].reg = srcReg[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour.
|
||||||
|
/// Contours will form simple polygons.
|
||||||
|
///
|
||||||
|
/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be
|
||||||
|
/// re-assigned to the zero (null) region.
|
||||||
|
///
|
||||||
|
/// Partitioning can result in smaller than necessary regions. @p mergeRegionArea helps
|
||||||
|
/// reduce unnecessarily small regions.
|
||||||
|
///
|
||||||
|
/// See the #rcConfig documentation for more information on the configuration parameters.
|
||||||
|
///
|
||||||
|
/// The region data will be available via the rcCompactHeightfield::maxRegions
|
||||||
|
/// and rcCompactSpan::reg fields.
|
||||||
|
///
|
||||||
|
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||||
|
///
|
||||||
|
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
||||||
|
private static void BuildRegionsMonotoneOrLayered(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea,
|
||||||
|
int mergeRegionArea, int[] srcReg, bool isLayered)
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
||||||
|
|
||||||
|
@ -1486,14 +1528,8 @@ namespace DotRecast.Recast
|
||||||
int borderSize = chf.borderSize;
|
int borderSize = chf.borderSize;
|
||||||
int id = 1;
|
int id = 1;
|
||||||
|
|
||||||
int[] srcReg = new int[chf.spanCount];
|
|
||||||
|
|
||||||
int nsweeps = Math.Max(chf.width, chf.height);
|
int nsweeps = Math.Max(chf.width, chf.height);
|
||||||
RcSweepSpan[] sweeps = new RcSweepSpan[nsweeps];
|
RcSweepSpan[] sweeps = new RcSweepSpan[nsweeps];
|
||||||
for (int i = 0; i < sweeps.Length; i++)
|
|
||||||
{
|
|
||||||
sweeps[i] = new RcSweepSpan();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark border regions.
|
// Mark border regions.
|
||||||
if (borderSize > 0)
|
if (borderSize > 0)
|
||||||
|
@ -1622,9 +1658,20 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
|
||||||
// Merge regions and filter out small regions.
|
// Merge regions and filter out small regions.
|
||||||
List<int> overlaps = new List<int>();
|
List<int> overlaps = new List<int>();
|
||||||
|
|
||||||
|
if (isLayered)
|
||||||
|
{
|
||||||
|
// Merge monotone regions to layers and remove small regions.
|
||||||
|
chf.maxRegions = MergeAndFilterLayerRegions(ctx, minRegionArea, id, chf, srcReg, overlaps);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Merge regions and filter out small regions.
|
||||||
chf.maxRegions = MergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, id, chf, srcReg, overlaps);
|
chf.maxRegions = MergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, id, chf, srcReg, overlaps);
|
||||||
|
}
|
||||||
|
|
||||||
// Monotone partitioning does not generate overlapping regions.
|
// Monotone partitioning does not generate overlapping regions.
|
||||||
ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
@ -1655,11 +1702,8 @@ namespace DotRecast.Recast
|
||||||
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
|
||||||
///
|
///
|
||||||
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
|
||||||
public static void BuildRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea,
|
private static void BuildRegionsWatershed(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea, int mergeRegionArea, int[] srcReg)
|
||||||
int mergeRegionArea)
|
|
||||||
{
|
{
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
|
||||||
|
|
||||||
int w = chf.width;
|
int w = chf.width;
|
||||||
int h = chf.height;
|
int h = chf.height;
|
||||||
int borderSize = chf.borderSize;
|
int borderSize = chf.borderSize;
|
||||||
|
@ -1676,7 +1720,6 @@ namespace DotRecast.Recast
|
||||||
|
|
||||||
List<int> stack = new List<int>(1024);
|
List<int> stack = new List<int>(1024);
|
||||||
|
|
||||||
int[] srcReg = new int[chf.spanCount];
|
|
||||||
int[] srcDist = new int[chf.spanCount];
|
int[] srcDist = new int[chf.spanCount];
|
||||||
|
|
||||||
int regionId = 1;
|
int regionId = 1;
|
||||||
|
@ -1770,170 +1813,6 @@ namespace DotRecast.Recast
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
||||||
|
|
||||||
// Write the result out.
|
|
||||||
for (int i = 0; i < chf.spanCount; ++i)
|
|
||||||
{
|
|
||||||
chf.spans[i].reg = srcReg[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void BuildLayerRegions(RcTelemetry ctx, RcCompactHeightfield chf, int minRegionArea)
|
|
||||||
{
|
|
||||||
using var timer = ctx.ScopedTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS);
|
|
||||||
|
|
||||||
int w = chf.width;
|
|
||||||
int h = chf.height;
|
|
||||||
int borderSize = chf.borderSize;
|
|
||||||
int id = 1;
|
|
||||||
|
|
||||||
int[] srcReg = new int[chf.spanCount];
|
|
||||||
int nsweeps = Math.Max(chf.width, chf.height);
|
|
||||||
RcSweepSpan[] sweeps = new RcSweepSpan[nsweeps];
|
|
||||||
for (int i = 0; i < sweeps.Length; i++)
|
|
||||||
{
|
|
||||||
sweeps[i] = new RcSweepSpan();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark border regions.
|
|
||||||
if (borderSize > 0)
|
|
||||||
{
|
|
||||||
// Make sure border will not overflow.
|
|
||||||
int bw = Math.Min(w, borderSize);
|
|
||||||
int bh = Math.Min(h, borderSize);
|
|
||||||
// Paint regions
|
|
||||||
PaintRectRegion(0, bw, 0, h, id | RC_BORDER_REG, chf, srcReg);
|
|
||||||
id++;
|
|
||||||
PaintRectRegion(w - bw, w, 0, h, id | RC_BORDER_REG, chf, srcReg);
|
|
||||||
id++;
|
|
||||||
PaintRectRegion(0, w, 0, bh, id | RC_BORDER_REG, chf, srcReg);
|
|
||||||
id++;
|
|
||||||
PaintRectRegion(0, w, h - bh, h, id | RC_BORDER_REG, chf, srcReg);
|
|
||||||
id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] prev = new int[1024];
|
|
||||||
|
|
||||||
// Sweep one line at a time.
|
|
||||||
for (int y = borderSize; y < h - borderSize; ++y)
|
|
||||||
{
|
|
||||||
// Collect spans from this row.
|
|
||||||
if (prev.Length <= id * 2)
|
|
||||||
{
|
|
||||||
prev = new int[id * 2];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Array.Fill(prev, 0, 0, (id) - (0));
|
|
||||||
}
|
|
||||||
|
|
||||||
int rid = 1;
|
|
||||||
|
|
||||||
for (int x = borderSize; x < w - borderSize; ++x)
|
|
||||||
{
|
|
||||||
RcCompactCell c = chf.cells[x + y * w];
|
|
||||||
|
|
||||||
for (int i = c.index, ni = c.index + c.count; i < ni; ++i)
|
|
||||||
{
|
|
||||||
RcCompactSpan s = chf.spans[i];
|
|
||||||
if (chf.areas[i] == RC_NULL_AREA)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -x
|
|
||||||
int previd = 0;
|
|
||||||
if (GetCon(s, 0) != RC_NOT_CONNECTED)
|
|
||||||
{
|
|
||||||
int ax = x + GetDirOffsetX(0);
|
|
||||||
int ay = y + GetDirOffsetY(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])
|
|
||||||
{
|
|
||||||
previd = srcReg[ai];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previd == 0)
|
|
||||||
{
|
|
||||||
previd = rid++;
|
|
||||||
sweeps[previd].rid = previd;
|
|
||||||
sweeps[previd].ns = 0;
|
|
||||||
sweeps[previd].nei = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -y
|
|
||||||
if (GetCon(s, 3) != RC_NOT_CONNECTED)
|
|
||||||
{
|
|
||||||
int ax = x + GetDirOffsetX(3);
|
|
||||||
int ay = y + GetDirOffsetY(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])
|
|
||||||
{
|
|
||||||
int nr = srcReg[ai];
|
|
||||||
if (sweeps[previd].nei == 0 || sweeps[previd].nei == nr)
|
|
||||||
{
|
|
||||||
sweeps[previd].nei = nr;
|
|
||||||
sweeps[previd].ns++;
|
|
||||||
if (prev.Length <= nr)
|
|
||||||
{
|
|
||||||
Array.Resize(ref prev, prev.Length * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
prev[nr]++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sweeps[previd].nei = RC_NULL_NEI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
srcReg[i] = previd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create unique ID.
|
|
||||||
for (int i = 1; i < rid; ++i)
|
|
||||||
{
|
|
||||||
if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 && prev[sweeps[i].nei] == sweeps[i].ns)
|
|
||||||
{
|
|
||||||
sweeps[i].id = sweeps[i].nei;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sweeps[i].id = id++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remap IDs
|
|
||||||
for (int x = borderSize; x < w - borderSize; ++x)
|
|
||||||
{
|
|
||||||
RcCompactCell c = chf.cells[x + y * w];
|
|
||||||
|
|
||||||
for (int i = c.index, ni = c.index + c.count; i < ni; ++i)
|
|
||||||
{
|
|
||||||
if (srcReg[i] > 0 && srcReg[i] < rid)
|
|
||||||
{
|
|
||||||
srcReg[i] = sweeps[srcReg[i]].id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.StartTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
|
||||||
|
|
||||||
// Merge monotone regions to layers and remove small regions.
|
|
||||||
List<int> overlaps = new List<int>();
|
|
||||||
chf.maxRegions = MergeAndFilterLayerRegions(ctx, minRegionArea, id, chf, srcReg, overlaps);
|
|
||||||
|
|
||||||
ctx.StopTimer(RcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER);
|
|
||||||
|
|
||||||
// Store the result out.
|
|
||||||
for (int i = 0; i < chf.spanCount; ++i)
|
|
||||||
{
|
|
||||||
chf.spans[i].reg = srcReg[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
namespace DotRecast.Recast
|
namespace DotRecast.Recast
|
||||||
{
|
{
|
||||||
public class RcSweepSpan
|
public struct RcSweepSpan
|
||||||
{
|
{
|
||||||
public int rid; // row id
|
public int rid; // row id
|
||||||
public int id; // region id
|
public int id; // region id
|
||||||
|
|
|
@ -217,20 +217,10 @@ 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.
|
||||||
RcRegions.BuildDistanceField(m_ctx, m_chf);
|
RcRegions.BuildDistanceField(m_ctx, m_chf);
|
||||||
// Partition the walkable surface into simple regions without holes.
|
|
||||||
RcRegions.BuildRegions(m_ctx, m_chf, cfg.MinRegionArea, cfg.MergeRegionArea);
|
|
||||||
}
|
}
|
||||||
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.
|
RcRegions.BuildRegions(m_ctx, m_chf, cfg.MinRegionArea, cfg.MergeRegionArea, RcPartitionType.OfValue(cfg.Partition));
|
||||||
RcRegions.BuildRegionsMonotone(m_ctx, m_chf, cfg.MinRegionArea, cfg.MergeRegionArea);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Partition the walkable surface into simple regions without holes.
|
|
||||||
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");
|
||||||
Assert.That(m_chf.maxRegions, Is.EqualTo(expRegions), "Regions");
|
Assert.That(m_chf.maxRegions, Is.EqualTo(expRegions), "Regions");
|
||||||
|
|
Loading…
Reference in New Issue