summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2023-05-22 14:47:42 +0200
committerRémi Verschelde <rverschelde@gmail.com>2023-05-22 14:47:42 +0200
commit2058b63067484a5ace4977731c0e040bd2cd9df9 (patch)
tree643ae8a9b97f3e8bfc4c8d6b6a339054e6cec7de
parent65fa775ff645e9ba1cb7fdc9cd8cb439bbbaae1a (diff)
downloadredot-engine-2058b63067484a5ace4977731c0e040bd2cd9df9.tar.gz
recast: Update to upstream version 1.6.0
Release notes: - https://github.com/recastnavigation/recastnavigation/releases/tag/v1.6.0
-rw-r--r--thirdparty/README.md2
-rw-r--r--thirdparty/recastnavigation/Recast/Include/Recast.h961
-rw-r--r--thirdparty/recastnavigation/Recast/Include/RecastAlloc.h29
-rw-r--r--thirdparty/recastnavigation/Recast/Include/RecastAssert.h13
-rw-r--r--thirdparty/recastnavigation/Recast/Source/Recast.cpp612
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastAlloc.cpp19
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastArea.cpp1
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastAssert.cpp2
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastContour.cpp11
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastFilter.cpp194
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastLayers.cpp20
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp5
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp1
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp658
-rw-r--r--thirdparty/recastnavigation/Recast/Source/RecastRegion.cpp1
15 files changed, 1353 insertions, 1176 deletions
diff --git a/thirdparty/README.md b/thirdparty/README.md
index b315d89f4e..6937d8125d 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -617,7 +617,7 @@ in 10.40, it can be found in the `patches` folder.
## recastnavigation
- Upstream: https://github.com/recastnavigation/recastnavigation
-- Version: git (4fef0446609b23d6ac180ed822817571525528a1, 2022)
+- Version: 1.6.0 (6dc1667f580357e8a2154c28b7867bea7e8ad3a7, 2023)
- License: zlib
Files extracted from upstream source:
diff --git a/thirdparty/recastnavigation/Recast/Include/Recast.h b/thirdparty/recastnavigation/Recast/Include/Recast.h
index 246376bbee..9def8fd2ae 100644
--- a/thirdparty/recastnavigation/Recast/Include/Recast.h
+++ b/thirdparty/recastnavigation/Recast/Include/Recast.h
@@ -100,11 +100,21 @@ enum rcTimerLabel
/// Provides an interface for optional logging and performance tracking of the Recast
/// build process.
+///
+/// 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.
+///
/// @ingroup recast
class rcContext
{
public:
- /// Contructor.
+ /// Constructor.
/// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true]
inline rcContext(bool state = true) : m_logEnabled(state), m_timerEnabled(state) {}
virtual ~rcContext() {}
@@ -117,28 +127,35 @@ public:
inline void resetLog() { if (m_logEnabled) doResetLog(); }
/// Logs a message.
- /// @param[in] category The category of the message.
- /// @param[in] format The message.
+ ///
+ /// Example:
+ /// @code
+ /// // Where ctx is an instance of rcContext and filepath is a char array.
+ /// ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath);
+ /// @endcode
+ ///
+ /// @param[in] category The category of the message.
+ /// @param[in] format The message.
void log(const rcLogCategory category, const char* format, ...);
/// Enables or disables the performance timers.
/// @param[in] state TRUE if timers should be enabled.
inline void enableTimer(bool state) { m_timerEnabled = state; }
- /// Clears all peformance timers. (Resets all to unused.)
+ /// Clears all performance timers. (Resets all to unused.)
inline void resetTimers() { if (m_timerEnabled) doResetTimers(); }
/// Starts the specified performance timer.
- /// @param label The category of the timer.
+ /// @param label The category of the timer.
inline void startTimer(const rcTimerLabel label) { if (m_timerEnabled) doStartTimer(label); }
/// Stops the specified performance timer.
- /// @param label The category of the timer.
+ /// @param label The category of the timer.
inline void stopTimer(const 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.
+ /// @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.
inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; }
protected:
@@ -146,25 +163,25 @@ protected:
virtual void doResetLog();
/// Logs a message.
- /// @param[in] category The category of the message.
- /// @param[in] msg The formatted message.
- /// @param[in] len The length of the formatted message.
+ /// @param[in] category The category of the message.
+ /// @param[in] msg The formatted message.
+ /// @param[in] len The length of the formatted message.
virtual void doLog(const rcLogCategory category, const char* msg, const int len) { rcIgnoreUnused(category); rcIgnoreUnused(msg); rcIgnoreUnused(len); }
/// Clears all timers. (Resets all to unused.)
virtual void doResetTimers() {}
/// Starts the specified performance timer.
- /// @param[in] label The category of timer.
+ /// @param[in] label The category of timer.
virtual void doStartTimer(const rcTimerLabel label) { rcIgnoreUnused(label); }
/// Stops the specified performance timer.
- /// @param[in] label The category of the timer.
+ /// @param[in] label The category of the timer.
virtual void doStopTimer(const rcTimerLabel label) { rcIgnoreUnused(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.
+ /// @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.
virtual int doGetAccumulatedTime(const rcTimerLabel label) const { rcIgnoreUnused(label); return -1; }
/// True if logging is enabled.
@@ -239,7 +256,7 @@ struct rcConfig
/// The maximum allowed length for contour edges along the border of the mesh. [Limit: >=0] [Units: vx]
int maxEdgeLen;
- /// The maximum distance a simplfied contour's border edges should deviate
+ /// The maximum distance a simplified contour's border edges should deviate
/// the original raw contour. [Limit: >=0] [Units: vx]
float maxSimplificationError;
@@ -335,6 +352,7 @@ struct rcCompactHeightfield
{
rcCompactHeightfield();
~rcCompactHeightfield();
+
int width; ///< The width of the heightfield. (Along the x-axis in cell units.)
int height; ///< The height of the heightfield. (Along the z-axis in cell units.)
int spanCount; ///< The number of spans in the heightfield.
@@ -351,6 +369,11 @@ struct rcCompactHeightfield
rcCompactSpan* spans; ///< Array of spans. [Size: #spanCount]
unsigned short* dist; ///< Array containing border distance data. [Size: #spanCount]
unsigned char* areas; ///< Array containing area id data. [Size: #spanCount]
+
+private:
+ // Explicitly-disabled copy constructor and copy assignment operator.
+ rcCompactHeightfield(const rcCompactHeightfield&);
+ rcCompactHeightfield& operator=(const rcCompactHeightfield&);
};
/// Represents a heightfield layer within a layer set.
@@ -381,8 +404,14 @@ struct rcHeightfieldLayerSet
{
rcHeightfieldLayerSet();
~rcHeightfieldLayerSet();
+
rcHeightfieldLayer* layers; ///< The layers in the set. [Size: #nlayers]
int nlayers; ///< The number of layers in the set.
+
+private:
+ // Explicitly-disabled copy constructor and copy assignment operator.
+ rcHeightfieldLayerSet(const rcHeightfieldLayerSet&);
+ rcHeightfieldLayerSet& operator=(const rcHeightfieldLayerSet&);
};
/// Represents a simple, non-overlapping contour in field space.
@@ -402,6 +431,7 @@ struct rcContourSet
{
rcContourSet();
~rcContourSet();
+
rcContour* conts; ///< An array of the contours in the set. [Size: #nconts]
int nconts; ///< The number of contours in the set.
float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)]
@@ -412,6 +442,11 @@ struct rcContourSet
int height; ///< The height of the set. (Along the z-axis in cell units.)
int borderSize; ///< The AABB border size used to generate the source data from which the contours were derived.
float maxError; ///< The max edge error that this contour set was simplified with.
+
+private:
+ // Explicitly-disabled copy constructor and copy assignment operator.
+ rcContourSet(const rcContourSet&);
+ rcContourSet& operator=(const rcContourSet&);
};
/// Represents a polygon mesh suitable for use in building a navigation mesh.
@@ -420,6 +455,7 @@ struct rcPolyMesh
{
rcPolyMesh();
~rcPolyMesh();
+
unsigned short* verts; ///< The mesh vertices. [Form: (x, y, z) * #nverts]
unsigned short* polys; ///< Polygon and neighbor data. [Length: #maxpolys * 2 * #nvp]
unsigned short* regs; ///< The region id assigned to each polygon. [Length: #maxpolys]
@@ -435,6 +471,11 @@ struct rcPolyMesh
float ch; ///< The height of each cell. (The minimum increment along the y-axis.)
int borderSize; ///< The AABB border size used to generate the source data from which the mesh was derived.
float maxEdgeError; ///< The max error of the polygon edges in the mesh.
+
+private:
+ // Explicitly-disabled copy constructor and copy assignment operator.
+ rcPolyMesh(const rcPolyMesh&);
+ rcPolyMesh& operator=(const rcPolyMesh&);
};
/// Contains triangle meshes that represent detailed height data associated
@@ -442,12 +483,19 @@ struct rcPolyMesh
/// @ingroup recast
struct rcPolyMeshDetail
{
+ rcPolyMeshDetail();
+
unsigned int* meshes; ///< The sub-mesh data. [Size: 4*#nmeshes]
float* verts; ///< The mesh vertices. [Size: 3*#nverts]
unsigned char* tris; ///< The mesh triangles. [Size: 4*#ntris]
int nmeshes; ///< The number of sub-meshes defined by #meshes.
int nverts; ///< The number of vertices in #verts.
int ntris; ///< The number of triangles in #tris.
+
+private:
+ // Explicitly-disabled copy constructor and copy assignment operator.
+ rcPolyMeshDetail(const rcPolyMeshDetail&);
+ rcPolyMeshDetail& operator=(const rcPolyMeshDetail&);
};
/// @name Allocation Functions
@@ -456,82 +504,82 @@ struct rcPolyMeshDetail
/// @{
/// 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
+/// @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);
+/// @param[in] heightfield A heightfield allocated using #rcAllocHeightfield
+/// @ingroup recast
+/// @see rcAllocHeightfield
+void rcFreeHeightField(rcHeightfield* heightfield);
/// 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
+/// @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);
+/// @param[in] compactHeightfield A compact heightfield allocated using #rcAllocCompactHeightfield
+/// @ingroup recast
+/// @see rcAllocCompactHeightfield
+void rcFreeCompactHeightfield(rcCompactHeightfield* compactHeightfield);
/// 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
+/// @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);
+/// @param[in] layerSet A heightfield layer set allocated using #rcAllocHeightfieldLayerSet
+/// @ingroup recast
+/// @see rcAllocHeightfieldLayerSet
+void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* layerSet);
/// 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
+/// @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);
+/// @param[in] contourSet A contour set allocated using #rcAllocContourSet
+/// @ingroup recast
+/// @see rcAllocContourSet
+void rcFreeContourSet(rcContourSet* contourSet);
/// 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
+/// @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);
+/// @param[in] polyMesh A polygon mesh allocated using #rcAllocPolyMesh
+/// @ingroup recast
+/// @see rcAllocPolyMesh
+void rcFreePolyMesh(rcPolyMesh* polyMesh);
/// 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
+/// @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);
+/// @param[in] detailMesh A detail mesh allocated using #rcAllocPolyMeshDetail
+/// @ingroup recast
+/// @see rcAllocPolyMeshDetail
+void rcFreePolyMeshDetail(rcPolyMeshDetail* detailMesh);
/// @}
-/// Heighfield border flag.
+/// Heightfield border flag.
/// If a heightfield region ID has this bit set, then the region is a border
-/// region and its spans are considered unwalkable.
+/// region and its spans are considered un-walkable.
/// (Used during the region and contour build process.)
/// @see rcCompactSpan::reg
static const unsigned short RC_BORDER_REG = 0x8000;
@@ -581,7 +629,7 @@ static const unsigned short 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.)
+/// assigned to a usable area. (E.g. It is un-walkable.)
static const unsigned char RC_NULL_AREA = 0;
/// The default area id used to indicate a walkable polygon.
@@ -597,38 +645,41 @@ static const int RC_NOT_CONNECTED = 0x3f;
/// @{
/// Swaps the values of the two parameters.
-/// @param[in,out] a Value A
-/// @param[in,out] b Value B
+/// @param[in,out] a Value A
+/// @param[in,out] b Value B
template<class T> inline void rcSwap(T& a, T& b) { T t = a; a = b; b = t; }
/// Returns the minimum of two values.
-/// @param[in] a Value A
-/// @param[in] b Value B
-/// @return The minimum of the two values.
+/// @param[in] a Value A
+/// @param[in] b Value B
+/// @return The minimum of the two values.
template<class T> inline T rcMin(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.
+/// @param[in] a Value A
+/// @param[in] b Value B
+/// @return The maximum of the two values.
template<class T> inline T rcMax(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.
+/// @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.
+/// @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); }
+/// @param[in] value The value to clamp.
+/// @param[in] minInclusive The minimum permitted return value.
+/// @param[in] maxInclusive The maximum permitted return value.
+/// @return The value, clamped to the specified range.
+template<class T> inline T rcClamp(T value, T minInclusive, T maxInclusive)
+{
+ return value < minInclusive ? minInclusive: (value > maxInclusive ? maxInclusive : value);
+}
/// Returns the square root of the value.
/// @param[in] x The value.
@@ -640,9 +691,9 @@ float rcSqrt(float x);
/// @{
/// 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)]
+/// @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)]
inline void rcVcross(float* dest, const float* v1, const float* v2)
{
dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
@@ -651,8 +702,8 @@ inline void rcVcross(float* dest, const float* v1, const float* v2)
}
/// 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)]
+/// @param[in] v1 A Vector [(x, y, z)]
+/// @param[in] v2 A vector [(x, y, z)]
/// @return The dot product.
inline float rcVdot(const float* v1, const float* v2)
{
@@ -660,10 +711,10 @@ inline float rcVdot(const float* v1, const float* v2)
}
/// 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.
+/// @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.
inline void rcVmad(float* dest, const float* v1, const float* v2, const float s)
{
dest[0] = v1[0]+v2[0]*s;
@@ -672,9 +723,9 @@ inline void rcVmad(float* dest, const float* v1, const float* v2, const float 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)]
+/// @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)]
inline void rcVadd(float* dest, const float* v1, const float* v2)
{
dest[0] = v1[0]+v2[0];
@@ -683,9 +734,9 @@ inline void rcVadd(float* dest, const float* v1, const float* v2)
}
/// 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)]
+/// @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)]
inline void rcVsub(float* dest, const float* v1, const float* v2)
{
dest[0] = v1[0]-v2[0];
@@ -694,8 +745,8 @@ inline void rcVsub(float* dest, const float* v1, const float* v2)
}
/// 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)]
+/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
+/// @param[in] v A vector. [(x, y, z)]
inline void rcVmin(float* mn, const float* v)
{
mn[0] = rcMin(mn[0], v[0]);
@@ -704,8 +755,8 @@ inline void rcVmin(float* mn, const float* v)
}
/// 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)]
+/// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
+/// @param[in] v A vector. [(x, y, z)]
inline void rcVmax(float* mx, const float* v)
{
mx[0] = rcMax(mx[0], v[0]);
@@ -714,8 +765,8 @@ inline void rcVmax(float* mx, const float* v)
}
/// Performs a vector copy.
-/// @param[out] dest The result. [(x, y, z)]
-/// @param[in] v The vector to copy. [(x, y, z)]
+/// @param[out] dest The result. [(x, y, z)]
+/// @param[in] v The vector to copy. [(x, y, z)]
inline void rcVcopy(float* dest, const float* v)
{
dest[0] = v[0];
@@ -724,8 +775,8 @@ inline void rcVcopy(float* dest, const float* v)
}
/// Returns the distance between two points.
-/// @param[in] v1 A point. [(x, y, z)]
-/// @param[in] v2 A point. [(x, y, z)]
+/// @param[in] v1 A point. [(x, y, z)]
+/// @param[in] v2 A point. [(x, y, z)]
/// @return The distance between the two points.
inline float rcVdist(const float* v1, const float* v2)
{
@@ -736,8 +787,8 @@ inline float rcVdist(const float* v1, const float* v2)
}
/// 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)]
+/// @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.
inline float rcVdistSqr(const float* v1, const float* v2)
{
@@ -748,7 +799,7 @@ inline float rcVdistSqr(const float* v1, const float* v2)
}
/// Normalizes the vector.
-/// @param[in,out] v The vector to normalize. [(x, y, z)]
+/// @param[in,out] v The vector to normalize. [(x, y, z)]
inline void rcVnormalize(float* v)
{
float d = 1.0f / rcSqrt(rcSqr(v[0]) + rcSqr(v[1]) + rcSqr(v[2]));
@@ -763,174 +814,249 @@ inline void rcVnormalize(float* v)
/// @{
/// 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);
+/// @ingroup recast
+/// @param[in] verts An array of vertices. [(x, y, z) * @p nv]
+/// @param[in] numVerts The number of vertices in the @p verts array.
+/// @param[out] minBounds The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
+/// @param[out] maxBounds The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
+void rcCalcBounds(const float* verts, int numVerts, float* minBounds, float* maxBounds);
/// 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);
+/// @ingroup recast
+/// @param[in] minBounds The minimum bounds of the AABB. [(x, y, z)] [Units: wu]
+/// @param[in] maxBounds The maximum bounds of the AABB. [(x, y, z)] [Units: wu]
+/// @param[in] cellSize The xz-plane cell size. [Limit: > 0] [Units: wu]
+/// @param[out] sizeX The width along the x-axis. [Limit: >= 0] [Units: vx]
+/// @param[out] sizeZ The height along the z-axis. [Limit: >= 0] [Units: vx]
+void rcCalcGridSize(const float* minBounds, const float* maxBounds, float cellSize, int* sizeX, int* sizeZ);
/// 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]
-/// @returns True if the operation completed successfully.
-bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
- const float* bmin, const float* bmax,
- float cs, float ch);
+/// See the #rcConfig documentation for more information on the configuration parameters.
+///
+/// @see rcAllocHeightfield, rcHeightfield
+/// @ingroup recast
+///
+/// @param[in,out] context The build context to use during the operation.
+/// @param[in,out] heightfield The allocated heightfield to initialize.
+/// @param[in] sizeX The width of the field along the x-axis. [Limit: >= 0] [Units: vx]
+/// @param[in] sizeZ The height of the field along the z-axis. [Limit: >= 0] [Units: vx]
+/// @param[in] minBounds The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu]
+/// @param[in] maxBounds The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu]
+/// @param[in] cellSize The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu]
+/// @param[in] cellHeight The y-axis cell size to use for field. [Limit: > 0] [Units: wu]
+/// @returns True if the operation completed successfully.
+bool rcCreateHeightfield(rcContext* context, rcHeightfield& heightfield, int sizeX, int sizeZ,
+ const float* minBounds, const float* maxBounds,
+ float cellSize, float cellHeight);
/// 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, unsigned char* areas);
+///
+/// Only sets the area id's for the walkable triangles. Does not alter the
+/// area id's for un-walkable triangles.
+///
+/// See the #rcConfig documentation for more information on the configuration parameters.
+///
+/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
+///
+/// @ingroup recast
+/// @param[in,out] context 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] numVerts The number of vertices.
+/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
+/// @param[in] numTris The number of triangles.
+/// @param[out] triAreaIDs The triangle area ids. [Length: >= @p nt]
+void rcMarkWalkableTriangles(rcContext* context, float walkableSlopeAngle, const float* verts, int numVerts,
+ const int* tris, int numTris, unsigned char* triAreaIDs);
/// 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, unsigned char* areas);
+///
+/// Only sets the area id's for the un-walkable 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
+///
+/// @ingroup recast
+/// @param[in,out] context 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] numVerts The number of vertices.
+/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt]
+/// @param[in] numTris The number of triangles.
+/// @param[out] triAreaIDs The triangle area ids. [Length: >= @p nt]
+void rcClearUnwalkableTriangles(rcContext* context, float walkableSlopeAngle, const float* verts, int numVerts,
+ const int* tris, int numTris, unsigned char* triAreaIDs);
/// 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]
-/// @returns True if the operation completed successfully.
-bool rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
- const unsigned short smin, const unsigned short smax,
- const unsigned char 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]
-/// @returns True if the operation completed successfully.
-bool rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
- const unsigned char area, rcHeightfield& solid,
- const int flagMergeThr = 1);
+///
+/// The span addition can be set to favor flags. If the span is merged to
+/// another span and the new @p spanMax is within @p flagMergeThreshold units
+/// from the existing span, the span flags are merged.
+///
+/// @ingroup recast
+/// @param[in,out] context The build context to use during the operation.
+/// @param[in,out] heightfield An initialized heightfield.
+/// @param[in] x The column x index where the span is to be added.
+/// [Limits: 0 <= value < rcHeightfield::width]
+/// @param[in] z The column z index where the span is to be added.
+/// [Limits: 0 <= value < rcHeightfield::height]
+/// @param[in] spanMin The minimum height of the span. [Limit: < @p spanMax] [Units: vx]
+/// @param[in] spanMax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx]
+/// @param[in] areaID The area id of the span. [Limit: <= #RC_WALKABLE_AREA)
+/// @param[in] flagMergeThreshold The merge threshold. [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcAddSpan(rcContext* context, rcHeightfield& heightfield,
+ int x, int z,
+ unsigned short spanMin, unsigned short spanMax,
+ unsigned char areaID, int flagMergeThreshold);
+
+/// Rasterizes a single triangle into the specified heightfield.
+///
+/// Calling this for each triangle in a mesh is less efficient than calling rcRasterizeTriangles
+///
+/// No spans will be added if the triangle does not overlap the heightfield grid.
+///
+/// @see rcHeightfield
+/// @ingroup recast
+/// @param[in,out] context 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] areaID The area id of the triangle. [Limit: <= #RC_WALKABLE_AREA]
+/// @param[in,out] heightfield An initialized heightfield.
+/// @param[in] flagMergeThreshold The distance where the walkable flag is favored over the non-walkable flag.
+/// [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcRasterizeTriangle(rcContext* context,
+ const float* v0, const float* v1, const float* v2,
+ unsigned char areaID, rcHeightfield& heightfield, int flagMergeThreshold = 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]
-/// @returns True if the operation completed successfully.
-bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
- const int* tris, const unsigned char* areas, const int nt,
- rcHeightfield& solid, const int flagMergeThr = 1);
+///
+/// Spans will only be added for triangles that overlap the heightfield grid.
+///
+/// @see rcHeightfield
+/// @ingroup recast
+/// @param[in,out] context The build context to use during the operation.
+/// @param[in] verts The vertices. [(x, y, z) * @p nv]
+/// @param[in] numVerts The number of vertices. (unused) TODO (graham): Remove in next major release
+/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
+/// @param[in] triAreaIDs The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
+/// @param[in] numTris The number of triangles.
+/// @param[in,out] heightfield An initialized heightfield.
+/// @param[in] flagMergeThreshold The distance where the walkable flag is favored over the non-walkable flag.
+/// [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcRasterizeTriangles(rcContext* context,
+ const float* verts, int numVerts,
+ const int* tris, const unsigned char* triAreaIDs, int numTris,
+ rcHeightfield& heightfield, int flagMergeThreshold = 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]
-/// @returns True if the operation completed successfully.
-bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv,
- const unsigned short* tris, const unsigned char* 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]
-/// @returns True if the operation completed successfully.
-bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* 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 neighbor.
-/// @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);
+///
+/// Spans will only be added for triangles that overlap the heightfield grid.
+///
+/// @see rcHeightfield
+/// @ingroup recast
+/// @param[in,out] context The build context to use during the operation.
+/// @param[in] verts The vertices. [(x, y, z) * @p nv]
+/// @param[in] numVerts The number of vertices. (unused) TODO (graham): Remove in next major release
+/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt]
+/// @param[in] triAreaIDs The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
+/// @param[in] numTris The number of triangles.
+/// @param[in,out] heightfield An initialized heightfield.
+/// @param[in] flagMergeThreshold The distance where the walkable flag is favored over the non-walkable flag.
+/// [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcRasterizeTriangles(rcContext* context,
+ const float* verts, int numVerts,
+ const unsigned short* tris, const unsigned char* triAreaIDs, int numTris,
+ rcHeightfield& heightfield, int flagMergeThreshold = 1);
+
+/// Rasterizes a triangle list into the specified heightfield.
+///
+/// Expects each triangle to be specified as three sequential vertices of 3 floats.
+///
+/// Spans will only be added for triangles that overlap the heightfield grid.
+///
+/// @see rcHeightfield
+/// @ingroup recast
+/// @param[in,out] context 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] triAreaIDs The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt]
+/// @param[in] numTris The number of triangles.
+/// @param[in,out] heightfield An initialized heightfield.
+/// @param[in] flagMergeThreshold The distance where the walkable flag is favored over the non-walkable flag.
+/// [Limit: >= 0] [Units: vx]
+/// @returns True if the operation completed successfully.
+bool rcRasterizeTriangles(rcContext* context,
+ const float* verts, const unsigned char* triAreaIDs, int numTris,
+ rcHeightfield& heightfield, int flagMergeThreshold = 1);
+
+/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimb of a walkable neighbor.
+///
+/// Allows the formation of walkable regions that will flow over low lying
+/// objects such as curbs, and up structures such as stairways.
+///
+/// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt>
+///
+/// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call
+/// #rcFilterLedgeSpans after calling this filter.
+///
+/// @see rcHeightfield, rcConfig
+///
+/// @ingroup recast
+/// @param[in,out] context 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] heightfield A fully built heightfield. (All spans have been added.)
+void rcFilterLowHangingWalkableObstacles(rcContext* context, int walkableClimb, rcHeightfield& heightfield);
+
+/// Marks spans that are ledges as not-walkable.
+///
+/// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb
+/// from the current span's maximum.
+/// This method removes the impact of the overestimation of conservative voxelization
+/// so the resulting mesh will not have regions hanging in the air over ledges.
+///
+/// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
+///
+/// @see rcHeightfield, rcConfig
+///
+/// @ingroup recast
+/// @param[in,out] context 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] heightfield A fully built heightfield. (All spans have been added.)
+void rcFilterLedgeSpans(rcContext* context, int walkableHeight, int walkableClimb, rcHeightfield& heightfield);
+
+/// Marks walkable spans as not walkable if the clearance above the span is less than the specified height.
+///
+/// For this filter, the clearance above the span is the distance from the span's
+/// maximum to the next higher span's minimum. (Same grid column.)
+///
+/// @see rcHeightfield, rcConfig
+/// @ingroup recast
+///
+/// @param[in,out] context 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] heightfield A fully built heightfield. (All spans have been added.)
+void rcFilterWalkableLowHeightSpans(rcContext* context, int walkableHeight, rcHeightfield& heightfield);
/// 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.
+/// @param[in,out] context The build context to use during the operation.
+/// @param[in] heightfield An initialized heightfield.
/// @returns The number of spans in the heightfield.
-int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf);
+int rcGetHeightFieldSpanCount(rcContext* context, const rcHeightfield& heightfield);
/// @}
/// @name Compact Heightfield Functions
@@ -938,176 +1064,181 @@ int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf);
/// @{
/// 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);
+///
+/// This is just the beginning of the process of fully building a compact heightfield.
+/// Various filters may be 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
+/// @ingroup recast
+///
+/// @param[in,out] context 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] heightfield The heightfield to be compacted.
+/// @param[out] compactHeightfield The resulting compact heightfield. (Must be pre-allocated.)
+/// @returns True if the operation completed successfully.
+bool rcBuildCompactHeightfield(rcContext* context, int walkableHeight, int walkableClimb,
+ const rcHeightfield& heightfield, rcCompactHeightfield& compactHeightfield);
/// 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.
+/// @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.
+/// @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.
+/// @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, unsigned char 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.
+/// @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, unsigned char 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[in] offset How much to offset the polygon by. [Units: wu]
-/// @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.
+/// @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[in] offset How much to offset the polygon by. [Units: wu]
+/// @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.
+/// @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, unsigned char 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.
+/// @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);
+/// @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, int borderSize, int minRegionArea, int mergeRegionArea);
/// Builds region data for the heightfield by partitioning the heightfield in non-overlapping layers.
-/// @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.
+/// @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.
+/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas.
/// [Limit: >=0] [Units: vx].
-/// @returns True if the operation completed successfully.
-bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
- const int borderSize, const int minRegionArea);
+/// @returns True if the operation completed successfully.
+bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf, int borderSize, int minRegionArea);
/// 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.
+/// @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.
+/// @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,
+/// @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.
+/// @returns True if the operation completed successfully.
bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
- const int borderSize, const int minRegionArea, const int mergeRegionArea);
+ int borderSize, int minRegionArea, 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.
-inline void rcSetCon(rcCompactSpan& s, int dir, int i)
+/// @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.
+inline void rcSetCon(rcCompactSpan& span, int direction, int neighborIndex)
{
- const unsigned int shift = (unsigned int)dir*6;
- unsigned int con = s.con;
- s.con = (con & ~(0x3f << shift)) | (((unsigned int)i & 0x3f) << shift);
+ const unsigned int shift = (unsigned int)direction * 6;
+ const unsigned int con = span.con;
+ span.con = (con & ~(0x3f << shift)) | (((unsigned int)neighborIndex & 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.
-inline int rcGetCon(const rcCompactSpan& s, int dir)
+/// @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.
+inline int rcGetCon(const rcCompactSpan& span, int direction)
{
- const unsigned int shift = (unsigned int)dir*6;
- return (s.con >> shift) & 0x3f;
+ const unsigned int shift = (unsigned int)direction * 6;
+ return (span.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.
-inline int rcGetDirOffsetX(int dir)
+/// @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.
+inline int rcGetDirOffsetX(int direction)
{
static const int offset[4] = { -1, 0, 1, 0, };
- return offset[dir&0x03];
+ return offset[direction & 0x03];
}
+// TODO (graham): Rename this to rcGetDirOffsetZ
/// 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.
-inline int rcGetDirOffsetY(int dir)
+/// @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.
+inline int rcGetDirOffsetY(int direction)
{
static const int offset[4] = { 0, 1, 0, -1 };
- return offset[dir&0x03];
+ return offset[direction & 0x03];
}
/// Gets the direction for the specified offset. One of x and y should be 0.
-/// @param[in] x The x offset. [Limits: -1 <= value <= 1]
-/// @param[in] y The y offset. [Limits: -1 <= value <= 1]
-/// @return The direction that represents the offset.
-inline int rcGetDirForOffset(int x, int y)
+/// @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.
+inline int rcGetDirForOffset(int offsetX, int offsetZ)
{
static const int dirs[5] = { 3, 0, -1, 2, 1 };
- return dirs[((y+1)<<1)+x];
+ return dirs[((offsetZ + 1) << 1) + offsetX];
}
/// @}
@@ -1116,43 +1247,43 @@ inline int rcGetDirForOffset(int x, int y)
/// @{
/// 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,
+/// @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, const rcCompactHeightfield& chf,
+ int borderSize, 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 buildFlags = RC_CONTOUR_TESS_WALL_EDGES);
+/// @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 simplified 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, const rcCompactHeightfield& chf,
+ float maxError, int maxEdgeLen,
+ rcContourSet& cset, int buildFlags = 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);
+/// @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, const rcContourSet& cset, const int nvp, rcPolyMesh& mesh);
/// Merges multiple polygon meshes into a single mesh.
/// @ingroup recast
@@ -1164,34 +1295,34 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe
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.
+/// @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 sampling 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,
+ float sampleDist, 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.
+/// @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.
+/// @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);
/// @}
diff --git a/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h b/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h
index 8b166d736d..1741de9f0e 100644
--- a/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h
+++ b/thirdparty/recastnavigation/Recast/Include/RecastAlloc.h
@@ -19,11 +19,11 @@
#ifndef RECASTALLOC_H
#define RECASTALLOC_H
-#include <stddef.h>
-#include <stdint.h>
-
#include "RecastAssert.h"
+#include <stdlib.h>
+#include <stdint.h>
+
/// Provides hint values to the memory allocator on how long the
/// memory is expected to be used.
enum rcAllocHint
@@ -47,18 +47,27 @@ typedef void (rcFreeFunc)(void* ptr);
/// Sets the base custom allocation functions to be used by Recast.
/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc
/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree
+///
+/// @see rcAlloc, rcFree
void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc);
/// Allocates a memory block.
-/// @param[in] size The size, in bytes of memory, to allocate.
-/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
-/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
-/// @see rcFree
+///
+/// @param[in] size The size, in bytes of memory, to allocate.
+/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use.
+/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed.
+///
+/// @see rcFree, rcAllocSetCustom
void* rcAlloc(size_t size, rcAllocHint hint);
-/// Deallocates a memory block.
-/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc.
-/// @see rcAlloc
+/// Deallocates a memory block. If @p ptr is NULL, this does nothing.
+///
+/// @warning This function leaves the value of @p ptr unchanged. So it still
+/// points to the same (now invalid) location, and not to null.
+///
+/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc.
+///
+/// @see rcAlloc, rcAllocSetCustom
void rcFree(void* ptr);
/// An implementation of operator new usable for placement new. The default one is part of STL (which we don't use).
diff --git a/thirdparty/recastnavigation/Recast/Include/RecastAssert.h b/thirdparty/recastnavigation/Recast/Include/RecastAssert.h
index e7cc10e496..81705bbe0b 100644
--- a/thirdparty/recastnavigation/Recast/Include/RecastAssert.h
+++ b/thirdparty/recastnavigation/Recast/Include/RecastAssert.h
@@ -19,13 +19,10 @@
#ifndef RECASTASSERT_H
#define RECASTASSERT_H
-// Note: This header file's only purpose is to include define assert.
-// Feel free to change the file and include your own implementation instead.
-
#ifdef NDEBUG
-// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
-# define rcAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false)
+// From https://web.archive.org/web/20210117002833/http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/
+# define rcAssert(x) do { (void)sizeof(x); } while ((void)(__LINE__==-1), false)
#else
@@ -38,7 +35,7 @@ typedef void (rcAssertFailFunc)(const char* expression, const char* file, int li
/// Sets the base custom assertion failure function to be used by Recast.
/// @param[in] assertFailFunc The function to be used in case of failure of #dtAssert
-void rcAssertFailSetCustom(rcAssertFailFunc *assertFailFunc);
+void rcAssertFailSetCustom(rcAssertFailFunc* assertFailFunc);
/// Gets the base custom assertion failure function to be used by Recast.
rcAssertFailFunc* rcAssertFailGetCustom();
@@ -47,8 +44,8 @@ rcAssertFailFunc* rcAssertFailGetCustom();
# define rcAssert(expression) \
{ \
rcAssertFailFunc* failFunc = rcAssertFailGetCustom(); \
- if(failFunc == NULL) { assert(expression); } \
- else if(!(expression)) { (*failFunc)(#expression, __FILE__, __LINE__); } \
+ if (failFunc == NULL) { assert(expression); } \
+ else if (!(expression)) { (*failFunc)(#expression, __FILE__, __LINE__); } \
}
#endif
diff --git a/thirdparty/recastnavigation/Recast/Source/Recast.cpp b/thirdparty/recastnavigation/Recast/Source/Recast.cpp
index 4cf145c981..d75a9f59f6 100644
--- a/thirdparty/recastnavigation/Recast/Source/Recast.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/Recast.cpp
@@ -16,81 +16,65 @@
// 3. This notice may not be removed or altered from any source distribution.
//
-#include <float.h>
-#define _USE_MATH_DEFINES
+#include "Recast.h"
+#include "RecastAlloc.h"
+#include "RecastAssert.h"
+
#include <math.h>
#include <string.h>
-#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
-#include "Recast.h"
-#include "RecastAlloc.h"
-#include "RecastAssert.h"
namespace
{
/// Allocates and constructs an object of the given type, returning a pointer.
-/// TODO: Support constructor args.
-/// @param[in] hint Hint to the allocator.
-template <typename T>
-T* rcNew(rcAllocHint hint) {
- T* ptr = (T*)rcAlloc(sizeof(T), hint);
+/// @param[in] allocLifetime Allocation lifetime hint
+template<typename T>
+T* rcNew(const rcAllocHint allocLifetime)
+{
+ T* ptr = (T*)rcAlloc(sizeof(T), allocLifetime);
::new(rcNewTag(), (void*)ptr) T();
return ptr;
}
/// Destroys and frees an object allocated with rcNew.
/// @param[in] ptr The object pointer to delete.
-template <typename T>
-void rcDelete(T* ptr) {
- if (ptr) {
+template<typename T>
+void rcDelete(T* ptr)
+{
+ if (ptr)
+ {
ptr->~T();
rcFree((void*)ptr);
}
}
-} // namespace
-
+} // anonymous namespace
float rcSqrt(float x)
{
return sqrtf(x);
}
-/// @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(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath);
-/// @endcode
void rcContext::log(const rcLogCategory category, const char* format, ...)
{
if (!m_logEnabled)
+ {
return;
+ }
static const int MSG_SIZE = 512;
char msg[MSG_SIZE];
- va_list ap;
- va_start(ap, format);
- int len = vsnprintf(msg, MSG_SIZE, format, ap);
+ va_list argList;
+ va_start(argList, format);
+ int len = vsnprintf(msg, MSG_SIZE, format, argList);
if (len >= MSG_SIZE)
{
- len = MSG_SIZE-1;
- msg[MSG_SIZE-1] = '\0';
+ len = MSG_SIZE - 1;
+ msg[MSG_SIZE - 1] = '\0';
+
+ const char* errorMessage = "Log message was truncated";
+ doLog(RC_LOG_ERROR, errorMessage, (int)strlen(errorMessage));
}
- va_end(ap);
+ va_end(argList);
doLog(category, msg, len);
}
@@ -103,16 +87,22 @@ rcHeightfield* rcAllocHeightfield()
{
return rcNew<rcHeightfield>(RC_ALLOC_PERM);
}
+
+void rcFreeHeightField(rcHeightfield* heightfield)
+{
+ rcDelete(heightfield);
+}
+
rcHeightfield::rcHeightfield()
- : width()
- , height()
- , bmin()
- , bmax()
- , cs()
- , ch()
- , spans()
- , pools()
- , freelist()
+: width()
+, height()
+, bmin()
+, bmax()
+, cs()
+, ch()
+, spans()
+, pools()
+, freelist()
{
}
@@ -129,40 +119,36 @@ rcHeightfield::~rcHeightfield()
}
}
-void rcFreeHeightField(rcHeightfield* hf)
-{
- rcDelete(hf);
-}
-
rcCompactHeightfield* rcAllocCompactHeightfield()
{
return rcNew<rcCompactHeightfield>(RC_ALLOC_PERM);
}
-void rcFreeCompactHeightfield(rcCompactHeightfield* chf)
+void rcFreeCompactHeightfield(rcCompactHeightfield* compactHeightfield)
{
- rcDelete(chf);
+ rcDelete(compactHeightfield);
}
rcCompactHeightfield::rcCompactHeightfield()
- : width(),
- height(),
- spanCount(),
- walkableHeight(),
- walkableClimb(),
- borderSize(),
- maxDistance(),
- maxRegions(),
- bmin(),
- bmax(),
- cs(),
- ch(),
- cells(),
- spans(),
- dist(),
- areas()
+: width()
+, height()
+, spanCount()
+, walkableHeight()
+, walkableClimb()
+, borderSize()
+, maxDistance()
+, maxRegions()
+, bmin()
+, bmax()
+, cs()
+, ch()
+, cells()
+, spans()
+, dist()
+, areas()
{
}
+
rcCompactHeightfield::~rcCompactHeightfield()
{
rcFree(cells);
@@ -175,13 +161,18 @@ rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet()
{
return rcNew<rcHeightfieldLayerSet>(RC_ALLOC_PERM);
}
-void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset)
+
+void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* layerSet)
{
- rcDelete(lset);
+ rcDelete(layerSet);
}
rcHeightfieldLayerSet::rcHeightfieldLayerSet()
- : layers(), nlayers() {}
+: layers()
+, nlayers()
+{
+}
+
rcHeightfieldLayerSet::~rcHeightfieldLayerSet()
{
for (int i = 0; i < nlayers; ++i)
@@ -198,22 +189,26 @@ rcContourSet* rcAllocContourSet()
{
return rcNew<rcContourSet>(RC_ALLOC_PERM);
}
-void rcFreeContourSet(rcContourSet* cset)
+
+void rcFreeContourSet(rcContourSet* contourSet)
{
- rcDelete(cset);
+ rcDelete(contourSet);
}
rcContourSet::rcContourSet()
- : conts(),
- nconts(),
- bmin(),
- bmax(),
- cs(),
- ch(),
- width(),
- height(),
- borderSize(),
- maxError() {}
+: conts()
+, nconts()
+, bmin()
+, bmax()
+, cs()
+, ch()
+, width()
+, height()
+, borderSize()
+, maxError()
+{
+}
+
rcContourSet::~rcContourSet()
{
for (int i = 0; i < nconts; ++i)
@@ -224,32 +219,34 @@ rcContourSet::~rcContourSet()
rcFree(conts);
}
-
rcPolyMesh* rcAllocPolyMesh()
{
return rcNew<rcPolyMesh>(RC_ALLOC_PERM);
}
-void rcFreePolyMesh(rcPolyMesh* pmesh)
+
+void rcFreePolyMesh(rcPolyMesh* polyMesh)
{
- rcDelete(pmesh);
+ rcDelete(polyMesh);
}
rcPolyMesh::rcPolyMesh()
- : verts(),
- polys(),
- regs(),
- flags(),
- areas(),
- nverts(),
- npolys(),
- maxpolys(),
- nvp(),
- bmin(),
- bmax(),
- cs(),
- ch(),
- borderSize(),
- maxEdgeError() {}
+: verts()
+, polys()
+, regs()
+, flags()
+, areas()
+, nverts()
+, npolys()
+, maxpolys()
+, nvp()
+, bmin()
+, bmax()
+, cs()
+, ch()
+, borderSize()
+, maxEdgeError()
+{
+}
rcPolyMesh::~rcPolyMesh()
{
@@ -262,319 +259,284 @@ rcPolyMesh::~rcPolyMesh()
rcPolyMeshDetail* rcAllocPolyMeshDetail()
{
- rcPolyMeshDetail* dmesh = (rcPolyMeshDetail*)rcAlloc(sizeof(rcPolyMeshDetail), RC_ALLOC_PERM);
- memset(dmesh, 0, sizeof(rcPolyMeshDetail));
- return dmesh;
+ return rcNew<rcPolyMeshDetail>(RC_ALLOC_PERM);
}
-void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh)
+void rcFreePolyMeshDetail(rcPolyMeshDetail* detailMesh)
+{
+ if (detailMesh == NULL)
+ {
+ return;
+ }
+ rcFree(detailMesh->meshes);
+ rcFree(detailMesh->verts);
+ rcFree(detailMesh->tris);
+ rcFree(detailMesh);
+}
+
+rcPolyMeshDetail::rcPolyMeshDetail()
+: meshes()
+, verts()
+, tris()
+, nmeshes()
+, nverts()
+, ntris()
{
- if (!dmesh) return;
- rcFree(dmesh->meshes);
- rcFree(dmesh->verts);
- rcFree(dmesh->tris);
- rcFree(dmesh);
}
-void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
+void rcCalcBounds(const float* verts, int numVerts, float* minBounds, float* maxBounds)
{
// Calculate bounding box.
- rcVcopy(bmin, verts);
- rcVcopy(bmax, verts);
- for (int i = 1; i < nv; ++i)
+ rcVcopy(minBounds, verts);
+ rcVcopy(maxBounds, verts);
+ for (int i = 1; i < numVerts; ++i)
{
- const float* v = &verts[i*3];
- rcVmin(bmin, v);
- rcVmax(bmax, v);
+ const float* v = &verts[i * 3];
+ rcVmin(minBounds, v);
+ rcVmax(maxBounds, v);
}
}
-void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h)
+void rcCalcGridSize(const float* minBounds, const float* maxBounds, const float cellSize, int* sizeX, int* sizeZ)
{
- *w = (int)((bmax[0] - bmin[0])/cs+0.5f);
- *h = (int)((bmax[2] - bmin[2])/cs+0.5f);
+ *sizeX = (int)((maxBounds[0] - minBounds[0]) / cellSize + 0.5f);
+ *sizeZ = (int)((maxBounds[2] - minBounds[2]) / cellSize + 0.5f);
}
-/// @par
-///
-/// See the #rcConfig documentation for more information on the configuration parameters.
-///
-/// @see rcAllocHeightfield, rcHeightfield
-bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
- const float* bmin, const float* bmax,
- float cs, float ch)
+bool rcCreateHeightfield(rcContext* context, rcHeightfield& heightfield, int sizeX, int sizeZ,
+ const float* minBounds, const float* maxBounds,
+ float cellSize, float cellHeight)
{
- rcIgnoreUnused(ctx);
-
- hf.width = width;
- hf.height = height;
- rcVcopy(hf.bmin, bmin);
- rcVcopy(hf.bmax, bmax);
- hf.cs = cs;
- hf.ch = ch;
- hf.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM);
- if (!hf.spans)
+ rcIgnoreUnused(context);
+
+ heightfield.width = sizeX;
+ heightfield.height = sizeZ;
+ rcVcopy(heightfield.bmin, minBounds);
+ rcVcopy(heightfield.bmax, maxBounds);
+ heightfield.cs = cellSize;
+ heightfield.ch = cellHeight;
+ heightfield.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*) * heightfield.width * heightfield.height, RC_ALLOC_PERM);
+ if (!heightfield.spans)
+ {
return false;
- memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height);
+ }
+ memset(heightfield.spans, 0, sizeof(rcSpan*) * heightfield.width * heightfield.height);
return true;
}
-static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* norm)
+static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* faceNormal)
{
float e0[3], e1[3];
rcVsub(e0, v1, v0);
rcVsub(e1, v2, v0);
- rcVcross(norm, e0, e1);
- rcVnormalize(norm);
-}
-
-/// @par
-///
-/// Only sets the area 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
-void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
- const float* verts, int nv,
- const int* tris, int nt,
- unsigned char* areas)
-{
- rcIgnoreUnused(ctx);
- rcIgnoreUnused(nv);
-
- const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
+ rcVcross(faceNormal, e0, e1);
+ rcVnormalize(faceNormal);
+}
+
+void rcMarkWalkableTriangles(rcContext* context, const float walkableSlopeAngle,
+ const float* verts, const int numVerts,
+ const int* tris, const int numTris,
+ unsigned char* triAreaIDs)
+{
+ rcIgnoreUnused(context);
+ rcIgnoreUnused(numVerts);
+
+ const float walkableThr = cosf(walkableSlopeAngle / 180.0f * RC_PI);
float norm[3];
-
- for (int i = 0; i < nt; ++i)
+
+ for (int i = 0; i < numTris; ++i)
{
- const int* tri = &tris[i*3];
- calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
+ const int* tri = &tris[i * 3];
+ calcTriNormal(&verts[tri[0] * 3], &verts[tri[1] * 3], &verts[tri[2] * 3], norm);
// Check if the face is walkable.
if (norm[1] > walkableThr)
- areas[i] = RC_WALKABLE_AREA;
+ {
+ triAreaIDs[i] = RC_WALKABLE_AREA;
+ }
}
}
-/// @par
-///
-/// Only sets the area 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
-void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
- const float* verts, int /*nv*/,
- const int* tris, int nt,
- unsigned char* areas)
-{
- rcIgnoreUnused(ctx);
-
- const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
-
- float norm[3];
-
- for (int i = 0; i < nt; ++i)
+void rcClearUnwalkableTriangles(rcContext* context, const float walkableSlopeAngle,
+ const float* verts, int numVerts,
+ const int* tris, int numTris,
+ unsigned char* triAreaIDs)
+{
+ rcIgnoreUnused(context);
+ rcIgnoreUnused(numVerts);
+
+ // The minimum Y value for a face normal of a triangle with a walkable slope.
+ const float walkableLimitY = cosf(walkableSlopeAngle / 180.0f * RC_PI);
+
+ float faceNormal[3];
+ for (int i = 0; i < numTris; ++i)
{
- const int* tri = &tris[i*3];
- calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
+ const int* tri = &tris[i * 3];
+ calcTriNormal(&verts[tri[0] * 3], &verts[tri[1] * 3], &verts[tri[2] * 3], faceNormal);
// Check if the face is walkable.
- if (norm[1] <= walkableThr)
- areas[i] = RC_NULL_AREA;
+ if (faceNormal[1] <= walkableLimitY)
+ {
+ triAreaIDs[i] = RC_NULL_AREA;
+ }
}
}
-int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf)
+int rcGetHeightFieldSpanCount(rcContext* context, const rcHeightfield& heightfield)
{
- rcIgnoreUnused(ctx);
-
- const int w = hf.width;
- const int h = hf.height;
+ rcIgnoreUnused(context);
+
+ const int numCols = heightfield.width * heightfield.height;
int spanCount = 0;
- for (int y = 0; y < h; ++y)
+ for (int columnIndex = 0; columnIndex < numCols; ++columnIndex)
{
- for (int x = 0; x < w; ++x)
+ for (rcSpan* span = heightfield.spans[columnIndex]; span != NULL; span = span->next)
{
- for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next)
+ if (span->area != RC_NULL_AREA)
{
- if (s->area != RC_NULL_AREA)
- spanCount++;
+ spanCount++;
}
}
}
return spanCount;
}
-/// @par
-///
-/// This is just the beginning of the process of fully building a compact heightfield.
-/// Various filters may be 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
-bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
- rcHeightfield& hf, rcCompactHeightfield& chf)
+bool rcBuildCompactHeightfield(rcContext* context, const int walkableHeight, const int walkableClimb,
+ const rcHeightfield& heightfield, rcCompactHeightfield& compactHeightfield)
{
- rcAssert(ctx);
-
- rcScopedTimer timer(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
-
- const int w = hf.width;
- const int h = hf.height;
- const int spanCount = rcGetHeightFieldSpanCount(ctx, hf);
+ rcAssert(context);
+
+ rcScopedTimer timer(context, RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
+
+ const int xSize = heightfield.width;
+ const int zSize = heightfield.height;
+ const int spanCount = rcGetHeightFieldSpanCount(context, heightfield);
// 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 = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM);
- if (!chf.cells)
+ compactHeightfield.width = xSize;
+ compactHeightfield.height = zSize;
+ compactHeightfield.spanCount = spanCount;
+ compactHeightfield.walkableHeight = walkableHeight;
+ compactHeightfield.walkableClimb = walkableClimb;
+ compactHeightfield.maxRegions = 0;
+ rcVcopy(compactHeightfield.bmin, heightfield.bmin);
+ rcVcopy(compactHeightfield.bmax, heightfield.bmax);
+ compactHeightfield.bmax[1] += walkableHeight * heightfield.ch;
+ compactHeightfield.cs = heightfield.cs;
+ compactHeightfield.ch = heightfield.ch;
+ compactHeightfield.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell) * xSize * zSize, RC_ALLOC_PERM);
+ if (!compactHeightfield.cells)
{
- ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
+ context->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", xSize * zSize);
return false;
}
- memset(chf.cells, 0, sizeof(rcCompactCell)*w*h);
- chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM);
- if (!chf.spans)
+ memset(compactHeightfield.cells, 0, sizeof(rcCompactCell) * xSize * zSize);
+ compactHeightfield.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan) * spanCount, RC_ALLOC_PERM);
+ if (!compactHeightfield.spans)
{
- ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
+ context->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
return false;
}
- memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
- chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM);
- if (!chf.areas)
+ memset(compactHeightfield.spans, 0, sizeof(rcCompactSpan) * spanCount);
+ compactHeightfield.areas = (unsigned char*)rcAlloc(sizeof(unsigned char) * spanCount, RC_ALLOC_PERM);
+ if (!compactHeightfield.areas)
{
- ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
+ context->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
return false;
}
- memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount);
-
+ memset(compactHeightfield.areas, RC_NULL_AREA, sizeof(unsigned char) * spanCount);
+
const int MAX_HEIGHT = 0xffff;
-
+
// Fill in cells and spans.
- int idx = 0;
- for (int y = 0; y < h; ++y)
+ int currentCellIndex = 0;
+ const int numColumns = xSize * zSize;
+ for (int columnIndex = 0; columnIndex < numColumns; ++columnIndex)
{
- for (int x = 0; x < w; ++x)
+ const rcSpan* span = heightfield.spans[columnIndex];
+
+ // If there are no spans at this cell, just leave the data to index=0, count=0.
+ if (span == NULL)
+ {
+ continue;
+ }
+
+ rcCompactCell& cell = compactHeightfield.cells[columnIndex];
+ cell.index = currentCellIndex;
+ cell.count = 0;
+
+ for (; span != NULL; span = span->next)
{
- const 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) continue;
- rcCompactCell& c = chf.cells[x+y*w];
- c.index = idx;
- c.count = 0;
- while (s)
+ if (span->area != RC_NULL_AREA)
{
- if (s->area != RC_NULL_AREA)
- {
- const int bot = (int)s->smax;
- const int top = s->next ? (int)s->next->smin : MAX_HEIGHT;
- chf.spans[idx].y = (unsigned short)rcClamp(bot, 0, 0xffff);
- chf.spans[idx].h = (unsigned char)rcClamp(top - bot, 0, 0xff);
- chf.areas[idx] = s->area;
- idx++;
- c.count++;
- }
- s = s->next;
+ const int bot = (int)span->smax;
+ const int top = span->next ? (int)span->next->smin : MAX_HEIGHT;
+ compactHeightfield.spans[currentCellIndex].y = (unsigned short)rcClamp(bot, 0, 0xffff);
+ compactHeightfield.spans[currentCellIndex].h = (unsigned char)rcClamp(top - bot, 0, 0xff);
+ compactHeightfield.areas[currentCellIndex] = span->area;
+ currentCellIndex++;
+ cell.count++;
}
}
}
-
+
// Find neighbour connections.
- const int MAX_LAYERS = RC_NOT_CONNECTED-1;
- int tooHighNeighbour = 0;
- for (int y = 0; y < h; ++y)
+ const int MAX_LAYERS = RC_NOT_CONNECTED - 1;
+ int maxLayerIndex = 0;
+ const int zStride = xSize; // for readability
+ for (int z = 0; z < zSize; ++z)
{
- for (int x = 0; x < w; ++x)
+ for (int x = 0; x < xSize; ++x)
{
- const rcCompactCell& c = chf.cells[x+y*w];
- for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
+ const rcCompactCell& cell = compactHeightfield.cells[x + z * zStride];
+ for (int i = (int)cell.index, ni = (int)(cell.index + cell.count); i < ni; ++i)
{
- rcCompactSpan& s = chf.spans[i];
-
+ rcCompactSpan& span = compactHeightfield.spans[i];
+
for (int dir = 0; dir < 4; ++dir)
{
- rcSetCon(s, dir, RC_NOT_CONNECTED);
- const int nx = x + rcGetDirOffsetX(dir);
- const int ny = y + rcGetDirOffsetY(dir);
+ rcSetCon(span, dir, RC_NOT_CONNECTED);
+ const int neighborX = x + rcGetDirOffsetX(dir);
+ const int neighborZ = z + rcGetDirOffsetY(dir);
// First check that the neighbour cell is in bounds.
- if (nx < 0 || ny < 0 || nx >= w || ny >= h)
+ if (neighborX < 0 || neighborZ < 0 || neighborX >= xSize || neighborZ >= zSize)
+ {
continue;
-
+ }
+
// Iterate over all neighbour spans and check if any of the is
// accessible from current cell.
- const rcCompactCell& nc = chf.cells[nx+ny*w];
- for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; ++k)
+ const rcCompactCell& neighborCell = compactHeightfield.cells[neighborX + neighborZ * zStride];
+ for (int k = (int)neighborCell.index, nk = (int)(neighborCell.index + neighborCell.count); k < nk; ++k)
{
- const rcCompactSpan& ns = chf.spans[k];
- const int bot = rcMax(s.y, ns.y);
- const int top = rcMin(s.y+s.h, ns.y+ns.h);
+ const rcCompactSpan& neighborSpan = compactHeightfield.spans[k];
+ const int bot = rcMax(span.y, neighborSpan.y);
+ const int top = rcMin(span.y + span.h, neighborSpan.y + neighborSpan.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 && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
+ if ((top - bot) >= walkableHeight && rcAbs((int)neighborSpan.y - (int)span.y) <= walkableClimb)
{
// Mark direction as walkable.
- const int lidx = k - (int)nc.index;
- if (lidx < 0 || lidx > MAX_LAYERS)
+ const int layerIndex = k - (int)neighborCell.index;
+ if (layerIndex < 0 || layerIndex > MAX_LAYERS)
{
- tooHighNeighbour = rcMax(tooHighNeighbour, lidx);
+ maxLayerIndex = rcMax(maxLayerIndex, layerIndex);
continue;
}
- rcSetCon(s, dir, lidx);
+ rcSetCon(span, dir, layerIndex);
break;
}
}
-
}
}
}
}
-
- if (tooHighNeighbour > MAX_LAYERS)
- {
- ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
- tooHighNeighbour, MAX_LAYERS);
- }
-
- 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)
+ if (maxLayerIndex > MAX_LAYERS)
{
- size += (sizeof(rcSpanPool) - sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL;
- pool = pool->next;
+ context->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
+ maxLayerIndex, MAX_LAYERS);
}
- 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;
+ return true;
}
-*/
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastAlloc.cpp b/thirdparty/recastnavigation/Recast/Source/RecastAlloc.cpp
index bdc366116e..e919daf7be 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastAlloc.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastAlloc.cpp
@@ -16,12 +16,9 @@
// 3. This notice may not be removed or altered from any source distribution.
//
-#include <stdlib.h>
-#include <string.h>
#include "RecastAlloc.h"
-#include "RecastAssert.h"
-static void *rcAllocDefault(size_t size, rcAllocHint)
+static void* rcAllocDefault(size_t size, rcAllocHint)
{
return malloc(size);
}
@@ -34,27 +31,21 @@ static void rcFreeDefault(void *ptr)
static rcAllocFunc* sRecastAllocFunc = rcAllocDefault;
static rcFreeFunc* sRecastFreeFunc = rcFreeDefault;
-/// @see rcAlloc, rcFree
-void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc)
+void rcAllocSetCustom(rcAllocFunc* allocFunc, rcFreeFunc* freeFunc)
{
sRecastAllocFunc = allocFunc ? allocFunc : rcAllocDefault;
sRecastFreeFunc = freeFunc ? freeFunc : rcFreeDefault;
}
-/// @see rcAllocSetCustom
void* rcAlloc(size_t size, rcAllocHint hint)
{
return sRecastAllocFunc(size, hint);
}
-/// @par
-///
-/// @warning This function leaves the value of @p ptr unchanged. So it still
-/// points to the same (now invalid) location, and not to null.
-///
-/// @see rcAllocSetCustom
void rcFree(void* ptr)
{
- if (ptr)
+ if (ptr != NULL)
+ {
sRecastFreeFunc(ptr);
+ }
}
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastArea.cpp b/thirdparty/recastnavigation/Recast/Source/RecastArea.cpp
index 97139cf996..07fb02189c 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastArea.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastArea.cpp
@@ -17,7 +17,6 @@
//
#include <float.h>
-#define _USE_MATH_DEFINES
#include <math.h>
#include <string.h>
#include <stdlib.h>
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastAssert.cpp b/thirdparty/recastnavigation/Recast/Source/RecastAssert.cpp
index 6297d42023..973b681121 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastAssert.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastAssert.cpp
@@ -22,7 +22,7 @@
static rcAssertFailFunc* sRecastAssertFailFunc = 0;
-void rcAssertFailSetCustom(rcAssertFailFunc *assertFailFunc)
+void rcAssertFailSetCustom(rcAssertFailFunc* assertFailFunc)
{
sRecastAssertFailFunc = assertFailFunc;
}
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastContour.cpp b/thirdparty/recastnavigation/Recast/Source/RecastContour.cpp
index 1293d4fbde..5508a98a7b 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastContour.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastContour.cpp
@@ -16,7 +16,6 @@
// 3. This notice may not be removed or altered from any source distribution.
//
-#define _USE_MATH_DEFINES
#include <math.h>
#include <string.h>
#include <stdio.h>
@@ -102,7 +101,7 @@ static int getCornerHeight(int x, int y, int i, int dir,
}
static void walkContour(int x, int y, int i,
- rcCompactHeightfield& chf,
+ const rcCompactHeightfield& chf,
unsigned char* flags, rcIntArray& points)
{
// Choose the first non-connected edge
@@ -542,7 +541,7 @@ static bool vequal(const int* a, const int* b)
return a[0] == b[0] && a[2] == b[2];
}
-static bool intersectSegCountour(const int* d0, const int* d1, int i, int n, const int* verts)
+static bool intersectSegContour(const int* d0, const int* d1, int i, int n, const int* verts)
{
// For each edge (k,k+1) of P
for (int k = 0; k < n; k++)
@@ -778,9 +777,9 @@ static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
for (int j = 0; j < ndiags; j++)
{
const int* pt = &outline->verts[diags[j].vert*4];
- bool intersect = intersectSegCountour(pt, corner, diags[i].vert, outline->nverts, outline->verts);
+ bool intersect = intersectSegContour(pt, corner, diags[i].vert, outline->nverts, outline->verts);
for (int k = i; k < region.nholes && !intersect; k++)
- intersect |= intersectSegCountour(pt, corner, -1, region.holes[k].contour->nverts, region.holes[k].contour->verts);
+ intersect |= intersectSegContour(pt, corner, -1, region.holes[k].contour->nverts, region.holes[k].contour->verts);
if (!intersect)
{
index = diags[j].vert;
@@ -821,7 +820,7 @@ static void mergeRegionHoles(rcContext* ctx, rcContourRegion& region)
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig
-bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
+bool rcBuildContours(rcContext* ctx, const rcCompactHeightfield& chf,
const float maxError, const int maxEdgeLen,
rcContourSet& cset, const int buildFlags)
{
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastFilter.cpp b/thirdparty/recastnavigation/Recast/Source/RecastFilter.cpp
index 9d3e63c482..b5adba43ea 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastFilter.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastFilter.cpp
@@ -16,186 +16,168 @@
// 3. This notice may not be removed or altered from any source distribution.
//
-#define _USE_MATH_DEFINES
-#include <math.h>
-#include <stdio.h>
#include "Recast.h"
#include "RecastAssert.h"
-/// @par
-///
-/// Allows the formation of walkable regions that will flow over low lying
-/// objects such as curbs, and up structures such as stairways.
-///
-/// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt>
-///
-/// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call
-/// #rcFilterLedgeSpans after calling this filter.
-///
-/// @see rcHeightfield, rcConfig
-void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid)
+#include <stdlib.h>
+
+void rcFilterLowHangingWalkableObstacles(rcContext* context, const int walkableClimb, rcHeightfield& heightfield)
{
- rcAssert(ctx);
+ rcAssert(context);
- rcScopedTimer timer(ctx, RC_TIMER_FILTER_LOW_OBSTACLES);
-
- const int w = solid.width;
- const int h = solid.height;
-
- for (int y = 0; y < h; ++y)
+ rcScopedTimer timer(context, RC_TIMER_FILTER_LOW_OBSTACLES);
+
+ const int xSize = heightfield.width;
+ const int zSize = heightfield.height;
+
+ for (int z = 0; z < zSize; ++z)
{
- for (int x = 0; x < w; ++x)
+ for (int x = 0; x < xSize; ++x)
{
- rcSpan* ps = 0;
- bool previousWalkable = false;
+ rcSpan* previousSpan = NULL;
+ bool previousWasWalkable = false;
unsigned char previousArea = RC_NULL_AREA;
-
- for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next)
+
+ for (rcSpan* span = heightfield.spans[x + z * xSize]; span != NULL; previousSpan = span, span = span->next)
{
- const bool walkable = s->area != RC_NULL_AREA;
+ const bool walkable = span->area != RC_NULL_AREA;
// If current span is not walkable, but there is walkable
// span just below it, mark the span above it walkable too.
- if (!walkable && previousWalkable)
+ if (!walkable && previousWasWalkable)
{
- if (rcAbs((int)s->smax - (int)ps->smax) <= walkableClimb)
- s->area = previousArea;
+ if (rcAbs((int)span->smax - (int)previousSpan->smax) <= walkableClimb)
+ {
+ span->area = previousArea;
+ }
}
// Copy walkable flag so that it cannot propagate
// past multiple non-walkable objects.
- previousWalkable = walkable;
- previousArea = s->area;
+ previousWasWalkable = walkable;
+ previousArea = span->area;
}
}
}
}
-/// @par
-///
-/// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb
-/// from the current span's maximum.
-/// This method removes the impact of the overestimation of conservative voxelization
-/// so the resulting mesh will not have regions hanging in the air over ledges.
-///
-/// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
-///
-/// @see rcHeightfield, rcConfig
-void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walkableClimb,
- rcHeightfield& solid)
+void rcFilterLedgeSpans(rcContext* context, const int walkableHeight, const int walkableClimb,
+ rcHeightfield& heightfield)
{
- rcAssert(ctx);
+ rcAssert(context);
- rcScopedTimer timer(ctx, RC_TIMER_FILTER_BORDER);
+ rcScopedTimer timer(context, RC_TIMER_FILTER_BORDER);
- const int w = solid.width;
- const int h = solid.height;
- const int MAX_HEIGHT = 0xffff;
+ const int xSize = heightfield.width;
+ const int zSize = heightfield.height;
+ const int MAX_HEIGHT = 0xffff; // TODO (graham): Move this to a more visible constant and update usages.
// Mark border spans.
- for (int y = 0; y < h; ++y)
+ for (int z = 0; z < zSize; ++z)
{
- for (int x = 0; x < w; ++x)
+ for (int x = 0; x < xSize; ++x)
{
- for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next)
+ for (rcSpan* span = heightfield.spans[x + z * xSize]; span; span = span->next)
{
// Skip non walkable spans.
- if (s->area == RC_NULL_AREA)
+ if (span->area == RC_NULL_AREA)
+ {
continue;
-
- const int bot = (int)(s->smax);
- const int top = s->next ? (int)(s->next->smin) : MAX_HEIGHT;
-
+ }
+
+ const int bot = (int)(span->smax);
+ const int top = span->next ? (int)(span->next->smin) : MAX_HEIGHT;
+
// Find neighbours minimum height.
- int minh = MAX_HEIGHT;
+ int minNeighborHeight = MAX_HEIGHT;
// Min and max height of accessible neighbours.
- int asmin = s->smax;
- int asmax = s->smax;
+ int accessibleNeighborMinHeight = span->smax;
+ int accessibleNeighborMaxHeight = span->smax;
- for (int dir = 0; dir < 4; ++dir)
+ for (int direction = 0; direction < 4; ++direction)
{
- int dx = x + rcGetDirOffsetX(dir);
- int dy = y + rcGetDirOffsetY(dir);
+ int dx = x + rcGetDirOffsetX(direction);
+ int dy = z + rcGetDirOffsetY(direction);
// Skip neighbours which are out of bounds.
- if (dx < 0 || dy < 0 || dx >= w || dy >= h)
+ if (dx < 0 || dy < 0 || dx >= xSize || dy >= zSize)
{
- minh = rcMin(minh, -walkableClimb - bot);
+ minNeighborHeight = rcMin(minNeighborHeight, -walkableClimb - bot);
continue;
}
// From minus infinity to the first span.
- rcSpan* ns = solid.spans[dx + dy*w];
- int nbot = -walkableClimb;
- int ntop = ns ? (int)ns->smin : MAX_HEIGHT;
- // Skip neightbour if the gap between the spans is too small.
- if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight)
- minh = rcMin(minh, nbot - bot);
+ const rcSpan* neighborSpan = heightfield.spans[dx + dy * xSize];
+ int neighborBot = -walkableClimb;
+ int neighborTop = neighborSpan ? (int)neighborSpan->smin : MAX_HEIGHT;
+ // Skip neighbour if the gap between the spans is too small.
+ if (rcMin(top, neighborTop) - rcMax(bot, neighborBot) > walkableHeight)
+ {
+ minNeighborHeight = rcMin(minNeighborHeight, neighborBot - bot);
+ }
+
// Rest of the spans.
- for (ns = solid.spans[dx + dy*w]; ns; ns = ns->next)
+ for (neighborSpan = heightfield.spans[dx + dy * xSize]; neighborSpan; neighborSpan = neighborSpan->next)
{
- nbot = (int)ns->smax;
- ntop = ns->next ? (int)ns->next->smin : MAX_HEIGHT;
- // Skip neightbour if the gap between the spans is too small.
- if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight)
- {
- minh = rcMin(minh, nbot - bot);
+ neighborBot = (int)neighborSpan->smax;
+ neighborTop = neighborSpan->next ? (int)neighborSpan->next->smin : MAX_HEIGHT;
+ // Skip neighbour if the gap between the spans is too small.
+ if (rcMin(top, neighborTop) - rcMax(bot, neighborBot) > walkableHeight)
+ {
+ minNeighborHeight = rcMin(minNeighborHeight, neighborBot - bot);
+
// Find min/max accessible neighbour height.
- if (rcAbs(nbot - bot) <= walkableClimb)
+ if (rcAbs(neighborBot - bot) <= walkableClimb)
{
- if (nbot < asmin) asmin = nbot;
- if (nbot > asmax) asmax = nbot;
+ if (neighborBot < accessibleNeighborMinHeight) accessibleNeighborMinHeight = neighborBot;
+ if (neighborBot > accessibleNeighborMaxHeight) accessibleNeighborMaxHeight = neighborBot;
}
-
+
}
}
}
-
+
// The current span is close to a ledge if the drop to any
// neighbour span is less than the walkableClimb.
- if (minh < -walkableClimb)
+ if (minNeighborHeight < -walkableClimb)
{
- s->area = RC_NULL_AREA;
+ span->area = RC_NULL_AREA;
}
// If the difference between all neighbours is too large,
// we are at steep slope, mark the span as ledge.
- else if ((asmax - asmin) > walkableClimb)
+ else if ((accessibleNeighborMaxHeight - accessibleNeighborMinHeight) > walkableClimb)
{
- s->area = RC_NULL_AREA;
+ span->area = RC_NULL_AREA;
}
}
}
}
}
-/// @par
-///
-/// For this filter, the clearance above the span is the distance from the span's
-/// maximum to the next higher span's minimum. (Same grid column.)
-///
-/// @see rcHeightfield, rcConfig
-void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid)
+void rcFilterWalkableLowHeightSpans(rcContext* context, const int walkableHeight, rcHeightfield& heightfield)
{
- rcAssert(ctx);
+ rcAssert(context);
- rcScopedTimer timer(ctx, RC_TIMER_FILTER_WALKABLE);
+ rcScopedTimer timer(context, RC_TIMER_FILTER_WALKABLE);
- const int w = solid.width;
- const int h = solid.height;
+ const int xSize = heightfield.width;
+ const int zSize = heightfield.height;
const int MAX_HEIGHT = 0xffff;
// Remove walkable flag from spans which do not have enough
// space above them for the agent to stand there.
- for (int y = 0; y < h; ++y)
+ for (int z = 0; z < zSize; ++z)
{
- for (int x = 0; x < w; ++x)
+ for (int x = 0; x < xSize; ++x)
{
- for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next)
+ for (rcSpan* span = heightfield.spans[x + z*xSize]; span; span = span->next)
{
- const int bot = (int)(s->smax);
- const int top = s->next ? (int)(s->next->smin) : MAX_HEIGHT;
- if ((top - bot) <= walkableHeight)
- s->area = RC_NULL_AREA;
+ const int bot = (int)(span->smax);
+ const int top = span->next ? (int)(span->next->smin) : MAX_HEIGHT;
+ if ((top - bot) < walkableHeight)
+ {
+ span->area = RC_NULL_AREA;
+ }
}
}
}
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastLayers.cpp b/thirdparty/recastnavigation/Recast/Source/RecastLayers.cpp
index acc97e44f0..ca37ebba7f 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastLayers.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastLayers.cpp
@@ -17,7 +17,6 @@
//
#include <float.h>
-#define _USE_MATH_DEFINES
#include <math.h>
#include <string.h>
#include <stdlib.h>
@@ -29,8 +28,21 @@
// Must be 255 or smaller (not 256) because layer IDs are stored as
// a byte where 255 is a special value.
-static const int RC_MAX_LAYERS = 63;
-static const int RC_MAX_NEIS = 16;
+#ifndef RC_MAX_LAYERS_DEF
+#define RC_MAX_LAYERS_DEF 63
+#endif
+
+#if RC_MAX_LAYERS_DEF > 255
+#error RC_MAX_LAYERS_DEF must be 255 or smaller
+#endif
+
+#ifndef RC_MAX_NEIS_DEF
+#define RC_MAX_NEIS_DEF 16
+#endif
+
+// Keep type checking.
+static const int RC_MAX_LAYERS = RC_MAX_LAYERS_DEF;
+static const int RC_MAX_NEIS = RC_MAX_NEIS_DEF;
struct rcLayerRegion
{
@@ -89,7 +101,7 @@ struct rcLayerSweepSpan
/// See the #rcConfig documentation for more information on the configuration parameters.
///
/// @see rcAllocHeightfieldLayerSet, rcCompactHeightfield, rcHeightfieldLayerSet, rcConfig
-bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
+bool rcBuildHeightfieldLayers(rcContext* ctx, const rcCompactHeightfield& chf,
const int borderSize, const int walkableHeight,
rcHeightfieldLayerSet& lset)
{
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp b/thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp
index ea09ee1de0..c2c0d51749 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastMesh.cpp
@@ -16,7 +16,6 @@
// 3. This notice may not be removed or altered from any source distribution.
//
-#define _USE_MATH_DEFINES
#include <math.h>
#include <string.h>
#include <stdio.h>
@@ -35,7 +34,7 @@ static bool buildMeshAdjacency(unsigned short* polys, const int npolys,
const int nverts, const int vertsPerPoly)
{
// Based on code by Eric Lengyel from:
- // http://www.terathon.com/code/edges.php
+ // https://web.archive.org/web/20080704083314/http://www.terathon.com/code/edges.php
int maxEdgeCount = npolys*vertsPerPoly;
unsigned short* firstEdge = (unsigned short*)rcAlloc(sizeof(unsigned short)*(nverts + maxEdgeCount), RC_ALLOC_TEMP);
@@ -987,7 +986,7 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
/// limit must be retricted to <= #DT_VERTS_PER_POLYGON.
///
/// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig
-bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh)
+bool rcBuildPolyMesh(rcContext* ctx, const rcContourSet& cset, const int nvp, rcPolyMesh& mesh)
{
rcAssert(ctx);
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp b/thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp
index 40bfc9b4bc..40f5b8c60b 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastMeshDetail.cpp
@@ -17,7 +17,6 @@
//
#include <float.h>
-#define _USE_MATH_DEFINES
#include <math.h>
#include <string.h>
#include <stdlib.h>
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp b/thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp
index 673550e79e..2a4f619fb8 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastRasterization.cpp
@@ -16,377 +16,485 @@
// 3. This notice may not be removed or altered from any source distribution.
//
-#define _USE_MATH_DEFINES
#include <math.h>
#include <stdio.h>
#include "Recast.h"
#include "RecastAlloc.h"
#include "RecastAssert.h"
-inline bool overlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax)
+/// Check whether two bounding boxes overlap
+///
+/// @param[in] aMin Min axis extents of bounding box A
+/// @param[in] aMax Max axis extents of bounding box A
+/// @param[in] bMin Min axis extents of bounding box B
+/// @param[in] bMax Max axis extents of bounding box B
+/// @returns true if the two bounding boxes overlap. False otherwise.
+static bool overlapBounds(const float* aMin, const float* aMax, const float* bMin, const float* bMax)
{
- bool overlap = true;
- overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
- overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
- overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
- return overlap;
+ return
+ aMin[0] <= bMax[0] && aMax[0] >= bMin[0] &&
+ aMin[1] <= bMax[1] && aMax[1] >= bMin[1] &&
+ aMin[2] <= bMax[2] && aMax[2] >= bMin[2];
}
-inline bool overlapInterval(unsigned short amin, unsigned short amax,
- unsigned short bmin, unsigned short bmax)
-{
- if (amax < bmin) return false;
- if (amin > bmax) return false;
- return true;
-}
-
-
+/// Allocates a new span in the heightfield.
+/// Use a memory pool and free list to minimize actual allocations.
+///
+/// @param[in] hf The heightfield
+/// @returns A pointer to the allocated or re-used span memory.
static rcSpan* allocSpan(rcHeightfield& hf)
{
- // If running out of memory, allocate new page and update the freelist.
- if (!hf.freelist || !hf.freelist->next)
+ // If necessary, allocate new page and update the freelist.
+ if (hf.freelist == NULL || hf.freelist->next == NULL)
{
// Create new page.
// Allocate memory for the new pool.
- rcSpanPool* pool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM);
- if (!pool) return 0;
+ rcSpanPool* spanPool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM);
+ if (spanPool == NULL)
+ {
+ return NULL;
+ }
// Add the pool into the list of pools.
- pool->next = hf.pools;
- hf.pools = pool;
- // Add new items to the free list.
- rcSpan* freelist = hf.freelist;
- rcSpan* head = &pool->items[0];
- rcSpan* it = &pool->items[RC_SPANS_PER_POOL];
+ spanPool->next = hf.pools;
+ hf.pools = spanPool;
+
+ // Add new spans to the free list.
+ rcSpan* freeList = hf.freelist;
+ rcSpan* head = &spanPool->items[0];
+ rcSpan* it = &spanPool->items[RC_SPANS_PER_POOL];
do
{
--it;
- it->next = freelist;
- freelist = it;
+ it->next = freeList;
+ freeList = it;
}
while (it != head);
hf.freelist = it;
}
-
- // Pop item from in front of the free list.
- rcSpan* it = hf.freelist;
+
+ // Pop item from the front of the free list.
+ rcSpan* newSpan = hf.freelist;
hf.freelist = hf.freelist->next;
- return it;
+ return newSpan;
}
-static void freeSpan(rcHeightfield& hf, rcSpan* ptr)
+/// Releases the memory used by the span back to the heightfield, so it can be re-used for new spans.
+/// @param[in] hf The heightfield.
+/// @param[in] span A pointer to the span to free
+static void freeSpan(rcHeightfield& hf, rcSpan* span)
{
- if (!ptr) return;
- // Add the node in front of the free list.
- ptr->next = hf.freelist;
- hf.freelist = ptr;
+ if (span == NULL)
+ {
+ return;
+ }
+ // Add the span to the front of the free list.
+ span->next = hf.freelist;
+ hf.freelist = span;
}
-static bool addSpan(rcHeightfield& hf, const int x, const int y,
- const unsigned short smin, const unsigned short smax,
- const unsigned char area, const int flagMergeThr)
+/// Adds a span to the heightfield. If the new span overlaps existing spans,
+/// it will merge the new span with the existing ones.
+///
+/// @param[in] hf Heightfield to add spans to
+/// @param[in] x The new span's column cell x index
+/// @param[in] z The new span's column cell z index
+/// @param[in] min The new span's minimum cell index
+/// @param[in] max The new span's maximum cell index
+/// @param[in] areaID The new span's area type ID
+/// @param[in] flagMergeThreshold How close two spans maximum extents need to be to merge area type IDs
+static bool addSpan(rcHeightfield& hf,
+ const int x, const int z,
+ const unsigned short min, const unsigned short max,
+ const unsigned char areaID, const int flagMergeThreshold)
{
-
- int idx = x + y*hf.width;
-
- rcSpan* s = allocSpan(hf);
- if (!s)
- return false;
- s->smin = smin;
- s->smax = smax;
- s->area = area;
- s->next = 0;
-
- // Empty cell, add the first span.
- if (!hf.spans[idx])
+ // Create the new span.
+ rcSpan* newSpan = allocSpan(hf);
+ if (newSpan == NULL)
{
- hf.spans[idx] = s;
- return true;
+ return false;
}
- rcSpan* prev = 0;
- rcSpan* cur = hf.spans[idx];
+ newSpan->smin = min;
+ newSpan->smax = max;
+ newSpan->area = areaID;
+ newSpan->next = NULL;
+
+ const int columnIndex = x + z * hf.width;
+ rcSpan* previousSpan = NULL;
+ rcSpan* currentSpan = hf.spans[columnIndex];
- // Insert and merge spans.
- while (cur)
+ // Insert the new span, possibly merging it with existing spans.
+ while (currentSpan != NULL)
{
- if (cur->smin > s->smax)
+ if (currentSpan->smin > newSpan->smax)
{
- // Current span is further than the new span, break.
+ // Current span is completely after the new span, break.
break;
}
- else if (cur->smax < s->smin)
+
+ if (currentSpan->smax < newSpan->smin)
{
- // Current span is before the new span advance.
- prev = cur;
- cur = cur->next;
+ // Current span is completely before the new span. Keep going.
+ previousSpan = currentSpan;
+ currentSpan = currentSpan->next;
}
else
{
- // Merge spans.
- if (cur->smin < s->smin)
- s->smin = cur->smin;
- if (cur->smax > s->smax)
- s->smax = cur->smax;
+ // The new span overlaps with an existing span. Merge them.
+ if (currentSpan->smin < newSpan->smin)
+ {
+ newSpan->smin = currentSpan->smin;
+ }
+ if (currentSpan->smax > newSpan->smax)
+ {
+ newSpan->smax = currentSpan->smax;
+ }
// Merge flags.
- if (rcAbs((int)s->smax - (int)cur->smax) <= flagMergeThr)
- s->area = rcMax(s->area, cur->area);
+ if (rcAbs((int)newSpan->smax - (int)currentSpan->smax) <= flagMergeThreshold)
+ {
+ // Higher area ID numbers indicate higher resolution priority.
+ newSpan->area = rcMax(newSpan->area, currentSpan->area);
+ }
- // Remove current span.
- rcSpan* next = cur->next;
- freeSpan(hf, cur);
- if (prev)
- prev->next = next;
+ // Remove the current span since it's now merged with newSpan.
+ // Keep going because there might be other overlapping spans that also need to be merged.
+ rcSpan* next = currentSpan->next;
+ freeSpan(hf, currentSpan);
+ if (previousSpan)
+ {
+ previousSpan->next = next;
+ }
else
- hf.spans[idx] = next;
- cur = next;
+ {
+ hf.spans[columnIndex] = next;
+ }
+ currentSpan = next;
}
}
- // Insert new span.
- if (prev)
+ // Insert new span after prev
+ if (previousSpan != NULL)
{
- s->next = prev->next;
- prev->next = s;
+ newSpan->next = previousSpan->next;
+ previousSpan->next = newSpan;
}
else
{
- s->next = hf.spans[idx];
- hf.spans[idx] = s;
+ // This span should go before the others in the list
+ newSpan->next = hf.spans[columnIndex];
+ hf.spans[columnIndex] = newSpan;
}
return true;
}
-/// @par
-///
-/// The span addition can be set to favor flags. If the span is merged to
-/// another span and the new @p smax is within @p flagMergeThr units
-/// from the existing span, the span flags are merged.
-///
-/// @see rcHeightfield, rcSpan.
-bool rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y,
- const unsigned short smin, const unsigned short smax,
- const unsigned char area, const int flagMergeThr)
+bool rcAddSpan(rcContext* context, rcHeightfield& heightfield,
+ const int x, const int z,
+ const unsigned short spanMin, const unsigned short spanMax,
+ const unsigned char areaID, const int flagMergeThreshold)
{
- rcAssert(ctx);
+ rcAssert(context);
- if (!addSpan(hf, x, y, smin, smax, area, flagMergeThr))
+ if (!addSpan(heightfield, x, z, spanMin, spanMax, areaID, flagMergeThreshold))
{
- ctx->log(RC_LOG_ERROR, "rcAddSpan: Out of memory.");
+ context->log(RC_LOG_ERROR, "rcAddSpan: Out of memory.");
return false;
}
return true;
}
-// divides a convex polygons into two convex polygons on both sides of a line
-static void dividePoly(const float* in, int nin,
- float* out1, int* nout1,
- float* out2, int* nout2,
- float x, int axis)
+enum rcAxis
+{
+ RC_AXIS_X = 0,
+ RC_AXIS_Y = 1,
+ RC_AXIS_Z = 2
+};
+
+/// Divides a convex polygon of max 12 vertices into two convex polygons
+/// across a separating axis.
+///
+/// @param[in] inVerts The input polygon vertices
+/// @param[in] inVertsCount The number of input polygon vertices
+/// @param[out] outVerts1 Resulting polygon 1's vertices
+/// @param[out] outVerts1Count The number of resulting polygon 1 vertices
+/// @param[out] outVerts2 Resulting polygon 2's vertices
+/// @param[out] outVerts2Count The number of resulting polygon 2 vertices
+/// @param[in] axisOffset THe offset along the specified axis
+/// @param[in] axis The separating axis
+static void dividePoly(const float* inVerts, int inVertsCount,
+ float* outVerts1, int* outVerts1Count,
+ float* outVerts2, int* outVerts2Count,
+ float axisOffset, rcAxis axis)
{
- float d[12];
- for (int i = 0; i < nin; ++i)
- d[i] = x - in[i*3+axis];
+ rcAssert(inVertsCount <= 12);
+
+ // How far positive or negative away from the separating axis is each vertex.
+ float inVertAxisDelta[12];
+ for (int inVert = 0; inVert < inVertsCount; ++inVert)
+ {
+ inVertAxisDelta[inVert] = axisOffset - inVerts[inVert * 3 + axis];
+ }
- int m = 0, n = 0;
- for (int i = 0, j = nin-1; i < nin; j=i, ++i)
+ int poly1Vert = 0;
+ int poly2Vert = 0;
+ for (int inVertA = 0, inVertB = inVertsCount - 1; inVertA < inVertsCount; inVertB = inVertA, ++inVertA)
{
- bool ina = d[j] >= 0;
- bool inb = d[i] >= 0;
- if (ina != inb)
+ // If the two vertices are on the same side of the separating axis
+ bool sameSide = (inVertAxisDelta[inVertA] >= 0) == (inVertAxisDelta[inVertB] >= 0);
+
+ if (!sameSide)
{
- float s = d[j] / (d[j] - d[i]);
- out1[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
- out1[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
- out1[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
- rcVcopy(out2 + n*3, out1 + m*3);
- m++;
- n++;
- // add the i'th point to the right polygon. Do NOT add points that are on the dividing line
+ float s = inVertAxisDelta[inVertB] / (inVertAxisDelta[inVertB] - inVertAxisDelta[inVertA]);
+ outVerts1[poly1Vert * 3 + 0] = inVerts[inVertB * 3 + 0] + (inVerts[inVertA * 3 + 0] - inVerts[inVertB * 3 + 0]) * s;
+ outVerts1[poly1Vert * 3 + 1] = inVerts[inVertB * 3 + 1] + (inVerts[inVertA * 3 + 1] - inVerts[inVertB * 3 + 1]) * s;
+ outVerts1[poly1Vert * 3 + 2] = inVerts[inVertB * 3 + 2] + (inVerts[inVertA * 3 + 2] - inVerts[inVertB * 3 + 2]) * s;
+ rcVcopy(&outVerts2[poly2Vert * 3], &outVerts1[poly1Vert * 3]);
+ poly1Vert++;
+ poly2Vert++;
+
+ // add the inVertA point to the right polygon. Do NOT add points that are on the dividing line
// since these were already added above
- if (d[i] > 0)
+ if (inVertAxisDelta[inVertA] > 0)
{
- rcVcopy(out1 + m*3, in + i*3);
- m++;
+ rcVcopy(&outVerts1[poly1Vert * 3], &inVerts[inVertA * 3]);
+ poly1Vert++;
}
- else if (d[i] < 0)
+ else if (inVertAxisDelta[inVertA] < 0)
{
- rcVcopy(out2 + n*3, in + i*3);
- n++;
+ rcVcopy(&outVerts2[poly2Vert * 3], &inVerts[inVertA * 3]);
+ poly2Vert++;
}
}
- else // same side
+ else
{
- // add the i'th point to the right polygon. Addition is done even for points on the dividing line
- if (d[i] >= 0)
+ // add the inVertA point to the right polygon. Addition is done even for points on the dividing line
+ if (inVertAxisDelta[inVertA] >= 0)
{
- rcVcopy(out1 + m*3, in + i*3);
- m++;
- if (d[i] != 0)
+ rcVcopy(&outVerts1[poly1Vert * 3], &inVerts[inVertA * 3]);
+ poly1Vert++;
+ if (inVertAxisDelta[inVertA] != 0)
+ {
continue;
+ }
}
- rcVcopy(out2 + n*3, in + i*3);
- n++;
+ rcVcopy(&outVerts2[poly2Vert * 3], &inVerts[inVertA * 3]);
+ poly2Vert++;
}
}
- *nout1 = m;
- *nout2 = n;
+ *outVerts1Count = poly1Vert;
+ *outVerts2Count = poly2Vert;
}
-
-
+/// Rasterize a single triangle to the heightfield.
+///
+/// This code is extremely hot, so much care should be given to maintaining maximum perf here.
+///
+/// @param[in] v0 Triangle vertex 0
+/// @param[in] v1 Triangle vertex 1
+/// @param[in] v2 Triangle vertex 2
+/// @param[in] areaID The area ID to assign to the rasterized spans
+/// @param[in] hf Heightfield to rasterize into
+/// @param[in] hfBBMin The min extents of the heightfield bounding box
+/// @param[in] hfBBMax The max extents of the heightfield bounding box
+/// @param[in] cellSize The x and z axis size of a voxel in the heightfield
+/// @param[in] inverseCellSize 1 / cellSize
+/// @param[in] inverseCellHeight 1 / cellHeight
+/// @param[in] flagMergeThreshold The threshold in which area flags will be merged
+/// @returns true if the operation completes successfully. false if there was an error adding spans to the heightfield.
static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
- const unsigned char area, rcHeightfield& hf,
- const float* bmin, const float* bmax,
- const float cs, const float ics, const float ich,
- const int flagMergeThr)
+ const unsigned char areaID, rcHeightfield& hf,
+ const float* hfBBMin, const float* hfBBMax,
+ const float cellSize, const float inverseCellSize, const float inverseCellHeight,
+ const int flagMergeThreshold)
{
- const int w = hf.width;
- const int h = hf.height;
- float tmin[3], tmax[3];
- const float by = bmax[1] - bmin[1];
-
// Calculate the bounding box of the triangle.
- rcVcopy(tmin, v0);
- rcVcopy(tmax, v0);
- rcVmin(tmin, v1);
- rcVmin(tmin, v2);
- rcVmax(tmax, v1);
- rcVmax(tmax, v2);
-
- // If the triangle does not touch the bbox of the heightfield, skip the triagle.
- if (!overlapBounds(bmin, bmax, tmin, tmax))
+ float triBBMin[3];
+ rcVcopy(triBBMin, v0);
+ rcVmin(triBBMin, v1);
+ rcVmin(triBBMin, v2);
+
+ float triBBMax[3];
+ rcVcopy(triBBMax, v0);
+ rcVmax(triBBMax, v1);
+ rcVmax(triBBMax, v2);
+
+ // If the triangle does not touch the bounding box of the heightfield, skip the triangle.
+ if (!overlapBounds(triBBMin, triBBMax, hfBBMin, hfBBMax))
+ {
return true;
-
- // Calculate the footprint of the triangle on the grid's y-axis
- int y0 = (int)((tmin[2] - bmin[2])*ics);
- int y1 = (int)((tmax[2] - bmin[2])*ics);
+ }
+
+ const int w = hf.width;
+ const int h = hf.height;
+ const float by = hfBBMax[1] - hfBBMin[1];
+
+ // Calculate the footprint of the triangle on the grid's z-axis
+ int z0 = (int)((triBBMin[2] - hfBBMin[2]) * inverseCellSize);
+ int z1 = (int)((triBBMax[2] - hfBBMin[2]) * inverseCellSize);
+
// use -1 rather than 0 to cut the polygon properly at the start of the tile
- y0 = rcClamp(y0, -1, h-1);
- y1 = rcClamp(y1, 0, h-1);
-
+ z0 = rcClamp(z0, -1, h - 1);
+ z1 = rcClamp(z1, 0, h - 1);
+
// Clip the triangle into all grid cells it touches.
- float buf[7*3*4];
- float *in = buf, *inrow = buf+7*3, *p1 = inrow+7*3, *p2 = p1+7*3;
+ float buf[7 * 3 * 4];
+ float* in = buf;
+ float* inRow = buf + 7 * 3;
+ float* p1 = inRow + 7 * 3;
+ float* p2 = p1 + 7 * 3;
rcVcopy(&in[0], v0);
- rcVcopy(&in[1*3], v1);
- rcVcopy(&in[2*3], v2);
- int nvrow, nvIn = 3;
-
- for (int y = y0; y <= y1; ++y)
+ rcVcopy(&in[1 * 3], v1);
+ rcVcopy(&in[2 * 3], v2);
+ int nvRow;
+ int nvIn = 3;
+
+ for (int z = z0; z <= z1; ++z)
{
// Clip polygon to row. Store the remaining polygon as well
- const float cz = bmin[2] + y*cs;
- dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2);
+ const float cellZ = hfBBMin[2] + (float)z * cellSize;
+ dividePoly(in, nvIn, inRow, &nvRow, p1, &nvIn, cellZ + cellSize, RC_AXIS_Z);
rcSwap(in, p1);
- if (nvrow < 3) continue;
- if (y < 0) continue;
- // find the horizontal bounds in the row
- float minX = inrow[0], maxX = inrow[0];
- for (int i=1; i<nvrow; ++i)
+
+ if (nvRow < 3)
{
- if (minX > inrow[i*3]) minX = inrow[i*3];
- if (maxX < inrow[i*3]) maxX = inrow[i*3];
+ continue;
}
- int x0 = (int)((minX - bmin[0])*ics);
- int x1 = (int)((maxX - bmin[0])*ics);
- if (x1 < 0 || x0 >= w) {
+ if (z < 0)
+ {
continue;
}
- x0 = rcClamp(x0, -1, w-1);
- x1 = rcClamp(x1, 0, w-1);
+
+ // find X-axis bounds of the row
+ float minX = inRow[0];
+ float maxX = inRow[0];
+ for (int vert = 1; vert < nvRow; ++vert)
+ {
+ if (minX > inRow[vert * 3])
+ {
+ minX = inRow[vert * 3];
+ }
+ if (maxX < inRow[vert * 3])
+ {
+ maxX = inRow[vert * 3];
+ }
+ }
+ int x0 = (int)((minX - hfBBMin[0]) * inverseCellSize);
+ int x1 = (int)((maxX - hfBBMin[0]) * inverseCellSize);
+ if (x1 < 0 || x0 >= w)
+ {
+ continue;
+ }
+ x0 = rcClamp(x0, -1, w - 1);
+ x1 = rcClamp(x1, 0, w - 1);
- int nv, nv2 = nvrow;
+ int nv;
+ int nv2 = nvRow;
for (int x = x0; x <= x1; ++x)
{
// Clip polygon to column. store the remaining polygon as well
- const float cx = bmin[0] + x*cs;
- dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
- rcSwap(inrow, p2);
- if (nv < 3) continue;
- if (x < 0) continue;
+ const float cx = hfBBMin[0] + (float)x * cellSize;
+ dividePoly(inRow, nv2, p1, &nv, p2, &nv2, cx + cellSize, RC_AXIS_X);
+ rcSwap(inRow, p2);
+
+ if (nv < 3)
+ {
+ continue;
+ }
+ if (x < 0)
+ {
+ continue;
+ }
+
// Calculate min and max of the span.
- float smin = p1[1], smax = p1[1];
- for (int i = 1; i < nv; ++i)
+ float spanMin = p1[1];
+ float spanMax = p1[1];
+ for (int vert = 1; vert < nv; ++vert)
{
- smin = rcMin(smin, p1[i*3+1]);
- smax = rcMax(smax, p1[i*3+1]);
+ spanMin = rcMin(spanMin, p1[vert * 3 + 1]);
+ spanMax = rcMax(spanMax, p1[vert * 3 + 1]);
}
- smin -= bmin[1];
- smax -= bmin[1];
- // Skip the span if it is outside the heightfield bbox
- if (smax < 0.0f) continue;
- if (smin > by) continue;
- // Clamp the span to the heightfield bbox.
- if (smin < 0.0f) smin = 0;
- if (smax > by) smax = by;
+ spanMin -= hfBBMin[1];
+ spanMax -= hfBBMin[1];
- // Snap the span to the heightfield height grid.
- unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
- unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);
+ // Skip the span if it's completely outside the heightfield bounding box
+ if (spanMax < 0.0f)
+ {
+ continue;
+ }
+ if (spanMin > by)
+ {
+ continue;
+ }
- if (!addSpan(hf, x, y, ismin, ismax, area, flagMergeThr))
+ // Clamp the span to the heightfield bounding box.
+ if (spanMin < 0.0f)
+ {
+ spanMin = 0;
+ }
+ if (spanMax > by)
+ {
+ spanMax = by;
+ }
+
+ // Snap the span to the heightfield height grid.
+ unsigned short spanMinCellIndex = (unsigned short)rcClamp((int)floorf(spanMin * inverseCellHeight), 0, RC_SPAN_MAX_HEIGHT);
+ unsigned short spanMaxCellIndex = (unsigned short)rcClamp((int)ceilf(spanMax * inverseCellHeight), (int)spanMinCellIndex + 1, RC_SPAN_MAX_HEIGHT);
+
+ if (!addSpan(hf, x, z, spanMinCellIndex, spanMaxCellIndex, areaID, flagMergeThreshold))
+ {
return false;
+ }
}
}
return true;
}
-/// @par
-///
-/// No spans will be added if the triangle does not overlap the heightfield grid.
-///
-/// @see rcHeightfield
-bool rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
- const unsigned char area, rcHeightfield& solid,
- const int flagMergeThr)
+bool rcRasterizeTriangle(rcContext* context,
+ const float* v0, const float* v1, const float* v2,
+ const unsigned char areaID, rcHeightfield& heightfield, const int flagMergeThreshold)
{
- rcAssert(ctx);
+ rcAssert(context != NULL);
- rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
+ rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
- const float ics = 1.0f/solid.cs;
- const float ich = 1.0f/solid.ch;
- if (!rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
+ // Rasterize the single triangle.
+ const float inverseCellSize = 1.0f / heightfield.cs;
+ const float inverseCellHeight = 1.0f / heightfield.ch;
+ if (!rasterizeTri(v0, v1, v2, areaID, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
{
- ctx->log(RC_LOG_ERROR, "rcRasterizeTriangle: Out of memory.");
+ context->log(RC_LOG_ERROR, "rcRasterizeTriangle: Out of memory.");
return false;
}
return true;
}
-/// @par
-///
-/// Spans will only be added for triangles that overlap the heightfield grid.
-///
-/// @see rcHeightfield
-bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
- const int* tris, const unsigned char* areas, const int nt,
- rcHeightfield& solid, const int flagMergeThr)
+bool rcRasterizeTriangles(rcContext* context,
+ const float* verts, const int /*nv*/,
+ const int* tris, const unsigned char* triAreaIDs, const int numTris,
+ rcHeightfield& heightfield, const int flagMergeThreshold)
{
- rcAssert(ctx);
+ rcAssert(context != NULL);
- rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
+ rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
- const float ics = 1.0f/solid.cs;
- const float ich = 1.0f/solid.ch;
- // Rasterize triangles.
- for (int i = 0; i < nt; ++i)
+ // Rasterize the triangles.
+ const float inverseCellSize = 1.0f / heightfield.cs;
+ const float inverseCellHeight = 1.0f / heightfield.ch;
+ for (int triIndex = 0; triIndex < numTris; ++triIndex)
{
- const float* v0 = &verts[tris[i*3+0]*3];
- const float* v1 = &verts[tris[i*3+1]*3];
- const float* v2 = &verts[tris[i*3+2]*3];
- // Rasterize.
- if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
+ const float* v0 = &verts[tris[triIndex * 3 + 0] * 3];
+ const float* v1 = &verts[tris[triIndex * 3 + 1] * 3];
+ const float* v2 = &verts[tris[triIndex * 3 + 2] * 3];
+ if (!rasterizeTri(v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
{
- ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
+ context->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
return false;
}
}
@@ -394,31 +502,26 @@ bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
return true;
}
-/// @par
-///
-/// Spans will only be added for triangles that overlap the heightfield grid.
-///
-/// @see rcHeightfield
-bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
- const unsigned short* tris, const unsigned char* areas, const int nt,
- rcHeightfield& solid, const int flagMergeThr)
+bool rcRasterizeTriangles(rcContext* context,
+ const float* verts, const int /*nv*/,
+ const unsigned short* tris, const unsigned char* triAreaIDs, const int numTris,
+ rcHeightfield& heightfield, const int flagMergeThreshold)
{
- rcAssert(ctx);
+ rcAssert(context != NULL);
- rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
-
- const float ics = 1.0f/solid.cs;
- const float ich = 1.0f/solid.ch;
- // Rasterize triangles.
- for (int i = 0; i < nt; ++i)
+ rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
+
+ // Rasterize the triangles.
+ const float inverseCellSize = 1.0f / heightfield.cs;
+ const float inverseCellHeight = 1.0f / heightfield.ch;
+ for (int triIndex = 0; triIndex < numTris; ++triIndex)
{
- const float* v0 = &verts[tris[i*3+0]*3];
- const float* v1 = &verts[tris[i*3+1]*3];
- const float* v2 = &verts[tris[i*3+2]*3];
- // Rasterize.
- if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
+ const float* v0 = &verts[tris[triIndex * 3 + 0] * 3];
+ const float* v1 = &verts[tris[triIndex * 3 + 1] * 3];
+ const float* v2 = &verts[tris[triIndex * 3 + 2] * 3];
+ if (!rasterizeTri(v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
{
- ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
+ context->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
return false;
}
}
@@ -426,30 +529,25 @@ bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
return true;
}
-/// @par
-///
-/// Spans will only be added for triangles that overlap the heightfield grid.
-///
-/// @see rcHeightfield
-bool rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
- rcHeightfield& solid, const int flagMergeThr)
+bool rcRasterizeTriangles(rcContext* context,
+ const float* verts, const unsigned char* triAreaIDs, const int numTris,
+ rcHeightfield& heightfield, const int flagMergeThreshold)
{
- rcAssert(ctx);
-
- rcScopedTimer timer(ctx, RC_TIMER_RASTERIZE_TRIANGLES);
+ rcAssert(context != NULL);
+
+ rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
- const float ics = 1.0f/solid.cs;
- const float ich = 1.0f/solid.ch;
- // Rasterize triangles.
- for (int i = 0; i < nt; ++i)
+ // Rasterize the triangles.
+ const float inverseCellSize = 1.0f / heightfield.cs;
+ const float inverseCellHeight = 1.0f / heightfield.ch;
+ for (int triIndex = 0; triIndex < numTris; ++triIndex)
{
- const float* v0 = &verts[(i*3+0)*3];
- const float* v1 = &verts[(i*3+1)*3];
- const float* v2 = &verts[(i*3+2)*3];
- // Rasterize.
- if (!rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr))
+ const float* v0 = &verts[(triIndex * 3 + 0) * 3];
+ const float* v1 = &verts[(triIndex * 3 + 1) * 3];
+ const float* v2 = &verts[(triIndex * 3 + 2) * 3];
+ if (!rasterizeTri(v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
{
- ctx->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
+ context->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
return false;
}
}
diff --git a/thirdparty/recastnavigation/Recast/Source/RecastRegion.cpp b/thirdparty/recastnavigation/Recast/Source/RecastRegion.cpp
index 48318688bc..4a7e841a92 100644
--- a/thirdparty/recastnavigation/Recast/Source/RecastRegion.cpp
+++ b/thirdparty/recastnavigation/Recast/Source/RecastRegion.cpp
@@ -17,7 +17,6 @@
//
#include <float.h>
-#define _USE_MATH_DEFINES
#include <math.h>
#include <string.h>
#include <stdlib.h>