Recast.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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. float rcSqrt(float x)
  29. {
  30. return sqrtf(x);
  31. }
  32. /// @class rcContext
  33. /// @par
  34. ///
  35. /// This class does not provide logging or timer functionality on its
  36. /// own. Both must be provided by a concrete implementation
  37. /// by overriding the protected member functions. Also, this class does not
  38. /// provide an interface for extracting log messages. (Only adding them.)
  39. /// So concrete implementations must provide one.
  40. ///
  41. /// If no logging or timers are required, just pass an instance of this
  42. /// class through the Recast build process.
  43. ///
  44. /// @par
  45. ///
  46. /// Example:
  47. /// @code
  48. /// // Where ctx is an instance of rcContext and filepath is a char array.
  49. /// ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath);
  50. /// @endcode
  51. void rcContext::log(const rcLogCategory category, const char* format, ...)
  52. {
  53. if (!m_logEnabled)
  54. return;
  55. static const int MSG_SIZE = 512;
  56. char msg[MSG_SIZE];
  57. va_list ap;
  58. va_start(ap, format);
  59. int len = vsnprintf(msg, MSG_SIZE, format, ap);
  60. if (len >= MSG_SIZE)
  61. {
  62. len = MSG_SIZE-1;
  63. msg[MSG_SIZE-1] = '\0';
  64. }
  65. va_end(ap);
  66. doLog(category, msg, len);
  67. }
  68. rcHeightfield* rcAllocHeightfield()
  69. {
  70. rcHeightfield* hf = (rcHeightfield*)rcAlloc(sizeof(rcHeightfield), RC_ALLOC_PERM);
  71. memset(hf, 0, sizeof(rcHeightfield));
  72. return hf;
  73. }
  74. void rcFreeHeightField(rcHeightfield* hf)
  75. {
  76. if (!hf) return;
  77. // Delete span array.
  78. rcFree(hf->spans);
  79. // Delete span pools.
  80. while (hf->pools)
  81. {
  82. rcSpanPool* next = hf->pools->next;
  83. rcFree(hf->pools);
  84. hf->pools = next;
  85. }
  86. rcFree(hf);
  87. }
  88. rcCompactHeightfield* rcAllocCompactHeightfield()
  89. {
  90. rcCompactHeightfield* chf = (rcCompactHeightfield*)rcAlloc(sizeof(rcCompactHeightfield), RC_ALLOC_PERM);
  91. memset(chf, 0, sizeof(rcCompactHeightfield));
  92. return chf;
  93. }
  94. void rcFreeCompactHeightfield(rcCompactHeightfield* chf)
  95. {
  96. if (!chf) return;
  97. rcFree(chf->cells);
  98. rcFree(chf->spans);
  99. rcFree(chf->dist);
  100. rcFree(chf->areas);
  101. rcFree(chf);
  102. }
  103. rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet()
  104. {
  105. rcHeightfieldLayerSet* lset = (rcHeightfieldLayerSet*)rcAlloc(sizeof(rcHeightfieldLayerSet), RC_ALLOC_PERM);
  106. memset(lset, 0, sizeof(rcHeightfieldLayerSet));
  107. return lset;
  108. }
  109. void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset)
  110. {
  111. if (!lset) return;
  112. for (int i = 0; i < lset->nlayers; ++i)
  113. {
  114. rcFree(lset->layers[i].heights);
  115. rcFree(lset->layers[i].areas);
  116. rcFree(lset->layers[i].cons);
  117. }
  118. rcFree(lset->layers);
  119. rcFree(lset);
  120. }
  121. rcContourSet* rcAllocContourSet()
  122. {
  123. rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM);
  124. memset(cset, 0, sizeof(rcContourSet));
  125. return cset;
  126. }
  127. void rcFreeContourSet(rcContourSet* cset)
  128. {
  129. if (!cset) return;
  130. for (int i = 0; i < cset->nconts; ++i)
  131. {
  132. rcFree(cset->conts[i].verts);
  133. rcFree(cset->conts[i].rverts);
  134. }
  135. rcFree(cset->conts);
  136. rcFree(cset);
  137. }
  138. rcPolyMesh* rcAllocPolyMesh()
  139. {
  140. rcPolyMesh* pmesh = (rcPolyMesh*)rcAlloc(sizeof(rcPolyMesh), RC_ALLOC_PERM);
  141. memset(pmesh, 0, sizeof(rcPolyMesh));
  142. return pmesh;
  143. }
  144. void rcFreePolyMesh(rcPolyMesh* pmesh)
  145. {
  146. if (!pmesh) return;
  147. rcFree(pmesh->verts);
  148. rcFree(pmesh->polys);
  149. rcFree(pmesh->regs);
  150. rcFree(pmesh->flags);
  151. rcFree(pmesh->areas);
  152. rcFree(pmesh);
  153. }
  154. rcPolyMeshDetail* rcAllocPolyMeshDetail()
  155. {
  156. rcPolyMeshDetail* dmesh = (rcPolyMeshDetail*)rcAlloc(sizeof(rcPolyMeshDetail), RC_ALLOC_PERM);
  157. memset(dmesh, 0, sizeof(rcPolyMeshDetail));
  158. return dmesh;
  159. }
  160. void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh)
  161. {
  162. if (!dmesh) return;
  163. rcFree(dmesh->meshes);
  164. rcFree(dmesh->verts);
  165. rcFree(dmesh->tris);
  166. rcFree(dmesh);
  167. }
  168. void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
  169. {
  170. // Calculate bounding box.
  171. rcVcopy(bmin, verts);
  172. rcVcopy(bmax, verts);
  173. for (int i = 1; i < nv; ++i)
  174. {
  175. const float* v = &verts[i*3];
  176. rcVmin(bmin, v);
  177. rcVmax(bmax, v);
  178. }
  179. }
  180. void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h)
  181. {
  182. *w = (int)((bmax[0] - bmin[0])/cs+0.5f);
  183. *h = (int)((bmax[2] - bmin[2])/cs+0.5f);
  184. }
  185. /// @par
  186. ///
  187. /// See the #rcConfig documentation for more information on the configuration parameters.
  188. ///
  189. /// @see rcAllocHeightfield, rcHeightfield
  190. bool rcCreateHeightfield(rcContext* /*ctx*/, rcHeightfield& hf, int width, int height,
  191. const float* bmin, const float* bmax,
  192. float cs, float ch)
  193. {
  194. // TODO: VC complains about unref formal variable, figure out a way to handle this better.
  195. // rcAssert(ctx);
  196. hf.width = width;
  197. hf.height = height;
  198. rcVcopy(hf.bmin, bmin);
  199. rcVcopy(hf.bmax, bmax);
  200. hf.cs = cs;
  201. hf.ch = ch;
  202. hf.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM);
  203. if (!hf.spans)
  204. return false;
  205. memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height);
  206. return true;
  207. }
  208. static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* norm)
  209. {
  210. float e0[3], e1[3];
  211. rcVsub(e0, v1, v0);
  212. rcVsub(e1, v2, v0);
  213. rcVcross(norm, e0, e1);
  214. rcVnormalize(norm);
  215. }
  216. /// @par
  217. ///
  218. /// Only sets the aread id's for the walkable triangles. Does not alter the
  219. /// area id's for unwalkable triangles.
  220. ///
  221. /// See the #rcConfig documentation for more information on the configuration parameters.
  222. ///
  223. /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
  224. void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
  225. const float* verts, int /*nv*/,
  226. const int* tris, int nt,
  227. unsigned char* areas)
  228. {
  229. // TODO: VC complains about unref formal variable, figure out a way to handle this better.
  230. // rcAssert(ctx);
  231. const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
  232. float norm[3];
  233. for (int i = 0; i < nt; ++i)
  234. {
  235. const int* tri = &tris[i*3];
  236. calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
  237. // Check if the face is walkable.
  238. if (norm[1] > walkableThr)
  239. areas[i] = RC_WALKABLE_AREA;
  240. }
  241. }
  242. /// @par
  243. ///
  244. /// Only sets the aread id's for the unwalkable triangles. Does not alter the
  245. /// area id's for walkable triangles.
  246. ///
  247. /// See the #rcConfig documentation for more information on the configuration parameters.
  248. ///
  249. /// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles
  250. void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle,
  251. const float* verts, int /*nv*/,
  252. const int* tris, int nt,
  253. unsigned char* areas)
  254. {
  255. // TODO: VC complains about unref formal variable, figure out a way to handle this better.
  256. // rcAssert(ctx);
  257. const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI);
  258. float norm[3];
  259. for (int i = 0; i < nt; ++i)
  260. {
  261. const int* tri = &tris[i*3];
  262. calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
  263. // Check if the face is walkable.
  264. if (norm[1] <= walkableThr)
  265. areas[i] = RC_NULL_AREA;
  266. }
  267. }
  268. int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf)
  269. {
  270. // TODO: VC complains about unref formal variable, figure out a way to handle this better.
  271. // rcAssert(ctx);
  272. const int w = hf.width;
  273. const int h = hf.height;
  274. int spanCount = 0;
  275. for (int y = 0; y < h; ++y)
  276. {
  277. for (int x = 0; x < w; ++x)
  278. {
  279. for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next)
  280. {
  281. if (s->area != RC_NULL_AREA)
  282. spanCount++;
  283. }
  284. }
  285. }
  286. return spanCount;
  287. }
  288. /// @par
  289. ///
  290. /// This is just the beginning of the process of fully building a compact heightfield.
  291. /// Various filters may be applied applied, then the distance field and regions built.
  292. /// E.g: #rcBuildDistanceField and #rcBuildRegions
  293. ///
  294. /// See the #rcConfig documentation for more information on the configuration parameters.
  295. ///
  296. /// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig
  297. bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
  298. rcHeightfield& hf, rcCompactHeightfield& chf)
  299. {
  300. rcAssert(ctx);
  301. ctx->startTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
  302. const int w = hf.width;
  303. const int h = hf.height;
  304. const int spanCount = rcGetHeightFieldSpanCount(ctx, hf);
  305. // Fill in header.
  306. chf.width = w;
  307. chf.height = h;
  308. chf.spanCount = spanCount;
  309. chf.walkableHeight = walkableHeight;
  310. chf.walkableClimb = walkableClimb;
  311. chf.maxRegions = 0;
  312. rcVcopy(chf.bmin, hf.bmin);
  313. rcVcopy(chf.bmax, hf.bmax);
  314. chf.bmax[1] += walkableHeight*hf.ch;
  315. chf.cs = hf.cs;
  316. chf.ch = hf.ch;
  317. chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM);
  318. if (!chf.cells)
  319. {
  320. ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
  321. return false;
  322. }
  323. memset(chf.cells, 0, sizeof(rcCompactCell)*w*h);
  324. chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM);
  325. if (!chf.spans)
  326. {
  327. ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
  328. return false;
  329. }
  330. memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
  331. chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM);
  332. if (!chf.areas)
  333. {
  334. ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
  335. return false;
  336. }
  337. memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount);
  338. const int MAX_HEIGHT = 0xffff;
  339. // Fill in cells and spans.
  340. int idx = 0;
  341. for (int y = 0; y < h; ++y)
  342. {
  343. for (int x = 0; x < w; ++x)
  344. {
  345. const rcSpan* s = hf.spans[x + y*w];
  346. // If there are no spans at this cell, just leave the data to index=0, count=0.
  347. if (!s) continue;
  348. rcCompactCell& c = chf.cells[x+y*w];
  349. c.index = idx;
  350. c.count = 0;
  351. while (s)
  352. {
  353. if (s->area != RC_NULL_AREA)
  354. {
  355. const int bot = (int)s->smax;
  356. const int top = s->next ? (int)s->next->smin : MAX_HEIGHT;
  357. chf.spans[idx].y = (unsigned short)rcClamp(bot, 0, 0xffff);
  358. chf.spans[idx].h = (unsigned char)rcClamp(top - bot, 0, 0xff);
  359. chf.areas[idx] = s->area;
  360. idx++;
  361. c.count++;
  362. }
  363. s = s->next;
  364. }
  365. }
  366. }
  367. // Find neighbour connections.
  368. const int MAX_LAYERS = RC_NOT_CONNECTED-1;
  369. int tooHighNeighbour = 0;
  370. for (int y = 0; y < h; ++y)
  371. {
  372. for (int x = 0; x < w; ++x)
  373. {
  374. const rcCompactCell& c = chf.cells[x+y*w];
  375. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  376. {
  377. rcCompactSpan& s = chf.spans[i];
  378. for (int dir = 0; dir < 4; ++dir)
  379. {
  380. rcSetCon(s, dir, RC_NOT_CONNECTED);
  381. const int nx = x + rcGetDirOffsetX(dir);
  382. const int ny = y + rcGetDirOffsetY(dir);
  383. // First check that the neighbour cell is in bounds.
  384. if (nx < 0 || ny < 0 || nx >= w || ny >= h)
  385. continue;
  386. // Iterate over all neighbour spans and check if any of the is
  387. // accessible from current cell.
  388. const rcCompactCell& nc = chf.cells[nx+ny*w];
  389. for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; ++k)
  390. {
  391. const rcCompactSpan& ns = chf.spans[k];
  392. const int bot = rcMax(s.y, ns.y);
  393. const int top = rcMin(s.y+s.h, ns.y+ns.h);
  394. // Check that the gap between the spans is walkable,
  395. // and that the climb height between the gaps is not too high.
  396. if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
  397. {
  398. // Mark direction as walkable.
  399. const int lidx = k - (int)nc.index;
  400. if (lidx < 0 || lidx > MAX_LAYERS)
  401. {
  402. tooHighNeighbour = rcMax(tooHighNeighbour, lidx);
  403. continue;
  404. }
  405. rcSetCon(s, dir, lidx);
  406. break;
  407. }
  408. }
  409. }
  410. }
  411. }
  412. }
  413. if (tooHighNeighbour > MAX_LAYERS)
  414. {
  415. ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
  416. tooHighNeighbour, MAX_LAYERS);
  417. }
  418. ctx->stopTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
  419. return true;
  420. }
  421. /*
  422. static int getHeightfieldMemoryUsage(const rcHeightfield& hf)
  423. {
  424. int size = 0;
  425. size += sizeof(hf);
  426. size += hf.width * hf.height * sizeof(rcSpan*);
  427. rcSpanPool* pool = hf.pools;
  428. while (pool)
  429. {
  430. size += (sizeof(rcSpanPool) - sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL;
  431. pool = pool->next;
  432. }
  433. return size;
  434. }
  435. static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf)
  436. {
  437. int size = 0;
  438. size += sizeof(rcCompactHeightfield);
  439. size += sizeof(rcCompactSpan) * chf.spanCount;
  440. size += sizeof(rcCompactCell) * chf.width * chf.height;
  441. return size;
  442. }
  443. */