RecastRasterization.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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. #define _USE_MATH_DEFINES
  19. #include <math.h>
  20. #include <stdio.h>
  21. #include "Recast.h"
  22. #include "RecastAlloc.h"
  23. #include "RecastAssert.h"
  24. inline bool overlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax)
  25. {
  26. bool overlap = true;
  27. overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
  28. overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
  29. overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
  30. return overlap;
  31. }
  32. inline bool overlapInterval(unsigned short amin, unsigned short amax,
  33. unsigned short bmin, unsigned short bmax)
  34. {
  35. if (amax < bmin) return false;
  36. if (amin > bmax) return false;
  37. return true;
  38. }
  39. static rcSpan* allocSpan(rcHeightfield& hf)
  40. {
  41. // If running out of memory, allocate new page and update the freelist.
  42. if (!hf.freelist || !hf.freelist->next)
  43. {
  44. // Create new page.
  45. // Allocate memory for the new pool.
  46. rcSpanPool* pool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM);
  47. if (!pool) return 0;
  48. pool->next = 0;
  49. // Add the pool into the list of pools.
  50. pool->next = hf.pools;
  51. hf.pools = pool;
  52. // Add new items to the free list.
  53. rcSpan* freelist = hf.freelist;
  54. rcSpan* head = &pool->items[0];
  55. rcSpan* it = &pool->items[RC_SPANS_PER_POOL];
  56. do
  57. {
  58. --it;
  59. it->next = freelist;
  60. freelist = it;
  61. }
  62. while (it != head);
  63. hf.freelist = it;
  64. }
  65. // Pop item from in front of the free list.
  66. rcSpan* it = hf.freelist;
  67. hf.freelist = hf.freelist->next;
  68. return it;
  69. }
  70. static void freeSpan(rcHeightfield& hf, rcSpan* ptr)
  71. {
  72. if (!ptr) return;
  73. // Add the node in front of the free list.
  74. ptr->next = hf.freelist;
  75. hf.freelist = ptr;
  76. }
  77. static void addSpan(rcHeightfield& hf, const int x, const int y,
  78. const unsigned short smin, const unsigned short smax,
  79. const unsigned char area, const int flagMergeThr)
  80. {
  81. int idx = x + y*hf.width;
  82. rcSpan* s = allocSpan(hf);
  83. s->smin = smin;
  84. s->smax = smax;
  85. s->area = area;
  86. s->next = 0;
  87. // Empty cell, add the first span.
  88. if (!hf.spans[idx])
  89. {
  90. hf.spans[idx] = s;
  91. return;
  92. }
  93. rcSpan* prev = 0;
  94. rcSpan* cur = hf.spans[idx];
  95. // Insert and merge spans.
  96. while (cur)
  97. {
  98. if (cur->smin > s->smax)
  99. {
  100. // Current span is further than the new span, break.
  101. break;
  102. }
  103. else if (cur->smax < s->smin)
  104. {
  105. // Current span is before the new span advance.
  106. prev = cur;
  107. cur = cur->next;
  108. }
  109. else
  110. {
  111. // Merge spans.
  112. if (cur->smin < s->smin)
  113. s->smin = cur->smin;
  114. if (cur->smax > s->smax)
  115. s->smax = cur->smax;
  116. // Merge flags.
  117. if (rcAbs((int)s->smax - (int)cur->smax) <= flagMergeThr)
  118. s->area = rcMax(s->area, cur->area);
  119. // Remove current span.
  120. rcSpan* next = cur->next;
  121. freeSpan(hf, cur);
  122. if (prev)
  123. prev->next = next;
  124. else
  125. hf.spans[idx] = next;
  126. cur = next;
  127. }
  128. }
  129. // Insert new span.
  130. if (prev)
  131. {
  132. s->next = prev->next;
  133. prev->next = s;
  134. }
  135. else
  136. {
  137. s->next = hf.spans[idx];
  138. hf.spans[idx] = s;
  139. }
  140. }
  141. /// @par
  142. ///
  143. /// The span addition can be set to favor flags. If the span is merged to
  144. /// another span and the new @p smax is within @p flagMergeThr units
  145. /// from the existing span, the span flags are merged.
  146. ///
  147. /// @see rcHeightfield, rcSpan.
  148. void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
  149. const unsigned short smin, const unsigned short smax,
  150. const unsigned char area, const int flagMergeThr)
  151. {
  152. // rcAssert(ctx);
  153. addSpan(hf, x,y, smin, smax, area, flagMergeThr);
  154. }
  155. // divides a convex polygons into two convex polygons on both sides of a line
  156. static void dividePoly(const float* in, int nin,
  157. float* out1, int* nout1,
  158. float* out2, int* nout2,
  159. float x, int axis)
  160. {
  161. float d[12];
  162. for (int i = 0; i < nin; ++i)
  163. d[i] = x - in[i*3+axis];
  164. int m = 0, n = 0;
  165. for (int i = 0, j = nin-1; i < nin; j=i, ++i)
  166. {
  167. bool ina = d[j] >= 0;
  168. bool inb = d[i] >= 0;
  169. if (ina != inb)
  170. {
  171. float s = d[j] / (d[j] - d[i]);
  172. out1[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
  173. out1[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
  174. out1[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
  175. rcVcopy(out2 + n*3, out1 + m*3);
  176. m++;
  177. n++;
  178. // add the i'th point to the right polygon. Do NOT add points that are on the dividing line
  179. // since these were already added above
  180. if (d[i] > 0)
  181. {
  182. rcVcopy(out1 + m*3, in + i*3);
  183. m++;
  184. }
  185. else if (d[i] < 0)
  186. {
  187. rcVcopy(out2 + n*3, in + i*3);
  188. n++;
  189. }
  190. }
  191. else // same side
  192. {
  193. // add the i'th point to the right polygon. Addition is done even for points on the dividing line
  194. if (d[i] >= 0)
  195. {
  196. rcVcopy(out1 + m*3, in + i*3);
  197. m++;
  198. if (d[i] != 0)
  199. continue;
  200. }
  201. rcVcopy(out2 + n*3, in + i*3);
  202. n++;
  203. }
  204. }
  205. *nout1 = m;
  206. *nout2 = n;
  207. }
  208. static void rasterizeTri(const float* v0, const float* v1, const float* v2,
  209. const unsigned char area, rcHeightfield& hf,
  210. const float* bmin, const float* bmax,
  211. const float cs, const float ics, const float ich,
  212. const int flagMergeThr)
  213. {
  214. const int w = hf.width;
  215. const int h = hf.height;
  216. float tmin[3], tmax[3];
  217. const float by = bmax[1] - bmin[1];
  218. // Calculate the bounding box of the triangle.
  219. rcVcopy(tmin, v0);
  220. rcVcopy(tmax, v0);
  221. rcVmin(tmin, v1);
  222. rcVmin(tmin, v2);
  223. rcVmax(tmax, v1);
  224. rcVmax(tmax, v2);
  225. // If the triangle does not touch the bbox of the heightfield, skip the triagle.
  226. if (!overlapBounds(bmin, bmax, tmin, tmax))
  227. return;
  228. // Calculate the footprint of the triangle on the grid's y-axis
  229. int y0 = (int)((tmin[2] - bmin[2])*ics);
  230. int y1 = (int)((tmax[2] - bmin[2])*ics);
  231. y0 = rcClamp(y0, 0, h-1);
  232. y1 = rcClamp(y1, 0, h-1);
  233. // Clip the triangle into all grid cells it touches.
  234. float buf[7*3*4];
  235. float *in = buf, *inrow = buf+7*3, *p1 = inrow+7*3, *p2 = p1+7*3;
  236. rcVcopy(&in[0], v0);
  237. rcVcopy(&in[1*3], v1);
  238. rcVcopy(&in[2*3], v2);
  239. int nvrow, nvIn = 3;
  240. for (int y = y0; y <= y1; ++y)
  241. {
  242. // Clip polygon to row. Store the remaining polygon as well
  243. const float cz = bmin[2] + y*cs;
  244. dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2);
  245. rcSwap(in, p1);
  246. if (nvrow < 3) continue;
  247. // find the horizontal bounds in the row
  248. float minX = inrow[0], maxX = inrow[0];
  249. for (int i=1; i<nvrow; ++i)
  250. {
  251. if (minX > inrow[i*3]) minX = inrow[i*3];
  252. if (maxX < inrow[i*3]) maxX = inrow[i*3];
  253. }
  254. int x0 = (int)((minX - bmin[0])*ics);
  255. int x1 = (int)((maxX - bmin[0])*ics);
  256. x0 = rcClamp(x0, 0, w-1);
  257. x1 = rcClamp(x1, 0, w-1);
  258. int nv, nv2 = nvrow;
  259. for (int x = x0; x <= x1; ++x)
  260. {
  261. // Clip polygon to column. store the remaining polygon as well
  262. const float cx = bmin[0] + x*cs;
  263. dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
  264. rcSwap(inrow, p2);
  265. if (nv < 3) continue;
  266. // Calculate min and max of the span.
  267. float smin = p1[1], smax = p1[1];
  268. for (int i = 1; i < nv; ++i)
  269. {
  270. smin = rcMin(smin, p1[i*3+1]);
  271. smax = rcMax(smax, p1[i*3+1]);
  272. }
  273. smin -= bmin[1];
  274. smax -= bmin[1];
  275. // Skip the span if it is outside the heightfield bbox
  276. if (smax < 0.0f) continue;
  277. if (smin > by) continue;
  278. // Clamp the span to the heightfield bbox.
  279. if (smin < 0.0f) smin = 0;
  280. if (smax > by) smax = by;
  281. // Snap the span to the heightfield height grid.
  282. unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
  283. unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);
  284. addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
  285. }
  286. }
  287. }
  288. /// @par
  289. ///
  290. /// No spans will be added if the triangle does not overlap the heightfield grid.
  291. ///
  292. /// @see rcHeightfield
  293. void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
  294. const unsigned char area, rcHeightfield& solid,
  295. const int flagMergeThr)
  296. {
  297. rcAssert(ctx);
  298. ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  299. const float ics = 1.0f/solid.cs;
  300. const float ich = 1.0f/solid.ch;
  301. rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
  302. ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  303. }
  304. /// @par
  305. ///
  306. /// Spans will only be added for triangles that overlap the heightfield grid.
  307. ///
  308. /// @see rcHeightfield
  309. void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
  310. const int* tris, const unsigned char* areas, const int nt,
  311. rcHeightfield& solid, const int flagMergeThr)
  312. {
  313. rcAssert(ctx);
  314. ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  315. const float ics = 1.0f/solid.cs;
  316. const float ich = 1.0f/solid.ch;
  317. // Rasterize triangles.
  318. for (int i = 0; i < nt; ++i)
  319. {
  320. const float* v0 = &verts[tris[i*3+0]*3];
  321. const float* v1 = &verts[tris[i*3+1]*3];
  322. const float* v2 = &verts[tris[i*3+2]*3];
  323. // Rasterize.
  324. rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
  325. }
  326. ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  327. }
  328. /// @par
  329. ///
  330. /// Spans will only be added for triangles that overlap the heightfield grid.
  331. ///
  332. /// @see rcHeightfield
  333. void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
  334. const unsigned short* tris, const unsigned char* areas, const int nt,
  335. rcHeightfield& solid, const int flagMergeThr)
  336. {
  337. rcAssert(ctx);
  338. ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  339. const float ics = 1.0f/solid.cs;
  340. const float ich = 1.0f/solid.ch;
  341. // Rasterize triangles.
  342. for (int i = 0; i < nt; ++i)
  343. {
  344. const float* v0 = &verts[tris[i*3+0]*3];
  345. const float* v1 = &verts[tris[i*3+1]*3];
  346. const float* v2 = &verts[tris[i*3+2]*3];
  347. // Rasterize.
  348. rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
  349. }
  350. ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  351. }
  352. /// @par
  353. ///
  354. /// Spans will only be added for triangles that overlap the heightfield grid.
  355. ///
  356. /// @see rcHeightfield
  357. void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
  358. rcHeightfield& solid, const int flagMergeThr)
  359. {
  360. rcAssert(ctx);
  361. ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  362. const float ics = 1.0f/solid.cs;
  363. const float ich = 1.0f/solid.ch;
  364. // Rasterize triangles.
  365. for (int i = 0; i < nt; ++i)
  366. {
  367. const float* v0 = &verts[(i*3+0)*3];
  368. const float* v1 = &verts[(i*3+1)*3];
  369. const float* v2 = &verts[(i*3+2)*3];
  370. // Rasterize.
  371. rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
  372. }
  373. ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  374. }