NavigationMesh.cpp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "CollisionShape.h"
  24. #include "Context.h"
  25. #include "DebugRenderer.h"
  26. #include "Drawable.h"
  27. #include "Geometry.h"
  28. #include "Log.h"
  29. #include "MemoryBuffer.h"
  30. #include "Model.h"
  31. #include "Navigable.h"
  32. #include "NavigationMesh.h"
  33. #include "Profiler.h"
  34. #include "Scene.h"
  35. #include "StaticModel.h"
  36. #include "TerrainPatch.h"
  37. #include "VectorBuffer.h"
  38. #include <cfloat>
  39. #include <DetourNavMesh.h>
  40. #include <DetourNavMeshBuilder.h>
  41. #include <DetourNavMeshQuery.h>
  42. #include <Recast.h>
  43. #include "DebugNew.h"
  44. namespace Urho3D
  45. {
  46. static const int DEFAULT_TILE_SIZE = 128;
  47. static const float DEFAULT_CELL_SIZE = 0.3f;
  48. static const float DEFAULT_CELL_HEIGHT = 0.2f;
  49. static const float DEFAULT_AGENT_HEIGHT = 2.0f;
  50. static const float DEFAULT_AGENT_RADIUS = 0.6f;
  51. static const float DEFAULT_AGENT_MAX_CLIMB = 0.9f;
  52. static const float DEFAULT_AGENT_MAX_SLOPE = 45.0f;
  53. static const float DEFAULT_REGION_MIN_SIZE = 8.0f;
  54. static const float DEFAULT_REGION_MERGE_SIZE = 20.0f;
  55. static const float DEFAULT_EDGE_MAX_LENGTH = 12.0f;
  56. static const float DEFAULT_EDGE_MAX_ERROR = 1.3f;
  57. static const float DEFAULT_DETAIL_SAMPLE_DISTANCE = 6.0f;
  58. static const float DEFAULT_DETAIL_SAMPLE_MAX_ERROR = 1.0f;
  59. static const int MAX_POLYS = 2048;
  60. /// Temporary data for building one tile of the navigation mesh.
  61. struct NavigationBuildData
  62. {
  63. /// Construct.
  64. NavigationBuildData() :
  65. ctx_(new rcContext(false)),
  66. heightField_(0),
  67. compactHeightField_(0),
  68. contourSet_(0),
  69. polyMesh_(0),
  70. polyMeshDetail_(0)
  71. {
  72. }
  73. /// Destruct.
  74. ~NavigationBuildData()
  75. {
  76. delete(ctx_);
  77. rcFreeHeightField(heightField_);
  78. rcFreeCompactHeightfield(compactHeightField_);
  79. rcFreeContourSet(contourSet_);
  80. rcFreePolyMesh(polyMesh_);
  81. rcFreePolyMeshDetail(polyMeshDetail_);
  82. ctx_ = 0;
  83. heightField_ = 0;
  84. compactHeightField_ = 0;
  85. contourSet_ = 0;
  86. polyMesh_ = 0;
  87. polyMeshDetail_ = 0;
  88. }
  89. /// World-space bounding box of the navigation mesh tile.
  90. BoundingBox worldBoundingBox_;
  91. /// Vertices from geometries.
  92. PODVector<Vector3> vertices_;
  93. /// Triangle indices from geometries.
  94. PODVector<int> indices_;
  95. /// Recast context.
  96. rcContext* ctx_;
  97. /// Recast heightfield.
  98. rcHeightfield* heightField_;
  99. /// Recast compact heightfield.
  100. rcCompactHeightfield* compactHeightField_;
  101. /// Recast contour set.
  102. rcContourSet* contourSet_;
  103. /// Recast poly mesh.
  104. rcPolyMesh* polyMesh_;
  105. /// Recast detail poly mesh.
  106. rcPolyMeshDetail* polyMeshDetail_;
  107. };
  108. /// Temporary data for finding a path.
  109. struct FindPathData
  110. {
  111. // Polygons.
  112. dtPolyRef polys_[MAX_POLYS];
  113. // Polygons on the path.
  114. dtPolyRef pathPolys_[MAX_POLYS];
  115. // Points on the path.
  116. Vector3 pathPoints_[MAX_POLYS];
  117. // Flags on the path.
  118. unsigned char pathFlags_[MAX_POLYS];
  119. };
  120. OBJECTTYPESTATIC(NavigationMesh);
  121. NavigationMesh::NavigationMesh(Context* context) :
  122. Component(context),
  123. navMesh_(0),
  124. navMeshQuery_(0),
  125. queryFilter_(new dtQueryFilter()),
  126. pathData_(new FindPathData()),
  127. tileSize_(DEFAULT_TILE_SIZE),
  128. cellSize_(DEFAULT_CELL_SIZE),
  129. cellHeight_(DEFAULT_CELL_HEIGHT),
  130. agentHeight_(DEFAULT_AGENT_HEIGHT),
  131. agentRadius_(DEFAULT_AGENT_RADIUS),
  132. agentMaxClimb_(DEFAULT_AGENT_MAX_CLIMB),
  133. agentMaxSlope_(DEFAULT_AGENT_MAX_SLOPE),
  134. regionMinSize_(DEFAULT_REGION_MIN_SIZE),
  135. regionMergeSize_(DEFAULT_REGION_MERGE_SIZE),
  136. edgeMaxLength_(DEFAULT_EDGE_MAX_LENGTH),
  137. edgeMaxError_(DEFAULT_EDGE_MAX_ERROR),
  138. detailSampleDistance_(DEFAULT_DETAIL_SAMPLE_DISTANCE),
  139. detailSampleMaxError_(DEFAULT_DETAIL_SAMPLE_MAX_ERROR),
  140. numTilesX_(0),
  141. numTilesZ_(0)
  142. {
  143. }
  144. NavigationMesh::~NavigationMesh()
  145. {
  146. ReleaseNavigationMesh();
  147. delete queryFilter_;
  148. queryFilter_ = 0;
  149. delete pathData_;
  150. pathData_ = 0;
  151. }
  152. void NavigationMesh::RegisterObject(Context* context)
  153. {
  154. context->RegisterFactory<NavigationMesh>();
  155. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_INT, "Tile Size", GetTileSize, SetTileSize, int, DEFAULT_TILE_SIZE, AM_DEFAULT);
  156. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Cell Size", GetCellSize, SetCellSize, float, DEFAULT_CELL_SIZE, AM_DEFAULT);
  157. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Cell Height", GetCellHeight, SetCellHeight, float, DEFAULT_CELL_HEIGHT, AM_DEFAULT);
  158. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Agent Height", GetAgentHeight, SetAgentHeight, float, DEFAULT_AGENT_HEIGHT, AM_DEFAULT);
  159. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Agent Radius", GetAgentRadius, SetAgentRadius, float, DEFAULT_AGENT_RADIUS, AM_DEFAULT);
  160. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Agent Max Climb", GetAgentMaxClimb, SetAgentMaxClimb, float, DEFAULT_AGENT_MAX_CLIMB, AM_DEFAULT);
  161. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Agent Max Slope", GetAgentMaxSlope, SetAgentMaxSlope, float, DEFAULT_AGENT_MAX_SLOPE, AM_DEFAULT);
  162. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Region Min Size", GetRegionMinSize, SetRegionMinSize, float, DEFAULT_REGION_MIN_SIZE, AM_DEFAULT);
  163. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Region Merge Size", GetRegionMergeSize, SetRegionMergeSize, float, DEFAULT_REGION_MERGE_SIZE, AM_DEFAULT);
  164. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Edge Max Length", GetEdgeMaxLength, SetEdgeMaxLength, float, DEFAULT_EDGE_MAX_LENGTH, AM_DEFAULT);
  165. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Edge Max Error", GetEdgeMaxError, SetEdgeMaxError, float, DEFAULT_EDGE_MAX_ERROR, AM_DEFAULT);
  166. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Detail Sample Distance", GetDetailSampleDistance, SetDetailSampleDistance, float, DEFAULT_DETAIL_SAMPLE_DISTANCE, AM_DEFAULT);
  167. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_FLOAT, "Detail Sample Max Error", GetDetailSampleMaxError, SetDetailSampleMaxError, float, DEFAULT_DETAIL_SAMPLE_MAX_ERROR, AM_DEFAULT);
  168. ACCESSOR_ATTRIBUTE(NavigationMesh, VAR_BUFFER, "Navigation Data", GetNavigationDataAttr, SetNavigationDataAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_FILE | AM_NOEDIT);
  169. }
  170. void NavigationMesh::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  171. {
  172. if (!navMesh_ || !node_)
  173. return;
  174. const Matrix3x4& worldTransform = node_->GetWorldTransform();
  175. const dtNavMesh* navMesh = navMesh_;
  176. for (int z = 0; z < numTilesZ_; ++z)
  177. {
  178. for (int x = 0; x < numTilesX_; ++x)
  179. {
  180. const dtMeshTile* tile = navMesh->getTileAt(x, z, 0);
  181. if (!tile)
  182. continue;
  183. for (int i = 0; i < tile->header->polyCount; ++i)
  184. {
  185. dtPoly* poly = tile->polys + i;
  186. for (unsigned j = 0; j < poly->vertCount; ++j)
  187. {
  188. debug->AddLine(
  189. worldTransform * *reinterpret_cast<const Vector3*>(&tile->verts[poly->verts[j] * 3]),
  190. worldTransform * *reinterpret_cast<const Vector3*>(&tile->verts[poly->verts[(j + 1) % poly->vertCount] * 3]),
  191. Color::YELLOW,
  192. depthTest
  193. );
  194. }
  195. }
  196. }
  197. }
  198. }
  199. void NavigationMesh::SetTileSize(int size)
  200. {
  201. tileSize_ = Max(size, 16);
  202. MarkNetworkUpdate();
  203. }
  204. void NavigationMesh::SetCellSize(float size)
  205. {
  206. cellSize_ = Max(size, M_EPSILON);
  207. MarkNetworkUpdate();
  208. }
  209. void NavigationMesh::SetCellHeight(float height)
  210. {
  211. cellHeight_ = Max(height, M_EPSILON);
  212. MarkNetworkUpdate();
  213. }
  214. void NavigationMesh::SetAgentHeight(float height)
  215. {
  216. agentHeight_ = Max(height, M_EPSILON);
  217. MarkNetworkUpdate();
  218. }
  219. void NavigationMesh::SetAgentRadius(float radius)
  220. {
  221. agentRadius_ = Max(radius, M_EPSILON);
  222. MarkNetworkUpdate();
  223. }
  224. void NavigationMesh::SetAgentMaxClimb(float maxClimb)
  225. {
  226. agentMaxClimb_ = Max(maxClimb, M_EPSILON);
  227. MarkNetworkUpdate();
  228. }
  229. void NavigationMesh::SetAgentMaxSlope(float maxSlope)
  230. {
  231. agentMaxSlope_ = Max(maxSlope, 0.0f);
  232. MarkNetworkUpdate();
  233. }
  234. void NavigationMesh::SetRegionMinSize(float size)
  235. {
  236. regionMinSize_ = Max(size, M_EPSILON);
  237. MarkNetworkUpdate();
  238. }
  239. void NavigationMesh::SetRegionMergeSize(float size)
  240. {
  241. regionMergeSize_ = Max(size, M_EPSILON);
  242. MarkNetworkUpdate();
  243. }
  244. void NavigationMesh::SetEdgeMaxLength(float length)
  245. {
  246. edgeMaxLength_ = Max(length, M_EPSILON);
  247. MarkNetworkUpdate();
  248. }
  249. void NavigationMesh::SetEdgeMaxError(float error)
  250. {
  251. edgeMaxError_ = Max(error, M_EPSILON);
  252. MarkNetworkUpdate();
  253. }
  254. void NavigationMesh::SetDetailSampleDistance(float distance)
  255. {
  256. detailSampleDistance_ = Max(distance, M_EPSILON);
  257. MarkNetworkUpdate();
  258. }
  259. void NavigationMesh::SetDetailSampleMaxError(float error)
  260. {
  261. detailSampleMaxError_ = Max(error, M_EPSILON);
  262. MarkNetworkUpdate();
  263. }
  264. bool NavigationMesh::Build()
  265. {
  266. PROFILE(BuildNavigationMesh);
  267. ReleaseNavigationMesh();
  268. if (!node_)
  269. return false;
  270. if (!node_->GetWorldScale().Equals(Vector3::ONE))
  271. LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended");
  272. Vector<NavigationGeometryInfo> geometryList;
  273. CollectGeometries(geometryList);
  274. if (geometryList.Empty())
  275. return true; // Nothing to do
  276. // Build the combined bounding box
  277. for (unsigned i = 0; i < geometryList.Size(); ++i)
  278. boundingBox_.Merge(geometryList[i].boundingBox_);
  279. {
  280. PROFILE(BuildNavigationMesh);
  281. // Calculate number of tiles
  282. int gridW = 0, gridH = 0;
  283. float tileEdgeLength = (float)tileSize_ * cellSize_;
  284. rcCalcGridSize(&boundingBox_.min_.x_, &boundingBox_.max_.x_, cellSize_, &gridW, &gridH);
  285. numTilesX_ = (gridW + tileSize_ - 1) / tileSize_;
  286. numTilesZ_ = (gridH + tileSize_ - 1) / tileSize_;
  287. // Calculate max. number of tiles and polygons, 22 bits available to identify both tile & polygon within tile
  288. unsigned maxTiles = NextPowerOfTwo(numTilesX_ * numTilesZ_);
  289. unsigned tileBits = 0;
  290. unsigned temp = maxTiles;
  291. while (temp > 1)
  292. {
  293. temp >>= 1;
  294. ++tileBits;
  295. }
  296. unsigned maxPolys = 1 << (22 - tileBits);
  297. dtNavMeshParams params;
  298. rcVcopy(params.orig, &boundingBox_.min_.x_);
  299. params.tileWidth = tileEdgeLength;
  300. params.tileHeight = tileEdgeLength;
  301. params.maxTiles = maxTiles;
  302. params.maxPolys = maxPolys;
  303. navMesh_ = dtAllocNavMesh();
  304. if (!navMesh_)
  305. {
  306. LOGERROR("Could not allocate navigation mesh");
  307. return false;
  308. }
  309. if (dtStatusFailed(navMesh_->init(&params)))
  310. {
  311. LOGERROR("Could not initialize navigation mesh");
  312. ReleaseNavigationMesh();
  313. return false;
  314. }
  315. // Build each tile
  316. unsigned numTiles = 0;
  317. for (int z = 0; z < numTilesZ_; ++z)
  318. {
  319. for (int x = 0; x < numTilesX_; ++x)
  320. {
  321. if (BuildTile(geometryList, x, z))
  322. ++numTiles;
  323. }
  324. }
  325. LOGDEBUG("Built navigation mesh with " + String(numTiles) + " tiles");
  326. return true;
  327. }
  328. }
  329. bool NavigationMesh::Build(const BoundingBox& boundingBox)
  330. {
  331. PROFILE(BuildPartialNavigationMesh);
  332. /// \todo Partial rebuild does not modify the bounding box. Modifying in Y-direction could be supported
  333. if (!node_)
  334. return false;
  335. if (!navMesh_)
  336. {
  337. LOGERROR("Navigation mesh must first be built fully before it can be partially rebuilt");
  338. return false;
  339. }
  340. if (!node_->GetWorldScale().Equals(Vector3::ONE))
  341. LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended");
  342. BoundingBox localSpaceBox = boundingBox.Transformed(node_->GetWorldTransform().Inverse());
  343. float tileEdgeLength = (float)tileSize_ * cellSize_;
  344. Vector<NavigationGeometryInfo> geometryList;
  345. CollectGeometries(geometryList);
  346. int sx = Clamp((int)((localSpaceBox.min_.x_ - boundingBox_.min_.x_) / tileEdgeLength), 0, numTilesX_ - 1);
  347. int sz = Clamp((int)((localSpaceBox.min_.z_ - boundingBox_.min_.z_) / tileEdgeLength), 0, numTilesZ_ - 1);
  348. int ex = Clamp((int)((localSpaceBox.max_.x_ - boundingBox_.min_.x_) / tileEdgeLength), 0, numTilesX_ - 1);
  349. int ez = Clamp((int)((localSpaceBox.max_.z_ - boundingBox_.min_.z_) / tileEdgeLength), 0, numTilesZ_ - 1);
  350. unsigned numTiles = 0;
  351. for (int z = sz; z <= ez; ++z)
  352. {
  353. for (int x = sx; x <= ex; ++x)
  354. {
  355. if (BuildTile(geometryList, x, z))
  356. ++numTiles;
  357. }
  358. }
  359. LOGDEBUG("Rebuilt " + String(numTiles) + " tiles of the navigation mesh");
  360. return true;
  361. }
  362. void NavigationMesh::FindPath(PODVector<Vector3>& dest, const Vector3& start, const Vector3& end, const Vector3& extents)
  363. {
  364. PROFILE(FindPath);
  365. dest.Clear();
  366. if (!InitializeQuery())
  367. return;
  368. // Navigation data is in local space. Transform path points from world to local
  369. const Matrix3x4& transform = node_->GetWorldTransform();
  370. Matrix3x4 inverse = transform.Inverse();
  371. Vector3 localStart = inverse * start;
  372. Vector3 localEnd = inverse * end;
  373. dtPolyRef startRef;
  374. dtPolyRef endRef;
  375. navMeshQuery_->findNearestPoly(&localStart.x_, &extents.x_, queryFilter_, &startRef, 0);
  376. navMeshQuery_->findNearestPoly(&localEnd.x_, &extents.x_, queryFilter_, &endRef, 0);
  377. if (!startRef || !endRef)
  378. return;
  379. int numPolys = 0;
  380. int numPathPoints = 0;
  381. navMeshQuery_->findPath(startRef, endRef, &localStart.x_, &localEnd.x_, queryFilter_, pathData_->polys_, &numPolys,
  382. MAX_POLYS);
  383. if (!numPolys)
  384. return;
  385. Vector3 actualLocalEnd = localEnd;
  386. // If full path was not found, clamp end point to the end polygon
  387. if (pathData_->polys_[numPolys - 1] != endRef)
  388. navMeshQuery_->closestPointOnPoly(pathData_->polys_[numPolys - 1], &localEnd.x_, &actualLocalEnd.x_);
  389. navMeshQuery_->findStraightPath(&localStart.x_, &actualLocalEnd.x_, pathData_->polys_, numPolys,
  390. &pathData_->pathPoints_[0].x_, pathData_->pathFlags_, pathData_->pathPolys_, &numPathPoints, MAX_POLYS);
  391. // Transform path result back to world space
  392. for (int i = 0; i < numPathPoints; ++i)
  393. dest.Push(transform * pathData_->pathPoints_[i]);
  394. }
  395. Vector3 NavigationMesh::GetRandomPoint()
  396. {
  397. if (!InitializeQuery())
  398. return Vector3::ZERO;
  399. dtPolyRef polyRef;
  400. Vector3 point(Vector3::ZERO);
  401. navMeshQuery_->findRandomPoint(queryFilter_, Random, &polyRef, &point.x_);
  402. return node_->GetWorldTransform() * point;
  403. }
  404. Vector3 NavigationMesh::GetRandomPointInCircle(const Vector3& center, float radius, const Vector3& extents)
  405. {
  406. if (!InitializeQuery())
  407. return center;
  408. const Matrix3x4& transform = node_->GetWorldTransform();
  409. Matrix3x4 inverse = transform.Inverse();
  410. Vector3 localCenter = inverse * center;
  411. dtPolyRef startRef;
  412. navMeshQuery_->findNearestPoly(&localCenter.x_, &extents.x_, queryFilter_, &startRef, 0);
  413. if (!startRef)
  414. return center;
  415. dtPolyRef polyRef;
  416. Vector3 point(localCenter);
  417. navMeshQuery_->findRandomPointAroundCircle(startRef, &localCenter.x_, radius, queryFilter_, Random, &polyRef, &point.x_);
  418. return transform * point;
  419. }
  420. float NavigationMesh::GetDistanceToWall(const Vector3& point, float radius, const Vector3& extents)
  421. {
  422. if (!InitializeQuery())
  423. return radius;
  424. const Matrix3x4& transform = node_->GetWorldTransform();
  425. Matrix3x4 inverse = transform.Inverse();
  426. Vector3 localPoint = inverse * point;
  427. dtPolyRef startRef;
  428. navMeshQuery_->findNearestPoly(&localPoint.x_, &extents.x_, queryFilter_, &startRef, 0);
  429. if (!startRef)
  430. return radius;
  431. float hitDist = radius;
  432. Vector3 hitPos;
  433. Vector3 hitNormal;
  434. navMeshQuery_->findDistanceToWall(startRef, &localPoint.x_, radius, queryFilter_, &hitDist, &hitPos.x_, &hitNormal.x_);
  435. return hitDist;
  436. }
  437. Vector3 NavigationMesh::Raycast(const Vector3& start, const Vector3& end, const Vector3& extents)
  438. {
  439. if (!InitializeQuery())
  440. return end;
  441. const Matrix3x4& transform = node_->GetWorldTransform();
  442. Matrix3x4 inverse = transform.Inverse();
  443. Vector3 localStart = inverse * start;
  444. Vector3 localEnd = inverse * end;
  445. dtPolyRef startRef;
  446. navMeshQuery_->findNearestPoly(&localStart.x_, &extents.x_, queryFilter_, &startRef, 0);
  447. if (!startRef)
  448. return end;
  449. Vector3 localHitNormal;
  450. float t;
  451. int numPolys;
  452. navMeshQuery_->raycast(startRef, &localStart.x_, &localEnd.x_, queryFilter_, &t, &localHitNormal.x_, pathData_->polys_, &numPolys, MAX_POLYS);
  453. if (t == FLT_MAX)
  454. t = 1.0f;
  455. return start.Lerp(end, t);
  456. }
  457. BoundingBox NavigationMesh::GetWorldBoundingBox() const
  458. {
  459. return node_ ? boundingBox_.Transformed(node_->GetWorldTransform()) : boundingBox_;
  460. }
  461. void NavigationMesh::SetNavigationDataAttr(PODVector<unsigned char> data)
  462. {
  463. ReleaseNavigationMesh();
  464. if (!data.Size())
  465. return;
  466. MemoryBuffer buffer(data);
  467. boundingBox_ = buffer.ReadBoundingBox();
  468. numTilesX_ = buffer.ReadInt();
  469. numTilesZ_ = buffer.ReadInt();
  470. dtNavMeshParams params;
  471. rcVcopy(params.orig, &boundingBox_.min_.x_);
  472. params.tileWidth = buffer.ReadFloat();
  473. params.tileHeight = buffer.ReadFloat();
  474. params.maxTiles = buffer.ReadInt();
  475. params.maxPolys = buffer.ReadInt();
  476. navMesh_ = dtAllocNavMesh();
  477. if (!navMesh_)
  478. {
  479. LOGERROR("Could not allocate navigation mesh");
  480. return;
  481. }
  482. if (dtStatusFailed(navMesh_->init(&params)))
  483. {
  484. LOGERROR("Could not initialize navigation mesh");
  485. ReleaseNavigationMesh();
  486. return;
  487. }
  488. unsigned numTiles = 0;
  489. while (!buffer.IsEof())
  490. {
  491. int x = buffer.ReadInt();
  492. int z = buffer.ReadInt();
  493. dtTileRef tileRef = buffer.ReadUInt();
  494. unsigned navDataSize = buffer.ReadUInt();
  495. unsigned char* navData = (unsigned char*)dtAlloc(navDataSize, DT_ALLOC_PERM);
  496. if (!navData)
  497. {
  498. LOGERROR("Could not allocate data for navigation mesh tile");
  499. return;
  500. }
  501. buffer.Read(navData, navDataSize);
  502. if (dtStatusFailed(navMesh_->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, 0)))
  503. {
  504. LOGERROR("Failed to add navigation mesh tile");
  505. dtFree(navData);
  506. return;
  507. }
  508. else
  509. ++numTiles;
  510. }
  511. LOGDEBUG("Created navigation mesh with " + String(numTiles) + " tiles from serialized data");
  512. }
  513. PODVector<unsigned char> NavigationMesh::GetNavigationDataAttr() const
  514. {
  515. VectorBuffer ret;
  516. if (navMesh_)
  517. {
  518. ret.WriteBoundingBox(boundingBox_);
  519. ret.WriteInt(numTilesX_);
  520. ret.WriteInt(numTilesZ_);
  521. const dtNavMeshParams* params = navMesh_->getParams();
  522. ret.WriteFloat(params->tileWidth);
  523. ret.WriteFloat(params->tileHeight);
  524. ret.WriteInt(params->maxTiles);
  525. ret.WriteInt(params->maxPolys);
  526. const dtNavMesh* navMesh = navMesh_;
  527. for (int z = 0; z < numTilesZ_; ++z)
  528. {
  529. for (int x = 0; x < numTilesX_; ++x)
  530. {
  531. const dtMeshTile* tile = navMesh->getTileAt(x, z, 0);
  532. if (!tile)
  533. continue;
  534. ret.WriteInt(x);
  535. ret.WriteInt(z);
  536. ret.WriteUInt(navMesh->getTileRef(tile));
  537. ret.WriteUInt(tile->dataSize);
  538. ret.Write(tile->data, tile->dataSize);
  539. }
  540. }
  541. }
  542. return ret.GetBuffer();
  543. }
  544. void NavigationMesh::CollectGeometries(Vector<NavigationGeometryInfo>& geometryList)
  545. {
  546. PROFILE(CollectNavigationGeometry);
  547. // Get Navigable components from child nodes, not from whole scene. This makes it possible to partition
  548. // the scene into several navigation meshes
  549. PODVector<Navigable*> navigables;
  550. node_->GetComponents<Navigable>(navigables, true);
  551. HashSet<Node*> processedNodes;
  552. for (unsigned i = 0; i < navigables.Size(); ++i)
  553. {
  554. if (navigables[i]->IsEnabledEffective())
  555. CollectGeometries(geometryList, navigables[i]->GetNode(), processedNodes, navigables[i]->IsRecursive());
  556. }
  557. }
  558. void NavigationMesh::CollectGeometries(Vector<NavigationGeometryInfo>& geometryList, Node* node, HashSet<Node*>& processedNodes, bool recursive)
  559. {
  560. // Make sure nodes are not included twice
  561. if (processedNodes.Contains(node))
  562. return;
  563. processedNodes.Insert(node);
  564. Matrix3x4 inverse = node_->GetWorldTransform().Inverse();
  565. // Prefer compatible physics collision shapes (triangle mesh, convex hull, box) if found.
  566. // Then fallback to visible geometry
  567. PODVector<CollisionShape*> collisionShapes;
  568. node->GetComponents<CollisionShape>(collisionShapes);
  569. bool collisionShapeFound = false;
  570. for (unsigned i = 0; i < collisionShapes.Size(); ++i)
  571. {
  572. CollisionShape* shape = collisionShapes[i];
  573. if (!shape->IsEnabledEffective())
  574. continue;
  575. ShapeType type = shape->GetShapeType();
  576. if ((type == SHAPE_BOX || type == SHAPE_TRIANGLEMESH || type == SHAPE_CONVEXHULL) && shape->GetCollisionShape())
  577. {
  578. NavigationGeometryInfo info;
  579. Matrix3x4 scaleMatrix(Matrix3x4::IDENTITY);
  580. scaleMatrix.SetScale(shape->GetSize());
  581. info.component_ = shape;
  582. info.transform_ = inverse * node->GetWorldTransform() * scaleMatrix;
  583. info.boundingBox_ = shape->GetWorldBoundingBox().Transformed(inverse);
  584. geometryList.Push(info);
  585. collisionShapeFound = true;
  586. }
  587. }
  588. if (!collisionShapeFound)
  589. {
  590. PODVector<Drawable*> drawables;
  591. node->GetDerivedComponents<Drawable>(drawables);
  592. for (unsigned i = 0; i < drawables.Size(); ++i)
  593. {
  594. /// \todo Evaluate whether should handle other types. Now StaticModel & TerrainPatch are supported, others skipped
  595. Drawable* drawable = drawables[i];
  596. if (!drawable->IsEnabledEffective())
  597. continue;
  598. NavigationGeometryInfo info;
  599. if (drawable->GetType() == StaticModel::GetTypeStatic())
  600. info.lodLevel_ = static_cast<StaticModel*>(drawable)->GetOcclusionLodLevel();
  601. else if (drawable->GetType() == TerrainPatch::GetTypeStatic())
  602. info.lodLevel_ = 0;
  603. else
  604. continue;
  605. info.component_ = drawable;
  606. info.transform_ = inverse * node->GetWorldTransform();
  607. info.boundingBox_ = drawable->GetWorldBoundingBox().Transformed(inverse);
  608. geometryList.Push(info);
  609. }
  610. }
  611. if (recursive)
  612. {
  613. const Vector<SharedPtr<Node> >& children = node->GetChildren();
  614. for(unsigned i = 0; i < children.Size(); ++i)
  615. CollectGeometries(geometryList, children[i], processedNodes, recursive);
  616. }
  617. }
  618. void NavigationMesh::GetTileGeometry(NavigationBuildData& build, Vector<NavigationGeometryInfo>& geometryList, BoundingBox& box)
  619. {
  620. for (unsigned i = 0; i < geometryList.Size(); ++i)
  621. {
  622. if (box.IsInsideFast(geometryList[i].boundingBox_) != OUTSIDE)
  623. {
  624. const Matrix3x4& transform = geometryList[i].transform_;
  625. CollisionShape* shape = dynamic_cast<CollisionShape*>(geometryList[i].component_);
  626. if (shape)
  627. {
  628. switch (shape->GetShapeType())
  629. {
  630. case SHAPE_TRIANGLEMESH:
  631. {
  632. Model* model = shape->GetModel();
  633. if (!model)
  634. continue;
  635. unsigned lodLevel = shape->GetLodLevel();
  636. for (unsigned j = 0; j < model->GetNumGeometries(); ++j)
  637. AddTriMeshGeometry(build, model->GetGeometry(j, lodLevel), transform);
  638. }
  639. break;
  640. case SHAPE_CONVEXHULL:
  641. {
  642. ConvexData* data = static_cast<ConvexData*>(shape->GetGeometryData());
  643. if (!data)
  644. continue;
  645. unsigned numVertices = data->vertexCount_;
  646. unsigned numIndices = data->indexCount_;
  647. unsigned destVertexStart = build.vertices_.Size();
  648. for (unsigned j = 0; j < numVertices; ++j)
  649. build.vertices_.Push(transform * data->vertexData_[j]);
  650. for (unsigned j = 0; j < numIndices; ++j)
  651. build.indices_.Push(data->indexData_[j] + destVertexStart);
  652. }
  653. break;
  654. case SHAPE_BOX:
  655. {
  656. unsigned destVertexStart = build.vertices_.Size();
  657. build.vertices_.Push(transform * Vector3(-0.5f, 0.5f, -0.5f));
  658. build.vertices_.Push(transform * Vector3(0.5f, 0.5f, -0.5f));
  659. build.vertices_.Push(transform * Vector3(0.5f, -0.5f, -0.5f));
  660. build.vertices_.Push(transform * Vector3(-0.5f, -0.5f, -0.5f));
  661. build.vertices_.Push(transform * Vector3(-0.5f, 0.5f, 0.5f));
  662. build.vertices_.Push(transform * Vector3(0.5f, 0.5f, 0.5f));
  663. build.vertices_.Push(transform * Vector3(0.5f, -0.5f, 0.5f));
  664. build.vertices_.Push(transform * Vector3(-0.5f, -0.5f, 0.5f));
  665. const unsigned indices[] = {
  666. 0, 1, 2, 0, 2, 3, 1, 5, 6, 1, 6, 2, 4, 5, 1, 4, 1, 0, 5, 4, 7, 5, 7, 6,
  667. 4, 0, 3, 4, 3, 7, 1, 0, 4, 1, 4, 5
  668. };
  669. for (unsigned j = 0; j < 36; ++j)
  670. build.indices_.Push(indices[j] + destVertexStart);
  671. }
  672. break;
  673. }
  674. }
  675. else
  676. {
  677. Drawable* drawable = dynamic_cast<Drawable*>(geometryList[i].component_);
  678. if (drawable)
  679. {
  680. const Vector<SourceBatch>& batches = drawable->GetBatches();
  681. for (unsigned j = 0; j < batches.Size(); ++j)
  682. AddTriMeshGeometry(build, drawable->GetLodGeometry(j, geometryList[i].lodLevel_), transform);
  683. }
  684. }
  685. }
  686. }
  687. }
  688. void NavigationMesh::AddTriMeshGeometry(NavigationBuildData& build, Geometry* geometry, const Matrix3x4& transform)
  689. {
  690. if (!geometry)
  691. return;
  692. const unsigned char* vertexData;
  693. const unsigned char* indexData;
  694. unsigned vertexSize;
  695. unsigned indexSize;
  696. unsigned elementMask;
  697. geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
  698. if (!vertexData || !indexData || (elementMask & MASK_POSITION) == 0)
  699. return;
  700. unsigned srcIndexStart = geometry->GetIndexStart();
  701. unsigned srcIndexCount = geometry->GetIndexCount();
  702. unsigned srcVertexStart = geometry->GetVertexStart();
  703. unsigned srcVertexCount = geometry->GetVertexCount();
  704. if (!srcIndexCount)
  705. return;
  706. unsigned destVertexStart = build.vertices_.Size();
  707. for (unsigned k = srcVertexStart; k < srcVertexStart + srcVertexCount; ++k)
  708. {
  709. Vector3 vertex = transform * *((const Vector3*)(&vertexData[k * vertexSize]));
  710. build.vertices_.Push(vertex);
  711. }
  712. // Copy remapped indices
  713. if (indexSize == sizeof(unsigned short))
  714. {
  715. const unsigned short* indices = ((const unsigned short*)indexData) + srcIndexStart;
  716. const unsigned short* indicesEnd = indices + srcIndexCount;
  717. while (indices < indicesEnd)
  718. {
  719. build.indices_.Push(*indices - srcVertexStart + destVertexStart);
  720. ++indices;
  721. }
  722. }
  723. else
  724. {
  725. const unsigned* indices = ((const unsigned*)indexData) + srcIndexStart;
  726. const unsigned* indicesEnd = indices + srcIndexCount;
  727. while (indices < indicesEnd)
  728. {
  729. build.indices_.Push(*indices - srcVertexStart + destVertexStart);
  730. ++indices;
  731. }
  732. }
  733. }
  734. bool NavigationMesh::BuildTile(Vector<NavigationGeometryInfo>& geometryList, int x, int z)
  735. {
  736. PROFILE(BuildNavigationMeshTile);
  737. // Remove previous tile (if any)
  738. navMesh_->removeTile(navMesh_->getTileRefAt(x, z, 0), 0, 0);
  739. float tileEdgeLength = (float)tileSize_ * cellSize_;
  740. BoundingBox tileBoundingBox(Vector3(
  741. boundingBox_.min_.x_ + tileEdgeLength * (float)x,
  742. boundingBox_.min_.y_,
  743. boundingBox_.min_.z_ + tileEdgeLength * (float)z
  744. ),
  745. Vector3(
  746. boundingBox_.min_.x_ + tileEdgeLength * (float)(x + 1),
  747. boundingBox_.max_.y_,
  748. boundingBox_.min_.z_ + tileEdgeLength * (float)(z + 1)
  749. ));
  750. NavigationBuildData build;
  751. rcConfig cfg;
  752. memset(&cfg, 0, sizeof cfg);
  753. cfg.cs = cellSize_;
  754. cfg.ch = cellHeight_;
  755. cfg.walkableSlopeAngle = agentMaxSlope_;
  756. cfg.walkableHeight = (int)ceilf(agentHeight_ / cfg.ch);
  757. cfg.walkableClimb = (int)floorf(agentMaxClimb_ / cfg.ch);
  758. cfg.walkableRadius = (int)ceilf(agentRadius_ / cfg.cs);
  759. cfg.maxEdgeLen = (int)(edgeMaxLength_ / cellSize_);
  760. cfg.maxSimplificationError = edgeMaxError_;
  761. cfg.minRegionArea = (int)sqrtf(regionMinSize_);
  762. cfg.mergeRegionArea = (int)sqrtf(regionMergeSize_);
  763. cfg.maxVertsPerPoly = 6;
  764. cfg.tileSize = tileSize_;
  765. cfg.borderSize = cfg.walkableRadius + 3; // Add padding
  766. cfg.width = cfg.tileSize + cfg.borderSize * 2;
  767. cfg.height = cfg.tileSize + cfg.borderSize * 2;
  768. cfg.detailSampleDist = detailSampleDistance_ < 0.9f ? 0.0f : cellSize_ * detailSampleDistance_;
  769. cfg.detailSampleMaxError = cellHeight_ * detailSampleMaxError_;
  770. rcVcopy(cfg.bmin, &tileBoundingBox.min_.x_);
  771. rcVcopy(cfg.bmax, &tileBoundingBox.max_.x_);
  772. cfg.bmin[0] -= cfg.borderSize * cfg.cs;
  773. cfg.bmin[2] -= cfg.borderSize * cfg.cs;
  774. cfg.bmax[0] += cfg.borderSize * cfg.cs;
  775. cfg.bmax[2] += cfg.borderSize * cfg.cs;
  776. BoundingBox expandedBox(*reinterpret_cast<Vector3*>(cfg.bmin), *reinterpret_cast<Vector3*>(cfg.bmax));
  777. GetTileGeometry(build, geometryList, expandedBox);
  778. if (build.vertices_.Empty() || build.indices_.Empty())
  779. return true; // Nothing to do
  780. build.heightField_ = rcAllocHeightfield();
  781. if (!build.heightField_)
  782. {
  783. LOGERROR("Could not allocate heightfield");
  784. return false;
  785. }
  786. if (!rcCreateHeightfield(build.ctx_, *build.heightField_, cfg.width, cfg.height, cfg.bmin, cfg.bmax, cfg.cs,
  787. cfg.ch))
  788. {
  789. LOGERROR("Could not create heightfield");
  790. return false;
  791. }
  792. unsigned numTriangles = build.indices_.Size() / 3;
  793. SharedArrayPtr<unsigned char> triAreas(new unsigned char[numTriangles]);
  794. memset(triAreas.Get(), 0, numTriangles);
  795. rcMarkWalkableTriangles(build.ctx_, cfg.walkableSlopeAngle, &build.vertices_[0].x_, build.vertices_.Size(),
  796. &build.indices_[0], numTriangles, triAreas.Get());
  797. rcRasterizeTriangles(build.ctx_, &build.vertices_[0].x_, build.vertices_.Size(), &build.indices_[0],
  798. triAreas.Get(), numTriangles, *build.heightField_, cfg.walkableClimb);
  799. rcFilterLowHangingWalkableObstacles(build.ctx_, cfg.walkableClimb, *build.heightField_);
  800. rcFilterLedgeSpans(build.ctx_, cfg.walkableHeight, cfg.walkableClimb, *build.heightField_);
  801. rcFilterWalkableLowHeightSpans(build.ctx_, cfg.walkableHeight, *build.heightField_);
  802. build.compactHeightField_ = rcAllocCompactHeightfield();
  803. if (!build.compactHeightField_)
  804. {
  805. LOGERROR("Could not allocate create compact heightfield");
  806. return false;
  807. }
  808. if (!rcBuildCompactHeightfield(build.ctx_, cfg.walkableHeight, cfg.walkableClimb, *build.heightField_,
  809. *build.compactHeightField_))
  810. {
  811. LOGERROR("Could not build compact heightfield");
  812. return false;
  813. }
  814. if (!rcErodeWalkableArea(build.ctx_, cfg.walkableRadius, *build.compactHeightField_))
  815. {
  816. LOGERROR("Could not erode compact heightfield");
  817. return false;
  818. }
  819. if (!rcBuildDistanceField(build.ctx_, *build.compactHeightField_))
  820. {
  821. LOGERROR("Could not build distance field");
  822. return false;
  823. }
  824. if (!rcBuildRegions(build.ctx_, *build.compactHeightField_, cfg.borderSize, cfg.minRegionArea,
  825. cfg.mergeRegionArea))
  826. {
  827. LOGERROR("Could not build regions");
  828. return false;
  829. }
  830. build.contourSet_ = rcAllocContourSet();
  831. if (!build.contourSet_)
  832. {
  833. LOGERROR("Could not allocate contour set");
  834. return false;
  835. }
  836. if (!rcBuildContours(build.ctx_, *build.compactHeightField_, cfg.maxSimplificationError, cfg.maxEdgeLen,
  837. *build.contourSet_))
  838. {
  839. LOGERROR("Could not create contours");
  840. return false;
  841. }
  842. build.polyMesh_ = rcAllocPolyMesh();
  843. if (!build.polyMesh_)
  844. {
  845. LOGERROR("Could not allocate poly mesh");
  846. return false;
  847. }
  848. if (!rcBuildPolyMesh(build.ctx_, *build.contourSet_, cfg.maxVertsPerPoly, *build.polyMesh_))
  849. {
  850. LOGERROR("Could not triangulate contours");
  851. return false;
  852. }
  853. build.polyMeshDetail_ = rcAllocPolyMeshDetail();
  854. if (!build.polyMeshDetail_)
  855. {
  856. LOGERROR("Could not allocate detail mesh");
  857. return false;
  858. }
  859. if (!rcBuildPolyMeshDetail(build.ctx_, *build.polyMesh_, *build.compactHeightField_, cfg.detailSampleDist,
  860. cfg.detailSampleMaxError, *build.polyMeshDetail_))
  861. {
  862. LOGERROR("Could not build detail mesh");
  863. return false;
  864. }
  865. // Set polygon flags
  866. /// \todo Allow to define custom flags
  867. for (int i = 0; i < build.polyMesh_->npolys; ++i)
  868. {
  869. if (build.polyMesh_->areas[i] == RC_WALKABLE_AREA)
  870. build.polyMesh_->flags[i] = 0x1;
  871. }
  872. unsigned char* navData = 0;
  873. int navDataSize = 0;
  874. dtNavMeshCreateParams params;
  875. memset(&params, 0, sizeof params);
  876. params.verts = build.polyMesh_->verts;
  877. params.vertCount = build.polyMesh_->nverts;
  878. params.polys = build.polyMesh_->polys;
  879. params.polyAreas = build.polyMesh_->areas;
  880. params.polyFlags = build.polyMesh_->flags;
  881. params.polyCount = build.polyMesh_->npolys;
  882. params.nvp = build.polyMesh_->nvp;
  883. params.detailMeshes = build.polyMeshDetail_->meshes;
  884. params.detailVerts = build.polyMeshDetail_->verts;
  885. params.detailVertsCount = build.polyMeshDetail_->nverts;
  886. params.detailTris = build.polyMeshDetail_->tris;
  887. params.detailTriCount = build.polyMeshDetail_->ntris;
  888. params.walkableHeight = agentHeight_;
  889. params.walkableRadius = agentRadius_;
  890. params.walkableClimb = agentMaxClimb_;
  891. params.tileX = x;
  892. params.tileY = z;
  893. rcVcopy(params.bmin, build.polyMesh_->bmin);
  894. rcVcopy(params.bmax, build.polyMesh_->bmax);
  895. params.cs = cfg.cs;
  896. params.ch = cfg.ch;
  897. params.buildBvTree = true;
  898. if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
  899. {
  900. LOGERROR("Could not build navigation mesh tile data");
  901. return false;
  902. }
  903. if (dtStatusFailed(navMesh_->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, 0)))
  904. {
  905. LOGERROR("Failed to add navigation mesh tile");
  906. dtFree(navData);
  907. return false;
  908. }
  909. return true;
  910. }
  911. bool NavigationMesh::InitializeQuery()
  912. {
  913. if (!navMesh_ || !node_)
  914. return false;
  915. if (navMeshQuery_)
  916. return true;
  917. navMeshQuery_ = dtAllocNavMeshQuery();
  918. if (!navMeshQuery_)
  919. {
  920. LOGERROR("Could not create navigation mesh query");
  921. return false;
  922. }
  923. if (dtStatusFailed(navMeshQuery_->init(navMesh_, MAX_POLYS)))
  924. {
  925. LOGERROR("Could not init navigation mesh query");
  926. return false;
  927. }
  928. return true;
  929. }
  930. void NavigationMesh::ReleaseNavigationMesh()
  931. {
  932. dtFreeNavMesh(navMesh_);
  933. navMesh_ = 0;
  934. dtFreeNavMeshQuery(navMeshQuery_);
  935. navMeshQuery_ = 0;
  936. numTilesX_ = 0;
  937. numTilesZ_ = 0;
  938. boundingBox_.min_ = boundingBox_.max_ = Vector3::ZERO;
  939. boundingBox_.defined_ = false;
  940. }
  941. }