From a6b4e0855ceeee3bf8860c84bfe569c3474bdba0 Mon Sep 17 00:00:00 2001 From: Vstar Date: Tue, 5 Nov 2013 07:05:00 +0800 Subject: [Info] MMaps rollback to the previous version Subject: [Type] Function Subject: [From] Nothing Subject: [Work] Unknown Subject: [BUG] Unknown Subject: [Code] NO --- dep/recastnavigation/Detour/DetourAlloc.h | 27 +- dep/recastnavigation/Detour/DetourAssert.h | 2 +- dep/recastnavigation/Detour/DetourCommon.cpp | 64 - dep/recastnavigation/Detour/DetourCommon.h | 338 +----- dep/recastnavigation/Detour/DetourNavMesh.cpp | 573 +++------ dep/recastnavigation/Detour/DetourNavMesh.h | 710 ++++------- .../Detour/DetourNavMeshBuilder.cpp | 356 +++--- dep/recastnavigation/Detour/DetourNavMeshBuilder.h | 157 +-- dep/recastnavigation/Detour/DetourNavMeshQuery.cpp | 1265 ++++---------------- dep/recastnavigation/Detour/DetourNavMeshQuery.h | 591 ++++----- dep/recastnavigation/Detour/DetourNode.cpp | 17 +- dep/recastnavigation/Detour/DetourNode.h | 32 +- dep/recastnavigation/Detour/DetourStatus.h | 64 - dep/recastnavigation/Recast/CMakeLists.txt | 1 - dep/recastnavigation/Recast/Recast.cpp | 80 +- dep/recastnavigation/Recast/Recast.h | 1180 ++++++------------ dep/recastnavigation/Recast/RecastAlloc.cpp | 21 - dep/recastnavigation/Recast/RecastAlloc.h | 65 +- dep/recastnavigation/Recast/RecastArea.cpp | 199 +-- dep/recastnavigation/Recast/RecastAssert.h | 2 +- dep/recastnavigation/Recast/RecastContour.cpp | 75 +- dep/recastnavigation/Recast/RecastFilter.cpp | 34 +- dep/recastnavigation/Recast/RecastLayers.cpp | 620 ---------- dep/recastnavigation/Recast/RecastMesh.cpp | 128 +- dep/recastnavigation/Recast/RecastMeshDetail.cpp | 40 +- .../Recast/RecastRasterization.cpp | 27 - dep/recastnavigation/Recast/RecastRegion.cpp | 116 +- src/server/collision/Management/MMapManager.cpp | 10 +- src/server/game/Grids/GridDefines.h | 2 +- src/server/game/Miscellaneous/SharedDefines.h | 2 +- src/server/game/Movement/PathGenerator.cpp | 34 +- src/server/scripts/Commands/cs_mmaps.cpp | 21 +- src/tools/mmaps_generator/Info/readme.txt | 4 +- src/tools/mmaps_generator/MapBuilder.cpp | 235 ++-- src/tools/mmaps_generator/MapBuilder.h | 2 +- src/tools/mmaps_generator/PathCommon.h | 1 + src/tools/mmaps_generator/PathGenerator.cpp | 4 +- src/tools/mmaps_generator/TerrainBuilder.cpp | 6 +- src/tools/mmaps_generator/TerrainBuilder.h | 2 +- 39 files changed, 1715 insertions(+), 5392 deletions(-) delete mode 100644 dep/recastnavigation/Detour/DetourStatus.h delete mode 100644 dep/recastnavigation/Recast/RecastLayers.cpp diff --git a/dep/recastnavigation/Detour/DetourAlloc.h b/dep/recastnavigation/Detour/DetourAlloc.h index e814b62..8693475 100644 --- a/dep/recastnavigation/Detour/DetourAlloc.h +++ b/dep/recastnavigation/Detour/DetourAlloc.h @@ -19,41 +19,18 @@ #ifndef DETOURALLOCATOR_H #define DETOURALLOCATOR_H -/// Provides hint values to the memory allocator on how long the -/// memory is expected to be used. enum dtAllocHint { - DT_ALLOC_PERM, ///< Memory persist after a function call. - DT_ALLOC_TEMP ///< Memory used temporarily within a function. + DT_ALLOC_PERM, // Memory persist after a function call. + DT_ALLOC_TEMP // Memory used temporarily within a function. }; -/// A memory allocation function. -// @param[in] size The size, in bytes of memory, to allocate. -// @param[in] rcAllocHint 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 dtAllocSetCustom typedef void* (dtAllocFunc)(int size, dtAllocHint hint); - -/// A memory deallocation function. -/// @param[in] ptr A pointer to a memory block previously allocated using #dtAllocFunc. -/// @see dtAllocSetCustom typedef void (dtFreeFunc)(void* ptr); -/// Sets the base custom allocation functions to be used by Detour. -/// @param[in] allocFunc The memory allocation function to be used by #dtAlloc -/// @param[in] freeFunc The memory de-allocation function to be used by #dtFree void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *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 dtFree void* dtAlloc(int size, dtAllocHint hint); - -/// Deallocates a memory block. -/// @param[in] ptr A pointer to a memory block previously allocated using #dtAlloc. -/// @see dtAlloc void dtFree(void* ptr); #endif diff --git a/dep/recastnavigation/Detour/DetourAssert.h b/dep/recastnavigation/Detour/DetourAssert.h index 3cf6522..709ebd9 100644 --- a/dep/recastnavigation/Detour/DetourAssert.h +++ b/dep/recastnavigation/Detour/DetourAssert.h @@ -24,7 +24,7 @@ #ifdef NDEBUG // From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/ -# define dtAssert(x) do { (void)sizeof(x); } while((void)(__LINE__==-1),false) +# define dtAssert(x) do { (void)sizeof(x); } while(__LINE__==-1,false) #else # include # define dtAssert assert diff --git a/dep/recastnavigation/Detour/DetourCommon.cpp b/dep/recastnavigation/Detour/DetourCommon.cpp index b5700f5..c0b973e 100644 --- a/dep/recastnavigation/Detour/DetourCommon.cpp +++ b/dep/recastnavigation/Detour/DetourCommon.cpp @@ -238,9 +238,6 @@ bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b return false; } -/// @par -/// -/// All points are projected onto the xz-plane, so the y-values are ignored. bool dtPointInPolygon(const float* pt, const float* verts, const int nverts) { // TODO: Replace pnpoly with triArea2D tests? @@ -294,9 +291,6 @@ inline bool overlapRange(const float amin, const float amax, return ((amin+eps) > bmax || (amax-eps) < bmin) ? false : true; } -/// @par -/// -/// All vertices are projected onto the xz-plane, so the y-values are ignored. bool dtOverlapPolyPoly2D(const float* polya, const int npolya, const float* polyb, const int npolyb) { @@ -333,61 +327,3 @@ bool dtOverlapPolyPoly2D(const float* polya, const int npolya, return true; } -// Returns a random point in a convex polygon. -// Adapted from Graphics Gems article. -void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas, - const float s, const float t, float* out) -{ - // Calc triangle araes - float areasum = 0.0f; - for (int i = 2; i < npts; i++) { - areas[i] = dtTriArea2D(&pts[0], &pts[(i-1)*3], &pts[i*3]); - areasum += dtMax(0.001f, areas[i]); - } - // Find sub triangle weighted by area. - const float thr = s*areasum; - float acc = 0.0f; - float u = 0.0f; - int tri = 0; - for (int i = 2; i < npts; i++) { - const float dacc = areas[i]; - if (thr >= acc && thr < (acc+dacc)) - { - u = (thr - acc) / dacc; - tri = i; - break; - } - acc += dacc; - } - - float v = dtSqrt(t); - - const float a = 1 - v; - const float b = (1 - u) * v; - const float c = u * v; - const float* pa = &pts[0]; - const float* pb = &pts[(tri-1)*3]; - const float* pc = &pts[tri*3]; - - out[0] = a*pa[0] + b*pb[0] + c*pc[0]; - out[1] = a*pa[1] + b*pb[1] + c*pc[1]; - out[2] = a*pa[2] + b*pb[2] + c*pc[2]; -} - -inline float vperpXZ(const float* a, const float* b) { return a[0]*b[2] - a[2]*b[0]; } - -bool dtIntersectSegSeg2D(const float* ap, const float* aq, - const float* bp, const float* bq, - float& s, float& t) -{ - float u[3], v[3], w[3]; - dtVsub(u,aq,ap); - dtVsub(v,bq,bp); - dtVsub(w,ap,bp); - float d = vperpXZ(u,v); - if (fabsf(d) < 1e-6f) return false; - s = vperpXZ(v,w) / d; - t = vperpXZ(u,w) / d; - return true; -} - diff --git a/dep/recastnavigation/Detour/DetourCommon.h b/dep/recastnavigation/Detour/DetourCommon.h index ed7c514..3cee3f6 100644 --- a/dep/recastnavigation/Detour/DetourCommon.h +++ b/dep/recastnavigation/Detour/DetourCommon.h @@ -19,66 +19,15 @@ #ifndef DETOURCOMMON_H #define DETOURCOMMON_H -/** -@defgroup detour Detour - -Members in this module are used to create, manipulate, and query navigation -meshes. - -@note This is a summary list of members. Use the index or search -feature to find minor members. -*/ - -/// @name General helper functions -/// @{ - -/// Swaps the values of the two parameters. -/// @param[in,out] a Value A -/// @param[in,out] b Value B template inline void dtSwap(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. template inline T dtMin(T a, T b) { return a < b ? a : b; } - -/// Returns the maximum of two values. -/// @param[in] a Value A -/// @param[in] b Value B -/// @return The maximum of the two values. template inline T dtMax(T a, T b) { return a > b ? a : b; } - -/// Returns the absolute value. -/// @param[in] a The value. -/// @return The absolute value of the specified value. template inline T dtAbs(T a) { return a < 0 ? -a : a; } - -/// Returns the square of the value. -/// @param[in] a The value. -/// @return The square of the value. template inline T dtSqr(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 inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); } -/// Returns the square root of the value. -/// @param[in] x The value. -/// @return The square root of the vlaue. float dtSqrt(float x); -/// @} -/// @name Vector helper functions. -/// @{ - -/// Derives the cross product of two vectors. (@p v1 x @p v2) -/// @param[out] dest The cross product. [(x, y, z)] -/// @param[in] v1 A Vector [(x, y, z)] -/// @param[in] v2 A vector [(x, y, z)] inline void dtVcross(float* dest, const float* v1, const float* v2) { dest[0] = v1[1]*v2[2] - v1[2]*v2[1]; @@ -86,20 +35,11 @@ inline void dtVcross(float* dest, const float* v1, const float* v2) dest[2] = v1[0]*v2[1] - v1[1]*v2[0]; } -/// Derives the dot product of two vectors. (@p v1 . @p v2) -/// @param[in] v1 A Vector [(x, y, z)] -/// @param[in] v2 A vector [(x, y, z)] -/// @return The dot product. inline float dtVdot(const float* v1, const float* v2) { return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; } -/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s)) -/// @param[out] dest The result vector. [(x, y, z)] -/// @param[in] v1 The base vector. [(x, y, z)] -/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)] -/// @param[in] s The amount to scale @p v2 by before adding to @p v1. inline void dtVmad(float* dest, const float* v1, const float* v2, const float s) { dest[0] = v1[0]+v2[0]*s; @@ -107,11 +47,6 @@ inline void dtVmad(float* dest, const float* v1, const float* v2, const float s) dest[2] = v1[2]+v2[2]*s; } -/// Performs a linear interpolation between two vectors. (@p v1 toward @p v2) -/// @param[out] dest The result vector. [(x, y, x)] -/// @param[in] v1 The starting vector. -/// @param[in] v2 The destination vector. -/// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0] inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t) { dest[0] = v1[0]+(v2[0]-v1[0])*t; @@ -119,10 +54,6 @@ inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t dest[2] = v1[2]+(v2[2]-v1[2])*t; } -/// 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)] inline void dtVadd(float* dest, const float* v1, const float* v2) { dest[0] = v1[0]+v2[0]; @@ -130,10 +61,6 @@ inline void dtVadd(float* dest, const float* v1, const float* v2) dest[2] = v1[2]+v2[2]; } -/// Performs a vector subtraction. (@p v1 - @p v2) -/// @param[out] dest The result vector. [(x, y, z)] -/// @param[in] v1 The base vector. [(x, y, z)] -/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)] inline void dtVsub(float* dest, const float* v1, const float* v2) { dest[0] = v1[0]-v2[0]; @@ -141,10 +68,6 @@ inline void dtVsub(float* dest, const float* v1, const float* v2) dest[2] = v1[2]-v2[2]; } -/// Scales the vector by the specified value. (@p v * @p t) -/// @param[out] dest The result vector. [(x, y, z)] -/// @param[in] v The vector to scale. [(x, y, z)] -/// @param[in] t The scaling factor. inline void dtVscale(float* dest, const float* v, const float t) { dest[0] = v[0]*t; @@ -152,9 +75,6 @@ inline void dtVscale(float* dest, const float* v, const float t) dest[2] = v[2]*t; } -/// 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)] inline void dtVmin(float* mn, const float* v) { mn[0] = dtMin(mn[0], v[0]); @@ -162,9 +82,6 @@ inline void dtVmin(float* mn, const float* v) mn[2] = dtMin(mn[2], v[2]); } -/// 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)] inline void dtVmax(float* mx, const float* v) { mx[0] = dtMax(mx[0], v[0]); @@ -172,19 +89,11 @@ inline void dtVmax(float* mx, const float* v) mx[2] = dtMax(mx[2], v[2]); } -/// Sets the vector elements to the specified values. -/// @param[out] dest The result vector. [(x, y, z)] -/// @param[in] x The x-value of the vector. -/// @param[in] y The y-value of the vector. -/// @param[in] z The z-value of the vector. inline void dtVset(float* dest, const float x, const float y, const float z) { dest[0] = x; dest[1] = y; dest[2] = z; } -/// Performs a vector copy. -/// @param[out] dest The result. [(x, y, z)] -/// @param[in] a The vector to copy. [(x, y, z)] inline void dtVcopy(float* dest, const float* a) { dest[0] = a[0]; @@ -192,26 +101,16 @@ inline void dtVcopy(float* dest, const float* a) dest[2] = a[2]; } -/// Derives the scalar length of the vector. -/// @param[in] v The vector. [(x, y, z)] -/// @return The scalar length of the vector. inline float dtVlen(const float* v) { return dtSqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); } -/// Derives the square of the scalar length of the vector. (len * len) -/// @param[in] v The vector. [(x, y, z)] -/// @return The square of the scalar length of the vector. inline float dtVlenSqr(const float* v) { return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; } -/// Returns the distance between two points. -/// @param[in] v1 A point. [(x, y, z)] -/// @param[in] v2 A point. [(x, y, z)] -/// @return The distance between the two points. inline float dtVdist(const float* v1, const float* v2) { const float dx = v2[0] - v1[0]; @@ -220,10 +119,6 @@ inline float dtVdist(const float* v1, const float* v2) return dtSqrt(dx*dx + dy*dy + dz*dz); } -/// Returns the square of the distance between two points. -/// @param[in] v1 A point. [(x, y, z)] -/// @param[in] v2 A point. [(x, y, z)] -/// @return The square of the distance between the two points. inline float dtVdistSqr(const float* v1, const float* v2) { const float dx = v2[0] - v1[0]; @@ -232,12 +127,6 @@ inline float dtVdistSqr(const float* v1, const float* v2) return dx*dx + dy*dy + dz*dz; } -/// Derives the distance between the specified points on the xz-plane. -/// @param[in] v1 A point. [(x, y, z)] -/// @param[in] v2 A point. [(x, y, z)] -/// @return The distance between the point on the xz-plane. -/// -/// The vectors are projected onto the xz-plane, so the y-values are ignored. inline float dtVdist2D(const float* v1, const float* v2) { const float dx = v2[0] - v1[0]; @@ -245,10 +134,6 @@ inline float dtVdist2D(const float* v1, const float* v2) return dtSqrt(dx*dx + dz*dz); } -/// Derives the square of the distance between the specified points on the xz-plane. -/// @param[in] v1 A point. [(x, y, z)] -/// @param[in] v2 A point. [(x, y, z)] -/// @return The square of the distance between the point on the xz-plane. inline float dtVdist2DSqr(const float* v1, const float* v2) { const float dx = v2[0] - v1[0]; @@ -256,8 +141,6 @@ inline float dtVdist2DSqr(const float* v1, const float* v2) return dx*dx + dz*dz; } -/// Normalizes the vector. -/// @param[in,out] v The vector to normalize. [(x, y, z)] inline void dtVnormalize(float* v) { float d = 1.0f / dtSqrt(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2])); @@ -266,13 +149,6 @@ inline void dtVnormalize(float* v) v[2] *= d; } -/// Performs a 'sloppy' colocation check of the specified points. -/// @param[in] p0 A point. [(x, y, z)] -/// @param[in] p1 A point. [(x, y, z)] -/// @return True if the points are considered to be at the same location. -/// -/// Basically, this function will return true if the specified points are -/// close enough to eachother to be considered colocated. inline bool dtVequal(const float* p0, const float* p1) { static const float thr = dtSqr(1.0f/16384.0f); @@ -280,37 +156,44 @@ inline bool dtVequal(const float* p0, const float* p1) return d < thr; } -/// Derives the dot product of two vectors on the xz-plane. (@p u . @p v) -/// @param[in] u A vector [(x, y, z)] -/// @param[in] v A vector [(x, y, z)] -/// @return The dot product on the xz-plane. -/// -/// The vectors are projected onto the xz-plane, so the y-values are ignored. +inline unsigned int dtNextPow2(unsigned int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +inline unsigned int dtIlog2(unsigned int v) +{ + unsigned int r; + unsigned int shift; + r = (v > 0xffff) << 4; v >>= r; + shift = (v > 0xff) << 3; v >>= shift; r |= shift; + shift = (v > 0xf) << 2; v >>= shift; r |= shift; + shift = (v > 0x3) << 1; v >>= shift; r |= shift; + r |= (v >> 1); + return r; +} + +inline int dtAlign4(int x) { return (x+3) & ~3; } + +inline int dtOppositeTile(int side) { return (side+4) & 0x7; } + inline float dtVdot2D(const float* u, const float* v) { return u[0]*v[0] + u[2]*v[2]; } -/// Derives the xz-plane 2D perp product of the two vectors. (uz*vx - ux*vz) -/// @param[in] u The LHV vector [(x, y, z)] -/// @param[in] v The RHV vector [(x, y, z)] -/// @return The dot product on the xz-plane. -/// -/// The vectors are projected onto the xz-plane, so the y-values are ignored. inline float dtVperp2D(const float* u, const float* v) { return u[2]*v[0] - u[0]*v[2]; } -/// @} -/// @name Computational geometry helper functions. -/// @{ - -/// Derives the signed xz-plane area of the triangle ABC, or the relationship of line AB to point C. -/// @param[in] a Vertex A. [(x, y, z)] -/// @param[in] b Vertex B. [(x, y, z)] -/// @param[in] c Vertex C. [(x, y, z)] -/// @return The signed xz-plane area of the triangle. inline float dtTriArea2D(const float* a, const float* b, const float* c) { const float abx = b[0] - a[0]; @@ -320,13 +203,6 @@ inline float dtTriArea2D(const float* a, const float* b, const float* c) return acx*abz - abx*acz; } -/// Determines if two axis-aligned bounding boxes overlap. -/// @param[in] amin Minimum bounds of box A. [(x, y, z)] -/// @param[in] amax Maximum bounds of box A. [(x, y, z)] -/// @param[in] bmin Minimum bounds of box B. [(x, y, z)] -/// @param[in] bmax Maximum bounds of box B. [(x, y, z)] -/// @return True if the two AABB's overlap. -/// @see dtOverlapBounds inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3], const unsigned short bmin[3], const unsigned short bmax[3]) { @@ -337,13 +213,6 @@ inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned sh return overlap; } -/// Determines if two axis-aligned bounding boxes overlap. -/// @param[in] amin Minimum bounds of box A. [(x, y, z)] -/// @param[in] amax Maximum bounds of box A. [(x, y, z)] -/// @param[in] bmin Minimum bounds of box B. [(x, y, z)] -/// @param[in] bmax Maximum bounds of box B. [(x, y, z)] -/// @return True if the two AABB's overlap. -/// @see dtOverlapQuantBounds inline bool dtOverlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax) { @@ -354,21 +223,9 @@ inline bool dtOverlapBounds(const float* amin, const float* amax, return overlap; } -/// Derives the closest point on a triangle from the specified reference point. -/// @param[out] closest The closest point on the triangle. -/// @param[in] p The reference point from which to test. [(x, y, z)] -/// @param[in] a Vertex A of triangle ABC. [(x, y, z)] -/// @param[in] b Vertex B of triangle ABC. [(x, y, z)] -/// @param[in] c Vertex C of triangle ABC. [(x, y, z)] void dtClosestPtPointTriangle(float* closest, const float* p, const float* a, const float* b, const float* c); -/// Derives the y-axis height of the closest point on the triangle from the specified reference point. -/// @param[in] p The reference point from which to test. [(x, y, z)] -/// @param[in] a Vertex A of triangle ABC. [(x, y, z)] -/// @param[in] b Vertex B of triangle ABC. [(x, y, z)] -/// @param[in] c Vertex C of triangle ABC. [(x, y, z)] -/// @param[out] h The resulting height. bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h); bool dtIntersectSegmentPoly2D(const float* p0, const float* p1, @@ -376,15 +233,6 @@ bool dtIntersectSegmentPoly2D(const float* p0, const float* p1, float& tmin, float& tmax, int& segMin, int& segMax); -bool dtIntersectSegSeg2D(const float* ap, const float* aq, - const float* bp, const float* bq, - float& s, float& t); - -/// Determines if the specified point is inside the convex polygon on the xz-plane. -/// @param[in] pt The point to check. [(x, y, z)] -/// @param[in] verts The polygon vertices. [(x, y, z) * @p nverts] -/// @param[in] nverts The number of vertices. [Limit: >= 3] -/// @return True if the point is inside the polygon. bool dtPointInPolygon(const float* pt, const float* verts, const int nverts); bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts, @@ -392,139 +240,9 @@ bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nve float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t); -/// Derives the centroid of a convex polygon. -/// @param[out] tc The centroid of the polgyon. [(x, y, z)] -/// @param[in] idx The polygon indices. [(vertIndex) * @p nidx] -/// @param[in] nidx The number of indices in the polygon. [Limit: >= 3] -/// @param[in] verts The polygon vertices. [(x, y, z) * vertCount] void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts); -/// Determines if the two convex polygons overlap on the xz-plane. -/// @param[in] polya Polygon A vertices. [(x, y, z) * @p npolya] -/// @param[in] npolya The number of vertices in polygon A. -/// @param[in] polyb Polygon B vertices. [(x, y, z) * @p npolyb] -/// @param[in] npolyb The number of vertices in polygon B. -/// @return True if the two polygons overlap. bool dtOverlapPolyPoly2D(const float* polya, const int npolya, const float* polyb, const int npolyb); -/// @} -/// @name Miscellanious functions. -/// @{ - -inline unsigned int dtNextPow2(unsigned int v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - -inline unsigned int dtIlog2(unsigned int v) -{ - unsigned int r; - unsigned int shift; - r = (v > 0xffff) << 4; v >>= r; - shift = (v > 0xff) << 3; v >>= shift; r |= shift; - shift = (v > 0xf) << 2; v >>= shift; r |= shift; - shift = (v > 0x3) << 1; v >>= shift; r |= shift; - r |= (v >> 1); - return r; -} - -inline int dtAlign4(int x) { return (x+3) & ~3; } - -inline int dtOppositeTile(int side) { return (side+4) & 0x7; } - -inline void dtSwapByte(unsigned char* a, unsigned char* b) -{ - unsigned char tmp = *a; - *a = *b; - *b = tmp; -} - -inline void dtSwapEndian(unsigned short* v) -{ - unsigned char* x = (unsigned char*)v; - dtSwapByte(x+0, x+1); -} - -inline void dtSwapEndian(short* v) -{ - unsigned char* x = (unsigned char*)v; - dtSwapByte(x+0, x+1); -} - -inline void dtSwapEndian(unsigned int* v) -{ - unsigned char* x = (unsigned char*)v; - dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2); -} - -inline void dtSwapEndian(int* v) -{ - unsigned char* x = (unsigned char*)v; - dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2); -} - -inline void dtSwapEndian(float* v) -{ - unsigned char* x = (unsigned char*)v; - dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2); -} - -void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas, - const float s, const float t, float* out); - -/// @} - #endif // DETOURCOMMON_H - -/////////////////////////////////////////////////////////////////////////// - -// This section contains detailed documentation for members that don't have -// a source file. It reduces clutter in the main section of the header. - -/** - -@fn float dtTriArea2D(const float* a, const float* b, const float* c) -@par - -The vertices are projected onto the xz-plane, so the y-values are ignored. - -This is a low cost function than can be used for various purposes. Its main purpose -is for point/line relationship testing. - -In all cases: A value of zero indicates that all vertices are collinear or represent the same point. -(On the xz-plane.) - -When used for point/line relationship tests, AB usually represents a line against which -the C point is to be tested. In this case: - -A positive value indicates that point C is to the left of line AB, looking from A toward B.
-A negative value indicates that point C is to the right of lineAB, looking from A toward B. - -When used for evaluating a triangle: - -The absolute value of the return value is two times the area of the triangle when it is -projected onto the xz-plane. - -A positive return value indicates: - -
    -
  • The vertices are wrapped in the normal Detour wrap direction.
  • -
  • The triangle's 3D face normal is in the general up direction.
  • -
- -A negative return value indicates: - -
    -
  • The vertices are reverse wrapped. (Wrapped opposite the normal Detour wrap direction.)
  • -
  • The triangle's 3D face normal is in the general down direction.
  • -
- -*/ diff --git a/dep/recastnavigation/Detour/DetourNavMesh.cpp b/dep/recastnavigation/Detour/DetourNavMesh.cpp index 6b8e2d9..e139e3f 100644 --- a/dep/recastnavigation/Detour/DetourNavMesh.cpp +++ b/dep/recastnavigation/Detour/DetourNavMesh.cpp @@ -64,15 +64,6 @@ inline bool overlapSlabs(const float* amin, const float* amax, return false; } -static float getSlabCoord(const float* va, const int side) -{ - if (side == 0 || side == 4) - return va[0]; - else if (side == 2 || side == 6) - return va[2]; - return 0; -} - static void calcSlabEndPoints(const float* va, const float* vb, float* bmin, float* bmax, const int side) { if (side == 0 || side == 4) @@ -142,10 +133,6 @@ dtNavMesh* dtAllocNavMesh() return new(mem) dtNavMesh; } -/// @par -/// -/// This function will only free the memory for tiles with the #DT_TILE_FREE_DATA -/// flag set. void dtFreeNavMesh(dtNavMesh* navmesh) { if (!navmesh) return; @@ -154,37 +141,6 @@ void dtFreeNavMesh(dtNavMesh* navmesh) } ////////////////////////////////////////////////////////////////////////////////////////// - -/** -@class dtNavMesh - -The navigation mesh consists of one or more tiles defining three primary types of structural data: - -A polygon mesh which defines most of the navigation graph. (See rcPolyMesh for its structure.) -A detail mesh used for determining surface height on the polygon mesh. (See rcPolyMeshDetail for its structure.) -Off-mesh connections, which define custom point-to-point edges within the navigation graph. - -The general build process is as follows: - --# Create rcPolyMesh and rcPolyMeshDetail data using the Recast build pipeline. --# Optionally, create off-mesh connection data. --# Combine the source data into a dtNavMeshCreateParams structure. --# Create a tile data array using dtCreateNavMeshData(). --# Allocate at dtNavMesh object and initialize it. (For single tile navigation meshes, - the tile data is loaded during this step.) --# For multi-tile navigation meshes, load the tile data using dtNavMesh::addTile(). - -Notes: - -- This class is usually used in conjunction with the dtNavMeshQuery class for pathfinding. -- Technically, all navigation meshes are tiled. A 'solo' mesh is simply a navigation mesh initialized - to have only a single tile. -- This class does not implement any asynchronous methods. So the ::dtStatus result of all methods will - always contain either a success or failure flag. - -@see dtNavMeshQuery, dtCreateNavMeshData, dtNavMeshCreateParams, #dtAllocNavMesh, #dtFreeNavMesh -*/ - dtNavMesh::dtNavMesh() : m_tileWidth(0), m_tileHeight(0), @@ -198,7 +154,6 @@ dtNavMesh::dtNavMesh() : m_tileBits(0), m_polyBits(0) { - memset(&m_params, 0, sizeof(dtNavMeshParams)); m_orig[0] = 0; m_orig[1] = 0; m_orig[2] = 0; @@ -234,10 +189,10 @@ dtStatus dtNavMesh::init(const dtNavMeshParams* params) m_tiles = (dtMeshTile*)dtAlloc(sizeof(dtMeshTile)*m_maxTiles, DT_ALLOC_PERM); if (!m_tiles) - return DT_FAILURE | DT_OUT_OF_MEMORY; + return DT_FAILURE; m_posLookup = (dtMeshTile**)dtAlloc(sizeof(dtMeshTile*)*m_tileLutSize, DT_ALLOC_PERM); if (!m_posLookup) - return DT_FAILURE | DT_OUT_OF_MEMORY; + return DT_FAILURE; memset(m_tiles, 0, sizeof(dtMeshTile)*m_maxTiles); memset(m_posLookup, 0, sizeof(dtMeshTile*)*m_tileLutSize); m_nextFree = 0; @@ -248,11 +203,13 @@ dtStatus dtNavMesh::init(const dtNavMeshParams* params) m_nextFree = &m_tiles[i]; } - // Edited by TC - m_tileBits = STATIC_TILE_BITS; - m_polyBits = STATIC_POLY_BITS; - m_saltBits = STATIC_SALT_BITS; - + // Init ID generator values. + m_tileBits = STATIC_TILE_BITS; //dtIlog2(dtNextPow2((unsigned int)params->maxTiles)); + m_polyBits = STATIC_POLY_BITS; //dtIlog2(dtNextPow2((unsigned int)params->maxPolys)); + m_saltBits = STATIC_SALT_BITS; //sizeof(dtPolyRef)*8 - m_tileBits - m_polyBits; + //if (m_saltBits < SALT_MIN_BITS) + //return DT_FAILURE; + return DT_SUCCESS; } @@ -261,9 +218,9 @@ dtStatus dtNavMesh::init(unsigned char* data, const int dataSize, const int flag // Make sure the data is in right format. dtMeshHeader* header = (dtMeshHeader*)data; if (header->magic != DT_NAVMESH_MAGIC) - return DT_FAILURE | DT_WRONG_MAGIC; + return DT_FAILURE; if (header->version != DT_NAVMESH_VERSION) - return DT_FAILURE | DT_WRONG_VERSION; + return DT_FAILURE; dtNavMeshParams params; dtVcopy(params.orig, header->bmin); @@ -272,17 +229,13 @@ dtStatus dtNavMesh::init(unsigned char* data, const int dataSize, const int flag params.maxTiles = 1; params.maxPolys = header->polyCount; - dtStatus status = init(¶ms); - if (dtStatusFailed(status)) - return status; + dtStatus res = init(¶ms); + if (res != DT_SUCCESS) + return res; return addTile(data, dataSize, flags, 0, 0); } -/// @par -/// -/// @note The parameters are created automatically when the single tile -/// initialization is performed. const dtNavMeshParams* dtNavMesh::getParams() const { return &m_params; @@ -297,7 +250,6 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb, float amin[2], amax[2]; calcSlabEndPoints(va,vb, amin,amax, side); - const float apos = getSlabCoord(va, side); // Remove links pointing to 'side' and compact the links array. float bmin[2], bmax[2]; @@ -314,18 +266,11 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb, { // Skip edges which do not point to the right side. if (poly->neis[j] != m) continue; - + // Check if the segments touch. const float* vc = &tile->verts[poly->verts[j]*3]; const float* vd = &tile->verts[poly->verts[(j+1) % nv]*3]; - const float bpos = getSlabCoord(vc, side); - - // Segments are not close enough. - if (dtAbs(apos-bpos) > 0.01f) - continue; - - // Check if the segments touch. calcSlabEndPoints(vc,vd, bmin,bmax, side); - + if (!overlapSlabs(amin,amax, bmin,bmax, 0.01f, tile->header->walkableClimb)) continue; // Add return value. @@ -342,11 +287,9 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb, return n; } -void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target) +void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, int side) { - if (!tile || !target) return; - - const unsigned int targetNum = decodePolyIdTile(getTileRef(target)); + if (!tile) return; for (int i = 0; i < tile->header->polyCount; ++i) { @@ -355,8 +298,7 @@ void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target) unsigned int pj = DT_NULL_LINK; while (j != DT_NULL_LINK) { - if (tile->links[j].side != 0xff && - decodePolyIdTile(tile->links[j].ref) == targetNum) + if (tile->links[j].side == side) { // Revove link. unsigned int nj = tile->links[j].next; @@ -387,25 +329,19 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side) dtPoly* poly = &tile->polys[i]; // Create new links. -// unsigned short m = DT_EXT_LINK | (unsigned short)side; - + unsigned short m = DT_EXT_LINK | (unsigned short)side; const int nv = poly->vertCount; for (int j = 0; j < nv; ++j) { - // Skip non-portal edges. - if ((poly->neis[j] & DT_EXT_LINK) == 0) - continue; - - const int dir = (int)(poly->neis[j] & 0xff); - if (side != -1 && dir != side) - continue; + // Skip edges which do not point to the right side. + if (poly->neis[j] != m) continue; // Create new links const float* va = &tile->verts[poly->verts[j]*3]; const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3]; dtPolyRef nei[4]; float neia[4*2]; - int nnei = findConnectingPolys(va,vb, target, dtOppositeTile(dir), nei,neia,4); + int nnei = findConnectingPolys(va,vb, target, dtOppositeTile(side), nei,neia,4); for (int k = 0; k < nnei; ++k) { unsigned int idx = allocLink(tile); @@ -414,13 +350,13 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side) dtLink* link = &tile->links[idx]; link->ref = nei[k]; link->edge = (unsigned char)j; - link->side = (unsigned char)dir; + link->side = (unsigned char)side; link->next = poly->firstLink; poly->firstLink = idx; // Compress portal limits to a byte value. - if (dir == 0 || dir == 4) + if (side == 0 || side == 4) { float tmin = (neia[k*2+0]-va[2]) / (vb[2]-va[2]); float tmax = (neia[k*2+1]-va[2]) / (vb[2]-va[2]); @@ -429,7 +365,7 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side) link->bmin = (unsigned char)(dtClamp(tmin, 0.0f, 1.0f)*255.0f); link->bmax = (unsigned char)(dtClamp(tmax, 0.0f, 1.0f)*255.0f); } - else if (dir == 2 || dir == 6) + else if (side == 2 || side == 6) { float tmin = (neia[k*2+0]-va[0]) / (vb[0]-va[0]); float tmax = (neia[k*2+1]-va[0]) / (vb[0]-va[0]); @@ -450,18 +386,15 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int // Connect off-mesh links. // We are interested on links which land from target tile to this tile. - const unsigned char oppositeSide = (side == -1) ? 0xff : (unsigned char)dtOppositeTile(side); + const unsigned char oppositeSide = (unsigned char)dtOppositeTile(side); for (int i = 0; i < target->header->offMeshConCount; ++i) { dtOffMeshConnection* targetCon = &target->offMeshCons[i]; if (targetCon->side != oppositeSide) continue; - + dtPoly* targetPoly = &target->polys[targetCon->poly]; - // Skip off-mesh connections which start location could not be connected at all. - if (targetPoly->firstLink == DT_NULL_LINK) - continue; const float ext[3] = { targetCon->rad, target->header->walkableClimb, targetCon->rad }; @@ -469,8 +402,7 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int const float* p = &targetCon->pos[3]; float nearestPt[3]; dtPolyRef ref = findNearestPolyInTile(tile, p, ext, nearestPt); - if (!ref) - continue; + if (!ref) continue; // findNearestPoly may return too optimistic results, further check to make sure. if (dtSqr(nearestPt[0]-p[0])+dtSqr(nearestPt[2]-p[2]) > dtSqr(targetCon->rad)) continue; @@ -495,19 +427,19 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int // Link target poly to off-mesh connection. if (targetCon->flags & DT_OFFMESH_CON_BIDIR) { - unsigned int tidx = allocLink(tile); - if (tidx != DT_NULL_LINK) + unsigned int idx = allocLink(tile); + if (idx != DT_NULL_LINK) { const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref); dtPoly* landPoly = &tile->polys[landPolyIdx]; - dtLink* link = &tile->links[tidx]; + dtLink* link = &tile->links[idx]; link->ref = getPolyRefBase(target) | (dtPolyRef)(targetCon->poly); link->edge = 0xff; - link->side = (unsigned char)(side == -1 ? 0xff : side); + link->side = (unsigned char)side; link->bmin = link->bmax = 0; // Add to linked list. link->next = landPoly->firstLink; - landPoly->firstLink = tidx; + landPoly->firstLink = idx; } } } @@ -551,13 +483,13 @@ void dtNavMesh::connectIntLinks(dtMeshTile* tile) } } -void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile) +void dtNavMesh::connectIntOffMeshLinks(dtMeshTile* tile) { if (!tile) return; dtPolyRef base = getPolyRefBase(tile); - // Base off-mesh connection start points. + // Find Off-mesh connection end points. for (int i = 0; i < tile->header->offMeshConCount; ++i) { dtOffMeshConnection* con = &tile->offMeshCons[i]; @@ -565,96 +497,72 @@ void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile) const float ext[3] = { con->rad, tile->header->walkableClimb, con->rad }; - // Find polygon to connect to. - const float* p = &con->pos[0]; // First vertex - float nearestPt[3]; - dtPolyRef ref = findNearestPolyInTile(tile, p, ext, nearestPt); - if (!ref) continue; - // findNearestPoly may return too optimistic results, further check to make sure. - if (dtSqr(nearestPt[0]-p[0])+dtSqr(nearestPt[2]-p[2]) > dtSqr(con->rad)) - continue; - // Make sure the location is on current mesh. - float* v = &tile->verts[poly->verts[0]*3]; - dtVcopy(v, nearestPt); - - // Link off-mesh connection to target poly. - unsigned int idx = allocLink(tile); - if (idx != DT_NULL_LINK) + for (int j = 0; j < 2; ++j) { - dtLink* link = &tile->links[idx]; - link->ref = ref; - link->edge = (unsigned char)0; - link->side = 0xff; - link->bmin = link->bmax = 0; - // Add to linked list. - link->next = poly->firstLink; - poly->firstLink = idx; - } + unsigned char side = j == 0 ? 0xff : con->side; - // Start end-point is always connect back to off-mesh connection. - unsigned int tidx = allocLink(tile); - if (tidx != DT_NULL_LINK) - { - const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref); - dtPoly* landPoly = &tile->polys[landPolyIdx]; - dtLink* link = &tile->links[tidx]; - link->ref = base | (dtPolyRef)(con->poly); - link->edge = 0xff; - link->side = 0xff; - link->bmin = link->bmax = 0; - // Add to linked list. - link->next = landPoly->firstLink; - landPoly->firstLink = tidx; + if (side == 0xff) + { + // Find polygon to connect to. + const float* p = &con->pos[j*3]; + float nearestPt[3]; + dtPolyRef ref = findNearestPolyInTile(tile, p, ext, nearestPt); + if (!ref) continue; + // findNearestPoly may return too optimistic results, further check to make sure. + if (dtSqr(nearestPt[0]-p[0])+dtSqr(nearestPt[2]-p[2]) > dtSqr(con->rad)) + continue; + // Make sure the location is on current mesh. + float* v = &tile->verts[poly->verts[j]*3]; + dtVcopy(v, nearestPt); + + // Link off-mesh connection to target poly. + unsigned int idx = allocLink(tile); + if (idx != DT_NULL_LINK) + { + dtLink* link = &tile->links[idx]; + link->ref = ref; + link->edge = (unsigned char)j; + link->side = 0xff; + link->bmin = link->bmax = 0; + // Add to linked list. + link->next = poly->firstLink; + poly->firstLink = idx; + } + + // Start end-point is always connect back to off-mesh connection, + // Destination end-point only if it is bidirectional link. + if (j == 0 || (j == 1 && (con->flags & DT_OFFMESH_CON_BIDIR))) + { + // Link target poly to off-mesh connection. + unsigned int idx = allocLink(tile); + if (idx != DT_NULL_LINK) + { + const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref); + dtPoly* landPoly = &tile->polys[landPolyIdx]; + dtLink* link = &tile->links[idx]; + link->ref = base | (dtPolyRef)(con->poly); + link->edge = 0xff; + link->side = 0xff; + link->bmin = link->bmax = 0; + // Add to linked list. + link->next = landPoly->firstLink; + landPoly->firstLink = idx; + } + } + + } } } } -void dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip, - const float* pos, float* closest) const +dtStatus dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip, + const float* pos, float* closest) const { const dtPoly* poly = &tile->polys[ip]; - // Off-mesh connections don't have detail polygons. - if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) - { - const float* v0 = &tile->verts[poly->verts[0]*3]; - const float* v1 = &tile->verts[poly->verts[1]*3]; - const float d0 = dtVdist(pos, v0); - const float d1 = dtVdist(pos, v1); - const float u = d0 / (d0+d1); - dtVlerp(closest, v0, v1, u); - return; - } + float closestDistSqr = FLT_MAX; const dtPolyDetail* pd = &tile->detailMeshes[ip]; - - // Clamp point to be inside the polygon. - float verts[DT_VERTS_PER_POLYGON*3]; - float edged[DT_VERTS_PER_POLYGON]; - float edget[DT_VERTS_PER_POLYGON]; - const int nv = poly->vertCount; - for (int i = 0; i < nv; ++i) - dtVcopy(&verts[i*3], &tile->verts[poly->verts[i]*3]); - dtVcopy(closest, pos); - if (!dtDistancePtPolyEdgesSqr(pos, verts, nv, edged, edget)) - { - // Point is outside the polygon, dtClamp to nearest edge. - float dmin = FLT_MAX; - int imin = -1; - for (int i = 0; i < nv; ++i) - { - if (edged[i] < dmin) - { - dmin = edged[i]; - imin = i; - } - } - const float* va = &verts[imin*3]; - const float* vb = &verts[((imin+1)%nv)*3]; - dtVlerp(closest, va, vb, edget[imin]); - } - - // Find height at the location. for (int j = 0; j < pd->triCount; ++j) { const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4]; @@ -666,13 +574,17 @@ void dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip else v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3]; } - float h; - if (dtClosestHeightPointTriangle(pos, v[0], v[1], v[2], h)) + float pt[3]; + dtClosestPtPointTriangle(pt, pos, v[0], v[1], v[2]); + float d = dtVdistSqr(pos, pt); + if (d < closestDistSqr) { - closest[1] = h; - break; + dtVcopy(closest, pt); + closestDistSqr = d; } } + + return DT_SUCCESS; } dtPolyRef dtNavMesh::findNearestPolyInTile(const dtMeshTile* tile, @@ -694,7 +606,8 @@ dtPolyRef dtNavMesh::findNearestPolyInTile(const dtMeshTile* tile, { dtPolyRef ref = polys[i]; float closestPtPoly[3]; - closestPointOnPolyInTile(tile, decodePolyIdPoly(ref), center, closestPtPoly); + if (closestPointOnPolyInTile(tile, decodePolyIdPoly(ref), center, closestPtPoly) != DT_SUCCESS) + continue; float d = dtVdistSqr(center, closestPtPoly); if (d < nearestDistanceSqr) { @@ -768,11 +681,8 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co dtPolyRef base = getPolyRefBase(tile); for (int i = 0; i < tile->header->polyCount; ++i) { - dtPoly* p = &tile->polys[i]; - // Do not return off-mesh connection polygons. - if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) - continue; // Calc polygon bounds. + dtPoly* p = &tile->polys[i]; const float* v = &tile->verts[p->verts[0]*3]; dtVcopy(bmin, v); dtVcopy(bmax, v); @@ -792,29 +702,18 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co } } -/// @par -/// -/// The add operation will fail if the data is in the wrong format, the allocated tile -/// space is full, or there is a tile already at the specified reference. -/// -/// The lastRef parameter is used to restore a tile with the same tile -/// reference it had previously used. In this case the #dtPolyRef's for the -/// tile will be restored to the same values they were before the tile was -/// removed. -/// -/// @see dtCreateNavMeshData, #removeTile dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result) { // Make sure the data is in right format. dtMeshHeader* header = (dtMeshHeader*)data; if (header->magic != DT_NAVMESH_MAGIC) - return DT_FAILURE | DT_WRONG_MAGIC; + return DT_FAILURE_DATA_MAGIC; if (header->version != DT_NAVMESH_VERSION) - return DT_FAILURE | DT_WRONG_VERSION; + return DT_FAILURE_DATA_VERSION; // Make sure the location is free. - if (getTileAt(header->x, header->y, header->layer)) + if (getTileAt(header->x, header->y)) return DT_FAILURE; // Allocate a tile. @@ -833,7 +732,7 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, // Try to relocate the tile to specific index with same salt. int tileIndex = (int)decodePolyIdTile((dtPolyRef)lastRef); if (tileIndex >= m_maxTiles) - return DT_FAILURE | DT_OUT_OF_MEMORY; + return DT_FAILURE_OUT_OF_MEMORY; // Try to find the specific tile id from the free list. dtMeshTile* target = &m_tiles[tileIndex]; dtMeshTile* prev = 0; @@ -845,7 +744,7 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, } // Could not find the correct location. if (tile != target) - return DT_FAILURE | DT_OUT_OF_MEMORY; + return DT_FAILURE_OUT_OF_MEMORY; // Remove from freelist if (!prev) m_nextFree = tile->next; @@ -858,7 +757,7 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, // Make sure we could allocate a tile. if (!tile) - return DT_FAILURE | DT_OUT_OF_MEMORY; + return DT_FAILURE_OUT_OF_MEMORY; // Insert tile into the position lut. int h = computeTileHash(header->x, header->y, m_tileLutMask); @@ -886,10 +785,6 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, tile->bvTree = (dtBVNode*)d; d += bvtreeSize; tile->offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize; - // If there are no items in the bvtree, reset the tree pointer. - if (!bvtreeSize) - tile->bvTree = 0; - // Build links freelist tile->linksFreeList = 0; tile->links[header->maxLinkCount-1].next = DT_NULL_LINK; @@ -903,36 +798,18 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, tile->flags = flags; connectIntLinks(tile); - baseOffMeshLinks(tile); + connectIntOffMeshLinks(tile); - // Create connections with neighbour tiles. - static const int MAX_NEIS = 32; - dtMeshTile* neis[MAX_NEIS]; - int nneis; - - // Connect with layers in current tile. - nneis = getTilesAt(header->x, header->y, neis, MAX_NEIS); - for (int j = 0; j < nneis; ++j) - { - if (neis[j] != tile) - { - connectExtLinks(tile, neis[j], -1); - connectExtLinks(neis[j], tile, -1); - } - connectExtOffMeshLinks(tile, neis[j], -1); - connectExtOffMeshLinks(neis[j], tile, -1); - } - - // Connect with neighbour tiles. + // Create connections connections. for (int i = 0; i < 8; ++i) { - nneis = getNeighbourTilesAt(header->x, header->y, i, neis, MAX_NEIS); - for (int j = 0; j < nneis; ++j) + dtMeshTile* nei = getNeighbourTileAt(header->x, header->y, i); + if (nei) { - connectExtLinks(tile, neis[j], i); - connectExtLinks(neis[j], tile, dtOppositeTile(i)); - connectExtOffMeshLinks(tile, neis[j], i); - connectExtOffMeshLinks(neis[j], tile, dtOppositeTile(i)); + connectExtLinks(tile, nei, i); + connectExtLinks(nei, tile, dtOppositeTile(i)); + connectExtOffMeshLinks(tile, nei, i); + connectExtOffMeshLinks(nei, tile, dtOppositeTile(i)); } } @@ -942,106 +819,55 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, return DT_SUCCESS; } -const dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer) const +const dtMeshTile* dtNavMesh::getTileAt(int x, int y) const { // Find tile based on hash. int h = computeTileHash(x,y,m_tileLutMask); dtMeshTile* tile = m_posLookup[h]; while (tile) { - if (tile->header && - tile->header->x == x && - tile->header->y == y && - tile->header->layer == layer) - { + if (tile->header && tile->header->x == x && tile->header->y == y) return tile; - } tile = tile->next; } return 0; } -int dtNavMesh::getNeighbourTilesAt(const int x, const int y, const int side, dtMeshTile** tiles, const int maxTiles) const +dtMeshTile* dtNavMesh::getNeighbourTileAt(int x, int y, int side) const { - int nx = x, ny = y; switch (side) { - case 0: nx++; break; - case 1: nx++; ny++; break; - case 2: ny++; break; - case 3: nx--; ny++; break; - case 4: nx--; break; - case 5: nx--; ny--; break; - case 6: ny--; break; - case 7: nx++; ny--; break; + case 0: x++; break; + case 1: x++; y++; break; + case 2: y++; break; + case 3: x--; y++; break; + case 4: x--; break; + case 5: x--; y--; break; + case 6: y--; break; + case 7: x++; y--; break; }; - return getTilesAt(nx, ny, tiles, maxTiles); -} - -int dtNavMesh::getTilesAt(const int x, const int y, dtMeshTile** tiles, const int maxTiles) const -{ - int n = 0; - - // Find tile based on hash. - int h = computeTileHash(x,y,m_tileLutMask); - dtMeshTile* tile = m_posLookup[h]; - while (tile) - { - if (tile->header && - tile->header->x == x && - tile->header->y == y) - { - if (n < maxTiles) - tiles[n++] = tile; - } - tile = tile->next; - } - - return n; -} - -/// @par -/// -/// This function will not fail if the tiles array is too small to hold the -/// entire result set. It will simply fill the array to capacity. -int dtNavMesh::getTilesAt(const int x, const int y, dtMeshTile const** tiles, const int maxTiles) const -{ - int n = 0; - // Find tile based on hash. int h = computeTileHash(x,y,m_tileLutMask); dtMeshTile* tile = m_posLookup[h]; while (tile) { - if (tile->header && - tile->header->x == x && - tile->header->y == y) - { - if (n < maxTiles) - tiles[n++] = tile; - } + if (tile->header && tile->header->x == x && tile->header->y == y) + return tile; tile = tile->next; } - - return n; + return 0; } - -dtTileRef dtNavMesh::getTileRefAt(const int x, const int y, const int layer) const +dtTileRef dtNavMesh::getTileRefAt(int x, int y) const { // Find tile based on hash. int h = computeTileHash(x,y,m_tileLutMask); dtMeshTile* tile = m_posLookup[h]; while (tile) { - if (tile->header && - tile->header->x == x && - tile->header->y == y && - tile->header->layer == layer) - { + if (tile->header && tile->header->x == x && tile->header->y == y) return getTileRef(tile); - } tile = tile->next; } return 0; @@ -1084,22 +910,16 @@ void dtNavMesh::calcTileLoc(const float* pos, int* tx, int* ty) const dtStatus dtNavMesh::getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const { - if (!ref) return DT_FAILURE; unsigned int salt, it, ip; decodePolyId(ref, salt, it, ip); - if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM; - if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE | DT_INVALID_PARAM; - if (ip >= (unsigned int)m_tiles[it].header->polyCount) return DT_FAILURE | DT_INVALID_PARAM; + if (it >= (unsigned int)m_maxTiles) return DT_FAILURE; + if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE; + if (ip >= (unsigned int)m_tiles[it].header->polyCount) return DT_FAILURE; *tile = &m_tiles[it]; *poly = &m_tiles[it].polys[ip]; return DT_SUCCESS; } -/// @par -/// -/// @warning Only use this function if it is known that the provided polygon -/// reference is valid. This function is faster than #getTileAndPolyByRef, but -/// it does not validate the reference. void dtNavMesh::getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const { unsigned int salt, it, ip; @@ -1110,7 +930,6 @@ void dtNavMesh::getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile* bool dtNavMesh::isValidPolyRef(dtPolyRef ref) const { - if (!ref) return false; unsigned int salt, it, ip; decodePolyId(ref, salt, it, ip); if (it >= (unsigned int)m_maxTiles) return false; @@ -1119,23 +938,17 @@ bool dtNavMesh::isValidPolyRef(dtPolyRef ref) const return true; } -/// @par -/// -/// This function returns the data for the tile so that, if desired, -/// it can be added back to the navigation mesh at a later point. -/// -/// @see #addTile dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSize) { if (!ref) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; unsigned int tileIndex = decodePolyIdTile((dtPolyRef)ref); unsigned int tileSalt = decodePolyIdSalt((dtPolyRef)ref); if ((int)tileIndex >= m_maxTiles) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; dtMeshTile* tile = &m_tiles[tileIndex]; if (tile->salt != tileSalt) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; // Remove tile from hash lookup. int h = computeTileHash(tile->header->x,tile->header->y,m_tileLutMask); @@ -1156,27 +969,14 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz } // Remove connections to neighbour tiles. - // Create connections with neighbour tiles. - static const int MAX_NEIS = 32; - dtMeshTile* neis[MAX_NEIS]; - int nneis; - - // Connect with layers in current tile. - nneis = getTilesAt(tile->header->x, tile->header->y, neis, MAX_NEIS); - for (int j = 0; j < nneis; ++j) - { - if (neis[j] == tile) continue; - unconnectExtLinks(neis[j], tile); - } - - // Connect with neighbour tiles. for (int i = 0; i < 8; ++i) { - nneis = getNeighbourTilesAt(tile->header->x, tile->header->y, i, neis, MAX_NEIS); - for (int j = 0; j < nneis; ++j) - unconnectExtLinks(neis[j], tile); + dtMeshTile* nei = getNeighbourTileAt(tile->header->x,tile->header->y,i); + if (!nei) continue; + unconnectExtLinks(nei, dtOppositeTile(i)); } - + + // Reset tile. if (tile->flags & DT_TILE_FREE_DATA) { @@ -1220,28 +1020,14 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz dtTileRef dtNavMesh::getTileRef(const dtMeshTile* tile) const { if (!tile) return 0; - const unsigned int it = (unsigned int)(tile - m_tiles); + const unsigned int it = tile - m_tiles; return (dtTileRef)encodePolyId(tile->salt, it, 0); } -/// @par -/// -/// Example use case: -/// @code -/// -/// const dtPolyRef base = navmesh->getPolyRefBase(tile); -/// for (int i = 0; i < tile->header->polyCount; ++i) -/// { -/// const dtPoly* p = &tile->polys[i]; -/// const dtPolyRef ref = base | (dtPolyRef)i; -/// -/// // Use the reference to access the polygon data. -/// } -/// @endcode dtPolyRef dtNavMesh::getPolyRefBase(const dtMeshTile* tile) const { if (!tile) return 0; - const unsigned int it = (unsigned int)(tile - m_tiles); + const unsigned int it = tile - m_tiles; return encodePolyId(tile->salt, it, 0); } @@ -1258,7 +1044,6 @@ struct dtPolyState unsigned char area; // Area ID of the polygon. }; -/// @see #storeTileState int dtNavMesh::getTileStateSize(const dtMeshTile* tile) const { if (!tile) return 0; @@ -1267,17 +1052,12 @@ int dtNavMesh::getTileStateSize(const dtMeshTile* tile) const return headerSize + polyStateSize; } -/// @par -/// -/// Tile state includes non-structural data such as polygon flags, area ids, etc. -/// @note The state data is only valid until the tile reference changes. -/// @see #getTileStateSize, #restoreTileState dtStatus dtNavMesh::storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const { // Make sure there is enough space to store the state. const int sizeReq = getTileStateSize(tile); if (maxDataSize < sizeReq) - return DT_FAILURE | DT_BUFFER_TOO_SMALL; + return DT_FAILURE; dtTileState* tileState = (dtTileState*)data; data += dtAlign4(sizeof(dtTileState)); dtPolyState* polyStates = (dtPolyState*)data; data += dtAlign4(sizeof(dtPolyState) * tile->header->polyCount); @@ -1299,28 +1079,23 @@ dtStatus dtNavMesh::storeTileState(const dtMeshTile* tile, unsigned char* data, return DT_SUCCESS; } -/// @par -/// -/// Tile state includes non-structural data such as polygon flags, area ids, etc. -/// @note This function does not impact the tile's #dtTileRef and #dtPolyRef's. -/// @see #storeTileState dtStatus dtNavMesh::restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize) { // Make sure there is enough space to store the state. const int sizeReq = getTileStateSize(tile); if (maxDataSize < sizeReq) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; const dtTileState* tileState = (const dtTileState*)data; data += dtAlign4(sizeof(dtTileState)); const dtPolyState* polyStates = (const dtPolyState*)data; data += dtAlign4(sizeof(dtPolyState) * tile->header->polyCount); // Check that the restore is possible. if (tileState->magic != DT_NAVMESH_STATE_MAGIC) - return DT_FAILURE | DT_WRONG_MAGIC; + return DT_FAILURE_DATA_MAGIC; if (tileState->version != DT_NAVMESH_STATE_VERSION) - return DT_FAILURE | DT_WRONG_VERSION; + return DT_FAILURE_DATA_VERSION; if (tileState->ref != getTileRef(tile)) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; // Restore per poly state. for (int i = 0; i < tile->header->polyCount; ++i) @@ -1334,26 +1109,17 @@ dtStatus dtNavMesh::restoreTileState(dtMeshTile* tile, const unsigned char* data return DT_SUCCESS; } -/// @par -/// -/// Off-mesh connections are stored in the navigation mesh as special 2-vertex -/// polygons with a single edge. At least one of the vertices is expected to be -/// inside a normal polygon. So an off-mesh connection is "entered" from a -/// normal polygon at one of its endpoints. This is the polygon identified by -/// the prevRef parameter. +// Returns start and end location of an off-mesh link polygon. dtStatus dtNavMesh::getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const { unsigned int salt, it, ip; - if (!polyRef) - return DT_FAILURE; - // Get current polygon decodePolyId(polyRef, salt, it, ip); - if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM; - if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE | DT_INVALID_PARAM; + if (it >= (unsigned int)m_maxTiles) return DT_FAILURE; + if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE; const dtMeshTile* tile = &m_tiles[it]; - if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE | DT_INVALID_PARAM; + if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE; const dtPoly* poly = &tile->polys[ip]; // Make sure that the current poly is indeed off-mesh link. @@ -1388,9 +1154,6 @@ const dtOffMeshConnection* dtNavMesh::getOffMeshConnectionByRef(dtPolyRef ref) c { unsigned int salt, it, ip; - if (!ref) - return 0; - // Get current polygon decodePolyId(ref, salt, it, ip); if (it >= (unsigned int)m_maxTiles) return 0; @@ -1411,13 +1174,12 @@ const dtOffMeshConnection* dtNavMesh::getOffMeshConnectionByRef(dtPolyRef ref) c dtStatus dtNavMesh::setPolyFlags(dtPolyRef ref, unsigned short flags) { - if (!ref) return DT_FAILURE; unsigned int salt, it, ip; decodePolyId(ref, salt, it, ip); - if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM; - if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE | DT_INVALID_PARAM; + if (it >= (unsigned int)m_maxTiles) return DT_FAILURE; + if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE; dtMeshTile* tile = &m_tiles[it]; - if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE | DT_INVALID_PARAM; + if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE; dtPoly* poly = &tile->polys[ip]; // Change flags. @@ -1428,13 +1190,12 @@ dtStatus dtNavMesh::setPolyFlags(dtPolyRef ref, unsigned short flags) dtStatus dtNavMesh::getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const { - if (!ref) return DT_FAILURE; unsigned int salt, it, ip; decodePolyId(ref, salt, it, ip); - if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM; - if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE | DT_INVALID_PARAM; + if (it >= (unsigned int)m_maxTiles) return DT_FAILURE; + if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE; const dtMeshTile* tile = &m_tiles[it]; - if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE | DT_INVALID_PARAM; + if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE; const dtPoly* poly = &tile->polys[ip]; *resultFlags = poly->flags; @@ -1444,13 +1205,12 @@ dtStatus dtNavMesh::getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) con dtStatus dtNavMesh::setPolyArea(dtPolyRef ref, unsigned char area) { - if (!ref) return DT_FAILURE; unsigned int salt, it, ip; decodePolyId(ref, salt, it, ip); - if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM; - if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE | DT_INVALID_PARAM; + if (it >= (unsigned int)m_maxTiles) return DT_FAILURE; + if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE; dtMeshTile* tile = &m_tiles[it]; - if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE | DT_INVALID_PARAM; + if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE; dtPoly* poly = &tile->polys[ip]; poly->setArea(area); @@ -1460,13 +1220,12 @@ dtStatus dtNavMesh::setPolyArea(dtPolyRef ref, unsigned char area) dtStatus dtNavMesh::getPolyArea(dtPolyRef ref, unsigned char* resultArea) const { - if (!ref) return DT_FAILURE; unsigned int salt, it, ip; decodePolyId(ref, salt, it, ip); - if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM; - if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE | DT_INVALID_PARAM; + if (it >= (unsigned int)m_maxTiles) return DT_FAILURE; + if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return DT_FAILURE; const dtMeshTile* tile = &m_tiles[it]; - if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE | DT_INVALID_PARAM; + if (ip >= (unsigned int)tile->header->polyCount) return DT_FAILURE; const dtPoly* poly = &tile->polys[ip]; *resultArea = poly->getArea(); diff --git a/dep/recastnavigation/Detour/DetourNavMesh.h b/dep/recastnavigation/Detour/DetourNavMesh.h index c094e41..b146631 100644 --- a/dep/recastnavigation/Detour/DetourNavMesh.h +++ b/dep/recastnavigation/Detour/DetourNavMesh.h @@ -20,12 +20,9 @@ #define DETOURNAVMESH_H #include "DetourAlloc.h" -#include "DetourStatus.h" - -// Edited by TC #if defined(WIN32) && !defined(__MINGW32__) -typedef unsigned __int64 uint64; + typedef unsigned __int64 uint64; #else #include #ifndef uint64_t @@ -33,473 +30,312 @@ typedef unsigned __int64 uint64; #include #endif #endif -typedef uint64_t uint64; -#endif + typedef uint64_t uint64; +#endif // Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef. -// It is also recommended that you change dtHashRef() to a proper 64-bit hash. - -// Edited by TC -// We cannot have over 31 bits for either tile nor poly -// without changing polyCount to use 64bits too. -static const int STATIC_SALT_BITS = 12; -static const int STATIC_TILE_BITS = 21; -static const int STATIC_POLY_BITS = 31; +// It is also recommended to change dtHashRef() to proper 64-bit hash too. -/// A handle to a polygon within a navigation mesh tile. -/// @ingroup detour -typedef uint64 dtPolyRef; // Edited by TC +// Reference to navigation polygon. +typedef uint64 dtPolyRef; -/// A handle to a tile within a navigation mesh. -/// @ingroup detour -typedef uint64 dtTileRef; // Edited by TC +// Reference to navigation mesh tile. +typedef uint64 dtTileRef; -/// The maximum number of vertices per navigation polygon. -/// @ingroup detour +// Maximum number of vertices per navigation polygon. static const int DT_VERTS_PER_POLYGON = 6; -/// @{ -/// @name Tile Serialization Constants -/// These constants are used to detect whether a navigation tile's data -/// and state format is compatible with the current build. -/// - -/// A magic number used to detect compatibility of navigation tile data. -static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V'; - -/// A version number used to detect compatibility of navigation tile data. -static const int DT_NAVMESH_VERSION = 7; +static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V'; //'DNAV'; +static const int DT_NAVMESH_VERSION = 6; -/// A magic number used to detect the compatibility of navigation tile states. -static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S'; - -/// A version number used to detect compatibility of navigation tile states. +static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S'; //'DNMS'; static const int DT_NAVMESH_STATE_VERSION = 1; -/// @} - -/// A flag that indicates that an entity links to an external entity. -/// (E.g. A polygon edge is a portal that links to another polygon.) static const unsigned short DT_EXT_LINK = 0x8000; - -/// A value that indicates the entity does not link to anything. static const unsigned int DT_NULL_LINK = 0xffffffff; - -/// A flag that indicates that an off-mesh connection can be traversed in both directions. (Is bidirectional.) static const unsigned int DT_OFFMESH_CON_BIDIR = 1; -/// The maximum number of user defined area ids. -/// @ingroup detour static const int DT_MAX_AREAS = 64; -/// Tile flags used for various functions and fields. -/// For an example, see dtNavMesh::addTile(). +static const int STATIC_SALT_BITS = 12; +static const int STATIC_TILE_BITS = 21; +static const int STATIC_POLY_BITS = 31; +// we cannot have over 31 bits for either tile nor poly +// without changing polyCount to use 64bits too. + +// Flags for addTile enum dtTileFlags { - /// The navigation mesh owns the tile memory and is responsible for freeing it. - DT_TILE_FREE_DATA = 0x01, + DT_TILE_FREE_DATA = 0x01, // Navmesh owns the tile memory and should free it. }; -/// Vertex flags returned by dtNavMeshQuery::findStraightPath. +// Flags returned by findStraightPath(). enum dtStraightPathFlags { - DT_STRAIGHTPATH_START = 0x01, ///< The vertex is the start position in the path. - DT_STRAIGHTPATH_END = 0x02, ///< The vertex is the end position in the path. - DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, ///< The vertex is the start of an off-mesh connection. + DT_STRAIGHTPATH_START = 0x01, // The vertex is the start position. + DT_STRAIGHTPATH_END = 0x02, // The vertex is the end position. + DT_STRAIGHTPATH_OFFMESH_CONNECTION = 0x04, // The vertex is start of an off-mesh link. }; -/// Options for dtNavMeshQuery::findStraightPath. -enum dtStraightPathOptions +// Flags describing polygon properties. +enum dtPolyTypes { - DT_STRAIGHTPATH_AREA_CROSSINGS = 0x01, ///< Add a vertex at every polygon edge crossing where area changes. - DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, ///< Add a vertex at every polygon edge crossing. + DT_POLYTYPE_GROUND = 0, // Regular ground polygons. + DT_POLYTYPE_OFFMESH_CONNECTION = 1, // Off-mesh connections. }; -/// Flags representing the type of a navigation mesh polygon. -enum dtPolyTypes +enum dtStatus { - /// The polygon is a standard convex polygon that is part of the surface of the mesh. - DT_POLYTYPE_GROUND = 0, - /// The polygon is an off-mesh connection consisting of two vertices. - DT_POLYTYPE_OFFMESH_CONNECTION = 1, + DT_FAILURE = 0, // Operation failed. + DT_FAILURE_DATA_MAGIC, + DT_FAILURE_DATA_VERSION, + DT_FAILURE_OUT_OF_MEMORY, + DT_SUCCESS, // Operation succeed. + DT_IN_PROGRESS, // Operation still in progress. }; -/// Defines a polyogn within a dtMeshTile object. -/// @ingroup detour +// Structure describing the navigation polygon data. struct dtPoly { - /// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.) - unsigned int firstLink; - - /// The indices of the polygon's vertices. - /// The actual vertices are located in dtMeshTile::verts. - unsigned short verts[DT_VERTS_PER_POLYGON]; - - /// Packed data representing neighbor polygons references and flags for each edge. - unsigned short neis[DT_VERTS_PER_POLYGON]; - - /// The user defined polygon flags. - unsigned short flags; - - /// The number of vertices in the polygon. - unsigned char vertCount; - - /// The bit packed area id and polygon type. - /// @note Use the structure's set and get methods to acess this value. - unsigned char areaAndtype; - - /// Sets the user defined area id. [Limit: < #DT_MAX_AREAS] + unsigned int firstLink; // Index to first link in linked list. + unsigned short verts[DT_VERTS_PER_POLYGON]; // Indices to vertices of the poly. + unsigned short neis[DT_VERTS_PER_POLYGON]; // Refs to neighbours of the poly. + unsigned short flags; // Flags (see dtPolyFlags). + unsigned char vertCount; // Number of vertices. + unsigned char areaAndtype; // Bit packed: Area ID of the polygon, and Polygon type, see dtPolyTypes.. inline void setArea(unsigned char a) { areaAndtype = (areaAndtype & 0xc0) | (a & 0x3f); } - - /// Sets the polygon type. (See: #dtPolyTypes.) inline void setType(unsigned char t) { areaAndtype = (areaAndtype & 0x3f) | (t << 6); } - - /// Gets the user defined area id. inline unsigned char getArea() const { return areaAndtype & 0x3f; } - - /// Gets the polygon type. (See: #dtPolyTypes) inline unsigned char getType() const { return areaAndtype >> 6; } }; -/// Defines the location of detail sub-mesh data within a dtMeshTile. +// Stucture describing polygon detail triangles. struct dtPolyDetail { - unsigned int vertBase; ///< The offset of the vertices in the dtMeshTile::detailVerts array. - unsigned int triBase; ///< The offset of the triangles in the dtMeshTile::detailTris array. - unsigned char vertCount; ///< The number of vertices in the sub-mesh. - unsigned char triCount; ///< The number of triangles in the sub-mesh. + unsigned int vertBase; // Offset to detail vertex array. + unsigned int triBase; // Offset to detail triangle array. + unsigned char vertCount; // Number of vertices in the detail mesh. + unsigned char triCount; // Number of triangles. }; -/// Defines a link between polygons. -/// @note This structure is rarely if ever used by the end user. -/// @see dtMeshTile +// Stucture describing a link to another polygon. struct dtLink { - dtPolyRef ref; ///< Neighbour reference. (The neighbor that is linked to.) - unsigned int next; ///< Index of the next link. - unsigned char edge; ///< Index of the polygon edge that owns this link. - unsigned char side; ///< If a boundary link, defines on which side the link is. - unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area. - unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area. + dtPolyRef ref; // Neighbour reference. + unsigned int next; // Index to next link. + unsigned char edge; // Index to polygon edge which owns this link. + unsigned char side; // If boundary link, defines on which side the link is. + unsigned char bmin, bmax; // If boundary link, defines the sub edge area. }; -/// Bounding volume node. -/// @note This structure is rarely if ever used by the end user. -/// @see dtMeshTile struct dtBVNode { - unsigned short bmin[3]; ///< Minimum bounds of the node's AABB. [(x, y, z)] - unsigned short bmax[3]; ///< Maximum bounds of the node's AABB. [(x, y, z)] - int i; ///< The node's index. (Negative for escape sequence.) + unsigned short bmin[3], bmax[3]; // BVnode bounds + int i; // Index to item or if negative, escape index. }; -/// Defines an navigation mesh off-mesh connection within a dtMeshTile object. -/// An off-mesh connection is a user defined traversable connection made up to two vertices. struct dtOffMeshConnection { - /// The endpoints of the connection. [(ax, ay, az, bx, by, bz)] - float pos[6]; - - /// The radius of the endpoints. [Limit: >= 0] - float rad; - - /// The polygon reference of the connection within the tile. - unsigned short poly; - - /// Link flags. - /// @note These are not the connection's user defined flags. Those are assigned via the - /// connection's dtPoly definition. These are link flags used for internal purposes. - unsigned char flags; - - /// End point side. - unsigned char side; - - /// The id of the offmesh connection. (User assigned when the navigation mesh is built.) - unsigned int userId; + float pos[6]; // Both end point locations. + float rad; // Link connection radius. + unsigned short poly; // Poly Id + unsigned char flags; // Link flags + unsigned char side; // End point side. + unsigned int userId; // User ID to identify this connection. }; -/// Provides high level information related to a dtMeshTile object. -/// @ingroup detour struct dtMeshHeader { - int magic; ///< Tile magic number. (Used to identify the data format.) - int version; ///< Tile data format version number. - int x; ///< The x-position of the tile within the dtNavMesh tile grid. (x, y, layer) - int y; ///< The y-position of the tile within the dtNavMesh tile grid. (x, y, layer) - int layer; ///< The layer of the tile within the dtNavMesh tile grid. (x, y, layer) - unsigned int userId; ///< The user defined id of the tile. - int polyCount; ///< The number of polygons in the tile. - int vertCount; ///< The number of vertices in the tile. - int maxLinkCount; ///< The number of allocated links. - int detailMeshCount; ///< The number of sub-meshes in the detail mesh. - - /// The number of unique vertices in the detail mesh. (In addition to the polygon vertices.) - int detailVertCount; - - int detailTriCount; ///< The number of triangles in the detail mesh. - int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.) - int offMeshConCount; ///< The number of off-mesh connections. - int offMeshBase; ///< The index of the first polygon which is an off-mesh connection. - float walkableHeight; ///< The height of the agents using the tile. - float walkableRadius; ///< The radius of the agents using the tile. - float walkableClimb; ///< The maximum climb height of the agents using the tile. - float bmin[3]; ///< The minimum bounds of the tile's AABB. [(x, y, z)] - float bmax[3]; ///< The maximum bounds of the tile's AABB. [(x, y, z)] - - /// The bounding volume quantization factor. - float bvQuantFactor; + int magic; // Magic number, used to identify the data. + int version; // Data version number. + int x, y; // Location of the time on the grid. + unsigned int userId; // User ID of the tile. + int polyCount; // Number of polygons in the tile. + int vertCount; // Number of vertices in the tile. + int maxLinkCount; // Number of allocated links. + int detailMeshCount; // Number of detail meshes. + int detailVertCount; // Number of detail vertices. + int detailTriCount; // Number of detail triangles. + int bvNodeCount; // Number of BVtree nodes. + int offMeshConCount; // Number of Off-Mesh links. + int offMeshBase; // Index to first polygon which is Off-Mesh link. + float walkableHeight; // Height of the agent. + float walkableRadius; // Radius of the agent + float walkableClimb; // Max climb height of the agent. + float bmin[3], bmax[3]; // Bounding box of the tile. + float bvQuantFactor; // BVtree quantization factor (world to bvnode coords) }; -/// Defines a navigation mesh tile. -/// @ingroup detour struct dtMeshTile { - unsigned int salt; ///< Counter describing modifications to the tile. - - unsigned int linksFreeList; ///< Index to the next free link. - dtMeshHeader* header; ///< The tile header. - dtPoly* polys; ///< The tile polygons. [Size: dtMeshHeader::polyCount] - float* verts; ///< The tile vertices. [Size: dtMeshHeader::vertCount] - dtLink* links; ///< The tile links. [Size: dtMeshHeader::maxLinkCount] - dtPolyDetail* detailMeshes; ///< The tile's detail sub-meshes. [Size: dtMeshHeader::detailMeshCount] - - /// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount] - float* detailVerts; - - /// The detail mesh's triangles. [(vertA, vertB, vertC) * dtMeshHeader::detailTriCount] - unsigned char* detailTris; - - /// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount] - /// (Will be null if bounding volumes are disabled.) - dtBVNode* bvTree; - - dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount] + unsigned int salt; // Counter describing modifications to the tile. + + unsigned int linksFreeList; // Index to next free link. + dtMeshHeader* header; // Pointer to tile header. + dtPoly* polys; // Pointer to the polygons (will be updated when tile is added). + float* verts; // Pointer to the vertices (will be updated when tile added). + dtLink* links; // Pointer to the links (will be updated when tile added). + dtPolyDetail* detailMeshes; // Pointer to detail meshes (will be updated when tile added). + float* detailVerts; // Pointer to detail vertices (will be updated when tile added). + unsigned char* detailTris; // Pointer to detail triangles (will be updated when tile added). + dtBVNode* bvTree; // Pointer to BVtree nodes (will be updated when tile added). + dtOffMeshConnection* offMeshCons; // Pointer to Off-Mesh links. (will be updated when tile added). - unsigned char* data; ///< The tile data. (Not directly accessed under normal situations.) - int dataSize; ///< Size of the tile data. - int flags; ///< Tile flags. (See: #dtTileFlags) - dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid. + unsigned char* data; // Pointer to tile data. + int dataSize; // Size of the tile data. + int flags; // Tile flags, see dtTileFlags. + dtMeshTile* next; // Next free tile or, next tile in spatial grid. }; -/// Configuration parameters used to define multi-tile navigation meshes. -/// The values are used to allocate space during the initialization of a navigation mesh. -/// @see dtNavMesh::init() -/// @ingroup detour struct dtNavMeshParams { - float orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)] - float tileWidth; ///< The width of each tile. (Along the x-axis.) - float tileHeight; ///< The height of each tile. (Along the z-axis.) - int maxTiles; ///< The maximum number of tiles the navigation mesh can contain. - int maxPolys; ///< The maximum number of polygons each tile can contain. + float orig[3]; // Origin of the nav mesh tile space. + float tileWidth, tileHeight; // Width and height of each tile. + int maxTiles; // Maximum number of tiles the navmesh can contain. + int maxPolys; // Maximum number of polygons each tile can contain. }; -/// A navigation mesh based on tiles of convex polygons. -/// @ingroup detour + class dtNavMesh { public: dtNavMesh(); ~dtNavMesh(); - /// @{ - /// @name Initialization and Tile Management - - /// Initializes the navigation mesh for tiled use. - /// @param[in] params Initialization parameters. - /// @return The status flags for the operation. + // Initializes the nav mesh for tiled use. + // Params: + // params - (in) navmesh initialization params, see dtNavMeshParams. + // Returns: True if succeed, else false. dtStatus init(const dtNavMeshParams* params); - /// Initializes the navigation mesh for single tile use. - /// @param[in] data Data of the new tile. (See: #dtCreateNavMeshData) - /// @param[in] dataSize The data size of the new tile. - /// @param[in] flags The tile flags. (See: #dtTileFlags) - /// @return The status flags for the operation. - /// @see dtCreateNavMeshData + // Initializes the nav mesh for single tile use. + // Params: + // data - (in) Data of the new tile mesh. + // dataSize - (in) Data size of the new tile mesh. + // flags - (in) Tile flags, see dtTileFlags. + // Returns: True if succeed, else false. dtStatus init(unsigned char* data, const int dataSize, const int flags); - /// The navigation mesh initialization params. + // Returns pointer to navmesh initialization params. const dtNavMeshParams* getParams() const; - - /// Adds a tile to the navigation mesh. - /// @param[in] data Data for the new tile mesh. (See: #dtCreateNavMeshData) - /// @param[in] dataSize Data size of the new tile mesh. - /// @param[in] flags Tile flags. (See: #dtTileFlags) - /// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0] - /// @param[out] result The tile reference. (If the tile was succesfully added.) [opt] - /// @return The status flags for the operation. + + // Adds new tile into the navmesh. + // The add will fail if the data is in wrong format, + // there is not enough tiles left, or if there is a tile already at the location. + // Params: + // data - (in) Data of the new tile mesh. + // dataSize - (in) Data size of the new tile mesh. + // flags - (in) Tile flags, see dtTileFlags. + // lastRef - (in,optional) Last tile ref, the tile will be restored so that + // the reference (as well as poly references) will be the same. Default: 0. + // result - (out,optional) tile ref if the tile was succesfully added. dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result); - /// Removes the specified tile from the navigation mesh. - /// @param[in] ref The reference of the tile to remove. - /// @param[out] data Data associated with deleted tile. - /// @param[out] dataSize Size of the data associated with deleted tile. - /// @return The status flags for the operation. + // Removes specified tile. + // Params: + // ref - (in) Reference to the tile to remove. + // data - (out) Data associated with deleted tile. + // dataSize - (out) Size of the data associated with deleted tile. dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize); - /// @} - - /// @{ - /// @name Query Functions - - /// Calculates the tile grid location for the specified world position. - /// @param[in] pos The world position for the query. [(x, y, z)] - /// @param[out] tx The tile's x-location. (x, y) - /// @param[out] ty The tile's y-location. (x, y) + // Calculates tile location based in input world position. + // Params: + // pos - (in) world position of the query. + // tx - (out) tile x location. + // ty - (out) tile y location. void calcTileLoc(const float* pos, int* tx, int* ty) const; - /// Gets the tile at the specified grid location. - /// @param[in] x The tile's x-location. (x, y, layer) - /// @param[in] y The tile's y-location. (x, y, layer) - /// @param[in] layer The tile's layer. (x, y, layer) - /// @return The tile, or null if the tile does not exist. - const dtMeshTile* getTileAt(const int x, const int y, const int layer) const; - - /// Gets all tiles at the specified grid location. (All layers.) - /// @param[in] x The tile's x-location. (x, y) - /// @param[in] y The tile's y-location. (x, y) - /// @param[out] tiles A pointer to an array of tiles that will hold the result. - /// @param[in] maxTiles The maximum tiles the tiles parameter can hold. - /// @return The number of tiles returned in the tiles array. - int getTilesAt(const int x, const int y, - dtMeshTile const** tiles, const int maxTiles) const; + // Returns pointer to tile at specified location. + // Params: + // x,y - (in) Location of the tile to get. + // Returns: pointer to tile if tile exists or 0 tile does not exists. + const dtMeshTile* getTileAt(int x, int y) const; + + // Returns reference to tile at specified location. + // Params: + // x,y - (in) Location of the tile to get. + // Returns: reference to tile if tile exists or 0 tile does not exists. + dtTileRef getTileRefAt(int x, int y) const; - /// Gets the tile reference for the tile at specified grid location. - /// @param[in] x The tile's x-location. (x, y, layer) - /// @param[in] y The tile's y-location. (x, y, layer) - /// @param[in] layer The tile's layer. (x, y, layer) - /// @return The tile reference of the tile, or 0 if there is none. - dtTileRef getTileRefAt(int x, int y, int layer) const; - - /// Gets the tile reference for the specified tile. - /// @param[in] tile The tile. - /// @return The tile reference of the tile. + // Returns tile references of a tile based on tile pointer. dtTileRef getTileRef(const dtMeshTile* tile) const; - /// Gets the tile for the specified tile reference. - /// @param[in] ref The tile reference of the tile to retrieve. - /// @return The tile for the specified reference, or null if the - /// reference is invalid. + // Returns tile based on references. const dtMeshTile* getTileByRef(dtTileRef ref) const; - /// The maximum number of tiles supported by the navigation mesh. - /// @return The maximum number of tiles supported by the navigation mesh. + // Returns max number of tiles. int getMaxTiles() const; - /// Gets the tile at the specified index. - /// @param[in] i The tile index. [Limit: 0 >= index < #getMaxTiles()] - /// @return The tile at the specified index. + // Returns pointer to tile in the tile array. + // Params: + // i - (in) Index to the tile to retrieve, max index is getMaxTiles()-1. + // Returns: Pointer to specified tile. const dtMeshTile* getTile(int i) const; - /// Gets the tile and polygon for the specified polygon reference. - /// @param[in] ref The reference for the a polygon. - /// @param[out] tile The tile containing the polygon. - /// @param[out] poly The polygon. - /// @return The status flags for the operation. + // Returns pointer to tile and polygon pointed by the polygon reference. + // Params: + // ref - (in) reference to a polygon. + // tile - (out) pointer to the tile containing the polygon. + // poly - (out) pointer to the polygon. dtStatus getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const; - /// Returns the tile and polygon for the specified polygon reference. - /// @param[in] ref A known valid reference for a polygon. - /// @param[out] tile The tile containing the polygon. - /// @param[out] poly The polygon. + // Returns pointer to tile and polygon pointed by the polygon reference. + // Note: this function does not check if 'ref' s valid, and is thus faster. Use only with valid refs! + // Params: + // ref - (in) reference to a polygon. + // tile - (out) pointer to the tile containing the polygon. + // poly - (out) pointer to the polygon. void getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const; - /// Checks the validity of a polygon reference. - /// @param[in] ref The polygon reference to check. - /// @return True if polygon reference is valid for the navigation mesh. + // Returns true if polygon reference points to valid data. bool isValidPolyRef(dtPolyRef ref) const; - /// Gets the polygon reference for the tile's base polygon. - /// @param[in] tile The tile. - /// @return The polygon reference for the base polygon in the specified tile. + // Returns base poly id for specified tile, polygon refs can be deducted from this. dtPolyRef getPolyRefBase(const dtMeshTile* tile) const; - /// Gets the endpoints for an off-mesh connection, ordered by "direction of travel". - /// @param[in] prevRef The reference of the polygon before the connection. - /// @param[in] polyRef The reference of the off-mesh connection polygon. - /// @param[out] startPos The start position of the off-mesh connection. [(x, y, z)] - /// @param[out] endPos The end position of the off-mesh connection. [(x, y, z)] - /// @return The status flags for the operation. + // Returns start and end location of an off-mesh link polygon. + // Params: + // prevRef - (in) ref to the polygon before the link (used to select direction). + // polyRef - (in) ref to the off-mesh link polygon. + // startPos[3] - (out) start point of the link. + // endPos[3] - (out) end point of the link. + // Returns: true if link is found. dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const; - /// Gets the specified off-mesh connection. - /// @param[in] ref The polygon reference of the off-mesh connection. - /// @return The specified off-mesh connection, or null if the polygon reference is not valid. + // Returns pointer to off-mesh connection based on polyref, or null if ref not valid. const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const; - /// @} - - /// @{ - /// @name State Management - /// These functions do not effect #dtTileRef or #dtPolyRef's. - - /// Sets the user defined flags for the specified polygon. - /// @param[in] ref The polygon reference. - /// @param[in] flags The new flags for the polygon. - /// @return The status flags for the operation. + // Sets polygon flags. dtStatus setPolyFlags(dtPolyRef ref, unsigned short flags); - /// Gets the user defined flags for the specified polygon. - /// @param[in] ref The polygon reference. - /// @param[out] resultFlags The polygon flags. - /// @return The status flags for the operation. + // Return polygon flags. dtStatus getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const; - /// Sets the user defined area for the specified polygon. - /// @param[in] ref The polygon reference. - /// @param[in] area The new area id for the polygon. [Limit: < #DT_MAX_AREAS] - /// @return The status flags for the operation. + // Set polygon type. dtStatus setPolyArea(dtPolyRef ref, unsigned char area); - /// Gets the user defined area for the specified polygon. - /// @param[in] ref The polygon reference. - /// @param[out] resultArea The area id for the polygon. - /// @return The status flags for the operation. + // Return polygon area type. dtStatus getPolyArea(dtPolyRef ref, unsigned char* resultArea) const; - /// Gets the size of the buffer required by #storeTileState to store the specified tile's state. - /// @param[in] tile The tile. - /// @return The size of the buffer required to store the state. + + // Returns number of bytes required to store tile state. int getTileStateSize(const dtMeshTile* tile) const; - /// Stores the non-structural state of the tile in the specified buffer. (Flags, area ids, etc.) - /// @param[in] tile The tile. - /// @param[out] data The buffer to store the tile's state in. - /// @param[in] maxDataSize The size of the data buffer. [Limit: >= #getTileStateSize] - /// @return The status flags for the operation. + // Stores tile state to buffer. dtStatus storeTileState(const dtMeshTile* tile, unsigned char* data, const int maxDataSize) const; - /// Restores the state of the tile. - /// @param[in] tile The tile. - /// @param[in] data The new state. (Obtained from #storeTileState.) - /// @param[in] maxDataSize The size of the state within the data buffer. - /// @return The status flags for the operation. + // Restores tile state. dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize); - /// @} - /// @{ - /// @name Encoding and Decoding - /// These functions are generally meant for internal use only. - - /// Derives a standard polygon reference. - /// @note This function is generally meant for internal use only. - /// @param[in] salt The tile's salt value. - /// @param[in] it The index of the tile. - /// @param[in] ip The index of the polygon within the tile. + // Encodes a tile id. inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const { return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip; } - /// Decodes a standard polygon reference. - /// @note This function is generally meant for internal use only. - /// @param[in] ref The polygon reference to decode. - /// @param[out] salt The tile's salt value. - /// @param[out] it The index of the tile. - /// @param[out] ip The index of the polygon within the tile. - /// @see #encodePolyId + // Decodes a tile id. inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const { const dtPolyRef saltMask = ((dtPolyRef)1<> (m_polyBits+m_tileBits)) & saltMask); } - /// Extracts the tile's index from the specified polygon reference. - /// @note This function is generally meant for internal use only. - /// @param[in] ref The polygon reference. - /// @see #encodePolyId + // Decodes a tile id. inline unsigned int decodePolyIdTile(dtPolyRef ref) const { const dtPolyRef tileMask = ((dtPolyRef)1<> m_polyBits) & tileMask); } - /// Extracts the polygon's index (within its tile) from the specified polygon reference. - /// @note This function is generally meant for internal use only. - /// @param[in] ref The polygon reference. - /// @see #encodePolyId + // Decodes a poly id. inline unsigned int decodePolyIdPoly(dtPolyRef ref) const { const dtPolyRef polyMask = ((dtPolyRef)1<header->bvQuantFactor; -const dtBVNode* n = &tile->bvTree[i]; -if (n->i >= 0) -{ - // This is a leaf node. - float worldMinX = tile->header->bmin[0] + n->bmin[0]*cs; - float worldMinY = tile->header->bmin[0] + n->bmin[1]*cs; - // Etc... -} -@endcode - -@struct dtMeshTile -@par - -Tiles generally only exist within the context of a dtNavMesh object. - -Some tile content is optional. For example, a tile may not contain any -off-mesh connections. In this case the associated pointer will be null. - -If a detail mesh exists it will share vertices with the base polygon mesh. -Only the vertices unique to the detail mesh will be stored in #detailVerts. - -@warning Tiles returned by a dtNavMesh object are not guarenteed to be populated. -For example: The tile at a location might not have been loaded yet, or may have been removed. -In this case, pointers will be null. So if in doubt, check the polygon count in the -tile's header to determine if a tile has polygons defined. - -@var float dtOffMeshConnection::pos[6] -@par - -For a properly built navigation mesh, vertex A will always be within the bounds of the mesh. -Vertex B is not required to be within the bounds of the mesh. - -*/ diff --git a/dep/recastnavigation/Detour/DetourNavMeshBuilder.cpp b/dep/recastnavigation/Detour/DetourNavMeshBuilder.cpp index 9d8471b..f648571 100644 --- a/dep/recastnavigation/Detour/DetourNavMeshBuilder.cpp +++ b/dep/recastnavigation/Detour/DetourNavMeshBuilder.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include "DetourNavMesh.h" #include "DetourCommon.h" #include "DetourNavMeshBuilder.h" @@ -238,19 +237,11 @@ static unsigned char classifyOffMeshPoint(const float* pt, const float* bmin, co case ZM: return 6; case XP|ZM: return 7; }; - return 0xff; } // TODO: Better error handling. -/// @par -/// -/// The output data array is allocated using the detour allocator (dtAlloc()). The method -/// used to free the memory will be determined by how the tile is added to the navigation -/// mesh. -/// -/// @see dtNavMesh, dtNavMesh::addTile() bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize) { if (params->nvp > DT_VERTS_PER_POLYGON) @@ -261,6 +252,8 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, return false; if (!params->polyCount || !params->polys) return false; + if (!params->detailMeshes || !params->detailVerts || !params->detailTris) + return false; const int nvp = params->nvp; @@ -276,50 +269,10 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, if (!offMeshConClass) return false; - // Find tight heigh bounds, used for culling out off-mesh start locations. - float hmin = FLT_MAX; - float hmax = -FLT_MAX; - - if (params->detailVerts && params->detailVertsCount) - { - for (int i = 0; i < params->detailVertsCount; ++i) - { - const float h = params->detailVerts[i*3+1]; - hmin = dtMin(hmin,h); - hmax = dtMax(hmax,h); - } - } - else - { - for (int i = 0; i < params->vertCount; ++i) - { - const unsigned short* iv = ¶ms->verts[i*3]; - const float h = params->bmin[1] + iv[1] * params->ch; - hmin = dtMin(hmin,h); - hmax = dtMax(hmax,h); - } - } - hmin -= params->walkableClimb; - hmax += params->walkableClimb; - float bmin[3], bmax[3]; - dtVcopy(bmin, params->bmin); - dtVcopy(bmax, params->bmax); - bmin[1] = hmin; - bmax[1] = hmax; - for (int i = 0; i < params->offMeshConCount; ++i) { - const float* p0 = ¶ms->offMeshConVerts[(i*2+0)*3]; - const float* p1 = ¶ms->offMeshConVerts[(i*2+1)*3]; - offMeshConClass[i*2+0] = classifyOffMeshPoint(p0, bmin, bmax); - offMeshConClass[i*2+1] = classifyOffMeshPoint(p1, bmin, bmax); - - // Zero out off-mesh start positions which are not even potentially touching the mesh. - if (offMeshConClass[i*2+0] == 0xff) - { - if (p0[1] < bmin[1] || p0[1] > bmax[1]) - offMeshConClass[i*2+0] = 0; - } + offMeshConClass[i*2+0] = classifyOffMeshPoint(¶ms->offMeshConVerts[(i*2+0)*3], params->bmin, params->bmax); + offMeshConClass[i*2+1] = classifyOffMeshPoint(¶ms->offMeshConVerts[(i*2+1)*3], params->bmin, params->bmax); // Cound how many links should be allocated for off-mesh connections. if (offMeshConClass[i*2+0] == 0xff) @@ -345,13 +298,23 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, for (int j = 0; j < nvp; ++j) { if (p[j] == MESH_NULL_IDX) break; + int nj = j+1; + if (nj >= nvp || p[nj] == MESH_NULL_IDX) nj = 0; + const unsigned short* va = ¶ms->verts[p[j]*3]; + const unsigned short* vb = ¶ms->verts[p[nj]*3]; + edgeCount++; - if (p[nvp+j] & 0x8000) + if (params->tileSize > 0) { - unsigned short dir = p[nvp+j] & 0xf; - if (dir != 0xf) - portalCount++; + if (va[0] == params->tileSize && vb[0] == params->tileSize) + portalCount++; // x+ + else if (va[2] == params->tileSize && vb[2] == params->tileSize) + portalCount++; // z+ + else if (va[0] == 0 && vb[0] == 0) + portalCount++; // x- + else if (va[2] == 0 && vb[2] == 0) + portalCount++; // z- } } } @@ -360,41 +323,18 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, // Find unique detail vertices. int uniqueDetailVertCount = 0; - int detailTriCount = 0; - if (params->detailMeshes) - { - // Has detail mesh, count unique detail vertex count and use input detail tri count. - detailTriCount = params->detailTriCount; - for (int i = 0; i < params->polyCount; ++i) - { - const unsigned short* p = ¶ms->polys[i*nvp*2]; - int ndv = params->detailMeshes[i*4+1]; - int nv = 0; - for (int j = 0; j < nvp; ++j) - { - if (p[j] == MESH_NULL_IDX) break; - nv++; - } - ndv -= nv; - uniqueDetailVertCount += ndv; - } - } - else + for (int i = 0; i < params->polyCount; ++i) { - // No input detail mesh, build detail mesh from nav polys. - uniqueDetailVertCount = 0; // No extra detail verts. - detailTriCount = 0; - for (int i = 0; i < params->polyCount; ++i) + const unsigned short* p = ¶ms->polys[i*nvp*2]; + int ndv = params->detailMeshes[i*4+1]; + int nv = 0; + for (int j = 0; j < nvp; ++j) { - const unsigned short* p = ¶ms->polys[i*nvp*2]; - int nv = 0; - for (int j = 0; j < nvp; ++j) - { - if (p[j] == MESH_NULL_IDX) break; - nv++; - } - detailTriCount += nv-2; + if (p[j] == MESH_NULL_IDX) break; + nv++; } + ndv -= nv; + uniqueDetailVertCount += ndv; } // Calculate data size @@ -404,8 +344,8 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, const int linksSize = dtAlign4(sizeof(dtLink)*maxLinkCount); const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount); const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount); - const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*detailTriCount); - const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode)*params->polyCount*2) : 0; + const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*params->detailTriCount); + const int bvTreeSize = dtAlign4(sizeof(dtBVNode)*params->polyCount*2); const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection)*storedOffMeshConCount); const int dataSize = headerSize + vertsSize + polysSize + linksSize + @@ -437,7 +377,6 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, header->version = DT_NAVMESH_VERSION; header->x = params->tileX; header->y = params->tileY; - header->layer = params->tileLayer; header->userId = params->userId; header->polyCount = totPolyCount; header->vertCount = totVertCount; @@ -446,14 +385,14 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, dtVcopy(header->bmax, params->bmax); header->detailMeshCount = params->polyCount; header->detailVertCount = uniqueDetailVertCount; - header->detailTriCount = detailTriCount; + header->detailTriCount = params->detailTriCount; header->bvQuantFactor = 1.0f / params->cs; header->offMeshBase = params->polyCount; header->walkableHeight = params->walkableHeight; header->walkableRadius = params->walkableRadius; header->walkableClimb = params->walkableClimb; header->offMeshConCount = storedOffMeshConCount; - header->bvNodeCount = params->buildBvTree ? params->polyCount*2 : 0; + header->bvNodeCount = params->polyCount*2; const int offMeshVertsBase = params->vertCount; const int offMeshPolyBase = params->polyCount; @@ -497,27 +436,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, { if (src[j] == MESH_NULL_IDX) break; p->verts[j] = src[j]; - if (src[nvp+j] & 0x8000) - { - // Border or portal edge. - unsigned short dir = src[nvp+j] & 0xf; - if (dir == 0xf) // Border - p->neis[j] = 0; - else if (dir == 0) // Portal x- - p->neis[j] = DT_EXT_LINK | 4; - else if (dir == 1) // Portal z+ - p->neis[j] = DT_EXT_LINK | 2; - else if (dir == 2) // Portal x+ - p->neis[j] = DT_EXT_LINK | 0; - else if (dir == 3) // Portal z- - p->neis[j] = DT_EXT_LINK | 6; - } - else - { - // Normal connection - p->neis[j] = src[nvp+j]+1; - } - + p->neis[j] = (src[nvp+j]+1) & 0xffff; p->vertCount++; } src += nvp*2; @@ -539,68 +458,61 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, n++; } } - - // Store detail meshes and vertices. - // The nav polygon vertices are stored as the first vertices on each mesh. - // We compress the mesh data by skipping them and using the navmesh coordinates. - if (params->detailMeshes) + + // Store portal edges. + if (params->tileSize > 0) { - unsigned short vbase = 0; for (int i = 0; i < params->polyCount; ++i) { - dtPolyDetail& dtl = navDMeshes[i]; - const int vb = (int)params->detailMeshes[i*4+0]; - const int ndv = (int)params->detailMeshes[i*4+1]; - const int nv = navPolys[i].vertCount; - dtl.vertBase = (unsigned int)vbase; - dtl.vertCount = (unsigned char)(ndv-nv); - dtl.triBase = (unsigned int)params->detailMeshes[i*4+2]; - dtl.triCount = (unsigned char)params->detailMeshes[i*4+3]; - // Copy vertices except the first 'nv' verts which are equal to nav poly verts. - if (ndv-nv) + dtPoly* poly = &navPolys[i]; + for (int j = 0; j < poly->vertCount; ++j) { - memcpy(&navDVerts[vbase*3], ¶ms->detailVerts[(vb+nv)*3], sizeof(float)*3*(ndv-nv)); - vbase += (unsigned short)(ndv-nv); + int nj = j+1; + if (nj >= poly->vertCount) nj = 0; + + const unsigned short* va = ¶ms->verts[poly->verts[j]*3]; + const unsigned short* vb = ¶ms->verts[poly->verts[nj]*3]; + + if (va[0] == params->tileSize && vb[0] == params->tileSize) // x+ + poly->neis[j] = DT_EXT_LINK | 0; + else if (va[2] == params->tileSize && vb[2] == params->tileSize) // z+ + poly->neis[j] = DT_EXT_LINK | 2; + else if (va[0] == 0 && vb[0] == 0) // x- + poly->neis[j] = DT_EXT_LINK | 4; + else if (va[2] == 0 && vb[2] == 0) // z- + poly->neis[j] = DT_EXT_LINK | 6; } } - // Store triangles. - memcpy(navDTris, params->detailTris, sizeof(unsigned char)*4*params->detailTriCount); } - else + + // Store detail meshes and vertices. + // The nav polygon vertices are stored as the first vertices on each mesh. + // We compress the mesh data by skipping them and using the navmesh coordinates. + unsigned short vbase = 0; + for (int i = 0; i < params->polyCount; ++i) { - // Create dummy detail mesh by triangulating polys. - int tbase = 0; - for (int i = 0; i < params->polyCount; ++i) + dtPolyDetail& dtl = navDMeshes[i]; + const int vb = (int)params->detailMeshes[i*4+0]; + const int ndv = (int)params->detailMeshes[i*4+1]; + const int nv = navPolys[i].vertCount; + dtl.vertBase = (unsigned int)vbase; + dtl.vertCount = (unsigned char)(ndv-nv); + dtl.triBase = (unsigned int)params->detailMeshes[i*4+2]; + dtl.triCount = (unsigned char)params->detailMeshes[i*4+3]; + // Copy vertices except the first 'nv' verts which are equal to nav poly verts. + if (ndv-nv) { - dtPolyDetail& dtl = navDMeshes[i]; - const int nv = navPolys[i].vertCount; - dtl.vertBase = 0; - dtl.vertCount = 0; - dtl.triBase = (unsigned int)tbase; - dtl.triCount = (unsigned char)(nv-2); - // Triangulate polygon (local indices). - for (int j = 2; j < nv; ++j) - { - unsigned char* t = &navDTris[tbase*4]; - t[0] = 0; - t[1] = (unsigned char)(j-1); - t[2] = (unsigned char)j; - // Bit for each edge that belongs to poly boundary. - t[3] = (1<<2); - if (j == 2) t[3] |= (1<<0); - if (j == nv-1) t[3] |= (1<<4); - tbase++; - } + memcpy(&navDVerts[vbase*3], ¶ms->detailVerts[(vb+nv)*3], sizeof(float)*3*(ndv-nv)); + vbase += (unsigned short)(ndv-nv); } } + // Store triangles. + memcpy(navDTris, params->detailTris, sizeof(unsigned char)*4*params->detailTriCount); // Store and create BVtree. // TODO: take detail mesh into account! use byte per bbox extent? - if (params->buildBvTree) - { - createBVTree(params->verts, params->vertCount, params->polys, params->polyCount, - nvp, params->cs, params->ch, params->polyCount*2, navBvtree); - } + createBVTree(params->verts, params->vertCount, params->polys, params->polyCount, + nvp, params->cs, params->ch, params->polyCount*2, navBvtree); // Store Off-Mesh connections. n = 0; @@ -632,14 +544,51 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, return true; } +inline void swapByte(unsigned char* a, unsigned char* b) +{ + unsigned char tmp = *a; + *a = *b; + *b = tmp; +} + +inline void swapEndian(unsigned short* v) +{ + unsigned char* x = (unsigned char*)v; + swapByte(x+0, x+1); +} + +inline void swapEndian(short* v) +{ + unsigned char* x = (unsigned char*)v; + swapByte(x+0, x+1); +} + +inline void swapEndian(unsigned int* v) +{ + unsigned char* x = (unsigned char*)v; + swapByte(x+0, x+3); swapByte(x+1, x+2); +} + +inline void swapEndian(int* v) +{ + unsigned char* x = (unsigned char*)v; + swapByte(x+0, x+3); swapByte(x+1, x+2); +} + +inline void swapEndian(float* v) +{ + unsigned char* x = (unsigned char*)v; + swapByte(x+0, x+3); swapByte(x+1, x+2); +} + bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/) { dtMeshHeader* header = (dtMeshHeader*)data; int swappedMagic = DT_NAVMESH_MAGIC; int swappedVersion = DT_NAVMESH_VERSION; - dtSwapEndian(&swappedMagic); - dtSwapEndian(&swappedVersion); + swapEndian(&swappedMagic); + swapEndian(&swappedVersion); if ((header->magic != DT_NAVMESH_MAGIC || header->version != DT_NAVMESH_VERSION) && (header->magic != swappedMagic || header->version != swappedVersion)) @@ -647,43 +596,36 @@ bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/) return false; } - dtSwapEndian(&header->magic); - dtSwapEndian(&header->version); - dtSwapEndian(&header->x); - dtSwapEndian(&header->y); - dtSwapEndian(&header->layer); - dtSwapEndian(&header->userId); - dtSwapEndian(&header->polyCount); - dtSwapEndian(&header->vertCount); - dtSwapEndian(&header->maxLinkCount); - dtSwapEndian(&header->detailMeshCount); - dtSwapEndian(&header->detailVertCount); - dtSwapEndian(&header->detailTriCount); - dtSwapEndian(&header->bvNodeCount); - dtSwapEndian(&header->offMeshConCount); - dtSwapEndian(&header->offMeshBase); - dtSwapEndian(&header->walkableHeight); - dtSwapEndian(&header->walkableRadius); - dtSwapEndian(&header->walkableClimb); - dtSwapEndian(&header->bmin[0]); - dtSwapEndian(&header->bmin[1]); - dtSwapEndian(&header->bmin[2]); - dtSwapEndian(&header->bmax[0]); - dtSwapEndian(&header->bmax[1]); - dtSwapEndian(&header->bmax[2]); - dtSwapEndian(&header->bvQuantFactor); + swapEndian(&header->magic); + swapEndian(&header->version); + swapEndian(&header->x); + swapEndian(&header->y); + swapEndian(&header->userId); + swapEndian(&header->polyCount); + swapEndian(&header->vertCount); + swapEndian(&header->maxLinkCount); + swapEndian(&header->detailMeshCount); + swapEndian(&header->detailVertCount); + swapEndian(&header->detailTriCount); + swapEndian(&header->bvNodeCount); + swapEndian(&header->offMeshConCount); + swapEndian(&header->offMeshBase); + swapEndian(&header->walkableHeight); + swapEndian(&header->walkableRadius); + swapEndian(&header->walkableClimb); + swapEndian(&header->bmin[0]); + swapEndian(&header->bmin[1]); + swapEndian(&header->bmin[2]); + swapEndian(&header->bmax[0]); + swapEndian(&header->bmax[1]); + swapEndian(&header->bmax[2]); + swapEndian(&header->bvQuantFactor); // Freelist index and pointers are updated when tile is added, no need to swap. return true; } -/// @par -/// -/// @warning This function assumes that the header is in the correct endianess already. -/// Call #dtNavMeshHeaderSwapEndian() first on the data if the data is expected to be in wrong endianess -/// to start with. Call #dtNavMeshHeaderSwapEndian() after the data has been swapped if converting from -/// native to foreign endianess. bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/) { // Make sure the data is in right format. @@ -717,7 +659,7 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/) // Vertices for (int i = 0; i < header->vertCount*3; ++i) { - dtSwapEndian(&verts[i]); + swapEndian(&verts[i]); } // Polys @@ -727,10 +669,10 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/) // poly->firstLink is update when tile is added, no need to swap. for (int j = 0; j < DT_VERTS_PER_POLYGON; ++j) { - dtSwapEndian(&p->verts[j]); - dtSwapEndian(&p->neis[j]); + swapEndian(&p->verts[j]); + swapEndian(&p->neis[j]); } - dtSwapEndian(&p->flags); + swapEndian(&p->flags); } // Links are rebuild when tile is added, no need to swap. @@ -739,14 +681,14 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/) for (int i = 0; i < header->detailMeshCount; ++i) { dtPolyDetail* pd = &detailMeshes[i]; - dtSwapEndian(&pd->vertBase); - dtSwapEndian(&pd->triBase); + swapEndian(&pd->vertBase); + swapEndian(&pd->triBase); } // Detail verts for (int i = 0; i < header->detailVertCount*3; ++i) { - dtSwapEndian(&detailVerts[i]); + swapEndian(&detailVerts[i]); } // BV-tree @@ -755,10 +697,10 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/) dtBVNode* node = &bvTree[i]; for (int j = 0; j < 3; ++j) { - dtSwapEndian(&node->bmin[j]); - dtSwapEndian(&node->bmax[j]); + swapEndian(&node->bmin[j]); + swapEndian(&node->bmax[j]); } - dtSwapEndian(&node->i); + swapEndian(&node->i); } // Off-mesh Connections. @@ -766,9 +708,9 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/) { dtOffMeshConnection* con = &offMeshCons[i]; for (int j = 0; j < 6; ++j) - dtSwapEndian(&con->pos[j]); - dtSwapEndian(&con->rad); - dtSwapEndian(&con->poly); + swapEndian(&con->pos[j]); + swapEndian(&con->rad); + swapEndian(&con->poly); } return true; diff --git a/dep/recastnavigation/Detour/DetourNavMeshBuilder.h b/dep/recastnavigation/Detour/DetourNavMeshBuilder.h index c80d171..8d8ef2e 100644 --- a/dep/recastnavigation/Detour/DetourNavMeshBuilder.h +++ b/dep/recastnavigation/Detour/DetourNavMeshBuilder.h @@ -21,128 +21,57 @@ #include "DetourAlloc.h" -/// Represents the source data used to build an navigation mesh tile. -/// @ingroup detour + +// The units of the parameters are specified in parenthesis as follows: +// (vx) voxels, (wu) world units struct dtNavMeshCreateParams { - - /// @name Polygon Mesh Attributes - /// Used to create the base navigation graph. - /// See #rcPolyMesh for details related to these attributes. - /// @{ - - const unsigned short* verts; ///< The polygon mesh vertices. [(x, y, z) * #vertCount] [Unit: vx] - int vertCount; ///< The number vertices in the polygon mesh. [Limit: >= 3] - const unsigned short* polys; ///< The polygon data. [Size: #polyCount * 2 * #nvp] - const unsigned short* polyFlags; ///< The user defined flags assigned to each polygon. [Size: #polyCount] - const unsigned char* polyAreas; ///< The user defined area ids assigned to each polygon. [Size: #polyCount] - int polyCount; ///< Number of polygons in the mesh. [Limit: >= 1] - int nvp; ///< Number maximum number of vertices per polygon. [Limit: >= 3] - - /// @} - /// @name Height Detail Attributes (Optional) - /// See #rcPolyMeshDetail for details related to these attributes. - /// @{ - - const unsigned int* detailMeshes; ///< The height detail sub-mesh data. [Size: 4 * #polyCount] - const float* detailVerts; ///< The detail mesh vertices. [Size: 3 * #detailVertsCount] [Unit: wu] - int detailVertsCount; ///< The number of vertices in the detail mesh. - const unsigned char* detailTris; ///< The detail mesh triangles. [Size: 4 * #detailTriCount] - int detailTriCount; ///< The number of triangles in the detail mesh. - - /// @} - /// @name Off-Mesh Connections Attributes (Optional) - /// Used to define a custom point-to-point edge within the navigation graph, an - /// off-mesh connection is a user defined traversable connection made up to two vertices, - /// at least one of which resides within a navigation mesh polygon. - /// @{ - - /// Off-mesh connection vertices. [(ax, ay, az, bx, by, bz) * #offMeshConCount] [Unit: wu] - const float* offMeshConVerts; - /// Off-mesh connection radii. [Size: #offMeshConCount] [Unit: wu] - const float* offMeshConRad; - /// User defined flags assigned to the off-mesh connections. [Size: #offMeshConCount] - const unsigned short* offMeshConFlags; - /// User defined area ids assigned to the off-mesh connections. [Size: #offMeshConCount] - const unsigned char* offMeshConAreas; - /// The permitted travel direction of the off-mesh connections. [Size: #offMeshConCount] - /// - /// 0 = Travel only from endpoint A to endpoint B.
- /// #DT_OFFMESH_CON_BIDIR = Bidirectional travel. - const unsigned char* offMeshConDir; - /// The user defined ids of the off-mesh connection. [Size: #offMeshConCount] - const unsigned int* offMeshConUserID; - /// The number of off-mesh connections. [Limit: >= 0] - int offMeshConCount; - - /// @} - /// @name Tile Attributes - /// @note The tile grid/layer data can be left at zero if the destination is a single tile mesh. - /// @{ - - unsigned int userId; ///< The user defined id of the tile. - int tileX; ///< The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.) - int tileY; ///< The tile's y-grid location within the multi-tile desitation mesh. (Along the z-axis.) - int tileLayer; ///< The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.) - float bmin[3]; ///< The minimum bounds of the tile. [(x, y, z)] [Unit: wu] - float bmax[3]; ///< The maximum bounds of the tile. [(x, y, z)] [Unit: wu] - - /// @} - /// @name General Configuration Attributes - /// @{ - - float walkableHeight; ///< The agent height. [Unit: wu] - float walkableRadius; ///< The agent radius. [Unit: wu] - float walkableClimb; ///< The agent maximum traversable ledge. (Up/Down) [Unit: wu] - float cs; ///< The xz-plane cell size of the polygon mesh. [Limit: > 0] [Unit: wu] - float ch; ///< The y-axis cell height of the polygon mesh. [Limit: > 0] [Unit: wu] - - /// True if a bounding volume tree should be built for the tile. - /// @note The BVTree is not normally needed for layered navigation meshes. - bool buildBvTree; - - /// @} + // Navmesh vertices. + const unsigned short* verts; // Array of vertices, each vertex has 3 components. (vx). + int vertCount; // Vertex count + // Navmesh polygons + const unsigned short* polys; // Array of polygons, uses same format as rcPolyMesh. + const unsigned short* polyFlags; // Array of flags per polygon. + const unsigned char* polyAreas; // Array of area ids per polygon. + int polyCount; // Number of polygons + int nvp; // Number of verts per polygon. + // Navmesh Detail + const unsigned int* detailMeshes; // Detail meshes, uses same format as rcPolyMeshDetail. + const float* detailVerts; // Detail mesh vertices, uses same format as rcPolyMeshDetail (wu). + int detailVertsCount; // Total number of detail vertices + const unsigned char* detailTris; // Array of detail tris per detail mesh. + int detailTriCount; // Total number of detail triangles. + // Off-Mesh Connections. + const float* offMeshConVerts; // Off-mesh connection vertices (wu). + const float* offMeshConRad; // Off-mesh connection radii (wu). + const unsigned short* offMeshConFlags; // Off-mesh connection flags. + const unsigned char* offMeshConAreas; // Off-mesh connection area ids. + const unsigned char* offMeshConDir; // Off-mesh connection direction flags (1 = bidir, 0 = oneway). + const unsigned int* offMeshConUserID; // Off-mesh connection user id (optional). + int offMeshConCount; // Number of off-mesh connections + // Tile location + unsigned int userId; // User ID bound to the tile. + int tileX, tileY; // Tile location (tile coords). + float bmin[3], bmax[3]; // Tile bounds (wu). + // Settings + float walkableHeight; // Agent height (wu). + float walkableRadius; // Agent radius (wu). + float walkableClimb; // Agent max climb (wu). + float cs; // Cell size (xz) (wu). + float ch; // Cell height (y) (wu). + int tileSize; // Tile size (width & height) (vx). }; -/// Builds navigation mesh tile data from the provided tile creation data. -/// @ingroup detour -/// @param[in] params Tile creation data. -/// @param[out] outData The resulting tile data. -/// @param[out] outDataSize The size of the tile data array. -/// @return True if the tile data was successfully created. +// Build navmesh data from given input data. bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize); -/// Swaps the endianess of the tile data's header (#dtMeshHeader). -/// @param[in,out] data The tile data array. -/// @param[in] dataSize The size of the data array. +// Swaps endianess of navmesh header. bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int dataSize); -/// Swaps endianess of the tile data. -/// @param[in,out] data The tile data array. -/// @param[in] dataSize The size of the data array. +// Swaps endianess of the navmesh data. This function assumes that the header is in correct +// endianess already. Call dtNavMeshHeaderSwapEndian() first on the data if the data is +// assumed to be in wrong endianess to start with. If converting from native endianess to foreign, +// call dtNavMeshHeaderSwapEndian() after the data has been swapped. bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize); #endif // DETOURNAVMESHBUILDER_H - -// This section contains detailed documentation for members that don't have -// a source file. It reduces clutter in the main section of the header. - -/** - -@struct dtNavMeshCreateParams -@par - -This structure is used to marshal data between the Recast mesh generation pipeline and Detour navigation components. - -See the rcPolyMesh and rcPolyMeshDetail documentation for detailed information related to mesh structure. - -Units are usually in voxels (vx) or world units (wu). The units for voxels, grid size, and cell size -are all based on the values of #cs and #ch. - -The standard navigation mesh build process is to create tile data using dtCreateNavMeshData, then add the tile -to a navigation mesh using either the dtNavMesh single tile init() function or the dtNavMesh::addTile() -function. - -@see dtCreateNavMeshData - -*/ \ No newline at end of file diff --git a/dep/recastnavigation/Detour/DetourNavMeshQuery.cpp b/dep/recastnavigation/Detour/DetourNavMeshQuery.cpp index e6557cf..6a6eb94 100644 --- a/dep/recastnavigation/Detour/DetourNavMeshQuery.cpp +++ b/dep/recastnavigation/Detour/DetourNavMeshQuery.cpp @@ -27,38 +27,6 @@ #include "DetourAssert.h" #include -/// @class dtQueryFilter -/// -/// The Default Implementation -/// -/// At construction: All area costs default to 1.0. All flags are included -/// and none are excluded. -/// -/// If a polygon has both an include and an exclude flag, it will be excluded. -/// -/// The way filtering works, a navigation mesh polygon must have at least one flag -/// set to ever be considered by a query. So a polygon with no flags will never -/// be considered. -/// -/// Setting the include flags to 0 will result in all polygons being excluded. -/// -/// Custom Implementations -/// -/// DT_VIRTUAL_QUERYFILTER must be defined in order to extend this class. -/// -/// Implement a custom query filter by overriding the virtual passFilter() -/// and getCost() functions. If this is done, both functions should be as -/// fast as possible. Use cached local copies of data rather than accessing -/// your own objects where possible. -/// -/// Custom implementations do not need to adhere to the flags or cost logic -/// used by the default implementation. -/// -/// In order for A* searches to work properly, the cost should be proportional to -/// the travel distance. Implementing a cost modifier less than 1.0 is likely -/// to lead to problems during pathfinding. -/// -/// @see dtNavMeshQuery dtQueryFilter::dtQueryFilter() : m_includeFlags(0xffff), @@ -81,7 +49,7 @@ float dtQueryFilter::getCost(const float* pa, const float* pb, const dtPolyRef /*curRef*/, const dtMeshTile* /*curTile*/, const dtPoly* curPoly, const dtPolyRef /*nextRef*/, const dtMeshTile* /*nextTile*/, const dtPoly* /*nextPoly*/) const { - return dtVdist(pa, pb) * m_areaCost[curPoly->getArea()]; + return dtVdist(pa, pb) * m_areaCost[curPoly->area]; } #else inline bool dtQueryFilter::passFilter(const dtPolyRef /*ref*/, @@ -99,9 +67,8 @@ inline float dtQueryFilter::getCost(const float* pa, const float* pb, return dtVdist(pa, pb) * m_areaCost[curPoly->getArea()]; } #endif - -// Edited by TC -static const float H_SCALE = 2.0f; // Search heuristic scale. + +static const float H_SCALE = 2.0f; // Search heuristic scale. dtNavMeshQuery* dtAllocNavMeshQuery() @@ -119,25 +86,7 @@ void dtFreeNavMeshQuery(dtNavMeshQuery* navmesh) } ////////////////////////////////////////////////////////////////////////////////////////// - -/// @class dtNavMeshQuery -/// -/// For methods that support undersized buffers, if the buffer is too small -/// to hold the entire result set the return status of the method will include -/// the #DT_BUFFER_TOO_SMALL flag. -/// -/// Constant member functions can be used by multiple clients without side -/// effects. (E.g. No change to the closed list. No impact on an in-progress -/// sliced path query. Etc.) -/// -/// Walls and portals: A @e wall is a polygon segment that is -/// considered impassable. A @e portal is a passable segment between polygons. -/// A portal may be treated as a wall based on the dtQueryFilter used for a query. -/// -/// @see dtNavMesh, dtQueryFilter, #dtAllocNavMeshQuery(), #dtAllocNavMeshQuery() - dtNavMeshQuery::dtNavMeshQuery() : - m_nav(0), m_tinyNodePool(0), m_nodePool(0), m_openList(0) @@ -158,12 +107,6 @@ dtNavMeshQuery::~dtNavMeshQuery() dtFree(m_openList); } -/// @par -/// -/// Must be the first function called after construction, before other -/// functions are used. -/// -/// This function can be used multiple times. dtStatus dtNavMeshQuery::init(const dtNavMesh* nav, const int maxNodes) { m_nav = nav; @@ -178,7 +121,7 @@ dtStatus dtNavMeshQuery::init(const dtNavMesh* nav, const int maxNodes) } m_nodePool = new (dtAlloc(sizeof(dtNodePool), DT_ALLOC_PERM)) dtNodePool(maxNodes, dtNextPow2(maxNodes/4)); if (!m_nodePool) - return DT_FAILURE | DT_OUT_OF_MEMORY; + return DT_FAILURE_OUT_OF_MEMORY; } else { @@ -189,7 +132,7 @@ dtStatus dtNavMeshQuery::init(const dtNavMesh* nav, const int maxNodes) { m_tinyNodePool = new (dtAlloc(sizeof(dtNodePool), DT_ALLOC_PERM)) dtNodePool(64, 32); if (!m_tinyNodePool) - return DT_FAILURE | DT_OUT_OF_MEMORY; + return DT_FAILURE_OUT_OF_MEMORY; } else { @@ -207,7 +150,7 @@ dtStatus dtNavMeshQuery::init(const dtNavMesh* nav, const int maxNodes) } m_openList = new (dtAlloc(sizeof(dtNodeQueue), DT_ALLOC_PERM)) dtNodeQueue(maxNodes); if (!m_openList) - return DT_FAILURE | DT_OUT_OF_MEMORY; + return DT_FAILURE_OUT_OF_MEMORY; } else { @@ -217,328 +160,33 @@ dtStatus dtNavMeshQuery::init(const dtNavMesh* nav, const int maxNodes) return DT_SUCCESS; } -dtStatus dtNavMeshQuery::findRandomPoint(const dtQueryFilter* filter, float (*frand)(), - dtPolyRef* randomRef, float* randomPt) const -{ - dtAssert(m_nav); - - // Randomly pick one tile. Assume that all tiles cover roughly the same area. - const dtMeshTile* tile = 0; - float tsum = 0.0f; - for (int i = 0; i < m_nav->getMaxTiles(); i++) - { - const dtMeshTile* t = m_nav->getTile(i); - if (!t || !t->header) continue; - - // Choose random tile using reservoi sampling. - const float area = 1.0f; // Could be tile area too. - tsum += area; - const float u = frand(); - if (u*tsum <= area) - tile = t; - } - if (!tile) - return DT_FAILURE; - - // Randomly pick one polygon weighted by polygon area. - const dtPoly* poly = 0; - dtPolyRef polyRef = 0; - const dtPolyRef base = m_nav->getPolyRefBase(tile); - - float areaSum = 0.0f; - for (int i = 0; i < tile->header->polyCount; ++i) - { - const dtPoly* p = &tile->polys[i]; - // Do not return off-mesh connection polygons. - if (p->getType() != DT_POLYTYPE_GROUND) - continue; - // Must pass filter - const dtPolyRef ref = base | (dtPolyRef)i; - if (!filter->passFilter(ref, tile, p)) - continue; - - // Calc area of the polygon. - float polyArea = 0.0f; - for (int j = 2; j < p->vertCount; ++j) - { - const float* va = &tile->verts[p->verts[0]*3]; - const float* vb = &tile->verts[p->verts[j-1]*3]; - const float* vc = &tile->verts[p->verts[j]*3]; - polyArea += dtTriArea2D(va,vb,vc); - } - - // Choose random polygon weighted by area, using reservoi sampling. - areaSum += polyArea; - const float u = frand(); - if (u*areaSum <= polyArea) - { - poly = p; - polyRef = ref; - } - } - - if (!poly) - return DT_FAILURE; - - // Randomly pick point on polygon. - const float* v = &tile->verts[poly->verts[0]*3]; - float verts[3*DT_VERTS_PER_POLYGON]; - float areas[DT_VERTS_PER_POLYGON]; - dtVcopy(&verts[0*3],v); - for (int j = 1; j < poly->vertCount; ++j) - { - v = &tile->verts[poly->verts[j]*3]; - dtVcopy(&verts[j*3],v); - } - - const float s = frand(); - const float t = frand(); - - float pt[3]; - dtRandomPointInConvexPoly(verts, poly->vertCount, areas, s, t, pt); - - float h = 0.0f; - dtStatus status = getPolyHeight(polyRef, pt, &h); - if (dtStatusFailed(status)) - return status; - pt[1] = h; - - dtVcopy(randomPt, pt); - *randomRef = polyRef; - - return DT_SUCCESS; -} - -dtStatus dtNavMeshQuery::findRandomPointAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius, - const dtQueryFilter* filter, float (*frand)(), - dtPolyRef* randomRef, float* randomPt) const -{ - dtAssert(m_nav); - dtAssert(m_nodePool); - dtAssert(m_openList); - - // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; - - const dtMeshTile* startTile = 0; - const dtPoly* startPoly = 0; - m_nav->getTileAndPolyByRefUnsafe(startRef, &startTile, &startPoly); - if (!filter->passFilter(startRef, startTile, startPoly)) - return DT_FAILURE | DT_INVALID_PARAM; - - m_nodePool->clear(); - m_openList->clear(); - - dtNode* startNode = m_nodePool->getNode(startRef); - dtVcopy(startNode->pos, centerPos); - startNode->pidx = 0; - startNode->cost = 0; - startNode->total = 0; - startNode->id = startRef; - startNode->flags = DT_NODE_OPEN; - m_openList->push(startNode); - - dtStatus status = DT_SUCCESS; - - const float radiusSqr = dtSqr(radius); - float areaSum = 0.0f; - - const dtMeshTile* randomTile = 0; - const dtPoly* randomPoly = 0; - dtPolyRef randomPolyRef = 0; - - while (!m_openList->empty()) - { - dtNode* bestNode = m_openList->pop(); - bestNode->flags &= ~DT_NODE_OPEN; - bestNode->flags |= DT_NODE_CLOSED; - - // Get poly and tile. - // The API input has been cheked already, skip checking internal data. - const dtPolyRef bestRef = bestNode->id; - const dtMeshTile* bestTile = 0; - const dtPoly* bestPoly = 0; - m_nav->getTileAndPolyByRefUnsafe(bestRef, &bestTile, &bestPoly); - - // Place random locations on on ground. - if (bestPoly->getType() == DT_POLYTYPE_GROUND) - { - // Calc area of the polygon. - float polyArea = 0.0f; - for (int j = 2; j < bestPoly->vertCount; ++j) - { - const float* va = &bestTile->verts[bestPoly->verts[0]*3]; - const float* vb = &bestTile->verts[bestPoly->verts[j-1]*3]; - const float* vc = &bestTile->verts[bestPoly->verts[j]*3]; - polyArea += dtTriArea2D(va,vb,vc); - } - // Choose random polygon weighted by area, using reservoi sampling. - areaSum += polyArea; - const float u = frand(); - if (u*areaSum <= polyArea) - { - randomTile = bestTile; - randomPoly = bestPoly; - randomPolyRef = bestRef; - } - } - - - // Get parent poly and tile. - dtPolyRef parentRef = 0; - const dtMeshTile* parentTile = 0; - const dtPoly* parentPoly = 0; - if (bestNode->pidx) - parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id; - if (parentRef) - m_nav->getTileAndPolyByRefUnsafe(parentRef, &parentTile, &parentPoly); - - for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next) - { - const dtLink* link = &bestTile->links[i]; - dtPolyRef neighbourRef = link->ref; - // Skip invalid neighbours and do not follow back to parent. - if (!neighbourRef || neighbourRef == parentRef) - continue; - - // Expand to neighbour - const dtMeshTile* neighbourTile = 0; - const dtPoly* neighbourPoly = 0; - m_nav->getTileAndPolyByRefUnsafe(neighbourRef, &neighbourTile, &neighbourPoly); - - // Do not advance if the polygon is excluded by the filter. - if (!filter->passFilter(neighbourRef, neighbourTile, neighbourPoly)) - continue; - - // Find edge and calc distance to the edge. - float va[3], vb[3]; - if (!getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, neighbourTile, va, vb)) - continue; - - // If the circle is not touching the next polygon, skip it. - float tseg; - float distSqr = dtDistancePtSegSqr2D(centerPos, va, vb, tseg); - if (distSqr > radiusSqr) - continue; - - dtNode* neighbourNode = m_nodePool->getNode(neighbourRef); - if (!neighbourNode) - { - status |= DT_OUT_OF_NODES; - continue; - } - - if (neighbourNode->flags & DT_NODE_CLOSED) - continue; - - // Cost - if (neighbourNode->flags == 0) - dtVlerp(neighbourNode->pos, va, vb, 0.5f); - - const float total = bestNode->total + dtVdist(bestNode->pos, neighbourNode->pos); - - // The node is already in open list and the new result is worse, skip. - if ((neighbourNode->flags & DT_NODE_OPEN) && total >= neighbourNode->total) - continue; - - neighbourNode->id = neighbourRef; - neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED); - neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode); - neighbourNode->total = total; - - if (neighbourNode->flags & DT_NODE_OPEN) - { - m_openList->modify(neighbourNode); - } - else - { - neighbourNode->flags = DT_NODE_OPEN; - m_openList->push(neighbourNode); - } - } - } - - if (!randomPoly) - return DT_FAILURE; - - // Randomly pick point on polygon. - const float* v = &randomTile->verts[randomPoly->verts[0]*3]; - float verts[3*DT_VERTS_PER_POLYGON]; - float areas[DT_VERTS_PER_POLYGON]; - dtVcopy(&verts[0*3],v); - for (int j = 1; j < randomPoly->vertCount; ++j) - { - v = &randomTile->verts[randomPoly->verts[j]*3]; - dtVcopy(&verts[j*3],v); - } - - const float s = frand(); - const float t = frand(); - - float pt[3]; - dtRandomPointInConvexPoly(verts, randomPoly->vertCount, areas, s, t, pt); - - float h = 0.0f; - dtStatus stat = getPolyHeight(randomPolyRef, pt, &h); - if (dtStatusFailed(status)) - return stat; - pt[1] = h; - - dtVcopy(randomPt, pt); - *randomRef = randomPolyRef; - - return DT_SUCCESS; -} - - ////////////////////////////////////////////////////////////////////////////////////////// - -/// @par -/// -/// Uses the detail polygons to find the surface height. (Most accurate.) -/// -/// @p pos does not have to be within the bounds of the polygon or navigation mesh. -/// -/// See closestPointOnPolyBoundary() for a limited but faster option. -/// dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const { dtAssert(m_nav); const dtMeshTile* tile = 0; const dtPoly* poly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) - return DT_FAILURE | DT_INVALID_PARAM; - if (!tile) - return DT_FAILURE | DT_INVALID_PARAM; + if (m_nav->getTileAndPolyByRef(ref, &tile, &poly) != DT_SUCCESS) + return DT_FAILURE; + if (!tile) return DT_FAILURE; - // Edited by TC - if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) + if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) return DT_FAILURE; - closestPointOnPolyInTile(tile, poly, pos, closest); - + if (closestPointOnPolyInTile(tile, poly, pos, closest) != DT_SUCCESS) + return DT_FAILURE; return DT_SUCCESS; } -void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly, - const float* pos, float* closest) const +dtStatus dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly, + const float* pos, float* closest) const { - // Off-mesh connections don't have detail polygons. - if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) - { - const float* v0 = &tile->verts[poly->verts[0]*3]; - const float* v1 = &tile->verts[poly->verts[1]*3]; - const float d0 = dtVdist(pos, v0); - const float d1 = dtVdist(pos, v1); - const float u = d0 / (d0+d1); - dtVlerp(closest, v0, v1, u); - return; - } - const unsigned int ip = (unsigned int)(poly - tile->polys); const dtPolyDetail* pd = &tile->detailMeshes[ip]; + // TODO: The commented out version finds 'cylinder distance' instead of 'sphere distance' to the navmesh. + // Test and enable. +/* // Clamp point to be inside the polygon. float verts[DT_VERTS_PER_POLYGON*3]; float edged[DT_VERTS_PER_POLYGON]; @@ -585,8 +233,8 @@ void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPo break; } } - -/* float closestDistSqr = FLT_MAX; +*/ + float closestDistSqr = FLT_MAX; for (int j = 0; j < pd->triCount; ++j) { const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4]; @@ -608,28 +256,19 @@ void dtNavMeshQuery::closestPointOnPolyInTile(const dtMeshTile* tile, const dtPo dtVcopy(closest, pt); closestDistSqr = d; } - }*/ + } + + return DT_SUCCESS; } -/// @par -/// -/// Much faster than closestPointOnPoly(). -/// -/// If the provided position lies within the polygon's xz-bounds (above or below), -/// then @p pos and @p closest will be equal. -/// -/// The height of @p closest will be the polygon boundary. The height detail is not used. -/// -/// @p pos does not have to be within the bounds of the polybon or the navigation mesh. -/// dtStatus dtNavMeshQuery::closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const { dtAssert(m_nav); const dtMeshTile* tile = 0; const dtPoly* poly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) - return DT_FAILURE | DT_INVALID_PARAM; + if (m_nav->getTileAndPolyByRef(ref, &tile, &poly) != DT_SUCCESS) + return DT_FAILURE; // Collect vertices. float verts[DT_VERTS_PER_POLYGON*3]; @@ -669,19 +308,15 @@ dtStatus dtNavMeshQuery::closestPointOnPolyBoundary(dtPolyRef ref, const float* return DT_SUCCESS; } -/// @par -/// -/// Will return #DT_FAILURE if the provided position is outside the xz-bounds -/// of the polygon. -/// + dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* height) const { dtAssert(m_nav); const dtMeshTile* tile = 0; const dtPoly* poly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) - return DT_FAILURE | DT_INVALID_PARAM; + if (m_nav->getTileAndPolyByRef(ref, &tile, &poly) != DT_SUCCESS) + return DT_FAILURE; if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) { @@ -719,18 +354,9 @@ dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* h } } - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; } -/// @par -/// -/// @note If the search box does not intersect any polygons the search will -/// return #DT_SUCCESS, but @p nearestRef will be zero. So if in doubt, check -/// @p nearestRef before using @p nearestPt. -/// -/// @warning This function is not suitable for large area searches. If the search -/// extents overlaps more than 128 polygons it may return an invalid result. -/// dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* extents, const dtQueryFilter* filter, dtPolyRef* nearestRef, float* nearestPt) const @@ -742,8 +368,8 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten // Get nearby polygons from proximity grid. dtPolyRef polys[128]; int polyCount = 0; - if (dtStatusFailed(queryPolygons(center, extents, filter, polys, &polyCount, 128))) - return DT_FAILURE | DT_INVALID_PARAM; + if (queryPolygons(center, extents, filter, polys, &polyCount, 128) != DT_SUCCESS) + return DT_FAILURE; // Find nearest polygon amongst the nearby polygons. dtPolyRef nearest = 0; @@ -752,7 +378,8 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* exten { dtPolyRef ref = polys[i]; float closestPtPoly[3]; - closestPointOnPoly(ref, center, closestPtPoly); + if (closestPointOnPoly(ref, center, closestPtPoly) != DT_SUCCESS) + continue; float d = dtVdistSqr(center, closestPtPoly); if (d < nearestDistanceSqr) { @@ -790,7 +417,8 @@ dtPolyRef dtNavMeshQuery::findNearestPolyInTile(const dtMeshTile* tile, const fl dtPolyRef ref = polys[i]; const dtPoly* poly = &tile->polys[m_nav->decodePolyIdPoly(ref)]; float closestPtPoly[3]; - closestPointOnPolyInTile(tile, poly, center, closestPtPoly); + if (closestPointOnPolyInTile(tile, poly, center, closestPtPoly) != DT_SUCCESS) + continue; float d = dtVdistSqr(center, closestPtPoly); if (d < nearestDistanceSqr) @@ -872,15 +500,8 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi const dtPolyRef base = m_nav->getPolyRefBase(tile); for (int i = 0; i < tile->header->polyCount; ++i) { - const dtPoly* p = &tile->polys[i]; - // Do not return off-mesh connection polygons. - if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) - continue; - // Must pass filter - const dtPolyRef ref = base | (dtPolyRef)i; - if (!filter->passFilter(ref, tile, p)) - continue; // Calc polygon bounds. + dtPoly* p = &tile->polys[i]; const float* v = &tile->verts[p->verts[0]*3]; dtVcopy(bmin, v); dtVcopy(bmax, v); @@ -892,23 +513,18 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi } if (dtOverlapBounds(qmin,qmax, bmin,bmax)) { - if (n < maxPolys) - polys[n++] = ref; + const dtPolyRef ref = base | (dtPolyRef)i; + if (filter->passFilter(ref, tile, p)) + { + if (n < maxPolys) + polys[n++] = ref; + } } } return n; } } -/// @par -/// -/// If no polygons are found, the function will return #DT_SUCCESS with a -/// @p polyCount of zero. -/// -/// If @p polys is too small to hold the entire result set, then the array will -/// be filled to capacity. The method of choosing which polygons from the -/// full set are included in the partial result set is undefined. -/// dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents, const dtQueryFilter* filter, dtPolyRef* polys, int* polyCount, const int maxPolys) const @@ -924,23 +540,18 @@ dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents m_nav->calcTileLoc(bmin, &minx, &miny); m_nav->calcTileLoc(bmax, &maxx, &maxy); - static const int MAX_NEIS = 32; - const dtMeshTile* neis[MAX_NEIS]; - int n = 0; for (int y = miny; y <= maxy; ++y) { for (int x = minx; x <= maxx; ++x) { - const int nneis = m_nav->getTilesAt(x,y,neis,MAX_NEIS); - for (int j = 0; j < nneis; ++j) + const dtMeshTile* tile = m_nav->getTileAt(x,y); + if (!tile) continue; + n += queryPolygonsInTile(tile, bmin, bmax, filter, polys+n, maxPolys-n); + if (n >= maxPolys) { - n += queryPolygonsInTile(neis[j], bmin, bmax, filter, polys+n, maxPolys-n); - if (n >= maxPolys) - { - *polyCount = n; - return DT_SUCCESS | DT_BUFFER_TOO_SMALL; - } + *polyCount = n; + return DT_SUCCESS; } } } @@ -949,17 +560,6 @@ dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents return DT_SUCCESS; } -/// @par -/// -/// If the end polygon cannot be reached through the navigation graph, -/// the last polygon in the path will be the nearest the end polygon. -/// -/// If the path array is to small to hold the full result, it will be filled as -/// far as possible from the start polygon toward the end polygon. -/// -/// The start and end positions are used to calculate traversal costs. -/// (The y-values impact the result.) -/// dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, const float* startPos, const float* endPos, const dtQueryFilter* filter, @@ -972,14 +572,14 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, *pathCount = 0; if (!startRef || !endRef) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; if (!maxPath) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; // Validate input if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef)) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; if (startRef == endRef) { @@ -1003,8 +603,6 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, dtNode* lastBestNode = startNode; float lastBestNodeCost = startNode->total; - dtStatus status = DT_SUCCESS; - while (!m_openList->empty()) { // Remove node from open list and put it in closed list. @@ -1054,10 +652,7 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, dtNode* neighbourNode = m_nodePool->getNode(neighbourRef); if (!neighbourNode) - { - status |= DT_OUT_OF_NODES; continue; - } // If the node is visited the first time, calculate node position. if (neighbourNode->flags == 0) @@ -1110,7 +705,7 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, // Add or update the node. neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode); neighbourNode->id = neighbourRef; - neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED); + neighbourNode->flags &= ~DT_NODE_CLOSED; neighbourNode->cost = cost; neighbourNode->total = total; @@ -1135,9 +730,6 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, } } - if (lastBestNode->id != endRef) - status |= DT_PARTIAL_RESULT; - // Reverse the path. dtNode* prev = 0; dtNode* node = lastBestNode; @@ -1156,28 +748,15 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, do { path[n++] = node->id; - if (n >= maxPath) - { - status |= DT_BUFFER_TOO_SMALL; - break; - } node = m_nodePool->getNodeAtIdx(node->pidx); } - while (node); + while (node && n < maxPath); *pathCount = n; - return status; + return DT_SUCCESS; } -/// @par -/// -/// @warning Calling any non-slice methods before calling finalizeSlicedFindPath() -/// or finalizeSlicedFindPathPartial() may result in corrupted data! -/// -/// The @p filter pointer is stored and used for the duration of the sliced -/// path query. -/// dtStatus dtNavMeshQuery::initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef, const float* startPos, const float* endPos, const dtQueryFilter* filter) @@ -1196,11 +775,11 @@ dtStatus dtNavMeshQuery::initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef m_query.filter = filter; if (!startRef || !endRef) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; // Validate input if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef)) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; if (startRef == endRef) { @@ -1227,9 +806,9 @@ dtStatus dtNavMeshQuery::initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef return m_query.status; } -dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) +dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter) { - if (!dtStatusInProgress(m_query.status)) + if (m_query.status!= DT_IN_PROGRESS) return m_query.status; // Make sure the request is still valid. @@ -1253,10 +832,7 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) if (bestNode->id == m_query.endRef) { m_query.lastBestNode = bestNode; - const dtStatus details = m_query.status & DT_STATUS_DETAIL_MASK; - m_query.status = DT_SUCCESS | details; - if (doneIters) - *doneIters = iter; + m_query.status = DT_SUCCESS; return m_query.status; } @@ -1265,12 +841,10 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) const dtPolyRef bestRef = bestNode->id; const dtMeshTile* bestTile = 0; const dtPoly* bestPoly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(bestRef, &bestTile, &bestPoly))) + if (m_nav->getTileAndPolyByRef(bestRef, &bestTile, &bestPoly) != DT_SUCCESS) { // The polygon has disappeared during the sliced query, fail. m_query.status = DT_FAILURE; - if (doneIters) - *doneIters = iter; return m_query.status; } @@ -1282,12 +856,10 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id; if (parentRef) { - if (dtStatusFailed(m_nav->getTileAndPolyByRef(parentRef, &parentTile, &parentPoly))) + if (m_nav->getTileAndPolyByRef(parentRef, &parentTile, &parentPoly) != DT_SUCCESS) { // The polygon has disappeared during the sliced query, fail. m_query.status = DT_FAILURE; - if (doneIters) - *doneIters = iter; return m_query.status; } } @@ -1311,10 +883,7 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) dtNode* neighbourNode = m_nodePool->getNode(neighbourRef); if (!neighbourNode) - { - m_query.status |= DT_OUT_OF_NODES; continue; - } // If the node is visited the first time, calculate node position. if (neighbourNode->flags == 0) @@ -1367,7 +936,7 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) // Add or update the node. neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode); neighbourNode->id = neighbourRef; - neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED); + neighbourNode->flags &= ~DT_NODE_CLOSED; neighbourNode->cost = cost; neighbourNode->total = total; @@ -1394,13 +963,7 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) // Exhausted all nodes, but could not find path. if (m_openList->empty()) - { - const dtStatus details = m_query.status & DT_STATUS_DETAIL_MASK; - m_query.status = DT_SUCCESS | details; - } - - if (doneIters) - *doneIters = iter; + m_query.status = DT_SUCCESS; return m_query.status; } @@ -1409,7 +972,7 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, { *pathCount = 0; - if (dtStatusFailed(m_query.status)) + if (m_query.status != DT_SUCCESS) { // Reset query. memset(&m_query, 0, sizeof(dtQueryData)); @@ -1427,10 +990,6 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, { // Reverse the path. dtAssert(m_query.lastBestNode); - - if (m_query.lastBestNode->id != m_query.endRef) - m_query.status |= DT_PARTIAL_RESULT; - dtNode* prev = 0; dtNode* node = m_query.lastBestNode; do @@ -1447,24 +1006,17 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, do { path[n++] = node->id; - if (n >= maxPath) - { - m_query.status |= DT_BUFFER_TOO_SMALL; - break; - } node = m_nodePool->getNodeAtIdx(node->pidx); } - while (node); + while (node && n < maxPath); } - const dtStatus details = m_query.status & DT_STATUS_DETAIL_MASK; - // Reset query. memset(&m_query, 0, sizeof(dtQueryData)); *pathCount = n; - return DT_SUCCESS | details; + return DT_SUCCESS; } dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize, @@ -1477,7 +1029,7 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing return DT_FAILURE; } - if (dtStatusFailed(m_query.status)) + if (m_query.status != DT_SUCCESS && m_query.status != DT_IN_PROGRESS) { // Reset query. memset(&m_query, 0, sizeof(dtQueryData)); @@ -1505,9 +1057,7 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing if (!node) { - m_query.status |= DT_PARTIAL_RESULT; - dtAssert(m_query.lastBestNode); - node = m_query.lastBestNode; + return DT_FAILURE; } // Reverse the path. @@ -1525,156 +1075,58 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing do { path[n++] = node->id; - if (n >= maxPath) - { - m_query.status |= DT_BUFFER_TOO_SMALL; - break; - } node = m_nodePool->getNodeAtIdx(node->pidx); } - while (node); + while (node && n < maxPath); } - const dtStatus details = m_query.status & DT_STATUS_DETAIL_MASK; - // Reset query. memset(&m_query, 0, sizeof(dtQueryData)); *pathCount = n; - return DT_SUCCESS | details; + return DT_SUCCESS; } -dtStatus dtNavMeshQuery::appendVertex(const float* pos, const unsigned char flags, const dtPolyRef ref, - float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs, - int* straightPathCount, const int maxStraightPath) const -{ - if ((*straightPathCount) > 0 && dtVequal(&straightPath[((*straightPathCount)-1)*3], pos)) - { - // The vertices are equal, update flags and poly. - if (straightPathFlags) - straightPathFlags[(*straightPathCount)-1] = flags; - if (straightPathRefs) - straightPathRefs[(*straightPathCount)-1] = ref; - } - else - { - // Append new vertex. - dtVcopy(&straightPath[(*straightPathCount)*3], pos); - if (straightPathFlags) - straightPathFlags[(*straightPathCount)] = flags; - if (straightPathRefs) - straightPathRefs[(*straightPathCount)] = ref; - (*straightPathCount)++; - // If reached end of path or there is no space to append more vertices, return. - if (flags == DT_STRAIGHTPATH_END || (*straightPathCount) >= maxStraightPath) - { - return DT_SUCCESS | (((*straightPathCount) >= maxStraightPath) ? DT_BUFFER_TOO_SMALL : 0); - } - } - return DT_IN_PROGRESS; -} - -dtStatus dtNavMeshQuery::appendPortals(const int startIdx, const int endIdx, const float* endPos, const dtPolyRef* path, - float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs, - int* straightPathCount, const int maxStraightPath, const int options) const -{ - const float* startPos = &straightPath[(*straightPathCount-1)*3]; - // Append or update last vertex - dtStatus stat = 0; - for (int i = startIdx; i < endIdx; i++) - { - // Calculate portal - const dtPolyRef from = path[i]; - const dtMeshTile* fromTile = 0; - const dtPoly* fromPoly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(from, &fromTile, &fromPoly))) - return DT_FAILURE | DT_INVALID_PARAM; - - const dtPolyRef to = path[i+1]; - const dtMeshTile* toTile = 0; - const dtPoly* toPoly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(to, &toTile, &toPoly))) - return DT_FAILURE | DT_INVALID_PARAM; - - float left[3], right[3]; - if (dtStatusFailed(getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, left, right))) - break; - - if (options & DT_STRAIGHTPATH_AREA_CROSSINGS) - { - // Skip intersection if only area crossings are requested. - if (fromPoly->getArea() == toPoly->getArea()) - continue; - } - - // Append intersection - float s,t; - if (dtIntersectSegSeg2D(startPos, endPos, left, right, s, t)) - { - float pt[3]; - dtVlerp(pt, left,right, t); - - stat = appendVertex(pt, 0, path[i+1], - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath); - if (stat != DT_IN_PROGRESS) - return stat; - } - } - return DT_IN_PROGRESS; -} - -/// @par -/// -/// This method peforms what is often called 'string pulling'. -/// -/// The start position is clamped to the first polygon in the path, and the -/// end position is clamped to the last. So the start and end positions should -/// normally be within or very near the first and last polygons respectively. -/// -/// The returned polygon references represent the reference id of the polygon -/// that is entered at the associated path position. The reference id associated -/// with the end point will always be zero. This allows, for example, matching -/// off-mesh link points to their representative polygons. -/// -/// If the provided result buffers are too small for the entire result set, -/// they will be filled as far as possible from the start toward the end -/// position. -/// dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* endPos, const dtPolyRef* path, const int pathSize, float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs, - int* straightPathCount, const int maxStraightPath, const int options) const + int* straightPathCount, const int maxStraightPath) const { dtAssert(m_nav); *straightPathCount = 0; if (!maxStraightPath) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; if (!path[0]) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; - dtStatus stat = 0; + int n = 0; // TODO: Should this be callers responsibility? float closestStartPos[3]; - if (dtStatusFailed(closestPointOnPolyBoundary(path[0], startPos, closestStartPos))) - return DT_FAILURE | DT_INVALID_PARAM; - - float closestEndPos[3]; - if (dtStatusFailed(closestPointOnPolyBoundary(path[pathSize-1], endPos, closestEndPos))) - return DT_FAILURE | DT_INVALID_PARAM; + if (closestPointOnPolyBoundary(path[0], startPos, closestStartPos) != DT_SUCCESS) + return DT_FAILURE; // Add start point. - stat = appendVertex(closestStartPos, DT_STRAIGHTPATH_START, path[0], - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath); - if (stat != DT_IN_PROGRESS) - return stat; + dtVcopy(&straightPath[n*3], closestStartPos); + if (straightPathFlags) + straightPathFlags[n] = DT_STRAIGHTPATH_START; + if (straightPathRefs) + straightPathRefs[n] = path[0]; + n++; + if (n >= maxStraightPath) + { + *straightPathCount = n; + return DT_SUCCESS; + } + + float closestEndPos[3]; + if (closestPointOnPolyBoundary(path[pathSize-1], endPos, closestEndPos) != DT_SUCCESS) + return DT_FAILURE; if (pathSize > 1) { @@ -1700,30 +1152,19 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en if (i+1 < pathSize) { // Next portal. - if (dtStatusFailed(getPortalPoints(path[i], path[i+1], left, right, fromType, toType))) + if (getPortalPoints(path[i], path[i+1], left, right, fromType, toType) != DT_SUCCESS) { - // Failed to get portal points, in practice this means that path[i+1] is invalid polygon. - // Clamp the end point to path[i], and return the path so far. + if (closestPointOnPolyBoundary(path[i], endPos, closestEndPos) != DT_SUCCESS) + return DT_FAILURE; - if (dtStatusFailed(closestPointOnPolyBoundary(path[i], endPos, closestEndPos))) - { - // This should only happen when the first polygon is invalid. - return DT_FAILURE | DT_INVALID_PARAM; - } - - // Apeend portals along the current straight path segment. - if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS)) - { - stat = appendPortals(apexIndex, i, closestEndPos, path, - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath, options); - } - - stat = appendVertex(closestEndPos, 0, path[i], - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath); + dtVcopy(&straightPath[n*3], closestEndPos); + if (straightPathFlags) + straightPathFlags[n] = 0; + if (straightPathRefs) + straightPathRefs[n] = path[i]; + n++; - return DT_SUCCESS | DT_PARTIAL_RESULT | ((*straightPathCount >= maxStraightPath) ? DT_BUFFER_TOO_SMALL : 0); + return DT_SUCCESS; } // If starting really close the portal, advance. @@ -1755,16 +1196,6 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en } else { - // Append portals along the current straight path segment. - if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS)) - { - stat = appendPortals(apexIndex, leftIndex, portalLeft, path, - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath, options); - if (stat != DT_IN_PROGRESS) - return stat; - } - dtVcopy(portalApex, portalLeft); apexIndex = leftIndex; @@ -1775,12 +1206,30 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en flags = DT_STRAIGHTPATH_OFFMESH_CONNECTION; dtPolyRef ref = leftPolyRef; - // Append or update vertex - stat = appendVertex(portalApex, flags, ref, - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath); - if (stat != DT_IN_PROGRESS) - return stat; + if (!dtVequal(&straightPath[(n-1)*3], portalApex)) + { + // Append new vertex. + dtVcopy(&straightPath[n*3], portalApex); + if (straightPathFlags) + straightPathFlags[n] = flags; + if (straightPathRefs) + straightPathRefs[n] = ref; + n++; + // If reached end of path or there is no space to append more vertices, return. + if (flags == DT_STRAIGHTPATH_END || n >= maxStraightPath) + { + *straightPathCount = n; + return DT_SUCCESS; + } + } + else + { + // The vertices are equal, update flags and poly. + if (straightPathFlags) + straightPathFlags[n-1] = flags; + if (straightPathRefs) + straightPathRefs[n-1] = ref; + } dtVcopy(portalLeft, portalApex); dtVcopy(portalRight, portalApex); @@ -1806,16 +1255,6 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en } else { - // Append portals along the current straight path segment. - if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS)) - { - stat = appendPortals(apexIndex, rightIndex, portalRight, path, - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath, options); - if (stat != DT_IN_PROGRESS) - return stat; - } - dtVcopy(portalApex, portalRight); apexIndex = rightIndex; @@ -1825,13 +1264,31 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en else if (rightPolyType == DT_POLYTYPE_OFFMESH_CONNECTION) flags = DT_STRAIGHTPATH_OFFMESH_CONNECTION; dtPolyRef ref = rightPolyRef; - - // Append or update vertex - stat = appendVertex(portalApex, flags, ref, - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath); - if (stat != DT_IN_PROGRESS) - return stat; + + if (!dtVequal(&straightPath[(n-1)*3], portalApex)) + { + // Append new vertex. + dtVcopy(&straightPath[n*3], portalApex); + if (straightPathFlags) + straightPathFlags[n] = flags; + if (straightPathRefs) + straightPathRefs[n] = ref; + n++; + // If reached end of path or there is no space to append more vertices, return. + if (flags == DT_STRAIGHTPATH_END || n >= maxStraightPath) + { + *straightPathCount = n; + return DT_SUCCESS; + } + } + else + { + // The vertices are equal, update flags and poly. + if (straightPathFlags) + straightPathFlags[n-1] = flags; + if (straightPathRefs) + straightPathRefs[n-1] = ref; + } dtVcopy(portalLeft, portalApex); dtVcopy(portalRight, portalApex); @@ -1845,45 +1302,27 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en } } } - - // Append portals along the current straight path segment. - if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS)) - { - stat = appendPortals(apexIndex, pathSize-1, closestEndPos, path, - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath, options); - if (stat != DT_IN_PROGRESS) - return stat; - } } - - stat = appendVertex(closestEndPos, DT_STRAIGHTPATH_END, 0, - straightPath, straightPathFlags, straightPathRefs, - straightPathCount, maxStraightPath); - return DT_SUCCESS | ((*straightPathCount >= maxStraightPath) ? DT_BUFFER_TOO_SMALL : 0); + // If the point already exists, remove it and add reappend the actual end location. + if (n > 0 && dtVequal(&straightPath[(n-1)*3], closestEndPos)) + n--; + + // Add end point. + if (n < maxStraightPath) + { + dtVcopy(&straightPath[n*3], closestEndPos); + if (straightPathFlags) + straightPathFlags[n] = DT_STRAIGHTPATH_END; + if (straightPathRefs) + straightPathRefs[n] = 0; + n++; + } + + *straightPathCount = n; + return DT_SUCCESS; } -/// @par -/// -/// This method is optimized for small delta movement and a small number of -/// polygons. If used for too great a distance, the result set will form an -/// incomplete path. -/// -/// @p resultPos will equal the @p endPos if the end is reached. -/// Otherwise the closest reachable position will be returned. -/// -/// @p resultPos is not projected onto the surface of the navigation -/// mesh. Use #getPolyHeight if this is needed. -/// -/// This method treats the end position in the same manner as -/// the #raycast method. (As a 2D point.) See that method's documentation -/// for details. -/// -/// If the @p visited array is too small to hold the entire result set, it will -/// be filled as far as possible from the start position toward the end -/// position. -/// dtStatus dtNavMeshQuery::moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos, const dtQueryFilter* filter, float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const @@ -1894,12 +1333,8 @@ dtStatus dtNavMeshQuery::moveAlongSurface(dtPolyRef startRef, const float* start *visitedCount = 0; // Validate input - if (!startRef) - return DT_FAILURE | DT_INVALID_PARAM; - if (!m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; - - dtStatus status = DT_SUCCESS; + if (!startRef) return DT_FAILURE; + if (!m_nav->isValidPolyRef(startRef)) return DT_FAILURE; static const int MAX_STACK = 48; dtNode* stack[MAX_STACK]; @@ -2064,21 +1499,16 @@ dtStatus dtNavMeshQuery::moveAlongSurface(dtPolyRef startRef, const float* start do { visited[n++] = node->id; - if (n >= maxVisitedSize) - { - status |= DT_BUFFER_TOO_SMALL; - break; - } node = m_tinyNodePool->getNodeAtIdx(node->pidx); } - while (node); + while (node && n < maxVisitedSize); } dtVcopy(resultPos, bestPos); *visitedCount = n; - return status; + return DT_SUCCESS; } @@ -2089,14 +1519,14 @@ dtStatus dtNavMeshQuery::getPortalPoints(dtPolyRef from, dtPolyRef to, float* le const dtMeshTile* fromTile = 0; const dtPoly* fromPoly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(from, &fromTile, &fromPoly))) - return DT_FAILURE | DT_INVALID_PARAM; + if (m_nav->getTileAndPolyByRef(from, &fromTile, &fromPoly) != DT_SUCCESS) + return DT_FAILURE; fromType = fromPoly->getType(); const dtMeshTile* toTile = 0; const dtPoly* toPoly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(to, &toTile, &toPoly))) - return DT_FAILURE | DT_INVALID_PARAM; + if (m_nav->getTileAndPolyByRef(to, &toTile, &toPoly) != DT_SUCCESS) + return DT_FAILURE; toType = toPoly->getType(); return getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, left, right); @@ -2118,7 +1548,7 @@ dtStatus dtNavMeshQuery::getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, } } if (!link) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; // Handle off-mesh connections. if (fromPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) @@ -2134,7 +1564,7 @@ dtStatus dtNavMeshQuery::getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, return DT_SUCCESS; } } - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; } if (toPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) @@ -2149,7 +1579,7 @@ dtStatus dtNavMeshQuery::getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, return DT_SUCCESS; } } - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; } // Find portal vertices. @@ -2181,8 +1611,7 @@ dtStatus dtNavMeshQuery::getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mi { float left[3], right[3]; unsigned char fromType, toType; - if (dtStatusFailed(getPortalPoints(from, to, left,right, fromType, toType))) - return DT_FAILURE | DT_INVALID_PARAM; + if (!getPortalPoints(from, to, left,right, fromType, toType)) return DT_FAILURE; mid[0] = (left[0]+right[0])*0.5f; mid[1] = (left[1]+right[1])*0.5f; mid[2] = (left[2]+right[2])*0.5f; @@ -2194,52 +1623,14 @@ dtStatus dtNavMeshQuery::getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, float* mid) const { float left[3], right[3]; - if (dtStatusFailed(getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, left, right))) - return DT_FAILURE | DT_INVALID_PARAM; + if (getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, left, right) != DT_SUCCESS) + return DT_FAILURE; mid[0] = (left[0]+right[0])*0.5f; mid[1] = (left[1]+right[1])*0.5f; mid[2] = (left[2]+right[2])*0.5f; return DT_SUCCESS; } -/// @par -/// -/// This method is meant to be used for quick, short distance checks. -/// -/// If the path array is too small to hold the result, it will be filled as -/// far as possible from the start postion toward the end position. -/// -/// Using the Hit Parameter (t) -/// -/// If the hit parameter is a very high value (FLT_MAX), then the ray has hit -/// the end position. In this case the path represents a valid corridor to the -/// end position and the value of @p hitNormal is undefined. -/// -/// If the hit parameter is zero, then the start position is on the wall that -/// was hit and the value of @p hitNormal is undefined. -/// -/// If 0 < t < 1.0 then the following applies: -/// -/// @code -/// distanceToHitBorder = distanceToEndPosition * t -/// hitPoint = startPos + (endPos - startPos) * t -/// @endcode -/// -/// Use Case Restriction -/// -/// The raycast ignores the y-value of the end position. (2D check.) This -/// places significant limits on how it can be used. For example: -/// -/// Consider a scene where there is a main floor with a second floor balcony -/// that hangs over the main floor. So the first floor mesh extends below the -/// balcony mesh. The start position is somewhere on the first floor. The end -/// position is on the balcony. -/// -/// The raycast will search toward the end position along the first floor mesh. -/// If it reaches the end position's xz-coordinates it will indicate FLT_MAX -/// (no wall hit), meaning it reached the end position. This is one example of why -/// this method is meant for short distance checks. -/// dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, const float* endPos, const dtQueryFilter* filter, float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const @@ -2252,7 +1643,7 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons // Validate input if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; + return DT_FAILURE; dtPolyRef curRef = startRef; float verts[DT_VERTS_PER_POLYGON*3]; @@ -2262,8 +1653,6 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons hitNormal[1] = 0; hitNormal[2] = 0; - dtStatus status = DT_SUCCESS; - while (curRef) { // Cast ray against current polygon. @@ -2288,7 +1677,7 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons // Could not hit the polygon, keep the old t and report hit. if (pathCount) *pathCount = n; - return status; + return DT_SUCCESS; } // Keep track of furthest t so far. if (tmax > *t) @@ -2297,8 +1686,6 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons // Store visited polygons. if (n < maxPath) path[n++] = curRef; - else - status |= DT_BUFFER_TOO_SMALL; // Ray end is completely inside the polygon. if (segMax == -1) @@ -2306,7 +1693,7 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons *t = FLT_MAX; if (pathCount) *pathCount = n; - return status; + return DT_SUCCESS; } // Follow neighbours. @@ -2408,7 +1795,7 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons if (pathCount) *pathCount = n; - return status; + return DT_SUCCESS; } // No hit, advance to neighbour polygon. @@ -2418,38 +1805,9 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons if (pathCount) *pathCount = n; - return status; + return DT_SUCCESS; } -/// @par -/// -/// At least one result array must be provided. -/// -/// The order of the result set is from least to highest cost to reach the polygon. -/// -/// A common use case for this method is to perform Dijkstra searches. -/// Candidate polygons are found by searching the graph beginning at the start polygon. -/// -/// If a polygon is not found via the graph search, even if it intersects the -/// search circle, it will not be included in the result set. For example: -/// -/// polyA is the start polygon. -/// polyB shares an edge with polyA. (Is adjacent.) -/// polyC shares an edge with polyB, but not with polyA -/// Even if the search circle overlaps polyC, it will not be included in the -/// result set unless polyB is also in the set. -/// -/// The value of the center point is used as the start position for cost -/// calculations. It is not projected onto the surface of the mesh, so its -/// y-value will effect the costs. -/// -/// Intersection tests occur in 2D. All polygons and the search circle are -/// projected onto the xz-plane. So the y-value of the center point does not -/// effect intersection tests. -/// -/// If the result arrays are to small to hold the entire result set, they will be -/// filled to capacity. -/// dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius, const dtQueryFilter* filter, dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost, @@ -2462,8 +1820,8 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* *resultCount = 0; // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; + if (!startRef) return DT_FAILURE; + if (!m_nav->isValidPolyRef(startRef)) return DT_FAILURE; m_nodePool->clear(); m_openList->clear(); @@ -2477,8 +1835,6 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* startNode->flags = DT_NODE_OPEN; m_openList->push(startNode); - dtStatus status = DT_SUCCESS; - int n = 0; if (n < maxResult) { @@ -2490,10 +1846,6 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* resultCost[n] = 0; ++n; } - else - { - status |= DT_BUFFER_TOO_SMALL; - } const float radiusSqr = dtSqr(radius); @@ -2549,10 +1901,7 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* dtNode* neighbourNode = m_nodePool->getNode(neighbourRef); if (!neighbourNode) - { - status |= DT_OUT_OF_NODES; continue; - } if (neighbourNode->flags & DT_NODE_CLOSED) continue; @@ -2568,7 +1917,7 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* continue; neighbourNode->id = neighbourRef; - neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED); + neighbourNode->flags &= ~DT_NODE_CLOSED; neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode); neighbourNode->total = total; @@ -2588,10 +1937,6 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* resultCost[n] = neighbourNode->total; ++n; } - else - { - status |= DT_BUFFER_TOO_SMALL; - } neighbourNode->flags = DT_NODE_OPEN; m_openList->push(neighbourNode); } @@ -2600,31 +1945,9 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* *resultCount = n; - return status; + return DT_SUCCESS; } -/// @par -/// -/// The order of the result set is from least to highest cost. -/// -/// At least one result array must be provided. -/// -/// A common use case for this method is to perform Dijkstra searches. -/// Candidate polygons are found by searching the graph beginning at the start -/// polygon. -/// -/// The same intersection test restrictions that apply to findPolysAroundCircle() -/// method apply to this method. -/// -/// The 3D centroid of the search polygon is used as the start position for cost -/// calculations. -/// -/// Intersection tests occur in 2D. All polygons are projected onto the -/// xz-plane. So the y-values of the vertices do not effect intersection tests. -/// -/// If the result arrays are is too small to hold the entire result set, they will -/// be filled to capacity. -/// dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts, const dtQueryFilter* filter, dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost, @@ -2637,8 +1960,8 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v *resultCount = 0; // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; + if (!startRef) return DT_FAILURE; + if (!m_nav->isValidPolyRef(startRef)) return DT_FAILURE; m_nodePool->clear(); m_openList->clear(); @@ -2657,8 +1980,6 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v startNode->flags = DT_NODE_OPEN; m_openList->push(startNode); - dtStatus status = DT_SUCCESS; - int n = 0; if (n < maxResult) { @@ -2670,10 +1991,6 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v resultCost[n] = 0; ++n; } - else - { - status |= DT_BUFFER_TOO_SMALL; - } while (!m_openList->empty()) { @@ -2729,10 +2046,7 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v dtNode* neighbourNode = m_nodePool->getNode(neighbourRef); if (!neighbourNode) - { - status |= DT_OUT_OF_NODES; continue; - } if (neighbourNode->flags & DT_NODE_CLOSED) continue; @@ -2748,7 +2062,7 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v continue; neighbourNode->id = neighbourRef; - neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED); + neighbourNode->flags &= ~DT_NODE_CLOSED; neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode); neighbourNode->total = total; @@ -2768,10 +2082,6 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v resultCost[n] = neighbourNode->total; ++n; } - else - { - status |= DT_BUFFER_TOO_SMALL; - } neighbourNode->flags = DT_NODE_OPEN; m_openList->push(neighbourNode); } @@ -2780,31 +2090,9 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v *resultCount = n; - return status; + return DT_SUCCESS; } -/// @par -/// -/// This method is optimized for a small search radius and small number of result -/// polygons. -/// -/// Candidate polygons are found by searching the navigation graph beginning at -/// the start polygon. -/// -/// The same intersection test restrictions that apply to the findPolysAroundCircle -/// mehtod applies to this method. -/// -/// The value of the center point is used as the start point for cost calculations. -/// It is not projected onto the surface of the mesh, so its y-value will effect -/// the costs. -/// -/// Intersection tests occur in 2D. All polygons and the search circle are -/// projected onto the xz-plane. So the y-value of the center point does not -/// effect intersection tests. -/// -/// If the result arrays are is too small to hold the entire result set, they will -/// be filled to capacity. -/// dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius, const dtQueryFilter* filter, dtPolyRef* resultRef, dtPolyRef* resultParent, @@ -2816,8 +2104,8 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* *resultCount = 0; // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; + if (!startRef) return DT_FAILURE; + if (!m_nav->isValidPolyRef(startRef)) return DT_FAILURE; static const int MAX_STACK = 48; dtNode* stack[MAX_STACK]; @@ -2836,8 +2124,6 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* float pa[DT_VERTS_PER_POLYGON*3]; float pb[DT_VERTS_PER_POLYGON*3]; - dtStatus status = DT_SUCCESS; - int n = 0; if (n < maxResult) { @@ -2846,10 +2132,6 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* resultParent[n] = 0; ++n; } - else - { - status |= DT_BUFFER_TOO_SMALL; - } while (nstack) { @@ -2963,10 +2245,6 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* resultParent[n] = curRef; ++n; } - else - { - status |= DT_BUFFER_TOO_SMALL; - } if (nstack < MAX_STACK) { @@ -2977,18 +2255,17 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* *resultCount = n; - return status; + return DT_SUCCESS; } struct dtSegInterval { - dtPolyRef ref; short tmin, tmax; }; static void insertInterval(dtSegInterval* ints, int& nints, const int maxInts, - const short tmin, const short tmax, const dtPolyRef ref) + const short tmin, const short tmax) { if (nints+1 > maxInts) return; // Find insertion point. @@ -3003,26 +2280,13 @@ static void insertInterval(dtSegInterval* ints, int& nints, const int maxInts, if (nints-idx) memmove(ints+idx+1, ints+idx, sizeof(dtSegInterval)*(nints-idx)); // Store - ints[idx].ref = ref; ints[idx].tmin = tmin; ints[idx].tmax = tmax; nints++; } -/// @par -/// -/// If the @p segmentRefs parameter is provided, then all polygon segments will be returned. -/// Otherwise only the wall segments are returned. -/// -/// A segment that is normally a portal will be included in the result set as a -/// wall if the @p filter results in the neighbor polygon becoomming impassable. -/// -/// The @p segmentVerts and @p segmentRefs buffers should normally be sized for the -/// maximum segments per polygon of the source navigation mesh. -/// dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter, - float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount, - const int maxSegments) const + float* segments, int* segmentCount, const int maxSegments) const { dtAssert(m_nav); @@ -3030,18 +2294,14 @@ dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* const dtMeshTile* tile = 0; const dtPoly* poly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) - return DT_FAILURE | DT_INVALID_PARAM; + if (m_nav->getTileAndPolyByRef(ref, &tile, &poly) != DT_SUCCESS) + return DT_FAILURE; int n = 0; static const int MAX_INTERVAL = 16; dtSegInterval ints[MAX_INTERVAL]; int nints; - const bool storePortals = segmentRefs != 0; - - dtStatus status = DT_SUCCESS; - for (int i = 0, j = (int)poly->vertCount-1; i < (int)poly->vertCount; j = i++) { // Skip non-solid edges. @@ -3061,95 +2321,54 @@ dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* m_nav->getTileAndPolyByRefUnsafe(link->ref, &neiTile, &neiPoly); if (filter->passFilter(link->ref, neiTile, neiPoly)) { - insertInterval(ints, nints, MAX_INTERVAL, link->bmin, link->bmax, link->ref); + insertInterval(ints, nints, MAX_INTERVAL, link->bmin, link->bmax); } } } } } - else + else if (poly->neis[j]) { // Internal edge - dtPolyRef neiRef = 0; - if (poly->neis[j]) - { - const unsigned int idx = (unsigned int)(poly->neis[j]-1); - neiRef = m_nav->getPolyRefBase(tile) | idx; - if (!filter->passFilter(neiRef, tile, &tile->polys[idx])) - neiRef = 0; - } - - // If the edge leads to another polygon and portals are not stored, skip. - if (neiRef != 0 && !storePortals) + const unsigned int idx = (unsigned int)(poly->neis[j]-1); + const dtPolyRef ref = m_nav->getPolyRefBase(tile) | idx; + if (filter->passFilter(ref, tile, &tile->polys[idx])) continue; - - if (n < maxSegments) - { - const float* vj = &tile->verts[poly->verts[j]*3]; - const float* vi = &tile->verts[poly->verts[i]*3]; - float* seg = &segmentVerts[n*6]; - dtVcopy(seg+0, vj); - dtVcopy(seg+3, vi); - if (segmentRefs) - segmentRefs[n] = neiRef; - n++; - } - else - { - status |= DT_BUFFER_TOO_SMALL; - } - - continue; } // Add sentinels - insertInterval(ints, nints, MAX_INTERVAL, -1, 0, 0); - insertInterval(ints, nints, MAX_INTERVAL, 255, 256, 0); + insertInterval(ints, nints, MAX_INTERVAL, -1, 0); + insertInterval(ints, nints, MAX_INTERVAL, 255, 256); - // Store segments. + // Store segment. const float* vj = &tile->verts[poly->verts[j]*3]; const float* vi = &tile->verts[poly->verts[i]*3]; for (int k = 1; k < nints; ++k) { - // Portal segment. - if (storePortals && ints[k].ref) + // Find the space inbetween the opening areas. + const int imin = ints[k-1].tmax; + const int imax = ints[k].tmin; + if (imin == imax) continue; + if (imin == 0 && imax == 255) { - const float tmin = ints[k].tmin/255.0f; - const float tmax = ints[k].tmax/255.0f; if (n < maxSegments) { - float* seg = &segmentVerts[n*6]; - dtVlerp(seg+0, vj,vi, tmin); - dtVlerp(seg+3, vj,vi, tmax); - if (segmentRefs) - segmentRefs[n] = ints[k].ref; + float* seg = &segments[n*6]; n++; - } - else - { - status |= DT_BUFFER_TOO_SMALL; + dtVcopy(seg+0, vj); + dtVcopy(seg+3, vi); } } - - // Wall segment. - const int imin = ints[k-1].tmax; - const int imax = ints[k].tmin; - if (imin != imax) + else { const float tmin = imin/255.0f; const float tmax = imax/255.0f; if (n < maxSegments) { - float* seg = &segmentVerts[n*6]; + float* seg = &segments[n*6]; + n++; dtVlerp(seg+0, vj,vi, tmin); dtVlerp(seg+3, vj,vi, tmax); - if (segmentRefs) - segmentRefs[n] = 0; - n++; - } - else - { - status |= DT_BUFFER_TOO_SMALL; } } } @@ -3157,19 +2376,9 @@ dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* *segmentCount = n; - return status; + return DT_SUCCESS; } -/// @par -/// -/// @p hitPos is not adjusted using the height detail data. -/// -/// @p hitDist will equal the search radius if there is no wall within the -/// radius. In this case the values of @p hitPos and @p hitNormal are -/// undefined. -/// -/// The normal will become unpredicable if @p hitDist is a very small number. -/// dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius, const dtQueryFilter* filter, float* hitDist, float* hitPos, float* hitNormal) const @@ -3179,8 +2388,8 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen dtAssert(m_openList); // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; + if (!startRef) return DT_FAILURE; + if (!m_nav->isValidPolyRef(startRef)) return DT_FAILURE; m_nodePool->clear(); m_openList->clear(); @@ -3196,8 +2405,6 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen float radiusSqr = dtSqr(maxRadius); - dtStatus status = DT_SUCCESS; - while (!m_openList->empty()) { dtNode* bestNode = m_openList->pop(); @@ -3305,10 +2512,7 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen dtNode* neighbourNode = m_nodePool->getNode(neighbourRef); if (!neighbourNode) - { - status |= DT_OUT_OF_NODES; continue; - } if (neighbourNode->flags & DT_NODE_CLOSED) continue; @@ -3327,7 +2531,7 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen continue; neighbourNode->id = neighbourRef; - neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED); + neighbourNode->flags &= ~DT_NODE_CLOSED; neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode); neighbourNode->total = total; @@ -3347,30 +2551,11 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen dtVsub(hitNormal, centerPos, hitPos); dtVnormalize(hitNormal); - *hitDist = dtSqrt(radiusSqr); + *hitDist = sqrtf(radiusSqr); - return status; -} - -bool dtNavMeshQuery::isValidPolyRef(dtPolyRef ref, const dtQueryFilter* filter) const -{ - const dtMeshTile* tile = 0; - const dtPoly* poly = 0; - dtStatus status = m_nav->getTileAndPolyByRef(ref, &tile, &poly); - // If cannot get polygon, assume it does not exists and boundary is invalid. - if (dtStatusFailed(status)) - return false; - // If cannot pass filter, assume flags has changed and boundary is invalid. - if (!filter->passFilter(ref, tile, poly)) - return false; - return true; + return DT_SUCCESS; } -/// @par -/// -/// The closed list is the list of polygons that were fully evaluated during -/// the last navigation graph search. (A* or Dijkstra) -/// bool dtNavMeshQuery::isInClosedList(dtPolyRef ref) const { if (!m_nodePool) return false; diff --git a/dep/recastnavigation/Detour/DetourNavMeshQuery.h b/dep/recastnavigation/Detour/DetourNavMeshQuery.h index d431bf1..f5046d8 100644 --- a/dep/recastnavigation/Detour/DetourNavMeshQuery.h +++ b/dep/recastnavigation/Detour/DetourNavMeshQuery.h @@ -20,31 +20,39 @@ #define DETOURNAVMESHQUERY_H #include "DetourNavMesh.h" -#include "DetourStatus.h" // Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter. // On certain platforms indirect or virtual function call is expensive. The default -// setting is to use non-virtual functions, the actual implementations of the functions +// setting is to use non-virtual functions, the actualy implementations of the functions // are declared as inline for maximum speed. //#define DT_VIRTUAL_QUERYFILTER 1 -/// Defines polygon filtering and traversal costs for navigation mesh query operations. -/// @ingroup detour +// Class for polygon filtering and cost calculation during query operations. +// - It is possible to derive a custom query filter from dtQueryFilter by overriding +// the virtual functions passFilter() and getCost(). +// - Both functions should be as fast as possible. Use cached local copy of data +// instead of accessing your own objects where possible. +// - You do not need to adhere to the flags and cost logic provided by the default +// implementation. +// - In order for the A* to work properly, the cost should be proportional to +// the travel distance. Using cost modifier less than 1.0 is likely to lead +// to problems during pathfinding. class dtQueryFilter { - float m_areaCost[DT_MAX_AREAS]; ///< Cost per area type. (Used by default implementation.) - unsigned short m_includeFlags; ///< Flags for polygons that can be visited. (Used by default implementation.) - unsigned short m_excludeFlags; ///< Flags for polygons that should not be visted. (Used by default implementation.) + float m_areaCost[DT_MAX_AREAS]; // Array storing cost per area type, used by default implementation. + unsigned short m_includeFlags; // Include poly flags, used by default implementation. + unsigned short m_excludeFlags; // Exclude poly flags, used by default implementation. public: dtQueryFilter(); - /// Returns true if the polygon can be visited. (I.e. Is traversable.) - /// @param[in] ref The reference id of the polygon test. - /// @param[in] tile The tile containing the polygon. - /// @param[in] poly The polygon to test. + // Returns true if the polygon is can visited. + // Params: + // ref - (in) reference to the polygon test. + // tile - (in) pointer to the tile of the polygon test. + // poly - (in) pointer to the polygon test. #ifdef DT_VIRTUAL_QUERYFILTER virtual bool passFilter(const dtPolyRef ref, const dtMeshTile* tile, @@ -55,19 +63,16 @@ public: const dtPoly* poly) const; #endif - /// Returns cost to move from the beginning to the end of a line segment - /// that is fully contained within a polygon. - /// @param[in] pa The start position on the edge of the previous and current polygon. [(x, y, z)] - /// @param[in] pb The end position on the edge of the current and next polygon. [(x, y, z)] - /// @param[in] prevRef The reference id of the previous polygon. [opt] - /// @param[in] prevTile The tile containing the previous polygon. [opt] - /// @param[in] prevPoly The previous polygon. [opt] - /// @param[in] curRef The reference id of the current polygon. - /// @param[in] curTile The tile containing the current polygon. - /// @param[in] curPoly The current polygon. - /// @param[in] nextRef The refernece id of the next polygon. [opt] - /// @param[in] nextTile The tile containing the next polygon. [opt] - /// @param[in] nextPoly The next polygon. [opt] + // Returns cost to travel from 'pa' to 'pb'.' + // The segment is fully contained inside 'cur'. + // 'pa' lies on the edge between 'prev' and 'cur', + // 'pb' lies on the edge between 'cur' and 'next'. + // Params: + // pa - (in) segment start position. + // pb - (in) segment end position. + // prevRef, prevTile, prevPoly - (in) data describing the previous polygon, can be null. + // curRef, curTile, curPoly - (in) data describing the current polygon. + // nextRef, nextTile, nextPoly - (in) data describing the next polygon, can be null. #ifdef DT_VIRTUAL_QUERYFILTER virtual float getCost(const float* pa, const float* pb, const dtPolyRef prevRef, const dtMeshTile* prevTile, const dtPoly* prevPoly, @@ -79,385 +84,305 @@ public: const dtPolyRef curRef, const dtMeshTile* curTile, const dtPoly* curPoly, const dtPolyRef nextRef, const dtMeshTile* nextTile, const dtPoly* nextPoly) const; #endif - - /// @name Getters and setters for the default implementation data. - ///@{ - - /// Returns the traversal cost of the area. - /// @param[in] i The id of the area. - /// @returns The traversal cost of the area. + + // Getters and setters for the default implementation data. inline float getAreaCost(const int i) const { return m_areaCost[i]; } - - /// Sets the traversal cost of the area. - /// @param[in] i The id of the area. - /// @param[in] cost The new cost of traversing the area. inline void setAreaCost(const int i, const float cost) { m_areaCost[i] = cost; } - /// Returns the include flags for the filter. - /// Any polygons that include one or more of these flags will be - /// included in the operation. inline unsigned short getIncludeFlags() const { return m_includeFlags; } - - /// Sets the include flags for the filter. - /// @param[in] flags The new flags. inline void setIncludeFlags(const unsigned short flags) { m_includeFlags = flags; } - /// Returns the exclude flags for the filter. - /// Any polygons that include one ore more of these flags will be - /// excluded from the operation. inline unsigned short getExcludeFlags() const { return m_excludeFlags; } - - /// Sets the exclude flags for the filter. - /// @param[in] flags The new flags. inline void setExcludeFlags(const unsigned short flags) { m_excludeFlags = flags; } - - ///@} - }; -/// Provides the ability to perform pathfinding related queries against -/// a navigation mesh. -/// @ingroup detour class dtNavMeshQuery { public: dtNavMeshQuery(); ~dtNavMeshQuery(); - /// Initializes the query object. - /// @param[in] nav Pointer to the dtNavMesh object to use for all queries. - /// @param[in] maxNodes Maximum number of search nodes. [Limits: 0 < value <= 65536] - /// @returns The status flags for the query. + // Initializes the nav mesh query. + // Params: + // nav - (in) pointer to navigation mesh data. + // maxNodes - (in) Maximum number of search nodes to use (max 65536). + // Returns: True if succeed, else false. dtStatus init(const dtNavMesh* nav, const int maxNodes); - /// @name Standard Pathfinding Functions - // /@{ - - /// Finds a path from the start polygon to the end polygon. - /// @param[in] startRef The refrence id of the start polygon. - /// @param[in] endRef The reference id of the end polygon. - /// @param[in] startPos A position within the start polygon. [(x, y, z)] - /// @param[in] endPos A position within the end polygon. [(x, y, z)] - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] path An ordered list of polygon references representing the path. (Start to end.) - /// [(polyRef) * @p pathCount] - /// @param[out] pathCount The number of polygons returned in the @p path array. - /// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 1] + // Finds the nearest navigation polygon around the center location. + // Params: + // center[3] - (in) The center of the search box. + // extents[3] - (in) The extents of the search box. + // filter - (in) path polygon filter. + // nearestRef - (out) Reference to the nearest polygon. + // nearestPt[3] - (out, opt) The nearest point on found polygon, null if not needed. + // Returns: Reference identifier for the polygon, or 0 if no polygons found. + dtStatus findNearestPoly(const float* center, const float* extents, + const dtQueryFilter* filter, + dtPolyRef* nearestRef, float* nearestPt) const; + + // Returns polygons which overlap the query box. + // Params: + // center[3] - (in) the center of the search box. + // extents[3] - (in) the extents of the search box. + // filter - (in) path polygon filter. + // polys - (out) array holding the search result. + // polyCount - (out) Number of polygons in search result array. + // maxPolys - (in) The max number of polygons the polys array can hold. + dtStatus queryPolygons(const float* center, const float* extents, + const dtQueryFilter* filter, + dtPolyRef* polys, int* polyCount, const int maxPolys) const; + + // Finds path from start polygon to end polygon. + // If target polygon canno be reached through the navigation graph, + // the last node on the array is nearest node to the end polygon. + // Start end end positions are needed to calculate more accurate + // traversal cost at start end end polygons. + // Params: + // startRef - (in) ref to path start polygon. + // endRef - (in) ref to path end polygon. + // startPos[3] - (in) Path start location. + // endPos[3] - (in) Path end location. + // filter - (in) path polygon filter. + // path - (out) array holding the search result. + // pathCount - (out) Number of polygons in search result array. + // maxPath - (in) The max number of polygons the path array can hold. Must be at least 1. dtStatus findPath(dtPolyRef startRef, dtPolyRef endRef, const float* startPos, const float* endPos, const dtQueryFilter* filter, dtPolyRef* path, int* pathCount, const int maxPath) const; - /// Finds the straight path from the start to the end position within the polygon corridor. - /// @param[in] startPos Path start position. [(x, y, z)] - /// @param[in] endPos Path end position. [(x, y, z)] - /// @param[in] path An array of polygon references that represent the path corridor. - /// @param[in] pathSize The number of polygons in the @p path array. - /// @param[out] straightPath Points describing the straight path. [(x, y, z) * @p straightPathCount]. - /// @param[out] straightPathFlags Flags describing each point. (See: #dtStraightPathFlags) [opt] - /// @param[out] straightPathRefs The reference id of the polygon that is being entered at each point. [opt] - /// @param[out] straightPathCount The number of points in the straight path. - /// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0] - /// @param[in] options Query options. (see: #dtStraightPathOptions) - /// @returns The status flags for the query. - dtStatus findStraightPath(const float* startPos, const float* endPos, - const dtPolyRef* path, const int pathSize, - float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs, - int* straightPathCount, const int maxStraightPath, const int options = 0) const; - - ///@} - /// @name Sliced Pathfinding Functions - /// Common use case: - /// -# Call initSlicedFindPath() to initialize the sliced path query. - /// -# Call updateSlicedFindPath() until it returns complete. - /// -# Call finalizeSlicedFindPath() to get the path. - ///@{ - - /// Intializes a sliced path query. - /// @param[in] startRef The refrence id of the start polygon. - /// @param[in] endRef The reference id of the end polygon. - /// @param[in] startPos A position within the start polygon. [(x, y, z)] - /// @param[in] endPos A position within the end polygon. [(x, y, z)] - /// @param[in] filter The polygon filter to apply to the query. - /// @returns The status flags for the query. + // Intializes sliced path find query. + // Note 1: calling any other dtNavMeshQuery method before calling findPathEnd() + // may results in corrupted data! + // Note 2: The pointer to filter is store, and used in subsequent + // calls to updateSlicedFindPath(). + // Params: + // startRef - (in) ref to path start polygon. + // endRef - (in) ref to path end polygon. + // startPos[3] - (in) Path start location. + // endPos[3] - (in) Path end location. + // filter - (in) path polygon filter. dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef, const float* startPos, const float* endPos, const dtQueryFilter* filter); - /// Updates an in-progress sliced path query. - /// @param[in] maxIter The maximum number of iterations to perform. - /// @param[out] doneIters The actual number of iterations completed. [opt] - /// @returns The status flags for the query. - dtStatus updateSlicedFindPath(const int maxIter, int* doneIters); + // Updates sliced path find query. + // Params: + // maxIter - (in) max number of iterations to update. + // Returns: Path query state. + dtStatus updateSlicedFindPath(const int maxIter); - /// Finalizes and returns the results of a sliced path query. - /// @param[out] path An ordered list of polygon references representing the path. (Start to end.) - /// [(polyRef) * @p pathCount] - /// @param[out] pathCount The number of polygons returned in the @p path array. - /// @param[in] maxPath The max number of polygons the path array can hold. [Limit: >= 1] - /// @returns The status flags for the query. + // Finalizes sliced path find query and returns found path. + // path - (out) array holding the search result. + // pathCount - (out) Number of polygons in search result array. + // maxPath - (in) The max number of polygons the path array can hold. dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath); - /// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest - /// polygon on the existing path that was visited during the search. - /// @param[out] existing An array of polygon references for the existing path. - /// @param[out] existingSize The number of polygon in the @p existing array. - /// @param[out] path An ordered list of polygon references representing the path. (Start to end.) - /// [(polyRef) * @p pathCount] - /// @param[out] pathCount The number of polygons returned in the @p path array. - /// @param[in] maxPath The max number of polygons the @p path array can hold. [Limit: >= 1] - /// @returns The status flags for the query. + // Finalizes partial sliced path find query and returns path to the furthest + // polygon on the existing path that was visited during the search. + // existing - (out) Array of polygons in the existing path. + // existingSize - (out) Number of polygons in existing path array. + // path - (out) array holding the search result. + // pathCount - (out) Number of polygons in search result array. + // maxPath - (in) The max number of polygons the path array can hold. dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize, dtPolyRef* path, int* pathCount, const int maxPath); - - ///@} - /// @name Dijkstra Search Functions - /// @{ - - /// Finds the polygons along the navigation graph that touch the specified circle. - /// @param[in] startRef The reference id of the polygon where the search starts. - /// @param[in] centerPos The center of the search circle. [(x, y, z)] - /// @param[in] radius The radius of the search circle. - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] resultRef The reference ids of the polygons touched by the circle. [opt] - /// @param[out] resultParent The reference ids of the parent polygons for each result. - /// Zero if a result polygon has no parent. [opt] - /// @param[out] resultCost The search cost from @p centerPos to the polygon. [opt] - /// @param[out] resultCount The number of polygons found. [opt] - /// @param[in] maxResult The maximum number of polygons the result arrays can hold. - /// @returns The status flags for the query. + + // Finds a straight path from start to end locations within the corridor + // described by the path polygons. + // Start and end locations will be clamped on the corridor. + // The returned polygon references are point to polygon which was entered when + // a path point was added. For the end point, zero will be returned. This allows + // to match for example off-mesh link points to their representative polygons. + // Params: + // startPos[3] - (in) Path start location. + // endPo[3] - (in) Path end location. + // path - (in) Array of connected polygons describing the corridor. + // pathSize - (in) Number of polygons in path array. + // straightPath - (out) Points describing the straight path. + // straightPathFlags - (out, opt) Flags describing each point type, see dtStraightPathFlags. + // straightPathRefs - (out, opt) References to polygons at point locations. + // straightPathCount - (out) Number of points in the path. + // maxStraightPath - (in) The max number of points the straight path array can hold. Must be at least 1. + dtStatus findStraightPath(const float* startPos, const float* endPos, + const dtPolyRef* path, const int pathSize, + float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs, + int* straightPathCount, const int maxStraightPath) const; + + // Moves from startPos to endPos constrained to the navmesh. + // If the endPos is reachable, the resultPos will be endPos, + // or else the resultPos will be the nearest point in navmesh. + // Note: The resulting point is not projected to the ground, use getPolyHeight() to get height. + // Note: The algorithm is optimized for small delta movement and small number of polygons. + // Params: + // startRef - (in) ref to the polygon where startPos lies. + // startPos[3] - (in) start position of the mover. + // endPos[3] - (in) desired end position of the mover. + // filter - (in) path polygon filter. + // resultPos[3] - (out) new position of the mover. + // visited - (out) array of visited polygons. + // visitedCount - (out) Number of entries in the visited array. + // maxVisitedSize - (in) max number of polygons in the visited array. + dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos, + const dtQueryFilter* filter, + float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const; + + // Casts 'walkability' ray along the navmesh surface from startPos towards the endPos. + // Params: + // startRef - (in) ref to the polygon where the start lies. + // startPos[3] - (in) start position of the query. + // endPos[3] - (in) end position of the query. + // t - (out) hit parameter along the segment, FLT_MAX if no hit. + // hitNormal[3] - (out) normal of the nearest hit. + // filter - (in) path polygon filter. + // path - (out,opt) visited path polygons. + // pathCount - (out,opt) Number of polygons visited. + // maxPath - (in) max number of polygons in the path array. + dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos, + const dtQueryFilter* filter, + float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const; + + // Returns distance to nearest wall from the specified location. + // Params: + // startRef - (in) ref to the polygon where the center lies. + // centerPos[3] - (in) center if the query circle. + // maxRadius - (in) max search radius. + // filter - (in) path polygon filter. + // hitDist - (out) distance to nearest wall from the test location. + // hitPos[3] - (out) location of the nearest hit. + // hitNormal[3] - (out) normal of the nearest hit. + dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius, + const dtQueryFilter* filter, + float* hitDist, float* hitPos, float* hitNormal) const; + + // Finds polygons found along the navigation graph which touch the specified circle. + // Params: + // startRef - (in) ref to the polygon where the search starts. + // centerPos[3] - (in) center if the query circle. + // radius - (in) radius of the query circle. + // filter - (in) path polygon filter. + // resultRef - (out, opt) refs to the polygons touched by the circle. + // resultParent - (out, opt) parent of each result polygon. + // resultCost - (out, opt) search cost at each result polygon. + // resultCount - (out, opt) Number of results. + // maxResult - (int) maximum capacity of search results. dtStatus findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius, const dtQueryFilter* filter, dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost, int* resultCount, const int maxResult) const; - /// Finds the polygons along the naviation graph that touch the specified convex polygon. - /// @param[in] startRef The reference id of the polygon where the search starts. - /// @param[in] verts The vertices describing the convex polygon. (CCW) - /// [(x, y, z) * @p nverts] - /// @param[in] nverts The number of vertices in the polygon. - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] resultRef The reference ids of the polygons touched by the search polygon. [opt] - /// @param[out] resultParent The reference ids of the parent polygons for each result. Zero if a - /// result polygon has no parent. [opt] - /// @param[out] resultCost The search cost from the centroid point to the polygon. [opt] - /// @param[out] resultCount The number of polygons found. - /// @param[in] maxResult The maximum number of polygons the result arrays can hold. - /// @returns The status flags for the query. + // Finds polygons found along the navigation graph which touch the convex polygon shape. + // Params: + // startRef - (in) ref to the polygon where the search starts. + // verts[3*n] - (in) vertices describing convex polygon shape (CCW). + // nverts - (in) number of vertices in the polygon. + // filter - (in) path polygon filter. + // resultRef - (out, opt) refs to the polygons touched by the circle. + // resultParent - (out, opt) parent of each result polygon. + // resultCost - (out, opt) search cost at each result polygon. + // resultCount - (out) number of results. + // maxResult - (int) maximum capacity of search results. dtStatus findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts, const dtQueryFilter* filter, dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost, int* resultCount, const int maxResult) const; - /// @} - /// @name Local Query Functions - ///@{ - - /// Finds the polygon nearest to the specified center point. - /// @param[in] center The center of the search box. [(x, y, z)] - /// @param[in] extents The search distance along each axis. [(x, y, z)] - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] nearestRef The reference id of the nearest polygon. - /// @param[out] nearestPt The nearest point on the polygon. [opt] [(x, y, z)] - /// @returns The status flags for the query. - dtStatus findNearestPoly(const float* center, const float* extents, - const dtQueryFilter* filter, - dtPolyRef* nearestRef, float* nearestPt) const; - - /// Finds polygons that overlap the search box. - /// @param[in] center The center of the search box. [(x, y, z)] - /// @param[in] extents The search distance along each axis. [(x, y, z)] - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] polys The reference ids of the polygons that overlap the query box. - /// @param[out] polyCount The number of polygons in the search result. - /// @param[in] maxPolys The maximum number of polygons the search result can hold. - /// @returns The status flags for the query. - dtStatus queryPolygons(const float* center, const float* extents, - const dtQueryFilter* filter, - dtPolyRef* polys, int* polyCount, const int maxPolys) const; - - /// Finds the non-overlapping navigation polygons in the local neighbourhood around the center position. - /// @param[in] startRef The reference id of the polygon where the search starts. - /// @param[in] centerPos The center of the query circle. [(x, y, z)] - /// @param[in] radius The radius of the query circle. - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] resultRef The reference ids of the polygons touched by the circle. - /// @param[out] resultParent The reference ids of the parent polygons for each result. - /// Zero if a result polygon has no parent. [opt] - /// @param[out] resultCount The number of polygons found. - /// @param[in] maxResult The maximum number of polygons the result arrays can hold. - /// @returns The status flags for the query. + // Finds non-overlapping local neighbourhood around center location. + // Note: The algorithm is optimized for small query radius and small number of polygons. + // Params: + // startRef - (in) ref to the polygon where the search starts. + // centerPos[3] - (in) center if the query circle. + // radius - (in) radius of the query circle. + // filter - (in) path polygon filter. + // resultRef - (out) refs to the polygons touched by the circle. + // resultParent - (out, opt) parent of each result polygon. + // resultCount - (out) number of results. + // maxResult - (int) maximum capacity of search results. dtStatus findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius, const dtQueryFilter* filter, dtPolyRef* resultRef, dtPolyRef* resultParent, int* resultCount, const int maxResult) const; - - /// Moves from the start to the end position constrained to the navigation mesh. - /// @param[in] startRef The reference id of the start polygon. - /// @param[in] startPos A position of the mover within the start polygon. [(x, y, x)] - /// @param[in] endPos The desired end position of the mover. [(x, y, z)] - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] resultPos The result position of the mover. [(x, y, z)] - /// @param[out] visited The reference ids of the polygons visited during the move. - /// @param[out] visitedCount The number of polygons visited during the move. - /// @param[in] maxVisitedSize The maximum number of polygons the @p visited array can hold. - /// @returns The status flags for the query. - dtStatus moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos, - const dtQueryFilter* filter, - float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const; - - /// Casts a 'walkability' ray along the surface of the navigation mesh from - /// the start position toward the end position. - /// @param[in] startRef The reference id of the start polygon. - /// @param[in] startPos A position within the start polygon representing - /// the start of the ray. [(x, y, z)] - /// @param[in] endPos The position to cast the ray toward. [(x, y, z)] - /// @param[out] t The hit parameter. (FLT_MAX if no wall hit.) - /// @param[out] hitNormal The normal of the nearest wall hit. [(x, y, z)] - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] path The reference ids of the visited polygons. [opt] - /// @param[out] pathCount The number of visited polygons. [opt] - /// @param[in] maxPath The maximum number of polygons the @p path array can hold. - /// @returns The status flags for the query. - dtStatus raycast(dtPolyRef startRef, const float* startPos, const float* endPos, - const dtQueryFilter* filter, - float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const; - /// Finds the distance from the specified position to the nearest polygon wall. - /// @param[in] startRef The reference id of the polygon containing @p centerPos. - /// @param[in] centerPos The center of the search circle. [(x, y, z)] - /// @param[in] maxRadius The radius of the search circle. - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] hitDist The distance to the nearest wall from @p centerPos. - /// @param[out] hitPos The nearest position on the wall that was hit. [(x, y, z)] - /// @param[out] hitNormal The normalized ray formed from the wall point to the - /// source point. [(x, y, z)] - /// @returns The status flags for the query. - dtStatus findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius, - const dtQueryFilter* filter, - float* hitDist, float* hitPos, float* hitNormal) const; - - /// Returns the segments for the specified polygon, optionally including portals. - /// @param[in] ref The reference id of the polygon. - /// @param[in] filter The polygon filter to apply to the query. - /// @param[out] segmentVerts The segments. [(ax, ay, az, bx, by, bz) * segmentCount] - /// @param[out] segmentRefs The reference ids of each segment's neighbor polygon. - /// Or zero if the segment is a wall. [opt] [(parentRef) * @p segmentCount] - /// @param[out] segmentCount The number of segments returned. - /// @param[in] maxSegments The maximum number of segments the result arrays can hold. - /// @returns The status flags for the query. + // Returns wall segments of specified polygon. + // Params: + // ref - (in) ref to the polygon. + // filter - (in) path polygon filter. + // segments[6*maxSegments] - (out) wall segments (2 endpoints per segment). + // segmentCount - (out) number of wall segments. + // maxSegments - (in) max number of segments that can be stored in 'segments'. dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter, - float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount, - const int maxSegments) const; - - /// Returns random location on navmesh. - /// Polygons are chosen weighted by area. The search runs in linear related to number of polygon. - /// @param[in] filter The polygon filter to apply to the query. - /// @param[in] frand Function returning a random number [0..1). - /// @param[out] randomRef The reference id of the random location. - /// @param[out] randomPt The random location. - /// @returns The status flags for the query. - dtStatus findRandomPoint(const dtQueryFilter* filter, float (*frand)(), - dtPolyRef* randomRef, float* randomPt) const; - - /// Returns random location on navmesh within the reach of specified location. - /// Polygons are chosen weighted by area. The search runs in linear related to number of polygon. - /// The location is not exactly constrained by the circle, but it limits the visited polygons. - /// @param[in] startRef The reference id of the polygon where the search starts. - /// @param[in] centerPos The center of the search circle. [(x, y, z)] - /// @param[in] filter The polygon filter to apply to the query. - /// @param[in] frand Function returning a random number [0..1). - /// @param[out] randomRef The reference id of the random location. - /// @param[out] randomPt The random location. [(x, y, z)] - /// @returns The status flags for the query. - dtStatus findRandomPointAroundCircle(dtPolyRef startRef, const float* centerPos, const float maxRadius, - const dtQueryFilter* filter, float (*frand)(), - dtPolyRef* randomRef, float* randomPt) const; + float* segments, int* segmentCount, const int maxSegments) const; - /// Finds the closest point on the specified polygon. - /// @param[in] ref The reference id of the polygon. - /// @param[in] pos The position to check. [(x, y, z)] - /// @param[out] closest The closest point on the polygon. [(x, y, z)] - /// @returns The status flags for the query. + // Returns closest point on navigation polygon. + // Uses detail polygons to find the closest point to the navigation polygon surface. + // Params: + // ref - (in) ref to the polygon. + // pos[3] - (in) the point to check. + // closest[3] - (out) closest point. + // Returns: true if closest point found. dtStatus closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const; - /// Returns a point on the boundary closest to the source point if the source point is outside the - /// polygon's xz-bounds. - /// @param[in] ref The reference id to the polygon. - /// @param[in] pos The position to check. [(x, y, z)] - /// @param[out] closest The closest point. [(x, y, z)] - /// @returns The status flags for the query. + // Returns closest point on navigation polygon boundary. + // Uses the navigation polygon boundary to snap the point to poly boundary + // if it is outside the polygon. Much faster than closestPointToPoly. Does not affect height. + // Params: + // ref - (in) ref to the polygon. + // pos[3] - (in) the point to check. + // closest[3] - (out) closest point. + // Returns: true if closest point found. dtStatus closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const; - /// Gets the height of the polygon at the provided position using the height detail. (Most accurate.) - /// @param[in] ref The reference id of the polygon. - /// @param[in] pos A position within the xz-bounds of the polygon. [(x, y, z)] - /// @param[out] height The height at the surface of the polygon. - /// @returns The status flags for the query. + // Returns start and end location of an off-mesh link polygon. + // Params: + // prevRef - (in) ref to the polygon before the link (used to select direction). + // polyRef - (in) ref to the off-mesh link polygon. + // startPos[3] - (out) start point of the link. + // endPos[3] - (out) end point of the link. + // Returns: true if link is found. + dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, float* startPos, float* endPos) const; + + // Returns height of the polygon at specified location. + // Params: + // ref - (in) ref to the polygon. + // pos[3] - (in) the point where to locate the height. + // height - (out) height at the location. + // Returns: true if over polygon. dtStatus getPolyHeight(dtPolyRef ref, const float* pos, float* height) const; - - /// @} - /// @name Miscellaneous Functions - /// @{ - - /// Returns true if the polygon reference is valid and passes the filter restrictions. - /// @param[in] ref The polygon reference to check. - /// @param[in] filter The filter to apply. - bool isValidPolyRef(dtPolyRef ref, const dtQueryFilter* filter) const; - - /// Returns true if the polygon reference is in the closed list. - /// @param[in] ref The reference id of the polygon to check. - /// @returns True if the polygon is in closed list. + + // Returns true if poly reference ins in closed list. bool isInClosedList(dtPolyRef ref) const; - /// Gets the node pool. - /// @returns The node pool. class dtNodePool* getNodePool() const { return m_nodePool; } - /// Gets the navigation mesh the query object is using. - /// @return The navigation mesh the query object is using. - const dtNavMesh* getAttachedNavMesh() const { return m_nav; } - - /// @} - private: - /// Returns neighbour tile based on side. + // Returns neighbour tile based on side. dtMeshTile* getNeighbourTileAt(int x, int y, int side) const; - /// Queries polygons within a tile. + // Queries polygons within a tile. int queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax, const dtQueryFilter* filter, dtPolyRef* polys, const int maxPolys) const; - /// Find nearest polygon within a tile. + // Find nearest polygon within a tile. dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center, const float* extents, const dtQueryFilter* filter, float* nearestPt) const; - /// Returns closest point on polygon. - void closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* closest) const; + // Returns closest point on polygon. + dtStatus closestPointOnPolyInTile(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* closest) const; - /// Returns portal points between two polygons. + // Returns portal points between two polygons. dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right, unsigned char& fromType, unsigned char& toType) const; dtStatus getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile, dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile, float* left, float* right) const; - /// Returns edge mid point between two polygons. + // Returns edge mid point between two polygons. dtStatus getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const; dtStatus getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile, dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile, float* mid) const; - // Appends vertex to a straight path - dtStatus appendVertex(const float* pos, const unsigned char flags, const dtPolyRef ref, - float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs, - int* straightPathCount, const int maxStraightPath) const; - - // Appends intermediate portal points to a straight path. - dtStatus appendPortals(const int startIdx, const int endIdx, const float* endPos, const dtPolyRef* path, - float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs, - int* straightPathCount, const int maxStraightPath, const int options) const; - - const dtNavMesh* m_nav; ///< Pointer to navmesh data. + const dtNavMesh* m_nav; // Pointer to navmesh data. struct dtQueryData { @@ -468,21 +393,15 @@ private: float startPos[3], endPos[3]; const dtQueryFilter* filter; }; - dtQueryData m_query; ///< Sliced query state. + dtQueryData m_query; // Sliced query state. - class dtNodePool* m_tinyNodePool; ///< Pointer to small node pool. - class dtNodePool* m_nodePool; ///< Pointer to node pool. - class dtNodeQueue* m_openList; ///< Pointer to open list queue. + class dtNodePool* m_tinyNodePool; // Pointer to small node pool. + class dtNodePool* m_nodePool; // Pointer to node pool. + class dtNodeQueue* m_openList; // Pointer to open list queue. }; -/// Allocates a query object using the Detour allocator. -/// @return An allocated query object, or null on failure. -/// @ingroup detour +// Helper function to allocate navmesh query class using Detour allocator. dtNavMeshQuery* dtAllocNavMeshQuery(); - -/// Frees the specified query object using the Detour allocator. -/// @param[in] query A query object allocated using #dtAllocNavMeshQuery -/// @ingroup detour void dtFreeNavMeshQuery(dtNavMeshQuery* query); #endif // DETOURNAVMESHQUERY_H diff --git a/dep/recastnavigation/Detour/DetourNode.cpp b/dep/recastnavigation/Detour/DetourNode.cpp index 4c8215e..0d1af83 100644 --- a/dep/recastnavigation/Detour/DetourNode.cpp +++ b/dep/recastnavigation/Detour/DetourNode.cpp @@ -24,7 +24,6 @@ inline unsigned int dtHashRef(dtPolyRef a) { - // Edited by TC a = (~a) + (a << 18); a = a ^ (a >> 31); a = a * 21; @@ -47,15 +46,15 @@ dtNodePool::dtNodePool(int maxNodes, int hashSize) : dtAssert(m_maxNodes > 0); m_nodes = (dtNode*)dtAlloc(sizeof(dtNode)*m_maxNodes, DT_ALLOC_PERM); - m_next = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*m_maxNodes, DT_ALLOC_PERM); - m_first = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*hashSize, DT_ALLOC_PERM); + m_next = (unsigned short*)dtAlloc(sizeof(unsigned short)*m_maxNodes, DT_ALLOC_PERM); + m_first = (unsigned short*)dtAlloc(sizeof(unsigned short)*hashSize, DT_ALLOC_PERM); dtAssert(m_nodes); dtAssert(m_next); dtAssert(m_first); - memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize); - memset(m_next, 0xff, sizeof(dtNodeIndex)*m_maxNodes); + memset(m_first, 0xff, sizeof(unsigned short)*m_hashSize); + memset(m_next, 0xff, sizeof(unsigned short)*m_maxNodes); } dtNodePool::~dtNodePool() @@ -67,14 +66,14 @@ dtNodePool::~dtNodePool() void dtNodePool::clear() { - memset(m_first, 0xff, sizeof(dtNodeIndex)*m_hashSize); + memset(m_first, 0xff, sizeof(unsigned short)*m_hashSize); m_nodeCount = 0; } dtNode* dtNodePool::findNode(dtPolyRef id) { unsigned int bucket = dtHashRef(id) & (m_hashSize-1); - dtNodeIndex i = m_first[bucket]; + unsigned short i = m_first[bucket]; while (i != DT_NULL_IDX) { if (m_nodes[i].id == id) @@ -87,7 +86,7 @@ dtNode* dtNodePool::findNode(dtPolyRef id) dtNode* dtNodePool::getNode(dtPolyRef id) { unsigned int bucket = dtHashRef(id) & (m_hashSize-1); - dtNodeIndex i = m_first[bucket]; + unsigned short i = m_first[bucket]; dtNode* node = 0; while (i != DT_NULL_IDX) { @@ -99,7 +98,7 @@ dtNode* dtNodePool::getNode(dtPolyRef id) if (m_nodeCount >= m_maxNodes) return 0; - i = (dtNodeIndex)m_nodeCount; + i = (unsigned short)m_nodeCount; m_nodeCount++; // Init node diff --git a/dep/recastnavigation/Detour/DetourNode.h b/dep/recastnavigation/Detour/DetourNode.h index b68c922..e893f78 100644 --- a/dep/recastnavigation/Detour/DetourNode.h +++ b/dep/recastnavigation/Detour/DetourNode.h @@ -27,20 +27,18 @@ enum dtNodeFlags DT_NODE_CLOSED = 0x02, }; -typedef unsigned short dtNodeIndex; -static const dtNodeIndex DT_NULL_IDX = (dtNodeIndex)~0; +static const unsigned short DT_NULL_IDX = 0xffff; struct dtNode { - float pos[3]; ///< Position of the node. - float cost; ///< Cost from previous node to current node. - float total; ///< Cost up to the node. - unsigned int pidx : 30; ///< Index to parent node. - unsigned int flags : 2; ///< Node flags 0/open/closed. - dtPolyRef id; ///< Polygon ref the node corresponds to. + float pos[3]; // Position of the node. + float cost; // Cost from previous node to current node. + float total; // Cost up to the node. + unsigned int pidx : 30; // Index to parent node. + unsigned int flags : 2; // Node flags 0/open/closed. + dtPolyRef id; // Polygon ref the node corresponds to. }; - class dtNodePool { public: @@ -72,22 +70,22 @@ public: inline int getMemUsed() const { return sizeof(*this) + - sizeof(dtNode)*m_maxNodes + - sizeof(dtNodeIndex)*m_maxNodes + - sizeof(dtNodeIndex)*m_hashSize; + sizeof(dtNode)*m_maxNodes + + sizeof(unsigned short)*m_maxNodes + + sizeof(unsigned short)*m_hashSize; } inline int getMaxNodes() const { return m_maxNodes; } inline int getHashSize() const { return m_hashSize; } - inline dtNodeIndex getFirst(int bucket) const { return m_first[bucket]; } - inline dtNodeIndex getNext(int i) const { return m_next[i]; } + inline unsigned short getFirst(int bucket) const { return m_first[bucket]; } + inline unsigned short getNext(int i) const { return m_next[i]; } private: dtNode* m_nodes; - dtNodeIndex* m_first; - dtNodeIndex* m_next; + unsigned short* m_first; + unsigned short* m_next; const int m_maxNodes; const int m_hashSize; int m_nodeCount; @@ -156,4 +154,4 @@ private: }; -#endif // DETOURNODE_H +#endif // DETOURNODE_H \ No newline at end of file diff --git a/dep/recastnavigation/Detour/DetourStatus.h b/dep/recastnavigation/Detour/DetourStatus.h deleted file mode 100644 index af822c4..0000000 --- a/dep/recastnavigation/Detour/DetourStatus.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. -// - -#ifndef DETOURSTATUS_H -#define DETOURSTATUS_H - -typedef unsigned int dtStatus; - -// High level status. -static const unsigned int DT_FAILURE = 1u << 31; // Operation failed. -static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed. -static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress. - -// Detail information for status. -static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff; -static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized. -static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version. -static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory. -static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid. -static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results. -static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search. -static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess. - - -// Returns true of status is success. -inline bool dtStatusSucceed(dtStatus status) -{ - return (status & DT_SUCCESS) != 0; -} - -// Returns true of status is failure. -inline bool dtStatusFailed(dtStatus status) -{ - return (status & DT_FAILURE) != 0; -} - -// Returns true of status is in progress. -inline bool dtStatusInProgress(dtStatus status) -{ - return (status & DT_IN_PROGRESS) != 0; -} - -// Returns true if specific detail is set. -inline bool dtStatusDetail(dtStatus status, unsigned int detail) -{ - return (status & detail) != 0; -} - -#endif // DETOURSTATUS_H diff --git a/dep/recastnavigation/Recast/CMakeLists.txt b/dep/recastnavigation/Recast/CMakeLists.txt index 5f466a4..726aff7 100644 --- a/dep/recastnavigation/Recast/CMakeLists.txt +++ b/dep/recastnavigation/Recast/CMakeLists.txt @@ -14,7 +14,6 @@ set(Recast_STAT_SRCS RecastArea.cpp RecastContour.cpp RecastFilter.cpp - RecastLayers.cpp RecastMesh.cpp RecastMeshDetail.cpp RecastRasterization.cpp diff --git a/dep/recastnavigation/Recast/Recast.cpp b/dep/recastnavigation/Recast/Recast.cpp index 803daac..d051418 100644 --- a/dep/recastnavigation/Recast/Recast.cpp +++ b/dep/recastnavigation/Recast/Recast.cpp @@ -32,26 +32,7 @@ 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) @@ -109,28 +90,6 @@ void rcFreeCompactHeightfield(rcCompactHeightfield* chf) rcFree(chf); } - -rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet() -{ - rcHeightfieldLayerSet* lset = (rcHeightfieldLayerSet*)rcAlloc(sizeof(rcHeightfieldLayerSet), RC_ALLOC_PERM); - memset(lset, 0, sizeof(rcHeightfieldLayerSet)); - return lset; -} - -void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset) -{ - if (!lset) return; - for (int i = 0; i < lset->nlayers; ++i) - { - rcFree(lset->layers[i].heights); - rcFree(lset->layers[i].areas); - rcFree(lset->layers[i].cons); - } - rcFree(lset->layers); - rcFree(lset); -} - - rcContourSet* rcAllocContourSet() { rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM); @@ -184,6 +143,7 @@ void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh) rcFree(dmesh); } + void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax) { // Calculate bounding box. @@ -203,11 +163,6 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* *h = (int)((bmax[2] - bmin[2])/cs+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) @@ -237,14 +192,6 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo rcVnormalize(norm); } -/// @par -/// -/// Only sets the aread id's for the walkable triangles. Does not alter the -/// area id's for unwalkable triangles. -/// -/// See the #rcConfig documentation for more information on the configuration parameters. -/// -/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle, const float* verts, int /*nv*/, const int* tris, int nt, @@ -267,14 +214,6 @@ void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle, } } -/// @par -/// -/// Only sets the aread id's for the unwalkable triangles. Does not alter the -/// area id's for walkable triangles. -/// -/// See the #rcConfig documentation for more information on the configuration parameters. -/// -/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle, const float* verts, int /*nv*/, const int* tris, int nt, @@ -319,15 +258,6 @@ int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf) return spanCount; } -/// @par -/// -/// This is just the beginning of the process of fully building a compact heightfield. -/// Various filters may be applied applied, then the distance field and regions built. -/// E.g: #rcBuildDistanceField and #rcBuildRegions -/// -/// See the #rcConfig documentation for more information on the configuration parameters. -/// -/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb, rcHeightfield& hf, rcCompactHeightfield& chf) { @@ -439,13 +369,13 @@ bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const i if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb) { // Mark direction as walkable. - const int lidx = k - (int)nc.index; - if (lidx < 0 || lidx > MAX_LAYERS) + const int idx = k - (int)nc.index; + if (idx < 0 || idx > MAX_LAYERS) { - tooHighNeighbour = rcMax(tooHighNeighbour, lidx); + tooHighNeighbour = rcMax(tooHighNeighbour, idx); continue; } - rcSetCon(s, dir, lidx); + rcSetCon(s, dir, idx); break; } } diff --git a/dep/recastnavigation/Recast/Recast.h b/dep/recastnavigation/Recast/Recast.h index fb36aa4..0e5f074 100644 --- a/dep/recastnavigation/Recast/Recast.h +++ b/dep/recastnavigation/Recast/Recast.h @@ -19,583 +19,327 @@ #ifndef RECAST_H #define RECAST_H -/// The value of PI used by Recast. +// Some math headers don't have PI defined. static const float RC_PI = 3.14159265f; -/// Recast log categories. -/// @see rcContext enum rcLogCategory { - RC_LOG_PROGRESS = 1, ///< A progress log entry. - RC_LOG_WARNING, ///< A warning log entry. - RC_LOG_ERROR, ///< An error log entry. + RC_LOG_PROGRESS = 1, + RC_LOG_WARNING, + RC_LOG_ERROR, }; -/// Recast performance timer categories. -/// @see rcContext enum rcTimerLabel { - /// The user defined total time of the build. RC_TIMER_TOTAL, - /// A user defined build time. RC_TIMER_TEMP, - /// The time to rasterize the triangles. (See: #rcRasterizeTriangle) RC_TIMER_RASTERIZE_TRIANGLES, - /// The time to build the compact heightfield. (See: #rcBuildCompactHeightfield) RC_TIMER_BUILD_COMPACTHEIGHTFIELD, - /// The total time to build the contours. (See: #rcBuildContours) RC_TIMER_BUILD_CONTOURS, - /// The time to trace the boundaries of the contours. (See: #rcBuildContours) RC_TIMER_BUILD_CONTOURS_TRACE, - /// The time to simplify the contours. (See: #rcBuildContours) RC_TIMER_BUILD_CONTOURS_SIMPLIFY, - /// The time to filter ledge spans. (See: #rcFilterLedgeSpans) RC_TIMER_FILTER_BORDER, - /// The time to filter low height spans. (See: #rcFilterWalkableLowHeightSpans) RC_TIMER_FILTER_WALKABLE, - /// The time to apply the median filter. (See: #rcMedianFilterWalkableArea) RC_TIMER_MEDIAN_AREA, - /// The time to filter low obstacles. (See: #rcFilterLowHangingWalkableObstacles) RC_TIMER_FILTER_LOW_OBSTACLES, - /// The time to build the polygon mesh. (See: #rcBuildPolyMesh) RC_TIMER_BUILD_POLYMESH, - /// The time to merge polygon meshes. (See: #rcMergePolyMeshes) RC_TIMER_MERGE_POLYMESH, - /// The time to erode the walkable area. (See: #rcErodeWalkableArea) RC_TIMER_ERODE_AREA, - /// The time to mark a box area. (See: #rcMarkBoxArea) RC_TIMER_MARK_BOX_AREA, - /// The time to mark a cylinder area. (See: #rcMarkCylinderArea) - RC_TIMER_MARK_CYLINDER_AREA, - /// The time to mark a convex polygon area. (See: #rcMarkConvexPolyArea) RC_TIMER_MARK_CONVEXPOLY_AREA, - /// The total time to build the distance field. (See: #rcBuildDistanceField) RC_TIMER_BUILD_DISTANCEFIELD, - /// The time to build the distances of the distance field. (See: #rcBuildDistanceField) RC_TIMER_BUILD_DISTANCEFIELD_DIST, - /// The time to blur the distance field. (See: #rcBuildDistanceField) RC_TIMER_BUILD_DISTANCEFIELD_BLUR, - /// The total time to build the regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone) RC_TIMER_BUILD_REGIONS, - /// The total time to apply the watershed algorithm. (See: #rcBuildRegions) RC_TIMER_BUILD_REGIONS_WATERSHED, - /// The time to expand regions while applying the watershed algorithm. (See: #rcBuildRegions) RC_TIMER_BUILD_REGIONS_EXPAND, - /// The time to flood regions while applying the watershed algorithm. (See: #rcBuildRegions) RC_TIMER_BUILD_REGIONS_FLOOD, - /// The time to filter out small regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone) RC_TIMER_BUILD_REGIONS_FILTER, - /// The time to build heightfield layers. (See: #rcBuildHeightfieldLayers) - RC_TIMER_BUILD_LAYERS, - /// The time to build the polygon mesh detail. (See: #rcBuildPolyMeshDetail) RC_TIMER_BUILD_POLYMESHDETAIL, - /// The time to merge polygon mesh details. (See: #rcMergePolyMeshDetails) RC_TIMER_MERGE_POLYMESHDETAIL, - /// The maximum number of timers. (Used for iterating timers.) RC_MAX_TIMERS }; -/// Provides an interface for optional logging and performance tracking of the Recast -/// build process. -/// @ingroup recast +// Build context provides several optional utilities needed for the build process, +// such as timing, logging, and build time collecting. class rcContext { public: - - /// Contructor. - /// @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() {} - /// Enables or disables logging. - /// @param[in] state TRUE if logging should be enabled. + // Enables or disables logging. inline void enableLog(bool state) { m_logEnabled = state; } - - /// Clears all log entries. + // Resets log. inline void resetLog() { if (m_logEnabled) doResetLog(); } - - /// Logs a message. - /// @param[in] category The category of the message. - /// @param[in] format The message. + // Logs a message. void log(const rcLogCategory category, const char* format, ...); - /// Enables or disables the performance timers. - /// @param[in] state TRUE if timers should be enabled. + // Enables or disables timer. inline void enableTimer(bool state) { m_timerEnabled = state; } - - /// Clears all peformance timers. (Resets all to unused.) + // Resets all timers. inline void resetTimers() { if (m_timerEnabled) doResetTimers(); } - - /// Starts the specified performance timer. - /// @param label The category of timer. + // Starts timer, used for performance timing. inline void startTimer(const rcTimerLabel label) { if (m_timerEnabled) doStartTimer(label); } - - /// Stops the specified performance timer. - /// @param label The category of the timer. + // Stops timer, used for performance timing. 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. + // Returns time accumulated between timer start/stop. inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; } protected: - - /// Clears all log entries. + // Virtual functions to override for custom implementations. 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. virtual void doLog(const rcLogCategory /*category*/, const char* /*msg*/, const int /*len*/) {} - - /// Clears all timers. (Resets all to unused.) virtual void doResetTimers() {} - - /// Starts the specified performance timer. - /// @param[in] label The category of timer. virtual void doStartTimer(const rcTimerLabel /*label*/) {} - - /// Stops the specified performance timer. - /// @param[in] label The category of the timer. virtual void doStopTimer(const rcTimerLabel /*label*/) {} - - /// Returns the total accumulated time of the specified performance timer. - /// @param[in] label The category of the timer. - /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. virtual int doGetAccumulatedTime(const rcTimerLabel /*label*/) const { return -1; } - /// True if logging is enabled. bool m_logEnabled; - - /// True if the performance timers are enabled. bool m_timerEnabled; }; -/// Specifies a configuration to use when performing Recast builds. -/// @ingroup recast + +// The units of the parameters are specified in parenthesis as follows: +// (vx) voxels, (wu) world units struct rcConfig { - /// The width of the field along the x-axis. [Limit: >= 0] [Units: vx] - int width; - - /// The height of the field along the z-axis. [Limit: >= 0] [Units: vx] - int height; - - /// The width/height size of tile's on the xz-plane. [Limit: >= 0] [Units: vx] - int tileSize; - - /// The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx] - int borderSize; - - /// The xz-plane cell size to use for fields. [Limit: > 0] [Units: wu] - float cs; - - /// The y-axis cell size to use for fields. [Limit: > 0] [Units: wu] - float ch; - - /// The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] - float bmin[3]; - - /// The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] - float bmax[3]; - - /// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees] - float walkableSlopeAngle; - - /// Minimum floor to 'ceiling' height that will still allow the floor area to - /// be considered walkable. [Limit: >= 3] [Units: vx] - int walkableHeight; - - /// Maximum ledge height that is considered to still be traversable. [Limit: >=0] [Units: vx] - int walkableClimb; - - /// The distance to erode/shrink the walkable area of the heightfield away from - /// obstructions. [Limit: >=0] [Units: vx] - int walkableRadius; - - /// 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 original raw contour. [Limit: >=0] [Units: wu] - float maxSimplificationError; - - /// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx] - int minRegionArea; - - /// Any regions with a span count smaller than this value will, if possible, - /// be merged with larger regions. [Limit: >=0] [Units: vx] - int mergeRegionArea; - - /// The maximum number of vertices allowed for polygons generated during the - /// contour to polygon conversion process. [Limit: >= 3] - int maxVertsPerPoly; - - /// Sets the sampling distance to use when generating the detail mesh. - /// (For height detail only.) [Limits: 0 or >= 0.9] [Units: wu] - float detailSampleDist; - - /// The maximum distance the detail mesh surface should deviate from heightfield - /// data. (For height detail only.) [Limit: >=0] [Units: wu] - float detailSampleMaxError; + int width, height; // Dimensions of the rasterized heightfield (vx) + int tileSize; // Width and Height of a tile (vx) + int borderSize; // Non-navigable Border around the heightfield (vx) + float cs, ch; // Grid cell size and height (wu) + float bmin[3], bmax[3]; // Grid bounds (wu) + float walkableSlopeAngle; // Maximum walkable slope angle in degrees. + int walkableHeight; // Minimum height where the agent can still walk (vx) + int walkableClimb; // Maximum height between grid cells the agent can climb (vx) + int walkableRadius; // Radius of the agent in cells (vx) + int maxEdgeLen; // Maximum contour edge length (vx) + float maxSimplificationError; // Maximum distance error from contour to cells (vx) + int minRegionArea; // Regions whose area is smaller than this threshold will be removed. (vx) + int mergeRegionArea; // Regions whose area is smaller than this threshold will be merged (vx) + int maxVertsPerPoly; // Max number of vertices per polygon + float detailSampleDist; // Detail mesh sample spacing. + float detailSampleMaxError; // Detail mesh simplification max sample error. }; -/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax. -static const int RC_SPAN_HEIGHT_BITS = 16; // EDITED BY TC -/// Defines the maximum value for rcSpan::smin and rcSpan::smax. +// Define number of bits in the above structure for smin/smax. +// The max height is used for clamping rasterized values. +static const int RC_SPAN_HEIGHT_BITS = 16; static const int RC_SPAN_MAX_HEIGHT = (1< inline void rcSwap(T& a, T& b) { T t = a; a = b; b = t; } +inline int rcGetCon(const rcCompactSpan& s, int dir) +{ + const unsigned int shift = (unsigned int)dir*6; + return (s.con >> shift) & 0x3f; +} -/// Returns the minimum of two values. -/// @param[in] a Value A -/// @param[in] b Value B -/// @return The minimum of the two values. -template inline T rcMin(T a, T b) { return a < b ? a : b; } +inline int rcGetDirOffsetX(int dir) +{ + const int offset[4] = { -1, 0, 1, 0, }; + return offset[dir&0x03]; +} -/// Returns the maximum of two values. -/// @param[in] a Value A -/// @param[in] b Value B -/// @return The maximum of the two values. -template inline T rcMax(T a, T b) { return a > b ? a : b; } +inline int rcGetDirOffsetY(int dir) +{ + const int offset[4] = { 0, 1, 0, -1 }; + return offset[dir&0x03]; +} -/// Returns the absolute value. -/// @param[in] a The value. -/// @return The absolute value of the specified value. +// Common helper functions +template inline void rcSwap(T& a, T& b) { T t = a; a = b; b = t; } +template inline T rcMin(T a, T b) { return a < b ? a : b; } +template inline T rcMax(T a, T b) { return a > b ? a : b; } template inline T rcAbs(T a) { return a < 0 ? -a : a; } - -/// Returns the square of the value. -/// @param[in] a The value. -/// @return The square of the value. template 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 inline T rcClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); } - -/// Returns the square root of the value. -/// @param[in] x The value. -/// @return The square root of the vlaue. float rcSqrt(float x); -/// @} -/// @name Vector helper functions. -/// @{ - -/// Derives the cross product of two vectors. (@p v1 x @p v2) -/// @param[out] dest The cross product. [(x, y, z)] -/// @param[in] v1 A Vector [(x, y, z)] -/// @param[in] v2 A vector [(x, y, z)] +// Common vector helper functions. inline void rcVcross(float* dest, const float* v1, const float* v2) { dest[0] = v1[1]*v2[2] - v1[2]*v2[1]; @@ -603,20 +347,11 @@ inline void rcVcross(float* dest, const float* v1, const float* v2) dest[2] = v1[0]*v2[1] - v1[1]*v2[0]; } -/// Derives the dot product of two vectors. (@p v1 . @p v2) -/// @param[in] v1 A Vector [(x, y, z)] -/// @param[in] v2 A vector [(x, y, z)] -/// @return The dot product. inline float rcVdot(const float* v1, const float* v2) { return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; } -/// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s)) -/// @param[out] dest The result vector. [(x, y, z)] -/// @param[in] v1 The base vector. [(x, y, z)] -/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)] -/// @param[in] s The amount to scale @p v2 by before adding to @p v1. inline void rcVmad(float* dest, const float* v1, const float* v2, const float s) { dest[0] = v1[0]+v2[0]*s; @@ -624,10 +359,6 @@ inline void rcVmad(float* dest, const float* v1, const float* v2, const float s) dest[2] = v1[2]+v2[2]*s; } -/// Performs a vector addition. (@p v1 + @p v2) -/// @param[out] dest The result vector. [(x, y, z)] -/// @param[in] v1 The base vector. [(x, y, z)] -/// @param[in] v2 The vector to add to @p v1. [(x, y, z)] inline void rcVadd(float* dest, const float* v1, const float* v2) { dest[0] = v1[0]+v2[0]; @@ -635,10 +366,6 @@ inline void rcVadd(float* dest, const float* v1, const float* v2) dest[2] = v1[2]+v2[2]; } -/// Performs a vector subtraction. (@p v1 - @p v2) -/// @param[out] dest The result vector. [(x, y, z)] -/// @param[in] v1 The base vector. [(x, y, z)] -/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)] inline void rcVsub(float* dest, const float* v1, const float* v2) { dest[0] = v1[0]-v2[0]; @@ -646,9 +373,6 @@ inline void rcVsub(float* dest, const float* v1, const float* v2) dest[2] = v1[2]-v2[2]; } -/// Selects the minimum value of each element from the specified vectors. -/// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)] -/// @param[in] v A vector. [(x, y, z)] inline void rcVmin(float* mn, const float* v) { mn[0] = rcMin(mn[0], v[0]); @@ -656,9 +380,6 @@ inline void rcVmin(float* mn, const float* v) mn[2] = rcMin(mn[2], v[2]); } -/// 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)] inline void rcVmax(float* mx, const float* v) { mx[0] = rcMax(mx[0], v[0]); @@ -666,9 +387,6 @@ inline void rcVmax(float* mx, const float* v) mx[2] = rcMax(mx[2], v[2]); } -/// Performs a vector copy. -/// @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]; @@ -676,10 +394,6 @@ inline void rcVcopy(float* dest, const float* v) dest[2] = v[2]; } -/// Returns the distance between two points. -/// @param[in] v1 A point. [(x, y, z)] -/// @param[in] v2 A point. [(x, y, z)] -/// @return The distance between the two points. inline float rcVdist(const float* v1, const float* v2) { float dx = v2[0] - v1[0]; @@ -688,10 +402,6 @@ inline float rcVdist(const float* v1, const float* v2) return rcSqrt(dx*dx + dy*dy + dz*dz); } -/// Returns the square of the distance between two points. -/// @param[in] v1 A point. [(x, y, z)] -/// @param[in] v2 A point. [(x, y, z)] -/// @return The square of the distance between the two points. inline float rcVdistSqr(const float* v1, const float* v2) { float dx = v2[0] - v1[0]; @@ -700,8 +410,6 @@ inline float rcVdistSqr(const float* v1, const float* v2) return dx*dx + dy*dy + dz*dz; } -/// Normalizes the vector. -/// @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])); @@ -710,421 +418,271 @@ inline void rcVnormalize(float* v) v[2] *= d; } -/// @} -/// @name Heightfield Functions -/// @see rcHeightfield -/// @{ - -/// Calculates the bounding box of an array of vertices. -/// @ingroup recast -/// @param[in] verts An array of vertices. [(x, y, z) * @p nv] -/// @param[in] nv The number of vertices in the @p verts array. -/// @param[out] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu] -/// @param[out] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu] +inline bool rcVequal(const float* p0, const float* p1) +{ + static const float thr = rcSqr(1.0f/16384.0f); + const float d = rcVdistSqr(p0, p1); + return d < thr; +} + +// Calculated bounding box of array of vertices. +// Params: +// verts - (in) array of vertices +// nv - (in) vertex count +// bmin, bmax - (out) bounding box void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax); -/// Calculates the grid size based on the bounding box and grid cell size. -/// @ingroup recast -/// @param[in] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu] -/// @param[in] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu] -/// @param[in] cs The xz-plane cell size. [Limit: > 0] [Units: wu] -/// @param[out] w The width along the x-axis. [Limit: >= 0] [Units: vx] -/// @param[out] h The height along the z-axis. [Limit: >= 0] [Units: vx] +// Calculates grid size based on bounding box and grid cell size. +// Params: +// bmin, bmax - (in) bounding box +// cs - (in) grid cell size +// w - (out) grid width +// h - (out) grid height void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h); -/// Initializes a new heightfield. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in,out] hf The allocated heightfield to initialize. -/// @param[in] width The width of the field along the x-axis. [Limit: >= 0] [Units: vx] -/// @param[in] height The height of the field along the z-axis. [Limit: >= 0] [Units: vx] -/// @param[in] bmin The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] -/// @param[in] bmax The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] -/// @param[in] cs The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu] -/// @param[in] ch The y-axis cell size to use for field. [Limit: > 0] [Units: wu] +// Creates and initializes new heightfield. +// Params: +// hf - (in/out) heightfield to initialize. +// width - (in) width of the heightfield. +// height - (in) height of the heightfield. +// bmin, bmax - (in) bounding box of the heightfield +// cs - (in) grid cell size +// ch - (in) grid cell height bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height, const float* bmin, const float* bmax, float cs, float ch); -/// Sets the area id of all triangles with a slope below the specified value -/// to #RC_WALKABLE_AREA. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. -/// [Limits: 0 <= value < 90] [Units: Degrees] -/// @param[in] verts The vertices. [(x, y, z) * @p nv] -/// @param[in] nv The number of vertices. -/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] -/// @param[in] nt The number of triangles. -/// @param[out] areas The triangle area ids. [Length: >= @p nt] +// Sets the RC_WALKABLE_AREA for every triangle whose slope is below +// the maximum walkable slope angle. +// Params: +// walkableSlopeAngle - (in) maximum slope angle in degrees. +// verts - (in) array of vertices +// nv - (in) vertex count +// tris - (in) array of triangle vertex indices +// nt - (in) triangle count +// areas - (out) array of triangle area types void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, const int* tris, int nt, unsigned char* areas); -/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. -/// [Limits: 0 <= value < 90] [Units: Degrees] -/// @param[in] verts The vertices. [(x, y, z) * @p nv] -/// @param[in] nv The number of vertices. -/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] -/// @param[in] nt The number of triangles. -/// @param[out] areas The triangle area ids. [Length: >= @p nt] +// Sets the RC_NULL_AREA for every triangle whose slope is steeper than +// the maximum walkable slope angle. +// Params: +// walkableSlopeAngle - (in) maximum slope angle in degrees. +// verts - (in) array of vertices +// nv - (in) vertex count +// tris - (in) array of triangle vertex indices +// nt - (in) triangle count +// areas - (out) array of triangle are types void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, const int* tris, int nt, unsigned char* areas); -/// Adds a span to the specified heightfield. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in,out] hf An initialized heightfield. -/// @param[in] x The width index where the span is to be added. -/// [Limits: 0 <= value < rcHeightfield::width] -/// @param[in] y The height index where the span is to be added. -/// [Limits: 0 <= value < rcHeightfield::height] -/// @param[in] smin The minimum height of the span. [Limit: < @p smax] [Units: vx] -/// @param[in] smax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx] -/// @param[in] area The area id of the span. [Limit: <= #RC_WALKABLE_AREA) -/// @param[in] flagMergeThr The merge theshold. [Limit: >= 0] [Units: vx] -void rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y, +// Adds span to heightfield. +// The span addition can set to favor flags. If the span is merged to +// another span and the new smax is within 'flagMergeThr' units away +// from the existing span the span flags are merged and stored. +// Params: +// solid - (in) heightfield where the spans is added to +// x,y - (in) location on the heightfield where the span is added +// smin,smax - (in) spans min/max height +// flags - (in) span flags (zero or WALKABLE) +// flagMergeThr - (in) merge threshold. +void rcAddSpan(rcContext* ctx, rcHeightfield& solid, 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] + const unsigned short area, const int flagMergeThr); + +// Rasterizes a triangle into heightfield spans. +// Params: +// v0,v1,v2 - (in) the vertices of the triangle. +// area - (in) area type of the triangle. +// solid - (in) heightfield where the triangle is rasterized +// flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable. void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2, const unsigned char area, rcHeightfield& solid, const int flagMergeThr = 1); -/// Rasterizes an indexed triangle mesh into the specified heightfield. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] verts The vertices. [(x, y, z) * @p nv] -/// @param[in] nv The number of vertices. -/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt] -/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] -/// @param[in] nt The number of triangles. -/// @param[in,out] solid An initialized heightfield. -/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. -/// [Limit: >= 0] [Units: vx] +// Rasterizes indexed triangle mesh into heightfield spans. +// Params: +// verts - (in) array of vertices +// nv - (in) vertex count +// tris - (in) array of triangle vertex indices +// area - (in) array of triangle area types. +// nt - (in) triangle count +// solid - (in) heightfield where the triangles are rasterized +// flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable. void 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); -/// 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] +// Rasterizes indexed triangle mesh into heightfield spans. +// Params: +// verts - (in) array of vertices +// nv - (in) vertex count +// tris - (in) array of triangle vertex indices +// area - (in) array of triangle area types. +// nt - (in) triangle count +// solid - (in) heightfield where the triangles are rasterized +// flagMergeThr - (in) distance in voxel where walkable flag is favored over non-walkable. void 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] +// Rasterizes the triangles into heightfield spans. +// Params: +// verts - (in) array of vertices +// area - (in) array of triangle area types. +// nt - (in) triangle count +// solid - (in) heightfield where the triangles are rasterized void 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 neihbor. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. -/// [Limit: >=0] [Units: vx] -/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +// Marks non-walkable low obstacles as walkable if they are closer than walkableClimb +// from a walkable surface. Applying this filter allows to step over low hanging +// low obstacles. +// Params: +// walkableHeight - (in) minimum height where the agent can still walk +// solid - (in/out) heightfield describing the solid space +// TODO: Missuses ledge flag, must be called before rcFilterLedgeSpans! 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.) +// Removes WALKABLE flag from all spans that are at ledges. This filtering +// removes possible overestimation of the conservative voxelization so that +// the resulting mesh will not have regions hanging in air over ledges. +// Params: +// walkableHeight - (in) minimum height where the agent can still walk +// walkableClimb - (in) maximum height between grid cells the agent can climb +// solid - (in/out) heightfield describing the solid space 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.) +// Removes WALKABLE flag from all spans which have smaller than +// 'walkableHeight' clearance above them. +// Params: +// walkableHeight - (in) minimum height where the agent can still walk +// solid - (in/out) heightfield describing the solid space void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid); -/// Returns the number of spans contained in the specified heightfield. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] hf An initialized heightfield. -/// @returns The number of spans in the heightfield. +// Returns number of spans contained in a heightfield. +// Params: +// hf - (in) heightfield to be compacted +// Returns number of spans. int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf); -/// @} -/// @name Compact Heightfield Functions -/// @see rcCompactHeightfield -/// @{ - -/// Builds a compact heightfield representing open space, from a heightfield representing solid space. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area -/// to be considered walkable. [Limit: >= 3] [Units: vx] -/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. -/// [Limit: >=0] [Units: vx] -/// @param[in] hf The heightfield to be compacted. -/// @param[out] chf The resulting compact heightfield. (Must be pre-allocated.) -/// @returns True if the operation completed successfully. +// Builds compact representation of the heightfield. +// Params: +// walkableHeight - (in) minimum height where the agent can still walk +// walkableClimb - (in) maximum height between grid cells the agent can climb +// flags - (in) require flags for a cell to be included in the compact heightfield. +// hf - (in) heightfield to be compacted +// chf - (out) compact heightfield representing the open space. +// Returns false if operation ran out of memory. bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb, rcHeightfield& hf, rcCompactHeightfield& chf); -/// Erodes the walkable area within the heightfield by the specified radius. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] radius The radius of erosion. [Limits: 0 < value < 255] [Units: vx] -/// @param[in,out] chf The populated compact heightfield to erode. -/// @returns True if the operation completed successfully. +// Erodes walkable area. +// Params: +// radius - (in) radius of erosion (max 255). +// chf - (in/out) compact heightfield to erode. +// Returns false if operation ran out of memory. 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. +// Applies median filter to walkable area types, removing noise. +// Params: +// chf - (in/out) compact heightfield to erode. +// Returns false if operation ran out of memory. 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. +// Marks the area of the convex polygon into the area type of the compact heightfield. +// Params: +// bmin/bmax - (in) bounds of the axis aligned box. +// areaId - (in) area ID to mark. +// chf - (in/out) compact heightfield to mark. 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. +// Marks the area of the convex polygon into the area type of the compact heightfield. +// Params: +// verts - (in) vertices of the convex polygon. +// nverts - (in) number of vertices in the polygon. +// hmin/hmax - (in) min and max height of the polygon. +// areaId - (in) area ID to mark. +// chf - (in/out) compact heightfield to mark. 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[out] outVerts The offset vertices (should hold up to 2 * @p nverts) [Form: (x, y, z) * return value] -/// @param[in] maxOutVerts The max number of vertices that can be stored to @p outVerts. -/// @returns Number of vertices in the offset polygon or 0 if too few vertices in @p outVerts. -int rcOffsetPoly(const float* verts, const int nverts, const float offset, - float* outVerts, const int maxOutVerts); - -/// Applies the area id to all spans within the specified cylinder. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] pos The center of the base of the cylinder. [Form: (x, y, z)] -/// @param[in] r The radius of the cylinder. -/// @param[in] h The height of the cylinder. -/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] -/// @param[in,out] chf A populated compact heightfield. -void rcMarkCylinderArea(rcContext* ctx, const float* pos, - const float r, const float h, 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. +// Builds distance field and stores it into the combat heightfield. +// Params: +// chf - (in/out) compact heightfield representing the open space. +// Returns false if operation ran out of memory. 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. +// Divides the walkable heighfied into simple regions using watershed partitioning. +// Each region has only one contour and no overlaps. +// The regions are stored in the compact heightfield 'reg' field. +// The process sometimes creates small regions. If the area of a regions is +// smaller than 'mergeRegionArea' then the region will be merged with a neighbour +// region if possible. If multiple regions form an area which is smaller than +// 'minRegionArea' all the regions belonging to that area will be removed. +// Here area means the count of spans in an area. +// Params: +// chf - (in/out) compact heightfield representing the open space. +// minRegionArea - (in) the smallest allowed region area. +// maxMergeRegionArea - (in) the largest allowed region area which can be merged. +// Returns false if operation ran out of memory. bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, const int borderSize, const int minRegionArea, const int mergeRegionArea); -/// Builds region data for the heightfield using simple monotone partitioning. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in,out] chf A populated compact heightfield. -/// @param[in] borderSize The size of the non-navigable border around the heightfield. -/// [Limit: >=0] [Units: vx] -/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. -/// [Limit: >=0] [Units: vx]. -/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible, -/// be merged with larger regions. [Limit: >=0] [Units: vx] -/// @returns True if the operation completed successfully. +// Divides the walkable heighfied into simple regions using simple monotone partitioning. +// Each region has only one contour and no overlaps. +// The regions are stored in the compact heightfield 'reg' field. +// The process sometimes creates small regions. If the area of a regions is +// smaller than 'mergeRegionArea' then the region will be merged with a neighbour +// region if possible. If multiple regions form an area which is smaller than +// 'minRegionArea' all the regions belonging to that area will be removed. +// Here area means the count of spans in an area. +// Params: +// chf - (in/out) compact heightfield representing the open space. +// minRegionArea - (in) the smallest allowed regions size. +// maxMergeRegionArea - (in) the largest allowed regions size which can be merged. +// Returns false if operation ran out of memory. bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, const int borderSize, const int minRegionArea, const int mergeRegionArea); - -/// Sets the neighbor connection data for the specified direction. -/// @param[in] s The span to update. -/// @param[in] dir The direction to set. [Limits: 0 <= value < 4] -/// @param[in] i The index of the neighbor span. -inline void rcSetCon(rcCompactSpan& s, int dir, int i) -{ - const unsigned int shift = (unsigned int)dir*6; - unsigned int con = s.con; - s.con = (con & ~(0x3f << shift)) | (((unsigned int)i & 0x3f) << shift); -} - -/// Gets neighbor connection data for the specified direction. -/// @param[in] s The span to check. -/// @param[in] dir The direction to check. [Limits: 0 <= value < 4] -/// @return The neighbor connection data for the specified direction, -/// or #RC_NOT_CONNECTED if there is no connection. -inline int rcGetCon(const rcCompactSpan& s, int dir) -{ - const unsigned int shift = (unsigned int)dir*6; - return (s.con >> shift) & 0x3f; -} - -/// Gets the standard width (x-axis) offset for the specified direction. -/// @param[in] dir The direction. [Limits: 0 <= value < 4] -/// @return The width offset to apply to the current cell position to move -/// in the direction. -inline int rcGetDirOffsetX(int dir) -{ - const int offset[4] = { -1, 0, 1, 0, }; - return offset[dir&0x03]; -} - -/// Gets the standard height (z-axis) offset for the specified direction. -/// @param[in] dir The direction. [Limits: 0 <= value < 4] -/// @return The height offset to apply to the current cell position to move -/// in the direction. -inline int rcGetDirOffsetY(int dir) -{ - const int offset[4] = { 0, 1, 0, -1 }; - return offset[dir&0x03]; -} - -/// @} -/// @name Layer, Contour, Polymesh, and Detail Mesh Functions -/// @see rcHeightfieldLayer, rcContourSet, rcPolyMesh, rcPolyMeshDetail -/// @{ - -/// Builds a layer set from the specified compact heightfield. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] chf A fully built compact heightfield. -/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0] -/// [Units: vx] -/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area -/// to be considered walkable. [Limit: >= 3] [Units: vx] -/// @param[out] lset The resulting layer set. (Must be pre-allocated.) -/// @returns True if the operation completed successfully. -bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, - const int borderSize, const int walkableHeight, - rcHeightfieldLayerSet& lset); - -/// Builds a contour set from the region outlines in the provided compact heightfield. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] chf A fully built compact heightfield. -/// @param[in] maxError The maximum distance a simplfied contour's border edges should deviate -/// the original raw contour. [Limit: >=0] [Units: wu] -/// @param[in] maxEdgeLen The maximum allowed length for contour edges along the border of the mesh. -/// [Limit: >=0] [Units: vx] -/// @param[out] cset The resulting contour set. (Must be pre-allocated.) -/// @param[in] buildFlags The build flags. (See: #rcBuildContoursFlags) -/// @returns True if the operation completed successfully. +// Builds simplified contours from the regions outlines. +// Params: +// chf - (in) compact heightfield which has regions set. +// maxError - (in) maximum allowed distance between simplified contour and cells. +// maxEdgeLen - (in) maximum allowed contour edge length in cells. +// cset - (out) Resulting contour set. +// flags - (in) build flags, see rcBuildContoursFlags. +// Returns false if operation ran out of memory. bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, const float maxError, const int maxEdgeLen, rcContourSet& cset, const int flags = RC_CONTOUR_TESS_WALL_EDGES); -/// Builds a polygon mesh from the provided contours. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] cset A fully built contour set. -/// @param[in] nvp The maximum number of vertices allowed for polygons generated during the -/// contour to polygon conversion process. [Limit: >= 3] -/// @param[out] mesh The resulting polygon mesh. (Must be re-allocated.) -/// @returns True if the operation completed successfully. -bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh); - -/// Merges multiple polygon meshes into a single mesh. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] meshes An array of polygon meshes to merge. [Size: @p nmeshes] -/// @param[in] nmeshes The number of polygon meshes in the meshes array. -/// @param[in] mesh The resulting polygon mesh. (Must be pre-allocated.) -/// @returns True if the operation completed successfully. +// Builds connected convex polygon mesh from contour polygons. +// Params: +// cset - (in) contour set. +// nvp - (in) maximum number of vertices per polygon. +// mesh - (out) poly mesh. +// Returns false if operation ran out of memory. +bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& mesh); + 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. +// Builds detail triangle mesh for each polygon in the poly mesh. +// Params: +// mesh - (in) poly mesh to detail. +// chf - (in) compact height field, used to query height for new vertices. +// sampleDist - (in) spacing between height samples used to generate more detail into mesh. +// sampleMaxError - (in) maximum allowed distance between simplified detail mesh and height sample. +// pmdtl - (out) detail mesh. +// Returns false if operation ran out of memory. bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf, const float sampleDist, const float sampleMaxError, rcPolyMeshDetail& dmesh); -/// Copies the poly mesh data from src to dst. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] src The source mesh to copy from. -/// @param[out] dst The resulting detail mesh. (Must be pre-allocated, must be empty mesh.) -/// @returns True if the operation completed successfully. -bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst); - -/// Merges multiple detail meshes into a single detail mesh. -/// @ingroup recast -/// @param[in,out] ctx The build context to use during the operation. -/// @param[in] meshes An array of detail meshes to merge. [Size: @p nmeshes] -/// @param[in] nmeshes The number of detail meshes in the meshes array. -/// @param[out] mesh The resulting detail mesh. (Must be pre-allocated.) -/// @returns True if the operation completed successfully. bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh); -/// @} #endif // RECAST_H - -/////////////////////////////////////////////////////////////////////////// - -// Due to the large amount of detail documentation for this file, -// the content normally located at the end of the header file has been separated -// out to a file in /Docs/Extern. diff --git a/dep/recastnavigation/Recast/RecastAlloc.cpp b/dep/recastnavigation/Recast/RecastAlloc.cpp index b5ec151..2c7396a 100644 --- a/dep/recastnavigation/Recast/RecastAlloc.cpp +++ b/dep/recastnavigation/Recast/RecastAlloc.cpp @@ -33,45 +33,24 @@ static void rcFreeDefault(void *ptr) static rcAllocFunc* sRecastAllocFunc = rcAllocDefault; static rcFreeFunc* sRecastFreeFunc = rcFreeDefault; -/// @see rcAlloc, rcFree void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc) { sRecastAllocFunc = allocFunc ? allocFunc : rcAllocDefault; sRecastFreeFunc = freeFunc ? freeFunc : rcFreeDefault; } -/// @see rcAllocSetCustom void* rcAlloc(int 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) sRecastFreeFunc(ptr); } -/// @class rcIntArray -/// -/// While it is possible to pre-allocate a specific array size during -/// construction or by using the #resize method, certain methods will -/// automatically resize the array as needed. -/// -/// @warning The array memory is not initialized to zero when the size is -/// manually set during construction or when using #resize. -/// @par -/// -/// Using this method ensures the array is at least large enough to hold -/// the specified number of elements. This can improve performance by -/// avoiding auto-resizing during use. void rcIntArray::resize(int n) { if (n > m_cap) diff --git a/dep/recastnavigation/Recast/RecastAlloc.h b/dep/recastnavigation/Recast/RecastAlloc.h index 438be9e..9a31637 100644 --- a/dep/recastnavigation/Recast/RecastAlloc.h +++ b/dep/recastnavigation/Recast/RecastAlloc.h @@ -19,45 +19,23 @@ #ifndef RECASTALLOC_H #define RECASTALLOC_H -/// Provides hint values to the memory allocator on how long the -/// memory is expected to be used. enum rcAllocHint { - RC_ALLOC_PERM, ///< Memory will persist after a function call. - RC_ALLOC_TEMP ///< Memory used temporarily within a function. + RC_ALLOC_PERM, // Memory persist after a function call. + RC_ALLOC_TEMP // Memory used temporarily within a function. }; -/// A memory allocation function. -// @param[in] size The size, in bytes of memory, to allocate. -// @param[in] rcAllocHint 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 rcAllocSetCustom typedef void* (rcAllocFunc)(int size, rcAllocHint hint); - -/// A memory deallocation function. -/// @param[in] ptr A pointer to a memory block previously allocated using #rcAllocFunc. -/// @see rcAllocSetCustom 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 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 void* rcAlloc(int size, rcAllocHint hint); - -/// Deallocates a memory block. -/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc. -/// @see rcAlloc void rcFree(void* ptr); -/// A simple dynamic array of integers. + +// Simple dynamic array ints. class rcIntArray { int* m_data; @@ -65,59 +43,26 @@ class rcIntArray inline rcIntArray(const rcIntArray&); inline rcIntArray& operator=(const rcIntArray&); public: - - /// Constructs an instance with an initial array size of zero. inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {} - - /// Constructs an instance initialized to the specified size. - /// @param[in] n The initial size of the integer array. inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); } inline ~rcIntArray() { rcFree(m_data); } - - /// Specifies the new size of the integer array. - /// @param[in] n The new size of the integer array. void resize(int n); - - /// Push the specified integer onto the end of the array and increases the size by one. - /// @param[in] item The new value. inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; } - - /// Returns the value at the end of the array and reduces the size by one. - /// @return The value at the end of the array. inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; } - - /// The value at the specified array index. - /// @warning Does not provide overflow protection. - /// @param[in] i The index of the value. inline const int& operator[](int i) const { return m_data[i]; } - - /// The value at the specified array index. - /// @warning Does not provide overflow protection. - /// @param[in] i The index of the value. inline int& operator[](int i) { return m_data[i]; } - - /// The current size of the integer array. inline int size() const { return m_size; } }; -/// A simple helper class used to delete an array when it goes out of scope. -/// @note This class is rarely if ever used by the end user. +// Simple internal helper class to delete array in scope template class rcScopedDelete { T* ptr; inline T* operator=(T* p); public: - - /// Constructs an instance with a null pointer. inline rcScopedDelete() : ptr(0) {} - - /// Constructs an instance with the specified pointer. - /// @param[in] p An pointer to an allocated array. inline rcScopedDelete(T* p) : ptr(p) {} inline ~rcScopedDelete() { rcFree(ptr); } - - /// The root array pointer. - /// @return The root array pointer. inline operator T*() { return ptr; } }; diff --git a/dep/recastnavigation/Recast/RecastArea.cpp b/dep/recastnavigation/Recast/RecastArea.cpp index 1a338cd..e89caee 100644 --- a/dep/recastnavigation/Recast/RecastArea.cpp +++ b/dep/recastnavigation/Recast/RecastArea.cpp @@ -26,14 +26,7 @@ #include "RecastAlloc.h" #include "RecastAssert.h" -/// @par -/// -/// Basically, any spans that are closer to a boundary or obstruction than the specified radius -/// are marked as unwalkable. -/// -/// This method is usually called immediately after the heightfield has been built. -/// -/// @see rcCompactHeightfield, rcBuildCompactHeightfield, rcConfig::walkableRadius + bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf) { rcAssert(ctx); @@ -61,26 +54,14 @@ bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf) const rcCompactCell& c = chf.cells[x+y*w]; for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { - if (chf.areas[i] == RC_NULL_AREA) - { - dist[i] = 0; - } - else + if (chf.areas[i] != RC_NULL_AREA) { const rcCompactSpan& s = chf.spans[i]; int nc = 0; for (int dir = 0; dir < 4; ++dir) { if (rcGetCon(s, dir) != RC_NOT_CONNECTED) - { - const int nx = x + rcGetDirOffsetX(dir); - const int ny = y + rcGetDirOffsetY(dir); - const int nidx = (int)chf.cells[nx+ny*w].index + rcGetCon(s, dir); - if (chf.areas[nidx] != RC_NULL_AREA) - { - nc++; - } - } + nc++; } // At least one missing neighbour. if (nc != 4) @@ -232,12 +213,7 @@ static void insertSort(unsigned char* a, const int n) } } -/// @par -/// -/// This filter is usually applied after applying area id's using functions -/// such as #rcMarkBoxArea, #rcMarkConvexPolyArea, and #rcMarkCylinderArea. -/// -/// @see rcCompactHeightfield + bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf) { rcAssert(ctx); @@ -312,11 +288,6 @@ bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf) return true; } -/// @par -/// -/// The value of spacial parameters are in world units. -/// -/// @see rcCompactHeightfield, rcMedianFilterWalkableArea void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId, rcCompactHeightfield& chf) { @@ -351,8 +322,7 @@ void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigne rcCompactSpan& s = chf.spans[i]; if ((int)s.y >= miny && (int)s.y <= maxy) { - if (chf.areas[i] != RC_NULL_AREA) - chf.areas[i] = areaId; + chf.areas[i] = areaId; } } } @@ -377,14 +347,6 @@ static int pointInPoly(int nvert, const float* verts, const float* p) return c; } -/// @par -/// -/// The value of spacial parameters are in world units. -/// -/// The y-values of the polygon vertices are ignored. So the polygon is effectively -/// projected onto the xz-plane at @p hmin, then extruded to @p hmax. -/// -/// @see rcCompactHeightfield, rcMedianFilterWalkableArea void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, const float hmin, const float hmax, unsigned char areaId, rcCompactHeightfield& chf) @@ -431,8 +393,6 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { rcCompactSpan& s = chf.spans[i]; - if (chf.areas[i] == RC_NULL_AREA) - continue; if ((int)s.y >= miny && (int)s.y <= maxy) { float p[3]; @@ -451,152 +411,3 @@ void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, ctx->stopTimer(RC_TIMER_MARK_CONVEXPOLY_AREA); } - -int rcOffsetPoly(const float* verts, const int nverts, const float offset, - float* outVerts, const int maxOutVerts) -{ - const float MITER_LIMIT = 1.20f; - - int n = 0; - - for (int i = 0; i < nverts; i++) - { - const int a = (i+nverts-1) % nverts; - const int b = i; - const int c = (i+1) % nverts; - const float* va = &verts[a*3]; - const float* vb = &verts[b*3]; - const float* vc = &verts[c*3]; - float dx0 = vb[0] - va[0]; - float dy0 = vb[2] - va[2]; - float d0 = dx0*dx0 + dy0*dy0; - if (d0 > 1e-6f) - { - d0 = 1.0f/rcSqrt(d0); - dx0 *= d0; - dy0 *= d0; - } - float dx1 = vc[0] - vb[0]; - float dy1 = vc[2] - vb[2]; - float d1 = dx1*dx1 + dy1*dy1; - if (d1 > 1e-6f) - { - d1 = 1.0f/rcSqrt(d1); - dx1 *= d1; - dy1 *= d1; - } - const float dlx0 = -dy0; - const float dly0 = dx0; - const float dlx1 = -dy1; - const float dly1 = dx1; - float cross = dx1*dy0 - dx0*dy1; - float dmx = (dlx0 + dlx1) * 0.5f; - float dmy = (dly0 + dly1) * 0.5f; - float dmr2 = dmx*dmx + dmy*dmy; - bool bevel = dmr2 * MITER_LIMIT*MITER_LIMIT < 1.0f; - if (dmr2 > 1e-6f) - { - const float scale = 1.0f / dmr2; - dmx *= scale; - dmy *= scale; - } - - if (bevel && cross < 0.0f) - { - if (n+2 >= maxOutVerts) - return 0; - float d = (1.0f - (dx0*dx1 + dy0*dy1))*0.5f; - outVerts[n*3+0] = vb[0] + (-dlx0+dx0*d)*offset; - outVerts[n*3+1] = vb[1]; - outVerts[n*3+2] = vb[2] + (-dly0+dy0*d)*offset; - n++; - outVerts[n*3+0] = vb[0] + (-dlx1-dx1*d)*offset; - outVerts[n*3+1] = vb[1]; - outVerts[n*3+2] = vb[2] + (-dly1-dy1*d)*offset; - n++; - } - else - { - if (n+1 >= maxOutVerts) - return 0; - outVerts[n*3+0] = vb[0] - dmx*offset; - outVerts[n*3+1] = vb[1]; - outVerts[n*3+2] = vb[2] - dmy*offset; - n++; - } - } - - return n; -} - - -/// @par -/// -/// The value of spacial parameters are in world units. -/// -/// @see rcCompactHeightfield, rcMedianFilterWalkableArea -void rcMarkCylinderArea(rcContext* ctx, const float* pos, - const float r, const float h, unsigned char areaId, - rcCompactHeightfield& chf) -{ - rcAssert(ctx); - - ctx->startTimer(RC_TIMER_MARK_CYLINDER_AREA); - - float bmin[3], bmax[3]; - bmin[0] = pos[0] - r; - bmin[1] = pos[1]; - bmin[2] = pos[2] - r; - bmax[0] = pos[0] + r; - bmax[1] = pos[1] + h; - bmax[2] = pos[2] + r; - const float r2 = r*r; - - int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs); - int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch); - int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs); - int maxx = (int)((bmax[0]-chf.bmin[0])/chf.cs); - int maxy = (int)((bmax[1]-chf.bmin[1])/chf.ch); - int maxz = (int)((bmax[2]-chf.bmin[2])/chf.cs); - - if (maxx < 0) return; - if (minx >= chf.width) return; - if (maxz < 0) return; - if (minz >= chf.height) return; - - if (minx < 0) minx = 0; - if (maxx >= chf.width) maxx = chf.width-1; - if (minz < 0) minz = 0; - if (maxz >= chf.height) maxz = chf.height-1; - - - for (int z = minz; z <= maxz; ++z) - { - for (int x = minx; x <= maxx; ++x) - { - const rcCompactCell& c = chf.cells[x+z*chf.width]; - for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) - { - rcCompactSpan& s = chf.spans[i]; - - if (chf.areas[i] == RC_NULL_AREA) - continue; - - if ((int)s.y >= miny && (int)s.y <= maxy) - { - const float sx = chf.bmin[0] + (x+0.5f)*chf.cs; - const float sz = chf.bmin[2] + (z+0.5f)*chf.cs; - const float dx = sx - pos[0]; - const float dz = sz - pos[2]; - - if (dx*dx + dz*dz < r2) - { - chf.areas[i] = areaId; - } - } - } - } - } - - ctx->stopTimer(RC_TIMER_MARK_CYLINDER_AREA); -} diff --git a/dep/recastnavigation/Recast/RecastAssert.h b/dep/recastnavigation/Recast/RecastAssert.h index 2aca0d9..b58b8fc 100644 --- a/dep/recastnavigation/Recast/RecastAssert.h +++ b/dep/recastnavigation/Recast/RecastAssert.h @@ -24,7 +24,7 @@ #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) +# define rcAssert(x) do { (void)sizeof(x); } while(__LINE__==-1,false) #else # include # define rcAssert assert diff --git a/dep/recastnavigation/Recast/RecastContour.cpp b/dep/recastnavigation/Recast/RecastContour.cpp index 5c324bc..1906b6e 100644 --- a/dep/recastnavigation/Recast/RecastContour.cpp +++ b/dep/recastnavigation/Recast/RecastContour.cpp @@ -340,7 +340,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, endi = ai; } - // Tessellate only outer edges or edges between areas. + // Tessellate only outer edges oredges between areas. if ((points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0 || (points[ci*4+3] & RC_AREA_BORDER)) { @@ -420,13 +420,15 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, // Round based on the segments in lexilogical order so that the // max tesselation is consistent regardles in which direction // segments are traversed. - const int n = bi < ai ? (bi+pn - ai) : (bi - ai); - if (n > 1) + if (bx > ax || (bx == ax && bz > az)) { - if (bx > ax || (bx == ax && bz > az)) - maxi = (ai + n/2) % pn; - else - maxi = (ai + (n+1)/2) % pn; + const int n = bi < ai ? (bi+pn - ai) : (bi - ai); + maxi = (ai + n/2) % pn; + } + else + { + const int n = bi < ai ? (bi+pn - ai) : (bi - ai); + maxi = (ai + (n+1)/2) % pn; } } } @@ -464,7 +466,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, // and the neighbour region is take from the next raw point. const int ai = (simplified[i*4+3]+1) % pn; const int bi = simplified[i*4+3]; - simplified[i*4+3] = (points[ai*4+3] & (RC_CONTOUR_REG_MASK|RC_AREA_BORDER)) | (points[bi*4+3] & RC_BORDER_VERTEX); + simplified[i*4+3] = (points[ai*4+3] & RC_CONTOUR_REG_MASK) | (points[bi*4+3] & RC_BORDER_VERTEX); } } @@ -590,19 +592,6 @@ static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib) return true; } -/// @par -/// -/// The raw contours will match the region outlines exactly. The @p maxError and @p maxEdgeLen -/// parameters control how closely the simplified contours will match the raw contours. -/// -/// Simplified contours are generated such that the vertices for portals between areas match up. -/// (They are considered mandatory vertices.) -/// -/// Setting @p maxEdgeLength to zero will disabled the edge length feature. -/// -/// See the #rcConfig documentation for more information on the configuration parameters. -/// -/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, const float maxError, const int maxEdgeLen, rcContourSet& cset, const int buildFlags) @@ -611,26 +600,13 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, const int w = chf.width; const int h = chf.height; - const int borderSize = chf.borderSize; ctx->startTimer(RC_TIMER_BUILD_CONTOURS); rcVcopy(cset.bmin, chf.bmin); rcVcopy(cset.bmax, chf.bmax); - if (borderSize > 0) - { - // If the heightfield was build with bordersize, remove the offset. - const float pad = borderSize*chf.cs; - cset.bmin[0] += pad; - cset.bmin[2] += pad; - cset.bmax[0] -= pad; - cset.bmax[2] -= pad; - } cset.cs = chf.cs; cset.ch = chf.ch; - cset.width = chf.width - chf.borderSize*2; - cset.height = chf.height - chf.borderSize*2; - cset.borderSize = chf.borderSize; int maxContours = rcMax((int)chf.maxRegions, 8); cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM); @@ -682,6 +658,8 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE); + ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY); + rcIntArray verts(256); rcIntArray simplified(64); @@ -704,17 +682,10 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, verts.resize(0); simplified.resize(0); - - ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE); walkContour(x, y, i, chf, flags, verts); - ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE); - - ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY); simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags); removeDegenerateSegments(simplified); - ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY); - // Store region->contour remap info. // Create contour. if (simplified.size()/4 >= 3) @@ -749,16 +720,6 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, return false; } memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4); - if (borderSize > 0) - { - // If the heightfield was build with bordersize, remove the offset. - for (int j = 0; j < cont->nverts; ++j) - { - int* v = &cont->verts[j*4]; - v[0] -= borderSize; - v[2] -= borderSize; - } - } cont->nrverts = verts.size()/4; cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM); @@ -768,16 +729,6 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, return false; } memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4); - if (borderSize > 0) - { - // If the heightfield was build with bordersize, remove the offset. - for (int j = 0; j < cont->nrverts; ++j) - { - int* v = &cont->rverts[j*4]; - v[0] -= borderSize; - v[2] -= borderSize; - } - } /* cont->cx = cont->cy = cont->cz = 0; for (int i = 0; i < cont->nverts; ++i) @@ -845,6 +796,8 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, } } + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY); + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS); return true; diff --git a/dep/recastnavigation/Recast/RecastFilter.cpp b/dep/recastnavigation/Recast/RecastFilter.cpp index bf985c3..d01808a 100644 --- a/dep/recastnavigation/Recast/RecastFilter.cpp +++ b/dep/recastnavigation/Recast/RecastFilter.cpp @@ -22,17 +22,7 @@ #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: rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb -/// -/// @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) { rcAssert(ctx); @@ -48,7 +38,6 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb { rcSpan* ps = 0; bool previousWalkable = false; - unsigned char previousArea = RC_NULL_AREA; for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next) { @@ -58,29 +47,18 @@ void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb if (!walkable && previousWalkable) { if (rcAbs((int)s->smax - (int)ps->smax) <= walkableClimb) - s->area = previousArea; + s->area = RC_NULL_AREA; } // Copy walkable flag so that it cannot propagate // past multiple non-walkable objects. previousWalkable = walkable; - previousArea = s->area; } } } ctx->stopTimer(RC_TIMER_FILTER_LOW_OBSTACLES); } - -/// @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: rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb -/// -/// @see rcHeightfield, rcConfig + void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walkableClimb, rcHeightfield& solid) { @@ -171,12 +149,6 @@ void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walk ctx->stopTimer(RC_TIMER_FILTER_BORDER); } -/// @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) { rcAssert(ctx); diff --git a/dep/recastnavigation/Recast/RecastLayers.cpp b/dep/recastnavigation/Recast/RecastLayers.cpp deleted file mode 100644 index 5ea6cb7..0000000 --- a/dep/recastnavigation/Recast/RecastLayers.cpp +++ /dev/null @@ -1,620 +0,0 @@ -// -// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. -// - -#include -#define _USE_MATH_DEFINES -#include -#include -#include -#include -#include "Recast.h" -#include "RecastAlloc.h" -#include "RecastAssert.h" - - -static const int RC_MAX_LAYERS = RC_NOT_CONNECTED; -static const int RC_MAX_NEIS = 16; - -struct rcLayerRegion -{ - unsigned char layers[RC_MAX_LAYERS]; - unsigned char neis[RC_MAX_NEIS]; - unsigned short ymin, ymax; - unsigned char layerId; // Layer ID - unsigned char nlayers; // Layer count - unsigned char nneis; // Neighbour count - unsigned char base; // Flag indicating if the region is hte base of merged regions. -}; - - -static void addUnique(unsigned char* a, unsigned char& an, unsigned char v) -{ - const int n = (int)an; - for (int i = 0; i < n; ++i) - if (a[i] == v) - return; - a[an] = v; - an++; -} - -static bool contains(const unsigned char* a, const unsigned char an, const unsigned char v) -{ - const int n = (int)an; - for (int i = 0; i < n; ++i) - if (a[i] == v) - return true; - return false; -} - -inline bool overlapRange(const unsigned short amin, const unsigned short amax, - const unsigned short bmin, const unsigned short bmax) -{ - return (amin > bmax || amax < bmin) ? false : true; -} - - - -struct rcLayerSweepSpan -{ - unsigned short ns; // number samples - unsigned char id; // region id - unsigned char nei; // neighbour id -}; - -/// @par -/// -/// See the #rcConfig documentation for more information on the configuration parameters. -/// -/// @see rcAllocHeightfieldLayerSet, rcCompactHeightfield, rcHeightfieldLayerSet, rcConfig -bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, - const int borderSize, const int walkableHeight, - rcHeightfieldLayerSet& lset) -{ - rcAssert(ctx); - - ctx->startTimer(RC_TIMER_BUILD_LAYERS); - - const int w = chf.width; - const int h = chf.height; - - rcScopedDelete srcReg = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); - if (!srcReg) - { - ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'srcReg' (%d).", chf.spanCount); - return false; - } - memset(srcReg,0xff,sizeof(unsigned char)*chf.spanCount); - - const int nsweeps = chf.width; - rcScopedDelete sweeps = (rcLayerSweepSpan*)rcAlloc(sizeof(rcLayerSweepSpan)*nsweeps, RC_ALLOC_TEMP); - if (!sweeps) - { - ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'sweeps' (%d).", nsweeps); - return false; - } - - - // Partition walkable area into monotone regions. - int prevCount[256]; - unsigned char regId = 0; - - for (int y = borderSize; y < h-borderSize; ++y) - { - memset(prevCount,0,sizeof(int)*regId); - unsigned char sweepId = 0; - - for (int x = borderSize; x < w-borderSize; ++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 rcCompactSpan& s = chf.spans[i]; - if (chf.areas[i] == RC_NULL_AREA) continue; - - unsigned char sid = 0xff; - - // -x - if (rcGetCon(s, 0) != RC_NOT_CONNECTED) - { - const int ax = x + rcGetDirOffsetX(0); - const int ay = y + rcGetDirOffsetY(0); - const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0); - if (chf.areas[ai] != RC_NULL_AREA && srcReg[ai] != 0xff) - sid = srcReg[ai]; - } - - if (sid == 0xff) - { - sid = sweepId++; - sweeps[sid].nei = 0xff; - sweeps[sid].ns = 0; - } - - // -y - if (rcGetCon(s,3) != RC_NOT_CONNECTED) - { - const int ax = x + rcGetDirOffsetX(3); - const int ay = y + rcGetDirOffsetY(3); - const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3); - const unsigned char nr = srcReg[ai]; - if (nr != 0xff) - { - // Set neighbour when first valid neighbour is encoutered. - if (sweeps[sid].ns == 0) - sweeps[sid].nei = nr; - - if (sweeps[sid].nei == nr) - { - // Update existing neighbour - sweeps[sid].ns++; - prevCount[nr]++; - } - else - { - // This is hit if there is nore than one neighbour. - // Invalidate the neighbour. - sweeps[sid].nei = 0xff; - } - } - } - - srcReg[i] = sid; - } - } - - // Create unique ID. - for (int i = 0; i < sweepId; ++i) - { - // If the neighbour is set and there is only one continuous connection to it, - // the sweep will be merged with the previous one, else new region is created. - if (sweeps[i].nei != 0xff && prevCount[sweeps[i].nei] == (int)sweeps[i].ns) - { - sweeps[i].id = sweeps[i].nei; - } - else - { - if (regId == 255) - { - ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Region ID overflow."); - return false; - } - sweeps[i].id = regId++; - } - } - - // Remap local sweep ids to region ids. - for (int x = borderSize; x < w-borderSize; ++x) - { - const rcCompactCell& c = chf.cells[x+y*w]; - for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) - { - if (srcReg[i] != 0xff) - srcReg[i] = sweeps[srcReg[i]].id; - } - } - } - - // Allocate and init layer regions. - const int nregs = (int)regId; - rcScopedDelete regs = (rcLayerRegion*)rcAlloc(sizeof(rcLayerRegion)*nregs, RC_ALLOC_TEMP); - if (!regs) - { - ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'regs' (%d).", nregs); - return false; - } - memset(regs, 0, sizeof(rcLayerRegion)*nregs); - for (int i = 0; i < nregs; ++i) - { - regs[i].layerId = 0xff; - regs[i].ymin = 0xffff; - regs[i].ymax = 0; - } - - // Find region neighbours and overlapping regions. - for (int y = 0; y < h; ++y) - { - for (int x = 0; x < w; ++x) - { - const rcCompactCell& c = chf.cells[x+y*w]; - - unsigned char lregs[RC_MAX_LAYERS]; - int nlregs = 0; - - for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) - { - const rcCompactSpan& s = chf.spans[i]; - const unsigned char ri = srcReg[i]; - if (ri == 0xff) continue; - - regs[ri].ymin = rcMin(regs[ri].ymin, s.y); - regs[ri].ymax = rcMax(regs[ri].ymax, s.y); - - // Collect all region layers. - if (nlregs < RC_MAX_LAYERS) - lregs[nlregs++] = ri; - - // Update neighbours - for (int dir = 0; dir < 4; ++dir) - { - if (rcGetCon(s, dir) != RC_NOT_CONNECTED) - { - const int ax = x + rcGetDirOffsetX(dir); - const int ay = y + rcGetDirOffsetY(dir); - const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); - const unsigned char rai = srcReg[ai]; - if (rai != 0xff && rai != ri) - addUnique(regs[ri].neis, regs[ri].nneis, rai); - } - } - - } - - // Update overlapping regions. - for (int i = 0; i < nlregs-1; ++i) - { - for (int j = i+1; j < nlregs; ++j) - { - if (lregs[i] != lregs[j]) - { - rcLayerRegion& ri = regs[lregs[i]]; - rcLayerRegion& rj = regs[lregs[j]]; - addUnique(ri.layers, ri.nlayers, lregs[j]); - addUnique(rj.layers, rj.nlayers, lregs[i]); - } - } - } - - } - } - - // Create 2D layers from regions. - unsigned char layerId = 0; - - static const int MAX_STACK = 64; - unsigned char stack[MAX_STACK]; - int nstack = 0; - - for (int i = 0; i < nregs; ++i) - { - rcLayerRegion& root = regs[i]; - // Skip alreadu visited. - if (root.layerId != 0xff) - continue; - - // Start search. - root.layerId = layerId; - root.base = 1; - - nstack = 0; - stack[nstack++] = (unsigned char)i; - - while (nstack) - { - // Pop front - rcLayerRegion& reg = regs[stack[0]]; - nstack--; - for (int j = 0; j < nstack; ++j) - stack[j] = stack[j+1]; - - const int nneis = (int)reg.nneis; - for (int j = 0; j < nneis; ++j) - { - const unsigned char nei = reg.neis[j]; - rcLayerRegion& regn = regs[nei]; - // Skip already visited. - if (regn.layerId != 0xff) - continue; - // Skip if the neighbour is overlapping root region. - if (contains(root.layers, root.nlayers, nei)) - continue; - // Skip if the height range would become too large. - const int ymin = rcMin(root.ymin, regn.ymin); - const int ymax = rcMax(root.ymax, regn.ymax); // Edited by TC - if ((ymax - ymin) >= 255) - continue; - - if (nstack < MAX_STACK) - { - // Deepen - stack[nstack++] = (unsigned char)nei; - - // Mark layer id - regn.layerId = layerId; - // Merge current layers to root. - for (int k = 0; k < regn.nlayers; ++k) - addUnique(root.layers, root.nlayers, regn.layers[k]); - root.ymin = rcMin(root.ymin, regn.ymin); - root.ymax = rcMax(root.ymax, regn.ymax); - } - } - } - - layerId++; - } - - // Merge non-overlapping regions that are close in height. - const unsigned short mergeHeight = (unsigned short)walkableHeight * 4; - - for (int i = 0; i < nregs; ++i) - { - rcLayerRegion& ri = regs[i]; - if (!ri.base) continue; - - unsigned char newId = ri.layerId; - - for (;;) - { - unsigned char oldId = 0xff; - - for (int j = 0; j < nregs; ++j) - { - if (i == j) continue; - rcLayerRegion& rj = regs[j]; - if (!rj.base) continue; - - // Skip if teh regions are not close to each other. - if (!overlapRange(ri.ymin,ri.ymax+mergeHeight, rj.ymin,rj.ymax+mergeHeight)) - continue; - // Skip if the height range would become too large. - const int ymin = rcMin(ri.ymin, rj.ymin); - const int ymax = rcMax(ri.ymax, rj.ymax); // Edited by TC - if ((ymax - ymin) >= 255) - continue; - - // Make sure that there is no overlap when mergin 'ri' and 'rj'. - bool overlap = false; - // Iterate over all regions which have the same layerId as 'rj' - for (int k = 0; k < nregs; ++k) - { - if (regs[k].layerId != rj.layerId) - continue; - // Check if region 'k' is overlapping region 'ri' - // Index to 'regs' is the same as region id. - if (contains(ri.layers,ri.nlayers, (unsigned char)k)) - { - overlap = true; - break; - } - } - // Cannot merge of regions overlap. - if (overlap) - continue; - - // Can merge i and j. - oldId = rj.layerId; - break; - } - - // Could not find anything to merge with, stop. - if (oldId == 0xff) - break; - - // Merge - for (int j = 0; j < nregs; ++j) - { - rcLayerRegion& rj = regs[j]; - if (rj.layerId == oldId) - { - rj.base = 0; - // Remap layerIds. - rj.layerId = newId; - // Add overlaid layers from 'rj' to 'ri'. - for (int k = 0; k < rj.nlayers; ++k) - addUnique(ri.layers, ri.nlayers, rj.layers[k]); - // Update heigh bounds. - ri.ymin = rcMin(ri.ymin, rj.ymin); - ri.ymax = rcMax(ri.ymax, rj.ymax); - } - } - } - } - - // Compact layerIds - unsigned char remap[256]; - memset(remap, 0, 256); - - // Find number of unique layers. - layerId = 0; - for (int i = 0; i < nregs; ++i) - remap[regs[i].layerId] = 1; - for (int i = 0; i < 256; ++i) - { - if (remap[i]) - remap[i] = layerId++; - else - remap[i] = 0xff; - } - // Remap ids. - for (int i = 0; i < nregs; ++i) - regs[i].layerId = remap[regs[i].layerId]; - - // No layers, return empty. - if (layerId == 0) - { - ctx->stopTimer(RC_TIMER_BUILD_LAYERS); - return true; - } - - // Create layers. - rcAssert(lset.layers == 0); - - const int lw = w - borderSize*2; - const int lh = h - borderSize*2; - - // Build contracted bbox for layers. - float bmin[3], bmax[3]; - rcVcopy(bmin, chf.bmin); - rcVcopy(bmax, chf.bmax); - bmin[0] += borderSize*chf.cs; - bmin[2] += borderSize*chf.cs; - bmax[0] -= borderSize*chf.cs; - bmax[2] -= borderSize*chf.cs; - - lset.nlayers = (int)layerId; - - lset.layers = (rcHeightfieldLayer*)rcAlloc(sizeof(rcHeightfieldLayer)*lset.nlayers, RC_ALLOC_PERM); - if (!lset.layers) - { - ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'layers' (%d).", lset.nlayers); - return false; - } - memset(lset.layers, 0, sizeof(rcHeightfieldLayer)*lset.nlayers); - - - // Store layers. - for (int i = 0; i < lset.nlayers; ++i) - { - unsigned char curId = (unsigned char)i; - - // Allocate memory for the current layer. - rcHeightfieldLayer* layer = &lset.layers[i]; - memset(layer, 0, sizeof(rcHeightfieldLayer)); - - const int gridSize = sizeof(unsigned char)*lw*lh; - - layer->heights = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); - if (!layer->heights) - { - ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'heights' (%d).", gridSize); - return false; - } - memset(layer->heights, 0xff, gridSize); - - layer->areas = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); - if (!layer->areas) - { - ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'areas' (%d).", gridSize); - return false; - } - memset(layer->areas, 0, gridSize); - - layer->cons = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); - if (!layer->cons) - { - ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'cons' (%d).", gridSize); - return false; - } - memset(layer->cons, 0, gridSize); - - // Find layer height bounds. - int hmin = 0, hmax = 0; - for (int j = 0; j < nregs; ++j) - { - if (regs[j].base && regs[j].layerId == curId) - { - hmin = (int)regs[j].ymin; - hmax = (int)regs[j].ymax; - } - } - - layer->width = lw; - layer->height = lh; - layer->cs = chf.cs; - layer->ch = chf.ch; - - // Adjust the bbox to fit the heighfield. - rcVcopy(layer->bmin, bmin); - rcVcopy(layer->bmax, bmax); - layer->bmin[1] = bmin[1] + hmin*chf.ch; - layer->bmax[1] = bmin[1] + hmax*chf.ch; - layer->hmin = hmin; - layer->hmax = hmax; - - // Update usable data region. - layer->minx = layer->width; - layer->maxx = 0; - layer->miny = layer->height; - layer->maxy = 0; - - // Copy height and area from compact heighfield. - for (int y = 0; y < lh; ++y) - { - for (int x = 0; x < lw; ++x) - { - const int cx = borderSize+x; - const int cy = borderSize+y; - const rcCompactCell& c = chf.cells[cx+cy*w]; - for (int j = (int)c.index, nj = (int)(c.index+c.count); j < nj; ++j) - { - const rcCompactSpan& s = chf.spans[j]; - // Skip unassigned regions. - if (srcReg[j] == 0xff) - continue; - // Skip of does nto belong to current layer. - unsigned char lid = regs[srcReg[j]].layerId; - if (lid != curId) - continue; - - // Update data bounds. - layer->minx = rcMin(layer->minx, x); - layer->maxx = rcMax(layer->maxx, x); - layer->miny = rcMin(layer->miny, y); - layer->maxy = rcMax(layer->maxy, y); - - // Store height and area type. - const int idx = x+y*lw; - layer->heights[idx] = (unsigned char)(s.y - hmin); - layer->areas[idx] = chf.areas[j]; - - // Check connection. - unsigned char portal = 0; - unsigned char con = 0; - for (int dir = 0; dir < 4; ++dir) - { - if (rcGetCon(s, dir) != RC_NOT_CONNECTED) - { - const int ax = cx + rcGetDirOffsetX(dir); - const int ay = cy + rcGetDirOffsetY(dir); - const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); - unsigned char alid = srcReg[ai] != 0xff ? regs[srcReg[ai]].layerId : 0xff; - // Portal mask - if (chf.areas[ai] != RC_NULL_AREA && lid != alid) - { - portal |= (unsigned char)(1< hmin) - layer->heights[idx] = rcMax(layer->heights[idx], (unsigned char)(as.y - hmin)); - } - // Valid connection mask - if (chf.areas[ai] != RC_NULL_AREA && lid == alid) - { - const int nx = ax - borderSize; - const int ny = ay - borderSize; - if (nx >= 0 && ny >= 0 && nx < lw && ny < lh) - con |= (unsigned char)(1<cons[idx] = (portal << 4) | con; - } - } - } - - if (layer->minx > layer->maxx) - layer->minx = layer->maxx = 0; - if (layer->miny > layer->maxy) - layer->miny = layer->maxy = 0; - } - - ctx->stopTimer(RC_TIMER_BUILD_LAYERS); - - return true; -} diff --git a/dep/recastnavigation/Recast/RecastMesh.cpp b/dep/recastnavigation/Recast/RecastMesh.cpp index 13aad2a..4b33c10 100644 --- a/dep/recastnavigation/Recast/RecastMesh.cpp +++ b/dep/recastnavigation/Recast/RecastMesh.cpp @@ -59,7 +59,6 @@ static bool buildMeshAdjacency(unsigned short* polys, const int npolys, unsigned short* t = &polys[i*vertsPerPoly*2]; for (int j = 0; j < vertsPerPoly; ++j) { - if (t[j] == RC_MESH_NULL_IDX) break; unsigned short v0 = t[j]; unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1]; if (v0 < v1) @@ -84,7 +83,6 @@ static bool buildMeshAdjacency(unsigned short* polys, const int npolys, unsigned short* t = &polys[i*vertsPerPoly*2]; for (int j = 0; j < vertsPerPoly; ++j) { - if (t[j] == RC_MESH_NULL_IDX) break; unsigned short v0 = t[j]; unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1]; if (v0 > v1) @@ -197,7 +195,7 @@ inline bool collinear(const int* a, const int* b, const int* c) // Returns true iff ab properly intersects cd: they share // a point interior to both segments. The properness of the // intersection is ensured by using strict leftness. -static bool intersectProp(const int* a, const int* b, const int* c, const int* d) +bool intersectProp(const int* a, const int* b, const int* c, const int* d) { // Eliminate improper cases. if (collinear(a,b,c) || collinear(a,b,d) || @@ -472,7 +470,6 @@ static void mergePolys(unsigned short* pa, unsigned short* pb, int ea, int eb, memcpy(pa, tmp, sizeof(unsigned short)*nvp); } - static void pushFront(int v, int* arr, int& an) { an++; @@ -550,9 +547,9 @@ static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned sho // Check if the edge exists bool exists = false; - for (int m = 0; m < nedges; ++m) + for (int k = 0; k < nedges; ++k) { - int* e = &edges[m*3]; + int* e = &edges[k*3]; if (e[1] == b) { // Exists, increment vertex share count. @@ -895,13 +892,8 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short return true; } -/// @par -/// -/// @note If the mesh data is to be used to construct a Detour navigation mesh, then the upper -/// 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, rcContourSet& cset, int nvp, rcPolyMesh& mesh) { rcAssert(ctx); @@ -911,7 +903,6 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe rcVcopy(mesh.bmax, cset.bmax); mesh.cs = cset.cs; mesh.ch = cset.ch; - mesh.borderSize = cset.borderSize; int maxVertices = 0; int maxTris = 0; @@ -934,7 +925,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe rcScopedDelete vflags = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP); if (!vflags) { - ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'vflags' (%d).", maxVertices); + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices); return false; } memset(vflags, 0, maxVertices); @@ -945,7 +936,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices); return false; } - mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2, RC_ALLOC_PERM); + mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2*2, RC_ALLOC_PERM); if (!mesh.polys) { ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2); @@ -1053,7 +1044,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe vflags[indices[j]] = 1; } } - + // Build initial polygons. int npolys = 0; memset(polys, 0xff, maxVertsPerCont*nvp*sizeof(unsigned short)); @@ -1150,7 +1141,6 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe } // Remove vertex // Note: mesh.nverts is already decremented inside removeVertex()! - // Fixup vertex flags for (int j = i; j < mesh.nverts; ++j) vflags[j] = vflags[j+1]; --i; @@ -1163,37 +1153,6 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed."); return false; } - - // Find portal edges - if (mesh.borderSize > 0) - { - const int w = cset.width; - const int h = cset.height; - for (int i = 0; i < mesh.npolys; ++i) - { - unsigned short* p = &mesh.polys[i*2*nvp]; - for (int j = 0; j < nvp; ++j) - { - if (p[j] == RC_MESH_NULL_IDX) break; - // Skip connected edges. - if (p[nvp+j] != RC_MESH_NULL_IDX) - continue; - int nj = j+1; - if (nj >= nvp || p[nj] == RC_MESH_NULL_IDX) nj = 0; - const unsigned short* va = &mesh.verts[p[j]*3]; - const unsigned short* vb = &mesh.verts[p[nj]*3]; - - if ((int)va[0] == 0 && (int)vb[0] == 0) - p[nvp+j] = 0x8000 | 0; - else if ((int)va[2] == h && (int)vb[2] == h) - p[nvp+j] = 0x8000 | 1; - else if ((int)va[0] == w && (int)vb[0] == w) - p[nvp+j] = 0x8000 | 2; - else if ((int)va[2] == 0 && (int)vb[2] == 0) - p[nvp+j] = 0x8000 | 3; - } - } - } // Just allocate the mesh flags array. The user is resposible to fill it. mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM); @@ -1206,11 +1165,11 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe if (mesh.nverts > 0xffff) { - ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff); + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff); } if (mesh.npolys > 0xffff) { - ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff); + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff); } ctx->stopTimer(RC_TIMER_BUILD_POLYMESH); @@ -1218,7 +1177,6 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMe return true; } -/// @see rcAllocPolyMesh, rcPolyMesh bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh) { rcAssert(ctx); @@ -1310,7 +1268,7 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh); return false; } - memset(vremap, 0, sizeof(unsigned short)*maxVertsPerMesh); + memset(nextVert, 0, sizeof(int)*maxVerts); for (int i = 0; i < nmeshes; ++i) { @@ -1362,67 +1320,3 @@ bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, r return true; } - -bool rcCopyPolyMesh(rcContext* ctx, const rcPolyMesh& src, rcPolyMesh& dst) -{ - rcAssert(ctx); - - // Destination must be empty. - rcAssert(dst.verts == 0); - rcAssert(dst.polys == 0); - rcAssert(dst.regs == 0); - rcAssert(dst.areas == 0); - rcAssert(dst.flags == 0); - - dst.nverts = src.nverts; - dst.npolys = src.npolys; - dst.maxpolys = src.npolys; - dst.nvp = src.nvp; - rcVcopy(dst.bmin, src.bmin); - rcVcopy(dst.bmax, src.bmax); - dst.cs = src.cs; - dst.ch = src.ch; - dst.borderSize = src.borderSize; - - dst.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.nverts*3, RC_ALLOC_PERM); - if (!dst.verts) - { - ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.verts' (%d).", src.nverts*3); - return false; - } - memcpy(dst.verts, src.verts, sizeof(unsigned short)*src.nverts*3); - - dst.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys*2*src.nvp, RC_ALLOC_PERM); - if (!dst.polys) - { - ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.polys' (%d).", src.npolys*2*src.nvp); - return false; - } - memcpy(dst.polys, src.polys, sizeof(unsigned short)*src.npolys*2*src.nvp); - - dst.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM); - if (!dst.regs) - { - ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.regs' (%d).", src.npolys); - return false; - } - memcpy(dst.regs, src.regs, sizeof(unsigned short)*src.npolys); - - dst.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*src.npolys, RC_ALLOC_PERM); - if (!dst.areas) - { - ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.areas' (%d).", src.npolys); - return false; - } - memcpy(dst.areas, src.areas, sizeof(unsigned char)*src.npolys); - - dst.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*src.npolys, RC_ALLOC_PERM); - if (!dst.flags) - { - ctx->log(RC_LOG_ERROR, "rcCopyPolyMesh: Out of memory 'dst.flags' (%d).", src.npolys); - return false; - } - memcpy(dst.flags, src.flags, sizeof(unsigned char)*src.npolys); - - return true; -} diff --git a/dep/recastnavigation/Recast/RecastMeshDetail.cpp b/dep/recastnavigation/Recast/RecastMeshDetail.cpp index f49d674..ffb4b58 100644 --- a/dep/recastnavigation/Recast/RecastMeshDetail.cpp +++ b/dep/recastnavigation/Recast/RecastMeshDetail.cpp @@ -267,11 +267,11 @@ static int addEdge(rcContext* ctx, int* edges, int& nedges, const int maxEdges, int e = findEdge(edges, nedges, s, t); if (e == UNDEF) { - int* edge = &edges[nedges*4]; - edge[0] = s; - edge[1] = t; - edge[2] = l; - edge[3] = r; + int* e = &edges[nedges*4]; + e[0] = s; + e[1] = t; + e[2] = l; + e[3] = r; return nedges++; } else @@ -554,7 +554,7 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin, float dx = vi[0] - vj[0]; float dy = vi[1] - vj[1]; float dz = vi[2] - vj[2]; - float d = rcSqrt(dx*dx + dz*dz); + float d = sqrtf(dx*dx + dz*dz); int nn = 1 + (int)floorf(d/sampleDist); if (nn >= MAX_VERTS_PER_EDGE) nn = MAX_VERTS_PER_EDGE-1; if (nverts+nn >= MAX_VERTS) @@ -583,10 +583,10 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin, int maxi = -1; for (int m = a+1; m < b; ++m) { - float dev = distancePtSeg(&edge[m*3],va,vb); - if (dev > maxd) + float d = distancePtSeg(&edge[m*3],va,vb); + if (d > maxd) { - maxd = dev; + maxd = d; maxi = m; } } @@ -743,15 +743,12 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin, static void getHeightData(const rcCompactHeightfield& chf, const unsigned short* poly, const int npoly, - const unsigned short* verts, const int bs, + const unsigned short* verts, rcHeightPatch& hp, rcIntArray& stack) { // Floodfill the heightfield to get 2D height data, // starting at vertex locations as seeds. - // Note: Reads to the compact heightfield are offset by border size (bs) - // since border size offset is already removed from the polymesh vertices. - memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height); stack.resize(0); @@ -775,7 +772,7 @@ static void getHeightData(const rcCompactHeightfield& chf, az < hp.ymin || az >= hp.ymin+hp.height) continue; - const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width]; + const rcCompactCell& c = chf.cells[ax+az*chf.width]; for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { const rcCompactSpan& s = chf.spans[i]; @@ -847,7 +844,7 @@ static void getHeightData(const rcCompactHeightfield& chf, if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0) continue; - const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir); + const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(cs, dir); int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width; hp.data[idx] = 1; @@ -903,7 +900,7 @@ static void getHeightData(const rcCompactHeightfield& chf, if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != RC_UNSET_HEIGHT) continue; - const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir); + const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(cs, dir); const rcCompactSpan& as = chf.spans[ai]; int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width; @@ -941,11 +938,8 @@ static unsigned char getTriFlags(const float* va, const float* vb, const float* return flags; } -/// @par -/// -/// See the #rcConfig documentation for more information on the configuration parameters. -/// -/// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig + + bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf, const float sampleDist, const float sampleMaxError, rcPolyMeshDetail& dmesh) @@ -961,7 +955,6 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa const float cs = mesh.cs; const float ch = mesh.ch; const float* orig = mesh.bmin; - const int borderSize = mesh.borderSize; rcIntArray edges(64); rcIntArray tris(512); @@ -1072,7 +1065,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa hp.ymin = bounds[i*4+2]; hp.width = bounds[i*4+1]-bounds[i*4+0]; hp.height = bounds[i*4+3]-bounds[i*4+2]; - getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack); + getHeightData(chf, p, npoly, mesh.verts, hp, stack); // Build detail mesh. int nverts = 0; @@ -1164,7 +1157,6 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa return true; } -/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh) { rcAssert(ctx); diff --git a/dep/recastnavigation/Recast/RecastRasterization.cpp b/dep/recastnavigation/Recast/RecastRasterization.cpp index d2bb7c9..71adfb6 100644 --- a/dep/recastnavigation/Recast/RecastRasterization.cpp +++ b/dep/recastnavigation/Recast/RecastRasterization.cpp @@ -154,13 +154,6 @@ static void addSpan(rcHeightfield& hf, const int x, const int y, } } -/// @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. void 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) @@ -283,11 +276,6 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2, } } -/// @par -/// -/// No spans will be added if the triangle does not overlap the heightfield grid. -/// -/// @see rcHeightfield void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2, const unsigned char area, rcHeightfield& solid, const int flagMergeThr) @@ -303,11 +291,6 @@ void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); } -/// @par -/// -/// Spans will only be added for triangles that overlap the heightfield grid. -/// -/// @see rcHeightfield void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/, const int* tris, const unsigned char* areas, const int nt, rcHeightfield& solid, const int flagMergeThr) @@ -331,11 +314,6 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/, ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); } -/// @par -/// -/// Spans will only be added for triangles that overlap the heightfield grid. -/// -/// @see rcHeightfield void 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) @@ -359,11 +337,6 @@ void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/, ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); } -/// @par -/// -/// Spans will only be added for triangles that overlap the heightfield grid. -/// -/// @see rcHeightfield void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt, rcHeightfield& solid, const int flagMergeThr) { diff --git a/dep/recastnavigation/Recast/RecastRegion.cpp b/dep/recastnavigation/Recast/RecastRegion.cpp index 76e631c..6ad9fa5 100644 --- a/dep/recastnavigation/Recast/RecastRegion.cpp +++ b/dep/recastnavigation/Recast/RecastRegion.cpp @@ -283,8 +283,6 @@ static bool floodRegion(int x, int y, int i, if (chf.areas[ai] != area) continue; unsigned short nr = srcReg[ai]; - if (nr & RC_BORDER_REG) // Do not take borders into account. - continue; if (nr != 0 && nr != r) ar = nr; @@ -298,9 +296,9 @@ static bool floodRegion(int x, int y, int i, const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2); if (chf.areas[ai2] != area) continue; - unsigned short nr2 = srcReg[ai2]; - if (nr2 != 0 && nr2 != r) - ar = nr2; + unsigned short nr = srcReg[ai2]; + if (nr != 0 && nr != r) + ar = nr; } } } @@ -321,13 +319,16 @@ static bool floodRegion(int x, int y, int i, const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir); if (chf.areas[ai] != area) continue; - if (chf.dist[ai] >= lev && srcReg[ai] == 0) + if (chf.dist[ai] >= lev) { - srcReg[ai] = r; - srcDist[ai] = 0; - stack.push(ax); - stack.push(ay); - stack.push(ai); + if (srcReg[ai] == 0) + { + srcReg[ai] = r; + srcDist[ai] = 0; + stack.push(ax); + stack.push(ay); + stack.push(ai); + } } } } @@ -678,17 +679,17 @@ static void walkContour(int x, int y, int i, int dir, // Remove adjacent duplicates. if (cont.size() > 1) { - for (int j = 0; j < cont.size(); ) + for (int i = 0; i < cont.size(); ) { - int nj = (j+1) % cont.size(); - if (cont[j] == cont[nj]) + int ni = (i+1) % cont.size(); + if (cont[i] == cont[ni]) { - for (int k = j; k < cont.size()-1; ++k) - cont[k] = cont[k+1]; + for (int j = i; j < cont.size()-1; ++j) + cont[j] = cont[j+1]; cont.pop(); } else - ++j; + ++i; } } } @@ -806,14 +807,14 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio connectsToBorder = true; continue; } - rcRegion& neireg = regions[creg.connections[j]]; - if (neireg.visited) + rcRegion& nreg = regions[creg.connections[j]]; + if (nreg.visited) continue; - if (neireg.id == 0 || (neireg.id & RC_BORDER_REG)) + if (nreg.id == 0 || (nreg.id & RC_BORDER_REG)) continue; // Visit - stack.push(neireg.id); - neireg.visited = true; + stack.push(nreg.id); + nreg.visited = true; } } @@ -936,16 +937,7 @@ static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegio return true; } -/// @par -/// -/// This is usually the second to the last step in creating a fully built -/// compact heightfield. This step is required before regions are built -/// using #rcBuildRegions or #rcBuildRegionsMonotone. -/// -/// After this step, the distance data is available via the rcCompactHeightfield::maxDistance -/// and rcCompactHeightfield::dist fields. -/// -/// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone + bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf) { rcAssert(ctx); @@ -1028,25 +1020,6 @@ struct rcSweepSpan unsigned short nei; // neighbour id }; -/// @par -/// -/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour. -/// Contours will form simple polygons. -/// -/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be -/// re-assigned to the zero (null) region. -/// -/// Partitioning can result in smaller than necessary regions. @p mergeRegionArea helps -/// reduce unecessarily small regions. -/// -/// See the #rcConfig documentation for more information on the configuration parameters. -/// -/// The region data will be available via the rcCompactHeightfield::maxRegions -/// and rcCompactSpan::reg fields. -/// -/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions. -/// -/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, const int borderSize, const int minRegionArea, const int mergeRegionArea) { @@ -1086,8 +1059,6 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++; paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++; paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++; - - chf.borderSize = borderSize; } rcIntArray prev(256); @@ -1199,25 +1170,6 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, return true; } -/// @par -/// -/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour. -/// Contours will form simple polygons. -/// -/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be -/// re-assigned to the zero (null) region. -/// -/// Watershed partitioning can result in smaller than necessary regions, especially in diagonal corridors. -/// @p mergeRegionArea helps reduce unecessarily small regions. -/// -/// See the #rcConfig documentation for more information on the configuration parameters. -/// -/// The region data will be available via the rcCompactHeightfield::maxRegions -/// and rcCompactSpan::reg fields. -/// -/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions. -/// -/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, const int borderSize, const int minRegionArea, const int mergeRegionArea) { @@ -1257,19 +1209,11 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, // const int expandIters = 4 + walkableRadius * 2; const int expandIters = 8; - if (borderSize > 0) - { - // Make sure border will not overflow. - const int bw = rcMin(w, borderSize); - const int bh = rcMin(h, borderSize); - // Paint regions - paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; - paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; - paintRectRegion(0, w, 0, bh, regionId|RC_BORDER_REG, chf, srcReg); regionId++; - paintRectRegion(0, w, h-bh, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; - - chf.borderSize = borderSize; - } + // Mark border regions. + paintRectRegion(0, borderSize, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(w-borderSize, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(0, w, 0, borderSize, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(0, w, h-borderSize, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; while (level > 0) { @@ -1298,6 +1242,7 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, { if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA) continue; + if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack)) regionId++; } @@ -1305,6 +1250,7 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, } ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FLOOD); + } // Expand current regions until no empty connected cells found. diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp index 65c13c0..a3f89f4 100644 --- a/src/server/collision/Management/MMapManager.cpp +++ b/src/server/collision/Management/MMapManager.cpp @@ -63,7 +63,7 @@ namespace MMAP dtNavMesh* mesh = dtAllocNavMesh(); ASSERT(mesh); - if (dtStatusFailed(mesh->init(¶ms))) + if (DT_SUCCESS != mesh->init(¶ms)) { dtFreeNavMesh(mesh); TC_LOG_ERROR(LOG_FILTER_MAPS, "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName); @@ -152,7 +152,7 @@ namespace MMAP dtTileRef tileRef = 0; // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed - if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef))) + if (DT_SUCCESS == mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef)) { mmap->mmapLoadedTiles.insert(std::pair(packedGridPos, tileRef)); ++loadedTiles; @@ -193,7 +193,7 @@ namespace MMAP dtTileRef tileRef = mmap->mmapLoadedTiles[packedGridPos]; // unload, and mark as non loaded - if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, NULL, NULL))) + if (DT_SUCCESS != mmap->navMesh->removeTile(tileRef, NULL, NULL)) { // this is technically a memory leak // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used @@ -227,7 +227,7 @@ namespace MMAP { uint32 x = (i->first >> 16); uint32 y = (i->first & 0x0000FFFF); - if (dtStatusFailed(mmap->navMesh->removeTile(i->second, NULL, NULL))) + if (DT_SUCCESS != mmap->navMesh->removeTile(i->second, NULL, NULL)) TC_LOG_ERROR(LOG_FILTER_MAPS, "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y); else { @@ -288,7 +288,7 @@ namespace MMAP // allocate mesh query dtNavMeshQuery* query = dtAllocNavMeshQuery(); ASSERT(query); - if (dtStatusFailed(query->init(mmap->navMesh, 1024))) + if (DT_SUCCESS != query->init(mmap->navMesh, 1024)) { dtFreeNavMeshQuery(query); TC_LOG_ERROR(LOG_FILTER_MAPS, "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index 9250c78..ad48e4f 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -35,7 +35,7 @@ class Player; #define MAX_NUMBER_OF_GRIDS 64 -#define SIZE_OF_GRIDS 533.3333f +#define SIZE_OF_GRIDS 533.33333f #define CENTER_GRID_ID (MAX_NUMBER_OF_GRIDS/2) #define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 02f5965..e4a2536 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -3542,7 +3542,7 @@ enum PartyResult }; const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP' -#define MMAP_VERSION 4 +#define MMAP_VERSION 3 struct MmapTileHeader { diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index c902eb8..182582a 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -97,7 +97,7 @@ dtPolyRef PathGenerator::GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 for (uint32 i = 0; i < polyPathSize; ++i) { float closestPoint[VERTEX_SIZE]; - if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint))) + if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint)) continue; float d = dtVdist2DSqr(point, closestPoint); @@ -132,7 +132,8 @@ dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance) // first try with low search box float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f}; // bounds of poly search area float closestPoint[VERTEX_SIZE] = {0.0f, 0.0f, 0.0f}; - if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF) + dtStatus result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint); + if (DT_SUCCESS == result && polyRef != INVALID_POLYREF) { *distance = dtVdist(closestPoint, point); return polyRef; @@ -140,10 +141,9 @@ dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance) // still nothing .. // try with bigger search box - // Note that the extent should not overlap more than 128 polygons in the navmesh (see dtNavMeshQuery::findNearestPoly) - extents[1] = 50.0f; - - if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF) + extents[1] = 200.0f; + result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint); + if (DT_SUCCESS == result && polyRef != INVALID_POLYREF) { *distance = dtVdist(closestPoint, point); return polyRef; @@ -228,7 +228,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con { float closestPoint[VERTEX_SIZE]; // we may want to use closestPointOnPolyBoundary instead - if (dtStatusSucceed(_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint))) + if (DT_SUCCESS == _navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint)) { dtVcopy(endPoint, closestPoint); SetActualEndPosition(G3D::Vector3(endPoint[2], endPoint[0], endPoint[1])); @@ -319,13 +319,13 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data float suffixEndPoint[VERTEX_SIZE]; - if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))) + if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint)) { // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that // try to recover by using prev polyref --prefixPolyLength; suffixStartPoly = _pathPolyRefs[prefixPolyLength-1]; - if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))) + if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint)) { // suffixStartPoly is still invalid, error state BuildShortcut(); @@ -346,7 +346,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con (int*)&suffixPolyLength, MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path - if (!suffixPolyLength || dtStatusFailed(dtResult)) + if (!suffixPolyLength || dtResult != DT_SUCCESS) { // this is probably an error state, but we'll leave it // and hopefully recover on the next Update @@ -380,7 +380,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con (int*)&_polyLength, MAX_PATH_LENGTH); // max number of polygons in output path - if (!_polyLength || dtStatusFailed(dtResult)) + if (!_polyLength || dtResult != DT_SUCCESS) { // only happens if we passed bad data to findPath(), or navmesh is messed up TC_LOG_ERROR(LOG_FILTER_MAPS, "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow()); @@ -430,7 +430,7 @@ void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoin _pointPathLimit); // maximum number of points } - if (pointCount < 2 || dtStatusFailed(dtResult)) + if (pointCount < 2 || dtResult != DT_SUCCESS) { // only happens if pass bad data to findStraightPath or navmesh is broken // single point paths can be generated here @@ -579,7 +579,7 @@ bool PathGenerator::HaveTile(const G3D::Vector3& p) const if (tx < 0 || ty < 0) return false; - return (_navMesh->getTileAt(tx, ty, 0) != NULL); + return (_navMesh->getTileAt(tx, ty) != NULL); } uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited) @@ -639,7 +639,7 @@ bool PathGenerator::GetSteerTarget(float const* startPos, float const* endPos, uint32 nsteerPath = 0; dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize, steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS); - if (!nsteerPath || dtStatusFailed(dtResult)) + if (!nsteerPath || DT_SUCCESS != dtResult) return false; // Find vertex far enough to steer to. @@ -676,10 +676,10 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo uint32 npolys = polyPathSize; float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE]; - if (dtStatusFailed(_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos))) + if (DT_SUCCESS != _navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos)) return DT_FAILURE; - if (dtStatusFailed(_navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos))) + if (DT_SUCCESS != _navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos)) return DT_FAILURE; dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos); @@ -758,7 +758,7 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo // Handle the connection. float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE]; - if (dtStatusSucceed(_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos))) + if (DT_SUCCESS == _navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos)) { if (nsmoothPath < maxSmoothPathSize) { diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp index 690988e..1e62a99 100644 --- a/src/server/scripts/Commands/cs_mmaps.cpp +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -153,11 +153,7 @@ public: // navmesh poly -> navmesh tile location dtQueryFilter filter = dtQueryFilter(); dtPolyRef polyRef = INVALID_POLYREF; - if (dtStatusFailed(navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL))) - { - handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)"); - return true; - } + navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL); if (polyRef == INVALID_POLYREF) handler->PSendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)"); @@ -165,16 +161,11 @@ public: { dtMeshTile const* tile; dtPoly const* poly; - if (dtStatusSucceed(navmesh->getTileAndPolyByRef(polyRef, &tile, &poly))) - { - if (tile) - { - handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y); - return false; - } - } - - handler->PSendSysMessage("Dt [??,??] (no tile loaded)"); + navmesh->getTileAndPolyByRef(polyRef, &tile, &poly); + if (tile) + handler->PSendSysMessage("Dt [%02i, %02i]", tile->header->x, tile->header->y); + else + handler->PSendSysMessage("Dt [??, ??] (no tile loaded)"); } return true; diff --git a/src/tools/mmaps_generator/Info/readme.txt b/src/tools/mmaps_generator/Info/readme.txt index bde8e61..ff3f2f4 100644 --- a/src/tools/mmaps_generator/Info/readme.txt +++ b/src/tools/mmaps_generator/Info/readme.txt @@ -8,7 +8,7 @@ Generator command line args "map_id tile_x,tile_y (start_x start_y start_z) (end_x end_y end_z) size //optional comments" Single mesh connection per line. ---silent [] Make us script friendly. Do not wait for user input +--silent Make us script friendly. Do not wait for user input on error or completion. --bigBaseUnit [true|false] Generate tile/map using bigger basic unit. @@ -20,7 +20,7 @@ Generator command line args float between 45 and 90 degrees (default 60) ---skipLiquid [true|false] extract liquid data for maps +--skipLiquid liquid data for maps false: include liquid data (default) diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 9c2dda5..cd85d92 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -36,7 +36,7 @@ namespace DisableMgr } #define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 4 +#define MMAP_VERSION 3 struct MmapTileHeader { @@ -202,10 +202,7 @@ namespace MMAP minX = INT_MIN; minY = INT_MIN; - float bmin[3] = { 0, 0, 0 }; - float bmax[3] = { 0, 0, 0 }; - float lmin[3] = { 0, 0, 0 }; - float lmax[3] = { 0, 0, 0 }; + float bmin[3], bmax[3], lmin[3], lmax[3]; MeshData meshData; // make sure we process maps which don't have tiles @@ -246,20 +243,11 @@ namespace MMAP printf("Building mesh from file\n"); int tileX, tileY, mapId; if (fread(&mapId, sizeof(int), 1, file) != 1) - { - fclose(file); return; - } if (fread(&tileX, sizeof(int), 1, file) != 1) - { - fclose(file); return; - } if (fread(&tileY, sizeof(int), 1, file) != 1) - { - fclose(file); return; - } dtNavMesh* navMesh = NULL; buildNavMesh(mapId, navMesh); @@ -272,45 +260,25 @@ namespace MMAP uint32 verticesCount, indicesCount; if (fread(&verticesCount, sizeof(uint32), 1, file) != 1) - { - fclose(file); return; - } - if (fread(&indicesCount, sizeof(uint32), 1, file) != 1) - { - fclose(file); return; - } float* verts = new float[verticesCount]; int* inds = new int[indicesCount]; if (fread(verts, sizeof(float), verticesCount, file) != verticesCount) - { - fclose(file); - delete[] verts; - delete[] inds; return; - } - if (fread(inds, sizeof(int), indicesCount, file) != indicesCount) - { - fclose(file); - delete[] verts; - delete[] inds; return; - } MeshData data; for (uint32 i = 0; i < verticesCount; ++i) data.solidVerts.append(verts[i]); - delete[] verts; for (uint32 i = 0; i < indicesCount; ++i) data.solidTris.append(inds[i]); - delete[] inds; TerrainBuilder::cleanVertices(data.solidVerts, data.solidTris); // get bounds of current tile @@ -364,12 +332,12 @@ namespace MMAP buildNavMesh(mapID, navMesh); if (!navMesh) { - printf("[Map %03i] Failed creating navmesh!\n", mapID); + printf("[Map %i] Failed creating navmesh!\n", mapID); return; } // now start building mmtiles for each tile - printf("[Map %03i] We have %u tiles. \n", mapID, (unsigned int)tiles->size()); + printf("[Map %i] We have %u tiles. \n", mapID, (unsigned int)tiles->size()); for (std::set::iterator it = tiles->begin(); it != tiles->end(); ++it) { uint32 tileX, tileY; @@ -386,13 +354,13 @@ namespace MMAP dtFreeNavMesh(navMesh); } - printf("[Map %03i] Complete!\n", mapID); + printf("[Map %i] Complete!\n", mapID); } /**************************************************************************/ void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh) { - printf("[Map %03i] Building tile [%02u,%02u]\n", mapID, tileX, tileY); + printf("[Map %i] Building tile [%02u,%02u]\n", mapID, tileX, tileY); MeshData meshData; @@ -478,10 +446,10 @@ namespace MMAP navMeshParams.maxPolys = maxPolysPerTile; navMesh = dtAllocNavMesh(); - printf("[Map %03i] Creating navMesh...\n", mapID); + printf("[Map %i] Creating navMesh...\n", mapID); if (!navMesh->init(&navMeshParams)) { - printf("[Map %03i] Failed creating navmesh! \n", mapID); + printf("[Map %i] Failed creating navmesh! \n", mapID); return; } @@ -493,7 +461,7 @@ namespace MMAP { dtFreeNavMesh(navMesh); char message[1024]; - sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName); + sprintf(message, "[Map %i] Failed to open %s for writing!\n", mapID, fileName); perror(message); return; } @@ -528,8 +496,8 @@ namespace MMAP // these are WORLD UNIT based metrics // this are basic unit dimentions - // value have to divide GRID_SIZE(533.3333f) ( aka: 0.5333, 0.2666, 0.3333, 0.1333, etc ) - const static float BASE_UNIT_DIM = m_bigBaseUnit ? 0.5333333f : 0.2666666f; + // value have to divide GRID_SIZE(533.33333f) ( aka: 0.5333, 0.2666, 0.3333, 0.1333, etc ) + const static float BASE_UNIT_DIM = m_bigBaseUnit ? 0.533333f : 0.266666f; // All are in UNIT metrics! const static int VERTEX_PER_MAP = int(GRID_SIZE/BASE_UNIT_DIM + 0.5f); @@ -549,12 +517,12 @@ namespace MMAP config.tileSize = VERTEX_PER_TILE; config.walkableRadius = m_bigBaseUnit ? 1 : 2; config.borderSize = config.walkableRadius + 3; - config.maxEdgeLen = VERTEX_PER_TILE + 1; // anything bigger than tileSize + config.maxEdgeLen = VERTEX_PER_TILE + 1; //anything bigger than tileSize config.walkableHeight = m_bigBaseUnit ? 3 : 6; config.walkableClimb = m_bigBaseUnit ? 2 : 4; // keep less than walkableHeight config.minRegionArea = rcSqr(60); config.mergeRegionArea = rcSqr(50); - config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons) + config.maxSimplificationError = 2.0f; // eliminates most jagged edges (tinny polygons) config.detailSampleDist = config.cs * 64; config.detailSampleMaxError = config.ch * 2; @@ -571,7 +539,19 @@ namespace MMAP // merge per tile poly and detail meshes rcPolyMesh** pmmerge = new rcPolyMesh*[TILES_PER_MAP * TILES_PER_MAP]; + if (!pmmerge) + { + printf("%s alloc pmmerge FIALED!\n", tileString); + return; + } + rcPolyMeshDetail** dmmerge = new rcPolyMeshDetail*[TILES_PER_MAP * TILES_PER_MAP]; + if (!dmmerge) + { + printf("%s alloc dmmerge FIALED!\n", tileString); + return; + } + int nmerge = 0; // build all tiles for (int y = 0; y < TILES_PER_MAP; ++y) @@ -666,9 +646,12 @@ namespace MMAP rcFreeContourSet(tile.cset); tile.cset = NULL; - pmmerge[nmerge] = tile.pmesh; - dmmerge[nmerge] = tile.dmesh; - nmerge++; + if (tile.pmesh) + { + pmmerge[nmerge] = tile.pmesh; + dmmerge[nmerge] = tile.dmesh; + nmerge++; + } } } @@ -676,9 +659,6 @@ namespace MMAP if (!iv.polyMesh) { printf("%s alloc iv.polyMesh FIALED!\n", tileString); - delete[] pmmerge; - delete[] dmmerge; - delete[] tiles; return; } rcMergePolyMeshes(m_rcContext, pmmerge, nmerge, *iv.polyMesh); @@ -687,9 +667,6 @@ namespace MMAP if (!iv.polyMeshDetail) { printf("%s alloc m_dmesh FIALED!\n", tileString); - delete[] pmmerge; - delete[] dmmerge; - delete[] tiles; return; } rcMergePolyMeshDetails(m_rcContext, dmmerge, nmerge, *iv.polyMeshDetail); @@ -697,8 +674,17 @@ namespace MMAP // free things up delete[] pmmerge; delete[] dmmerge; + delete[] tiles; + // remove padding for extraction + for (int i = 0; i < iv.polyMesh->nverts; ++i) + { + unsigned short* v = &iv.polyMesh->verts[i*3]; + v[0] -= (unsigned short)config.borderSize; + v[2] -= (unsigned short)config.borderSize; + } + // set polygons as walkable // TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off for (int i = 0; i < iv.polyMesh->npolys; ++i) @@ -737,8 +723,7 @@ namespace MMAP rcVcopy(params.bmax, bmax); params.cs = config.cs; params.ch = config.ch; - params.tileLayer = 0; - params.buildBvTree = true; + params.tileSize = VERTEX_PER_MAP; // will hold final navmesh unsigned char* navData = NULL; @@ -807,7 +792,7 @@ namespace MMAP if (!file) { char message[1024]; - sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName); + sprintf(message, "[Map %i] Failed to open %s for writing!\n", mapID, fileName); perror(message); navMesh->removeTile(tileRef, NULL, NULL); continue; @@ -869,50 +854,50 @@ namespace MMAP { if (m_skipContinents) switch (mapID) - { - case 0: - case 1: - case 530: - case 571: - return true; - default: - break; - } + { + case 0: + case 1: + case 530: + case 571: + return true; + default: + break; + } if (m_skipJunkMaps) switch (mapID) - { - case 13: // test.wdt - case 25: // ScottTest.wdt - case 29: // Test.wdt - case 42: // Colin.wdt - case 169: // EmeraldDream.wdt (unused, and very large) - case 451: // development.wdt - case 573: // ExteriorTest.wdt - case 597: // CraigTest.wdt - case 605: // development_nonweighted.wdt - case 606: // QA_DVD.wdt + { + case 13: // test.wdt + case 25: // ScottTest.wdt + case 29: // Test.wdt + case 42: // Colin.wdt + case 169: // EmeraldDream.wdt (unused, and very large) + case 451: // development.wdt + case 573: // ExteriorTest.wdt + case 597: // CraigTest.wdt + case 605: // development_nonweighted.wdt + case 606: // QA_DVD.wdt + return true; + default: + if (isTransportMap(mapID)) return true; - default: - if (isTransportMap(mapID)) - return true; - break; - } + break; + } if (m_skipBattlegrounds) switch (mapID) - { - case 30: // AV - case 37: // ? - case 489: // WSG - case 529: // AB - case 566: // EotS - case 607: // SotA - case 628: // IoC - return true; - default: - break; - } + { + case 30: // AV + case 37: // ? + case 489: // WSG + case 529: // AB + case 566: // EotS + case 607: // SotA + case 628: // IoC + return true; + default: + break; + } return false; } @@ -923,37 +908,37 @@ namespace MMAP switch (mapID) { // transport maps - case 582: - case 584: - case 586: - case 587: - case 588: - case 589: - case 590: - case 591: - case 592: - case 593: - case 594: - case 596: - case 610: - case 612: - case 613: - case 614: - case 620: - case 621: - case 622: - case 623: - case 641: - case 642: - case 647: - case 672: - case 673: - case 712: - case 713: - case 718: - return true; - default: - return false; + case 582: + case 584: + case 586: + case 587: + case 588: + case 589: + case 590: + case 591: + case 592: + case 593: + case 594: + case 596: + case 610: + case 612: + case 613: + case 614: + case 620: + case 621: + case 622: + case 623: + case 641: + case 642: + case 647: + case 672: + case 673: + case 712: + case 713: + case 718: + return true; + default: + return false; } } diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h index 6ab0b31..3ffaea0 100644 --- a/src/tools/mmaps_generator/MapBuilder.h +++ b/src/tools/mmaps_generator/MapBuilder.h @@ -61,7 +61,7 @@ namespace MMAP class MapBuilder { public: - MapBuilder(float maxWalkableAngle = 55.f, + MapBuilder(float maxWalkableAngle = 60.f, bool skipLiquid = false, bool skipContinents = false, bool skipJunkMaps = true, diff --git a/src/tools/mmaps_generator/PathCommon.h b/src/tools/mmaps_generator/PathCommon.h index 94a11e0..3e06ff5 100644 --- a/src/tools/mmaps_generator/PathCommon.h +++ b/src/tools/mmaps_generator/PathCommon.h @@ -114,6 +114,7 @@ namespace MMAP const char *p = dirpath.c_str(); DIR * dirp = opendir(p); struct dirent * dp; + dirp = opendir(p); while (dirp) { diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp index 882ec7f..47d35b5 100644 --- a/src/tools/mmaps_generator/PathGenerator.cpp +++ b/src/tools/mmaps_generator/PathGenerator.cpp @@ -235,14 +235,14 @@ bool handleArgs(int argc, char** argv, int finish(const char* message, int returnValue) { printf("%s", message); - getchar(); // Wait for user input + getchar(); return returnValue; } int main(int argc, char** argv) { int threads = 3, mapnum = -1; - float maxAngle = 55.0f; + float maxAngle = 60.0f; int tileX = -1, tileY = -1; bool skipLiquid = false, skipContinents = false, diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 5c76161..3a87da3 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -260,8 +260,7 @@ namespace MMAP meshData.solidVerts.append(coord[1]); } - int indices[] = { 0, 0, 0 }; - int loopStart = 0, loopEnd = 0, loopInc = 0; + int indices[3], loopStart = 0, loopEnd = 0, loopInc = 0; getLoopVars(portion, loopStart, loopEnd, loopInc); for (int i = loopStart; i < loopEnd; i+=loopInc) for (int j = TOP; j <= BOTTOM; j+=1) @@ -341,8 +340,7 @@ namespace MMAP delete [] liquid_map; - int indices[] = { 0, 0, 0 }; - int loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP; + int indices[3], loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP; getLoopVars(portion, loopStart, loopEnd, loopInc); // generate triangles diff --git a/src/tools/mmaps_generator/TerrainBuilder.h b/src/tools/mmaps_generator/TerrainBuilder.h index e9ff2a3..069a5a9 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.h +++ b/src/tools/mmaps_generator/TerrainBuilder.h @@ -47,7 +47,7 @@ namespace MMAP static const int V9_SIZE_SQ = V9_SIZE*V9_SIZE; static const int V8_SIZE = 128; static const int V8_SIZE_SQ = V8_SIZE*V8_SIZE; - static const float GRID_SIZE = 533.3333f; + static const float GRID_SIZE = 533.33333f; static const float GRID_PART_SIZE = GRID_SIZE/V8_SIZE; // see contrib/extractor/system.cpp, CONF_use_minHeight -- 1.8.3.msysgit.0