RecastRasterization.cpp 11 KB

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