Recast.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen [email protected]
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #include <float.h>
  19. #define _USE_MATH_DEFINES
  20. #include <math.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <stdarg.h>
  25. #include "Recast.h"
  26. #include "RecastAlloc.h"
  27. #include "RecastAssert.h"
  28. namespace
  29. {
  30. /// Allocates and constructs an object of the given type, returning a pointer.
  31. /// TODO: Support constructor args.
  32. /// @param[in] hint Hint to the allocator.
  33. template <typename T>
  34. T* rcNew(rcAllocHint hint) {
  35. T* ptr = (T*)rcAlloc(sizeof(T), hint);
  36. ::new(rcNewTag(), (void*)ptr) T();
  37. return ptr;
  38. }
  39. /// Destroys and frees an object allocated with rcNew.
  40. /// @param[in] ptr The object pointer to delete.
  41. template <typename T>
  42. void rcDelete(T* ptr) {
  43. if (ptr) {
  44. ptr->~T();
  45. rcFree((void*)ptr);
  46. }
  47. }
  48. } // namespace
  49. float rcSqrt(float x)
  50. {
  51. return sqrtf(x);
  52. }
  53. /// @class rcContext
  54. /// @par
  55. ///
  56. /// This class does not provide logging or timer functionality on its
  57. /// own. Both must be provided by a concrete implementation
  58. /// by overriding the protected member functions. Also, this class does not
  59. /// provide an interface for extracting log messages. (Only adding them.)
  60. /// So concrete implementations must provide one.
  61. ///
  62. /// If no logging or timers are required, just pass an instance of this
  63. /// class through the Recast build process.
  64. ///
  65. /// @par
  66. ///
  67. /// Example:
  68. /// @code
  69. /// // Where ctx is an instance of rcContext and filepath is a char array.
  70. /// ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath);
  71. /// @endcode
  72. void rcContext::log(const rcLogCategory category, const char* format, ...)
  73. {
  74. if (!m_logEnabled)
  75. return;
  76. static const int MSG_SIZE = 512;
  77. char msg[MSG_SIZE];
  78. va_list ap;
  79. va_start(ap, format);
  80. int len = vsnprintf(msg, MSG_SIZE, format, ap);
  81. if (len >= MSG_SIZE)
  82. {
  83. len = MSG_SIZE-1;
  84. msg[MSG_SIZE-1] = '\0';
  85. }
  86. va_end(ap);
  87. doLog(category, msg, len);
  88. }
  89. void rcContext::doResetLog()
  90. {
  91. // Defined out of line to fix the weak v-tables warning
  92. }
  93. rcHeightfield* rcAllocHeightfield()
  94. {
  95. return rcNew<rcHeightfield>(RC_ALLOC_PERM);
  96. }
  97. rcHeightfield::rcHeightfield()
  98. : width()
  99. , height()
  100. , bmin()
  101. , bmax()
  102. , cs()
  103. , ch()
  104. , spans()
  105. , pools()
  106. , freelist()
  107. {
  108. }
  109. rcHeightfield::~rcHeightfield()
  110. {
  111. // Delete span array.
  112. rcFree(spans);
  113. // Delete span pools.
  114. while (pools)
  115. {
  116. rcSpanPool* next = pools->next;
  117. rcFree(pools);
  118. pools = next;
  119. }
  120. }
  121. void rcFreeHeightField(rcHeightfield* hf)
  122. {
  123. rcDelete(hf);
  124. }
  125. rcCompactHeightfield* rcAllocCompactHeightfield()
  126. {
  127. return rcNew<rcCompactHeightfield>(RC_ALLOC_PERM);
  128. }
  129. void rcFreeCompactHeightfield(rcCompactHeightfield* chf)
  130. {
  131. rcDelete(chf);
  132. }
  133. rcCompactHeightfield::rcCompactHeightfield()
  134. : width(),
  135. height(),
  136. spanCount(),
  137. walkableHeight(),
  138. walkableClimb(),
  139. borderSize(),
  140. maxDistance(),
  141. maxRegions(),
  142. bmin(),
  143. bmax(),
  144. cs(),
  145. ch(),
  146. cells(),
  147. spans(),
  148. dist(),
  149. areas()
  150. {
  151. }
  152. rcCompactHeightfield::~rcCompactHeightfield()
  153. {
  154. rcFree(cells);
  155. rcFree(spans);
  156. rcFree(dist);
  157. rcFree(areas);
  158. }
  159. rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet()
  160. {
  161. return rcNew<rcHeightfieldLayerSet>(RC_ALLOC_PERM);
  162. }
  163. void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset)
  164. {
  165. rcDelete(lset);
  166. }
  167. rcHeightfieldLayerSet::rcHeightfieldLayerSet()
  168. : layers(), nlayers() {}
  169. rcHeightfieldLayerSet::~rcHeightfieldLayerSet()
  170. {
  171. for (int i = 0; i < nlayers; ++i)
  172. {
  173. rcFree(layers[i].heights);
  174. rcFree(layers[i].areas);
  175. rcFree(layers[i].cons);
  176. }
  177. rcFree(layers);
  178. }
  179. rcContourSet* rcAllocContourSet()
  180. {
  181. return rcNew<rcContourSet>(RC_ALLOC_PERM);
  182. }
  183. void rcFreeContourSet(rcContourSet* cset)
  184. {
  185. rcDelete(cset);
  186. }
  187. rcContourSet::rcContourSet()
  188. : conts(),
  189. nconts(),
  190. bmin(),
  191. bmax(),
  192. cs(),
  193. ch(),
  194. width(),
  195. height(),
  196. borderSize(),
  197. maxError() {}
  198. rcContourSet::~rcContourSet()
  199. {
  200. for (int i = 0; i < nconts; ++i)
  201. {
  202. rcFree(conts[i].verts);
  203. rcFree(conts[i].rverts);
  204. }
  205. rcFree(conts);
  206. }
  207. rcPolyMesh* rcAllocPolyMesh()
  208. {
  209. return rcNew<rcPolyMesh>(RC_ALLOC_PERM);
  210. }
  211. void rcFreePolyMesh(rcPolyMesh* pmesh)
  212. {
  213. rcDelete(pmesh);
  214. }
  215. rcPolyMesh::rcPolyMesh()
  216. : verts(),
  217. polys(),
  218. regs(),
  219. flags(),
  220. areas(),
  221. nverts(),
  222. npolys(),
  223. maxpolys(),
  224. nvp(),
  225. bmin(),
  226. bmax(),
  227. cs(),
  228. ch(),
  229. borderSize(),
  230. maxEdgeError() {}
  231. rcPolyMesh::~rcPolyMesh()
  232. {
  233. rcFree(verts);
  234. rcFree(polys);
  235. rcFree(regs);
  236. rcFree(flags);
  237. rcFree(areas);
  238. }
  239. rcPolyMeshDetail* rcAllocPolyMeshDetail()
  240. {
  241. rcPolyMeshDetail* dmesh = (rcPolyMeshDetail*)rcAlloc(sizeof(rcPolyMeshDetail), RC_ALLOC_PERM);
  242. memset(dmesh, 0, sizeof(rcPolyMeshDetail));
  243. return dmesh;
  244. }
  245. void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh)
  246. {
  247. if (!dmesh) return;
  248. rcFree(dmesh->meshes);
  249. rcFree(dmesh->verts);
  250. rcFree(dmesh->tris);
  251. rcFree(dmesh);
  252. }
  253. void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
  254. {
  255. // Calculate bounding box.
  256. rcVcopy(bmin, verts);
  257. rcVcopy(bmax, verts);
  258. for (int i = 1; i < nv; ++i)
  259. {
  260. const float* v = &verts[i*3];
  261. rcVmin(bmin, v);
  262. rcVmax(bmax, v);
  263. }
  264. }
  265. void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h)
  266. {
  267. *w = (int)((bmax[0] - bmin[0])/cs+0.5f);
  268. *h = (int)((bmax[2] - bmin[2])/cs+0.5f);
  269. }
  270. /// @par
  271. ///
  272. /// See the #rcConfig documentation for more information on the configuration parameters.
  273. ///
  274. /// @see rcAllocHeightfield, rcHeightfield
  275. bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height,
  276. const float* bmin, const float* bmax,
  277. float cs, float ch)
  278. {
  279. rcIgnoreUnused(ctx);
  280. hf.width = width;
  281. hf.height = height;
  282. rcVcopy(hf.bmin, bmin);
  283. rcVcopy(hf.bmax, bmax);
  284. hf.cs = cs;
  285. hf.ch = ch;
  286. hf.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM);
  287. if (!hf.spans)
  288. return false;
  289. memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height);
  290. return true;
  291. }
  292. static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* norm)
  293. {
  294. float e0[3], e1[3];
  295. rcVsub(e0, v1, v0);
  296. rcVsub(e1, v2, v0);
  297. rcVcross(norm, e0, e1);
  298. rcVnormalize(norm);
  299. }
  300. /// @par
  301. ///
  302. /// Only sets the area id's for the walkable triangles. Does not alter the
  303. /// area id's for unwalkable triangles.
  304. ///
  305. /// See the #rcConfig documentation for more information on the configuration parameters.
  306. ///
  307. /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
  308. void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
  309. const float* verts, int nv,
  310. const int* tris, int nt,
  311. unsigned char* areas)
  312. {
  313. rcIgnoreUnused(ctx);
  314. rcIgnoreUnused(nv);
  315. const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
  316. float norm[3];
  317. for (int i = 0; i < nt; ++i)
  318. {
  319. const int* tri = &tris[i*3];
  320. calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
  321. // Check if the face is walkable.
  322. if (norm[1] > walkableThr)
  323. areas[i] = RC_WALKABLE_AREA;
  324. }
  325. }
  326. /// @par
  327. ///
  328. /// Only sets the area id's for the unwalkable triangles. Does not alter the
  329. /// area id's for walkable triangles.
  330. ///
  331. /// See the #rcConfig documentation for more information on the configuration parameters.
  332. ///
  333. /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
  334. void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
  335. const float* verts, int /*nv*/,
  336. const int* tris, int nt,
  337. unsigned char* areas)
  338. {
  339. rcIgnoreUnused(ctx);
  340. const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
  341. float norm[3];
  342. for (int i = 0; i < nt; ++i)
  343. {
  344. const int* tri = &tris[i*3];
  345. calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
  346. // Check if the face is walkable.
  347. if (norm[1] <= walkableThr)
  348. areas[i] = RC_NULL_AREA;
  349. }
  350. }
  351. int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf)
  352. {
  353. rcIgnoreUnused(ctx);
  354. const int w = hf.width;
  355. const int h = hf.height;
  356. int spanCount = 0;
  357. for (int y = 0; y < h; ++y)
  358. {
  359. for (int x = 0; x < w; ++x)
  360. {
  361. for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next)
  362. {
  363. if (s->area != RC_NULL_AREA)
  364. spanCount++;
  365. }
  366. }
  367. }
  368. return spanCount;
  369. }
  370. /// @par
  371. ///
  372. /// This is just the beginning of the process of fully building a compact heightfield.
  373. /// Various filters may be applied, then the distance field and regions built.
  374. /// E.g: #rcBuildDistanceField and #rcBuildRegions
  375. ///
  376. /// See the #rcConfig documentation for more information on the configuration parameters.
  377. ///
  378. /// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
  379. bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
  380. rcHeightfield& hf, rcCompactHeightfield& chf)
  381. {
  382. rcAssert(ctx);
  383. rcScopedTimer timer(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
  384. const int w = hf.width;
  385. const int h = hf.height;
  386. const int spanCount = rcGetHeightFieldSpanCount(ctx, hf);
  387. // Fill in header.
  388. chf.width = w;
  389. chf.height = h;
  390. chf.spanCount = spanCount;
  391. chf.walkableHeight = walkableHeight;
  392. chf.walkableClimb = walkableClimb;
  393. chf.maxRegions = 0;
  394. rcVcopy(chf.bmin, hf.bmin);
  395. rcVcopy(chf.bmax, hf.bmax);
  396. chf.bmax[1] += walkableHeight*hf.ch;
  397. chf.cs = hf.cs;
  398. chf.ch = hf.ch;
  399. chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM);
  400. if (!chf.cells)
  401. {
  402. ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
  403. return false;
  404. }
  405. memset(chf.cells, 0, sizeof(rcCompactCell)*w*h);
  406. chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM);
  407. if (!chf.spans)
  408. {
  409. ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
  410. return false;
  411. }
  412. memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
  413. chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM);
  414. if (!chf.areas)
  415. {
  416. ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
  417. return false;
  418. }
  419. memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount);
  420. const int MAX_HEIGHT = 0xffff;
  421. // Fill in cells and spans.
  422. int idx = 0;
  423. for (int y = 0; y < h; ++y)
  424. {
  425. for (int x = 0; x < w; ++x)
  426. {
  427. const rcSpan* s = hf.spans[x + y*w];
  428. // If there are no spans at this cell, just leave the data to index=0, count=0.
  429. if (!s) continue;
  430. rcCompactCell& c = chf.cells[x+y*w];
  431. c.index = idx;
  432. c.count = 0;
  433. while (s)
  434. {
  435. if (s->area != RC_NULL_AREA)
  436. {
  437. const int bot = (int)s->smax;
  438. const int top = s->next ? (int)s->next->smin : MAX_HEIGHT;
  439. chf.spans[idx].y = (unsigned short)rcClamp(bot, 0, 0xffff);
  440. chf.spans[idx].h = (unsigned char)rcClamp(top - bot, 0, 0xff);
  441. chf.areas[idx] = s->area;
  442. idx++;
  443. c.count++;
  444. }
  445. s = s->next;
  446. }
  447. }
  448. }
  449. // Find neighbour connections.
  450. const int MAX_LAYERS = RC_NOT_CONNECTED-1;
  451. int tooHighNeighbour = 0;
  452. for (int y = 0; y < h; ++y)
  453. {
  454. for (int x = 0; x < w; ++x)
  455. {
  456. const rcCompactCell& c = chf.cells[x+y*w];
  457. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  458. {
  459. rcCompactSpan& s = chf.spans[i];
  460. for (int dir = 0; dir < 4; ++dir)
  461. {
  462. rcSetCon(s, dir, RC_NOT_CONNECTED);
  463. const int nx = x + rcGetDirOffsetX(dir);
  464. const int ny = y + rcGetDirOffsetY(dir);
  465. // First check that the neighbour cell is in bounds.
  466. if (nx < 0 || ny < 0 || nx >= w || ny >= h)
  467. continue;
  468. // Iterate over all neighbour spans and check if any of the is
  469. // accessible from current cell.
  470. const rcCompactCell& nc = chf.cells[nx+ny*w];
  471. for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; ++k)
  472. {
  473. const rcCompactSpan& ns = chf.spans[k];
  474. const int bot = rcMax(s.y, ns.y);
  475. const int top = rcMin(s.y+s.h, ns.y+ns.h);
  476. // Check that the gap between the spans is walkable,
  477. // and that the climb height between the gaps is not too high.
  478. if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
  479. {
  480. // Mark direction as walkable.
  481. const int lidx = k - (int)nc.index;
  482. if (lidx < 0 || lidx > MAX_LAYERS)
  483. {
  484. tooHighNeighbour = rcMax(tooHighNeighbour, lidx);
  485. continue;
  486. }
  487. rcSetCon(s, dir, lidx);
  488. break;
  489. }
  490. }
  491. }
  492. }
  493. }
  494. }
  495. if (tooHighNeighbour > MAX_LAYERS)
  496. {
  497. ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
  498. tooHighNeighbour, MAX_LAYERS);
  499. }
  500. return true;
  501. }
  502. /*
  503. static int getHeightfieldMemoryUsage(const rcHeightfield& hf)
  504. {
  505. int size = 0;
  506. size += sizeof(hf);
  507. size += hf.width * hf.height * sizeof(rcSpan*);
  508. rcSpanPool* pool = hf.pools;
  509. while (pool)
  510. {
  511. size += (sizeof(rcSpanPool) - sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL;
  512. pool = pool->next;
  513. }
  514. return size;
  515. }
  516. static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf)
  517. {
  518. int size = 0;
  519. size += sizeof(rcCompactHeightfield);
  520. size += sizeof(rcCompactSpan) * chf.spanCount;
  521. size += sizeof(rcCompactCell) * chf.width * chf.height;
  522. return size;
  523. }
  524. */