RecastRasterization.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
  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 <math.h>
  19. #include <stdio.h>
  20. #include "Recast.h"
  21. #include "RecastAlloc.h"
  22. #include "RecastAssert.h"
  23. /// Check whether two bounding boxes overlap
  24. ///
  25. /// @param[in] aMin Min axis extents of bounding box A
  26. /// @param[in] aMax Max axis extents of bounding box A
  27. /// @param[in] bMin Min axis extents of bounding box B
  28. /// @param[in] bMax Max axis extents of bounding box B
  29. /// @returns true if the two bounding boxes overlap. False otherwise.
  30. static bool overlapBounds(const float* aMin, const float* aMax, const float* bMin, const float* bMax)
  31. {
  32. return
  33. aMin[0] <= bMax[0] && aMax[0] >= bMin[0] &&
  34. aMin[1] <= bMax[1] && aMax[1] >= bMin[1] &&
  35. aMin[2] <= bMax[2] && aMax[2] >= bMin[2];
  36. }
  37. /// Allocates a new span in the heightfield.
  38. /// Use a memory pool and free list to minimize actual allocations.
  39. ///
  40. /// @param[in] hf The heightfield
  41. /// @returns A pointer to the allocated or re-used span memory.
  42. static rcSpan* allocSpan(rcHeightfield& hf)
  43. {
  44. // If necessary, allocate new page and update the freelist.
  45. if (hf.freelist == NULL || hf.freelist->next == NULL)
  46. {
  47. // Create new page.
  48. // Allocate memory for the new pool.
  49. rcSpanPool* spanPool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM);
  50. if (spanPool == NULL)
  51. {
  52. return NULL;
  53. }
  54. // Add the pool into the list of pools.
  55. spanPool->next = hf.pools;
  56. hf.pools = spanPool;
  57. // Add new spans to the free list.
  58. rcSpan* freeList = hf.freelist;
  59. rcSpan* head = &spanPool->items[0];
  60. rcSpan* it = &spanPool->items[RC_SPANS_PER_POOL];
  61. do
  62. {
  63. --it;
  64. it->next = freeList;
  65. freeList = it;
  66. }
  67. while (it != head);
  68. hf.freelist = it;
  69. }
  70. // Pop item from the front of the free list.
  71. rcSpan* newSpan = hf.freelist;
  72. hf.freelist = hf.freelist->next;
  73. return newSpan;
  74. }
  75. /// Releases the memory used by the span back to the heightfield, so it can be re-used for new spans.
  76. /// @param[in] hf The heightfield.
  77. /// @param[in] span A pointer to the span to free
  78. static void freeSpan(rcHeightfield& hf, rcSpan* span)
  79. {
  80. if (span == NULL)
  81. {
  82. return;
  83. }
  84. // Add the span to the front of the free list.
  85. span->next = hf.freelist;
  86. hf.freelist = span;
  87. }
  88. /// Adds a span to the heightfield. If the new span overlaps existing spans,
  89. /// it will merge the new span with the existing ones.
  90. ///
  91. /// @param[in] hf Heightfield to add spans to
  92. /// @param[in] x The new span's column cell x index
  93. /// @param[in] z The new span's column cell z index
  94. /// @param[in] min The new span's minimum cell index
  95. /// @param[in] max The new span's maximum cell index
  96. /// @param[in] areaID The new span's area type ID
  97. /// @param[in] flagMergeThreshold How close two spans maximum extents need to be to merge area type IDs
  98. static bool addSpan(rcHeightfield& hf,
  99. const int x, const int z,
  100. const unsigned short min, const unsigned short max,
  101. const unsigned char areaID, const int flagMergeThreshold)
  102. {
  103. // Create the new span.
  104. rcSpan* newSpan = allocSpan(hf);
  105. if (newSpan == NULL)
  106. {
  107. return false;
  108. }
  109. newSpan->smin = min;
  110. newSpan->smax = max;
  111. newSpan->area = areaID;
  112. newSpan->next = NULL;
  113. const int columnIndex = x + z * hf.width;
  114. rcSpan* previousSpan = NULL;
  115. rcSpan* currentSpan = hf.spans[columnIndex];
  116. // Insert the new span, possibly merging it with existing spans.
  117. while (currentSpan != NULL)
  118. {
  119. if (currentSpan->smin > newSpan->smax)
  120. {
  121. // Current span is completely after the new span, break.
  122. break;
  123. }
  124. if (currentSpan->smax < newSpan->smin)
  125. {
  126. // Current span is completely before the new span. Keep going.
  127. previousSpan = currentSpan;
  128. currentSpan = currentSpan->next;
  129. }
  130. else
  131. {
  132. // The new span overlaps with an existing span. Merge them.
  133. if (currentSpan->smin < newSpan->smin)
  134. {
  135. newSpan->smin = currentSpan->smin;
  136. }
  137. if (currentSpan->smax > newSpan->smax)
  138. {
  139. newSpan->smax = currentSpan->smax;
  140. }
  141. // Merge flags.
  142. if (rcAbs((int)newSpan->smax - (int)currentSpan->smax) <= flagMergeThreshold)
  143. {
  144. // Higher area ID numbers indicate higher resolution priority.
  145. newSpan->area = rcMax(newSpan->area, currentSpan->area);
  146. }
  147. // Remove the current span since it's now merged with newSpan.
  148. // Keep going because there might be other overlapping spans that also need to be merged.
  149. rcSpan* next = currentSpan->next;
  150. freeSpan(hf, currentSpan);
  151. if (previousSpan)
  152. {
  153. previousSpan->next = next;
  154. }
  155. else
  156. {
  157. hf.spans[columnIndex] = next;
  158. }
  159. currentSpan = next;
  160. }
  161. }
  162. // Insert new span after prev
  163. if (previousSpan != NULL)
  164. {
  165. newSpan->next = previousSpan->next;
  166. previousSpan->next = newSpan;
  167. }
  168. else
  169. {
  170. // This span should go before the others in the list
  171. newSpan->next = hf.spans[columnIndex];
  172. hf.spans[columnIndex] = newSpan;
  173. }
  174. return true;
  175. }
  176. bool rcAddSpan(rcContext* context, rcHeightfield& heightfield,
  177. const int x, const int z,
  178. const unsigned short spanMin, const unsigned short spanMax,
  179. const unsigned char areaID, const int flagMergeThreshold)
  180. {
  181. rcAssert(context);
  182. if (!addSpan(heightfield, x, z, spanMin, spanMax, areaID, flagMergeThreshold))
  183. {
  184. context->log(RC_LOG_ERROR, "rcAddSpan: Out of memory.");
  185. return false;
  186. }
  187. return true;
  188. }
  189. enum rcAxis
  190. {
  191. RC_AXIS_X = 0,
  192. RC_AXIS_Y = 1,
  193. RC_AXIS_Z = 2
  194. };
  195. /// Divides a convex polygon of max 12 vertices into two convex polygons
  196. /// across a separating axis.
  197. ///
  198. /// @param[in] inVerts The input polygon vertices
  199. /// @param[in] inVertsCount The number of input polygon vertices
  200. /// @param[out] outVerts1 Resulting polygon 1's vertices
  201. /// @param[out] outVerts1Count The number of resulting polygon 1 vertices
  202. /// @param[out] outVerts2 Resulting polygon 2's vertices
  203. /// @param[out] outVerts2Count The number of resulting polygon 2 vertices
  204. /// @param[in] axisOffset THe offset along the specified axis
  205. /// @param[in] axis The separating axis
  206. static void dividePoly(const float* inVerts, int inVertsCount,
  207. float* outVerts1, int* outVerts1Count,
  208. float* outVerts2, int* outVerts2Count,
  209. float axisOffset, rcAxis axis)
  210. {
  211. rcAssert(inVertsCount <= 12);
  212. // How far positive or negative away from the separating axis is each vertex.
  213. float inVertAxisDelta[12];
  214. for (int inVert = 0; inVert < inVertsCount; ++inVert)
  215. {
  216. inVertAxisDelta[inVert] = axisOffset - inVerts[inVert * 3 + axis];
  217. }
  218. int poly1Vert = 0;
  219. int poly2Vert = 0;
  220. for (int inVertA = 0, inVertB = inVertsCount - 1; inVertA < inVertsCount; inVertB = inVertA, ++inVertA)
  221. {
  222. // If the two vertices are on the same side of the separating axis
  223. bool sameSide = (inVertAxisDelta[inVertA] >= 0) == (inVertAxisDelta[inVertB] >= 0);
  224. if (!sameSide)
  225. {
  226. float s = inVertAxisDelta[inVertB] / (inVertAxisDelta[inVertB] - inVertAxisDelta[inVertA]);
  227. outVerts1[poly1Vert * 3 + 0] = inVerts[inVertB * 3 + 0] + (inVerts[inVertA * 3 + 0] - inVerts[inVertB * 3 + 0]) * s;
  228. outVerts1[poly1Vert * 3 + 1] = inVerts[inVertB * 3 + 1] + (inVerts[inVertA * 3 + 1] - inVerts[inVertB * 3 + 1]) * s;
  229. outVerts1[poly1Vert * 3 + 2] = inVerts[inVertB * 3 + 2] + (inVerts[inVertA * 3 + 2] - inVerts[inVertB * 3 + 2]) * s;
  230. rcVcopy(&outVerts2[poly2Vert * 3], &outVerts1[poly1Vert * 3]);
  231. poly1Vert++;
  232. poly2Vert++;
  233. // add the inVertA point to the right polygon. Do NOT add points that are on the dividing line
  234. // since these were already added above
  235. if (inVertAxisDelta[inVertA] > 0)
  236. {
  237. rcVcopy(&outVerts1[poly1Vert * 3], &inVerts[inVertA * 3]);
  238. poly1Vert++;
  239. }
  240. else if (inVertAxisDelta[inVertA] < 0)
  241. {
  242. rcVcopy(&outVerts2[poly2Vert * 3], &inVerts[inVertA * 3]);
  243. poly2Vert++;
  244. }
  245. }
  246. else
  247. {
  248. // add the inVertA point to the right polygon. Addition is done even for points on the dividing line
  249. if (inVertAxisDelta[inVertA] >= 0)
  250. {
  251. rcVcopy(&outVerts1[poly1Vert * 3], &inVerts[inVertA * 3]);
  252. poly1Vert++;
  253. if (inVertAxisDelta[inVertA] != 0)
  254. {
  255. continue;
  256. }
  257. }
  258. rcVcopy(&outVerts2[poly2Vert * 3], &inVerts[inVertA * 3]);
  259. poly2Vert++;
  260. }
  261. }
  262. *outVerts1Count = poly1Vert;
  263. *outVerts2Count = poly2Vert;
  264. }
  265. /// Rasterize a single triangle to the heightfield.
  266. ///
  267. /// This code is extremely hot, so much care should be given to maintaining maximum perf here.
  268. ///
  269. /// @param[in] v0 Triangle vertex 0
  270. /// @param[in] v1 Triangle vertex 1
  271. /// @param[in] v2 Triangle vertex 2
  272. /// @param[in] areaID The area ID to assign to the rasterized spans
  273. /// @param[in] hf Heightfield to rasterize into
  274. /// @param[in] hfBBMin The min extents of the heightfield bounding box
  275. /// @param[in] hfBBMax The max extents of the heightfield bounding box
  276. /// @param[in] cellSize The x and z axis size of a voxel in the heightfield
  277. /// @param[in] inverseCellSize 1 / cellSize
  278. /// @param[in] inverseCellHeight 1 / cellHeight
  279. /// @param[in] flagMergeThreshold The threshold in which area flags will be merged
  280. /// @returns true if the operation completes successfully. false if there was an error adding spans to the heightfield.
  281. static bool rasterizeTri(const float* v0, const float* v1, const float* v2,
  282. const unsigned char areaID, rcHeightfield& hf,
  283. const float* hfBBMin, const float* hfBBMax,
  284. const float cellSize, const float inverseCellSize, const float inverseCellHeight,
  285. const int flagMergeThreshold)
  286. {
  287. // Calculate the bounding box of the triangle.
  288. float triBBMin[3];
  289. rcVcopy(triBBMin, v0);
  290. rcVmin(triBBMin, v1);
  291. rcVmin(triBBMin, v2);
  292. float triBBMax[3];
  293. rcVcopy(triBBMax, v0);
  294. rcVmax(triBBMax, v1);
  295. rcVmax(triBBMax, v2);
  296. // If the triangle does not touch the bounding box of the heightfield, skip the triangle.
  297. if (!overlapBounds(triBBMin, triBBMax, hfBBMin, hfBBMax))
  298. {
  299. return true;
  300. }
  301. const int w = hf.width;
  302. const int h = hf.height;
  303. const float by = hfBBMax[1] - hfBBMin[1];
  304. // Calculate the footprint of the triangle on the grid's z-axis
  305. int z0 = (int)((triBBMin[2] - hfBBMin[2]) * inverseCellSize);
  306. int z1 = (int)((triBBMax[2] - hfBBMin[2]) * inverseCellSize);
  307. // use -1 rather than 0 to cut the polygon properly at the start of the tile
  308. z0 = rcClamp(z0, -1, h - 1);
  309. z1 = rcClamp(z1, 0, h - 1);
  310. // Clip the triangle into all grid cells it touches.
  311. float buf[7 * 3 * 4];
  312. float* in = buf;
  313. float* inRow = buf + 7 * 3;
  314. float* p1 = inRow + 7 * 3;
  315. float* p2 = p1 + 7 * 3;
  316. rcVcopy(&in[0], v0);
  317. rcVcopy(&in[1 * 3], v1);
  318. rcVcopy(&in[2 * 3], v2);
  319. int nvRow;
  320. int nvIn = 3;
  321. for (int z = z0; z <= z1; ++z)
  322. {
  323. // Clip polygon to row. Store the remaining polygon as well
  324. const float cellZ = hfBBMin[2] + (float)z * cellSize;
  325. dividePoly(in, nvIn, inRow, &nvRow, p1, &nvIn, cellZ + cellSize, RC_AXIS_Z);
  326. rcSwap(in, p1);
  327. if (nvRow < 3)
  328. {
  329. continue;
  330. }
  331. if (z < 0)
  332. {
  333. continue;
  334. }
  335. // find X-axis bounds of the row
  336. float minX = inRow[0];
  337. float maxX = inRow[0];
  338. for (int vert = 1; vert < nvRow; ++vert)
  339. {
  340. if (minX > inRow[vert * 3])
  341. {
  342. minX = inRow[vert * 3];
  343. }
  344. if (maxX < inRow[vert * 3])
  345. {
  346. maxX = inRow[vert * 3];
  347. }
  348. }
  349. int x0 = (int)((minX - hfBBMin[0]) * inverseCellSize);
  350. int x1 = (int)((maxX - hfBBMin[0]) * inverseCellSize);
  351. if (x1 < 0 || x0 >= w)
  352. {
  353. continue;
  354. }
  355. x0 = rcClamp(x0, -1, w - 1);
  356. x1 = rcClamp(x1, 0, w - 1);
  357. int nv;
  358. int nv2 = nvRow;
  359. for (int x = x0; x <= x1; ++x)
  360. {
  361. // Clip polygon to column. store the remaining polygon as well
  362. const float cx = hfBBMin[0] + (float)x * cellSize;
  363. dividePoly(inRow, nv2, p1, &nv, p2, &nv2, cx + cellSize, RC_AXIS_X);
  364. rcSwap(inRow, p2);
  365. if (nv < 3)
  366. {
  367. continue;
  368. }
  369. if (x < 0)
  370. {
  371. continue;
  372. }
  373. // Calculate min and max of the span.
  374. float spanMin = p1[1];
  375. float spanMax = p1[1];
  376. for (int vert = 1; vert < nv; ++vert)
  377. {
  378. spanMin = rcMin(spanMin, p1[vert * 3 + 1]);
  379. spanMax = rcMax(spanMax, p1[vert * 3 + 1]);
  380. }
  381. spanMin -= hfBBMin[1];
  382. spanMax -= hfBBMin[1];
  383. // Skip the span if it's completely outside the heightfield bounding box
  384. if (spanMax < 0.0f)
  385. {
  386. continue;
  387. }
  388. if (spanMin > by)
  389. {
  390. continue;
  391. }
  392. // Clamp the span to the heightfield bounding box.
  393. if (spanMin < 0.0f)
  394. {
  395. spanMin = 0;
  396. }
  397. if (spanMax > by)
  398. {
  399. spanMax = by;
  400. }
  401. // Snap the span to the heightfield height grid.
  402. unsigned short spanMinCellIndex = (unsigned short)rcClamp((int)floorf(spanMin * inverseCellHeight), 0, RC_SPAN_MAX_HEIGHT);
  403. unsigned short spanMaxCellIndex = (unsigned short)rcClamp((int)ceilf(spanMax * inverseCellHeight), (int)spanMinCellIndex + 1, RC_SPAN_MAX_HEIGHT);
  404. if (!addSpan(hf, x, z, spanMinCellIndex, spanMaxCellIndex, areaID, flagMergeThreshold))
  405. {
  406. return false;
  407. }
  408. }
  409. }
  410. return true;
  411. }
  412. bool rcRasterizeTriangle(rcContext* context,
  413. const float* v0, const float* v1, const float* v2,
  414. const unsigned char areaID, rcHeightfield& heightfield, const int flagMergeThreshold)
  415. {
  416. rcAssert(context != NULL);
  417. rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
  418. // Rasterize the single triangle.
  419. const float inverseCellSize = 1.0f / heightfield.cs;
  420. const float inverseCellHeight = 1.0f / heightfield.ch;
  421. if (!rasterizeTri(v0, v1, v2, areaID, heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
  422. {
  423. context->log(RC_LOG_ERROR, "rcRasterizeTriangle: Out of memory.");
  424. return false;
  425. }
  426. return true;
  427. }
  428. bool rcRasterizeTriangles(rcContext* context,
  429. const float* verts, const int /*nv*/,
  430. const int* tris, const unsigned char* triAreaIDs, const int numTris,
  431. rcHeightfield& heightfield, const int flagMergeThreshold)
  432. {
  433. rcAssert(context != NULL);
  434. rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
  435. // Rasterize the triangles.
  436. const float inverseCellSize = 1.0f / heightfield.cs;
  437. const float inverseCellHeight = 1.0f / heightfield.ch;
  438. for (int triIndex = 0; triIndex < numTris; ++triIndex)
  439. {
  440. const float* v0 = &verts[tris[triIndex * 3 + 0] * 3];
  441. const float* v1 = &verts[tris[triIndex * 3 + 1] * 3];
  442. const float* v2 = &verts[tris[triIndex * 3 + 2] * 3];
  443. if (!rasterizeTri(v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
  444. {
  445. context->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
  446. return false;
  447. }
  448. }
  449. return true;
  450. }
  451. bool rcRasterizeTriangles(rcContext* context,
  452. const float* verts, const int /*nv*/,
  453. const unsigned short* tris, const unsigned char* triAreaIDs, const int numTris,
  454. rcHeightfield& heightfield, const int flagMergeThreshold)
  455. {
  456. rcAssert(context != NULL);
  457. rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
  458. // Rasterize the triangles.
  459. const float inverseCellSize = 1.0f / heightfield.cs;
  460. const float inverseCellHeight = 1.0f / heightfield.ch;
  461. for (int triIndex = 0; triIndex < numTris; ++triIndex)
  462. {
  463. const float* v0 = &verts[tris[triIndex * 3 + 0] * 3];
  464. const float* v1 = &verts[tris[triIndex * 3 + 1] * 3];
  465. const float* v2 = &verts[tris[triIndex * 3 + 2] * 3];
  466. if (!rasterizeTri(v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
  467. {
  468. context->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
  469. return false;
  470. }
  471. }
  472. return true;
  473. }
  474. bool rcRasterizeTriangles(rcContext* context,
  475. const float* verts, const unsigned char* triAreaIDs, const int numTris,
  476. rcHeightfield& heightfield, const int flagMergeThreshold)
  477. {
  478. rcAssert(context != NULL);
  479. rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
  480. // Rasterize the triangles.
  481. const float inverseCellSize = 1.0f / heightfield.cs;
  482. const float inverseCellHeight = 1.0f / heightfield.ch;
  483. for (int triIndex = 0; triIndex < numTris; ++triIndex)
  484. {
  485. const float* v0 = &verts[(triIndex * 3 + 0) * 3];
  486. const float* v1 = &verts[(triIndex * 3 + 1) * 3];
  487. const float* v2 = &verts[(triIndex * 3 + 2) * 3];
  488. if (!rasterizeTri(v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
  489. {
  490. context->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
  491. return false;
  492. }
  493. }
  494. return true;
  495. }