DetourStatNavMesh.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. //
  2. // Copyright (c) 2009 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 <float.h>
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include "DetourStatNavMesh.h"
  23. #include "DetourNode.h"
  24. #include "DetourCommon.h"
  25. //////////////////////////////////////////////////////////////////////////////////////////
  26. dtStatNavMesh::dtStatNavMesh() :
  27. m_data(0),
  28. m_dataSize(0),
  29. m_header(0),
  30. m_nodePool(0),
  31. m_openList(0)
  32. {
  33. }
  34. dtStatNavMesh::~dtStatNavMesh()
  35. {
  36. delete m_nodePool;
  37. delete m_openList;
  38. if (m_data)
  39. delete [] m_data;
  40. }
  41. bool dtStatNavMesh::init(unsigned char* data, int dataSize, bool ownsData)
  42. {
  43. dtStatNavMeshHeader* header = (dtStatNavMeshHeader*)data;
  44. if (header->magic != DT_STAT_NAVMESH_MAGIC)
  45. return false;
  46. if (header->version != DT_STAT_NAVMESH_VERSION)
  47. return false;
  48. const int headerSize = sizeof(dtStatNavMeshHeader);
  49. const int vertsSize = sizeof(float)*3*header->nverts;
  50. const int polysSize = sizeof(dtStatPoly)*header->npolys;
  51. const int nodesSize = sizeof(dtStatBVNode)*header->npolys*2;
  52. const int detailMeshesSize = sizeof(dtStatPolyDetail)*header->ndmeshes;
  53. const int detailVertsSize = sizeof(float)*3*header->ndverts;
  54. const int detailTrisSize = sizeof(unsigned char)*4*header->ndtris;
  55. unsigned char* d = data + headerSize;
  56. header->verts = (float*)d; d += vertsSize;
  57. header->polys = (dtStatPoly*)d; d += polysSize;
  58. header->bvtree = (dtStatBVNode*)d; d += nodesSize;
  59. header->dmeshes = (dtStatPolyDetail*)d; d += detailMeshesSize;
  60. header->dverts = (float*)d; d += detailVertsSize;
  61. header->dtris = (unsigned char*)d; d += detailTrisSize;
  62. m_nodePool = new dtNodePool(2048, 256);
  63. if (!m_nodePool)
  64. return false;
  65. m_openList = new dtNodeQueue(2048);
  66. if (!m_openList)
  67. return false;
  68. if (ownsData)
  69. {
  70. m_data = data;
  71. m_dataSize = dataSize;
  72. }
  73. m_header = header;
  74. return true;
  75. }
  76. const dtStatPoly* dtStatNavMesh::getPolyByRef(dtStatPolyRef ref) const
  77. {
  78. if (!m_header || ref == 0 || (int)ref > m_header->npolys) return 0;
  79. return &m_header->polys[ref-1];
  80. }
  81. int dtStatNavMesh::getPolyIndexByRef(dtStatPolyRef ref) const
  82. {
  83. if (!m_header || ref == 0 || (int)ref > m_header->npolys) return -1;
  84. return (int)ref-1;
  85. }
  86. int dtStatNavMesh::findPath(dtStatPolyRef startRef, dtStatPolyRef endRef,
  87. const float* startPos, const float* endPos,
  88. dtStatPolyRef* path, const int maxPathSize)
  89. {
  90. if (!m_header) return 0;
  91. if (!startRef || !endRef)
  92. return 0;
  93. if (!maxPathSize)
  94. return 0;
  95. if (startRef == endRef)
  96. {
  97. path[0] = startRef;
  98. return 1;
  99. }
  100. m_nodePool->clear();
  101. m_openList->clear();
  102. static const float H_SCALE = 1.1f; // Heuristic scale.
  103. dtNode* startNode = m_nodePool->getNode(startRef);
  104. startNode->pidx = 0;
  105. startNode->cost = 0;
  106. startNode->total = vdist(startPos, endPos) * H_SCALE;
  107. startNode->id = startRef;
  108. startNode->flags = DT_NODE_OPEN;
  109. m_openList->push(startNode);
  110. dtNode* lastBestNode = startNode;
  111. float lastBestNodeCost = startNode->total;
  112. while (!m_openList->empty())
  113. {
  114. dtNode* bestNode = m_openList->pop();
  115. if (bestNode->id == endRef)
  116. {
  117. lastBestNode = bestNode;
  118. break;
  119. }
  120. const dtStatPoly* poly = getPoly(bestNode->id-1);
  121. for (int i = 0; i < (int)poly->nv; ++i)
  122. {
  123. dtStatPolyRef neighbour = poly->n[i];
  124. if (neighbour)
  125. {
  126. // Skip parent node.
  127. if (bestNode->pidx && m_nodePool->getNodeAtIdx(bestNode->pidx)->id == neighbour)
  128. continue;
  129. dtNode* parent = bestNode;
  130. dtNode newNode;
  131. newNode.pidx = m_nodePool->getNodeIdx(parent);
  132. newNode.id = neighbour;
  133. // Calculate cost.
  134. float p0[3], p1[3];
  135. if (!parent->pidx)
  136. vcopy(p0, startPos);
  137. else
  138. getEdgeMidPoint(m_nodePool->getNodeAtIdx(parent->pidx)->id, parent->id, p0);
  139. getEdgeMidPoint(parent->id, newNode.id, p1);
  140. newNode.cost = parent->cost + vdist(p0,p1);
  141. // Special case for last node.
  142. if (newNode.id == endRef)
  143. newNode.cost += vdist(p1, endPos);
  144. // Heuristic
  145. const float h = vdist(p1,endPos)*H_SCALE;
  146. newNode.total = newNode.cost + h;
  147. dtNode* actualNode = m_nodePool->getNode(newNode.id);
  148. if (!actualNode)
  149. continue;
  150. if (!((actualNode->flags & DT_NODE_OPEN) && newNode.total > actualNode->total) &&
  151. !((actualNode->flags & DT_NODE_CLOSED) && newNode.total > actualNode->total))
  152. {
  153. actualNode->flags &= ~DT_NODE_CLOSED;
  154. actualNode->pidx = newNode.pidx;
  155. actualNode->cost = newNode.cost;
  156. actualNode->total = newNode.total;
  157. if (h < lastBestNodeCost)
  158. {
  159. lastBestNodeCost = h;
  160. lastBestNode = actualNode;
  161. }
  162. if (actualNode->flags & DT_NODE_OPEN)
  163. {
  164. m_openList->modify(actualNode);
  165. }
  166. else
  167. {
  168. actualNode->flags |= DT_NODE_OPEN;
  169. m_openList->push(actualNode);
  170. }
  171. }
  172. }
  173. }
  174. bestNode->flags |= DT_NODE_CLOSED;
  175. }
  176. // Reverse the path.
  177. dtNode* prev = 0;
  178. dtNode* node = lastBestNode;
  179. do
  180. {
  181. dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
  182. node->pidx = m_nodePool->getNodeIdx(prev);
  183. prev = node;
  184. node = next;
  185. }
  186. while (node);
  187. // Store path
  188. node = prev;
  189. int n = 0;
  190. do
  191. {
  192. path[n++] = node->id;
  193. node = m_nodePool->getNodeAtIdx(node->pidx);
  194. }
  195. while (node && n < maxPathSize);
  196. return n;
  197. }
  198. bool dtStatNavMesh::closestPointToPoly(dtStatPolyRef ref, const float* pos, float* closest) const
  199. {
  200. int idx = getPolyIndexByRef(ref);
  201. if (idx == -1)
  202. return false;
  203. float closestDistSqr = FLT_MAX;
  204. const dtStatPoly* p = getPoly(idx);
  205. const dtStatPolyDetail* pd = getPolyDetail(idx);
  206. for (int j = 0; j < pd->ntris; ++j)
  207. {
  208. const unsigned char* t = getDetailTri(pd->tbase+j);
  209. const float* v[3];
  210. for (int k = 0; k < 3; ++k)
  211. {
  212. if (t[k] < p->nv)
  213. v[k] = getVertex(p->v[t[k]]);
  214. else
  215. v[k] = getDetailVertex(pd->vbase+(t[k]-p->nv));
  216. }
  217. float pt[3];
  218. closestPtPointTriangle(pt, pos, v[0], v[1], v[2]);
  219. float d = vdistSqr(pos, pt);
  220. if (d < closestDistSqr)
  221. {
  222. vcopy(closest, pt);
  223. closestDistSqr = d;
  224. }
  225. }
  226. return true;
  227. }
  228. bool dtStatNavMesh::getPolyHeight(dtStatPolyRef ref, const float* pos, float* height) const
  229. {
  230. int idx = getPolyIndexByRef(ref);
  231. if (idx == -1)
  232. return false;
  233. const dtStatPoly* p = getPoly(idx);
  234. const dtStatPolyDetail* pd = getPolyDetail(idx);
  235. for (int i = 0; i < pd->ntris; ++i)
  236. {
  237. const unsigned char* t = getDetailTri(pd->tbase+i);
  238. const float* v[3];
  239. for (int j = 0; j < 3; ++j)
  240. {
  241. if (t[j] < p->nv)
  242. v[j] = getVertex(p->v[t[j]]);
  243. else
  244. v[j] = getDetailVertex(pd->vbase+(t[j]-p->nv));
  245. }
  246. float h;
  247. if (closestHeightPointTriangle(pos, v[0], v[1], v[2], h))
  248. {
  249. if (height)
  250. *height = h;
  251. return true;
  252. }
  253. }
  254. return false;
  255. }
  256. int dtStatNavMesh::findStraightPath(const float* startPos, const float* endPos,
  257. const dtStatPolyRef* path, const int pathSize,
  258. float* straightPath, const int maxStraightPathSize)
  259. {
  260. if (!m_header) return 0;
  261. if (!maxStraightPathSize)
  262. return 0;
  263. if (!path[0])
  264. return 0;
  265. int straightPathSize = 0;
  266. float closestStartPos[3];
  267. if (!closestPointToPoly(path[0], startPos, closestStartPos))
  268. return 0;
  269. // Add start point.
  270. vcopy(&straightPath[straightPathSize*3], closestStartPos);
  271. straightPathSize++;
  272. if (straightPathSize >= maxStraightPathSize)
  273. return straightPathSize;
  274. float closestEndPos[3];
  275. if (!closestPointToPoly(path[pathSize-1], endPos, closestEndPos))
  276. return 0;
  277. float portalApex[3], portalLeft[3], portalRight[3];
  278. if (pathSize > 1)
  279. {
  280. vcopy(portalApex, closestStartPos);
  281. vcopy(portalLeft, portalApex);
  282. vcopy(portalRight, portalApex);
  283. int apexIndex = 0;
  284. int leftIndex = 0;
  285. int rightIndex = 0;
  286. for (int i = 0; i < pathSize; ++i)
  287. {
  288. float left[3], right[3];
  289. if (i < pathSize-1)
  290. {
  291. // Next portal.
  292. getPortalPoints(path[i], path[i+1], left, right);
  293. }
  294. else
  295. {
  296. // End of the path.
  297. vcopy(left, closestEndPos);
  298. vcopy(right, closestEndPos);
  299. }
  300. // Right vertex.
  301. if (vequal(portalApex, portalRight))
  302. {
  303. vcopy(portalRight, right);
  304. rightIndex = i;
  305. }
  306. else
  307. {
  308. if (triArea2D(portalApex, portalRight, right) <= 0.0f)
  309. {
  310. if (triArea2D(portalApex, portalLeft, right) > 0.0f)
  311. {
  312. vcopy(portalRight, right);
  313. rightIndex = i;
  314. }
  315. else
  316. {
  317. vcopy(portalApex, portalLeft);
  318. apexIndex = leftIndex;
  319. if (!vequal(&straightPath[(straightPathSize-1)*3], portalApex))
  320. {
  321. vcopy(&straightPath[straightPathSize*3], portalApex);
  322. straightPathSize++;
  323. if (straightPathSize >= maxStraightPathSize)
  324. return straightPathSize;
  325. }
  326. vcopy(portalLeft, portalApex);
  327. vcopy(portalRight, portalApex);
  328. leftIndex = apexIndex;
  329. rightIndex = apexIndex;
  330. // Restart
  331. i = apexIndex;
  332. continue;
  333. }
  334. }
  335. }
  336. // Left vertex.
  337. if (vequal(portalApex, portalLeft))
  338. {
  339. vcopy(portalLeft, left);
  340. leftIndex = i;
  341. }
  342. else
  343. {
  344. if (triArea2D(portalApex, portalLeft, left) >= 0.0f)
  345. {
  346. if (triArea2D(portalApex, portalRight, left) < 0.0f)
  347. {
  348. vcopy(portalLeft, left);
  349. leftIndex = i;
  350. }
  351. else
  352. {
  353. vcopy(portalApex, portalRight);
  354. apexIndex = rightIndex;
  355. if (!vequal(&straightPath[(straightPathSize-1)*3], portalApex))
  356. {
  357. vcopy(&straightPath[straightPathSize*3], portalApex);
  358. straightPathSize++;
  359. if (straightPathSize >= maxStraightPathSize)
  360. return straightPathSize;
  361. }
  362. vcopy(portalLeft, portalApex);
  363. vcopy(portalRight, portalApex);
  364. leftIndex = apexIndex;
  365. rightIndex = apexIndex;
  366. // Restart
  367. i = apexIndex;
  368. continue;
  369. }
  370. }
  371. }
  372. }
  373. }
  374. // Add end point.
  375. vcopy(&straightPath[straightPathSize*3], closestEndPos);
  376. straightPathSize++;
  377. return straightPathSize;
  378. }
  379. int dtStatNavMesh::getPolyVerts(dtStatPolyRef ref, float* verts) const
  380. {
  381. if (!m_header) return 0;
  382. const dtStatPoly* poly = getPolyByRef(ref);
  383. if (!poly) return 0;
  384. float* v = verts;
  385. for (int i = 0; i < (int)poly->nv; ++i)
  386. {
  387. const float* cv = &m_header->verts[poly->v[i]*3];
  388. *v++ = cv[0];
  389. *v++ = cv[1];
  390. *v++ = cv[2];
  391. }
  392. return (int)poly->nv;
  393. }
  394. int dtStatNavMesh::raycast(dtStatPolyRef centerRef, const float* startPos, const float* endPos,
  395. float& t, dtStatPolyRef* path, const int pathSize)
  396. {
  397. if (!m_header) return 0;
  398. if (!centerRef) return 0;
  399. /* dtStatPolyRef prevRef = centerRef; */ /* UNUSED */
  400. dtStatPolyRef curRef = centerRef;
  401. t = 0;
  402. float verts[DT_STAT_VERTS_PER_POLYGON*3];
  403. int n = 0;
  404. while (curRef)
  405. {
  406. // Cast ray against current polygon.
  407. int nv = getPolyVerts(curRef, verts);
  408. if (nv < 3)
  409. {
  410. // Hit bad polygon, report hit.
  411. return n;
  412. }
  413. float tmin, tmax;
  414. int segMin, segMax;
  415. if (!intersectSegmentPoly2D(startPos, endPos, verts, nv, tmin, tmax, segMin, segMax))
  416. {
  417. // Could not a polygon, keep the old t and report hit.
  418. return n;
  419. }
  420. // Keep track of furthest t so far.
  421. if (tmax > t)
  422. t = tmax;
  423. if (n < pathSize)
  424. path[n++] = curRef;
  425. // Check the neighbour of this polygon.
  426. const dtStatPoly* poly = getPolyByRef(curRef);
  427. dtStatPolyRef nextRef = poly->n[segMax];
  428. if (!nextRef)
  429. {
  430. // No neighbour, we hit a wall.
  431. return n;
  432. }
  433. // No hit, advance to neighbour polygon.
  434. /* prevRef = curRef; */ /* UNUSED */
  435. curRef = nextRef;
  436. }
  437. return n;
  438. }
  439. float dtStatNavMesh::findDistanceToWall(dtStatPolyRef centerRef, const float* centerPos, float maxRadius,
  440. float* hitPos, float* hitNormal)
  441. {
  442. if (!m_header) return 0;
  443. if (!centerRef) return 0;
  444. m_nodePool->clear();
  445. m_openList->clear();
  446. dtNode* startNode = m_nodePool->getNode(centerRef);
  447. startNode->pidx = 0;
  448. startNode->cost = 0;
  449. startNode->total = 0;
  450. startNode->id = centerRef;
  451. startNode->flags = DT_NODE_OPEN;
  452. m_openList->push(startNode);
  453. float radiusSqr = sqr(maxRadius);
  454. hitNormal[0] = 1;
  455. hitNormal[1] = 0;
  456. hitNormal[2] = 0;
  457. while (!m_openList->empty())
  458. {
  459. dtNode* bestNode = m_openList->pop();
  460. const dtStatPoly* poly = getPoly(bestNode->id-1);
  461. // Hit test walls.
  462. for (int i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j = i++)
  463. {
  464. // Skip non-solid edges.
  465. if (poly->n[j]) continue;
  466. // Calc distance to the edge.
  467. const float* vj = getVertex(poly->v[j]);
  468. const float* vi = getVertex(poly->v[i]);
  469. float tseg;
  470. float distSqr = distancePtSegSqr2D(centerPos, vj, vi, tseg);
  471. // Edge is too far, skip.
  472. if (distSqr > radiusSqr)
  473. continue;
  474. // Hit wall, update radius.
  475. radiusSqr = distSqr;
  476. // Calculate hit pos.
  477. hitPos[0] = vj[0] + (vi[0] - vj[0])*tseg;
  478. hitPos[1] = vj[1] + (vi[1] - vj[1])*tseg;
  479. hitPos[2] = vj[2] + (vi[2] - vj[2])*tseg;
  480. }
  481. // Check to see if the circle expands to one of the neighbours and expand.
  482. for (int i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j = i++)
  483. {
  484. // Skip solid edges.
  485. if (!poly->n[j]) continue;
  486. // Expand to neighbour if not visited yet.
  487. dtStatPolyRef neighbour = poly->n[j];
  488. // Skip parent node.
  489. if (bestNode->pidx && m_nodePool->getNodeAtIdx(bestNode->pidx)->id == neighbour)
  490. continue;
  491. // Calc distance to the edge.
  492. const float* vj = getVertex(poly->v[j]);
  493. const float* vi = getVertex(poly->v[i]);
  494. float tseg;
  495. float distSqr = distancePtSegSqr2D(centerPos, vj, vi, tseg);
  496. // Edge is too far, skip.
  497. if (distSqr > radiusSqr)
  498. continue;
  499. dtNode* parent = bestNode;
  500. dtNode newNode;
  501. newNode.pidx = m_nodePool->getNodeIdx(parent);
  502. newNode.id = neighbour;
  503. // Cost
  504. float p0[3], p1[3];
  505. if (!parent->pidx)
  506. vcopy(p0, centerPos);
  507. else
  508. getEdgeMidPoint(m_nodePool->getNodeAtIdx(parent->pidx)->id, parent->id, p0);
  509. getEdgeMidPoint(parent->id, newNode.id, p1);
  510. newNode.total = parent->total + vdist(p0,p1);
  511. dtNode* actualNode = m_nodePool->getNode(newNode.id);
  512. if (!actualNode)
  513. continue;
  514. if (!((actualNode->flags & DT_NODE_OPEN) && newNode.total > actualNode->total) &&
  515. !((actualNode->flags & DT_NODE_CLOSED) && newNode.total > actualNode->total))
  516. {
  517. actualNode->flags &= ~DT_NODE_CLOSED;
  518. actualNode->pidx = newNode.pidx;
  519. actualNode->total = newNode.total;
  520. if (actualNode->flags & DT_NODE_OPEN)
  521. {
  522. m_openList->modify(actualNode);
  523. }
  524. else
  525. {
  526. actualNode->flags |= DT_NODE_OPEN;
  527. m_openList->push(actualNode);
  528. }
  529. }
  530. }
  531. bestNode->flags |= DT_NODE_CLOSED;
  532. }
  533. // Calc hit normal.
  534. vsub(hitNormal, centerPos, hitPos);
  535. vnormalize(hitNormal);
  536. return sqrtf(radiusSqr);
  537. }
  538. int dtStatNavMesh::findPolysAround(dtStatPolyRef centerRef, const float* centerPos, float radius,
  539. dtStatPolyRef* resultRef, dtStatPolyRef* resultParent, float* resultCost,
  540. const int maxResult)
  541. {
  542. if (!m_header) return 0;
  543. if (!centerRef) return 0;
  544. m_nodePool->clear();
  545. m_openList->clear();
  546. dtNode* startNode = m_nodePool->getNode(centerRef);
  547. startNode->pidx = 0;
  548. startNode->cost = 0;
  549. startNode->total = 0;
  550. startNode->id = centerRef;
  551. startNode->flags = DT_NODE_OPEN;
  552. m_openList->push(startNode);
  553. int n = 0;
  554. if (n < maxResult)
  555. {
  556. if (resultRef)
  557. resultRef[n] = startNode->id;
  558. if (resultParent)
  559. resultParent[n] = 0;
  560. if (resultCost)
  561. resultCost[n] = 0;
  562. ++n;
  563. }
  564. const float radiusSqr = sqr(radius);
  565. while (!m_openList->empty())
  566. {
  567. dtNode* bestNode = m_openList->pop();
  568. const dtStatPoly* poly = getPoly(bestNode->id-1);
  569. for (unsigned i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j=i++)
  570. {
  571. dtStatPolyRef neighbour = poly->n[j];
  572. if (neighbour)
  573. {
  574. // Skip parent node.
  575. if (bestNode->pidx && m_nodePool->getNodeAtIdx(bestNode->pidx)->id == neighbour)
  576. continue;
  577. // Calc distance to the edge.
  578. const float* vj = getVertex(poly->v[j]);
  579. const float* vi = getVertex(poly->v[i]);
  580. float tseg;
  581. float distSqr = distancePtSegSqr2D(centerPos, vj, vi, tseg);
  582. // If the circle is not touching the next polygon, skip it.
  583. if (distSqr > radiusSqr)
  584. continue;
  585. dtNode* parent = bestNode;
  586. dtNode newNode;
  587. newNode.pidx = m_nodePool->getNodeIdx(parent);
  588. newNode.id = neighbour;
  589. // Cost
  590. float p0[3], p1[3];
  591. if (!parent->pidx)
  592. vcopy(p0, centerPos);
  593. else
  594. getEdgeMidPoint(m_nodePool->getNodeAtIdx(parent->pidx)->id, parent->id, p0);
  595. getEdgeMidPoint(parent->id, newNode.id, p1);
  596. newNode.total = parent->total + vdist(p0,p1);
  597. dtNode* actualNode = m_nodePool->getNode(newNode.id);
  598. if (!actualNode)
  599. continue;
  600. if (!((actualNode->flags & DT_NODE_OPEN) && newNode.total > actualNode->total) &&
  601. !((actualNode->flags & DT_NODE_CLOSED) && newNode.total > actualNode->total))
  602. {
  603. actualNode->flags &= ~DT_NODE_CLOSED;
  604. actualNode->pidx = newNode.pidx;
  605. actualNode->total = newNode.total;
  606. if (actualNode->flags & DT_NODE_OPEN)
  607. {
  608. m_openList->modify(actualNode);
  609. }
  610. else
  611. {
  612. if (n < maxResult)
  613. {
  614. if (resultRef)
  615. resultRef[n] = actualNode->id;
  616. if (resultParent)
  617. resultParent[n] = m_nodePool->getNodeAtIdx(actualNode->pidx)->id;
  618. if (resultCost)
  619. resultCost[n] = actualNode->total;
  620. ++n;
  621. }
  622. actualNode->flags |= DT_NODE_OPEN;
  623. m_openList->push(actualNode);
  624. }
  625. }
  626. }
  627. }
  628. bestNode->flags |= DT_NODE_CLOSED;
  629. }
  630. return n;
  631. }
  632. // Returns polygons which are withing certain radius from the query location.
  633. int dtStatNavMesh::queryPolygons(const float* center, const float* extents,
  634. dtStatPolyRef* polys, const int maxIds)
  635. {
  636. if (!m_header) return 0;
  637. const dtStatBVNode* node = &m_header->bvtree[0];
  638. const dtStatBVNode* end = &m_header->bvtree[m_header->nnodes];
  639. // Calculate quantized box
  640. const float ics = 1.0f / m_header->cs;
  641. unsigned short bmin[3], bmax[3];
  642. // Clamp query box to world box.
  643. float minx = clamp(center[0] - extents[0], m_header->bmin[0], m_header->bmax[0]) - m_header->bmin[0];
  644. float miny = clamp(center[1] - extents[1], m_header->bmin[1], m_header->bmax[1]) - m_header->bmin[1];
  645. float minz = clamp(center[2] - extents[2], m_header->bmin[2], m_header->bmax[2]) - m_header->bmin[2];
  646. float maxx = clamp(center[0] + extents[0], m_header->bmin[0], m_header->bmax[0]) - m_header->bmin[0];
  647. float maxy = clamp(center[1] + extents[1], m_header->bmin[1], m_header->bmax[1]) - m_header->bmin[1];
  648. float maxz = clamp(center[2] + extents[2], m_header->bmin[2], m_header->bmax[2]) - m_header->bmin[2];
  649. // Quantize
  650. bmin[0] = (unsigned short)(ics * minx) & 0xfffe;
  651. bmin[1] = (unsigned short)(ics * miny) & 0xfffe;
  652. bmin[2] = (unsigned short)(ics * minz) & 0xfffe;
  653. bmax[0] = (unsigned short)(ics * maxx + 1) | 1;
  654. bmax[1] = (unsigned short)(ics * maxy + 1) | 1;
  655. bmax[2] = (unsigned short)(ics * maxz + 1) | 1;
  656. // Traverse tree
  657. int n = 0;
  658. while (node < end)
  659. {
  660. bool overlap = checkOverlapBox(bmin, bmax, node->bmin, node->bmax);
  661. bool isLeafNode = node->i >= 0;
  662. if (isLeafNode && overlap)
  663. {
  664. if (n < maxIds)
  665. {
  666. polys[n] = (dtStatPolyRef)node->i;
  667. n++;
  668. }
  669. }
  670. if (overlap || isLeafNode)
  671. node++;
  672. else
  673. {
  674. const int escapeIndex = -node->i;
  675. node += escapeIndex;
  676. }
  677. }
  678. return n;
  679. }
  680. dtStatPolyRef dtStatNavMesh::findNearestPoly(const float* center, const float* extents)
  681. {
  682. if (!m_header) return 0;
  683. // Get nearby polygons from proximity grid.
  684. dtStatPolyRef polys[128];
  685. int npolys = queryPolygons(center, extents, polys, 128);
  686. // Find nearest polygon amongst the nearby polygons.
  687. dtStatPolyRef nearest = 0;
  688. float nearestDistanceSqr = FLT_MAX;
  689. for (int i = 0; i < npolys; ++i)
  690. {
  691. dtStatPolyRef ref = polys[i];
  692. float closest[3];
  693. if (!closestPointToPoly(ref, center, closest))
  694. continue;
  695. float d = vdistSqr(center, closest);
  696. if (d < nearestDistanceSqr)
  697. {
  698. nearestDistanceSqr = d;
  699. nearest = ref;
  700. }
  701. }
  702. return nearest;
  703. }
  704. bool dtStatNavMesh::getPortalPoints(dtStatPolyRef from, dtStatPolyRef to, float* left, float* right) const
  705. {
  706. const dtStatPoly* fromPoly = getPolyByRef(from);
  707. if (!fromPoly)
  708. return false;
  709. // Find common edge between the polygons and returns the segment end points.
  710. for (unsigned i = 0, j = (int)fromPoly->nv - 1; i < (int)fromPoly->nv; j = i++)
  711. {
  712. unsigned short neighbour = fromPoly->n[j];
  713. if (neighbour == to)
  714. {
  715. vcopy(left, getVertex(fromPoly->v[j]));
  716. vcopy(right, getVertex(fromPoly->v[i]));
  717. return true;
  718. }
  719. }
  720. return false;
  721. }
  722. bool dtStatNavMesh::getEdgeMidPoint(dtStatPolyRef from, dtStatPolyRef to, float* mid) const
  723. {
  724. float left[3], right[3];
  725. if (!getPortalPoints(from, to, left,right)) return false;
  726. mid[0] = (left[0]+right[0])*0.5f;
  727. mid[1] = (left[1]+right[1])*0.5f;
  728. mid[2] = (left[2]+right[2])*0.5f;
  729. return true;
  730. }
  731. bool dtStatNavMesh::isInClosedList(dtStatPolyRef ref) const
  732. {
  733. if (!m_nodePool) return false;
  734. const dtNode* node = m_nodePool->findNode(ref);
  735. return node && node->flags & DT_NODE_CLOSED;
  736. }
  737. int dtStatNavMesh::getMemUsed() const
  738. {
  739. if (!m_nodePool || ! m_openList)
  740. return 0;
  741. return sizeof(*this) + m_dataSize +
  742. m_nodePool->getMemUsed() +
  743. m_openList->getMemUsed();
  744. }