Files
UnrealEngine/Engine/Source/Runtime/Navmesh/Public/Detour/DetourNavMesh.h
2025-05-18 13:04:45 +08:00

1130 lines
43 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
// Modified version of Recast/Detour's source file
//
// 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 "CoreMinimal.h"
#include "Detour/DetourAlloc.h"
#include "Detour/DetourStatus.h"
#include "DetourLargeWorldCoordinates.h"
#include "Logging/LogMacros.h"
NAVMESH_API DECLARE_LOG_CATEGORY_EXTERN(LogDetour, Log, All);
#if WITH_NAVMESH_SEGMENT_LINKS
NAVMESH_API DECLARE_LOG_CATEGORY_EXTERN(LogSegmentLink, Warning, All);
#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.
#ifndef USE_64BIT_ADDRESS
#define USE_64BIT_ADDRESS 1
#endif
#if USE_64BIT_ADDRESS
#if defined(__LP64__)
// LP64 (Linux/OS X): UE will define its uint64 type as "unsigned long long" so we need to match this
typedef unsigned long long UEType_uint64;
#else
#include <stdint.h>
typedef uint64_t UEType_uint64;
#endif
/// A handle to a polygon within a navigation mesh tile.
/// @ingroup detour
typedef UEType_uint64 dtPolyRef;
/// A handle to a tile within a navigation mesh.
/// @ingroup detour
typedef UEType_uint64 dtTileRef;
/// A handle to a cluster within a navigation mesh tile.
typedef UEType_uint64 dtClusterRef;
#else
/// A handle to a polygon within a navigation mesh tile.
/// @ingroup detour
typedef unsigned int dtPolyRef;
/// A handle to a tile within a navigation mesh.
/// @ingroup detour
typedef unsigned int dtTileRef;
/// A handle to a cluster within a navigation mesh tile.
typedef unsigned int dtClusterRef;
#endif // USE_64BIT_ADDRESS
/// 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.
/// UE magic removed to save memory
//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.
inline 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 char DT_OFFMESH_CON_BIDIR = 0x01;
static const unsigned char DT_OFFMESH_CON_POINT = 0x02; //UE
static const unsigned char DT_OFFMESH_CON_SEGMENT = 0x04; //UE
static const unsigned char DT_OFFMESH_CON_CHEAPAREA = 0x08; //UE
static const unsigned char DT_OFFMESH_CON_GENERATED = 0x10; //UE
/// The maximum number of user defined area ids.
/// @ingroup detour
static const int DT_MAX_AREAS = 64;
//@UE BEGIN
/// Navmesh tiles' salt will have at least this much bits
static const int DT_MIN_SALT_BITS = 5;
static const int DT_SALT_BASE = 1;
static const int DT_RESOLUTION_COUNT = 3;
#if WITH_NAVMESH_SEGMENT_LINKS
/// Max segment parts for segment-to-segment off mesh connection
static const int DT_MAX_OFFMESH_SEGMENT_PARTS = 4;
static const int DT_INVALID_SEGMENT_PART = 0xffff;
#endif // WITH_NAVMESH_SEGMENT_LINKS
/// flags use to annotate dtLink::side with addotional data
static const unsigned char DT_CONNECTION_INTERNAL = (1 << 7);
static const unsigned char DT_LINK_FLAG_OFFMESH_CON = (1 << 6);
static const unsigned char DT_LINK_FLAG_OFFMESH_CON_BIDIR = (1 << 5);
static const unsigned char DT_LINK_FLAG_OFFMESH_CON_BACKTRACKER = (1 << 4);
static const unsigned char DT_LINK_FLAG_OFFMESH_CON_ENABLED = (1 << 3);
static const unsigned char DT_LINK_FLAG_SIDE_MASK = 7;
#if WITH_NAVMESH_CLUSTER_LINKS
/// flags used to annotate dtClusterLink::flags with additional data
static const unsigned char DT_CLINK_VALID_FWD = 0x01;
static const unsigned char DT_CLINK_VALID_BCK = 0x02;
/// Index of first cluster link within tile
static const unsigned int DT_CLINK_FIRST = 0x80000000;
#endif // WITH_NAVMESH_CLUSTER_LINKS
//@UE END
//@UE BEGIN Adding support for memory tracking.
struct dtMeshTile;
typedef void (dtStatsPostAddTileFunc)(const dtMeshTile& TileAdd);
typedef void (dtStatsPreRemoveTileFunc)(const dtMeshTile& tileRemove);
NAVMESH_API void dtStatsSetCustom(dtStatsPostAddTileFunc* addFunc, dtStatsPreRemoveTileFunc* removeFunc);
//@UE END Adding support for memory tracking.
/// Tile flags used for various functions and fields.
/// For an example, see dtNavMesh::addTile().
enum dtTileFlags
{
DT_TILE_FREE_DATA = 0x01, ///< The navigation mesh owns the tile memory and is responsible for freeing it.
};
/// 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.
};
/// 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_POINT = 1,
//@UE BEGIN
#if WITH_NAVMESH_SEGMENT_LINKS
/// The polygon is an off-mesh connection consisting of four vertices.
DT_POLYTYPE_OFFMESH_SEGMENT = 2,
#endif // WITH_NAVMESH_SEGMENT_LINKS
//@UE END
};
/// Defines a polyogn 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 acess this value.
unsigned char areaAndtype;
/// Sets the user defined area id. [Limit: < #DT_MAX_AREAS]
inline void setArea(unsigned char a) { areaAndtype = static_cast<unsigned char>((areaAndtype & 0xc0) | (a & 0x3f)); }
/// Sets the polygon type. (See: #dtPolyTypes.)
inline void setType(unsigned char t) { areaAndtype = static_cast<unsigned char>((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 short vertBase; ///< The offset of the vertices in the dtMeshTile::detailVerts array.
unsigned short 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.)
};
//@UE BEGIN
#if WITH_NAVMESH_SEGMENT_LINKS
/// This is an experimental feature and has not been finished to production quality.
struct dtOffMeshSegmentConnection
{
dtReal startA[3]; ///< Start point of segment A
dtReal endA[3]; ///< End point of segment A
dtReal startB[3]; ///< Start point of segment B
dtReal endB[3]; ///< End point of segment B
/// The radius of the endpoints. [Limit: >= 0]
dtReal rad;
/// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
unsigned int userId;
/// First poly in segment pool (+ header->offMeshSegPolyBase)
unsigned short firstPoly;
/// Number of created polys
unsigned char npolys;
/// Link flags.
unsigned char flags;
/// Sets link flags
inline void setFlags(unsigned char conFlags)
{
flags = ((conFlags & DT_OFFMESH_CON_BIDIR) ? 0x80 : 0);
}
/// Gets the link direction
inline bool getBiDirectional() const { return (flags & 0x80) != 0; }
};
#endif // WITH_NAVMESH_SEGMENT_LINKS
//@UE END
/// 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)]
dtReal pos[6];
/// The radius of the endpoints. [Limit: >= 0]
dtReal rad;
//@UE BEGIN
/// The snap height of endpoints (less than 0 = use step height)
dtReal height;
//@UE END
/// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
unsigned long long int userId;
/// The polygon reference of the connection within the tile.
unsigned short poly;
/// End point side.
unsigned char side;
/// Link flags.
unsigned char flags;
//@UE BEGIN
/// Sets link flags
inline void setFlags(unsigned char conTypeFlags)
{
flags = ((conTypeFlags & DT_OFFMESH_CON_BIDIR) ? 0x80 : 0) |
((conTypeFlags & DT_OFFMESH_CON_CHEAPAREA) ? 0x40 : 0) |
((conTypeFlags & DT_OFFMESH_CON_GENERATED) ? 0x20 : 0);
}
/// Gets the link direction
inline bool getBiDirectional() const { return (flags & 0x80) != 0; }
/// Gets the link snap mode
inline bool getSnapToCheapestArea() const { return (flags & 0x40) != 0; }
/// Indicates if the link was automatically generated
inline bool getIsGenerated() const { return (flags & 0x20) != 0; }
//@UE END
};
//@UE BEGIN
#if WITH_NAVMESH_CLUSTER_LINKS
/// Cluster of polys
struct dtCluster
{
dtReal center[3]; ///< Center pos of cluster
unsigned int firstLink; ///< Link in dtMeshTile.links array
unsigned int numLinks; ///< Number of cluster links
};
/// Links between clusters
struct dtClusterLink
{
dtClusterRef ref; ///< Destination tile and cluster
unsigned int next; ///< Next link in dtMeshTile.links array
unsigned char flags; ///< Link traversing data
};
#endif // WITH_NAVMESH_CLUSTER_LINKS
//@UE END
/// Provides high level information related to a dtMeshTile object.
/// @ingroup detour
struct dtMeshHeader
{
unsigned short version; ///< Tile data format version number.
unsigned short layer; ///< The layer of the tile within the dtNavMesh tile grid. (x, y, layer)
unsigned short polyCount; ///< The number of polygons in the tile.
unsigned short vertCount; ///< The number of vertices in the tile.
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)
unsigned short maxLinkCount; ///< The number of allocated links.
unsigned short 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.)
unsigned short detailVertCount;
unsigned short detailTriCount; ///< The number of triangles in the detail mesh.
unsigned short bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
unsigned short offMeshConCount; ///< The number of point type off-mesh connections.
unsigned short offMeshBase; ///< The index of the first polygon which is a point type off-mesh connection.
//@UE BEGIN
#if WITH_NAVMESH_SEGMENT_LINKS
unsigned short offMeshSegConCount; ///< The number of segment type off-mesh connections.
unsigned short offMeshSegPolyBase; ///< The index of the first polygon which is an segment type off-mesh connection
unsigned short offMeshSegVertBase; ///< The index of the first vertex used by segment type off-mesh connection
#endif // WITH_NAVMESH_SEGMENT_LINKS
#if WITH_NAVMESH_CLUSTER_LINKS
unsigned short clusterCount; ///< Number of clusters
#endif // WITH_NAVMESH_CLUSTER_LINKS
unsigned char resolution; ///< The resolution index used for the tile.
//@UE END
// These should be at the bottom, as they are less often used than the rest of the data. The rest will fit in one cache line.
dtReal bmin[3]; ///< The minimum bounds of the tile's AABB. [(x, y, z)]
dtReal bmax[3]; ///< The maximum bounds of the tile's AABB. [(x, y, z)]
};
/// 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]
dtReal* verts; ///< The tile vertices. [Size: dtMeshHeader::vertCount (3 real per vertex)]
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]
dtReal* detailVerts;
/// The detail mesh's triangles. [(vertA, vertB, vertC) * dtMeshHeader::detailTriCount]
unsigned char* detailTris;
/// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount]
/// (Will be null if bounding volumes are disabled.)
dtBVNode* bvTree;
dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
unsigned 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.
//@UE BEGIN
#if WITH_NAVMESH_SEGMENT_LINKS
dtOffMeshSegmentConnection* offMeshSeg; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshSegConCount]
#endif // WITH_NAVMESH_SEGMENT_LINKS
#if WITH_NAVMESH_CLUSTER_LINKS
dtCluster* clusters; ///< Cluster data
unsigned short* polyClusters; ///< Cluster Id for each ground type polygon [Size: dtMeshHeader::polyCount]
dtChunkArray<dtClusterLink, DT_ALLOC_PERM_TILE_DYNLINK_CLUSTER> dynamicLinksC; ///< Dynamic links array (indices starting from DT_CLINK_FIRST)
#endif // WITH_NAVMESH_CLUSTER_LINKS
dtChunkArray<dtLink, DT_ALLOC_PERM_TILE_DYNLINK_OFFMESH> dynamicLinksO; ///< Dynamic links array (indices starting from dtMeshHeader::maxLinkCount)
unsigned int dynamicFreeListO; ///< Index of the next free dynamic link
#if WITH_NAVMESH_CLUSTER_LINKS
unsigned int dynamicFreeListC; ///< Index of the next free dynamic link
#endif // WITH_NAVMESH_CLUSTER_LINKS
//@UE END
};
//@UE BEGIN
/// Configuration parameters depending on navmesh resolution.
struct dtNavMeshResParams
{
dtReal bvQuantFactor; ///< The bounding volume quantization factor.
};
//@UE END
/// 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
{
//@UE BEGIN
dtReal walkableHeight; ///< The height of the agents using the tile.
dtReal walkableRadius; ///< The radius of the agents using the tile.
dtReal walkableClimb; ///< The maximum climb height of the agents using the tile.
dtNavMeshResParams resolutionParams[DT_RESOLUTION_COUNT]; ///< Parameters depending on resolutions.
//@UE END
dtReal orig[3]; ///< The world space origin of the navigation mesh's tile space. [(x, y, z)]
dtReal tileWidth; ///< The width of each tile. (Along the x-axis.)
dtReal tileHeight; ///< The height of each tile. (Along the z-axis.)
int maxTiles; ///< The maximum number of tiles the navigation mesh can contain.
int maxPolys; ///< The maximum number of polygons each tile can contain.
};
/// A navigation mesh based on tiles of convex polygons.
/// @ingroup detour
class dtNavMesh
{
public:
NAVMESH_API dtNavMesh();
NAVMESH_API ~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.
NAVMESH_API 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
NAVMESH_API dtStatus init(unsigned char* data, const int dataSize, const int flags);
/// The navigation mesh initialization params.
NAVMESH_API 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.
NAVMESH_API dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
#if WITH_NAVMESH_SEGMENT_LINKS
/// Create segment link connections within a tile.
/// @param[in] tileRef The tileRef of the tile owning the segment link connections.
/// @param[in] maxSkippedNeighborTiles The max number of neighbor indices that can be held in skippedNeighborTiles.
/// @param[out] skippedNeighborTiles Array containing the indices of the neighbor tiles processed.
/// @param[out] numSkippedNeighborTiles The number of neighbor tiles skipped during link connection.
NAVMESH_API void processSegmentLinksForTile(dtTileRef tileRef, unsigned int maxSkippedNeighborTiles, dtTileRef* skippedNeighborTiles, unsigned int& numSkippedNeighborTiles);
#endif // WITH_NAVMESH_SEGMENT_LINKS
/// 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.
NAVMESH_API 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)
NAVMESH_API void calcTileLoc(const dtReal* pos, int* tx, int* ty) const;
/// Calculates whether the tile grid location for the specified world position
/// can fit in the tile indices type (currently an int)
/// @param[in] pos The world position for the query. [(x, y, z)]
NAVMESH_API bool isTileLocInValidRange(const dtReal* pos) 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.
NAVMESH_API const dtMeshTile* getTileAt(const int x, const int y, const int layer) const;
// @UE BEGIN
/// Gets number of 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)
/// @return The number of tiles in grid.
NAVMESH_API int getTileCountAt(const int x, const int y) const;
// @UE END
/// 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API const dtMeshTile* getTileByRef(dtTileRef ref) 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.
NAVMESH_API dtMeshTile* getMutableTileByRef(dtTileRef ref) const;
/// The maximum number of tiles supported by the navigation mesh.
/// @return The maximum number of tiles supported by the navigation mesh.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API dtPolyRef getPolyRefBase(const dtMeshTile* tile) const;
/// Gets the cluster reference for the tile's base cluster.
/// @param[in] tile The tile.
/// @return The cluster reference for the base cluster in the specified tile.
NAVMESH_API dtClusterRef getClusterRefBase(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[in] currentPos Position before entering off-mesh connection [(x, y, z)]
/// @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.
NAVMESH_API dtStatus getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef polyRef, const dtReal* currentPos, dtReal* startPos, dtReal* endPos) const;
/// Gets the specified off-mesh connection: point type.
/// @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.
NAVMESH_API const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
/// Updates area and flags for specified off-mesh connection: point type
/// @param[in] userId User Id of connection
/// @param[in] newArea Area code to apply
NAVMESH_API void updateOffMeshConnectionByUserId(unsigned long long int userId, unsigned char newArea, unsigned short newFlags);
//@UE BEGIN
#if WITH_NAVMESH_SEGMENT_LINKS
/// Gets the specified off-mesh connection: segment type
/// @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.
NAVMESH_API const dtOffMeshSegmentConnection* getOffMeshSegmentConnectionByRef(dtPolyRef ref) const;
/// Updates area and flags for specified off-mesh connection: segment type
/// @param[in] userId User Id of connection
/// @param[in] newArea Area code to apply
NAVMESH_API void updateOffMeshSegmentConnectionByUserId(unsigned int userId, unsigned char newArea, unsigned short newFlags);
#endif // WITH_NAVMESH_SEGMENT_LINKS
//@UE END
/// @}
/// @{
/// @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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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.
NAVMESH_API 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
{
return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
}
/// Decodes a standard polygon reference.
/// @note This function is generally meant for internal use only.
/// @param[in] ref The polygon reference to decode.
/// @param[out] salt The tile's salt value.
/// @param[out] it The index of the tile.
/// @param[out] ip The index of the polygon within the tile.
/// @see #encodePolyId
inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
{
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);
}
/// 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
{
const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
}
/// Extracts the tile's index from the specified polygon reference.
/// @note This function is generally meant for internal use only.
/// @param[in] ref The polygon reference.
/// @see #encodePolyId
inline unsigned int decodePolyIdTile(dtPolyRef ref) const
{
const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
return (unsigned int)((ref >> m_polyBits) & tileMask);
}
/// Extracts the polygon's index (within its tile) from the specified polygon reference.
/// @note This function is generally meant for internal use only.
/// @param[in] ref The polygon reference.
/// @see #encodePolyId
inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
{
const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
return (unsigned int)(ref & polyMask);
}
/// Extracts the tile's index from the specified cluster reference.
/// @note This function is generally meant for internal use only.
/// @param[in] ref The cluster reference.
inline unsigned int decodeClusterIdTile(dtClusterRef ref) const
{
return decodePolyIdTile(ref);
}
//@UE BEGIN
#if WITH_NAVMESH_CLUSTER_LINKS
/// Extracts the cluster's index (within its tile) from the specified cluster reference.
/// @note This function is generally meant for internal use only.
/// @param[in] ref The cluster reference.
inline unsigned int decodeClusterIdCluster(dtClusterRef ref) const
{
return decodePolyIdPoly(ref);
}
#endif // WITH_NAVMESH_CLUSTER_LINKS
/// Shift navigation mesh by provided offset
NAVMESH_API void applyWorldOffset(const dtReal* offset);
/// Helper for accessing links
inline dtLink& getLink(dtMeshTile* tile, unsigned int linkIdx)
{
return (linkIdx < (unsigned int)tile->header->maxLinkCount) ? tile->links[linkIdx] : tile->dynamicLinksO[linkIdx - tile->header->maxLinkCount];
}
inline const dtLink& getLink(const dtMeshTile* tile, unsigned int linkIdx) const
{
return (linkIdx < (unsigned int)tile->header->maxLinkCount) ? tile->links[linkIdx] : tile->dynamicLinksO[linkIdx - tile->header->maxLinkCount];
}
#if WITH_NAVMESH_CLUSTER_LINKS
/// Helper for accessing cluster links
inline dtClusterLink& getClusterLink(dtMeshTile* tile, unsigned int linkIdx)
{
return tile->dynamicLinksC[linkIdx - DT_CLINK_FIRST];
}
inline const dtClusterLink& getClusterLink(const dtMeshTile* tile, unsigned int linkIdx) const
{
return tile->dynamicLinksC[linkIdx - DT_CLINK_FIRST];
}
#endif // WITH_NAVMESH_CLUSTER_LINKS
/// Helper for creating links in off-mesh connections
NAVMESH_API void linkOffMeshHelper(dtMeshTile* tile0, unsigned int polyIdx0, const dtMeshTile* tile1, unsigned int polyIdx1, unsigned char side, unsigned char edge);
inline bool isEmpty() const
{
// has no tile grid set up
return (m_tileWidth > 0 && m_tileHeight > 0) == false;
}
inline unsigned int getSaltBits() const
{
return m_saltBits;
}
NAVMESH_API void applyAreaCostOrder(unsigned char* costOrder);
/// Returns neighbour tile count based on side of given tile.
NAVMESH_API int getNeighbourTilesCountAt(const int x, const int y, const int side) const;
bool getNeighbourCoords(const int x, const int y, const int side, int& outX, int& outY) const
{
outX = x;
outY = y;
switch (side)
{
case 0: ++outX; break;
case 1: ++outX; ++outY; break;
case 2: ++outY; break;
case 3: --outX; ++outY; break;
case 4: --outX; break;
case 5: --outX; --outY; break;
case 6: --outY; break;
case 7: ++outX; --outY; break;
};
// @todo we might want to do some validation
return true;
}
unsigned int getTileIndex(const dtMeshTile* tile) const
{
return (unsigned int)(tile - m_tiles);
}
//@UE END
/// @}
//@UE Begin LWCoords
dtReal getWalkableHeight() const { return m_params.walkableHeight; }
dtReal getWalkableRadius() const { return m_params.walkableRadius; }
dtReal getWalkableClimb() const { return m_params.walkableClimb; }
dtReal getBVQuantFactor(const unsigned char resolution) const { return m_params.resolutionParams[resolution].bvQuantFactor; }
//@UE END LWCoords
private:
// [UE] result struct for findConnectingPolys
struct FConnectingPolyData
{
dtReal min;
dtReal max;
dtPolyRef ref;
};
/// Returns pointer to tile in the tile array.
NAVMESH_API dtMeshTile* getTile(int i);
/// Returns the tile at the coordinates.
NAVMESH_API int getTilesAt(const int x, const int y,
dtMeshTile** tiles, const int maxTiles) const;
/// Returns neighbour tile based on side.
NAVMESH_API int getNeighbourTilesAt(const int x, const int y, const int side,
dtMeshTile** tiles, const int maxTiles) const;
/// [UE] Returns all polygons in neighbour tile based on portal defined by the segment.
NAVMESH_API int findConnectingPolys(const dtReal* va, const dtReal* vb,
const dtMeshTile* fromTile, int fromPolyIdx,
const dtMeshTile* tile, int side,
dtChunkArray<FConnectingPolyData>& cons) const;
/// Builds internal polygons links for a tile.
NAVMESH_API void connectIntLinks(dtMeshTile* tile);
/// Builds internal polygons links for a tile.
NAVMESH_API void baseOffMeshLinks(dtMeshTile* tile);
/// Builds external polygon links for a tile.
NAVMESH_API void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side, bool updateCLinks);
/// Builds external polygon links for a tile.
NAVMESH_API void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side, bool updateCLinks);
/// Removes external links at specified side.
NAVMESH_API void unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target);
//@UE BEGIN
#if WITH_NAVMESH_CLUSTER_LINKS
/// Try to connect clusters
NAVMESH_API void connectClusterLink(dtMeshTile* tile0, unsigned int cluster0,
dtMeshTile* tile1, unsigned int cluster1,
unsigned char flags, bool bCheckExisting = true);
/// Removes cluster links at specified side.
NAVMESH_API void unconnectClusterLinks(dtMeshTile* tile, dtMeshTile* target);
#endif // WITH_NAVMESH_CLUSTER_LINKS
//@UE END
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.
/// Queries polygons within a tile.
NAVMESH_API int queryPolygonsInTile(const dtMeshTile* tile, const dtReal* qmin, const dtReal* qmax,
dtPolyRef* polys, const int maxPolys, bool bExcludeUnwalkable = false) const;
/// Find nearest polygon within a tile.
NAVMESH_API dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const dtReal* center,
const dtReal* extents, dtReal* nearestPt, bool bExcludeUnwalkable = false) const;
NAVMESH_API dtPolyRef findCheapestNearPolyInTile(const dtMeshTile* tile, const dtReal* center,
const dtReal* extents, dtReal* nearestPt) const;
/// Returns closest point on polygon.
NAVMESH_API void closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip,
const dtReal* pos, dtReal* closest) const;
private:
/// Calculates whether the tile grid location can fit in the tile indices type (currently an int)
/// @param[in] tx Tile X coord
/// @param[in] ty Tile Y coord
NAVMESH_API bool isTileLocInValidRange(const dtReal tx, const dtReal ty) const;
NAVMESH_API void calcTileLoc(const dtReal* pos, dtReal* tx, dtReal* ty) const;
public:
dtNavMeshParams m_params; ///< Current initialization params.
dtReal m_orig[3]; ///< Origin of the tile (0,0)
dtReal m_tileWidth, m_tileHeight; ///< Dimensions of each tile.
int m_maxTiles; ///< Max number of tiles.
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
int m_tileLutMask; ///< Tile hash lookup mask.
unsigned char m_areaCostOrder[DT_MAX_AREAS];
dtMeshTile** m_posLookup; ///< Tile hash lookup.
dtMeshTile* m_nextFree; ///< Freelist of tiles.
dtMeshTile* m_tiles; ///< List of tiles.
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.
};
/// Allocates a navigation mesh object using the Detour allocator.
/// @return A navigation mesh that is ready for initialization, or null on failure.
/// @ingroup detour
NAVMESH_API dtNavMesh* dtAllocNavMesh();
/// Frees the specified navigation mesh object using the Detour allocator.
/// @param[in] navmesh A navigation mesh allocated using #dtAllocNavMesh
/// @ingroup detour
NAVMESH_API void dtFreeNavMesh(dtNavMesh* navmesh);
// @UE BEGIN: helper for reading tiles
struct ReadTilesHelper
{
static const int MaxTiles = 32;
dtMeshTile* Tiles[MaxTiles];
int NumAllocated;
dtMeshTile** AllocatedTiles;
ReadTilesHelper() : NumAllocated(0), AllocatedTiles(0) {}
~ReadTilesHelper()
{
dtFree(AllocatedTiles, DT_ALLOC_TEMP);
}
dtMeshTile** PrepareArray(int RequestedSize)
{
if (RequestedSize < MaxTiles)
{
return Tiles;
}
if (NumAllocated < RequestedSize)
{
dtFree(AllocatedTiles, DT_ALLOC_TEMP);
AllocatedTiles = (dtMeshTile**)dtAlloc(RequestedSize * sizeof(dtMeshTile*), DT_ALLOC_TEMP);
NumAllocated = AllocatedTiles != nullptr ? RequestedSize : 0;
}
return AllocatedTiles;
}
};
// @UE END
#endif // DETOURNAVMESH_H
///////////////////////////////////////////////////////////////////////////
// This section contains detailed documentation for members that don't have
// a source file. It reduces clutter in the main section of the header.
/**
@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 dtReal dtNavMesh::bvQuantFactor
@par
This value is used for converting between world and bounding volume coordinates.
For example:
@code
const dtReal cs = 1.0f / bvQuantFactor;
const dtBVNode* n = &tile->bvTree[i];
if (n->i >= 0)
{
// This is a leaf node.
dtReal worldMinX = tile->header->bmin[0] + n->bmin[0]*cs;
dtReal 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 dtReal 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.
*/