DynamicNavigationMesh.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Navigation/DynamicNavigationMesh.h"
  23. #include "../Math/BoundingBox.h"
  24. #include "../Core/Context.h"
  25. #include "../Navigation/CrowdAgent.h"
  26. #include "../Graphics/DebugRenderer.h"
  27. #include "../IO/Log.h"
  28. #include "../IO/MemoryBuffer.h"
  29. #include "../Navigation/NavArea.h"
  30. #include "../Navigation/NavBuildData.h"
  31. #include "../Navigation/NavigationEvents.h"
  32. #include "../Scene/Node.h"
  33. #include "../Navigation/Obstacle.h"
  34. #include "../Navigation/OffMeshConnection.h"
  35. #include "../Core/Profiler.h"
  36. #include "../Scene/Scene.h"
  37. #include "../Scene/SceneEvents.h"
  38. #include <LZ4/lz4.h>
  39. #include <cfloat>
  40. #include <Detour/include/DetourNavMesh.h>
  41. #include <Detour/include/DetourNavMeshBuilder.h>
  42. #include <Detour/include/DetourNavMeshQuery.h>
  43. #include <DetourTileCache/include/DetourTileCache.h>
  44. #include <DetourTileCache/include/DetourTileCacheBuilder.h>
  45. #include <Recast/include/Recast.h>
  46. #include <Recast/include/RecastAlloc.h>
  47. //DebugNew is deliberately not used because the macro 'free' conflicts DetourTileCache's LinearAllocator interface
  48. //#include "../DebugNew.h"
  49. #define TILECACHE_MAXLAYERS 128
  50. namespace Atomic
  51. {
  52. extern const char* NAVIGATION_CATEGORY;
  53. static const int DEFAULT_MAX_OBSTACLES = 1024;
  54. struct DynamicNavigationMesh::TileCacheData
  55. {
  56. unsigned char* data;
  57. int dataSize;
  58. };
  59. struct TileCompressor : public dtTileCacheCompressor
  60. {
  61. virtual int maxCompressedSize(const int bufferSize)
  62. {
  63. return (int)(bufferSize* 1.05f);
  64. }
  65. virtual dtStatus compress(const unsigned char* buffer, const int bufferSize,
  66. unsigned char* compressed, const int /*maxCompressedSize*/, int* compressedSize)
  67. {
  68. *compressedSize = LZ4_compress((const char*)buffer, (char*)compressed, bufferSize);
  69. return DT_SUCCESS;
  70. }
  71. virtual dtStatus decompress(const unsigned char* compressed, const int compressedSize,
  72. unsigned char* buffer, const int maxBufferSize, int* bufferSize)
  73. {
  74. *bufferSize = LZ4_decompress_safe((const char*)compressed, (char*)buffer, compressedSize, maxBufferSize);
  75. return *bufferSize < 0 ? DT_FAILURE : DT_SUCCESS;
  76. }
  77. };
  78. struct MeshProcess : public dtTileCacheMeshProcess
  79. {
  80. DynamicNavigationMesh* owner_;
  81. PODVector<Vector3> offMeshVertices_;
  82. PODVector<float> offMeshRadii_;
  83. PODVector<unsigned short> offMeshFlags_;
  84. PODVector<unsigned char> offMeshAreas_;
  85. PODVector<unsigned char> offMeshDir_;
  86. inline MeshProcess(DynamicNavigationMesh* owner) :
  87. owner_(owner)
  88. {
  89. }
  90. virtual void process(struct dtNavMeshCreateParams* params, unsigned char* polyAreas, unsigned short* polyFlags)
  91. {
  92. // Update poly flags from areas.
  93. // \todo Assignment of flags from areas?
  94. for (int i = 0; i < params->polyCount; ++i)
  95. {
  96. if (polyAreas[i] != RC_NULL_AREA)
  97. polyFlags[i] = RC_WALKABLE_AREA;
  98. }
  99. BoundingBox bounds;
  100. rcVcopy(&bounds.min_.x_, params->bmin);
  101. rcVcopy(&bounds.max_.x_, params->bmin);
  102. // collect off-mesh connections
  103. PODVector<OffMeshConnection*> offMeshConnections = owner_->CollectOffMeshConnections(bounds);
  104. if (offMeshConnections.Size() > 0)
  105. {
  106. if (offMeshConnections.Size() != offMeshRadii_.Size())
  107. {
  108. Matrix3x4 inverse = owner_->GetNode()->GetWorldTransform().Inverse();
  109. ClearConnectionData();
  110. for (unsigned i = 0; i < offMeshConnections.Size(); ++i)
  111. {
  112. OffMeshConnection* connection = offMeshConnections[i];
  113. Vector3 start = inverse * connection->GetNode()->GetWorldPosition();
  114. Vector3 end = inverse * connection->GetEndPoint()->GetWorldPosition();
  115. offMeshVertices_.Push(start);
  116. offMeshVertices_.Push(end);
  117. offMeshRadii_.Push(connection->GetRadius());
  118. offMeshFlags_.Push(connection->GetMask());
  119. offMeshAreas_.Push((unsigned char)connection->GetAreaID());
  120. offMeshDir_.Push(connection->IsBidirectional() ? DT_OFFMESH_CON_BIDIR : 0);
  121. }
  122. }
  123. params->offMeshConCount = offMeshRadii_.Size();
  124. params->offMeshConVerts = &offMeshVertices_[0].x_;
  125. params->offMeshConRad = &offMeshRadii_[0];
  126. params->offMeshConFlags = &offMeshFlags_[0];
  127. params->offMeshConAreas = &offMeshAreas_[0];
  128. params->offMeshConDir = &offMeshDir_[0];
  129. }
  130. }
  131. void ClearConnectionData()
  132. {
  133. offMeshVertices_.Clear();
  134. offMeshRadii_.Clear();
  135. offMeshFlags_.Clear();
  136. offMeshAreas_.Clear();
  137. offMeshDir_.Clear();
  138. }
  139. };
  140. // From the Detour/Recast Sample_TempObstacles.cpp
  141. struct LinearAllocator : public dtTileCacheAlloc
  142. {
  143. unsigned char* buffer;
  144. int capacity;
  145. int top;
  146. int high;
  147. LinearAllocator(const int cap) : buffer(0), capacity(0), top(0), high(0)
  148. {
  149. resize(cap);
  150. }
  151. ~LinearAllocator()
  152. {
  153. dtFree(buffer);
  154. }
  155. void resize(const int cap)
  156. {
  157. if (buffer)
  158. dtFree(buffer);
  159. buffer = (unsigned char*)dtAlloc(cap, DT_ALLOC_PERM);
  160. capacity = cap;
  161. }
  162. virtual void reset()
  163. {
  164. high = Max(high, top);
  165. top = 0;
  166. }
  167. virtual void* alloc(const int size)
  168. {
  169. if (!buffer)
  170. return 0;
  171. if (top + size > capacity)
  172. return 0;
  173. unsigned char* mem = &buffer[top];
  174. top += size;
  175. return mem;
  176. }
  177. virtual void free(void*)
  178. {
  179. }
  180. };
  181. DynamicNavigationMesh::DynamicNavigationMesh(Context* context) :
  182. NavigationMesh(context),
  183. tileCache_(0),
  184. maxObstacles_(1024),
  185. drawObstacles_(false)
  186. {
  187. //64 is the largest tile-size that DetourTileCache will tolerate without silently failing
  188. tileSize_ = 64;
  189. partitionType_ = NAVMESH_PARTITION_MONOTONE;
  190. allocator_ = new LinearAllocator(32000); //32kb to start
  191. compressor_ = new TileCompressor();
  192. meshProcessor_ = new MeshProcess(this);
  193. }
  194. DynamicNavigationMesh::~DynamicNavigationMesh()
  195. {
  196. ReleaseNavigationMesh();
  197. delete allocator_;
  198. allocator_ = 0;
  199. delete compressor_;
  200. compressor_ = 0;
  201. delete meshProcessor_;
  202. meshProcessor_ = 0;
  203. }
  204. void DynamicNavigationMesh::RegisterObject(Context* context)
  205. {
  206. context->RegisterFactory<DynamicNavigationMesh>(NAVIGATION_CATEGORY);
  207. COPY_BASE_ATTRIBUTES(NavigationMesh);
  208. ACCESSOR_ATTRIBUTE("Max Obstacles", GetMaxObstacles, SetMaxObstacles, unsigned, DEFAULT_MAX_OBSTACLES, AM_DEFAULT);
  209. ACCESSOR_ATTRIBUTE("Draw Obstacles", GetDrawObstacles, SetDrawObstacles, bool, false, AM_DEFAULT);
  210. }
  211. bool DynamicNavigationMesh::Build()
  212. {
  213. PROFILE(BuildNavigationMesh);
  214. // Release existing navigation data and zero the bounding box
  215. ReleaseNavigationMesh();
  216. if (!node_)
  217. return false;
  218. if (!node_->GetWorldScale().Equals(Vector3::ONE))
  219. LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended");
  220. Vector<NavigationGeometryInfo> geometryList;
  221. CollectGeometries(geometryList);
  222. if (geometryList.Empty())
  223. return true; // Nothing to do
  224. // Build the combined bounding box
  225. for (unsigned i = 0; i < geometryList.Size(); ++i)
  226. boundingBox_.Merge(geometryList[i].boundingBox_);
  227. // Expand bounding box by padding
  228. boundingBox_.min_ -= padding_;
  229. boundingBox_.max_ += padding_;
  230. {
  231. PROFILE(BuildNavigationMesh);
  232. // Calculate number of tiles
  233. int gridW = 0, gridH = 0;
  234. float tileEdgeLength = (float)tileSize_ * cellSize_;
  235. rcCalcGridSize(&boundingBox_.min_.x_, &boundingBox_.max_.x_, cellSize_, &gridW, &gridH);
  236. numTilesX_ = (gridW + tileSize_ - 1) / tileSize_;
  237. numTilesZ_ = (gridH + tileSize_ - 1) / tileSize_;
  238. // Calculate max. number of tiles and polygons, 22 bits available to identify both tile & polygon within tile
  239. unsigned maxTiles = NextPowerOfTwo(numTilesX_ * numTilesZ_) * TILECACHE_MAXLAYERS;
  240. unsigned tileBits = 0;
  241. unsigned temp = maxTiles;
  242. while (temp > 1)
  243. {
  244. temp >>= 1;
  245. ++tileBits;
  246. }
  247. unsigned maxPolys = 1 << (22 - tileBits);
  248. dtNavMeshParams params;
  249. rcVcopy(params.orig, &boundingBox_.min_.x_);
  250. params.tileWidth = tileEdgeLength;
  251. params.tileHeight = tileEdgeLength;
  252. params.maxTiles = maxTiles;
  253. params.maxPolys = maxPolys;
  254. navMesh_ = dtAllocNavMesh();
  255. if (!navMesh_)
  256. {
  257. LOGERROR("Could not allocate navigation mesh");
  258. return false;
  259. }
  260. if (dtStatusFailed(navMesh_->init(&params)))
  261. {
  262. LOGERROR("Could not initialize navigation mesh");
  263. ReleaseNavigationMesh();
  264. return false;
  265. }
  266. dtTileCacheParams tileCacheParams;
  267. memset(&tileCacheParams, 0, sizeof(tileCacheParams));
  268. rcVcopy(tileCacheParams.orig, &boundingBox_.min_.x_);
  269. tileCacheParams.ch = cellHeight_;
  270. tileCacheParams.cs = cellSize_;
  271. tileCacheParams.width = tileSize_;
  272. tileCacheParams.height = tileSize_;
  273. tileCacheParams.maxSimplificationError = edgeMaxError_;
  274. tileCacheParams.maxTiles = numTilesX_ * numTilesZ_ * TILECACHE_MAXLAYERS;
  275. tileCacheParams.maxObstacles = maxObstacles_;
  276. // Settings from NavigationMesh
  277. tileCacheParams.walkableClimb = agentMaxClimb_;
  278. tileCacheParams.walkableHeight = agentHeight_;
  279. tileCacheParams.walkableRadius = agentRadius_;
  280. tileCache_ = dtAllocTileCache();
  281. if (!tileCache_)
  282. {
  283. LOGERROR("Could not allocate tile cache");
  284. ReleaseNavigationMesh();
  285. return false;
  286. }
  287. if (dtStatusFailed(tileCache_->init(&tileCacheParams, allocator_, compressor_, meshProcessor_)))
  288. {
  289. LOGERROR("Could not initialize tile cache");
  290. ReleaseNavigationMesh();
  291. return false;
  292. }
  293. // Build each tile
  294. unsigned numTiles = 0;
  295. for (int z = 0; z < numTilesZ_; ++z)
  296. {
  297. for (int x = 0; x < numTilesX_; ++x)
  298. {
  299. TileCacheData tiles[TILECACHE_MAXLAYERS];
  300. int layerCt = BuildTile(geometryList, x, z, tiles);
  301. for (int i = 0; i < layerCt; ++i)
  302. {
  303. dtCompressedTileRef tileRef;
  304. int status = tileCache_->addTile(tiles[i].data, tiles[i].dataSize, DT_COMPRESSEDTILE_FREE_DATA, &tileRef);
  305. if (dtStatusFailed(status))
  306. {
  307. dtFree(tiles[i].data);
  308. tiles[i].data = 0x0;
  309. }
  310. }
  311. ++numTiles;
  312. }
  313. for (int x = 0; x < numTilesX_; ++x)
  314. tileCache_->buildNavMeshTilesAt(x, z, navMesh_);
  315. }
  316. // For a full build it's necessary to update the nav mesh
  317. // not doing so will cause dependent components to crash, like DetourCrowdManager
  318. tileCache_->update(0, navMesh_);
  319. LOGDEBUG("Built navigation mesh with " + String(numTiles) + " tiles");
  320. // Send a notification event to concerned parties that we've been fully rebuilt
  321. {
  322. using namespace NavigationMeshRebuilt;
  323. VariantMap& buildEventParams = GetContext()->GetEventDataMap();
  324. buildEventParams[P_NODE] = node_;
  325. buildEventParams[P_MESH] = this;
  326. SendEvent(E_NAVIGATION_MESH_REBUILT, buildEventParams);
  327. }
  328. // Scan for obstacles to insert into us
  329. PODVector<Node*> obstacles;
  330. GetScene()->GetChildrenWithComponent<Obstacle>(obstacles, true);
  331. for (unsigned i = 0; i < obstacles.Size(); ++i)
  332. {
  333. Obstacle* obs = obstacles[i]->GetComponent<Obstacle>();
  334. if (obs && obs->IsEnabledEffective())
  335. AddObstacle(obs);
  336. }
  337. return true;
  338. }
  339. }
  340. bool DynamicNavigationMesh::Build(const BoundingBox& boundingBox)
  341. {
  342. PROFILE(BuildPartialNavigationMesh);
  343. if (!node_)
  344. return false;
  345. if (!navMesh_)
  346. {
  347. LOGERROR("Navigation mesh must first be built fully before it can be partially rebuilt");
  348. return false;
  349. }
  350. if (!node_->GetWorldScale().Equals(Vector3::ONE))
  351. LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended");
  352. BoundingBox localSpaceBox = boundingBox.Transformed(node_->GetWorldTransform().Inverse());
  353. float tileEdgeLength = (float)tileSize_ * cellSize_;
  354. Vector<NavigationGeometryInfo> geometryList;
  355. CollectGeometries(geometryList);
  356. int sx = Clamp((int)((localSpaceBox.min_.x_ - boundingBox_.min_.x_) / tileEdgeLength), 0, numTilesX_ - 1);
  357. int sz = Clamp((int)((localSpaceBox.min_.z_ - boundingBox_.min_.z_) / tileEdgeLength), 0, numTilesZ_ - 1);
  358. int ex = Clamp((int)((localSpaceBox.max_.x_ - boundingBox_.min_.x_) / tileEdgeLength), 0, numTilesX_ - 1);
  359. int ez = Clamp((int)((localSpaceBox.max_.z_ - boundingBox_.min_.z_) / tileEdgeLength), 0, numTilesZ_ - 1);
  360. unsigned numTiles = 0;
  361. for (int z = sz; z <= ez; ++z)
  362. {
  363. for (int x = sx; x <= ex; ++x)
  364. {
  365. dtCompressedTileRef existing[TILECACHE_MAXLAYERS];
  366. const int existingCt = tileCache_->getTilesAt(x, z, existing, TILECACHE_MAXLAYERS);
  367. for (int i = 0; i < existingCt; ++i)
  368. {
  369. unsigned char* data = 0x0;
  370. if (!dtStatusFailed(tileCache_->removeTile(existing[i], &data, 0)) && data != 0x0)
  371. dtFree(data);
  372. }
  373. TileCacheData tiles[TILECACHE_MAXLAYERS];
  374. int layerCt = BuildTile(geometryList, x, z, tiles);
  375. for (int i = 0; i < layerCt; ++i)
  376. {
  377. dtCompressedTileRef tileRef;
  378. int status = tileCache_->addTile(tiles[i].data, tiles[i].dataSize, DT_COMPRESSEDTILE_FREE_DATA, &tileRef);
  379. if (dtStatusFailed(status))
  380. {
  381. dtFree(tiles[i].data);
  382. tiles[i].data = 0x0;
  383. }
  384. else
  385. {
  386. tileCache_->buildNavMeshTile(tileRef, navMesh_);
  387. ++numTiles;
  388. }
  389. }
  390. }
  391. }
  392. LOGDEBUG("Rebuilt " + String(numTiles) + " tiles of the navigation mesh");
  393. return true;
  394. }
  395. void DynamicNavigationMesh::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  396. {
  397. if (!debug || !navMesh_ || !node_)
  398. return;
  399. const Matrix3x4& worldTransform = node_->GetWorldTransform();
  400. const dtNavMesh* navMesh = navMesh_;
  401. for (int z = 0; z < numTilesZ_; ++z)
  402. {
  403. for (int x = 0; x < numTilesX_; ++x)
  404. {
  405. // Get the layers from the tile-cache
  406. const dtMeshTile* tiles[TILECACHE_MAXLAYERS];
  407. int tileCount = navMesh->getTilesAt(x, z, tiles, TILECACHE_MAXLAYERS);
  408. for (int i = 0; i < tileCount; ++i)
  409. {
  410. const dtMeshTile* tile = tiles[i];
  411. if (!tile)
  412. continue;
  413. for (int i = 0; i < tile->header->polyCount; ++i)
  414. {
  415. dtPoly* poly = tile->polys + i;
  416. for (unsigned j = 0; j < poly->vertCount; ++j)
  417. {
  418. debug->AddLine(
  419. worldTransform * *reinterpret_cast<const Vector3*>(&tile->verts[poly->verts[j] * 3]),
  420. worldTransform * *reinterpret_cast<const Vector3*>(&tile->verts[poly->verts[(j + 1) % poly->vertCount] * 3]),
  421. Color::YELLOW,
  422. depthTest
  423. );
  424. }
  425. }
  426. }
  427. }
  428. }
  429. Scene* scene = GetScene();
  430. if (scene)
  431. {
  432. // Draw Obstacle components
  433. if (drawObstacles_)
  434. {
  435. PODVector<Node*> obstacles;
  436. scene->GetChildrenWithComponent<Obstacle>(obstacles, true);
  437. for (unsigned i = 0; i < obstacles.Size(); ++i)
  438. {
  439. Obstacle* obstacle = obstacles[i]->GetComponent<Obstacle>();
  440. if (obstacle && obstacle->IsEnabledEffective())
  441. obstacle->DrawDebugGeometry(debug, depthTest);
  442. }
  443. }
  444. // Draw OffMeshConnection components
  445. if (drawOffMeshConnections_)
  446. {
  447. PODVector<Node*> connections;
  448. scene->GetChildrenWithComponent<OffMeshConnection>(connections, true);
  449. for (unsigned i = 0; i < connections.Size(); ++i)
  450. {
  451. OffMeshConnection* connection = connections[i]->GetComponent<OffMeshConnection>();
  452. if (connection && connection->IsEnabledEffective())
  453. connection->DrawDebugGeometry(debug, depthTest);
  454. }
  455. }
  456. // Draw NavArea components
  457. if (drawNavAreas_)
  458. {
  459. PODVector<Node*> areas;
  460. scene->GetChildrenWithComponent<NavArea>(areas, true);
  461. for (unsigned i = 0; i < areas.Size(); ++i)
  462. {
  463. NavArea* area = areas[i]->GetComponent<NavArea>();
  464. if (area && area->IsEnabledEffective())
  465. area->DrawDebugGeometry(debug, depthTest);
  466. }
  467. }
  468. }
  469. }
  470. void DynamicNavigationMesh::DrawDebugGeometry(bool depthTest)
  471. {
  472. Scene* scene = GetScene();
  473. if (scene)
  474. {
  475. DebugRenderer* debug = scene->GetComponent<DebugRenderer>();
  476. if (debug)
  477. DrawDebugGeometry(debug, depthTest);
  478. }
  479. }
  480. void DynamicNavigationMesh::SetNavigationDataAttr(const PODVector<unsigned char>& value)
  481. {
  482. ReleaseNavigationMesh();
  483. if (value.Empty())
  484. return;
  485. MemoryBuffer buffer(value);
  486. boundingBox_ = buffer.ReadBoundingBox();
  487. numTilesX_ = buffer.ReadInt();
  488. numTilesZ_ = buffer.ReadInt();
  489. dtNavMeshParams params;
  490. buffer.Read(&params, sizeof(dtNavMeshParams));
  491. navMesh_ = dtAllocNavMesh();
  492. if (!navMesh_)
  493. {
  494. LOGERROR("Could not allocate navigation mesh");
  495. return;
  496. }
  497. if (dtStatusFailed(navMesh_->init(&params)))
  498. {
  499. LOGERROR("Could not initialize navigation mesh");
  500. ReleaseNavigationMesh();
  501. return;
  502. }
  503. dtTileCacheParams tcParams;
  504. buffer.Read(&tcParams, sizeof(tcParams));
  505. tileCache_ = dtAllocTileCache();
  506. if (!tileCache_)
  507. {
  508. LOGERROR("Could not allocate tile cache");
  509. ReleaseNavigationMesh();
  510. return;
  511. }
  512. if (dtStatusFailed(tileCache_->init(&tcParams, allocator_, compressor_, meshProcessor_)))
  513. {
  514. LOGERROR("Could not initialize tile cache");
  515. ReleaseNavigationMesh();
  516. return;
  517. }
  518. while (!buffer.IsEof())
  519. {
  520. dtTileCacheLayerHeader header;
  521. buffer.Read(&header, sizeof(dtTileCacheLayerHeader));
  522. const int dataSize = buffer.ReadInt();
  523. unsigned char* data = (unsigned char*)dtAlloc(dataSize, DT_ALLOC_PERM);
  524. buffer.Read(data, dataSize);
  525. if (dtStatusFailed(tileCache_->addTile(data, dataSize, DT_TILE_FREE_DATA, 0)))
  526. {
  527. LOGERROR("Failed to add tile");
  528. dtFree(data);
  529. return;
  530. }
  531. }
  532. for (int x = 0; x < numTilesX_; ++x)
  533. {
  534. for (int z = 0; z < numTilesZ_; ++z)
  535. tileCache_->buildNavMeshTilesAt(x, z, navMesh_);
  536. }
  537. tileCache_->update(0, navMesh_);
  538. }
  539. PODVector<unsigned char> DynamicNavigationMesh::GetNavigationDataAttr() const
  540. {
  541. VectorBuffer ret;
  542. if (navMesh_ && tileCache_)
  543. {
  544. ret.WriteBoundingBox(boundingBox_);
  545. ret.WriteInt(numTilesX_);
  546. ret.WriteInt(numTilesZ_);
  547. const dtNavMeshParams* params = navMesh_->getParams();
  548. ret.Write(params, sizeof(dtNavMeshParams));
  549. const dtTileCacheParams* tcParams = tileCache_->getParams();
  550. ret.Write(tcParams, sizeof(dtTileCacheParams));
  551. for (int z = 0; z < numTilesZ_; ++z)
  552. {
  553. for (int x = 0; x < numTilesX_; ++x)
  554. {
  555. dtCompressedTileRef tiles[TILECACHE_MAXLAYERS];
  556. const int ct = tileCache_->getTilesAt(x, z, tiles, TILECACHE_MAXLAYERS);
  557. for (int i = 0; i < ct; ++i)
  558. {
  559. const dtCompressedTile* tile = tileCache_->getTileByRef(tiles[i]);
  560. if (!tile || !tile->header || !tile->dataSize)
  561. continue; // Don't write "void-space" tiles
  562. // The header conveniently has the majority of the information required
  563. ret.Write(tile->header, sizeof(dtTileCacheLayerHeader));
  564. ret.WriteInt(tile->dataSize);
  565. ret.Write(tile->data, tile->dataSize);
  566. }
  567. }
  568. }
  569. }
  570. return ret.GetBuffer();
  571. }
  572. int DynamicNavigationMesh::BuildTile(Vector<NavigationGeometryInfo>& geometryList, int x, int z, TileCacheData* tiles)
  573. {
  574. PROFILE(BuildNavigationMeshTile);
  575. tileCache_->removeTile(navMesh_->getTileRefAt(x, z, 0), 0, 0);
  576. float tileEdgeLength = (float)tileSize_ * cellSize_;
  577. BoundingBox tileBoundingBox(Vector3(
  578. boundingBox_.min_.x_ + tileEdgeLength * (float)x,
  579. boundingBox_.min_.y_,
  580. boundingBox_.min_.z_ + tileEdgeLength * (float)z
  581. ),
  582. Vector3(
  583. boundingBox_.min_.x_ + tileEdgeLength * (float)(x + 1),
  584. boundingBox_.max_.y_,
  585. boundingBox_.min_.z_ + tileEdgeLength * (float)(z + 1)
  586. ));
  587. DynamicNavBuildData build(allocator_);
  588. rcConfig cfg;
  589. memset(&cfg, 0, sizeof cfg);
  590. cfg.cs = cellSize_;
  591. cfg.ch = cellHeight_;
  592. cfg.walkableSlopeAngle = agentMaxSlope_;
  593. cfg.walkableHeight = (int)ceilf(agentHeight_ / cfg.ch);
  594. cfg.walkableClimb = (int)floorf(agentMaxClimb_ / cfg.ch);
  595. cfg.walkableRadius = (int)ceilf(agentRadius_ / cfg.cs);
  596. cfg.maxEdgeLen = (int)(edgeMaxLength_ / cellSize_);
  597. cfg.maxSimplificationError = edgeMaxError_;
  598. cfg.minRegionArea = (int)sqrtf(regionMinSize_);
  599. cfg.mergeRegionArea = (int)sqrtf(regionMergeSize_);
  600. cfg.maxVertsPerPoly = 6;
  601. cfg.tileSize = tileSize_;
  602. cfg.borderSize = cfg.walkableRadius + 3; // Add padding
  603. cfg.width = cfg.tileSize + cfg.borderSize * 2;
  604. cfg.height = cfg.tileSize + cfg.borderSize * 2;
  605. cfg.detailSampleDist = detailSampleDistance_ < 0.9f ? 0.0f : cellSize_ * detailSampleDistance_;
  606. cfg.detailSampleMaxError = cellHeight_ * detailSampleMaxError_;
  607. rcVcopy(cfg.bmin, &tileBoundingBox.min_.x_);
  608. rcVcopy(cfg.bmax, &tileBoundingBox.max_.x_);
  609. cfg.bmin[0] -= cfg.borderSize * cfg.cs;
  610. cfg.bmin[2] -= cfg.borderSize * cfg.cs;
  611. cfg.bmax[0] += cfg.borderSize * cfg.cs;
  612. cfg.bmax[2] += cfg.borderSize * cfg.cs;
  613. BoundingBox expandedBox(*reinterpret_cast<Vector3*>(cfg.bmin), *reinterpret_cast<Vector3*>(cfg.bmax));
  614. GetTileGeometry(&build, geometryList, expandedBox);
  615. if (build.vertices_.Empty() || build.indices_.Empty())
  616. return 0; // Nothing to do
  617. build.heightField_ = rcAllocHeightfield();
  618. if (!build.heightField_)
  619. {
  620. LOGERROR("Could not allocate heightfield");
  621. return 0;
  622. }
  623. if (!rcCreateHeightfield(build.ctx_, *build.heightField_, cfg.width, cfg.height, cfg.bmin, cfg.bmax, cfg.cs,
  624. cfg.ch))
  625. {
  626. LOGERROR("Could not create heightfield");
  627. return 0;
  628. }
  629. unsigned numTriangles = build.indices_.Size() / 3;
  630. SharedArrayPtr<unsigned char> triAreas(new unsigned char[numTriangles]);
  631. memset(triAreas.Get(), 0, numTriangles);
  632. rcMarkWalkableTriangles(build.ctx_, cfg.walkableSlopeAngle, &build.vertices_[0].x_, build.vertices_.Size(),
  633. &build.indices_[0], numTriangles, triAreas.Get());
  634. rcRasterizeTriangles(build.ctx_, &build.vertices_[0].x_, build.vertices_.Size(), &build.indices_[0],
  635. triAreas.Get(), numTriangles, *build.heightField_, cfg.walkableClimb);
  636. rcFilterLowHangingWalkableObstacles(build.ctx_, cfg.walkableClimb, *build.heightField_);
  637. rcFilterLedgeSpans(build.ctx_, cfg.walkableHeight, cfg.walkableClimb, *build.heightField_);
  638. rcFilterWalkableLowHeightSpans(build.ctx_, cfg.walkableHeight, *build.heightField_);
  639. build.compactHeightField_ = rcAllocCompactHeightfield();
  640. if (!build.compactHeightField_)
  641. {
  642. LOGERROR("Could not allocate create compact heightfield");
  643. return 0;
  644. }
  645. if (!rcBuildCompactHeightfield(build.ctx_, cfg.walkableHeight, cfg.walkableClimb, *build.heightField_,
  646. *build.compactHeightField_))
  647. {
  648. LOGERROR("Could not build compact heightfield");
  649. return 0;
  650. }
  651. if (!rcErodeWalkableArea(build.ctx_, cfg.walkableRadius, *build.compactHeightField_))
  652. {
  653. LOGERROR("Could not erode compact heightfield");
  654. return 0;
  655. }
  656. // area volumes
  657. for (unsigned i = 0; i < build.navAreas_.Size(); ++i)
  658. rcMarkBoxArea(build.ctx_, &build.navAreas_[i].bounds_.min_.x_, &build.navAreas_[i].bounds_.max_.x_, build.navAreas_[i].areaID_, *build.compactHeightField_);
  659. if (this->partitionType_ == NAVMESH_PARTITION_WATERSHED)
  660. {
  661. if (!rcBuildDistanceField(build.ctx_, *build.compactHeightField_))
  662. {
  663. LOGERROR("Could not build distance field");
  664. return 0;
  665. }
  666. if (!rcBuildRegions(build.ctx_, *build.compactHeightField_, cfg.borderSize, cfg.minRegionArea,
  667. cfg.mergeRegionArea))
  668. {
  669. LOGERROR("Could not build regions");
  670. return 0;
  671. }
  672. }
  673. else
  674. {
  675. if (!rcBuildRegionsMonotone(build.ctx_, *build.compactHeightField_, cfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea))
  676. {
  677. LOGERROR("Could not build monotone regions");
  678. return 0;
  679. }
  680. }
  681. build.heightFieldLayers_ = rcAllocHeightfieldLayerSet();
  682. if (!build.heightFieldLayers_)
  683. {
  684. LOGERROR("Could not allocate height field layer set");
  685. return 0;
  686. }
  687. if (!rcBuildHeightfieldLayers(build.ctx_, *build.compactHeightField_, cfg.borderSize, cfg.walkableHeight, *build.heightFieldLayers_))
  688. {
  689. LOGERROR("Could not build height field layers");
  690. return 0;
  691. }
  692. int retCt = 0;
  693. for (int i = 0; i < build.heightFieldLayers_->nlayers; ++i)
  694. {
  695. dtTileCacheLayerHeader header;
  696. header.magic = DT_TILECACHE_MAGIC;
  697. header.version = DT_TILECACHE_VERSION;
  698. header.tx = x;
  699. header.ty = z;
  700. header.tlayer = i;
  701. rcHeightfieldLayer* layer = &build.heightFieldLayers_->layers[i];
  702. // Tile info.
  703. rcVcopy(header.bmin, layer->bmin);
  704. rcVcopy(header.bmax, layer->bmax);
  705. header.width = (unsigned char)layer->width;
  706. header.height = (unsigned char)layer->height;
  707. header.minx = (unsigned char)layer->minx;
  708. header.maxx = (unsigned char)layer->maxx;
  709. header.miny = (unsigned char)layer->miny;
  710. header.maxy = (unsigned char)layer->maxy;
  711. header.hmin = (unsigned short)layer->hmin;
  712. header.hmax = (unsigned short)layer->hmax;
  713. if (dtStatusFailed(dtBuildTileCacheLayer(compressor_/*compressor*/, &header, layer->heights, layer->areas/*areas*/, layer->cons, &(tiles[retCt].data), &tiles[retCt].dataSize)))
  714. {
  715. LOGERROR("Failed to build tile cache layers");
  716. return 0;
  717. }
  718. else
  719. ++retCt;
  720. }
  721. // Send a notification of the rebuild of this tile to anyone interested
  722. {
  723. using namespace NavigationAreaRebuilt;
  724. VariantMap& eventData = GetContext()->GetEventDataMap();
  725. eventData[P_NODE] = GetNode();
  726. eventData[P_MESH] = this;
  727. eventData[P_BOUNDSMIN] = Variant(tileBoundingBox.min_);
  728. eventData[P_BOUNDSMAX] = Variant(tileBoundingBox.max_);
  729. SendEvent(E_NAVIGATION_AREA_REBUILT, eventData);
  730. }
  731. return retCt;
  732. }
  733. PODVector<OffMeshConnection*> DynamicNavigationMesh::CollectOffMeshConnections(const BoundingBox& bounds)
  734. {
  735. PODVector<OffMeshConnection*> connections;
  736. node_->GetComponents<OffMeshConnection>(connections, true);
  737. for (unsigned i = 0; i < connections.Size(); ++i)
  738. {
  739. OffMeshConnection* connection = connections[i];
  740. if (!(connection->IsEnabledEffective() && connection->GetEndPoint()))
  741. {
  742. // discard this connection
  743. connections.Erase(i);
  744. --i;
  745. }
  746. }
  747. return connections;
  748. }
  749. void DynamicNavigationMesh::ReleaseNavigationMesh()
  750. {
  751. NavigationMesh::ReleaseNavigationMesh();
  752. ReleaseTileCache();
  753. }
  754. void DynamicNavigationMesh::ReleaseTileCache()
  755. {
  756. dtFreeTileCache(tileCache_);
  757. tileCache_ = 0;
  758. }
  759. void DynamicNavigationMesh::OnNodeSet(Node* node)
  760. {
  761. // Subscribe to the scene subsystem update, which will trigger the tile cache to update the nav mesh
  762. if (node)
  763. SubscribeToEvent(node, E_SCENESUBSYSTEMUPDATE, HANDLER(DynamicNavigationMesh, HandleSceneSubsystemUpdate));
  764. }
  765. void DynamicNavigationMesh::AddObstacle(Obstacle* obstacle, bool silent)
  766. {
  767. if (tileCache_)
  768. {
  769. float pos[3];
  770. Vector3 obsPos = obstacle->GetNode()->GetWorldPosition();
  771. rcVcopy(pos, &obsPos.x_);
  772. dtObstacleRef refHolder;
  773. // Because dtTileCache doesn't process obstacle requests while updating tiles
  774. // it's necessary update until sufficient request space is available
  775. while (tileCache_->isObstacleQueueFull())
  776. tileCache_->update(1, navMesh_);
  777. if (dtStatusFailed(tileCache_->addObstacle(pos, obstacle->GetRadius(), obstacle->GetHeight(), &refHolder)))
  778. {
  779. LOGERROR("Failed to add obstacle");
  780. return;
  781. }
  782. obstacle->obstacleId_ = refHolder;
  783. assert(refHolder > 0);
  784. if (!silent)
  785. {
  786. using namespace NavigationObstacleAdded;
  787. VariantMap& eventData = GetContext()->GetEventDataMap();
  788. eventData[P_NODE] = obstacle->GetNode();
  789. eventData[P_OBSTACLE] = obstacle;
  790. eventData[P_POSITION] = obstacle->GetNode()->GetWorldPosition();
  791. eventData[P_RADIUS] = obstacle->GetRadius();
  792. eventData[P_HEIGHT] = obstacle->GetHeight();
  793. SendEvent(E_NAVIGATION_OBSTACLE_ADDED, eventData);
  794. }
  795. }
  796. }
  797. void DynamicNavigationMesh::ObstacleChanged(Obstacle* obstacle)
  798. {
  799. if (tileCache_)
  800. {
  801. RemoveObstacle(obstacle, true);
  802. AddObstacle(obstacle, true);
  803. }
  804. }
  805. void DynamicNavigationMesh::RemoveObstacle(Obstacle* obstacle, bool silent)
  806. {
  807. if (tileCache_ && obstacle->obstacleId_ > 0)
  808. {
  809. // Because dtTileCache doesn't process obstacle requests while updating tiles
  810. // it's necessary update until sufficient request space is available
  811. while (tileCache_->isObstacleQueueFull())
  812. tileCache_->update(1, navMesh_);
  813. if (dtStatusFailed(tileCache_->removeObstacle(obstacle->obstacleId_)))
  814. {
  815. LOGERROR("Failed to remove obstacle");
  816. return;
  817. }
  818. obstacle->obstacleId_ = 0;
  819. // Require a node in order to send an event
  820. if (!silent && obstacle->GetNode())
  821. {
  822. using namespace NavigationObstacleRemoved;
  823. VariantMap& eventData = GetContext()->GetEventDataMap();
  824. eventData[P_NODE] = obstacle->GetNode();
  825. eventData[P_OBSTACLE] = obstacle;
  826. eventData[P_POSITION] = obstacle->GetNode()->GetWorldPosition();
  827. eventData[P_RADIUS] = obstacle->GetRadius();
  828. eventData[P_HEIGHT] = obstacle->GetHeight();
  829. SendEvent(E_NAVIGATION_OBSTACLE_REMOVED, eventData);
  830. }
  831. }
  832. }
  833. void DynamicNavigationMesh::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)
  834. {
  835. using namespace SceneSubsystemUpdate;
  836. if (tileCache_ && navMesh_ && IsEnabledEffective())
  837. tileCache_->update(eventData[P_TIMESTEP].GetFloat(), navMesh_);
  838. }
  839. }