16#include <recastnavigation/RecastDump.h>
17#include <recastnavigation/DetourDebugDraw.h>
18#include <recastnavigation/RecastDebugDraw.h>
28 , _parentScene(parentScene)
30 , _recastInterface( recastInterface )
109 return Util::ConvertData<I32, const char*>( val );
114 return Util::ConvertData<F32, const char*>( val );
119 return _stricmp( val,
"true" ) == 0;
130 if ( !ini.GetSection(
"Rasterization" ) || !ini.GetSection(
"Agent" ) ||
131 !ini.GetSection(
"Region" ) || !ini.GetSection(
"Polygonization" ) ||
132 !ini.GetSection(
"DetailMesh" ) )
137 charToFloat( ini.GetValue(
"Rasterization",
"fCellSize",
"0.3" ) ) );
139 charToFloat( ini.GetValue(
"Rasterization",
"fCellHeight",
"0.2" ) ) );
141 charToInt( ini.GetValue(
"Rasterization",
"iTileSize",
"48" ) ) );
144 charToFloat( ini.GetValue(
"Agent",
"fAgentHeight",
"2.5" ) ) );
146 charToFloat( ini.GetValue(
"Agent",
"fAgentRadius",
"0.5" ) ) );
148 charToFloat( ini.GetValue(
"Agent",
"fAgentMaxClimb",
"1" ) ) );
150 charToFloat( ini.GetValue(
"Agent",
"fAgentMaxSlope",
"20" ) ) );
153 charToInt( ini.GetValue(
"Region",
"fMergeSize",
"20" ) ) );
155 charToInt( ini.GetValue(
"Region",
"fMinSize",
"50" ) ) );
158 charToInt( ini.GetValue(
"Polygonization",
"fEdgeMaxLength",
"12" ) ) );
160 charToFloat( ini.GetValue(
"Polygonization",
"fEdgeMaxError",
"1.3" ) ) );
162 charToInt( ini.GetValue(
"Polygonization",
"iVertsPerPoly",
"6" ) ) );
165 charToFloat( ini.GetValue(
"DetailMesh",
"fDetailSampleDist",
"6" ) ) );
167 charToFloat( ini.GetValue(
"DetailMesh",
"fDetailSampleMaxError",
"1" ) ) );
169 charToBool( ini.GetValue(
"DetailMesh",
"bKeepInterResults",
"false" ) ) );
176 const bool threaded )
224 Time::MicrosecondsToSeconds<F32>( importTimer.
get() ) );
232 dtFreeNavMesh( old );
239 "NavigationMesh Error: Navigation query creation failed!" );
255 Time::MicrosecondsToSeconds<F32>( importTimer.
get() ) );
270 Time::MicrosecondsToSeconds<F32>( importTimer.
get() ) );
275 Time::MicrosecondsToSeconds<F32>( importTimer.
get() ) );
283 dtFreeNavMesh( old );
290 "NavigationMesh Error: Navigation query creation failed!" );
308 assert(
_sgn !=
nullptr );
323 data.name( nodeName );
347 memset( &cfg, 0,
sizeof cfg );
368 rcCalcGridSize( cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height );
370 cfg.bmax[2], cfg.bmin[0], cfg.bmin[1], cfg.bmin[2] );
373 cfg.bmax[2] - cfg.bmin[2] );
382 dtNavMeshCreateParams params;
383 memset( ¶ms, 0,
sizeof params );
384 rcVcopy( params.bmax, cfg.bmax );
385 rcVcopy( params.bmin, cfg.bmin );
389 params.walkableHeight =
to_F32( cfg.walkableHeight );
390 params.walkableRadius =
to_F32( cfg.walkableRadius );
391 params.walkableClimb =
to_F32( cfg.walkableClimb );
395 params.tileLayer = 0;
396 params.buildBvTree =
true;
461 ctx->startTimer( RC_TIMER_TOTAL );
462 ctx->log( RC_LOG_PROGRESS,
"Building navigation:" );
463 ctx->log( RC_LOG_PROGRESS,
" - %d x %d cells", cfg.width, cfg.height );
464 ctx->log( RC_LOG_PROGRESS,
" - %.1fK verts, %.1fK tris",
467 if ( !rcCreateHeightfield( ctx, *
_heightField, cfg.width, cfg.height,
468 cfg.bmin, cfg.bmax, cfg.cs, cfg.ch ) )
485 rcMarkWalkableTriangles( ctx, cfg.walkableSlopeAngle, data.
getVerts(),
499 rcFilterLowHangingWalkableObstacles( ctx, cfg.walkableClimb, *
_heightField );
501 rcFilterLedgeSpans( ctx, cfg.walkableHeight, cfg.walkableClimb,
504 rcFilterWalkableLowHeightSpans( ctx, cfg.walkableHeight, *
_heightField );
509 !rcBuildCompactHeightfield( ctx, cfg.walkableHeight, cfg.walkableClimb,
522 if constexpr( false )
524 if ( !rcBuildRegionsMonotone( ctx, *
_compactHeightField, cfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea ) )
538 cfg.minRegionArea, cfg.mergeRegionArea ) )
564 cfg.detailSampleDist, cfg.detailSampleMaxError,
572 ctx->stopTimer( RC_TIMER_TOTAL );
573 duLogBuildTimes( *ctx, ctx->getAccumulatedTime( RC_TIMER_TOTAL ) );
574 ctx->log( RC_LOG_PROGRESS,
">> Polymesh: %d vertices %d polygons",
578 "[RC_LOG_PROGRESS] Polymesh: %d vertices %d polygons %5.2f ms\n",
580 to_F32( ctx->getAccumulatedTime( RC_TIMER_TOTAL ) / 1000.0f ) );
588 U8* tileData =
nullptr;
589 I32 tileDataSize = 0;
590 if ( !dtCreateNavMeshData( ¶ms, &tileData, &tileDataSize ) )
603 const dtStatus s =
_tempNavMesh->init( tileData, tileDataSize, DT_TILE_FREE_DATA );
604 if ( dtStatusFailed( s ) )
613 const dtMeshTile* tile = ((
const dtNavMesh*)
_tempNavMesh)->getTile( i );
620 const dtPolyRef base =
_tempNavMesh->getPolyRefBase( tile );
622 for (
U32 j = 0; j <
to_U32( tile->header->polyCount ); ++j )
624 const dtPolyRef ref = base | j;
715 const string sourceFile = (
_filePath / file).
string();
717 FILE* fp = fopen( sourceFile.c_str(),
"rb" );
739 dtNavMesh* temp = dtAllocNavMesh();
747 const dtStatus status = temp->init( &header.
params );
749 if ( dtStatusFailed( status ) )
759 fread( &tileHeader,
sizeof tileHeader, 1, fp );
764 U8* data = (
U8*)dtAlloc( tileHeader.
dataSize, DT_ALLOC_PERM );
771 memset( data, 0, tileHeader.
dataSize );
772 fread( data, tileHeader.
dataSize, 1, fp );
774 temp->addTile( data, tileHeader.
dataSize, DT_TILE_FREE_DATA,
797 const string sourceFile = (
_filePath / file).
string();
798 FILE* fp = fopen( sourceFile.c_str(),
"wb" );
816 const dtMeshTile* tile = ((
const dtNavMesh*)
_navMesh)->getTile( i );
818 if ( !tile || !tile->header || !tile->dataSize )
825 memcpy( &header.
params,
_navMesh->getParams(),
sizeof( dtNavMeshParams ) );
831 const dtMeshTile* tile = ((
const dtNavMesh*)
_navMesh)->getTile( i );
833 if ( !tile || !tile->header || !tile->dataSize )
840 tileHeader.
dataSize = tile->dataSize;
842 fwrite( &tileHeader,
sizeof tileHeader, 1, fp );
843 fwrite( tile->data, tile->dataSize, 1, fp );
853 return sgn->parent() !=
nullptr
863 dtPolyRef resultPoly;
876 const U8 maxIters )
const
#define PROFILE_SCOPE_AUTO(CATEGORY)
bool getRandomNavMeshPoint(const NavigationMesh &navMesh, vec3< F32 > &resultPt) const
bool findNearestPointOnNavmesh(const NavigationMesh &navMesh, const vec3< F32 > &position, const vec3< F32 > &extents, F32 delta, vec3< F32 > &resultPt, dtPolyRef &resultPoly) const
bool getRandomPointAroundCircle(const NavigationMesh &navMesh, const vec3< F32 > ¢erPosition, F32 radius, const vec3< F32 > &extents, vec3< F32 > &resultPt, U8 maxIters) const
const F32 * getVerts() const noexcept
U32 getVertCount() const noexcept
U32 getTriCount() const noexcept
const I32 * getTris() const noexcept
NavigationMeshConfig _configParams
rcContourSet * _countourSet
DivideRecast & _recastInterface
bool save(const SceneGraphNode *sgn)
Save the NavigationMesh to a file.
void draw(bool force, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Render the debug mesh if debug drawing is enabled.
Mutex _navigationMeshLock
A mutex for accessing our actual NavigationMesh.
bool unload()
Unload the navmesh reverting the instance to an empty container.
DELEGATE< void, NavigationMesh * > CreationCallback
NavigationMesh(PlatformContext &context, DivideRecast &recastInterface, Scene &parentScene)
bool loadConfigFromFile()
Load nav mesh configuration from file.
static Str< 256 > GenerateMeshName(const SceneGraphNode *sgn)
Create a unique mesh name using the given root node.
bool build(SceneGraphNode *sgn, CreationCallback creationCompleteCallback, bool threaded=true)
I64 _buildJobGUID
A thread for us to update in.
std::atomic_bool _building
A simple flag to say we are building.
CreationCallback _loadCompleteClbk
A callback function to call after building is complete.
void buildInternal()
Used for multithreaded loading.
bool getClosestPosition(const vec3< F32 > &destination, const vec3< F32 > &extents, F32 delta, vec3< F32 > &result) const
bool getRandomPosition(vec3< F32 > &result) const
bool createPolyMesh(const rcConfig &cfg, const NavModelData &data, rcContextDivide *ctx)
Performs the Recast part of the build process.
SceneGraphNode * _sgn
SceneGraphNode from which to build.
std::unique_ptr< NavMeshDebugDraw > _debugDrawInterface
DebugDraw interface.
rcCompactHeightfield * _compactHeightField
dtNavMeshQuery * _navQuery
Query object used for this mesh.
vec3< F32 > _extents
NavMesh extents.
string _configFile
Configuration file.
rcHeightfield * _heightField
bool createNavigationMesh(dtNavMeshCreateParams ¶ms)
Performs the Detour part of the build process.
void stopThreadedBuild()
Stop the threaded build process;.
void freeIntermediates(bool freeAll)
bool createNavigationQuery(U32 maxNodes=2048)
Create a navigation mesh query to help in pathfinding.
Str< 256 > _fileName
Data file to store this nav mesh in.
std::atomic_bool _debugDraw
~NavigationMesh() override
bool load(const SceneGraphNode *sgn)
Load a saved NavigationMesh from a file.
bool buildThreaded()
Initiates the build process in a separate thread.
bool getRandomPositionInCircle(const vec3< F32 > ¢er, F32 radius, const vec3< F32 > &extents, vec3< F32 > &result, U8 maxIters=15) const
rcPolyMeshDetail * _polyMeshDetail
void setDetailSampleMaxError(const F32 detailSampleMaxError)
void setAgentRadius(const F32 agentRadius)
I32 base_getWalkableHeight() const noexcept
I32 base_getWalkableClimb() const noexcept
I32 base_getWalkableRadius() const noexcept
F32 getEdgeMaxError() const noexcept
F32 getCellSize() const noexcept
void setAgentMaxSlope(const F32 agentMaxSlope) noexcept
void setTileSize(const I32 tileSize) noexcept
I32 getRegionMinSize() const noexcept
void setEdgeMaxError(const F32 edgeMaxError) noexcept
void setCellSize(const F32 cellSize)
void setAgentMaxClimb(const F32 agentMaxClimb)
F32 getDetailSampleMaxError() const noexcept
I32 getTileSize() const noexcept
F32 getCellHeight() const noexcept
void setDetailSampleDist(const F32 detailSampleDist)
void setKeepInterResults(const bool keepInterResults) noexcept
void setEdgeMaxLen(const I32 edgeMaxLength)
void setVertsPerPoly(const I32 vertsPerPoly) noexcept
F32 getDetailSampleDist() const noexcept
bool getKeepInterResults() const noexcept
F32 getAgentMaxSlope() const noexcept
I32 getRegionMergeSize() const noexcept
void setAgentHeight(const F32 agentHeight)
I32 getVertsPerPoly() const noexcept
I32 getEdgeMaxLen() const noexcept
void setRegionMergeSize(const I32 regionMergeSize)
void setRegionMinSize(const I32 regionMinSize)
void setCellHeight(const F32 cellHeight)
const BoundingBox & getBoundingBox() const noexcept
Utility class that adds basic GUID management to objects.
PlatformContext & _context
TaskPool & taskPool(const TaskPoolType type) noexcept
FORCE_INLINE T * get() const
Returns a pointer to a specific component. Returns null if the SGN does not have the component reques...
static ResourcePath GetSceneFullPath(const Scene &scene)
Return the full path to the scene's location on disk. It's equivalent to GetSceneRootFolder(scene....
void set(const T *v) noexcept
set the 3 components of the vector manually using a source pointer to a (large enough) array
bool SaveMeshFile(const NavModelData &inData, const ResourcePath &filePath, const char *filename)
Save the navigation input geometry in Wavefront OBJ format.
bool LoadMeshFile(NavModelData &outData, const ResourcePath &filePath, const char *fileName)
Load the input geometry from file (Wavefront OBJ format) and save it in 'outData'.
bool Parse(const BoundingBox &box, NavModelData &outData, SceneGraphNode *sgn)
Parsing method that calls itself recursively until all geometry has been parsed.
F32 charToFloat(const char *val)
bool charToBool(const char *val) noexcept
I32 charToInt(const char *val)
constexpr I32 NAVMESHSET_MAGIC
constexpr I32 NAVMESHSET_VERSION
constexpr F32 BORDER_PADDING
constexpr Optick::Category::Type Streaming
Str StringFormat(const char *fmt, Args &&...args)
bool ReplaceStringInPlace(T_str &subject, std::span< const std::string_view > search, std::string_view replace, bool recursive=false)
std::lock_guard< mutex > LockGuard
constexpr U32 to_U32(const T value)
void Wait(const Task &task, TaskPool &pool)
Task * CreateTask(Predicate &&threadedFunction, bool allowedInIdle=true)
constexpr F32 to_F32(const T value)
void Start(Task &task, TaskPool &pool, TaskPriority priority=TaskPriority::DONT_CARE, const DELEGATE< void > &onCompletionFunction={})
static NO_INLINE void errorfn(const char *format, T &&... args)
static NO_INLINE void printfn(const char *format, T &&... args)