RecastRasterization.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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 he 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. static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd)
  156. {
  157. float d[12];
  158. for (int i = 0; i < n; ++i)
  159. d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd;
  160. int m = 0;
  161. for (int i = 0, j = n-1; i < n; j=i, ++i)
  162. {
  163. bool ina = d[j] >= 0;
  164. bool inb = d[i] >= 0;
  165. if (ina != inb)
  166. {
  167. float s = d[j] / (d[j] - d[i]);
  168. out[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
  169. out[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
  170. out[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
  171. m++;
  172. }
  173. if (inb)
  174. {
  175. out[m*3+0] = in[i*3+0];
  176. out[m*3+1] = in[i*3+1];
  177. out[m*3+2] = in[i*3+2];
  178. m++;
  179. }
  180. }
  181. return m;
  182. }
  183. static void rasterizeTri(const float* v0, const float* v1, const float* v2,
  184. const unsigned char area, rcHeightfield& hf,
  185. const float* bmin, const float* bmax,
  186. const float cs, const float ics, const float ich,
  187. const int flagMergeThr)
  188. {
  189. const int w = hf.width;
  190. const int h = hf.height;
  191. float tmin[3], tmax[3];
  192. const float by = bmax[1] - bmin[1];
  193. // Calculate the bounding box of the triangle.
  194. rcVcopy(tmin, v0);
  195. rcVcopy(tmax, v0);
  196. rcVmin(tmin, v1);
  197. rcVmin(tmin, v2);
  198. rcVmax(tmax, v1);
  199. rcVmax(tmax, v2);
  200. // If the triangle does not touch the bbox of the heightfield, skip the triagle.
  201. if (!overlapBounds(bmin, bmax, tmin, tmax))
  202. return;
  203. // Calculate the footpring of the triangle on the grid.
  204. int x0 = (int)((tmin[0] - bmin[0])*ics);
  205. int y0 = (int)((tmin[2] - bmin[2])*ics);
  206. int x1 = (int)((tmax[0] - bmin[0])*ics);
  207. int y1 = (int)((tmax[2] - bmin[2])*ics);
  208. x0 = rcClamp(x0, 0, w-1);
  209. y0 = rcClamp(y0, 0, h-1);
  210. x1 = rcClamp(x1, 0, w-1);
  211. y1 = rcClamp(y1, 0, h-1);
  212. // Clip the triangle into all grid cells it touches.
  213. float in[7*3], out[7*3], inrow[7*3];
  214. for (int y = y0; y <= y1; ++y)
  215. {
  216. // Clip polygon to row.
  217. rcVcopy(&in[0], v0);
  218. rcVcopy(&in[1*3], v1);
  219. rcVcopy(&in[2*3], v2);
  220. int nvrow = 3;
  221. const float cz = bmin[2] + y*cs;
  222. nvrow = clipPoly(in, nvrow, out, 0, 1, -cz);
  223. if (nvrow < 3) continue;
  224. nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs);
  225. if (nvrow < 3) continue;
  226. for (int x = x0; x <= x1; ++x)
  227. {
  228. // Clip polygon to column.
  229. int nv = nvrow;
  230. const float cx = bmin[0] + x*cs;
  231. nv = clipPoly(inrow, nv, out, 1, 0, -cx);
  232. if (nv < 3) continue;
  233. nv = clipPoly(out, nv, in, -1, 0, cx+cs);
  234. if (nv < 3) continue;
  235. // Calculate min and max of the span.
  236. float smin = in[1], smax = in[1];
  237. for (int i = 1; i < nv; ++i)
  238. {
  239. smin = rcMin(smin, in[i*3+1]);
  240. smax = rcMax(smax, in[i*3+1]);
  241. }
  242. smin -= bmin[1];
  243. smax -= bmin[1];
  244. // Skip the span if it is outside the heightfield bbox
  245. if (smax < 0.0f) continue;
  246. if (smin > by) continue;
  247. // Clamp the span to the heightfield bbox.
  248. if (smin < 0.0f) smin = 0;
  249. if (smax > by) smax = by;
  250. // Snap the span to the heightfield height grid.
  251. unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
  252. unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);
  253. addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
  254. }
  255. }
  256. }
  257. /// @par
  258. ///
  259. /// No spans will be added if the triangle does not overlap the heightfield grid.
  260. ///
  261. /// @see rcHeightfield
  262. void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2,
  263. const unsigned char area, rcHeightfield& solid,
  264. const int flagMergeThr)
  265. {
  266. rcAssert(ctx);
  267. ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  268. const float ics = 1.0f/solid.cs;
  269. const float ich = 1.0f/solid.ch;
  270. rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
  271. ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  272. }
  273. /// @par
  274. ///
  275. /// Spans will only be added for triangles that overlap the heightfield grid.
  276. ///
  277. /// @see rcHeightfield
  278. void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
  279. const int* tris, const unsigned char* areas, const int nt,
  280. rcHeightfield& solid, const int flagMergeThr)
  281. {
  282. rcAssert(ctx);
  283. ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  284. const float ics = 1.0f/solid.cs;
  285. const float ich = 1.0f/solid.ch;
  286. // Rasterize triangles.
  287. for (int i = 0; i < nt; ++i)
  288. {
  289. const float* v0 = &verts[tris[i*3+0]*3];
  290. const float* v1 = &verts[tris[i*3+1]*3];
  291. const float* v2 = &verts[tris[i*3+2]*3];
  292. // Rasterize.
  293. rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
  294. }
  295. ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  296. }
  297. /// @par
  298. ///
  299. /// Spans will only be added for triangles that overlap the heightfield grid.
  300. ///
  301. /// @see rcHeightfield
  302. void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/,
  303. const unsigned short* tris, const unsigned char* areas, const int nt,
  304. rcHeightfield& solid, const int flagMergeThr)
  305. {
  306. rcAssert(ctx);
  307. ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  308. const float ics = 1.0f/solid.cs;
  309. const float ich = 1.0f/solid.ch;
  310. // Rasterize triangles.
  311. for (int i = 0; i < nt; ++i)
  312. {
  313. const float* v0 = &verts[tris[i*3+0]*3];
  314. const float* v1 = &verts[tris[i*3+1]*3];
  315. const float* v2 = &verts[tris[i*3+2]*3];
  316. // Rasterize.
  317. rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
  318. }
  319. ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  320. }
  321. /// @par
  322. ///
  323. /// Spans will only be added for triangles that overlap the heightfield grid.
  324. ///
  325. /// @see rcHeightfield
  326. void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt,
  327. rcHeightfield& solid, const int flagMergeThr)
  328. {
  329. rcAssert(ctx);
  330. ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  331. const float ics = 1.0f/solid.cs;
  332. const float ich = 1.0f/solid.ch;
  333. // Rasterize triangles.
  334. for (int i = 0; i < nt; ++i)
  335. {
  336. const float* v0 = &verts[(i*3+0)*3];
  337. const float* v1 = &verts[(i*3+1)*3];
  338. const float* v2 = &verts[(i*3+2)*3];
  339. // Rasterize.
  340. rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
  341. }
  342. ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES);
  343. }