mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-02 10:33:46 +00:00
Properly update Recastnav:
The commit not contained the last updates, added them and correct CMakeLists include. MMaps re-extraction wil be REQUIRED.
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
#ifndef DETOURALLOCATOR_H
|
||||
#define DETOURALLOCATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/// Provides hint values to the memory allocator on how long the
|
||||
/// memory is expected to be used.
|
||||
enum dtAllocHint
|
||||
@@ -32,7 +34,7 @@ enum dtAllocHint
|
||||
// @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);
|
||||
typedef void* (dtAllocFunc)(size_t size, dtAllocHint hint);
|
||||
|
||||
/// A memory deallocation function.
|
||||
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAllocFunc.
|
||||
@@ -49,7 +51,7 @@ void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc);
|
||||
/// @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);
|
||||
void* dtAlloc(size_t size, dtAllocHint hint);
|
||||
|
||||
/// Deallocates a memory block.
|
||||
/// @param[in] ptr A pointer to a memory block previously allocated using #dtAlloc.
|
||||
|
||||
@@ -20,11 +20,14 @@
|
||||
#define DETOURCOMMON_H
|
||||
|
||||
#include "DetourMath.h"
|
||||
#include <stddef.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.
|
||||
*/
|
||||
@@ -480,6 +483,23 @@ inline void dtSwapEndian(float* v)
|
||||
void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||
const float s, const float t, float* out);
|
||||
|
||||
template<typename TypeToRetrieveAs>
|
||||
TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(const unsigned char*& buffer, const size_t distanceToAdvance)
|
||||
{
|
||||
TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
|
||||
buffer += distanceToAdvance;
|
||||
return returnPointer;
|
||||
}
|
||||
|
||||
template<typename TypeToRetrieveAs>
|
||||
TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(unsigned char*& buffer, const size_t distanceToAdvance)
|
||||
{
|
||||
TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
|
||||
buffer += distanceToAdvance;
|
||||
return returnPointer;
|
||||
}
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
#endif // DETOURCOMMON_H
|
||||
@@ -490,28 +510,41 @@ void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
|
||||
// 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.<br/>
|
||||
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:
|
||||
|
||||
<ul>
|
||||
<li>The vertices are wrapped in the normal Detour wrap direction.</li>
|
||||
<li>The triangle's 3D face normal is in the general up direction.</li>
|
||||
</ul>
|
||||
|
||||
A negative return value indicates:
|
||||
|
||||
<ul>
|
||||
<li>The vertices are reverse wrapped. (Wrapped opposite the normal Detour wrap direction.)</li>
|
||||
<li>The triangle's 3D face normal is in the general down direction.</li>
|
||||
</ul>
|
||||
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
@defgroup detour Detour
|
||||
|
||||
Members in this module are wrappers around the standard math library
|
||||
*/
|
||||
|
||||
|
||||
@@ -22,8 +22,15 @@
|
||||
#include "DetourAlloc.h"
|
||||
#include "DetourStatus.h"
|
||||
|
||||
// Undefine (or define in a build cofnig) the following line to use 64bit polyref.
|
||||
// Generally not needed, useful for very large worlds.
|
||||
// Note: tiles build using 32bit refs are not compatible with 64bit refs!
|
||||
#define DT_POLYREF64 1
|
||||
|
||||
// Edited by TC
|
||||
#ifdef DT_POLYREF64
|
||||
// TODO: figure out a multiplatform version of uint64_t
|
||||
// - maybe: https://code.google.com/p/msinttypes/
|
||||
// - or: http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
#if defined(WIN32) && !defined(__MINGW32__)
|
||||
/// Do not rename back to uint64. Otherwise mac complains about typedef redefinition
|
||||
typedef unsigned __int64 uint64_d;
|
||||
@@ -37,20 +44,29 @@ typedef unsigned __int64 uint64_d;
|
||||
/// Do not rename back to uint64. Otherwise mac complains about typedef redefinition
|
||||
typedef uint64_t uint64_d;
|
||||
#endif
|
||||
#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.
|
||||
/// A handle to a polygon within a navigation mesh tile.
|
||||
/// @ingroup detour
|
||||
typedef uint64_d dtPolyRef; // Edited by TC
|
||||
#ifdef DT_POLYREF64
|
||||
static const unsigned int DT_SALT_BITS = 12;
|
||||
static const unsigned int DT_TILE_BITS = 21;
|
||||
static const unsigned int DT_POLY_BITS = 31;
|
||||
typedef uint64_d dtPolyRef;
|
||||
#else
|
||||
typedef unsigned int dtPolyRef;
|
||||
#endif
|
||||
|
||||
/// A handle to a tile within a navigation mesh.
|
||||
/// @ingroup detour
|
||||
typedef uint64_d dtTileRef; // Edited by TC
|
||||
#ifdef DT_POLYREF64
|
||||
typedef uint64_d dtTileRef;
|
||||
#else
|
||||
typedef unsigned int dtTileRef;
|
||||
#endif
|
||||
|
||||
/// The maximum number of vertices per navigation polygon.
|
||||
/// @ingroup detour
|
||||
@@ -90,12 +106,6 @@ static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
|
||||
/// @ingroup detour
|
||||
static const int DT_MAX_AREAS = 64;
|
||||
|
||||
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.
|
||||
|
||||
/// Tile flags used for various functions and fields.
|
||||
/// For an example, see dtNavMesh::addTile().
|
||||
enum dtTileFlags
|
||||
@@ -120,11 +130,10 @@ enum dtStraightPathOptions
|
||||
};
|
||||
|
||||
|
||||
/// Options for dtNavMeshQuery::findPath
|
||||
/// Options for dtNavMeshQuery::initSlicedFindPath and updateSlicedFindPath
|
||||
enum dtFindPathOptions
|
||||
{
|
||||
DT_FINDPATH_LOW_QUALITY_FAR = 0x01, ///< [provisional] trade quality for performance far from the origin. The idea is that by then a new query will be issued
|
||||
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||
};
|
||||
|
||||
/// Options for dtNavMeshQuery::raycast
|
||||
@@ -148,7 +157,7 @@ enum dtPolyTypes
|
||||
};
|
||||
|
||||
|
||||
/// Defines a polyogn within a dtMeshTile object.
|
||||
/// Defines a polygon within a dtMeshTile object.
|
||||
/// @ingroup detour
|
||||
struct dtPoly
|
||||
{
|
||||
@@ -303,6 +312,9 @@ struct dtMeshTile
|
||||
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.
|
||||
private:
|
||||
dtMeshTile(const dtMeshTile&);
|
||||
dtMeshTile& operator=(const dtMeshTile&);
|
||||
};
|
||||
|
||||
/// Configuration parameters used to define multi-tile navigation meshes.
|
||||
@@ -513,7 +525,11 @@ public:
|
||||
/// @param[in] ip The index of the polygon within the tile.
|
||||
inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
return ((dtPolyRef)salt << (DT_POLY_BITS+DT_TILE_BITS)) | ((dtPolyRef)it << DT_POLY_BITS) | (dtPolyRef)ip;
|
||||
#else
|
||||
return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Decodes a standard polygon reference.
|
||||
@@ -525,12 +541,21 @@ public:
|
||||
/// @see #encodePolyId
|
||||
inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
|
||||
const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
|
||||
salt = (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
|
||||
it = (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
|
||||
ip = (unsigned int)(ref & polyMask);
|
||||
#else
|
||||
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
||||
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||
salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||
it = (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||
ip = (unsigned int)(ref & polyMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts a tile's salt value from the specified polygon reference.
|
||||
@@ -539,8 +564,13 @@ public:
|
||||
/// @see #encodePolyId
|
||||
inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
|
||||
return (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
|
||||
#else
|
||||
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
|
||||
return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts the tile's index from the specified polygon reference.
|
||||
@@ -549,8 +579,13 @@ public:
|
||||
/// @see #encodePolyId
|
||||
inline unsigned int decodePolyIdTile(dtPolyRef ref) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
|
||||
return (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
|
||||
#else
|
||||
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
|
||||
return (unsigned int)((ref >> m_polyBits) & tileMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Extracts the polygon's index (within its tile) from the specified polygon reference.
|
||||
@@ -559,13 +594,21 @@ public:
|
||||
/// @see #encodePolyId
|
||||
inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
|
||||
{
|
||||
#ifdef DT_POLYREF64
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
|
||||
return (unsigned int)(ref & polyMask);
|
||||
#else
|
||||
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
|
||||
return (unsigned int)(ref & polyMask);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNavMesh(const dtNavMesh&);
|
||||
dtNavMesh& operator=(const dtNavMesh&);
|
||||
|
||||
/// Returns pointer to tile in the tile array.
|
||||
dtMeshTile* getTile(int i);
|
||||
@@ -594,7 +637,7 @@ private:
|
||||
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||
|
||||
/// Removes external links at specified side.
|
||||
void unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||
void unconnectLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||
|
||||
|
||||
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
|
||||
@@ -619,9 +662,11 @@ private:
|
||||
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
||||
dtMeshTile* m_tiles; ///< List of tiles.
|
||||
|
||||
#ifndef DT_POLYREF64
|
||||
unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
|
||||
unsigned int m_tileBits; ///< Number of tile bits in the tile ID.
|
||||
unsigned int m_polyBits; ///< Number of poly bits in the tile ID.
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Allocates a navigation mesh object using the Detour allocator.
|
||||
@@ -642,41 +687,57 @@ void dtFreeNavMesh(dtNavMesh* navmesh);
|
||||
// a source file. It reduces clutter in the main section of the header.
|
||||
|
||||
/**
|
||||
|
||||
@typedef dtPolyRef
|
||||
@par
|
||||
|
||||
Polygon references are subject to the same invalidate/preserve/restore
|
||||
rules that apply to #dtTileRef's. If the #dtTileRef for the polygon's
|
||||
tile changes, the polygon reference becomes invalid.
|
||||
|
||||
Changing a polygon's flags, area id, etc. does not impact its polygon
|
||||
reference.
|
||||
|
||||
@typedef dtTileRef
|
||||
@par
|
||||
|
||||
The following changes will invalidate a tile reference:
|
||||
|
||||
- The referenced tile has been removed from the navigation mesh.
|
||||
- The navigation mesh has been initialized using a different set
|
||||
of #dtNavMeshParams.
|
||||
|
||||
A tile reference is preserved/restored if the tile is added to a navigation
|
||||
mesh initialized with the original #dtNavMeshParams and is added at the
|
||||
original reference location. (E.g. The lastRef parameter is used with
|
||||
dtNavMesh::addTile.)
|
||||
|
||||
Basically, if the storage structure of a tile changes, its associated
|
||||
tile reference changes.
|
||||
|
||||
|
||||
@var unsigned short dtPoly::neis[DT_VERTS_PER_POLYGON]
|
||||
@par
|
||||
|
||||
Each entry represents data for the edge starting at the vertex of the same index.
|
||||
E.g. The entry at index n represents the edge data for vertex[n] to vertex[n+1].
|
||||
|
||||
A value of zero indicates the edge has no polygon connection. (It makes up the
|
||||
border of the navigation mesh.)
|
||||
|
||||
The information can be extracted as follows:
|
||||
@code
|
||||
neighborRef = neis[n] & 0xff; // Get the neighbor polygon reference.
|
||||
|
||||
if (neis[n] & #DT_EX_LINK)
|
||||
{
|
||||
// The edge is an external (portal) edge.
|
||||
}
|
||||
@endcode
|
||||
|
||||
@var float dtMeshHeader::bvQuantFactor
|
||||
@par
|
||||
|
||||
This value is used for converting between world and bounding volume coordinates.
|
||||
For example:
|
||||
@code
|
||||
@@ -690,19 +751,27 @@ if (n->i >= 0)
|
||||
// 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.
|
||||
|
||||
*/
|
||||
|
||||
@@ -128,14 +128,22 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int dataSize);
|
||||
// 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 <tt>init()</tt> function or the dtNavMesh::addTile()
|
||||
function.
|
||||
|
||||
@see dtCreateNavMeshData
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -131,6 +131,9 @@ struct dtRaycastHit
|
||||
|
||||
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||
float hitNormal[3];
|
||||
|
||||
/// The index of the edge on the final polygon where the wall was hit.
|
||||
int hitEdgeIndex;
|
||||
|
||||
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
||||
dtPolyRef* path;
|
||||
@@ -145,7 +148,18 @@ struct dtRaycastHit
|
||||
float pathCost;
|
||||
};
|
||||
|
||||
/// Provides custom polygon query behavior.
|
||||
/// Used by dtNavMeshQuery::queryPolygons.
|
||||
/// @ingroup detour
|
||||
class dtPolyQuery
|
||||
{
|
||||
public:
|
||||
virtual ~dtPolyQuery() { }
|
||||
|
||||
/// Called for each batch of unique polygons touched by the search area in dtNavMeshQuery::queryPolygons.
|
||||
/// This can be called multiple times for a single query.
|
||||
virtual void process(const dtMeshTile* tile, dtPoly** polys, dtPolyRef* refs, int count) = 0;
|
||||
};
|
||||
|
||||
/// Provides the ability to perform pathfinding related queries against
|
||||
/// a navigation mesh.
|
||||
@@ -158,7 +172,7 @@ public:
|
||||
|
||||
/// 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]
|
||||
/// @param[in] maxNodes Maximum number of search nodes. [Limits: 0 < value <= 65535]
|
||||
/// @returns The status flags for the query.
|
||||
dtStatus init(const dtNavMesh* nav, const int maxNodes);
|
||||
|
||||
@@ -179,7 +193,7 @@ public:
|
||||
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)]
|
||||
@@ -282,6 +296,20 @@ public:
|
||||
dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
|
||||
int* resultCount, const int maxResult) const;
|
||||
|
||||
/// Gets a path from the explored nodes in the previous search.
|
||||
/// @param[in] endRef The reference id of the end polygon.
|
||||
/// @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: >= 0]
|
||||
/// @returns The status flags. Returns DT_FAILURE | DT_INVALID_PARAM if any parameter is wrong, or if
|
||||
/// @p endRef was not explored in the previous search. Returns DT_SUCCESS | DT_BUFFER_TOO_SMALL
|
||||
/// if @p path cannot contain the entire path. In this case it is filled to capacity with a partial path.
|
||||
/// Otherwise returns DT_SUCCESS.
|
||||
/// @remarks The result of this function depends on the state of the query object. For that reason it should only
|
||||
/// be used immediately after one of the two Dijkstra searches, findPolysAroundCircle or findPolysAroundShape.
|
||||
dtStatus getPathFromDijkstraSearch(dtPolyRef endRef, dtPolyRef* path, int* pathCount, int maxPath) const;
|
||||
|
||||
/// @}
|
||||
/// @name Local Query Functions
|
||||
///@{
|
||||
@@ -309,6 +337,14 @@ public:
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* polys, int* polyCount, const int maxPolys) 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[in] query The query. Polygons found will be batched together and passed to this query.
|
||||
dtStatus queryPolygons(const float* center, const float* extents,
|
||||
const dtQueryFilter* filter, dtPolyQuery* query) 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)]
|
||||
@@ -472,13 +508,13 @@ public:
|
||||
/// @}
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator
|
||||
dtNavMeshQuery(const dtNavMeshQuery&);
|
||||
dtNavMeshQuery& operator=(const dtNavMeshQuery&);
|
||||
|
||||
/// Returns neighbour tile based on side.
|
||||
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
|
||||
|
||||
/// 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;
|
||||
void queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||
const dtQueryFilter* filter, dtPolyQuery* query) const;
|
||||
|
||||
/// Returns portal points between two polygons.
|
||||
dtStatus getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
|
||||
@@ -502,6 +538,9 @@ private:
|
||||
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;
|
||||
|
||||
// Gets the path leading to the specified end node.
|
||||
dtStatus getPathToNode(struct dtNode* endNode, dtPolyRef* path, int* pathCount, int maxPath) const;
|
||||
|
||||
const dtNavMesh* m_nav; ///< Pointer to navmesh data.
|
||||
|
||||
|
||||
@@ -31,28 +31,26 @@ enum dtNodeFlags
|
||||
typedef unsigned short dtNodeIndex;
|
||||
static const dtNodeIndex DT_NULL_IDX = (dtNodeIndex)~0;
|
||||
|
||||
static const int DT_NODE_PARENT_BITS = 24;
|
||||
static const int DT_NODE_STATE_BITS = 2;
|
||||
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 : 24; ///< Index to parent node.
|
||||
unsigned int state : 2; ///< extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
||||
unsigned int flags : 3; ///< Node flags. A combination of dtNodeFlags.
|
||||
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 : DT_NODE_PARENT_BITS; ///< Index to parent node.
|
||||
unsigned int state : DT_NODE_STATE_BITS; ///< extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
||||
unsigned int flags : 3; ///< Node flags. A combination of dtNodeFlags.
|
||||
dtPolyRef id; ///< Polygon ref the node corresponds to.
|
||||
};
|
||||
|
||||
|
||||
static const int DT_MAX_STATES_PER_NODE = 4; // number of extra states per node. See dtNode::state
|
||||
|
||||
|
||||
static const int DT_MAX_STATES_PER_NODE = 1 << DT_NODE_STATE_BITS; // number of extra states per node. See dtNode::state
|
||||
|
||||
class dtNodePool
|
||||
{
|
||||
public:
|
||||
dtNodePool(int maxNodes, int hashSize);
|
||||
~dtNodePool();
|
||||
inline void operator=(const dtNodePool&) {}
|
||||
void clear();
|
||||
|
||||
// Get a dtNode by ref and extra state information. If there is none then - allocate
|
||||
@@ -64,19 +62,19 @@ public:
|
||||
inline unsigned int getNodeIdx(const dtNode* node) const
|
||||
{
|
||||
if (!node) return 0;
|
||||
return (unsigned int)(node - m_nodes)+1;
|
||||
return (unsigned int)(node - m_nodes) + 1;
|
||||
}
|
||||
|
||||
inline dtNode* getNodeAtIdx(unsigned int idx)
|
||||
{
|
||||
if (!idx) return 0;
|
||||
return &m_nodes[idx-1];
|
||||
return &m_nodes[idx - 1];
|
||||
}
|
||||
|
||||
inline const dtNode* getNodeAtIdx(unsigned int idx) const
|
||||
{
|
||||
if (!idx) return 0;
|
||||
return &m_nodes[idx-1];
|
||||
return &m_nodes[idx - 1];
|
||||
}
|
||||
|
||||
inline int getMemUsed() const
|
||||
@@ -95,6 +93,9 @@ public:
|
||||
inline int getNodeCount() const { return m_nodeCount; }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNodePool(const dtNodePool&);
|
||||
dtNodePool& operator=(const dtNodePool&);
|
||||
|
||||
dtNode* m_nodes;
|
||||
dtNodeIndex* m_first;
|
||||
@@ -109,17 +110,10 @@ class dtNodeQueue
|
||||
public:
|
||||
dtNodeQueue(int n);
|
||||
~dtNodeQueue();
|
||||
inline void operator=(dtNodeQueue&) {}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
m_size = 0;
|
||||
}
|
||||
inline void clear() { m_size = 0; }
|
||||
|
||||
inline dtNode* top()
|
||||
{
|
||||
return m_heap[0];
|
||||
}
|
||||
inline dtNode* top() { return m_heap[0]; }
|
||||
|
||||
inline dtNode* pop()
|
||||
{
|
||||
@@ -152,12 +146,16 @@ public:
|
||||
inline int getMemUsed() const
|
||||
{
|
||||
return sizeof(*this) +
|
||||
sizeof(dtNode*)*(m_capacity+1);
|
||||
sizeof(dtNode*) * (m_capacity + 1);
|
||||
}
|
||||
|
||||
inline int getCapacity() const { return m_capacity; }
|
||||
|
||||
private:
|
||||
// Explicitly disabled copy constructor and copy assignment operator.
|
||||
dtNodeQueue(const dtNodeQueue&);
|
||||
dtNodeQueue& operator=(const dtNodeQueue&);
|
||||
|
||||
void bubbleUp(int i, dtNode* node);
|
||||
void trickleDown(int i, dtNode* node);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <stdlib.h>
|
||||
#include "DetourAlloc.h"
|
||||
|
||||
static void *dtAllocDefault(int size, dtAllocHint)
|
||||
static void *dtAllocDefault(size_t size, dtAllocHint)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
@@ -38,7 +38,7 @@ void dtAllocSetCustom(dtAllocFunc *allocFunc, dtFreeFunc *freeFunc)
|
||||
sFreeFunc = freeFunc ? freeFunc : dtFreeDefault;
|
||||
}
|
||||
|
||||
void* dtAlloc(int size, dtAllocHint hint)
|
||||
void* dtAlloc(size_t size, dtAllocHint hint)
|
||||
{
|
||||
return sAllocFunc(size, hint);
|
||||
}
|
||||
|
||||
@@ -385,3 +385,4 @@ bool dtIntersectSegSeg2D(const float* ap, const float* aq,
|
||||
t = vperpXZ(u,w) / d;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,11 +157,15 @@ 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.
|
||||
@@ -169,12 +173,15 @@ The general build process is as follows:
|
||||
-# 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
|
||||
*/
|
||||
|
||||
@@ -186,11 +193,13 @@ dtNavMesh::dtNavMesh() :
|
||||
m_tileLutMask(0),
|
||||
m_posLookup(0),
|
||||
m_nextFree(0),
|
||||
m_tiles(0),
|
||||
m_saltBits(0),
|
||||
m_tileBits(0),
|
||||
m_polyBits(0)
|
||||
m_tiles(0)
|
||||
{
|
||||
#ifndef DT_POLYREF64
|
||||
m_saltBits = 0;
|
||||
m_tileBits = 0;
|
||||
m_polyBits = 0;
|
||||
#endif
|
||||
memset(&m_params, 0, sizeof(dtNavMeshParams));
|
||||
m_orig[0] = 0;
|
||||
m_orig[1] = 0;
|
||||
@@ -241,11 +250,17 @@ 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.
|
||||
#ifndef DT_POLYREF64
|
||||
m_tileBits = dtIlog2(dtNextPow2((unsigned int)params->maxTiles));
|
||||
m_polyBits = dtIlog2(dtNextPow2((unsigned int)params->maxPolys));
|
||||
// Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow.
|
||||
m_saltBits = dtMin((unsigned int)31, 32 - m_tileBits - m_polyBits);
|
||||
|
||||
if (m_saltBits < 10)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
#endif
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -289,7 +304,7 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
|
||||
if (!tile) return 0;
|
||||
|
||||
float amin[2], amax[2];
|
||||
calcSlabEndPoints(va,vb, amin,amax, side);
|
||||
calcSlabEndPoints(va, vb, amin, amax, side);
|
||||
const float apos = getSlabCoord(va, side);
|
||||
|
||||
// Remove links pointing to 'side' and compact the links array.
|
||||
@@ -335,7 +350,7 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
|
||||
return n;
|
||||
}
|
||||
|
||||
void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target)
|
||||
void dtNavMesh::unconnectLinks(dtMeshTile* tile, dtMeshTile* target)
|
||||
{
|
||||
if (!tile || !target) return;
|
||||
|
||||
@@ -348,10 +363,9 @@ 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 (decodePolyIdTile(tile->links[j].ref) == targetNum)
|
||||
{
|
||||
// Revove link.
|
||||
// Remove link.
|
||||
unsigned int nj = tile->links[j].next;
|
||||
if (pj == DT_NULL_LINK)
|
||||
poly->firstLink = nj;
|
||||
@@ -637,9 +651,9 @@ void dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* close
|
||||
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)
|
||||
float dmin = edged[0];
|
||||
int imin = 0;
|
||||
for (int i = 1; i < nv; ++i)
|
||||
{
|
||||
if (edged[i] < dmin)
|
||||
{
|
||||
@@ -823,6 +837,11 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co
|
||||
/// tile will be restored to the same values they were before the tile was
|
||||
/// removed.
|
||||
///
|
||||
/// The nav mesh assumes exclusive access to the data passed and will make
|
||||
/// changes to the dynamic portion of the data. For that reason the data
|
||||
/// should not be reused in other nav meshes until the tile has been successfully
|
||||
/// removed from this nav mesh.
|
||||
///
|
||||
/// @see dtCreateNavMeshData, #removeTile
|
||||
dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
||||
dtTileRef lastRef, dtTileRef* result)
|
||||
@@ -898,14 +917,14 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
||||
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection)*header->offMeshConCount);
|
||||
|
||||
unsigned char* d = data + headerSize;
|
||||
tile->verts = (float*)d; d += vertsSize;
|
||||
tile->polys = (dtPoly*)d; d += polysSize;
|
||||
tile->links = (dtLink*)d; d += linksSize;
|
||||
tile->detailMeshes = (dtPolyDetail*)d; d += detailMeshesSize;
|
||||
tile->detailVerts = (float*)d; d += detailVertsSize;
|
||||
tile->detailTris = (unsigned char*)d; d += detailTrisSize;
|
||||
tile->bvTree = (dtBVNode*)d; d += bvtreeSize;
|
||||
tile->offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize;
|
||||
tile->verts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||
tile->polys = dtGetThenAdvanceBufferPointer<dtPoly>(d, polysSize);
|
||||
tile->links = dtGetThenAdvanceBufferPointer<dtLink>(d, linksSize);
|
||||
tile->detailMeshes = dtGetThenAdvanceBufferPointer<dtPolyDetail>(d, detailMeshesSize);
|
||||
tile->detailVerts = dtGetThenAdvanceBufferPointer<float>(d, detailVertsSize);
|
||||
tile->detailTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
tile->bvTree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvtreeSize);
|
||||
tile->offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshLinksSize);
|
||||
|
||||
// If there are no items in the bvtree, reset the tree pointer.
|
||||
if (!bvtreeSize)
|
||||
@@ -924,7 +943,10 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
||||
tile->flags = flags;
|
||||
|
||||
connectIntLinks(tile);
|
||||
|
||||
// Base off-mesh connections to their starting polygons and connect connections inside the tile.
|
||||
baseOffMeshLinks(tile);
|
||||
connectExtOffMeshLinks(tile, tile, -1);
|
||||
|
||||
// Create connections with neighbour tiles.
|
||||
static const int MAX_NEIS = 32;
|
||||
@@ -935,11 +957,11 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
||||
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);
|
||||
}
|
||||
if (neis[j] == tile)
|
||||
continue;
|
||||
|
||||
connectExtLinks(tile, neis[j], -1);
|
||||
connectExtLinks(neis[j], tile, -1);
|
||||
connectExtOffMeshLinks(tile, neis[j], -1);
|
||||
connectExtOffMeshLinks(neis[j], tile, -1);
|
||||
}
|
||||
@@ -1177,25 +1199,24 @@ 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.
|
||||
// Disconnect from other 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);
|
||||
unconnectLinks(neis[j], tile);
|
||||
}
|
||||
|
||||
// Connect with neighbour tiles.
|
||||
// Disconnect from 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);
|
||||
unconnectLinks(neis[j], tile);
|
||||
}
|
||||
|
||||
// Reset tile.
|
||||
@@ -1227,7 +1248,11 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz
|
||||
tile->offMeshCons = 0;
|
||||
|
||||
// Update salt, salt should never be zero.
|
||||
#ifdef DT_POLYREF64
|
||||
tile->salt = (tile->salt+1) & ((1<<DT_SALT_BITS)-1);
|
||||
#else
|
||||
tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1);
|
||||
#endif
|
||||
if (tile->salt == 0)
|
||||
tile->salt++;
|
||||
|
||||
@@ -1300,8 +1325,8 @@ dtStatus dtNavMesh::storeTileState(const dtMeshTile* tile, unsigned char* data,
|
||||
if (maxDataSize < sizeReq)
|
||||
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||
|
||||
dtTileState* tileState = (dtTileState*)data; data += dtAlign4(sizeof(dtTileState));
|
||||
dtPolyState* polyStates = (dtPolyState*)data; data += dtAlign4(sizeof(dtPolyState) * tile->header->polyCount);
|
||||
dtTileState* tileState = dtGetThenAdvanceBufferPointer<dtTileState>(data, dtAlign4(sizeof(dtTileState)));
|
||||
dtPolyState* polyStates = dtGetThenAdvanceBufferPointer<dtPolyState>(data, dtAlign4(sizeof(dtPolyState) * tile->header->polyCount));
|
||||
|
||||
// Store tile state.
|
||||
tileState->magic = DT_NAVMESH_STATE_MAGIC;
|
||||
@@ -1332,8 +1357,8 @@ dtStatus dtNavMesh::restoreTileState(dtMeshTile* tile, const unsigned char* data
|
||||
if (maxDataSize < sizeReq)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
const dtTileState* tileState = (const dtTileState*)data; data += dtAlign4(sizeof(dtTileState));
|
||||
const dtPolyState* polyStates = (const dtPolyState*)data; data += dtAlign4(sizeof(dtPolyState) * tile->header->polyCount);
|
||||
const dtTileState* tileState = dtGetThenAdvanceBufferPointer<const dtTileState>(data, dtAlign4(sizeof(dtTileState)));
|
||||
const dtPolyState* polyStates = dtGetThenAdvanceBufferPointer<const dtPolyState>(data, dtAlign4(sizeof(dtPolyState) * tile->header->polyCount));
|
||||
|
||||
// Check that the restore is possible.
|
||||
if (tileState->magic != DT_NAVMESH_STATE_MAGIC)
|
||||
@@ -1494,3 +1519,4 @@ dtStatus dtNavMesh::getPolyArea(dtPolyRef ref, unsigned char* resultArea) const
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,6 @@ inline int longestAxis(unsigned short x, unsigned short y, unsigned short z)
|
||||
if (z > maxVal)
|
||||
{
|
||||
axis = 2;
|
||||
maxVal = z;
|
||||
}
|
||||
return axis;
|
||||
}
|
||||
@@ -421,15 +420,16 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
||||
memset(data, 0, dataSize);
|
||||
|
||||
unsigned char* d = data;
|
||||
dtMeshHeader* header = (dtMeshHeader*)d; d += headerSize;
|
||||
float* navVerts = (float*)d; d += vertsSize;
|
||||
dtPoly* navPolys = (dtPoly*)d; d += polysSize;
|
||||
d += linksSize;
|
||||
dtPolyDetail* navDMeshes = (dtPolyDetail*)d; d += detailMeshesSize;
|
||||
float* navDVerts = (float*)d; d += detailVertsSize;
|
||||
unsigned char* navDTris = (unsigned char*)d; d += detailTrisSize;
|
||||
dtBVNode* navBvtree = (dtBVNode*)d; d += bvTreeSize;
|
||||
dtOffMeshConnection* offMeshCons = (dtOffMeshConnection*)d; d += offMeshConsSize;
|
||||
|
||||
dtMeshHeader* header = dtGetThenAdvanceBufferPointer<dtMeshHeader>(d, headerSize);
|
||||
float* navVerts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||
dtPoly* navPolys = dtGetThenAdvanceBufferPointer<dtPoly>(d, polysSize);
|
||||
d += linksSize; // Ignore links; just leave enough space for them. They'll be created on load.
|
||||
dtPolyDetail* navDMeshes = dtGetThenAdvanceBufferPointer<dtPolyDetail>(d, detailMeshesSize);
|
||||
float* navDVerts = dtGetThenAdvanceBufferPointer<float>(d, detailVertsSize);
|
||||
unsigned char* navDTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
dtBVNode* navBvtree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvTreeSize);
|
||||
dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshConsSize);
|
||||
|
||||
|
||||
// Store header
|
||||
@@ -705,14 +705,16 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
||||
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection)*header->offMeshConCount);
|
||||
|
||||
unsigned char* d = data + headerSize;
|
||||
float* verts = (float*)d; d += vertsSize;
|
||||
dtPoly* polys = (dtPoly*)d; d += polysSize;
|
||||
/*dtLink* links = (dtLink*)d;*/ d += linksSize;
|
||||
dtPolyDetail* detailMeshes = (dtPolyDetail*)d; d += detailMeshesSize;
|
||||
float* detailVerts = (float*)d; d += detailVertsSize;
|
||||
/*unsigned char* detailTris = (unsigned char*)d;*/ d += detailTrisSize;
|
||||
dtBVNode* bvTree = (dtBVNode*)d; d += bvtreeSize;
|
||||
dtOffMeshConnection* offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize;
|
||||
float* verts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||
dtPoly* polys = dtGetThenAdvanceBufferPointer<dtPoly>(d, polysSize);
|
||||
d += linksSize; // Ignore links; they technically should be endian-swapped but all their data is overwritten on load anyway.
|
||||
//dtLink* links = dtGetThenAdvanceBufferPointer<dtLink>(d, linksSize);
|
||||
dtPolyDetail* detailMeshes = dtGetThenAdvanceBufferPointer<dtPolyDetail>(d, detailMeshesSize);
|
||||
float* detailVerts = dtGetThenAdvanceBufferPointer<float>(d, detailVertsSize);
|
||||
d += detailTrisSize; // Ignore detail tris; single bytes can't be endian-swapped.
|
||||
//unsigned char* detailTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
dtBVNode* bvTree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvtreeSize);
|
||||
dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshLinksSize);
|
||||
|
||||
// Vertices
|
||||
for (int i = 0; i < header->vertCount*3; ++i)
|
||||
|
||||
@@ -100,7 +100,6 @@ inline float dtQueryFilter::getCost(const float* pa, const float* pb,
|
||||
}
|
||||
#endif
|
||||
|
||||
// Edited by TC
|
||||
static const float H_SCALE = 2.0f; // Search heuristic scale.
|
||||
|
||||
|
||||
@@ -166,6 +165,9 @@ dtNavMeshQuery::~dtNavMeshQuery()
|
||||
/// This function can be used multiple times.
|
||||
dtStatus dtNavMeshQuery::init(const dtNavMesh* nav, const int maxNodes)
|
||||
{
|
||||
if (maxNodes > DT_NULL_IDX || maxNodes > (1 << DT_NODE_PARENT_BITS) - 1)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
m_nav = nav;
|
||||
|
||||
if (!m_nodePool || m_nodePool->getMaxNodes() < maxNodes)
|
||||
@@ -196,7 +198,6 @@ dtStatus dtNavMeshQuery::init(const dtNavMesh* nav, const int maxNodes)
|
||||
m_tinyNodePool->clear();
|
||||
}
|
||||
|
||||
// TODO: check the open list size too.
|
||||
if (!m_openList || m_openList->getCapacity() < maxNodes)
|
||||
{
|
||||
if (m_openList)
|
||||
@@ -541,9 +542,9 @@ dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, flo
|
||||
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)
|
||||
float dmin = edged[0];
|
||||
int imin = 0;
|
||||
for (int i = 1; i < nv; ++i)
|
||||
{
|
||||
if (edged[i] < dmin)
|
||||
{
|
||||
@@ -627,9 +628,9 @@ dtStatus dtNavMeshQuery::closestPointOnPolyBoundary(dtPolyRef ref, const float*
|
||||
else
|
||||
{
|
||||
// Point is outside the polygon, dtClamp to nearest edge.
|
||||
float dmin = FLT_MAX;
|
||||
int imin = -1;
|
||||
for (int i = 0; i < nv; ++i)
|
||||
float dmin = edged[0];
|
||||
int imin = 0;
|
||||
for (int i = 1; i < nv; ++i)
|
||||
{
|
||||
if (edged[i] < dmin)
|
||||
{
|
||||
@@ -698,78 +699,98 @@ dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* h
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
}
|
||||
|
||||
class dtFindNearestPolyQuery : public dtPolyQuery
|
||||
{
|
||||
const dtNavMeshQuery* m_query;
|
||||
const float* m_center;
|
||||
float m_nearestDistanceSqr;
|
||||
dtPolyRef m_nearestRef;
|
||||
float m_nearestPoint[3];
|
||||
|
||||
public:
|
||||
dtFindNearestPolyQuery(const dtNavMeshQuery* query, const float* center)
|
||||
: m_query(query), m_center(center), m_nearestDistanceSqr(FLT_MAX), m_nearestRef(0), m_nearestPoint()
|
||||
{
|
||||
}
|
||||
|
||||
dtPolyRef nearestRef() const { return m_nearestRef; }
|
||||
const float* nearestPoint() const { return m_nearestPoint; }
|
||||
|
||||
void process(const dtMeshTile* tile, dtPoly** polys, dtPolyRef* refs, int count)
|
||||
{
|
||||
dtIgnoreUnused(polys);
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
dtPolyRef ref = refs[i];
|
||||
float closestPtPoly[3];
|
||||
float diff[3];
|
||||
bool posOverPoly = false;
|
||||
float d;
|
||||
m_query->closestPointOnPoly(ref, m_center, closestPtPoly, &posOverPoly);
|
||||
|
||||
// If a point is directly over a polygon and closer than
|
||||
// climb height, favor that instead of straight line nearest point.
|
||||
dtVsub(diff, m_center, closestPtPoly);
|
||||
if (posOverPoly)
|
||||
{
|
||||
d = dtAbs(diff[1]) - tile->header->walkableClimb;
|
||||
d = d > 0 ? d*d : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = dtVlenSqr(diff);
|
||||
}
|
||||
|
||||
if (d < m_nearestDistanceSqr)
|
||||
{
|
||||
dtVcopy(m_nearestPoint, closestPtPoly);
|
||||
|
||||
m_nearestDistanceSqr = d;
|
||||
m_nearestRef = ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// @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 MAX_SEARCH (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
|
||||
{
|
||||
dtAssert(m_nav);
|
||||
|
||||
*nearestRef = 0;
|
||||
|
||||
// Get nearby polygons from proximity grid.
|
||||
const int MAX_SEARCH = 128;
|
||||
dtPolyRef polys[MAX_SEARCH];
|
||||
int polyCount = 0;
|
||||
if (dtStatusFailed(queryPolygons(center, extents, filter, polys, &polyCount, MAX_SEARCH)))
|
||||
if (!nearestRef)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
// Find nearest polygon amongst the nearby polygons.
|
||||
dtPolyRef nearest = 0;
|
||||
float nearestDistanceSqr = FLT_MAX;
|
||||
for (int i = 0; i < polyCount; ++i)
|
||||
{
|
||||
dtPolyRef ref = polys[i];
|
||||
float closestPtPoly[3];
|
||||
float diff[3];
|
||||
bool posOverPoly = false;
|
||||
float d = 0;
|
||||
closestPointOnPoly(ref, center, closestPtPoly, &posOverPoly);
|
||||
dtFindNearestPolyQuery query(this, center);
|
||||
|
||||
// If a point is directly over a polygon and closer than
|
||||
// climb height, favor that instead of straight line nearest point.
|
||||
dtVsub(diff, center, closestPtPoly);
|
||||
if (posOverPoly)
|
||||
{
|
||||
const dtMeshTile* tile = 0;
|
||||
const dtPoly* poly = 0;
|
||||
m_nav->getTileAndPolyByRefUnsafe(polys[i], &tile, &poly);
|
||||
d = dtAbs(diff[1]) - tile->header->walkableClimb;
|
||||
d = d > 0 ? d*d : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = dtVlenSqr(diff);
|
||||
}
|
||||
|
||||
if (d < nearestDistanceSqr)
|
||||
{
|
||||
if (nearestPt)
|
||||
dtVcopy(nearestPt, closestPtPoly);
|
||||
nearestDistanceSqr = d;
|
||||
nearest = ref;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearestRef)
|
||||
*nearestRef = nearest;
|
||||
dtStatus status = queryPolygons(center, extents, filter, &query);
|
||||
if (dtStatusFailed(status))
|
||||
return status;
|
||||
|
||||
*nearestRef = query.nearestRef();
|
||||
// Only override nearestPt if we actually found a poly so the nearest point
|
||||
// is valid.
|
||||
if (nearestPt && *nearestRef)
|
||||
dtVcopy(nearestPt, query.nearestPoint());
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* polys, const int maxPolys) const
|
||||
void dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
|
||||
const dtQueryFilter* filter, dtPolyQuery* query) const
|
||||
{
|
||||
dtAssert(m_nav);
|
||||
static const int batchSize = 32;
|
||||
dtPolyRef polyRefs[batchSize];
|
||||
dtPoly* polys[batchSize];
|
||||
int n = 0;
|
||||
|
||||
if (tile->bvTree)
|
||||
{
|
||||
@@ -778,7 +799,7 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi
|
||||
const float* tbmin = tile->header->bmin;
|
||||
const float* tbmax = tile->header->bmax;
|
||||
const float qfac = tile->header->bvQuantFactor;
|
||||
|
||||
|
||||
// Calculate quantized box
|
||||
unsigned short bmin[3], bmax[3];
|
||||
// dtClamp query box to world box.
|
||||
@@ -795,25 +816,34 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi
|
||||
bmax[0] = (unsigned short)(qfac * maxx + 1) | 1;
|
||||
bmax[1] = (unsigned short)(qfac * maxy + 1) | 1;
|
||||
bmax[2] = (unsigned short)(qfac * maxz + 1) | 1;
|
||||
|
||||
|
||||
// Traverse tree
|
||||
const dtPolyRef base = m_nav->getPolyRefBase(tile);
|
||||
int n = 0;
|
||||
while (node < end)
|
||||
{
|
||||
const bool overlap = dtOverlapQuantBounds(bmin, bmax, node->bmin, node->bmax);
|
||||
const bool isLeafNode = node->i >= 0;
|
||||
|
||||
|
||||
if (isLeafNode && overlap)
|
||||
{
|
||||
dtPolyRef ref = base | (dtPolyRef)node->i;
|
||||
if (filter->passFilter(ref, tile, &tile->polys[node->i]))
|
||||
{
|
||||
if (n < maxPolys)
|
||||
polys[n++] = ref;
|
||||
polyRefs[n] = ref;
|
||||
polys[n] = &tile->polys[node->i];
|
||||
|
||||
if (n == batchSize - 1)
|
||||
{
|
||||
query->process(tile, polys, polyRefs, batchSize);
|
||||
n = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (overlap || isLeafNode)
|
||||
node++;
|
||||
else
|
||||
@@ -822,17 +852,14 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi
|
||||
node += escapeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
else
|
||||
{
|
||||
float bmin[3], bmax[3];
|
||||
int n = 0;
|
||||
const dtPolyRef base = m_nav->getPolyRefBase(tile);
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
const dtPoly* p = &tile->polys[i];
|
||||
dtPoly* p = &tile->polys[i];
|
||||
// Do not return off-mesh connection polygons.
|
||||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
continue;
|
||||
@@ -850,16 +877,63 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi
|
||||
dtVmin(bmin, v);
|
||||
dtVmax(bmax, v);
|
||||
}
|
||||
if (dtOverlapBounds(qmin,qmax, bmin,bmax))
|
||||
if (dtOverlapBounds(qmin, qmax, bmin, bmax))
|
||||
{
|
||||
if (n < maxPolys)
|
||||
polys[n++] = ref;
|
||||
polyRefs[n] = ref;
|
||||
polys[n] = p;
|
||||
|
||||
if (n == batchSize - 1)
|
||||
{
|
||||
query->process(tile, polys, polyRefs, batchSize);
|
||||
n = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// Process the last polygons that didn't make a full batch.
|
||||
if (n > 0)
|
||||
query->process(tile, polys, polyRefs, n);
|
||||
}
|
||||
|
||||
class dtCollectPolysQuery : public dtPolyQuery
|
||||
{
|
||||
dtPolyRef* m_polys;
|
||||
const int m_maxPolys;
|
||||
int m_numCollected;
|
||||
bool m_overflow;
|
||||
|
||||
public:
|
||||
dtCollectPolysQuery(dtPolyRef* polys, const int maxPolys)
|
||||
: m_polys(polys), m_maxPolys(maxPolys), m_numCollected(0), m_overflow(false)
|
||||
{
|
||||
}
|
||||
|
||||
int numCollected() const { return m_numCollected; }
|
||||
bool overflowed() const { return m_overflow; }
|
||||
|
||||
void process(const dtMeshTile* tile, dtPoly** polys, dtPolyRef* refs, int count)
|
||||
{
|
||||
dtIgnoreUnused(tile);
|
||||
dtIgnoreUnused(polys);
|
||||
|
||||
int numLeft = m_maxPolys - m_numCollected;
|
||||
int toCopy = count;
|
||||
if (toCopy > numLeft)
|
||||
{
|
||||
m_overflow = true;
|
||||
toCopy = numLeft;
|
||||
}
|
||||
|
||||
memcpy(m_polys + m_numCollected, refs, (size_t)toCopy * sizeof(dtPolyRef));
|
||||
m_numCollected += toCopy;
|
||||
}
|
||||
};
|
||||
|
||||
/// @par
|
||||
///
|
||||
/// If no polygons are found, the function will return #DT_SUCCESS with a
|
||||
@@ -872,9 +946,35 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi
|
||||
dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents,
|
||||
const dtQueryFilter* filter,
|
||||
dtPolyRef* polys, int* polyCount, const int maxPolys) const
|
||||
{
|
||||
if (!polys || !polyCount || maxPolys < 0)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
dtCollectPolysQuery collector(polys, maxPolys);
|
||||
|
||||
dtStatus status = queryPolygons(center, extents, filter, &collector);
|
||||
if (dtStatusFailed(status))
|
||||
return status;
|
||||
|
||||
*polyCount = collector.numCollected();
|
||||
return collector.overflowed() ? DT_SUCCESS | DT_BUFFER_TOO_SMALL : DT_SUCCESS;
|
||||
}
|
||||
|
||||
/// @par
|
||||
///
|
||||
/// The query will be invoked with batches of polygons. Polygons passed
|
||||
/// to the query have bounding boxes that overlap with the center and extents
|
||||
/// passed to this function. The dtPolyQuery::process function is invoked multiple
|
||||
/// times until all overlapping polygons have been processed.
|
||||
///
|
||||
dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents,
|
||||
const dtQueryFilter* filter, dtPolyQuery* query) const
|
||||
{
|
||||
dtAssert(m_nav);
|
||||
|
||||
|
||||
if (!center || !extents || !filter || !query)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
dtVsub(bmin, center, extents);
|
||||
dtVadd(bmax, center, extents);
|
||||
@@ -887,7 +987,6 @@ dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents
|
||||
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)
|
||||
@@ -895,16 +994,10 @@ dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents
|
||||
const int nneis = m_nav->getTilesAt(x,y,neis,MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
n += queryPolygonsInTile(neis[j], bmin, bmax, filter, polys+n, maxPolys-n);
|
||||
if (n >= maxPolys)
|
||||
{
|
||||
*polyCount = n;
|
||||
return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
queryPolygonsInTile(neis[j], bmin, bmax, filter, query);
|
||||
}
|
||||
}
|
||||
}
|
||||
*polyCount = n;
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
@@ -929,18 +1022,14 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||
dtAssert(m_nodePool);
|
||||
dtAssert(m_openList);
|
||||
|
||||
*pathCount = 0;
|
||||
|
||||
if (!startRef || !endRef)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
if (!maxPath)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
if (pathCount)
|
||||
*pathCount = 0;
|
||||
|
||||
// Validate input
|
||||
if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef))
|
||||
if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef) ||
|
||||
!startPos || !endPos || !filter || maxPath <= 0 || !path || !pathCount)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
|
||||
if (startRef == endRef)
|
||||
{
|
||||
path[0] = startRef;
|
||||
@@ -963,7 +1052,7 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||
dtNode* lastBestNode = startNode;
|
||||
float lastBestNodeCost = startNode->total;
|
||||
|
||||
dtStatus status = DT_SUCCESS;
|
||||
bool outOfNodes = false;
|
||||
|
||||
while (!m_openList->empty())
|
||||
{
|
||||
@@ -1021,7 +1110,7 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||
dtNode* neighbourNode = m_nodePool->getNode(neighbourRef, crossSide);
|
||||
if (!neighbourNode)
|
||||
{
|
||||
status |= DT_OUT_OF_NODES;
|
||||
outOfNodes = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1100,42 +1189,59 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dtStatus status = getPathToNode(lastBestNode, path, pathCount, maxPath);
|
||||
|
||||
if (lastBestNode->id != endRef)
|
||||
status |= DT_PARTIAL_RESULT;
|
||||
|
||||
// Reverse the path.
|
||||
dtNode* prev = 0;
|
||||
dtNode* node = lastBestNode;
|
||||
do
|
||||
{
|
||||
dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
|
||||
node->pidx = m_nodePool->getNodeIdx(prev);
|
||||
prev = node;
|
||||
node = next;
|
||||
}
|
||||
while (node);
|
||||
|
||||
// Store path
|
||||
node = prev;
|
||||
int n = 0;
|
||||
do
|
||||
{
|
||||
path[n++] = node->id;
|
||||
if (n >= maxPath)
|
||||
{
|
||||
status |= DT_BUFFER_TOO_SMALL;
|
||||
break;
|
||||
}
|
||||
node = m_nodePool->getNodeAtIdx(node->pidx);
|
||||
}
|
||||
while (node);
|
||||
|
||||
*pathCount = n;
|
||||
|
||||
if (outOfNodes)
|
||||
status |= DT_OUT_OF_NODES;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
dtStatus dtNavMeshQuery::getPathToNode(dtNode* endNode, dtPolyRef* path, int* pathCount, int maxPath) const
|
||||
{
|
||||
// Find the length of the entire path.
|
||||
dtNode* curNode = endNode;
|
||||
int length = 0;
|
||||
do
|
||||
{
|
||||
length++;
|
||||
curNode = m_nodePool->getNodeAtIdx(curNode->pidx);
|
||||
} while (curNode);
|
||||
|
||||
// If the path cannot be fully stored then advance to the last node we will be able to store.
|
||||
curNode = endNode;
|
||||
int writeCount;
|
||||
for (writeCount = length; writeCount > maxPath; writeCount--)
|
||||
{
|
||||
dtAssert(curNode);
|
||||
|
||||
curNode = m_nodePool->getNodeAtIdx(curNode->pidx);
|
||||
}
|
||||
|
||||
// Write path
|
||||
for (int i = writeCount - 1; i >= 0; i--)
|
||||
{
|
||||
dtAssert(curNode);
|
||||
|
||||
path[i] = curNode->id;
|
||||
curNode = m_nodePool->getNodeAtIdx(curNode->pidx);
|
||||
}
|
||||
|
||||
dtAssert(!curNode);
|
||||
|
||||
*pathCount = dtMin(length, maxPath);
|
||||
|
||||
if (length > maxPath)
|
||||
return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/// @par
|
||||
///
|
||||
/// @warning Calling any non-slice methods before calling finalizeSlicedFindPath()
|
||||
@@ -1628,10 +1734,17 @@ dtStatus dtNavMeshQuery::appendVertex(const float* pos, const unsigned char flag
|
||||
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)
|
||||
|
||||
// If there is no space to append more vertices, return.
|
||||
if ((*straightPathCount) >= maxStraightPath)
|
||||
{
|
||||
return DT_SUCCESS | (((*straightPathCount) >= maxStraightPath) ? DT_BUFFER_TOO_SMALL : 0);
|
||||
return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
// If reached end of path, return.
|
||||
if (flags == DT_STRAIGHTPATH_END)
|
||||
{
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
}
|
||||
return DT_IN_PROGRESS;
|
||||
@@ -1756,10 +1869,12 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en
|
||||
for (int i = 0; i < pathSize; ++i)
|
||||
{
|
||||
float left[3], right[3];
|
||||
unsigned char fromType, toType;
|
||||
unsigned char toType;
|
||||
|
||||
if (i+1 < pathSize)
|
||||
{
|
||||
unsigned char fromType; // fromType is ignored.
|
||||
|
||||
// Next portal.
|
||||
if (dtStatusFailed(getPortalPoints(path[i], path[i+1], left, right, fromType, toType)))
|
||||
{
|
||||
@@ -1775,12 +1890,14 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en
|
||||
// Apeend portals along the current straight path segment.
|
||||
if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS))
|
||||
{
|
||||
stat = appendPortals(apexIndex, i, closestEndPos, path,
|
||||
// Ignore status return value as we're just about to return anyway.
|
||||
appendPortals(apexIndex, i, closestEndPos, path,
|
||||
straightPath, straightPathFlags, straightPathRefs,
|
||||
straightPathCount, maxStraightPath, options);
|
||||
}
|
||||
|
||||
stat = appendVertex(closestEndPos, 0, path[i],
|
||||
// Ignore status return value as we're just about to return anyway.
|
||||
appendVertex(closestEndPos, 0, path[i],
|
||||
straightPath, straightPathFlags, straightPathRefs,
|
||||
straightPathCount, maxStraightPath);
|
||||
|
||||
@@ -1801,7 +1918,7 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en
|
||||
dtVcopy(left, closestEndPos);
|
||||
dtVcopy(right, closestEndPos);
|
||||
|
||||
fromType = toType = DT_POLYTYPE_GROUND;
|
||||
toType = DT_POLYTYPE_GROUND;
|
||||
}
|
||||
|
||||
// Right vertex.
|
||||
@@ -1918,7 +2035,8 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en
|
||||
}
|
||||
}
|
||||
|
||||
stat = appendVertex(closestEndPos, DT_STRAIGHTPATH_END, 0,
|
||||
// Ignore status return value as we're just about to return anyway.
|
||||
appendVertex(closestEndPos, DT_STRAIGHTPATH_END, 0,
|
||||
straightPath, straightPathFlags, straightPathRefs,
|
||||
straightPathCount, maxStraightPath);
|
||||
|
||||
@@ -2389,10 +2507,10 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons
|
||||
|
||||
const dtMeshTile* prevTile, *tile, *nextTile;
|
||||
const dtPoly* prevPoly, *poly, *nextPoly;
|
||||
dtPolyRef curRef, nextRef;
|
||||
dtPolyRef curRef;
|
||||
|
||||
// The API input has been checked already, skip checking internal data.
|
||||
nextRef = curRef = startRef;
|
||||
curRef = startRef;
|
||||
tile = 0;
|
||||
poly = 0;
|
||||
m_nav->getTileAndPolyByRefUnsafe(curRef, &tile, &poly);
|
||||
@@ -2421,6 +2539,9 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons
|
||||
hit->pathCount = n;
|
||||
return status;
|
||||
}
|
||||
|
||||
hit->hitEdgeIndex = segMax;
|
||||
|
||||
// Keep track of furthest t so far.
|
||||
if (tmax > hit->t)
|
||||
hit->t = tmax;
|
||||
@@ -2444,7 +2565,7 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons
|
||||
}
|
||||
|
||||
// Follow neighbours.
|
||||
nextRef = 0;
|
||||
dtPolyRef nextRef = 0;
|
||||
|
||||
for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = tile->links[i].next)
|
||||
{
|
||||
@@ -2635,20 +2756,6 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float*
|
||||
dtStatus status = DT_SUCCESS;
|
||||
|
||||
int n = 0;
|
||||
if (n < maxResult)
|
||||
{
|
||||
if (resultRef)
|
||||
resultRef[n] = startNode->id;
|
||||
if (resultParent)
|
||||
resultParent[n] = 0;
|
||||
if (resultCost)
|
||||
resultCost[n] = 0;
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
const float radiusSqr = dtSqr(radius);
|
||||
|
||||
@@ -2673,6 +2780,21 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float*
|
||||
parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id;
|
||||
if (parentRef)
|
||||
m_nav->getTileAndPolyByRefUnsafe(parentRef, &parentTile, &parentPoly);
|
||||
|
||||
if (n < maxResult)
|
||||
{
|
||||
if (resultRef)
|
||||
resultRef[n] = bestRef;
|
||||
if (resultParent)
|
||||
resultParent[n] = parentRef;
|
||||
if (resultCost)
|
||||
resultCost[n] = bestNode->total;
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next)
|
||||
{
|
||||
@@ -2716,14 +2838,19 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float*
|
||||
if (neighbourNode->flags == 0)
|
||||
dtVlerp(neighbourNode->pos, va, vb, 0.5f);
|
||||
|
||||
const float total = bestNode->total + dtVdist(bestNode->pos, neighbourNode->pos);
|
||||
float cost = filter->getCost(
|
||||
bestNode->pos, neighbourNode->pos,
|
||||
parentRef, parentTile, parentPoly,
|
||||
bestRef, bestTile, bestPoly,
|
||||
neighbourRef, neighbourTile, neighbourPoly);
|
||||
|
||||
const float total = bestNode->total + cost;
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -2733,20 +2860,6 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float*
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n < maxResult)
|
||||
{
|
||||
if (resultRef)
|
||||
resultRef[n] = neighbourNode->id;
|
||||
if (resultParent)
|
||||
resultParent[n] = m_nodePool->getNodeAtIdx(neighbourNode->pidx)->id;
|
||||
if (resultCost)
|
||||
resultCost[n] = neighbourNode->total;
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
neighbourNode->flags = DT_NODE_OPEN;
|
||||
m_openList->push(neighbourNode);
|
||||
}
|
||||
@@ -2815,20 +2928,6 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v
|
||||
dtStatus status = DT_SUCCESS;
|
||||
|
||||
int n = 0;
|
||||
if (n < maxResult)
|
||||
{
|
||||
if (resultRef)
|
||||
resultRef[n] = startNode->id;
|
||||
if (resultParent)
|
||||
resultParent[n] = 0;
|
||||
if (resultCost)
|
||||
resultCost[n] = 0;
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
while (!m_openList->empty())
|
||||
{
|
||||
@@ -2851,6 +2950,22 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v
|
||||
parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id;
|
||||
if (parentRef)
|
||||
m_nav->getTileAndPolyByRefUnsafe(parentRef, &parentTile, &parentPoly);
|
||||
|
||||
if (n < maxResult)
|
||||
{
|
||||
if (resultRef)
|
||||
resultRef[n] = bestRef;
|
||||
if (resultParent)
|
||||
resultParent[n] = parentRef;
|
||||
if (resultCost)
|
||||
resultCost[n] = bestNode->total;
|
||||
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next)
|
||||
{
|
||||
@@ -2896,14 +3011,19 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v
|
||||
if (neighbourNode->flags == 0)
|
||||
dtVlerp(neighbourNode->pos, va, vb, 0.5f);
|
||||
|
||||
const float total = bestNode->total + dtVdist(bestNode->pos, neighbourNode->pos);
|
||||
float cost = filter->getCost(
|
||||
bestNode->pos, neighbourNode->pos,
|
||||
parentRef, parentTile, parentPoly,
|
||||
bestRef, bestTile, bestPoly,
|
||||
neighbourRef, neighbourTile, neighbourPoly);
|
||||
|
||||
const float total = bestNode->total + cost;
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -2913,20 +3033,6 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n < maxResult)
|
||||
{
|
||||
if (resultRef)
|
||||
resultRef[n] = neighbourNode->id;
|
||||
if (resultParent)
|
||||
resultParent[n] = m_nodePool->getNodeAtIdx(neighbourNode->pidx)->id;
|
||||
if (resultCost)
|
||||
resultCost[n] = neighbourNode->total;
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
status |= DT_BUFFER_TOO_SMALL;
|
||||
}
|
||||
neighbourNode->flags = DT_NODE_OPEN;
|
||||
m_openList->push(neighbourNode);
|
||||
}
|
||||
@@ -2938,6 +3044,21 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v
|
||||
return status;
|
||||
}
|
||||
|
||||
dtStatus dtNavMeshQuery::getPathFromDijkstraSearch(dtPolyRef endRef, dtPolyRef* path, int* pathCount, int maxPath) const
|
||||
{
|
||||
if (!m_nav->isValidPolyRef(endRef) || !path || !pathCount || maxPath < 0)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
*pathCount = 0;
|
||||
|
||||
dtNode* endNode;
|
||||
if (m_nodePool->findNodes(endRef, &endNode, 1) != 1 ||
|
||||
(endNode->flags & DT_NODE_CLOSED) == 0)
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
|
||||
return getPathToNode(endNode, path, pathCount, maxPath);
|
||||
}
|
||||
|
||||
/// @par
|
||||
///
|
||||
/// This method is optimized for a small search radius and small number of result
|
||||
|
||||
@@ -22,17 +22,30 @@
|
||||
#include "DetourCommon.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef DT_POLYREF64
|
||||
// From Thomas Wang, https://gist.github.com/badboy/6267743
|
||||
inline unsigned int dtHashRef(dtPolyRef a)
|
||||
{
|
||||
// Edited by TC
|
||||
a = (~a) + (a << 18);
|
||||
a = a ^ (a >> 31);
|
||||
a = a * 21;
|
||||
a = a ^ (a >> 11);
|
||||
a = a + (a << 6);
|
||||
a = a ^ (a >> 22);
|
||||
return (unsigned int)a;
|
||||
a = (~a) + (a << 18); // a = (a << 18) - a - 1;
|
||||
a = a ^ (a >> 31);
|
||||
a = a * 21; // a = (a + (a << 2)) + (a << 4);
|
||||
a = a ^ (a >> 11);
|
||||
a = a + (a << 6);
|
||||
a = a ^ (a >> 22);
|
||||
return (unsigned int)a;
|
||||
}
|
||||
#else
|
||||
inline unsigned int dtHashRef(dtPolyRef a)
|
||||
{
|
||||
a += ~(a<<15);
|
||||
a ^= (a>>10);
|
||||
a += (a<<3);
|
||||
a ^= (a>>6);
|
||||
a += ~(a<<11);
|
||||
a ^= (a>>16);
|
||||
return (unsigned int)a;
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
dtNodePool::dtNodePool(int maxNodes, int hashSize) :
|
||||
@@ -44,7 +57,9 @@ dtNodePool::dtNodePool(int maxNodes, int hashSize) :
|
||||
m_nodeCount(0)
|
||||
{
|
||||
dtAssert(dtNextPow2(m_hashSize) == (unsigned int)m_hashSize);
|
||||
dtAssert(m_maxNodes > 0);
|
||||
// pidx is special as 0 means "none" and 1 is the first node. For that reason
|
||||
// we have 1 fewer nodes available than the number of values it can contain.
|
||||
dtAssert(m_maxNodes > 0 && m_maxNodes <= DT_NULL_IDX && m_maxNodes <= (1 << DT_NODE_PARENT_BITS) - 1);
|
||||
|
||||
m_nodes = (dtNode*)dtAlloc(sizeof(dtNode)*m_maxNodes, DT_ALLOC_PERM);
|
||||
m_next = (dtNodeIndex*)dtAlloc(sizeof(dtNodeIndex)*m_maxNodes, DT_ALLOC_PERM);
|
||||
|
||||
Reference in New Issue
Block a user