RecastMeshDetail.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319
  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 <float.h>
  19. #define _USE_MATH_DEFINES
  20. #include <math.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include "Recast.h"
  25. #include "RecastAlloc.h"
  26. #include "RecastAssert.h"
  27. static const unsigned RC_UNSET_HEIGHT = 0xffff;
  28. struct rcHeightPatch
  29. {
  30. inline rcHeightPatch() : data(0), xmin(0), ymin(0), width(0), height(0) {}
  31. inline ~rcHeightPatch() { rcFree(data); }
  32. unsigned short* data;
  33. int xmin, ymin, width, height;
  34. };
  35. inline float vdot2(const float* a, const float* b)
  36. {
  37. return a[0]*b[0] + a[2]*b[2];
  38. }
  39. inline float vdistSq2(const float* p, const float* q)
  40. {
  41. const float dx = q[0] - p[0];
  42. const float dy = q[2] - p[2];
  43. return dx*dx + dy*dy;
  44. }
  45. inline float vdist2(const float* p, const float* q)
  46. {
  47. return sqrtf(vdistSq2(p,q));
  48. }
  49. inline float vcross2(const float* p1, const float* p2, const float* p3)
  50. {
  51. const float u1 = p2[0] - p1[0];
  52. const float v1 = p2[2] - p1[2];
  53. const float u2 = p3[0] - p1[0];
  54. const float v2 = p3[2] - p1[2];
  55. return u1 * v2 - v1 * u2;
  56. }
  57. static bool circumCircle(const float* p1, const float* p2, const float* p3,
  58. float* c, float& r)
  59. {
  60. static const float EPS = 1e-6f;
  61. const float cp = vcross2(p1, p2, p3);
  62. if (fabsf(cp) > EPS)
  63. {
  64. const float p1Sq = vdot2(p1,p1);
  65. const float p2Sq = vdot2(p2,p2);
  66. const float p3Sq = vdot2(p3,p3);
  67. c[0] = (p1Sq*(p2[2]-p3[2]) + p2Sq*(p3[2]-p1[2]) + p3Sq*(p1[2]-p2[2])) / (2*cp);
  68. c[2] = (p1Sq*(p3[0]-p2[0]) + p2Sq*(p1[0]-p3[0]) + p3Sq*(p2[0]-p1[0])) / (2*cp);
  69. r = vdist2(c, p1);
  70. return true;
  71. }
  72. c[0] = p1[0];
  73. c[2] = p1[2];
  74. r = 0;
  75. return false;
  76. }
  77. static float distPtTri(const float* p, const float* a, const float* b, const float* c)
  78. {
  79. float v0[3], v1[3], v2[3];
  80. rcVsub(v0, c,a);
  81. rcVsub(v1, b,a);
  82. rcVsub(v2, p,a);
  83. const float dot00 = vdot2(v0, v0);
  84. const float dot01 = vdot2(v0, v1);
  85. const float dot02 = vdot2(v0, v2);
  86. const float dot11 = vdot2(v1, v1);
  87. const float dot12 = vdot2(v1, v2);
  88. // Compute barycentric coordinates
  89. const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
  90. const float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  91. float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
  92. // If point lies inside the triangle, return interpolated y-coord.
  93. static const float EPS = 1e-4f;
  94. if (u >= -EPS && v >= -EPS && (u+v) <= 1+EPS)
  95. {
  96. const float y = a[1] + v0[1]*u + v1[1]*v;
  97. return fabsf(y-p[1]);
  98. }
  99. return FLT_MAX;
  100. }
  101. static float distancePtSeg(const float* pt, const float* p, const float* q)
  102. {
  103. float pqx = q[0] - p[0];
  104. float pqy = q[1] - p[1];
  105. float pqz = q[2] - p[2];
  106. float dx = pt[0] - p[0];
  107. float dy = pt[1] - p[1];
  108. float dz = pt[2] - p[2];
  109. float d = pqx*pqx + pqy*pqy + pqz*pqz;
  110. float t = pqx*dx + pqy*dy + pqz*dz;
  111. if (d > 0)
  112. t /= d;
  113. if (t < 0)
  114. t = 0;
  115. else if (t > 1)
  116. t = 1;
  117. dx = p[0] + t*pqx - pt[0];
  118. dy = p[1] + t*pqy - pt[1];
  119. dz = p[2] + t*pqz - pt[2];
  120. return dx*dx + dy*dy + dz*dz;
  121. }
  122. static float distancePtSeg2d(const float* pt, const float* p, const float* q)
  123. {
  124. float pqx = q[0] - p[0];
  125. float pqz = q[2] - p[2];
  126. float dx = pt[0] - p[0];
  127. float dz = pt[2] - p[2];
  128. float d = pqx*pqx + pqz*pqz;
  129. float t = pqx*dx + pqz*dz;
  130. if (d > 0)
  131. t /= d;
  132. if (t < 0)
  133. t = 0;
  134. else if (t > 1)
  135. t = 1;
  136. dx = p[0] + t*pqx - pt[0];
  137. dz = p[2] + t*pqz - pt[2];
  138. return dx*dx + dz*dz;
  139. }
  140. static float distToTriMesh(const float* p, const float* verts, const int /*nverts*/, const int* tris, const int ntris)
  141. {
  142. float dmin = FLT_MAX;
  143. for (int i = 0; i < ntris; ++i)
  144. {
  145. const float* va = &verts[tris[i*4+0]*3];
  146. const float* vb = &verts[tris[i*4+1]*3];
  147. const float* vc = &verts[tris[i*4+2]*3];
  148. float d = distPtTri(p, va,vb,vc);
  149. if (d < dmin)
  150. dmin = d;
  151. }
  152. if (dmin == FLT_MAX) return -1;
  153. return dmin;
  154. }
  155. static float distToPoly(int nvert, const float* verts, const float* p)
  156. {
  157. float dmin = FLT_MAX;
  158. int i, j, c = 0;
  159. for (i = 0, j = nvert-1; i < nvert; j = i++)
  160. {
  161. const float* vi = &verts[i*3];
  162. const float* vj = &verts[j*3];
  163. if (((vi[2] > p[2]) != (vj[2] > p[2])) &&
  164. (p[0] < (vj[0]-vi[0]) * (p[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) )
  165. c = !c;
  166. dmin = rcMin(dmin, distancePtSeg2d(p, vj, vi));
  167. }
  168. return c ? -dmin : dmin;
  169. }
  170. static unsigned short getHeight(const float fx, const float fy, const float fz,
  171. const float /*cs*/, const float ics, const float ch,
  172. const rcHeightPatch& hp)
  173. {
  174. int ix = (int)floorf(fx*ics + 0.01f);
  175. int iz = (int)floorf(fz*ics + 0.01f);
  176. ix = rcClamp(ix-hp.xmin, 0, hp.width - 1);
  177. iz = rcClamp(iz-hp.ymin, 0, hp.height - 1);
  178. unsigned short h = hp.data[ix+iz*hp.width];
  179. if (h == RC_UNSET_HEIGHT)
  180. {
  181. // Special case when data might be bad.
  182. // Find nearest neighbour pixel which has valid height.
  183. const int off[8*2] = { -1,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1};
  184. float dmin = FLT_MAX;
  185. for (int i = 0; i < 8; ++i)
  186. {
  187. const int nx = ix+off[i*2+0];
  188. const int nz = iz+off[i*2+1];
  189. if (nx < 0 || nz < 0 || nx >= hp.width || nz >= hp.height) continue;
  190. const unsigned short nh = hp.data[nx+nz*hp.width];
  191. if (nh == RC_UNSET_HEIGHT) continue;
  192. const float d = fabsf(nh*ch - fy);
  193. if (d < dmin)
  194. {
  195. h = nh;
  196. dmin = d;
  197. }
  198. /* const float dx = (nx+0.5f)*cs - fx;
  199. const float dz = (nz+0.5f)*cs - fz;
  200. const float d = dx*dx+dz*dz;
  201. if (d < dmin)
  202. {
  203. h = nh;
  204. dmin = d;
  205. } */
  206. }
  207. }
  208. return h;
  209. }
  210. enum EdgeValues
  211. {
  212. UNDEF = -1,
  213. HULL = -2,
  214. };
  215. static int findEdge(const int* edges, int nedges, int s, int t)
  216. {
  217. for (int i = 0; i < nedges; i++)
  218. {
  219. const int* e = &edges[i*4];
  220. if ((e[0] == s && e[1] == t) || (e[0] == t && e[1] == s))
  221. return i;
  222. }
  223. return UNDEF;
  224. }
  225. static int addEdge(rcContext* ctx, int* edges, int& nedges, const int maxEdges, int s, int t, int l, int r)
  226. {
  227. if (nedges >= maxEdges)
  228. {
  229. ctx->log(RC_LOG_ERROR, "addEdge: Too many edges (%d/%d).", nedges, maxEdges);
  230. return UNDEF;
  231. }
  232. // Add edge if not already in the triangulation.
  233. int e = findEdge(edges, nedges, s, t);
  234. if (e == UNDEF)
  235. {
  236. int* edge = &edges[nedges*4];
  237. edge[0] = s;
  238. edge[1] = t;
  239. edge[2] = l;
  240. edge[3] = r;
  241. return nedges++;
  242. }
  243. else
  244. {
  245. return UNDEF;
  246. }
  247. }
  248. static void updateLeftFace(int* e, int s, int t, int f)
  249. {
  250. if (e[0] == s && e[1] == t && e[2] == UNDEF)
  251. e[2] = f;
  252. else if (e[1] == s && e[0] == t && e[3] == UNDEF)
  253. e[3] = f;
  254. }
  255. static int overlapSegSeg2d(const float* a, const float* b, const float* c, const float* d)
  256. {
  257. const float a1 = vcross2(a, b, d);
  258. const float a2 = vcross2(a, b, c);
  259. if (a1*a2 < 0.0f)
  260. {
  261. float a3 = vcross2(c, d, a);
  262. float a4 = a3 + a2 - a1;
  263. if (a3 * a4 < 0.0f)
  264. return 1;
  265. }
  266. return 0;
  267. }
  268. static bool overlapEdges(const float* pts, const int* edges, int nedges, int s1, int t1)
  269. {
  270. for (int i = 0; i < nedges; ++i)
  271. {
  272. const int s0 = edges[i*4+0];
  273. const int t0 = edges[i*4+1];
  274. // Same or connected edges do not overlap.
  275. if (s0 == s1 || s0 == t1 || t0 == s1 || t0 == t1)
  276. continue;
  277. if (overlapSegSeg2d(&pts[s0*3],&pts[t0*3], &pts[s1*3],&pts[t1*3]))
  278. return true;
  279. }
  280. return false;
  281. }
  282. static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges, int& nedges, const int maxEdges, int& nfaces, int e)
  283. {
  284. static const float EPS = 1e-5f;
  285. int* edge = &edges[e*4];
  286. // Cache s and t.
  287. int s,t;
  288. if (edge[2] == UNDEF)
  289. {
  290. s = edge[0];
  291. t = edge[1];
  292. }
  293. else if (edge[3] == UNDEF)
  294. {
  295. s = edge[1];
  296. t = edge[0];
  297. }
  298. else
  299. {
  300. // Edge already completed.
  301. return;
  302. }
  303. // Find best point on left of edge.
  304. int pt = npts;
  305. float c[3] = {0,0,0};
  306. float r = -1;
  307. for (int u = 0; u < npts; ++u)
  308. {
  309. if (u == s || u == t) continue;
  310. if (vcross2(&pts[s*3], &pts[t*3], &pts[u*3]) > EPS)
  311. {
  312. if (r < 0)
  313. {
  314. // The circle is not updated yet, do it now.
  315. pt = u;
  316. circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r);
  317. continue;
  318. }
  319. const float d = vdist2(c, &pts[u*3]);
  320. const float tol = 0.001f;
  321. if (d > r*(1+tol))
  322. {
  323. // Outside current circumcircle, skip.
  324. continue;
  325. }
  326. else if (d < r*(1-tol))
  327. {
  328. // Inside safe circumcircle, update circle.
  329. pt = u;
  330. circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r);
  331. }
  332. else
  333. {
  334. // Inside epsilon circum circle, do extra tests to make sure the edge is valid.
  335. // s-u and t-u cannot overlap with s-pt nor t-pt if they exists.
  336. if (overlapEdges(pts, edges, nedges, s,u))
  337. continue;
  338. if (overlapEdges(pts, edges, nedges, t,u))
  339. continue;
  340. // Edge is valid.
  341. pt = u;
  342. circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r);
  343. }
  344. }
  345. }
  346. // Add new triangle or update edge info if s-t is on hull.
  347. if (pt < npts)
  348. {
  349. // Update face information of edge being completed.
  350. updateLeftFace(&edges[e*4], s, t, nfaces);
  351. // Add new edge or update face info of old edge.
  352. e = findEdge(edges, nedges, pt, s);
  353. if (e == UNDEF)
  354. addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, UNDEF);
  355. else
  356. updateLeftFace(&edges[e*4], pt, s, nfaces);
  357. // Add new edge or update face info of old edge.
  358. e = findEdge(edges, nedges, t, pt);
  359. if (e == UNDEF)
  360. addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, UNDEF);
  361. else
  362. updateLeftFace(&edges[e*4], t, pt, nfaces);
  363. nfaces++;
  364. }
  365. else
  366. {
  367. updateLeftFace(&edges[e*4], s, t, HULL);
  368. }
  369. }
  370. static void delaunayHull(rcContext* ctx, const int npts, const float* pts,
  371. const int nhull, const int* hull,
  372. rcIntArray& tris, rcIntArray& edges)
  373. {
  374. int nfaces = 0;
  375. int nedges = 0;
  376. const int maxEdges = npts*10;
  377. edges.resize(maxEdges*4);
  378. for (int i = 0, j = nhull-1; i < nhull; j=i++)
  379. addEdge(ctx, &edges[0], nedges, maxEdges, hull[j],hull[i], HULL, UNDEF);
  380. int currentEdge = 0;
  381. while (currentEdge < nedges)
  382. {
  383. if (edges[currentEdge*4+2] == UNDEF)
  384. completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
  385. if (edges[currentEdge*4+3] == UNDEF)
  386. completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge);
  387. currentEdge++;
  388. }
  389. // Create tris
  390. tris.resize(nfaces*4);
  391. for (int i = 0; i < nfaces*4; ++i)
  392. tris[i] = -1;
  393. for (int i = 0; i < nedges; ++i)
  394. {
  395. const int* e = &edges[i*4];
  396. if (e[3] >= 0)
  397. {
  398. // Left face
  399. int* t = &tris[e[3]*4];
  400. if (t[0] == -1)
  401. {
  402. t[0] = e[0];
  403. t[1] = e[1];
  404. }
  405. else if (t[0] == e[1])
  406. t[2] = e[0];
  407. else if (t[1] == e[0])
  408. t[2] = e[1];
  409. }
  410. if (e[2] >= 0)
  411. {
  412. // Right
  413. int* t = &tris[e[2]*4];
  414. if (t[0] == -1)
  415. {
  416. t[0] = e[1];
  417. t[1] = e[0];
  418. }
  419. else if (t[0] == e[0])
  420. t[2] = e[1];
  421. else if (t[1] == e[1])
  422. t[2] = e[0];
  423. }
  424. }
  425. for (int i = 0; i < tris.size()/4; ++i)
  426. {
  427. int* t = &tris[i*4];
  428. if (t[0] == -1 || t[1] == -1 || t[2] == -1)
  429. {
  430. ctx->log(RC_LOG_WARNING, "delaunayHull: Removing dangling face %d [%d,%d,%d].", i, t[0],t[1],t[2]);
  431. t[0] = tris[tris.size()-4];
  432. t[1] = tris[tris.size()-3];
  433. t[2] = tris[tris.size()-2];
  434. t[3] = tris[tris.size()-1];
  435. tris.resize(tris.size()-4);
  436. --i;
  437. }
  438. }
  439. }
  440. inline float getJitterX(const int i)
  441. {
  442. return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
  443. }
  444. inline float getJitterY(const int i)
  445. {
  446. return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f;
  447. }
  448. static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
  449. const float sampleDist, const float sampleMaxError,
  450. const rcCompactHeightfield& chf, const rcHeightPatch& hp,
  451. float* verts, int& nverts, rcIntArray& tris,
  452. rcIntArray& edges, rcIntArray& samples)
  453. {
  454. static const int MAX_VERTS = 127;
  455. static const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts).
  456. static const int MAX_VERTS_PER_EDGE = 32;
  457. float edge[(MAX_VERTS_PER_EDGE+1)*3];
  458. int hull[MAX_VERTS];
  459. int nhull = 0;
  460. nverts = 0;
  461. for (int i = 0; i < nin; ++i)
  462. rcVcopy(&verts[i*3], &in[i*3]);
  463. nverts = nin;
  464. const float cs = chf.cs;
  465. const float ics = 1.0f/cs;
  466. // Tessellate outlines.
  467. // This is done in separate pass in order to ensure
  468. // seamless height values across the ply boundaries.
  469. if (sampleDist > 0)
  470. {
  471. for (int i = 0, j = nin-1; i < nin; j=i++)
  472. {
  473. const float* vj = &in[j*3];
  474. const float* vi = &in[i*3];
  475. bool swapped = false;
  476. // Make sure the segments are always handled in same order
  477. // using lexological sort or else there will be seams.
  478. if (fabsf(vj[0]-vi[0]) < 1e-6f)
  479. {
  480. if (vj[2] > vi[2])
  481. {
  482. rcSwap(vj,vi);
  483. swapped = true;
  484. }
  485. }
  486. else
  487. {
  488. if (vj[0] > vi[0])
  489. {
  490. rcSwap(vj,vi);
  491. swapped = true;
  492. }
  493. }
  494. // Create samples along the edge.
  495. float dx = vi[0] - vj[0];
  496. float dy = vi[1] - vj[1];
  497. float dz = vi[2] - vj[2];
  498. float d = sqrtf(dx*dx + dz*dz);
  499. int nn = 1 + (int)floorf(d/sampleDist);
  500. if (nn >= MAX_VERTS_PER_EDGE) nn = MAX_VERTS_PER_EDGE-1;
  501. if (nverts+nn >= MAX_VERTS)
  502. nn = MAX_VERTS-1-nverts;
  503. for (int k = 0; k <= nn; ++k)
  504. {
  505. float u = (float)k/(float)nn;
  506. float* pos = &edge[k*3];
  507. pos[0] = vj[0] + dx*u;
  508. pos[1] = vj[1] + dy*u;
  509. pos[2] = vj[2] + dz*u;
  510. pos[1] = getHeight(pos[0],pos[1],pos[2], cs, ics, chf.ch, hp)*chf.ch;
  511. }
  512. // Simplify samples.
  513. int idx[MAX_VERTS_PER_EDGE] = {0,nn};
  514. int nidx = 2;
  515. for (int k = 0; k < nidx-1; )
  516. {
  517. const int a = idx[k];
  518. const int b = idx[k+1];
  519. const float* va = &edge[a*3];
  520. const float* vb = &edge[b*3];
  521. // Find maximum deviation along the segment.
  522. float maxd = 0;
  523. int maxi = -1;
  524. for (int m = a+1; m < b; ++m)
  525. {
  526. float dev = distancePtSeg(&edge[m*3],va,vb);
  527. if (dev > maxd)
  528. {
  529. maxd = dev;
  530. maxi = m;
  531. }
  532. }
  533. // If the max deviation is larger than accepted error,
  534. // add new point, else continue to next segment.
  535. if (maxi != -1 && maxd > rcSqr(sampleMaxError))
  536. {
  537. for (int m = nidx; m > k; --m)
  538. idx[m] = idx[m-1];
  539. idx[k+1] = maxi;
  540. nidx++;
  541. }
  542. else
  543. {
  544. ++k;
  545. }
  546. }
  547. hull[nhull++] = j;
  548. // Add new vertices.
  549. if (swapped)
  550. {
  551. for (int k = nidx-2; k > 0; --k)
  552. {
  553. rcVcopy(&verts[nverts*3], &edge[idx[k]*3]);
  554. hull[nhull++] = nverts;
  555. nverts++;
  556. }
  557. }
  558. else
  559. {
  560. for (int k = 1; k < nidx-1; ++k)
  561. {
  562. rcVcopy(&verts[nverts*3], &edge[idx[k]*3]);
  563. hull[nhull++] = nverts;
  564. nverts++;
  565. }
  566. }
  567. }
  568. }
  569. // Tessellate the base mesh.
  570. edges.resize(0);
  571. tris.resize(0);
  572. delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
  573. if (tris.size() == 0)
  574. {
  575. // Could not triangulate the poly, make sure there is some valid data there.
  576. ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon, adding default data.");
  577. for (int i = 2; i < nverts; ++i)
  578. {
  579. tris.push(0);
  580. tris.push(i-1);
  581. tris.push(i);
  582. tris.push(0);
  583. }
  584. return true;
  585. }
  586. if (sampleDist > 0)
  587. {
  588. // Create sample locations in a grid.
  589. float bmin[3], bmax[3];
  590. rcVcopy(bmin, in);
  591. rcVcopy(bmax, in);
  592. for (int i = 1; i < nin; ++i)
  593. {
  594. rcVmin(bmin, &in[i*3]);
  595. rcVmax(bmax, &in[i*3]);
  596. }
  597. int x0 = (int)floorf(bmin[0]/sampleDist);
  598. int x1 = (int)ceilf(bmax[0]/sampleDist);
  599. int z0 = (int)floorf(bmin[2]/sampleDist);
  600. int z1 = (int)ceilf(bmax[2]/sampleDist);
  601. samples.resize(0);
  602. for (int z = z0; z < z1; ++z)
  603. {
  604. for (int x = x0; x < x1; ++x)
  605. {
  606. float pt[3];
  607. pt[0] = x*sampleDist;
  608. pt[1] = (bmax[1]+bmin[1])*0.5f;
  609. pt[2] = z*sampleDist;
  610. // Make sure the samples are not too close to the edges.
  611. if (distToPoly(nin,in,pt) > -sampleDist/2) continue;
  612. samples.push(x);
  613. samples.push(getHeight(pt[0], pt[1], pt[2], cs, ics, chf.ch, hp));
  614. samples.push(z);
  615. samples.push(0); // Not added
  616. }
  617. }
  618. // Add the samples starting from the one that has the most
  619. // error. The procedure stops when all samples are added
  620. // or when the max error is within treshold.
  621. const int nsamples = samples.size()/4;
  622. for (int iter = 0; iter < nsamples; ++iter)
  623. {
  624. if (nverts >= MAX_VERTS)
  625. break;
  626. // Find sample with most error.
  627. float bestpt[3] = {0,0,0};
  628. float bestd = 0;
  629. int besti = -1;
  630. for (int i = 0; i < nsamples; ++i)
  631. {
  632. const int* s = &samples[i*4];
  633. if (s[3]) continue; // skip added.
  634. float pt[3];
  635. // The sample location is jittered to get rid of some bad triangulations
  636. // which are cause by symmetrical data from the grid structure.
  637. pt[0] = s[0]*sampleDist + getJitterX(i)*cs*0.1f;
  638. pt[1] = s[1]*chf.ch;
  639. pt[2] = s[2]*sampleDist + getJitterY(i)*cs*0.1f;
  640. float d = distToTriMesh(pt, verts, nverts, &tris[0], tris.size()/4);
  641. if (d < 0) continue; // did not hit the mesh.
  642. if (d > bestd)
  643. {
  644. bestd = d;
  645. besti = i;
  646. rcVcopy(bestpt,pt);
  647. }
  648. }
  649. // If the max error is within accepted threshold, stop tesselating.
  650. if (bestd <= sampleMaxError || besti == -1)
  651. break;
  652. // Mark sample as added.
  653. samples[besti*4+3] = 1;
  654. // Add the new sample point.
  655. rcVcopy(&verts[nverts*3],bestpt);
  656. nverts++;
  657. // Create new triangulation.
  658. // TODO: Incremental add instead of full rebuild.
  659. edges.resize(0);
  660. tris.resize(0);
  661. delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges);
  662. }
  663. }
  664. const int ntris = tris.size()/4;
  665. if (ntris > MAX_TRIS)
  666. {
  667. tris.resize(MAX_TRIS*4);
  668. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Shrinking triangle count from %d to max %d.", ntris, MAX_TRIS);
  669. }
  670. return true;
  671. }
  672. static void getHeightDataSeedsFromVertices(const rcCompactHeightfield& chf,
  673. const unsigned short* poly, const int npoly,
  674. const unsigned short* verts, const int bs,
  675. rcHeightPatch& hp, rcIntArray& stack)
  676. {
  677. // Floodfill the heightfield to get 2D height data,
  678. // starting at vertex locations as seeds.
  679. // Note: Reads to the compact heightfield are offset by border size (bs)
  680. // since border size offset is already removed from the polymesh vertices.
  681. memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
  682. stack.resize(0);
  683. static const int offset[9*2] =
  684. {
  685. 0,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0,
  686. };
  687. // Use poly vertices as seed points for the flood fill.
  688. for (int j = 0; j < npoly; ++j)
  689. {
  690. int cx = 0, cz = 0, ci =-1;
  691. int dmin = RC_UNSET_HEIGHT;
  692. for (int k = 0; k < 9; ++k)
  693. {
  694. const int ax = (int)verts[poly[j]*3+0] + offset[k*2+0];
  695. const int ay = (int)verts[poly[j]*3+1];
  696. const int az = (int)verts[poly[j]*3+2] + offset[k*2+1];
  697. if (ax < hp.xmin || ax >= hp.xmin+hp.width ||
  698. az < hp.ymin || az >= hp.ymin+hp.height)
  699. continue;
  700. const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width];
  701. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  702. {
  703. const rcCompactSpan& s = chf.spans[i];
  704. int d = rcAbs(ay - (int)s.y);
  705. if (d < dmin)
  706. {
  707. cx = ax;
  708. cz = az;
  709. ci = i;
  710. dmin = d;
  711. }
  712. }
  713. }
  714. if (ci != -1)
  715. {
  716. stack.push(cx);
  717. stack.push(cz);
  718. stack.push(ci);
  719. }
  720. }
  721. // Find center of the polygon using flood fill.
  722. int pcx = 0, pcz = 0;
  723. for (int j = 0; j < npoly; ++j)
  724. {
  725. pcx += (int)verts[poly[j]*3+0];
  726. pcz += (int)verts[poly[j]*3+2];
  727. }
  728. pcx /= npoly;
  729. pcz /= npoly;
  730. for (int i = 0; i < stack.size(); i += 3)
  731. {
  732. int cx = stack[i+0];
  733. int cy = stack[i+1];
  734. int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
  735. hp.data[idx] = 1;
  736. }
  737. while (stack.size() > 0)
  738. {
  739. int ci = stack.pop();
  740. int cy = stack.pop();
  741. int cx = stack.pop();
  742. // Check if close to center of the polygon.
  743. if (rcAbs(cx-pcx) <= 1 && rcAbs(cy-pcz) <= 1)
  744. {
  745. stack.resize(0);
  746. stack.push(cx);
  747. stack.push(cy);
  748. stack.push(ci);
  749. break;
  750. }
  751. const rcCompactSpan& cs = chf.spans[ci];
  752. for (int dir = 0; dir < 4; ++dir)
  753. {
  754. if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue;
  755. const int ax = cx + rcGetDirOffsetX(dir);
  756. const int ay = cy + rcGetDirOffsetY(dir);
  757. if (ax < hp.xmin || ax >= (hp.xmin+hp.width) ||
  758. ay < hp.ymin || ay >= (hp.ymin+hp.height))
  759. continue;
  760. if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0)
  761. continue;
  762. const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
  763. int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
  764. hp.data[idx] = 1;
  765. stack.push(ax);
  766. stack.push(ay);
  767. stack.push(ai);
  768. }
  769. }
  770. memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
  771. // Mark start locations.
  772. for (int i = 0; i < stack.size(); i += 3)
  773. {
  774. int cx = stack[i+0];
  775. int cy = stack[i+1];
  776. int ci = stack[i+2];
  777. int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
  778. const rcCompactSpan& cs = chf.spans[ci];
  779. hp.data[idx] = cs.y;
  780. // getHeightData seeds are given in coordinates with borders
  781. stack[i+0] += bs;
  782. stack[i+1] += bs;
  783. }
  784. }
  785. static void getHeightData(const rcCompactHeightfield& chf,
  786. const unsigned short* poly, const int npoly,
  787. const unsigned short* verts, const int bs,
  788. rcHeightPatch& hp, rcIntArray& stack,
  789. int region)
  790. {
  791. // Note: Reads to the compact heightfield are offset by border size (bs)
  792. // since border size offset is already removed from the polymesh vertices.
  793. stack.resize(0);
  794. memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
  795. bool empty = true;
  796. // Copy the height from the same region, and mark region borders
  797. // as seed points to fill the rest.
  798. for (int hy = 0; hy < hp.height; hy++)
  799. {
  800. int y = hp.ymin + hy + bs;
  801. for (int hx = 0; hx < hp.width; hx++)
  802. {
  803. int x = hp.xmin + hx + bs;
  804. const rcCompactCell& c = chf.cells[x+y*chf.width];
  805. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  806. {
  807. const rcCompactSpan& s = chf.spans[i];
  808. if (s.reg == region)
  809. {
  810. // Store height
  811. hp.data[hx + hy*hp.width] = s.y;
  812. empty = false;
  813. // If any of the neighbours is not in same region,
  814. // add the current location as flood fill start
  815. bool border = false;
  816. for (int dir = 0; dir < 4; ++dir)
  817. {
  818. if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
  819. {
  820. const int ax = x + rcGetDirOffsetX(dir);
  821. const int ay = y + rcGetDirOffsetY(dir);
  822. const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
  823. const rcCompactSpan& as = chf.spans[ai];
  824. if (as.reg != region)
  825. {
  826. border = true;
  827. break;
  828. }
  829. }
  830. }
  831. if (border)
  832. {
  833. stack.push(x);
  834. stack.push(y);
  835. stack.push(i);
  836. }
  837. break;
  838. }
  839. }
  840. }
  841. }
  842. // if the polygon does not contian any points from the current region (rare, but happens)
  843. // then use the cells closest to the polygon vertices as seeds to fill the height field
  844. if (empty)
  845. getHeightDataSeedsFromVertices(chf, poly, npoly, verts, bs, hp, stack);
  846. static const int RETRACT_SIZE = 256;
  847. int head = 0;
  848. while (head*3 < stack.size())
  849. {
  850. int cx = stack[head*3+0];
  851. int cy = stack[head*3+1];
  852. int ci = stack[head*3+2];
  853. head++;
  854. if (head >= RETRACT_SIZE)
  855. {
  856. head = 0;
  857. if (stack.size() > RETRACT_SIZE*3)
  858. memmove(&stack[0], &stack[RETRACT_SIZE*3], sizeof(int)*(stack.size()-RETRACT_SIZE*3));
  859. stack.resize(stack.size()-RETRACT_SIZE*3);
  860. }
  861. const rcCompactSpan& cs = chf.spans[ci];
  862. for (int dir = 0; dir < 4; ++dir)
  863. {
  864. if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue;
  865. const int ax = cx + rcGetDirOffsetX(dir);
  866. const int ay = cy + rcGetDirOffsetY(dir);
  867. const int hx = ax - hp.xmin - bs;
  868. const int hy = ay - hp.ymin - bs;
  869. if (hx < 0 || hx >= hp.width || hy < 0 || hy >= hp.height)
  870. continue;
  871. if (hp.data[hx + hy*hp.width] != RC_UNSET_HEIGHT)
  872. continue;
  873. const int ai = (int)chf.cells[ax + ay*chf.width].index + rcGetCon(cs, dir);
  874. const rcCompactSpan& as = chf.spans[ai];
  875. hp.data[hx + hy*hp.width] = as.y;
  876. stack.push(ax);
  877. stack.push(ay);
  878. stack.push(ai);
  879. }
  880. }
  881. }
  882. static unsigned char getEdgeFlags(const float* va, const float* vb,
  883. const float* vpoly, const int npoly)
  884. {
  885. // Return true if edge (va,vb) is part of the polygon.
  886. static const float thrSqr = rcSqr(0.001f);
  887. for (int i = 0, j = npoly-1; i < npoly; j=i++)
  888. {
  889. if (distancePtSeg2d(va, &vpoly[j*3], &vpoly[i*3]) < thrSqr &&
  890. distancePtSeg2d(vb, &vpoly[j*3], &vpoly[i*3]) < thrSqr)
  891. return 1;
  892. }
  893. return 0;
  894. }
  895. static unsigned char getTriFlags(const float* va, const float* vb, const float* vc,
  896. const float* vpoly, const int npoly)
  897. {
  898. unsigned char flags = 0;
  899. flags |= getEdgeFlags(va,vb,vpoly,npoly) << 0;
  900. flags |= getEdgeFlags(vb,vc,vpoly,npoly) << 2;
  901. flags |= getEdgeFlags(vc,va,vpoly,npoly) << 4;
  902. return flags;
  903. }
  904. /// @par
  905. ///
  906. /// See the #rcConfig documentation for more information on the configuration parameters.
  907. ///
  908. /// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig
  909. bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf,
  910. const float sampleDist, const float sampleMaxError,
  911. rcPolyMeshDetail& dmesh)
  912. {
  913. rcAssert(ctx);
  914. ctx->startTimer(RC_TIMER_BUILD_POLYMESHDETAIL);
  915. if (mesh.nverts == 0 || mesh.npolys == 0)
  916. return true;
  917. const int nvp = mesh.nvp;
  918. const float cs = mesh.cs;
  919. const float ch = mesh.ch;
  920. const float* orig = mesh.bmin;
  921. const int borderSize = mesh.borderSize;
  922. rcIntArray edges(64);
  923. rcIntArray tris(512);
  924. rcIntArray stack(512);
  925. rcIntArray samples(512);
  926. float verts[256*3];
  927. rcHeightPatch hp;
  928. int nPolyVerts = 0;
  929. int maxhw = 0, maxhh = 0;
  930. rcScopedDelete<int> bounds = (int*)rcAlloc(sizeof(int)*mesh.npolys*4, RC_ALLOC_TEMP);
  931. if (!bounds)
  932. {
  933. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4);
  934. return false;
  935. }
  936. rcScopedDelete<float> poly = (float*)rcAlloc(sizeof(float)*nvp*3, RC_ALLOC_TEMP);
  937. if (!poly)
  938. {
  939. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3);
  940. return false;
  941. }
  942. // Find max size for a polygon area.
  943. for (int i = 0; i < mesh.npolys; ++i)
  944. {
  945. const unsigned short* p = &mesh.polys[i*nvp*2];
  946. int& xmin = bounds[i*4+0];
  947. int& xmax = bounds[i*4+1];
  948. int& ymin = bounds[i*4+2];
  949. int& ymax = bounds[i*4+3];
  950. xmin = chf.width;
  951. xmax = 0;
  952. ymin = chf.height;
  953. ymax = 0;
  954. for (int j = 0; j < nvp; ++j)
  955. {
  956. if(p[j] == RC_MESH_NULL_IDX) break;
  957. const unsigned short* v = &mesh.verts[p[j]*3];
  958. xmin = rcMin(xmin, (int)v[0]);
  959. xmax = rcMax(xmax, (int)v[0]);
  960. ymin = rcMin(ymin, (int)v[2]);
  961. ymax = rcMax(ymax, (int)v[2]);
  962. nPolyVerts++;
  963. }
  964. xmin = rcMax(0,xmin-1);
  965. xmax = rcMin(chf.width,xmax+1);
  966. ymin = rcMax(0,ymin-1);
  967. ymax = rcMin(chf.height,ymax+1);
  968. if (xmin >= xmax || ymin >= ymax) continue;
  969. maxhw = rcMax(maxhw, xmax-xmin);
  970. maxhh = rcMax(maxhh, ymax-ymin);
  971. }
  972. hp.data = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP);
  973. if (!hp.data)
  974. {
  975. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh);
  976. return false;
  977. }
  978. dmesh.nmeshes = mesh.npolys;
  979. dmesh.nverts = 0;
  980. dmesh.ntris = 0;
  981. dmesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*dmesh.nmeshes*4, RC_ALLOC_PERM);
  982. if (!dmesh.meshes)
  983. {
  984. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4);
  985. return false;
  986. }
  987. int vcap = nPolyVerts+nPolyVerts/2;
  988. int tcap = vcap*2;
  989. dmesh.nverts = 0;
  990. dmesh.verts = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
  991. if (!dmesh.verts)
  992. {
  993. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", vcap*3);
  994. return false;
  995. }
  996. dmesh.ntris = 0;
  997. dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char*)*tcap*4, RC_ALLOC_PERM);
  998. if (!dmesh.tris)
  999. {
  1000. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4);
  1001. return false;
  1002. }
  1003. for (int i = 0; i < mesh.npolys; ++i)
  1004. {
  1005. const unsigned short* p = &mesh.polys[i*nvp*2];
  1006. // Store polygon vertices for processing.
  1007. int npoly = 0;
  1008. for (int j = 0; j < nvp; ++j)
  1009. {
  1010. if(p[j] == RC_MESH_NULL_IDX) break;
  1011. const unsigned short* v = &mesh.verts[p[j]*3];
  1012. poly[j*3+0] = v[0]*cs;
  1013. poly[j*3+1] = v[1]*ch;
  1014. poly[j*3+2] = v[2]*cs;
  1015. npoly++;
  1016. }
  1017. // Get the height data from the area of the polygon.
  1018. hp.xmin = bounds[i*4+0];
  1019. hp.ymin = bounds[i*4+2];
  1020. hp.width = bounds[i*4+1]-bounds[i*4+0];
  1021. hp.height = bounds[i*4+3]-bounds[i*4+2];
  1022. getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack, mesh.regs[i]);
  1023. // Build detail mesh.
  1024. int nverts = 0;
  1025. if (!buildPolyDetail(ctx, poly, npoly,
  1026. sampleDist, sampleMaxError,
  1027. chf, hp, verts, nverts, tris,
  1028. edges, samples))
  1029. {
  1030. return false;
  1031. }
  1032. // Move detail verts to world space.
  1033. for (int j = 0; j < nverts; ++j)
  1034. {
  1035. verts[j*3+0] += orig[0];
  1036. verts[j*3+1] += orig[1] + chf.ch; // Is this offset necessary?
  1037. verts[j*3+2] += orig[2];
  1038. }
  1039. // Offset poly too, will be used to flag checking.
  1040. for (int j = 0; j < npoly; ++j)
  1041. {
  1042. poly[j*3+0] += orig[0];
  1043. poly[j*3+1] += orig[1];
  1044. poly[j*3+2] += orig[2];
  1045. }
  1046. // Store detail submesh.
  1047. const int ntris = tris.size()/4;
  1048. dmesh.meshes[i*4+0] = (unsigned int)dmesh.nverts;
  1049. dmesh.meshes[i*4+1] = (unsigned int)nverts;
  1050. dmesh.meshes[i*4+2] = (unsigned int)dmesh.ntris;
  1051. dmesh.meshes[i*4+3] = (unsigned int)ntris;
  1052. // Store vertices, allocate more memory if necessary.
  1053. if (dmesh.nverts+nverts > vcap)
  1054. {
  1055. while (dmesh.nverts+nverts > vcap)
  1056. vcap += 256;
  1057. float* newv = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM);
  1058. if (!newv)
  1059. {
  1060. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newv' (%d).", vcap*3);
  1061. return false;
  1062. }
  1063. if (dmesh.nverts)
  1064. memcpy(newv, dmesh.verts, sizeof(float)*3*dmesh.nverts);
  1065. rcFree(dmesh.verts);
  1066. dmesh.verts = newv;
  1067. }
  1068. for (int j = 0; j < nverts; ++j)
  1069. {
  1070. dmesh.verts[dmesh.nverts*3+0] = verts[j*3+0];
  1071. dmesh.verts[dmesh.nverts*3+1] = verts[j*3+1];
  1072. dmesh.verts[dmesh.nverts*3+2] = verts[j*3+2];
  1073. dmesh.nverts++;
  1074. }
  1075. // Store triangles, allocate more memory if necessary.
  1076. if (dmesh.ntris+ntris > tcap)
  1077. {
  1078. while (dmesh.ntris+ntris > tcap)
  1079. tcap += 256;
  1080. unsigned char* newt = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM);
  1081. if (!newt)
  1082. {
  1083. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newt' (%d).", tcap*4);
  1084. return false;
  1085. }
  1086. if (dmesh.ntris)
  1087. memcpy(newt, dmesh.tris, sizeof(unsigned char)*4*dmesh.ntris);
  1088. rcFree(dmesh.tris);
  1089. dmesh.tris = newt;
  1090. }
  1091. for (int j = 0; j < ntris; ++j)
  1092. {
  1093. const int* t = &tris[j*4];
  1094. dmesh.tris[dmesh.ntris*4+0] = (unsigned char)t[0];
  1095. dmesh.tris[dmesh.ntris*4+1] = (unsigned char)t[1];
  1096. dmesh.tris[dmesh.ntris*4+2] = (unsigned char)t[2];
  1097. dmesh.tris[dmesh.ntris*4+3] = getTriFlags(&verts[t[0]*3], &verts[t[1]*3], &verts[t[2]*3], poly, npoly);
  1098. dmesh.ntris++;
  1099. }
  1100. }
  1101. ctx->stopTimer(RC_TIMER_BUILD_POLYMESHDETAIL);
  1102. return true;
  1103. }
  1104. /// @see rcAllocPolyMeshDetail, rcPolyMeshDetail
  1105. bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh)
  1106. {
  1107. rcAssert(ctx);
  1108. ctx->startTimer(RC_TIMER_MERGE_POLYMESHDETAIL);
  1109. int maxVerts = 0;
  1110. int maxTris = 0;
  1111. int maxMeshes = 0;
  1112. for (int i = 0; i < nmeshes; ++i)
  1113. {
  1114. if (!meshes[i]) continue;
  1115. maxVerts += meshes[i]->nverts;
  1116. maxTris += meshes[i]->ntris;
  1117. maxMeshes += meshes[i]->nmeshes;
  1118. }
  1119. mesh.nmeshes = 0;
  1120. mesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*maxMeshes*4, RC_ALLOC_PERM);
  1121. if (!mesh.meshes)
  1122. {
  1123. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4);
  1124. return false;
  1125. }
  1126. mesh.ntris = 0;
  1127. mesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris*4, RC_ALLOC_PERM);
  1128. if (!mesh.tris)
  1129. {
  1130. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4);
  1131. return false;
  1132. }
  1133. mesh.nverts = 0;
  1134. mesh.verts = (float*)rcAlloc(sizeof(float)*maxVerts*3, RC_ALLOC_PERM);
  1135. if (!mesh.verts)
  1136. {
  1137. ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", maxVerts*3);
  1138. return false;
  1139. }
  1140. // Merge datas.
  1141. for (int i = 0; i < nmeshes; ++i)
  1142. {
  1143. rcPolyMeshDetail* dm = meshes[i];
  1144. if (!dm) continue;
  1145. for (int j = 0; j < dm->nmeshes; ++j)
  1146. {
  1147. unsigned int* dst = &mesh.meshes[mesh.nmeshes*4];
  1148. unsigned int* src = &dm->meshes[j*4];
  1149. dst[0] = (unsigned int)mesh.nverts+src[0];
  1150. dst[1] = src[1];
  1151. dst[2] = (unsigned int)mesh.ntris+src[2];
  1152. dst[3] = src[3];
  1153. mesh.nmeshes++;
  1154. }
  1155. for (int k = 0; k < dm->nverts; ++k)
  1156. {
  1157. rcVcopy(&mesh.verts[mesh.nverts*3], &dm->verts[k*3]);
  1158. mesh.nverts++;
  1159. }
  1160. for (int k = 0; k < dm->ntris; ++k)
  1161. {
  1162. mesh.tris[mesh.ntris*4+0] = dm->tris[k*4+0];
  1163. mesh.tris[mesh.ntris*4+1] = dm->tris[k*4+1];
  1164. mesh.tris[mesh.ntris*4+2] = dm->tris[k*4+2];
  1165. mesh.tris[mesh.ntris*4+3] = dm->tris[k*4+3];
  1166. mesh.ntris++;
  1167. }
  1168. }
  1169. ctx->stopTimer(RC_TIMER_MERGE_POLYMESHDETAIL);
  1170. return true;
  1171. }