Recast.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  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 "Recast.h"
  19. #include "RecastAlloc.h"
  20. #include "RecastAssert.h"
  21. #include <math.h>
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <stdarg.h>
  25. namespace
  26. {
  27. /// Allocates and constructs an object of the given type, returning a pointer.
  28. /// @param[in] allocLifetime Allocation lifetime hint
  29. template<typename T>
  30. T* rcNew(const rcAllocHint allocLifetime)
  31. {
  32. T* ptr = (T*)rcAlloc(sizeof(T), allocLifetime);
  33. ::new(rcNewTag(), (void*)ptr) T();
  34. return ptr;
  35. }
  36. /// Destroys and frees an object allocated with rcNew.
  37. /// @param[in] ptr The object pointer to delete.
  38. template<typename T>
  39. void rcDelete(T* ptr)
  40. {
  41. if (ptr)
  42. {
  43. ptr->~T();
  44. rcFree((void*)ptr);
  45. }
  46. }
  47. } // anonymous namespace
  48. float rcSqrt(float x)
  49. {
  50. return sqrtf(x);
  51. }
  52. void rcContext::log(const rcLogCategory category, const char* format, ...)
  53. {
  54. if (!m_logEnabled)
  55. {
  56. return;
  57. }
  58. static const int MSG_SIZE = 512;
  59. char msg[MSG_SIZE];
  60. va_list argList;
  61. va_start(argList, format);
  62. int len = vsnprintf(msg, MSG_SIZE, format, argList);
  63. if (len >= MSG_SIZE)
  64. {
  65. len = MSG_SIZE - 1;
  66. msg[MSG_SIZE - 1] = '\0';
  67. const char* errorMessage = "Log message was truncated";
  68. doLog(RC_LOG_ERROR, errorMessage, (int)strlen(errorMessage));
  69. }
  70. va_end(argList);
  71. doLog(category, msg, len);
  72. }
  73. void rcContext::doResetLog()
  74. {
  75. // Defined out of line to fix the weak v-tables warning
  76. }
  77. rcHeightfield* rcAllocHeightfield()
  78. {
  79. return rcNew<rcHeightfield>(RC_ALLOC_PERM);
  80. }
  81. void rcFreeHeightField(rcHeightfield* heightfield)
  82. {
  83. rcDelete(heightfield);
  84. }
  85. rcHeightfield::rcHeightfield()
  86. : width()
  87. , height()
  88. , bmin()
  89. , bmax()
  90. , cs()
  91. , ch()
  92. , spans()
  93. , pools()
  94. , freelist()
  95. {
  96. }
  97. rcHeightfield::~rcHeightfield()
  98. {
  99. // Delete span array.
  100. rcFree(spans);
  101. // Delete span pools.
  102. while (pools)
  103. {
  104. rcSpanPool* next = pools->next;
  105. rcFree(pools);
  106. pools = next;
  107. }
  108. }
  109. rcCompactHeightfield* rcAllocCompactHeightfield()
  110. {
  111. return rcNew<rcCompactHeightfield>(RC_ALLOC_PERM);
  112. }
  113. void rcFreeCompactHeightfield(rcCompactHeightfield* compactHeightfield)
  114. {
  115. rcDelete(compactHeightfield);
  116. }
  117. rcCompactHeightfield::rcCompactHeightfield()
  118. : width()
  119. , height()
  120. , spanCount()
  121. , walkableHeight()
  122. , walkableClimb()
  123. , borderSize()
  124. , maxDistance()
  125. , maxRegions()
  126. , bmin()
  127. , bmax()
  128. , cs()
  129. , ch()
  130. , cells()
  131. , spans()
  132. , dist()
  133. , areas()
  134. {
  135. }
  136. rcCompactHeightfield::~rcCompactHeightfield()
  137. {
  138. rcFree(cells);
  139. rcFree(spans);
  140. rcFree(dist);
  141. rcFree(areas);
  142. }
  143. rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet()
  144. {
  145. return rcNew<rcHeightfieldLayerSet>(RC_ALLOC_PERM);
  146. }
  147. void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* layerSet)
  148. {
  149. rcDelete(layerSet);
  150. }
  151. rcHeightfieldLayerSet::rcHeightfieldLayerSet()
  152. : layers()
  153. , nlayers()
  154. {
  155. }
  156. rcHeightfieldLayerSet::~rcHeightfieldLayerSet()
  157. {
  158. for (int i = 0; i < nlayers; ++i)
  159. {
  160. rcFree(layers[i].heights);
  161. rcFree(layers[i].areas);
  162. rcFree(layers[i].cons);
  163. }
  164. rcFree(layers);
  165. }
  166. rcContourSet* rcAllocContourSet()
  167. {
  168. return rcNew<rcContourSet>(RC_ALLOC_PERM);
  169. }
  170. void rcFreeContourSet(rcContourSet* contourSet)
  171. {
  172. rcDelete(contourSet);
  173. }
  174. rcContourSet::rcContourSet()
  175. : conts()
  176. , nconts()
  177. , bmin()
  178. , bmax()
  179. , cs()
  180. , ch()
  181. , width()
  182. , height()
  183. , borderSize()
  184. , maxError()
  185. {
  186. }
  187. rcContourSet::~rcContourSet()
  188. {
  189. for (int i = 0; i < nconts; ++i)
  190. {
  191. rcFree(conts[i].verts);
  192. rcFree(conts[i].rverts);
  193. }
  194. rcFree(conts);
  195. }
  196. rcPolyMesh* rcAllocPolyMesh()
  197. {
  198. return rcNew<rcPolyMesh>(RC_ALLOC_PERM);
  199. }
  200. void rcFreePolyMesh(rcPolyMesh* polyMesh)
  201. {
  202. rcDelete(polyMesh);
  203. }
  204. rcPolyMesh::rcPolyMesh()
  205. : verts()
  206. , polys()
  207. , regs()
  208. , flags()
  209. , areas()
  210. , nverts()
  211. , npolys()
  212. , maxpolys()
  213. , nvp()
  214. , bmin()
  215. , bmax()
  216. , cs()
  217. , ch()
  218. , borderSize()
  219. , maxEdgeError()
  220. {
  221. }
  222. rcPolyMesh::~rcPolyMesh()
  223. {
  224. rcFree(verts);
  225. rcFree(polys);
  226. rcFree(regs);
  227. rcFree(flags);
  228. rcFree(areas);
  229. }
  230. rcPolyMeshDetail* rcAllocPolyMeshDetail()
  231. {
  232. return rcNew<rcPolyMeshDetail>(RC_ALLOC_PERM);
  233. }
  234. void rcFreePolyMeshDetail(rcPolyMeshDetail* detailMesh)
  235. {
  236. if (detailMesh == NULL)
  237. {
  238. return;
  239. }
  240. rcFree(detailMesh->meshes);
  241. rcFree(detailMesh->verts);
  242. rcFree(detailMesh->tris);
  243. rcFree(detailMesh);
  244. }
  245. rcPolyMeshDetail::rcPolyMeshDetail()
  246. : meshes()
  247. , verts()
  248. , tris()
  249. , nmeshes()
  250. , nverts()
  251. , ntris()
  252. {
  253. }
  254. void rcCalcBounds(const float* verts, int numVerts, float* minBounds, float* maxBounds)
  255. {
  256. // Calculate bounding box.
  257. rcVcopy(minBounds, verts);
  258. rcVcopy(maxBounds, verts);
  259. for (int i = 1; i < numVerts; ++i)
  260. {
  261. const float* v = &verts[i * 3];
  262. rcVmin(minBounds, v);
  263. rcVmax(maxBounds, v);
  264. }
  265. }
  266. void rcCalcGridSize(const float* minBounds, const float* maxBounds, const float cellSize, int* sizeX, int* sizeZ)
  267. {
  268. *sizeX = (int)((maxBounds[0] - minBounds[0]) / cellSize + 0.5f);
  269. *sizeZ = (int)((maxBounds[2] - minBounds[2]) / cellSize + 0.5f);
  270. }
  271. bool rcCreateHeightfield(rcContext* context, rcHeightfield& heightfield, int sizeX, int sizeZ,
  272. const float* minBounds, const float* maxBounds,
  273. float cellSize, float cellHeight)
  274. {
  275. rcIgnoreUnused(context);
  276. heightfield.width = sizeX;
  277. heightfield.height = sizeZ;
  278. rcVcopy(heightfield.bmin, minBounds);
  279. rcVcopy(heightfield.bmax, maxBounds);
  280. heightfield.cs = cellSize;
  281. heightfield.ch = cellHeight;
  282. heightfield.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*) * heightfield.width * heightfield.height, RC_ALLOC_PERM);
  283. if (!heightfield.spans)
  284. {
  285. return false;
  286. }
  287. memset(heightfield.spans, 0, sizeof(rcSpan*) * heightfield.width * heightfield.height);
  288. return true;
  289. }
  290. static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* faceNormal)
  291. {
  292. float e0[3], e1[3];
  293. rcVsub(e0, v1, v0);
  294. rcVsub(e1, v2, v0);
  295. rcVcross(faceNormal, e0, e1);
  296. rcVnormalize(faceNormal);
  297. }
  298. void rcMarkWalkableTriangles(rcContext* context, const float walkableSlopeAngle,
  299. const float* verts, const int numVerts,
  300. const int* tris, const int numTris,
  301. unsigned char* triAreaIDs)
  302. {
  303. rcIgnoreUnused(context);
  304. rcIgnoreUnused(numVerts);
  305. const float walkableThr = cosf(walkableSlopeAngle / 180.0f * RC_PI);
  306. float norm[3];
  307. for (int i = 0; i < numTris; ++i)
  308. {
  309. const int* tri = &tris[i * 3];
  310. calcTriNormal(&verts[tri[0] * 3], &verts[tri[1] * 3], &verts[tri[2] * 3], norm);
  311. // Check if the face is walkable.
  312. if (norm[1] > walkableThr)
  313. {
  314. triAreaIDs[i] = RC_WALKABLE_AREA;
  315. }
  316. }
  317. }
  318. void rcClearUnwalkableTriangles(rcContext* context, const float walkableSlopeAngle,
  319. const float* verts, int numVerts,
  320. const int* tris, int numTris,
  321. unsigned char* triAreaIDs)
  322. {
  323. rcIgnoreUnused(context);
  324. rcIgnoreUnused(numVerts);
  325. // The minimum Y value for a face normal of a triangle with a walkable slope.
  326. const float walkableLimitY = cosf(walkableSlopeAngle / 180.0f * RC_PI);
  327. float faceNormal[3];
  328. for (int i = 0; i < numTris; ++i)
  329. {
  330. const int* tri = &tris[i * 3];
  331. calcTriNormal(&verts[tri[0] * 3], &verts[tri[1] * 3], &verts[tri[2] * 3], faceNormal);
  332. // Check if the face is walkable.
  333. if (faceNormal[1] <= walkableLimitY)
  334. {
  335. triAreaIDs[i] = RC_NULL_AREA;
  336. }
  337. }
  338. }
  339. int rcGetHeightFieldSpanCount(rcContext* context, const rcHeightfield& heightfield)
  340. {
  341. rcIgnoreUnused(context);
  342. const int numCols = heightfield.width * heightfield.height;
  343. int spanCount = 0;
  344. for (int columnIndex = 0; columnIndex < numCols; ++columnIndex)
  345. {
  346. for (rcSpan* span = heightfield.spans[columnIndex]; span != NULL; span = span->next)
  347. {
  348. if (span->area != RC_NULL_AREA)
  349. {
  350. spanCount++;
  351. }
  352. }
  353. }
  354. return spanCount;
  355. }
  356. bool rcBuildCompactHeightfield(rcContext* context, const int walkableHeight, const int walkableClimb,
  357. const rcHeightfield& heightfield, rcCompactHeightfield& compactHeightfield)
  358. {
  359. rcAssert(context);
  360. rcScopedTimer timer(context, RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
  361. const int xSize = heightfield.width;
  362. const int zSize = heightfield.height;
  363. const int spanCount = rcGetHeightFieldSpanCount(context, heightfield);
  364. // Fill in header.
  365. compactHeightfield.width = xSize;
  366. compactHeightfield.height = zSize;
  367. compactHeightfield.spanCount = spanCount;
  368. compactHeightfield.walkableHeight = walkableHeight;
  369. compactHeightfield.walkableClimb = walkableClimb;
  370. compactHeightfield.maxRegions = 0;
  371. rcVcopy(compactHeightfield.bmin, heightfield.bmin);
  372. rcVcopy(compactHeightfield.bmax, heightfield.bmax);
  373. compactHeightfield.bmax[1] += walkableHeight * heightfield.ch;
  374. compactHeightfield.cs = heightfield.cs;
  375. compactHeightfield.ch = heightfield.ch;
  376. compactHeightfield.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell) * xSize * zSize, RC_ALLOC_PERM);
  377. if (!compactHeightfield.cells)
  378. {
  379. context->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", xSize * zSize);
  380. return false;
  381. }
  382. memset(compactHeightfield.cells, 0, sizeof(rcCompactCell) * xSize * zSize);
  383. compactHeightfield.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan) * spanCount, RC_ALLOC_PERM);
  384. if (!compactHeightfield.spans)
  385. {
  386. context->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
  387. return false;
  388. }
  389. memset(compactHeightfield.spans, 0, sizeof(rcCompactSpan) * spanCount);
  390. compactHeightfield.areas = (unsigned char*)rcAlloc(sizeof(unsigned char) * spanCount, RC_ALLOC_PERM);
  391. if (!compactHeightfield.areas)
  392. {
  393. context->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
  394. return false;
  395. }
  396. memset(compactHeightfield.areas, RC_NULL_AREA, sizeof(unsigned char) * spanCount);
  397. const int MAX_HEIGHT = 0xffff;
  398. // Fill in cells and spans.
  399. int currentCellIndex = 0;
  400. const int numColumns = xSize * zSize;
  401. for (int columnIndex = 0; columnIndex < numColumns; ++columnIndex)
  402. {
  403. const rcSpan* span = heightfield.spans[columnIndex];
  404. // If there are no spans at this cell, just leave the data to index=0, count=0.
  405. if (span == NULL)
  406. {
  407. continue;
  408. }
  409. rcCompactCell& cell = compactHeightfield.cells[columnIndex];
  410. cell.index = currentCellIndex;
  411. cell.count = 0;
  412. for (; span != NULL; span = span->next)
  413. {
  414. if (span->area != RC_NULL_AREA)
  415. {
  416. const int bot = (int)span->smax;
  417. const int top = span->next ? (int)span->next->smin : MAX_HEIGHT;
  418. compactHeightfield.spans[currentCellIndex].y = (unsigned short)rcClamp(bot, 0, 0xffff);
  419. compactHeightfield.spans[currentCellIndex].h = (unsigned char)rcClamp(top - bot, 0, 0xff);
  420. compactHeightfield.areas[currentCellIndex] = span->area;
  421. currentCellIndex++;
  422. cell.count++;
  423. }
  424. }
  425. }
  426. // Find neighbour connections.
  427. const int MAX_LAYERS = RC_NOT_CONNECTED - 1;
  428. int maxLayerIndex = 0;
  429. const int zStride = xSize; // for readability
  430. for (int z = 0; z < zSize; ++z)
  431. {
  432. for (int x = 0; x < xSize; ++x)
  433. {
  434. const rcCompactCell& cell = compactHeightfield.cells[x + z * zStride];
  435. for (int i = (int)cell.index, ni = (int)(cell.index + cell.count); i < ni; ++i)
  436. {
  437. rcCompactSpan& span = compactHeightfield.spans[i];
  438. for (int dir = 0; dir < 4; ++dir)
  439. {
  440. rcSetCon(span, dir, RC_NOT_CONNECTED);
  441. const int neighborX = x + rcGetDirOffsetX(dir);
  442. const int neighborZ = z + rcGetDirOffsetY(dir);
  443. // First check that the neighbour cell is in bounds.
  444. if (neighborX < 0 || neighborZ < 0 || neighborX >= xSize || neighborZ >= zSize)
  445. {
  446. continue;
  447. }
  448. // Iterate over all neighbour spans and check if any of the is
  449. // accessible from current cell.
  450. const rcCompactCell& neighborCell = compactHeightfield.cells[neighborX + neighborZ * zStride];
  451. for (int k = (int)neighborCell.index, nk = (int)(neighborCell.index + neighborCell.count); k < nk; ++k)
  452. {
  453. const rcCompactSpan& neighborSpan = compactHeightfield.spans[k];
  454. const int bot = rcMax(span.y, neighborSpan.y);
  455. const int top = rcMin(span.y + span.h, neighborSpan.y + neighborSpan.h);
  456. // Check that the gap between the spans is walkable,
  457. // and that the climb height between the gaps is not too high.
  458. if ((top - bot) >= walkableHeight && rcAbs((int)neighborSpan.y - (int)span.y) <= walkableClimb)
  459. {
  460. // Mark direction as walkable.
  461. const int layerIndex = k - (int)neighborCell.index;
  462. if (layerIndex < 0 || layerIndex > MAX_LAYERS)
  463. {
  464. maxLayerIndex = rcMax(maxLayerIndex, layerIndex);
  465. continue;
  466. }
  467. rcSetCon(span, dir, layerIndex);
  468. break;
  469. }
  470. }
  471. }
  472. }
  473. }
  474. }
  475. if (maxLayerIndex > MAX_LAYERS)
  476. {
  477. context->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
  478. maxLayerIndex, MAX_LAYERS);
  479. }
  480. return true;
  481. }