// // 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 DETOURNAVMESH_H #define DETOURNAVMESH_H #include "DetourAlloc.h" #include "DetourStatus.h" // Undefine (or define in a build config) 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 #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 #include #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. /// A handle to a polygon within a navigation mesh tile. /// @ingroup detour #ifdef DT_POLYREF64 static const unsigned int DT_SALT_BITS = 16; static const unsigned int DT_TILE_BITS = 28; static const unsigned int DT_POLY_BITS = 20; typedef uint64_t dtPolyRef; #else typedef unsigned int dtPolyRef; #endif /// A handle to a tile within a navigation mesh. /// @ingroup detour #ifdef DT_POLYREF64 typedef uint64_t dtTileRef; #else typedef unsigned int dtTileRef; #endif /// The maximum number of vertices per navigation polygon. /// @ingroup detour 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; /// 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_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(). enum dtTileFlags { /// The navigation mesh owns the tile memory and is responsible for freeing it. DT_TILE_FREE_DATA = 0x01 }; /// Vertex flags returned by dtNavMeshQuery::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. }; /// Options for dtNavMeshQuery::findStraightPath. enum dtStraightPathOptions { 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. }; /// Options for dtNavMeshQuery::initSlicedFindPath and updateSlicedFindPath enum dtFindPathOptions { DT_FINDPATH_ANY_ANGLE = 0x02 ///< use raycasts during pathfind to "shortcut" (raycast still consider costs) }; /// Options for dtNavMeshQuery::raycast enum dtRaycastOptions { DT_RAYCAST_USE_COSTS = 0x01 ///< Raycast should calculate movement cost along the ray and fill RaycastHit::cost }; enum dtDetailTriEdgeFlags { DT_DETAIL_EDGE_BOUNDARY = 0x01 ///< Detail triangle edge is part of the poly boundary }; /// Limit raycasting during any angle pahfinding /// The limit is given as a multiple of the character radius static const float DT_RAY_CAST_LIMIT_PROPORTIONS = 50.0f; /// Flags representing the type of a navigation mesh polygon. enum dtPolyTypes { /// 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 }; /// Defines a polygon within a dtMeshTile object. /// @ingroup detour 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 access this value. unsigned char areaAndtype; /// Sets the user defined area id. [Limit: < #DT_MAX_AREAS] 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. 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. }; /// Defines a link between polygons. /// @note This structure is rarely if ever used by the end user. /// @see dtMeshTile 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. }; /// 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.) }; /// 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; }; /// 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; }; /// 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. [(x, y, z) * 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, triFlags) * dtMeshHeader::detailTriCount]. /// See dtDetailTriEdgeFlags and dtGetDetailTriEdgeFlags. 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 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. private: dtMeshTile(const dtMeshTile&); dtMeshTile& operator=(const dtMeshTile&); }; /// Get flags for edge in detail triangle. /// @param[in] triFlags The flags for the triangle (last component of detail vertices above). /// @param[in] edgeIndex The index of the first vertex of the edge. For instance, if 0, /// returns flags for edge AB. inline int dtGetDetailTriEdgeFlags(unsigned char triFlags, int edgeIndex) { return (triFlags >> (edgeIndex * 2)) & 0x3; } /// 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. This and maxPolys are used to calculate how many bits are needed to identify tiles and polygons uniquely. int maxPolys; ///< The maximum number of polygons each tile can contain. This and maxTiles are used to calculate how many bits are needed to identify tiles and polygons uniquely. }; /// 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. 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 dtStatus init(unsigned char* data, const int dataSize, const int flags); /// The navigation mesh 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. 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. 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) 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; /// 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. /// @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 inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const { #ifdef DT_POLYREF64 const dtPolyRef saltMask = ((dtPolyRef)1<> (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_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. /// @note This function is generally meant for internal use only. /// @param[in] ref The polygon reference. /// @see #encodePolyId inline unsigned int decodePolyIdSalt(dtPolyRef ref) const { #ifdef DT_POLYREF64 const dtPolyRef saltMask = ((dtPolyRef)1<> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask); #else const dtPolyRef saltMask = ((dtPolyRef)1<> (m_polyBits+m_tileBits)) & saltMask); #endif } /// 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 inline unsigned int decodePolyIdTile(dtPolyRef ref) const { #ifdef DT_POLYREF64 const dtPolyRef tileMask = ((dtPolyRef)1<> DT_POLY_BITS) & tileMask); #else const dtPolyRef tileMask = ((dtPolyRef)1<> m_polyBits) & tileMask); #endif } /// 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 inline unsigned int decodePolyIdPoly(dtPolyRef ref) const { #ifdef DT_POLYREF64 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. */