DetourTileCache.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. #include "DetourTileCache.h"
  2. #include "DetourTileCacheBuilder.h"
  3. #include "DetourNavMeshBuilder.h"
  4. #include "DetourNavMesh.h"
  5. #include "DetourCommon.h"
  6. #include "DetourMath.h"
  7. #include "DetourAlloc.h"
  8. #include "DetourAssert.h"
  9. #include <string.h>
  10. #include <new>
  11. dtTileCache* dtAllocTileCache()
  12. {
  13. void* mem = dtAlloc(sizeof(dtTileCache), DT_ALLOC_PERM);
  14. if (!mem) return 0;
  15. return new(mem) dtTileCache;
  16. }
  17. void dtFreeTileCache(dtTileCache* tc)
  18. {
  19. if (!tc) return;
  20. tc->~dtTileCache();
  21. dtFree(tc);
  22. }
  23. static bool contains(const dtCompressedTileRef* a, const int n, const dtCompressedTileRef v)
  24. {
  25. for (int i = 0; i < n; ++i)
  26. if (a[i] == v)
  27. return true;
  28. return false;
  29. }
  30. inline int computeTileHash(int x, int y, const int mask)
  31. {
  32. const unsigned int h1 = 0x8da6b343; // Large multiplicative constants;
  33. const unsigned int h2 = 0xd8163841; // here arbitrarily chosen primes
  34. unsigned int n = h1 * x + h2 * y;
  35. return (int)(n & mask);
  36. }
  37. struct NavMeshTileBuildContext
  38. {
  39. inline NavMeshTileBuildContext(struct dtTileCacheAlloc* a) : layer(0), lcset(0), lmesh(0), alloc(a) {}
  40. inline ~NavMeshTileBuildContext() { purge(); }
  41. void purge()
  42. {
  43. dtFreeTileCacheLayer(alloc, layer);
  44. layer = 0;
  45. dtFreeTileCacheContourSet(alloc, lcset);
  46. lcset = 0;
  47. dtFreeTileCachePolyMesh(alloc, lmesh);
  48. lmesh = 0;
  49. }
  50. struct dtTileCacheLayer* layer;
  51. struct dtTileCacheContourSet* lcset;
  52. struct dtTileCachePolyMesh* lmesh;
  53. struct dtTileCacheAlloc* alloc;
  54. };
  55. dtTileCache::dtTileCache() :
  56. m_tileLutSize(0),
  57. m_tileLutMask(0),
  58. m_posLookup(0),
  59. m_nextFreeTile(0),
  60. m_tiles(0),
  61. m_saltBits(0),
  62. m_tileBits(0),
  63. m_talloc(0),
  64. m_tcomp(0),
  65. m_tmproc(0),
  66. m_obstacles(0),
  67. m_nextFreeObstacle(0),
  68. m_nreqs(0),
  69. m_nupdate(0)
  70. {
  71. memset(&m_params, 0, sizeof(m_params));
  72. memset(m_reqs, 0, sizeof(ObstacleRequest) * MAX_REQUESTS);
  73. }
  74. dtTileCache::~dtTileCache()
  75. {
  76. for (int i = 0; i < m_params.maxTiles; ++i)
  77. {
  78. if (m_tiles[i].flags & DT_COMPRESSEDTILE_FREE_DATA)
  79. {
  80. dtFree(m_tiles[i].data);
  81. m_tiles[i].data = 0;
  82. }
  83. }
  84. dtFree(m_obstacles);
  85. m_obstacles = 0;
  86. dtFree(m_posLookup);
  87. m_posLookup = 0;
  88. dtFree(m_tiles);
  89. m_tiles = 0;
  90. m_nreqs = 0;
  91. m_nupdate = 0;
  92. }
  93. const dtCompressedTile* dtTileCache::getTileByRef(dtCompressedTileRef ref) const
  94. {
  95. if (!ref)
  96. return 0;
  97. unsigned int tileIndex = decodeTileIdTile(ref);
  98. unsigned int tileSalt = decodeTileIdSalt(ref);
  99. if ((int)tileIndex >= m_params.maxTiles)
  100. return 0;
  101. const dtCompressedTile* tile = &m_tiles[tileIndex];
  102. if (tile->salt != tileSalt)
  103. return 0;
  104. return tile;
  105. }
  106. dtStatus dtTileCache::init(const dtTileCacheParams* params,
  107. dtTileCacheAlloc* talloc,
  108. dtTileCacheCompressor* tcomp,
  109. dtTileCacheMeshProcess* tmproc)
  110. {
  111. m_talloc = talloc;
  112. m_tcomp = tcomp;
  113. m_tmproc = tmproc;
  114. m_nreqs = 0;
  115. memcpy(&m_params, params, sizeof(m_params));
  116. // Alloc space for obstacles.
  117. m_obstacles = (dtTileCacheObstacle*)dtAlloc(sizeof(dtTileCacheObstacle)*m_params.maxObstacles, DT_ALLOC_PERM);
  118. if (!m_obstacles)
  119. return DT_FAILURE | DT_OUT_OF_MEMORY;
  120. memset(m_obstacles, 0, sizeof(dtTileCacheObstacle)*m_params.maxObstacles);
  121. m_nextFreeObstacle = 0;
  122. for (int i = m_params.maxObstacles-1; i >= 0; --i)
  123. {
  124. m_obstacles[i].salt = 1;
  125. m_obstacles[i].next = m_nextFreeObstacle;
  126. m_nextFreeObstacle = &m_obstacles[i];
  127. }
  128. // Init tiles
  129. m_tileLutSize = dtNextPow2(m_params.maxTiles/4);
  130. if (!m_tileLutSize) m_tileLutSize = 1;
  131. m_tileLutMask = m_tileLutSize-1;
  132. m_tiles = (dtCompressedTile*)dtAlloc(sizeof(dtCompressedTile)*m_params.maxTiles, DT_ALLOC_PERM);
  133. if (!m_tiles)
  134. return DT_FAILURE | DT_OUT_OF_MEMORY;
  135. m_posLookup = (dtCompressedTile**)dtAlloc(sizeof(dtCompressedTile*)*m_tileLutSize, DT_ALLOC_PERM);
  136. if (!m_posLookup)
  137. return DT_FAILURE | DT_OUT_OF_MEMORY;
  138. memset(m_tiles, 0, sizeof(dtCompressedTile)*m_params.maxTiles);
  139. memset(m_posLookup, 0, sizeof(dtCompressedTile*)*m_tileLutSize);
  140. m_nextFreeTile = 0;
  141. for (int i = m_params.maxTiles-1; i >= 0; --i)
  142. {
  143. m_tiles[i].salt = 1;
  144. m_tiles[i].next = m_nextFreeTile;
  145. m_nextFreeTile = &m_tiles[i];
  146. }
  147. // Init ID generator values.
  148. m_tileBits = dtIlog2(dtNextPow2((unsigned int)m_params.maxTiles));
  149. // Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow.
  150. m_saltBits = dtMin((unsigned int)31, 32 - m_tileBits);
  151. if (m_saltBits < 10)
  152. return DT_FAILURE | DT_INVALID_PARAM;
  153. return DT_SUCCESS;
  154. }
  155. int dtTileCache::getTilesAt(const int tx, const int ty, dtCompressedTileRef* tiles, const int maxTiles) const
  156. {
  157. int n = 0;
  158. // Find tile based on hash.
  159. int h = computeTileHash(tx,ty,m_tileLutMask);
  160. dtCompressedTile* tile = m_posLookup[h];
  161. while (tile)
  162. {
  163. if (tile->header &&
  164. tile->header->tx == tx &&
  165. tile->header->ty == ty)
  166. {
  167. if (n < maxTiles)
  168. tiles[n++] = getTileRef(tile);
  169. }
  170. tile = tile->next;
  171. }
  172. return n;
  173. }
  174. dtCompressedTile* dtTileCache::getTileAt(const int tx, const int ty, const int tlayer)
  175. {
  176. // Find tile based on hash.
  177. int h = computeTileHash(tx,ty,m_tileLutMask);
  178. dtCompressedTile* tile = m_posLookup[h];
  179. while (tile)
  180. {
  181. if (tile->header &&
  182. tile->header->tx == tx &&
  183. tile->header->ty == ty &&
  184. tile->header->tlayer == tlayer)
  185. {
  186. return tile;
  187. }
  188. tile = tile->next;
  189. }
  190. return 0;
  191. }
  192. dtCompressedTileRef dtTileCache::getTileRef(const dtCompressedTile* tile) const
  193. {
  194. if (!tile) return 0;
  195. const unsigned int it = (unsigned int)(tile - m_tiles);
  196. return (dtCompressedTileRef)encodeTileId(tile->salt, it);
  197. }
  198. dtObstacleRef dtTileCache::getObstacleRef(const dtTileCacheObstacle* ob) const
  199. {
  200. if (!ob) return 0;
  201. const unsigned int idx = (unsigned int)(ob - m_obstacles);
  202. return encodeObstacleId(ob->salt, idx);
  203. }
  204. const dtTileCacheObstacle* dtTileCache::getObstacleByRef(dtObstacleRef ref)
  205. {
  206. if (!ref)
  207. return 0;
  208. unsigned int idx = decodeObstacleIdObstacle(ref);
  209. if ((int)idx >= m_params.maxObstacles)
  210. return 0;
  211. const dtTileCacheObstacle* ob = &m_obstacles[idx];
  212. unsigned int salt = decodeObstacleIdSalt(ref);
  213. if (ob->salt != salt)
  214. return 0;
  215. return ob;
  216. }
  217. dtStatus dtTileCache::addTile(unsigned char* data, const int dataSize, unsigned char flags, dtCompressedTileRef* result)
  218. {
  219. // Make sure the data is in right format.
  220. dtTileCacheLayerHeader* header = (dtTileCacheLayerHeader*)data;
  221. if (header->magic != DT_TILECACHE_MAGIC)
  222. return DT_FAILURE | DT_WRONG_MAGIC;
  223. if (header->version != DT_TILECACHE_VERSION)
  224. return DT_FAILURE | DT_WRONG_VERSION;
  225. // Make sure the location is free.
  226. if (getTileAt(header->tx, header->ty, header->tlayer))
  227. return DT_FAILURE;
  228. // Allocate a tile.
  229. dtCompressedTile* tile = 0;
  230. if (m_nextFreeTile)
  231. {
  232. tile = m_nextFreeTile;
  233. m_nextFreeTile = tile->next;
  234. tile->next = 0;
  235. }
  236. // Make sure we could allocate a tile.
  237. if (!tile)
  238. return DT_FAILURE | DT_OUT_OF_MEMORY;
  239. // Insert tile into the position lut.
  240. int h = computeTileHash(header->tx, header->ty, m_tileLutMask);
  241. tile->next = m_posLookup[h];
  242. m_posLookup[h] = tile;
  243. // Init tile.
  244. const int headerSize = dtAlign4(sizeof(dtTileCacheLayerHeader));
  245. tile->header = (dtTileCacheLayerHeader*)data;
  246. tile->data = data;
  247. tile->dataSize = dataSize;
  248. tile->compressed = tile->data + headerSize;
  249. tile->compressedSize = tile->dataSize - headerSize;
  250. tile->flags = flags;
  251. if (result)
  252. *result = getTileRef(tile);
  253. return DT_SUCCESS;
  254. }
  255. dtStatus dtTileCache::removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize)
  256. {
  257. if (!ref)
  258. return DT_FAILURE | DT_INVALID_PARAM;
  259. unsigned int tileIndex = decodeTileIdTile(ref);
  260. unsigned int tileSalt = decodeTileIdSalt(ref);
  261. if ((int)tileIndex >= m_params.maxTiles)
  262. return DT_FAILURE | DT_INVALID_PARAM;
  263. dtCompressedTile* tile = &m_tiles[tileIndex];
  264. if (tile->salt != tileSalt)
  265. return DT_FAILURE | DT_INVALID_PARAM;
  266. // Remove tile from hash lookup.
  267. const int h = computeTileHash(tile->header->tx,tile->header->ty,m_tileLutMask);
  268. dtCompressedTile* prev = 0;
  269. dtCompressedTile* cur = m_posLookup[h];
  270. while (cur)
  271. {
  272. if (cur == tile)
  273. {
  274. if (prev)
  275. prev->next = cur->next;
  276. else
  277. m_posLookup[h] = cur->next;
  278. break;
  279. }
  280. prev = cur;
  281. cur = cur->next;
  282. }
  283. // Reset tile.
  284. if (tile->flags & DT_COMPRESSEDTILE_FREE_DATA)
  285. {
  286. // Owns data
  287. dtFree(tile->data);
  288. tile->data = 0;
  289. tile->dataSize = 0;
  290. if (data) *data = 0;
  291. if (dataSize) *dataSize = 0;
  292. }
  293. else
  294. {
  295. if (data) *data = tile->data;
  296. if (dataSize) *dataSize = tile->dataSize;
  297. }
  298. tile->header = 0;
  299. tile->data = 0;
  300. tile->dataSize = 0;
  301. tile->compressed = 0;
  302. tile->compressedSize = 0;
  303. tile->flags = 0;
  304. // Update salt, salt should never be zero.
  305. tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1);
  306. if (tile->salt == 0)
  307. tile->salt++;
  308. // Add to free list.
  309. tile->next = m_nextFreeTile;
  310. m_nextFreeTile = tile;
  311. return DT_SUCCESS;
  312. }
  313. dtStatus dtTileCache::addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result)
  314. {
  315. if (m_nreqs >= MAX_REQUESTS)
  316. return DT_FAILURE | DT_BUFFER_TOO_SMALL;
  317. dtTileCacheObstacle* ob = 0;
  318. if (m_nextFreeObstacle)
  319. {
  320. ob = m_nextFreeObstacle;
  321. m_nextFreeObstacle = ob->next;
  322. ob->next = 0;
  323. }
  324. if (!ob)
  325. return DT_FAILURE | DT_OUT_OF_MEMORY;
  326. unsigned short salt = ob->salt;
  327. memset(ob, 0, sizeof(dtTileCacheObstacle));
  328. ob->salt = salt;
  329. ob->state = DT_OBSTACLE_PROCESSING;
  330. ob->type = DT_OBSTACLE_CYLINDER;
  331. dtVcopy(ob->cylinder.pos, pos);
  332. ob->cylinder.radius = radius;
  333. ob->cylinder.height = height;
  334. ObstacleRequest* req = &m_reqs[m_nreqs++];
  335. memset(req, 0, sizeof(ObstacleRequest));
  336. req->action = REQUEST_ADD;
  337. req->ref = getObstacleRef(ob);
  338. if (result)
  339. *result = req->ref;
  340. return DT_SUCCESS;
  341. }
  342. dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result)
  343. {
  344. if (m_nreqs >= MAX_REQUESTS)
  345. return DT_FAILURE | DT_BUFFER_TOO_SMALL;
  346. dtTileCacheObstacle* ob = 0;
  347. if (m_nextFreeObstacle)
  348. {
  349. ob = m_nextFreeObstacle;
  350. m_nextFreeObstacle = ob->next;
  351. ob->next = 0;
  352. }
  353. if (!ob)
  354. return DT_FAILURE | DT_OUT_OF_MEMORY;
  355. unsigned short salt = ob->salt;
  356. memset(ob, 0, sizeof(dtTileCacheObstacle));
  357. ob->salt = salt;
  358. ob->state = DT_OBSTACLE_PROCESSING;
  359. ob->type = DT_OBSTACLE_BOX;
  360. dtVcopy(ob->box.bmin, bmin);
  361. dtVcopy(ob->box.bmax, bmax);
  362. ObstacleRequest* req = &m_reqs[m_nreqs++];
  363. memset(req, 0, sizeof(ObstacleRequest));
  364. req->action = REQUEST_ADD;
  365. req->ref = getObstacleRef(ob);
  366. if (result)
  367. *result = req->ref;
  368. return DT_SUCCESS;
  369. }
  370. dtStatus dtTileCache::addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, dtObstacleRef* result)
  371. {
  372. if (m_nreqs >= MAX_REQUESTS)
  373. return DT_FAILURE | DT_BUFFER_TOO_SMALL;
  374. dtTileCacheObstacle* ob = 0;
  375. if (m_nextFreeObstacle)
  376. {
  377. ob = m_nextFreeObstacle;
  378. m_nextFreeObstacle = ob->next;
  379. ob->next = 0;
  380. }
  381. if (!ob)
  382. return DT_FAILURE | DT_OUT_OF_MEMORY;
  383. unsigned short salt = ob->salt;
  384. memset(ob, 0, sizeof(dtTileCacheObstacle));
  385. ob->salt = salt;
  386. ob->state = DT_OBSTACLE_PROCESSING;
  387. ob->type = DT_OBSTACLE_ORIENTED_BOX;
  388. dtVcopy(ob->orientedBox.center, center);
  389. dtVcopy(ob->orientedBox.halfExtents, halfExtents);
  390. float coshalf= cosf(0.5f*yRadians);
  391. float sinhalf = sinf(-0.5f*yRadians);
  392. ob->orientedBox.rotAux[0] = coshalf*sinhalf;
  393. ob->orientedBox.rotAux[1] = coshalf*coshalf - 0.5f;
  394. ObstacleRequest* req = &m_reqs[m_nreqs++];
  395. memset(req, 0, sizeof(ObstacleRequest));
  396. req->action = REQUEST_ADD;
  397. req->ref = getObstacleRef(ob);
  398. if (result)
  399. *result = req->ref;
  400. return DT_SUCCESS;
  401. }
  402. dtStatus dtTileCache::removeObstacle(const dtObstacleRef ref)
  403. {
  404. if (!ref)
  405. return DT_SUCCESS;
  406. if (m_nreqs >= MAX_REQUESTS)
  407. return DT_FAILURE | DT_BUFFER_TOO_SMALL;
  408. ObstacleRequest* req = &m_reqs[m_nreqs++];
  409. memset(req, 0, sizeof(ObstacleRequest));
  410. req->action = REQUEST_REMOVE;
  411. req->ref = ref;
  412. return DT_SUCCESS;
  413. }
  414. dtStatus dtTileCache::queryTiles(const float* bmin, const float* bmax,
  415. dtCompressedTileRef* results, int* resultCount, const int maxResults) const
  416. {
  417. const int MAX_TILES = 32;
  418. dtCompressedTileRef tiles[MAX_TILES];
  419. int n = 0;
  420. const float tw = m_params.width * m_params.cs;
  421. const float th = m_params.height * m_params.cs;
  422. const int tx0 = (int)dtMathFloorf((bmin[0]-m_params.orig[0]) / tw);
  423. const int tx1 = (int)dtMathFloorf((bmax[0]-m_params.orig[0]) / tw);
  424. const int ty0 = (int)dtMathFloorf((bmin[2]-m_params.orig[2]) / th);
  425. const int ty1 = (int)dtMathFloorf((bmax[2]-m_params.orig[2]) / th);
  426. for (int ty = ty0; ty <= ty1; ++ty)
  427. {
  428. for (int tx = tx0; tx <= tx1; ++tx)
  429. {
  430. const int ntiles = getTilesAt(tx,ty,tiles,MAX_TILES);
  431. for (int i = 0; i < ntiles; ++i)
  432. {
  433. const dtCompressedTile* tile = &m_tiles[decodeTileIdTile(tiles[i])];
  434. float tbmin[3], tbmax[3];
  435. calcTightTileBounds(tile->header, tbmin, tbmax);
  436. if (dtOverlapBounds(bmin,bmax, tbmin,tbmax))
  437. {
  438. if (n < maxResults)
  439. results[n++] = tiles[i];
  440. }
  441. }
  442. }
  443. }
  444. *resultCount = n;
  445. return DT_SUCCESS;
  446. }
  447. dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
  448. bool* upToDate)
  449. {
  450. if (m_nupdate == 0)
  451. {
  452. // Process requests.
  453. for (int i = 0; i < m_nreqs; ++i)
  454. {
  455. ObstacleRequest* req = &m_reqs[i];
  456. unsigned int idx = decodeObstacleIdObstacle(req->ref);
  457. if ((int)idx >= m_params.maxObstacles)
  458. continue;
  459. dtTileCacheObstacle* ob = &m_obstacles[idx];
  460. unsigned int salt = decodeObstacleIdSalt(req->ref);
  461. if (ob->salt != salt)
  462. continue;
  463. if (req->action == REQUEST_ADD)
  464. {
  465. // Find touched tiles.
  466. float bmin[3], bmax[3];
  467. getObstacleBounds(ob, bmin, bmax);
  468. int ntouched = 0;
  469. queryTiles(bmin, bmax, ob->touched, &ntouched, DT_MAX_TOUCHED_TILES);
  470. ob->ntouched = (unsigned char)ntouched;
  471. // Add tiles to update list.
  472. ob->npending = 0;
  473. for (int j = 0; j < ob->ntouched; ++j)
  474. {
  475. if (m_nupdate < MAX_UPDATE)
  476. {
  477. if (!contains(m_update, m_nupdate, ob->touched[j]))
  478. m_update[m_nupdate++] = ob->touched[j];
  479. ob->pending[ob->npending++] = ob->touched[j];
  480. }
  481. }
  482. }
  483. else if (req->action == REQUEST_REMOVE)
  484. {
  485. // Prepare to remove obstacle.
  486. ob->state = DT_OBSTACLE_REMOVING;
  487. // Add tiles to update list.
  488. ob->npending = 0;
  489. for (int j = 0; j < ob->ntouched; ++j)
  490. {
  491. if (m_nupdate < MAX_UPDATE)
  492. {
  493. if (!contains(m_update, m_nupdate, ob->touched[j]))
  494. m_update[m_nupdate++] = ob->touched[j];
  495. ob->pending[ob->npending++] = ob->touched[j];
  496. }
  497. }
  498. }
  499. }
  500. m_nreqs = 0;
  501. }
  502. dtStatus status = DT_SUCCESS;
  503. // Process updates
  504. if (m_nupdate)
  505. {
  506. // Build mesh
  507. const dtCompressedTileRef ref = m_update[0];
  508. status = buildNavMeshTile(ref, navmesh);
  509. m_nupdate--;
  510. if (m_nupdate > 0)
  511. memmove(m_update, m_update+1, m_nupdate*sizeof(dtCompressedTileRef));
  512. // Update obstacle states.
  513. for (int i = 0; i < m_params.maxObstacles; ++i)
  514. {
  515. dtTileCacheObstacle* ob = &m_obstacles[i];
  516. if (ob->state == DT_OBSTACLE_PROCESSING || ob->state == DT_OBSTACLE_REMOVING)
  517. {
  518. // Remove handled tile from pending list.
  519. for (int j = 0; j < (int)ob->npending; j++)
  520. {
  521. if (ob->pending[j] == ref)
  522. {
  523. ob->pending[j] = ob->pending[(int)ob->npending-1];
  524. ob->npending--;
  525. break;
  526. }
  527. }
  528. // If all pending tiles processed, change state.
  529. if (ob->npending == 0)
  530. {
  531. if (ob->state == DT_OBSTACLE_PROCESSING)
  532. {
  533. ob->state = DT_OBSTACLE_PROCESSED;
  534. }
  535. else if (ob->state == DT_OBSTACLE_REMOVING)
  536. {
  537. ob->state = DT_OBSTACLE_EMPTY;
  538. // Update salt, salt should never be zero.
  539. ob->salt = (ob->salt+1) & ((1<<16)-1);
  540. if (ob->salt == 0)
  541. ob->salt++;
  542. // Return obstacle to free list.
  543. ob->next = m_nextFreeObstacle;
  544. m_nextFreeObstacle = ob;
  545. }
  546. }
  547. }
  548. }
  549. }
  550. if (upToDate)
  551. *upToDate = m_nupdate == 0 && m_nreqs == 0;
  552. return status;
  553. }
  554. dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* navmesh)
  555. {
  556. const int MAX_TILES = 32;
  557. dtCompressedTileRef tiles[MAX_TILES];
  558. const int ntiles = getTilesAt(tx,ty,tiles,MAX_TILES);
  559. for (int i = 0; i < ntiles; ++i)
  560. {
  561. dtStatus status = buildNavMeshTile(tiles[i], navmesh);
  562. if (dtStatusFailed(status))
  563. return status;
  564. }
  565. return DT_SUCCESS;
  566. }
  567. dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh)
  568. {
  569. dtAssert(m_talloc);
  570. dtAssert(m_tcomp);
  571. unsigned int idx = decodeTileIdTile(ref);
  572. if (idx > (unsigned int)m_params.maxTiles)
  573. return DT_FAILURE | DT_INVALID_PARAM;
  574. const dtCompressedTile* tile = &m_tiles[idx];
  575. unsigned int salt = decodeTileIdSalt(ref);
  576. if (tile->salt != salt)
  577. return DT_FAILURE | DT_INVALID_PARAM;
  578. m_talloc->reset();
  579. NavMeshTileBuildContext bc(m_talloc);
  580. const int walkableClimbVx = (int)(m_params.walkableClimb / m_params.ch);
  581. dtStatus status;
  582. // Decompress tile layer data.
  583. status = dtDecompressTileCacheLayer(m_talloc, m_tcomp, tile->data, tile->dataSize, &bc.layer);
  584. if (dtStatusFailed(status))
  585. return status;
  586. // Rasterize obstacles.
  587. for (int i = 0; i < m_params.maxObstacles; ++i)
  588. {
  589. const dtTileCacheObstacle* ob = &m_obstacles[i];
  590. if (ob->state == DT_OBSTACLE_EMPTY || ob->state == DT_OBSTACLE_REMOVING)
  591. continue;
  592. if (contains(ob->touched, ob->ntouched, ref))
  593. {
  594. if (ob->type == DT_OBSTACLE_CYLINDER)
  595. {
  596. dtMarkCylinderArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
  597. ob->cylinder.pos, ob->cylinder.radius, ob->cylinder.height, 0);
  598. }
  599. else if (ob->type == DT_OBSTACLE_BOX)
  600. {
  601. dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
  602. ob->box.bmin, ob->box.bmax, 0);
  603. }
  604. else if (ob->type == DT_OBSTACLE_ORIENTED_BOX)
  605. {
  606. dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
  607. ob->orientedBox.center, ob->orientedBox.halfExtents, ob->orientedBox.rotAux, 0);
  608. }
  609. }
  610. }
  611. // Build navmesh
  612. status = dtBuildTileCacheRegions(m_talloc, *bc.layer, walkableClimbVx);
  613. if (dtStatusFailed(status))
  614. return status;
  615. bc.lcset = dtAllocTileCacheContourSet(m_talloc);
  616. if (!bc.lcset)
  617. return DT_FAILURE | DT_OUT_OF_MEMORY;
  618. status = dtBuildTileCacheContours(m_talloc, *bc.layer, walkableClimbVx,
  619. m_params.maxSimplificationError, *bc.lcset);
  620. if (dtStatusFailed(status))
  621. return status;
  622. bc.lmesh = dtAllocTileCachePolyMesh(m_talloc);
  623. if (!bc.lmesh)
  624. return DT_FAILURE | DT_OUT_OF_MEMORY;
  625. status = dtBuildTileCachePolyMesh(m_talloc, *bc.lcset, *bc.lmesh);
  626. if (dtStatusFailed(status))
  627. return status;
  628. // Early out if the mesh tile is empty.
  629. if (!bc.lmesh->npolys)
  630. {
  631. // Remove existing tile.
  632. navmesh->removeTile(navmesh->getTileRefAt(tile->header->tx,tile->header->ty,tile->header->tlayer),0,0);
  633. return DT_SUCCESS;
  634. }
  635. dtNavMeshCreateParams params;
  636. memset(&params, 0, sizeof(params));
  637. params.verts = bc.lmesh->verts;
  638. params.vertCount = bc.lmesh->nverts;
  639. params.polys = bc.lmesh->polys;
  640. params.polyAreas = bc.lmesh->areas;
  641. params.polyFlags = bc.lmesh->flags;
  642. params.polyCount = bc.lmesh->npolys;
  643. params.nvp = DT_VERTS_PER_POLYGON;
  644. params.walkableHeight = m_params.walkableHeight;
  645. params.walkableRadius = m_params.walkableRadius;
  646. params.walkableClimb = m_params.walkableClimb;
  647. params.tileX = tile->header->tx;
  648. params.tileY = tile->header->ty;
  649. params.tileLayer = tile->header->tlayer;
  650. params.cs = m_params.cs;
  651. params.ch = m_params.ch;
  652. params.buildBvTree = false;
  653. dtVcopy(params.bmin, tile->header->bmin);
  654. dtVcopy(params.bmax, tile->header->bmax);
  655. if (m_tmproc)
  656. {
  657. m_tmproc->process(&params, bc.lmesh->areas, bc.lmesh->flags);
  658. }
  659. unsigned char* navData = 0;
  660. int navDataSize = 0;
  661. if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
  662. return DT_FAILURE;
  663. // Remove existing tile.
  664. navmesh->removeTile(navmesh->getTileRefAt(tile->header->tx,tile->header->ty,tile->header->tlayer),0,0);
  665. // Add new tile, or leave the location empty.
  666. if (navData)
  667. {
  668. // Let the navmesh own the data.
  669. status = navmesh->addTile(navData,navDataSize,DT_TILE_FREE_DATA,0,0);
  670. if (dtStatusFailed(status))
  671. {
  672. dtFree(navData);
  673. return status;
  674. }
  675. }
  676. return DT_SUCCESS;
  677. }
  678. void dtTileCache::calcTightTileBounds(const dtTileCacheLayerHeader* header, float* bmin, float* bmax) const
  679. {
  680. const float cs = m_params.cs;
  681. bmin[0] = header->bmin[0] + header->minx*cs;
  682. bmin[1] = header->bmin[1];
  683. bmin[2] = header->bmin[2] + header->miny*cs;
  684. bmax[0] = header->bmin[0] + (header->maxx+1)*cs;
  685. bmax[1] = header->bmax[1];
  686. bmax[2] = header->bmin[2] + (header->maxy+1)*cs;
  687. }
  688. void dtTileCache::getObstacleBounds(const struct dtTileCacheObstacle* ob, float* bmin, float* bmax) const
  689. {
  690. if (ob->type == DT_OBSTACLE_CYLINDER)
  691. {
  692. const dtObstacleCylinder &cl = ob->cylinder;
  693. bmin[0] = cl.pos[0] - cl.radius;
  694. bmin[1] = cl.pos[1];
  695. bmin[2] = cl.pos[2] - cl.radius;
  696. bmax[0] = cl.pos[0] + cl.radius;
  697. bmax[1] = cl.pos[1] + cl.height;
  698. bmax[2] = cl.pos[2] + cl.radius;
  699. }
  700. else if (ob->type == DT_OBSTACLE_BOX)
  701. {
  702. dtVcopy(bmin, ob->box.bmin);
  703. dtVcopy(bmax, ob->box.bmax);
  704. }
  705. else if (ob->type == DT_OBSTACLE_ORIENTED_BOX)
  706. {
  707. const dtObstacleOrientedBox &orientedBox = ob->orientedBox;
  708. float maxr = 1.41f*dtMax(orientedBox.halfExtents[0], orientedBox.halfExtents[2]);
  709. bmin[0] = orientedBox.center[0] - maxr;
  710. bmax[0] = orientedBox.center[0] + maxr;
  711. bmin[1] = orientedBox.center[1] - orientedBox.halfExtents[1];
  712. bmax[1] = orientedBox.center[1] + orientedBox.halfExtents[1];
  713. bmin[2] = orientedBox.center[2] - maxr;
  714. bmax[2] = orientedBox.center[2] + maxr;
  715. }
  716. }