Files
CypherCore/Source/Framework/RecastDetour/Recast/Recast.cs
T
Fabian a3dc7b3f48 Ported .Net Core commits:
hondacrx:
- Initial commit: Switch to .Net Core 2.0
- Fix build and removed not needed files
Fabi:
- Updated solution platforms.
- Changed folder structure.
- Change library target framework to netstandard2.0.
- Updated solution platforms again...
- Removed windows specific kernel32 function usage (Ctrl-C handler).
2017-10-26 17:23:44 +02:00

1693 lines
77 KiB
C#

using System;
using System.Diagnostics;
using System.IO;
using System.Text;
public static partial class Recast {
/// The value of PI used by Recast.
public const float RC_PI = 3.14159265f;
/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax.
public const int RC_SPAN_HEIGHT_BITS = 13;
/// Defines the maximum value for rcSpan::smin and rcSpan::smax.
public const int RC_SPAN_MAX_HEIGHT = (1 << RC_SPAN_HEIGHT_BITS) - 1;
/// Recast log categories.
/// @see rcContext
public enum rcLogCategory {
RC_LOG_PROGRESS = 1, //< A progress log entry.
RC_LOG_WARNING, //< A warning log entry.
RC_LOG_ERROR, //< An error log entry.
};
/// Recast performance timer categories.
/// @see rcContext
public enum rcTimerLabel {
/// The user defined total time of the build.
RC_TIMER_TOTAL,
/// A user defined build time.
RC_TIMER_TEMP,
/// The time to rasterize the triangles. (See: #rcRasterizeTriangle)
RC_TIMER_RASTERIZE_TRIANGLES,
/// The time to build the compact heightfield. (See: #rcBuildCompactHeightfield)
RC_TIMER_BUILD_COMPACTHEIGHTFIELD,
/// The total time to build the contours. (See: #rcBuildContours)
RC_TIMER_BUILD_CONTOURS,
/// The time to trace the boundaries of the contours. (See: #rcBuildContours)
RC_TIMER_BUILD_CONTOURS_TRACE,
/// The time to simplify the contours. (See: #rcBuildContours)
RC_TIMER_BUILD_CONTOURS_SIMPLIFY,
/// The time to filter ledge spans. (See: #rcFilterLedgeSpans)
RC_TIMER_FILTER_BORDER,
/// The time to filter low height spans. (See: #rcFilterWalkableLowHeightSpans)
RC_TIMER_FILTER_WALKABLE,
/// The time to apply the median filter. (See: #rcMedianFilterWalkableArea)
RC_TIMER_MEDIAN_AREA,
/// The time to filter low obstacles. (See: #rcFilterLowHangingWalkableObstacles)
RC_TIMER_FILTER_LOW_OBSTACLES,
/// The time to build the polygon mesh. (See: #rcBuildPolyMesh)
RC_TIMER_BUILD_POLYMESH,
/// The time to merge polygon meshes. (See: #rcMergePolyMeshes)
RC_TIMER_MERGE_POLYMESH,
/// The time to erode the walkable area. (See: #rcErodeWalkableArea)
RC_TIMER_ERODE_AREA,
/// The time to mark a box area. (See: #rcMarkBoxArea)
RC_TIMER_MARK_BOX_AREA,
/// The time to mark a cylinder area. (See: #rcMarkCylinderArea)
RC_TIMER_MARK_CYLINDER_AREA,
/// The time to mark a convex polygon area. (See: #rcMarkConvexPolyArea)
RC_TIMER_MARK_CONVEXPOLY_AREA,
/// The total time to build the distance field. (See: #rcBuildDistanceField)
RC_TIMER_BUILD_DISTANCEFIELD,
/// The time to build the distances of the distance field. (See: #rcBuildDistanceField)
RC_TIMER_BUILD_DISTANCEFIELD_DIST,
/// The time to blur the distance field. (See: #rcBuildDistanceField)
RC_TIMER_BUILD_DISTANCEFIELD_BLUR,
/// The total time to build the regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone)
RC_TIMER_BUILD_REGIONS,
/// The total time to apply the watershed algorithm. (See: #rcBuildRegions)
RC_TIMER_BUILD_REGIONS_WATERSHED,
/// The time to expand regions while applying the watershed algorithm. (See: #rcBuildRegions)
RC_TIMER_BUILD_REGIONS_EXPAND,
/// The time to flood regions while applying the watershed algorithm. (See: #rcBuildRegions)
RC_TIMER_BUILD_REGIONS_FLOOD,
/// The time to filter out small regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone)
RC_TIMER_BUILD_REGIONS_FILTER,
/// The time to build heightfield layers. (See: #rcBuildHeightfieldLayers)
RC_TIMER_BUILD_LAYERS,
/// The time to build the polygon mesh detail. (See: #rcBuildPolyMeshDetail)
RC_TIMER_BUILD_POLYMESHDETAIL,
/// The time to merge polygon mesh details. (See: #rcMergePolyMeshDetails)
RC_TIMER_MERGE_POLYMESHDETAIL,
/// The maximum number of timers. (Used for iterating timers.)
RC_MAX_TIMERS
};
public static void rcCalcBounds(float[] verts, int nv, float[] bmin, float[] bmax) {
// Calculate bounding box.
rcVcopy(bmin, verts);
rcVcopy(bmax, verts);
for (int i = 1; i < nv; ++i) {
int vStart = i * 3;
rcVmin(bmin, 0, verts, vStart);
rcVmax(bmax, 0, verts, vStart);
}
}
public static void rcCalcGridSize(float[] bmin, float[] bmax, float cs, out int w, out int h) {
w = (int)((bmax[0] - bmin[0]) / cs + 0.5f);
h = (int)((bmax[2] - bmin[2]) / cs + 0.5f);
}
/// @par
///
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcAllocHeightfield, rcHeightfield
public static bool rcCreateHeightfield(rcContext ctx, rcHeightfield hf, int width, int height,
float[] bmin, float[] bmax,
float cs, float ch) {
rcIgnoreUnused(ctx);
hf.width = width;
hf.height = height;
rcVcopy(hf.bmin, bmin);
rcVcopy(hf.bmax, bmax);
hf.cs = cs;
hf.ch = ch;
hf.spans = new rcSpan[hf.width * hf.height];//(rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM);
if (hf.spans == null)
return false;
//memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height);
return true;
}
public static void calcTriNormal(float[] v0, float[] v1, float[] v2, float[] norm) {
float[] e0 = new float[3];
float[] e1 = new float[3];
rcVsub(e0, v1, v0);
rcVsub(e1, v2, v0);
rcVcross(norm, e0, e1);
rcVnormalize(norm);
}
public static void calcTriNormal(float[] v0, int v0Start, float[] v1, int v1Start, float[] v2, int v2Start, float[] norm) {
float[] e0 = new float[3];
float[] e1 = new float[3];
rcVsub(e0, 0, v1, v1Start, v0, v0Start);
rcVsub(e1, 0, v2, v2Start, v0, v0Start);
rcVcross(norm, 0, e0, 0, e1, 0);
rcVnormalize(norm);
}
/// @par
///
/// Only sets the aread id's for the walkable triangles. Does not alter the
/// area id's for unwalkable triangles.
///
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
public static void rcMarkWalkableTriangles(rcContext ctx, float walkableSlopeAngle,
float[] verts, int nv,
int[] tris, int nt,
byte[] areas) {
rcIgnoreUnused(ctx);
float walkableThr = (float)Math.Cos(walkableSlopeAngle / 180.0f * RC_PI);
float[] norm = new float[3];
for (int i = 0; i < nt; ++i) {
int triStart = i * 3;
calcTriNormal(verts, tris[triStart + 0] * 3, verts, tris[triStart + 1] * 3, verts, tris[triStart + 2] * 3, norm);
// Check if the face is walkable.
if (norm[1] > walkableThr)
areas[i] = RC_WALKABLE_AREA;
}
}
/// @par
///
/// Only sets the aread id's for the unwalkable triangles. Does not alter the
/// area id's for walkable triangles.
///
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
public static void rcClearUnwalkableTriangles(rcContext ctx, float walkableSlopeAngle,
float[] verts, int nv,
int[] tris, int nt,
byte[] areas) {
rcIgnoreUnused(ctx);
float walkableThr = (float)Math.Cos(walkableSlopeAngle / 180.0f * RC_PI);
float[] norm = new float[3];
for (int i = 0; i < nt; ++i) {
int triStart = i * 3;
calcTriNormal(verts, tris[triStart + 0] * 3, verts, tris[triStart + 1] * 3, verts, tris[triStart + 2] * 3, norm);
// Check if the face is walkable.
if (norm[1] <= walkableThr)
areas[i] = RC_NULL_AREA;
}
}
public static int rcGetHeightFieldSpanCount(rcContext ctx, rcHeightfield hf) {
rcIgnoreUnused(ctx);
int w = hf.width;
int h = hf.height;
int spanCount = 0;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
for (rcSpan s = hf.spans[x + y * w]; s != null; s = s.next) {
if (s.area != RC_NULL_AREA)
spanCount++;
}
}
}
return spanCount;
}
public static void rccsArrayItemsCreate<T>(T[] array) where T : class, new() {
for (int i = 0; i < array.Length; ++i) {
array[i] = new T();
}
}
/// @par
///
/// This is just the beginning of the process of fully building a compact heightfield.
/// Various filters may be applied applied, then the distance field and regions built.
/// E.g: #rcBuildDistanceField and #rcBuildRegions
///
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
public static bool rcBuildCompactHeightfield(rcContext ctx, int walkableHeight, int walkableClimb,
rcHeightfield hf, rcCompactHeightfield chf) {
Debug.Assert(ctx != null, "rcBuildCompactHeightfield Assert(ctx != null)");
ctx.startTimer(rcTimerLabel.RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
int w = hf.width;
int h = hf.height;
int spanCount = rcGetHeightFieldSpanCount(ctx, hf);
// Fill in header.
chf.width = w;
chf.height = h;
chf.spanCount = spanCount;
chf.walkableHeight = walkableHeight;
chf.walkableClimb = walkableClimb;
chf.maxRegions = 0;
rcVcopy(chf.bmin, hf.bmin);
rcVcopy(chf.bmax, hf.bmax);
chf.bmax[1] += walkableHeight * hf.ch;
chf.cs = hf.cs;
chf.ch = hf.ch;
chf.cells = new rcCompactCell[w * h];
//chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM);
if (chf.cells == null) {
ctx.log(rcLogCategory.RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (" + (w * h) + ")");
return false;
}
chf.spans = new rcCompactSpan[spanCount];// (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM);
if (chf.spans == null) {
ctx.log(rcLogCategory.RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (" + spanCount + ")");
return false;
}
chf.areas = new byte[spanCount]; //(byte*)rcAlloc(sizeof(byte)*spanCount, RC_ALLOC_PERM);
if (chf.areas == null) {
ctx.log(rcLogCategory.RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (" + spanCount + ")"); ;
return false;
}
int MAX_HEIGHT = 0xffff;
// Fill in cells and spans.
int idx = 0;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
rcSpan s = hf.spans[x + y * w];
// If there are no spans at this cell, just leave the data to index=0, count=0.
if (s == null) {
continue;
}
rcCompactCell c;// = chf.cells[x + y * w];
c.index = (uint)idx;
c.count = 0;
while (s != null) {
if (s.area != RC_NULL_AREA) {
int bot = (int)s.smax;
int top = s.next != null ? (int)s.next.smin : MAX_HEIGHT;
chf.spans[idx].y = (ushort)rcClamp(bot, 0, 0xffff);
chf.spans[idx].h = (byte)rcClamp(top - bot, 0, 0xff);
chf.areas[idx] = s.area;
idx++;
c.count++;
}
s = s.next;
}
chf.cells[x + y * w] = c;
}
}
// Find neighbour connections.
int MAX_LAYERS = RC_NOT_CONNECTED - 1;
int tooHighNeighbour = 0;
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
rcCompactCell c = chf.cells[x + y * w];
for (int i = (int)c.index, ni = (int)(c.index + c.count); i < ni; ++i) {
rcCompactSpan s = chf.spans[i];
for (int dir = 0; dir < 4; ++dir) {
rcSetCon(ref s, dir, RC_NOT_CONNECTED);
int nx = x + rcGetDirOffsetX(dir);
int ny = y + rcGetDirOffsetY(dir);
// First check that the neighbour cell is in bounds.
if (nx < 0 || ny < 0 || nx >= w || ny >= h)
continue;
// Iterate over all neighbour spans and check if any of the is
// accessible from current cell.
rcCompactCell nc = chf.cells[nx + ny * w];
for (int k = (int)nc.index, nk = (int)(nc.index + nc.count); k < nk; ++k) {
rcCompactSpan ns = chf.spans[k];
int bot = Math.Max(s.y, ns.y);
int top = Math.Min(s.y + s.h, ns.y + ns.h);
// Check that the gap between the spans is walkable,
// and that the climb height between the gaps is not too high.
if ((top - bot) >= walkableHeight && Math.Abs((int)ns.y - (int)s.y) <= walkableClimb) {
// Mark direction as walkable.
int lidx = k - (int)nc.index;
if (lidx < 0 || lidx > MAX_LAYERS) {
tooHighNeighbour = Math.Max(tooHighNeighbour, lidx);
continue;
}
rcSetCon(ref s, dir, lidx);
break;
}
}
}
chf.spans[i] = s;
}
}
}
if (tooHighNeighbour > MAX_LAYERS) {
ctx.log(rcLogCategory.RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers " + tooHighNeighbour + " (max: " + MAX_LAYERS + ")");
}
ctx.stopTimer(rcTimerLabel.RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
return true;
}
/*
static int getHeightfieldMemoryUsage(const rcHeightfield& hf)
{
int size = 0;
size += sizeof(hf);
size += hf.width * hf.height * sizeof(rcSpan*);
rcSpanPool* pool = hf.pools;
while (pool)
{
size += (sizeof(rcSpanPool) - sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL;
pool = pool.next;
}
return size;
}
static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf)
{
int size = 0;
size += sizeof(rcCompactHeightfield);
size += sizeof(rcCompactSpan) * chf.spanCount;
size += sizeof(rcCompactCell) * chf.width * chf.height;
return size;
}
*/
/// @class rcContext
/// @par
///
/// This class does not provide logging or timer functionality on its
/// own. Both must be provided by a concrete implementation
/// by overriding the protected member functions. Also, this class does not
/// provide an interface for extracting log messages. (Only adding them.)
/// So concrete implementations must provide one.
///
/// If no logging or timers are required, just pass an instance of this
/// class through the Recast build process.
///
/// @par
///
/// Example:
/// @code
/// // Where ctx is an instance of rcContext and filepath is a char array.
/// ctx.log(rcLogCategory.RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath);
/// @endcode
/// Provides an interface for optional logging and performance tracking of the Recast
/// build process.
/// @ingroup recast
public class rcContext {
/// True if logging is enabled.
bool m_logEnabled = true;
/// True if the performance timers are enabled.
bool m_timerEnabled = true;
/// Contructor.
/// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true]
public rcContext(bool state = true) {
m_logEnabled = state;
m_timerEnabled = state;
}
/// Enables or disables logging.
/// @param[in] state TRUE if logging should be enabled.
public void enableLog(bool state) {
m_logEnabled = state;
}
/// Clears all log entries.
public void resetLog() {
if (m_logEnabled) {
doResetLog();
}
}
/// Logs a message.
/// @param[in] category The category of the message.
/// @param[in] message The message.
//public void log(rcLogCategory category, string message);
public void log(rcLogCategory category, string message) {
if (!m_logEnabled) {
return;
}
doLog(category, message);
}
/// Enables or disables the performance timers.
/// @param[in] state TRUE if timers should be enabled.
public void enableTimer(bool state) {
m_timerEnabled = state;
}
/// Clears all peformance timers. (Resets all to unused.)
public void resetTimers() {
if (m_timerEnabled) {
doResetTimers();
}
}
/// Starts the specified performance timer.
/// @param label The category of timer.
public void startTimer(rcTimerLabel label) {
if (m_timerEnabled) {
doStartTimer(label);
}
}
/// Stops the specified performance timer.
/// @param label The category of the timer.
public void stopTimer(rcTimerLabel label) {
if (m_timerEnabled) {
doStopTimer(label);
}
}
/// Returns the total accumulated time of the specified performance timer.
/// @param label The category of the timer.
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
public long getAccumulatedTime(rcTimerLabel label) {
return m_timerEnabled ? doGetAccumulatedTime(label) : -1;
}
public double getAccumulatedTimeHiResolution(rcTimerLabel label) {
return m_timerEnabled ? doGetAccumulatedTimeHiResolution(label) : -1.0;
}
/// Clears all log entries.
protected virtual void doResetLog() { }
/// Logs a message.
/// @param[in] category The category of the message.
/// @param[in] msg The formatted message.
protected virtual void doLog(rcLogCategory category, string msg) { //int len unnecessary because c# string
}
/// Clears all timers. (Resets all to unused.)
protected virtual void doResetTimers() {
}
/// Starts the specified performance timer.
/// @param[in] label The category of timer.
protected virtual void doStartTimer(rcTimerLabel label) {
}
/// Stops the specified performance timer.
/// @param[in] label The category of the timer.
protected virtual void doStopTimer(rcTimerLabel label) {
}
/// Returns the total accumulated time of the specified performance timer.
/// @param[in] label The category of the timer.
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
protected virtual long doGetAccumulatedTime(rcTimerLabel label) {
return -1;
}
//C# port: alternate return type to use high precision timer on platforms where it's available
/// Returns the total accumulated time of the specified performance timer.
/// @param[in] label The category of the timer.
/// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started.
protected virtual double doGetAccumulatedTimeHiResolution(rcTimerLabel label) {
return -1.0;
}
};
/// Specifies a configuration to use when performing Recast builds.
/// @ingroup recast
public class rcConfig {
/// The width of the field along the x-axis. [Limit: >= 0] [Units: vx]
public int width;
/// The height of the field along the z-axis. [Limit: >= 0] [Units: vx]
public int height;
/// The width/height size of tile's on the xz-plane. [Limit: >= 0] [Units: vx]
public int tileSize;
/// The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx]
public int borderSize;
/// The xz-plane cell size to use for fields. [Limit: > 0] [Units: wu]
public float cs;
/// The y-axis cell size to use for fields. [Limit: > 0] [Units: wu]
public float ch;
/// The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu]
public float[] bmin = new float[3];
/// The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]
public float[] bmax = new float[3];
/// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees]
public float walkableSlopeAngle;
/// Minimum floor to 'ceiling' height that will still allow the floor area to
/// be considered walkable. [Limit: >= 3] [Units: vx]
public int walkableHeight;
/// Maximum ledge height that is considered to still be traversable. [Limit: >=0] [Units: vx]
public int walkableClimb;
/// The distance to erode/shrink the walkable area of the heightfield away from
/// obstructions. [Limit: >=0] [Units: vx]
public int walkableRadius;
/// The maximum allowed length for contour edges along the border of the mesh. [Limit: >=0] [Units: vx]
public int maxEdgeLen;
/// The maximum distance a simplfied contour's border edges should deviate
/// the original raw contour. [Limit: >=0] [Units: vx]
public float maxSimplificationError;
/// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx]
public int minRegionArea;
/// Any regions with a span count smaller than this value will, if possible,
/// be merged with larger regions. [Limit: >=0] [Units: vx]
public int mergeRegionArea;
/// The maximum number of vertices allowed for polygons generated during the
/// contour to polygon conversion process. [Limit: >= 3]
public int maxVertsPerPoly;
/// Sets the sampling distance to use when generating the detail mesh.
/// (For height detail only.) [Limits: 0 or >= 0.9] [Units: wu]
public float detailSampleDist;
/// The maximum distance the detail mesh surface should deviate from heightfield
/// data. (For height detail only.) [Limit: >=0] [Units: wu]
public float detailSampleMaxError;
};
/// Represents a span in a heightfield.
/// @see rcHeightfield
public class rcSpan {
public ushort smin;// : 13; //< The lower limit of the span. [Limit: < #smax]
public ushort smax;// : 13; //< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT]
public byte area;// : 6; //< The area id assigned to the span.
public rcSpan next = null; //< The next span higher up in column.
}
// A memory pool used for quick allocation of spans within a heightfield.
// @see rcHeightfield
public class rcSpanPool {
public rcSpanPool next = null; //< The next span pool.
public rcSpan[] items = new rcSpan[RC_SPANS_PER_POOL]; //< Array of spans in the pool.
///
public rcSpanPool() {
for (int i = 0; i < items.Length; ++i) {
items[i] = new rcSpan();
}
}
};
/// A dynamic heightfield representing obstructed space.
/// @ingroup recast
public class rcHeightfield {
public int width; //< The width of the heightfield. (Along the x-axis in cell units.)
public int height; //< The height of the heightfield. (Along the z-axis in cell units.)
public float[] bmin = new float[3]; //< The minimum bounds in world space. [(x, y, z)]
public float[] bmax = new float[3]; //< The maximum bounds in world space. [(x, y, z)]
public float cs; //< The size of each cell. (On the xz-plane.)
public float ch; //< The height of each cell. (The minimum increment along the y-axis.)
public rcSpan[] spans = null;//** //< Heightfield of spans (width*height).
public rcSpanPool pools = null; //< Linked list of span pools.
public rcSpan freelist = null; //< The next free span.
};
/// Provides information on the content of a cell column in a compact heightfield.
public struct rcCompactCell {
public uint index;// : 24; //< Index to the first span in the column.
public ushort count;// : 8; //< Number of spans in the column.
};
/// Represents a span of unobstructed space within a compact heightfield.
public struct rcCompactSpan {
public ushort y; //< The lower extent of the span. (Measured from the heightfield's base.)
public ushort reg; //< The id of the region the span belongs to. (Or zero if not in a region.)
public uint con;// : 24; //< Packed neighbor connection data.
public ushort h;// : 8; //< The height of the span. (Measured from #y.)
};
/// A compact, static heightfield representing unobstructed space.
/// @ingroup recast
public class rcCompactHeightfield {
public int width; //< The width of the heightfield. (Along the x-axis in cell units.)
public int height; //< The height of the heightfield. (Along the z-axis in cell units.)
public int spanCount; //< The number of spans in the heightfield.
public int walkableHeight; //< The walkable height used during the build of the field. (See: rcConfig::walkableHeight)
public int walkableClimb; //< The walkable climb used during the build of the field. (See: rcConfig::walkableClimb)
public int borderSize; //< The AABB border size used during the build of the field. (See: rcConfig::borderSize)
public ushort maxDistance; //< The maximum distance value of any span within the field.
public ushort maxRegions; //< The maximum region id of any span within the field.
public float[] bmin = new float[3]; //< The minimum bounds in world space. [(x, y, z)]
public float[] bmax = new float[3]; //< The maximum bounds in world space. [(x, y, z)]
public float cs; //< The size of each cell. (On the xz-plane.)
public float ch; //< The height of each cell. (The minimum increment along the y-axis.)
public rcCompactCell[] cells = null; //< Array of cells. [Size: #width*#height]
public rcCompactSpan[] spans = null; //< Array of spans. [Size: #spanCount]
public ushort[] dist = null; //< Array containing border distance data. [Size: #spanCount]
public byte[] areas = null; //< Array containing area id data. [Size: #spanCount]
};
/// Represents a heightfield layer within a layer set.
/// @see rcHeightfieldLayerSet
public class rcHeightfieldLayer {
public float[] bmin = new float[3]; //< The minimum bounds in world space. [(x, y, z)]
public float[] bmax = new float[3]; //< The maximum bounds in world space. [(x, y, z)]
public float cs; //< The size of each cell. (On the xz-plane.)
public float ch; //< The height of each cell. (The minimum increment along the y-axis.)
public int width; //< The width of the heightfield. (Along the x-axis in cell units.)
public int height; //< The height of the heightfield. (Along the z-axis in cell units.)
public int minx; //< The minimum x-bounds of usable data.
public int maxx; //< The maximum x-bounds of usable data.
public int miny; //< The minimum y-bounds of usable data. (Along the z-axis.)
public int maxy; //< The maximum y-bounds of usable data. (Along the z-axis.)
public int hmin; //< The minimum height bounds of usable data. (Along the y-axis.)
public int hmax; //< The maximum height bounds of usable data. (Along the y-axis.)
public byte[] heights; //< The heightfield. [Size: (width - borderSize*2) * (h - borderSize*2)]
public byte[] areas; //< Area ids. [Size: Same as #heights]
public byte[] cons; //< Packed neighbor connection information. [Size: Same as #heights]
};
/// Represents a set of heightfield layers.
/// @ingroup recast
/// @see rcAllocHeightfieldLayerSet, rcFreeHeightfieldLayerSet
public class rcHeightfieldLayerSet {
public rcHeightfieldLayer[] layers = null; //< The layers in the set. [Size: #nlayers]
public int nlayers; //< The number of layers in the set.
};
/// Represents a simple, non-overlapping contour in field space.
public struct rcContour {
public int[] verts; //< Simplified contour vertex and connection data. [Size: 4 * #nverts]
public int nverts; //< The number of vertices in the simplified contour.
public int[] rverts; //< Raw contour vertex and connection data. [Size: 4 * #nrverts]
public int nrverts; //< The number of vertices in the raw contour.
public ushort reg; //< The region id of the contour.
public byte area; //< The area id of the contour.
///
public void dumpToTxt(StreamWriter stream) {
stream.WriteLine("\treg: " + reg);
stream.WriteLine("\tarea: " + area);
stream.WriteLine("\tnverts: " + nverts);
for (int i = 0; i < nverts; ++i) {
int vIndex = i * 4;
stream.WriteLine("\t\tverts[" + i + "]: x:" + verts[vIndex] + " y:" + verts[vIndex + 1] + " z:" + verts[vIndex + 2] + " ?:" + verts[vIndex + 3]);
}
stream.WriteLine("\tnrverts: " + nrverts);
for (int i = 0; i < nrverts; ++i) {
int vIndex = i * 4;
stream.WriteLine("\t\trverts[" + i + "]: x:" + rverts[vIndex] + " y:" + rverts[vIndex + 1] + " z:" + rverts[vIndex + 2] + " ?:" + rverts[vIndex + 3]);
}
}
public string dumpToString() {
StringBuilder sb = new StringBuilder();
sb.AppendLine("\treg: " + reg);
sb.AppendLine("\tarea: " + area);
sb.AppendLine("\tnverts: " + nverts);
for (int i = 0; i < nverts; ++i) {
int vIndex = i * 4;
sb.AppendLine("\t\tverts[" + i + "]: x:" + verts[vIndex] + " y:" + verts[vIndex + 1] + " z:" + verts[vIndex + 2] + " ?:" + verts[vIndex + 3]);
}
sb.AppendLine("\tnrverts: " + nrverts);
for (int i = 0; i < nrverts; ++i) {
int vIndex = i * 4;
sb.AppendLine("\t\trverts[" + i + "]: x:" + rverts[vIndex] + " y:" + rverts[vIndex + 1] + " z:" + rverts[vIndex + 2] + " ?:" + rverts[vIndex + 3]);
}
return sb.ToString();
}
};
/// Represents a group of related contours.
/// @ingroup recast
public class rcContourSet {
public rcContour[] conts = null; //< An array of the contours in the set. [Size: #nconts]
public int nconts; //< The number of contours in the set.
public float[] bmin = new float[3]; //< The minimum bounds in world space. [(x, y, z)]
public float[] bmax = new float[3]; //< The maximum bounds in world space. [(x, y, z)]
public float cs; //< The size of each cell. (On the xz-plane.)
public float ch; //< The height of each cell. (The minimum increment along the y-axis.)
public int width; //< The width of the set. (Along the x-axis in cell units.)
public int height; //< The height of the set. (Along the z-axis in cell units.)
public int borderSize; //< The AABB border size used to generate the source data from which the contours were derived.
///
public override string ToString() {
StringBuilder sb = new StringBuilder();
sb.AppendLine("nconts: " + nconts);
sb.AppendLine("bmin: " + bmin[0] + " " + bmin[1] + " " + bmin[2]);
sb.AppendLine("bmax: " + bmax[0] + " " + bmax[1] + " " + bmax[2]);
sb.AppendLine("cs: " + cs);
sb.AppendLine("ch: " + ch);
sb.AppendLine("width: " + width);
sb.AppendLine("height: " + height);
sb.AppendLine("bordersize: " + borderSize);
for (int i = 0; i < nconts; ++i) {
sb.Append("contour[" + i + "]: ");
sb.AppendLine(conts[i].ToString());
}
return sb.ToString();
}
};
/// Represents a polygon mesh suitable for use in building a navigation mesh.
/// @ingroup recast
public class rcPolyMesh {
public ushort[] verts = null; //< The mesh vertices. [Form: (x, y, z) * #nverts]
public ushort[] polys = null; //< Polygon and neighbor data. [Length: #maxpolys * 2 * #nvp]
public ushort[] regs = null; //< The region id assigned to each polygon. [Length: #maxpolys]
public ushort[] flags = null; //< The user defined flags for each polygon. [Length: #maxpolys]
public byte[] areas = null; //< The area id assigned to each polygon. [Length: #maxpolys]
public int nverts; //< The number of vertices.
public int npolys; //< The number of polygons.
public int maxpolys; //< The number of allocated polygons.
public int nvp; //< The maximum number of vertices per polygon.
public float[] bmin = new float[3]; //< The minimum bounds in world space. [(x, y, z)]
public float[] bmax = new float[3]; //< The maximum bounds in world space. [(x, y, z)]
public float cs; //< The size of each cell. (On the xz-plane.)
public float ch; //< The height of each cell. (The minimum increment along the y-axis.)
public int borderSize; //< The AABB border size used to generate the source data from which the mesh was derived.
///
public override string ToString() {
StringBuilder sb = new StringBuilder();
sb.AppendLine("bmin: " + bmin[0] + " " + bmin[1] + " " + bmin[2]);
sb.AppendLine("bmax: " + bmax[0] + " " + bmax[1] + " " + bmax[2]);
sb.AppendLine("cs: " + cs);
sb.AppendLine("ch: " + ch);
sb.AppendLine("bordersize: " + borderSize);
sb.AppendLine("nverts: " + nverts);
for (int i = 0; i < nverts; ++i) {
int vIndex = i * 3;
sb.AppendLine("\tverts[" + i + "]: x:" + verts[vIndex] + " y:" + verts[vIndex + 1] + " z:" + verts[vIndex + 2]);
}
sb.AppendLine("\tmaxpolys: " + maxpolys);
sb.AppendLine("\tnvp: " + nvp);
sb.AppendLine("\tnpolys: " + npolys);
for (int i = 0; i < maxpolys; ++i) {
int vIndex = i * nvp;
sb.Append("\t\tpolys[" + i + "]: ");
for (int j = 0; j < nvp; ++j) {
sb.Append(" " + j + ":" + polys[vIndex + j]);
}
vIndex += nvp;
sb.AppendLine();
sb.Append("\t\tneighbor[" + i + "]: ");
for (int j = 0; j < nvp; ++j) {
sb.Append(" " + j + ":" + polys[vIndex + j]);
}
sb.AppendLine();
}
for (int i = 0; i < maxpolys; ++i) {
sb.AppendLine("regs[" + i + "]: " + regs[i]);
}
sb.AppendLine();
for (int i = 0; i < flags.Length; ++i) {
sb.AppendLine("flags[" + i + "]: " + flags[i]);
}
return sb.ToString();
}
public string ToObj(){
StringBuilder sb = new StringBuilder();
sb.AppendLine("# Recast Navmesh");
sb.AppendLine("o NavMesh");
sb.AppendLine();
for (int i = 0; i < nverts; ++i) {
//ushort* v = &pmesh.verts[i*3];
int vIndex = i * 3;
float x = bmin[0] + verts[vIndex + 0] * cs;
float y = bmin[1] + (verts[vIndex + 1] + 1) * ch + 0.1f;
float z = bmin[2] + verts[vIndex + 2] * cs;
//ioprintf(io, "v %f %f %f\n", x,y,z);
sb.AppendLine("v " + x + " " + y + " " + z);
}
sb.AppendLine();
for (int i = 0; i < npolys; ++i) {
//const unsigned short* p = &pmesh.polys[i*nvp*2];
int pIndex = i * nvp * 2;
for (int j = 2; j < nvp; ++j) {
if (polys[pIndex + j] == RC_MESH_NULL_IDX)
break;
//ioprintf(io, "f %d %d %d\n", p[0]+1, p[j-1]+1, p[j]+1);
int a = polys[pIndex] + 1;
int b = polys[pIndex + j - 1] + 1;
int c = polys[pIndex + j] + 1;
sb.AppendLine("f " + a + " " + b + " " + c);
}
}
return sb.ToString ();
}
};
/// Contains triangle meshes that represent detailed height data associated
/// with the polygons in its associated polygon mesh object.
/// @ingroup recast
public class rcPolyMeshDetail {
public uint[] meshes = null; //< The sub-mesh data. [Size: 4*#nmeshes]
public float[] verts = null; //< The mesh vertices. [Size: 3*#nverts]
public byte[] tris = null; //< The mesh triangles. [Size: 4*#ntris]
public int nmeshes; //< The number of sub-meshes defined by #meshes.
public int nverts; //< The number of vertices in #verts.
public int ntris; //< The number of triangles in #tris.
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("nmeshes: " + nmeshes);
for (int i = 0; i < nmeshes; ++i) {
int vIndex = i * 4;
sb.AppendLine("\tmeshes[" + i + "]: a:" + meshes[vIndex] + " b:" + meshes[vIndex + 1] + " c:" + meshes[vIndex + 2] + " d:" + meshes[vIndex + 3]);
}
sb.AppendLine("nverts: " + nverts);
for (int i = 0; i < nverts; ++i) {
int vIndex = i * 3;
sb.AppendLine("\tverts[" + i + "]: x:" + verts[vIndex] + " y:" + verts[vIndex + 1] + " z:" + verts[vIndex + 2]);
}
sb.AppendLine("ntris: " + ntris);
for (int i = 0; i < ntris; ++i) {
int vIndex = i * 4;
sb.AppendLine("\ttris[" + i + "]: a:" + tris[vIndex] + " b:" + tris[vIndex + 1] + " c:" + tris[vIndex + 2] + " d:" + tris[vIndex + 3]);
}
return sb.ToString();
}
public string ToObj()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("# Recast C# Navmesh\n");
sb.AppendLine("o NavMesh\n");
sb.AppendLine("\n");
for (int i = 0; i < nverts; ++i) {
int vIndex = i * 3;
sb.AppendLine("v " + verts[vIndex + 0] + " " + verts[vIndex + 1] + " " + verts[vIndex + 2]);
}
sb.AppendLine();
for (int i = 0; i < nmeshes; ++i) {
//uint* m = &dmesh.meshes[i*4];
int mIndex = i * 4;
uint bverts = meshes[mIndex + 0];
uint btris = meshes[mIndex + 2];
uint _ntris = meshes[mIndex + 3];
uint trisIndex = btris * 4;
for (uint j = 0; j < _ntris; ++j) {
sb.AppendLine("f "
+ ((int)(bverts + tris[trisIndex + j * 4 + 0]) + 1) + " "
+ ((int)(bverts + tris[trisIndex + j * 4 + 1]) + 1) + " "
+ ((int)(bverts + tris[trisIndex + j * 4 + 2]) + 1) + " ");
}
}
return sb.ToString();
}
};
/// @name Allocation Functions
/// Functions used to allocate and de-allocate Recast objects.
/// @see rcAllocSetCustom
/// @{
/// Allocates a heightfield object using the Recast allocator.
/// @return A heightfield that is ready for initialization, or null on failure.
/// @ingroup recast
/// @see rcCreateHeightfield, rcFreeHeightField
//rcHeightfield* rcAllocHeightfield();
/// Frees the specified heightfield object using the Recast allocator.
/// @param[in] hf A heightfield allocated using #rcAllocHeightfield
/// @ingroup recast
/// @see rcAllocHeightfield
//void rcFreeHeightField(rcHeightfield* hf);
/// Allocates a compact heightfield object using the Recast allocator.
/// @return A compact heightfield that is ready for initialization, or null on failure.
/// @ingroup recast
/// @see rcBuildCompactHeightfield, rcFreeCompactHeightfield
//rcCompactHeightfield* rcAllocCompactHeightfield();
/// Frees the specified compact heightfield object using the Recast allocator.
/// @param[in] chf A compact heightfield allocated using #rcAllocCompactHeightfield
/// @ingroup recast
/// @see rcAllocCompactHeightfield
//void rcFreeCompactHeightfield(rcCompactHeightfield* chf);
/// Allocates a heightfield layer set using the Recast allocator.
/// @return A heightfield layer set that is ready for initialization, or null on failure.
/// @ingroup recast
/// @see rcBuildHeightfieldLayers, rcFreeHeightfieldLayerSet
//rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet();
/// Frees the specified heightfield layer set using the Recast allocator.
/// @param[in] lset A heightfield layer set allocated using #rcAllocHeightfieldLayerSet
/// @ingroup recast
/// @see rcAllocHeightfieldLayerSet
//void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset);
/// Allocates a contour set object using the Recast allocator.
/// @return A contour set that is ready for initialization, or null on failure.
/// @ingroup recast
/// @see rcBuildContours, rcFreeContourSet
//rcContourSet* rcAllocContourSet();
/// Frees the specified contour set using the Recast allocator.
/// @param[in] cset A contour set allocated using #rcAllocContourSet
/// @ingroup recast
/// @see rcAllocContourSet
//void rcFreeContourSet(rcContourSet* cset);
/// Allocates a polygon mesh object using the Recast allocator.
/// @return A polygon mesh that is ready for initialization, or null on failure.
/// @ingroup recast
/// @see rcBuildPolyMesh, rcFreePolyMesh
//rcPolyMesh* rcAllocPolyMesh();
/// Frees the specified polygon mesh using the Recast allocator.
/// @param[in] pmesh A polygon mesh allocated using #rcAllocPolyMesh
/// @ingroup recast
/// @see rcAllocPolyMesh
//void rcFreePolyMesh(rcPolyMesh* pmesh);
/// Allocates a detail mesh object using the Recast allocator.
/// @return A detail mesh that is ready for initialization, or null on failure.
/// @ingroup recast
/// @see rcBuildPolyMeshDetail, rcFreePolyMeshDetail
//rcPolyMeshDetail* rcAllocPolyMeshDetail();
/// Frees the specified detail mesh using the Recast allocator.
/// @param[in] dmesh A detail mesh allocated using #rcAllocPolyMeshDetail
/// @ingroup recast
/// @see rcAllocPolyMeshDetail
//void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh);
/// The number of spans allocated per span spool.
/// @see rcSpanPool
public const int RC_SPANS_PER_POOL = 2048;
/// Heighfield border flag.
/// If a heightfield region ID has this bit set, then the region is a border
/// region and its spans are considered unwalkable.
/// (Used during the region and contour build process.)
/// @see rcCompactSpan::reg
public const ushort RC_BORDER_REG = 0x8000;
/// Border vertex flag.
/// If a region ID has this bit set, then the associated element lies on
/// a tile border. If a contour vertex's region ID has this bit set, the
/// vertex will later be removed in order to match the segments and vertices
/// at tile boundaries.
/// (Used during the build process.)
/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts
public const int RC_BORDER_VERTEX = 0x10000;
/// Area border flag.
/// If a region ID has this bit set, then the associated element lies on
/// the border of an area.
/// (Used during the region and contour build process.)
/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts
public const int RC_AREA_BORDER = 0x20000;
/// Contour build flags.
/// @see rcBuildContours
public enum rcBuildContoursFlags {
RC_CONTOUR_TESS_WALL_EDGES = 0x01, //< Tessellate solid (impassable) edges during contour simplification.
RC_CONTOUR_TESS_AREA_EDGES = 0x02, //< Tessellate edges between areas during contour simplification.
};
/// Applied to the region id field of contour vertices in order to extract the region id.
/// The region id field of a vertex may have several flags applied to it. So the
/// fields value can't be used directly.
/// @see rcContour::verts, rcContour::rverts
public const int RC_CONTOUR_REG_MASK = 0xffff;
/// An value which indicates an invalid index within a mesh.
/// @note This does not necessarily indicate an error.
/// @see rcPolyMesh::polys
public const ushort RC_MESH_NULL_IDX = 0xffff;
/// Represents the null area.
/// When a data element is given this value it is considered to no longer be
/// assigned to a usable area. (E.g. It is unwalkable.)
public const byte RC_NULL_AREA = 0;
/// The default area id used to indicate a walkable polygon.
/// This is also the maximum allowed area id, and the only non-null area id
/// recognized by some steps in the build process.
public const byte RC_WALKABLE_AREA = 63;
/// The value returned by #rcGetCon if the specified direction is not connected
/// to another span. (Has no neighbor.)
public const int RC_NOT_CONNECTED = 0x3f;
/// @name General helper functions
/// @{
/// Used to ignore a function parameter. VS complains about unused parameters
/// and this silences the warning.
/// @param [in] _ Unused parameter
public static void rcIgnoreUnused<T>(T t) { }
//Use C# for this kind of things
/// Swaps the values of the two parameters.
/// @param[in,out] a Value A
/// @param[in,out] b Value B
//public void rcSwap<T>(T a, T b) { T t = a; a = b; b = t; }
static void rcSwap<T>(ref T lhs, ref T rhs) {
T temp = lhs;
lhs = rhs;
rhs = temp;
}
/// Returns the minimum of two values.
/// @param[in] a Value A
/// @param[in] b Value B
/// @return The minimum of the two values.
//public T Math.Min<T>(T a, T b) {
// return a < b ? a : b;
//}
/// Returns the maximum of two values.
/// @param[in] a Value A
/// @param[in] b Value B
/// @return The maximum of the two values.
//template<class T> inline T Math.Max(T a, T b) { return a > b ? a : b; }
/// Returns the absolute value.
/// @param[in] a The value.
/// @return The absolute value of the specified value.
//template<class T> inline T rcAbs(T a) { return a < 0 ? -a : a; }
/// Returns the square of the value.
/// @param[in] a The value.
/// @return The square of the value.
//template<class T> inline T rcSqr(T a) { return a*a; }
/// Clamps the value to the specified range.
/// @param[in] v The value to clamp.
/// @param[in] mn The minimum permitted return value.
/// @param[in] mx The maximum permitted return value.
/// @return The value, clamped to the specified range.
//template<class T> inline T rcClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
public static int rcClamp(int v, int mn, int mx) {
return v < mn ? mn : (v > mx ? mx : v);
}
/// Returns the square root of the value.
/// @param[in] x The value.
/// @return The square root of the vlaue.
//float rcSqrt(float x);
/// @}
/// @name Vector helper functions.
/// @{
/// Derives the cross product of two vectors. (@p v1 x @p v2)
/// @param[out] dest The cross product. [(x, y, z)]
/// @param[in] v1 A Vector [(x, y, z)]
/// @param[in] v2 A vector [(x, y, z)]
public static void rcVcross(float[] dest, float[] v1, float[] v2) {
dest[0] = v1[1] * v2[2] - v1[2] * v2[1];
dest[1] = v1[2] * v2[0] - v1[0] * v2[2];
dest[2] = v1[0] * v2[1] - v1[1] * v2[0];
}
public static void rcVcross(float[] dest, int destStart, float[] v1, int v1Start, float[] v2, int v2Start) {
dest[destStart + 0] = v1[v1Start + 1] * v2[v2Start + 2] - v1[v1Start + 2] * v2[v2Start + 1];
dest[destStart + 1] = v1[v1Start + 2] * v2[v2Start + 0] - v1[v1Start + 0] * v2[v2Start + 2];
dest[destStart + 2] = v1[v1Start + 0] * v2[v2Start + 1] - v1[v1Start + 1] * v2[v2Start + 0];
}
/// Derives the dot product of two vectors. (@p v1 . @p v2)
/// @param[in] v1 A Vector [(x, y, z)]
/// @param[in] v2 A vector [(x, y, z)]
/// @return The dot product.
public static float rcVdot(float[] v1, float[] v2) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
/// @param[out] dest The result vector. [(x, y, z)]
/// @param[in] v1 The base vector. [(x, y, z)]
/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
/// @param[in] s The amount to scale @p v2 by before adding to @p v1.
public static void rcVmad(float[] dest, float[] v1, float[] v2, float s) {
dest[0] = v1[0] + v2[0] * s;
dest[1] = v1[1] + v2[1] * s;
dest[2] = v1[2] + v2[2] * s;
}
/// Performs a vector addition. (@p v1 + @p v2)
/// @param[out] dest The result vector. [(x, y, z)]
/// @param[in] v1 The base vector. [(x, y, z)]
/// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
public static void rcVadd(float[] dest, float[] v1, float[] v2) {
dest[0] = v1[0] + v2[0];
dest[1] = v1[1] + v2[1];
dest[2] = v1[2] + v2[2];
}
/// Performs a vector subtraction. (@p v1 - @p v2)
/// @param[out] dest The result vector. [(x, y, z)]
/// @param[in] v1 The base vector. [(x, y, z)]
/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
public static void rcVsub(float[] dest, float[] v1, float[] v2) {
dest[0] = v1[0] - v2[0];
dest[1] = v1[1] - v2[1];
dest[2] = v1[2] - v2[2];
}
public static void rcVsub(float[] dest, int destStart, float[] v1, int v1Start, float[] v2, int v2Start) {
dest[destStart + 0] = v1[v1Start + 0] - v2[v2Start + 0];
dest[destStart + 1] = v1[v1Start + 1] - v2[v2Start + 1];
dest[destStart + 2] = v1[v1Start + 2] - v2[v2Start + 2];
}
/// Selects the minimum value of each element from the specified vectors.
/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
/// @param[in] v A vector. [(x, y, z)]
public static void rcVmin(float[] mn, float[] v) {
mn[0] = Math.Min(mn[0], v[0]);
mn[1] = Math.Min(mn[1], v[1]);
mn[2] = Math.Min(mn[2], v[2]);
}
public static void rcVmin(float[] mn, int mnStart, float[] v, int vStart) {
mn[0 + mnStart] = Math.Min(mn[0 + mnStart], v[0 + vStart]);
mn[1 + mnStart] = Math.Min(mn[1 + mnStart], v[1 + vStart]);
mn[2 + mnStart] = Math.Min(mn[2 + mnStart], v[2 + vStart]);
}
/// Selects the maximum value of each element from the specified vectors.
/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
/// @param[in] v A vector. [(x, y, z)]
public static void rcVmax(float[] mx, float[] v) {
mx[0] = Math.Max(mx[0], v[0]);
mx[1] = Math.Max(mx[1], v[1]);
mx[2] = Math.Max(mx[2], v[2]);
}
public static void rcVmax(float[] mx, int mxStart, float[] v, int vStart) {
mx[0 + mxStart] = Math.Max(mx[0 + mxStart], v[0 + vStart]);
mx[1 + mxStart] = Math.Max(mx[1 + mxStart], v[1 + vStart]);
mx[2 + mxStart] = Math.Max(mx[2 + mxStart], v[2 + vStart]);
}
/// Performs a vector copy.
/// @param[out] dest The result. [(x, y, z)]
/// @param[in] v The vector to copy. [(x, y, z)]
public static void rcVcopy(float[] dest, float[] v) {
dest[0] = v[0];
dest[1] = v[1];
dest[2] = v[2];
}
public static void rcVcopy(float[] dest, int destStart, float[] v, int vStart) {
dest[destStart + 0] = v[vStart + 0];
dest[destStart + 1] = v[vStart + 1];
dest[destStart + 2] = v[vStart + 2];
}
/// Returns the distance between two points.
/// @param[in] v1 A point. [(x, y, z)]
/// @param[in] v2 A point. [(x, y, z)]
/// @return The distance between the two points.
public static float rcVdist(float[] v1, float[] v2) {
float dx = v2[0] - v1[0];
float dy = v2[1] - v1[1];
float dz = v2[2] - v1[2];
return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
}
/// Returns the square of the distance between two points.
/// @param[in] v1 A point. [(x, y, z)]
/// @param[in] v2 A point. [(x, y, z)]
/// @return The square of the distance between the two points.
public static float rcVdistSqr(float[] v1, float[] v2) {
float dx = v2[0] - v1[0];
float dy = v2[1] - v1[1];
float dz = v2[2] - v1[2];
return dx * dx + dy * dy + dz * dz;
}
/// Normalizes the vector.
/// @param[in,out] v The vector to normalize. [(x, y, z)]
public static void rcVnormalize(float[] v) {
float d = 1.0f / (float)Math.Sqrt((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2]));
v[0] *= d;
v[1] *= d;
v[2] *= d;
}
/// @}
/// @name Heightfield Functions
/// @see rcHeightfield
/// @{
/// Calculates the bounding box of an array of vertices.
/// @ingroup recast
/// @param[in] verts An array of vertices. [(x, y, z) * @p nv]
/// @param[in] nv The number of vertices in the @p verts array.
/// @param[out] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
/// @param[out] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
//void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax);
/// Calculates the grid size based on the bounding box and grid cell size.
/// @ingroup recast
/// @param[in] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
/// @param[in] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
/// @param[in] cs The xz-plane cell size. [Limit: > 0] [Units: wu]
/// @param[out] w The width along the x-axis. [Limit: >= 0] [Units: vx]
/// @param[out] h The height along the z-axis. [Limit: >= 0] [Units: vx]
//void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h);
/// Initializes a new heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in,out] hf The allocated heightfield to initialize.
/// @param[in] width The width of the field along the x-axis. [Limit: >= 0] [Units: vx]
/// @param[in] height The height of the field along the z-axis. [Limit: >= 0] [Units: vx]
/// @param[in] bmin The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu]
/// @param[in] bmax The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]
/// @param[in] cs The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu]
/// @param[in] ch The y-axis cell size to use for field. [Limit: > 0] [Units: wu]
//bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
// const float* bmin, const float* bmax,
// float cs, float ch);
/// Sets the area id of all triangles with a slope below the specified value
/// to #RC_WALKABLE_AREA.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable.
/// [Limits: 0 <= value < 90] [Units: Degrees]
/// @param[in] verts The vertices. [(x, y, z) * @p nv]
/// @param[in] nv The number of vertices.
/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
/// @param[in] nt The number of triangles.
/// @param[out] areas The triangle area ids. [Length: >= @p nt]
//void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv,
// const int* tris, int nt, byte* areas);
/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable.
/// [Limits: 0 <= value < 90] [Units: Degrees]
/// @param[in] verts The vertices. [(x, y, z) * @p nv]
/// @param[in] nv The number of vertices.
/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
/// @param[in] nt The number of triangles.
/// @param[out] areas The triangle area ids. [Length: >= @p nt]
//void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv,
//const int* tris, int nt, byte* areas);
/// Adds a span to the specified heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in,out] hf An initialized heightfield.
/// @param[in] x The width index where the span is to be added.
/// [Limits: 0 <= value < rcHeightfield::width]
/// @param[in] y The height index where the span is to be added.
/// [Limits: 0 <= value < rcHeightfield::height]
/// @param[in] smin The minimum height of the span. [Limit: < @p smax] [Units: vx]
/// @param[in] smax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx]
/// @param[in] area The area id of the span. [Limit: <= #RC_WALKABLE_AREA)
/// @param[in] flagMergeThr The merge theshold. [Limit: >= 0] [Units: vx]
//void rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
// const ushort smin, const ushort smax,
// const byte area, const int flagMergeThr);
/// Rasterizes a triangle into the specified heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] v0 Triangle vertex 0 [(x, y, z)]
/// @param[in] v1 Triangle vertex 1 [(x, y, z)]
/// @param[in] v2 Triangle vertex 2 [(x, y, z)]
/// @param[in] area The area id of the triangle. [Limit: <= #RC_WALKABLE_AREA]
/// @param[in,out] solid An initialized heightfield.
/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
/// [Limit: >= 0] [Units: vx]
//void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
// const byte area, rcHeightfield& solid,
// const int flagMergeThr = 1);
/// Rasterizes an indexed triangle mesh into the specified heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] verts The vertices. [(x, y, z) * @p nv]
/// @param[in] nv The number of vertices.
/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
/// @param[in] nt The number of triangles.
/// @param[in,out] solid An initialized heightfield.
/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
/// [Limit: >= 0] [Units: vx]
//void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
// const int* tris, const byte* areas, const int nt,
// rcHeightfield& solid, const int flagMergeThr = 1);
/// Rasterizes an indexed triangle mesh into the specified heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] verts The vertices. [(x, y, z) * @p nv]
/// @param[in] nv The number of vertices.
/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
/// @param[in] nt The number of triangles.
/// @param[in,out] solid An initialized heightfield.
/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
/// [Limit: >= 0] [Units: vx]
//void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
// const ushort* tris, const byte* areas, const int nt,
// rcHeightfield& solid, const int flagMergeThr = 1);
/// Rasterizes triangles into the specified heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] verts The triangle vertices. [(ax, ay, az, bx, by, bz, cx, by, cx) * @p nt]
/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
/// @param[in] nt The number of triangles.
/// @param[in,out] solid An initialized heightfield.
/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag.
/// [Limit: >= 0] [Units: vx]
//void rcRasterizeTriangles(rcContext* ctx, const float* verts, const byte* areas, const int nt,
// rcHeightfield& solid, const int flagMergeThr = 1);
/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimp of a walkable neihbor.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
/// [Limit: >=0] [Units: vx]
/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
//void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid);
/// Marks spans that are ledges as not-walkable.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to
/// be considered walkable. [Limit: >= 3] [Units: vx]
/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
/// [Limit: >=0] [Units: vx]
/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
//void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight,
// const int walkableClimb, rcHeightfield& solid);
/// Marks walkable spans as not walkable if the clearence above the span is less than the specified height.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to
/// be considered walkable. [Limit: >= 3] [Units: vx]
/// @param[in,out] solid A fully built heightfield. (All spans have been added.)
//void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid);
/// Returns the number of spans contained in the specified heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] hf An initialized heightfield.
/// @returns The number of spans in the heightfield.
//int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf);
/// @}
/// @name Compact Heightfield Functions
/// @see rcCompactHeightfield
/// @{
/// Builds a compact heightfield representing open space, from a heightfield representing solid space.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area
/// to be considered walkable. [Limit: >= 3] [Units: vx]
/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable.
/// [Limit: >=0] [Units: vx]
/// @param[in] hf The heightfield to be compacted.
/// @param[out] chf The resulting compact heightfield. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
//bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
// rcHeightfield& hf, rcCompactHeightfield& chf);
/// Erodes the walkable area within the heightfield by the specified radius.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] radius The radius of erosion. [Limits: 0 < value < 255] [Units: vx]
/// @param[in,out] chf The populated compact heightfield to erode.
/// @returns True if the operation completed successfully.
//bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf);
/// Applies a median filter to walkable area types (based on area id), removing noise.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in,out] chf A populated compact heightfield.
/// @returns True if the operation completed successfully.
//bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf);
/// Applies an area id to all spans within the specified bounding box. (AABB)
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] bmin The minimum of the bounding box. [(x, y, z)]
/// @param[in] bmax The maximum of the bounding box. [(x, y, z)]
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
/// @param[in,out] chf A populated compact heightfield.
//void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, byte areaId,
// rcCompactHeightfield& chf);
/// Applies the area id to the all spans within the specified convex polygon.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] verts The vertices of the polygon [Fomr: (x, y, z) * @p nverts]
/// @param[in] nverts The number of vertices in the polygon.
/// @param[in] hmin The height of the base of the polygon.
/// @param[in] hmax The height of the top of the polygon.
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
/// @param[in,out] chf A populated compact heightfield.
//void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts,
// const float hmin, const float hmax, byte areaId,
// rcCompactHeightfield& chf);
/// Helper function to offset voncex polygons for rcMarkConvexPolyArea.
/// @ingroup recast
/// @param[in] verts The vertices of the polygon [Form: (x, y, z) * @p nverts]
/// @param[in] nverts The number of vertices in the polygon.
/// @param[out] outVerts The offset vertices (should hold up to 2 * @p nverts) [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.
//int rcOffsetPoly(const float* verts, const int nverts, const float offset,
// float* outVerts, const int maxOutVerts);
/// Applies the area id to all spans within the specified cylinder.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] pos The center of the base of the cylinder. [Form: (x, y, z)]
/// @param[in] r The radius of the cylinder.
/// @param[in] h The height of the cylinder.
/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA]
/// @param[in,out] chf A populated compact heightfield.
//void rcMarkCylinderArea(rcContext* ctx, const float* pos,
// const float r, const float h, byte areaId,
// rcCompactHeightfield& chf);
/// Builds the distance field for the specified compact heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in,out] chf A populated compact heightfield.
/// @returns True if the operation completed successfully.
//bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf);
/// Builds region data for the heightfield using watershed partitioning.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in,out] chf A populated compact heightfield.
/// @param[in] borderSize The size of the non-navigable border around the heightfield.
/// [Limit: >=0] [Units: vx]
/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas.
/// [Limit: >=0] [Units: vx].
/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible,
/// be merged with larger regions. [Limit: >=0] [Units: vx]
/// @returns True if the operation completed successfully.
//bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
// const int borderSize, const int minRegionArea, const int mergeRegionArea);
/// Builds region data for the heightfield using simple monotone partitioning.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in,out] chf A populated compact heightfield.
/// @param[in] borderSize The size of the non-navigable border around the heightfield.
/// [Limit: >=0] [Units: vx]
/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas.
/// [Limit: >=0] [Units: vx].
/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible,
/// be merged with larger regions. [Limit: >=0] [Units: vx]
/// @returns True if the operation completed successfully.
//bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
// const int borderSize, const int minRegionArea, const int mergeRegionArea);
/// Sets the neighbor connection data for the specified direction.
/// @param[in] s The span to update.
/// @param[in] dir The direction to set. [Limits: 0 <= value < 4]
/// @param[in] i The index of the neighbor span.
public static void rcSetCon(ref rcCompactSpan s, int dir, int i) {
uint udir = (uint)dir;
int shift = (int)(udir * 6);
uint con = s.con;
s.con = (uint)(con & ~(0x3f << shift)) | (((uint)i & 0x3f) << shift);
}
/// Gets neighbor connection data for the specified direction.
/// @param[in] s The span to check.
/// @param[in] dir 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 rcGetCon(rcCompactSpan s, int dir) {
uint udir = (uint)dir;
int shift = (int)(udir * 6);
return (int)((s.con >> shift) & 0x3f);
}
/// Gets the standard width (x-axis) offset for the specified direction.
/// @param[in] dir 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 rcGetDirOffsetX(int dir) {
int[] offset = new int[] { -1, 0, 1, 0, };
return offset[dir & 0x03];
}
/// Gets the standard height (z-axis) offset for the specified direction.
/// @param[in] dir 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 rcGetDirOffsetY(int dir) {
int[] offset = new int[] { 0, 1, 0, -1 };
return offset[dir & 0x03];
}
/// @}
/// @name Layer, Contour, Polymesh, and Detail Mesh Functions
/// @see rcHeightfieldLayer, rcContourSet, rcPolyMesh, rcPolyMeshDetail
/// @{
/// Builds a layer set from the specified compact heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] chf A fully built compact heightfield.
/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0]
/// [Units: vx]
/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area
/// to be considered walkable. [Limit: >= 3] [Units: vx]
/// @param[out] lset The resulting layer set. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
//bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
// const int borderSize, const int walkableHeight,
// rcHeightfieldLayerSet& lset);
/// Builds a contour set from the region outlines in the provided compact heightfield.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] chf A fully built compact heightfield.
/// @param[in] maxError The maximum distance a simplfied contour's border edges should deviate
/// the original raw contour. [Limit: >=0] [Units: wu]
/// @param[in] maxEdgeLen The maximum allowed length for contour edges along the border of the mesh.
/// [Limit: >=0] [Units: vx]
/// @param[out] cset The resulting contour set. (Must be pre-allocated.)
/// @param[in] buildFlags The build flags. (See: #rcBuildContoursFlags)
/// @returns True if the operation completed successfully.
//bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
// const float maxError, const int maxEdgeLen,
// rcContourSet& cset, const int flags = RC_CONTOUR_TESS_WALL_EDGES);
/// Builds a polygon mesh from the provided contours.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] cset A fully built contour set.
/// @param[in] nvp The maximum number of vertices allowed for polygons generated during the
/// contour to polygon conversion process. [Limit: >= 3]
/// @param[out] mesh The resulting polygon mesh. (Must be re-allocated.)
/// @returns True if the operation completed successfully.
//bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh);
/// Merges multiple polygon meshes into a single mesh.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] meshes An array of polygon meshes to merge. [Size: @p nmeshes]
/// @param[in] nmeshes The number of polygon meshes in the meshes array.
/// @param[in] mesh The resulting polygon mesh. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
//bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh);
/// Builds a detail mesh from the provided polygon mesh.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] mesh A fully built polygon mesh.
/// @param[in] chf The compact heightfield used to build the polygon mesh.
/// @param[in] sampleDist Sets the distance to use when samping the heightfield. [Limit: >=0] [Units: wu]
/// @param[in] sampleMaxError The maximum distance the detail mesh surface should deviate from
/// heightfield data. [Limit: >=0] [Units: wu]
/// @param[out] dmesh The resulting detail mesh. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
//bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf,
// const float sampleDist, const float sampleMaxError,
// rcPolyMeshDetail& dmesh);
/// Copies the poly mesh data from src to dst.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] src The source mesh to copy from.
/// @param[out] dst The resulting detail mesh. (Must be pre-allocated, must be empty mesh.)
/// @returns True if the operation completed successfully.
//bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst);
/// Merges multiple detail meshes into a single detail mesh.
/// @ingroup recast
/// @param[in,out] ctx The build context to use during the operation.
/// @param[in] meshes An array of detail meshes to merge. [Size: @p nmeshes]
/// @param[in] nmeshes The number of detail meshes in the meshes array.
/// @param[out] mesh The resulting detail mesh. (Must be pre-allocated.)
/// @returns True if the operation completed successfully.
//bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh);
/// @}
}
///////////////////////////////////////////////////////////////////////////
// Due to the large amount of detail documentation for this file,
// the content normally located at the end of the header file has been separated
// out to a file in /Docs/Extern.