navMesh.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  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
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell 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
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include <stdio.h>
  23. #include "navMesh.h"
  24. #include <DetourDebugDraw.h>
  25. #include <RecastDebugDraw.h>
  26. #include "math/mathUtils.h"
  27. #include "math/mRandom.h"
  28. #include "console/consoleTypes.h"
  29. #include "console/engineAPI.h"
  30. #include "console/typeValidators.h"
  31. #include "scene/sceneRenderState.h"
  32. #include "gfx/gfxDrawUtil.h"
  33. #include "renderInstance/renderPassManager.h"
  34. #include "gfx/primBuilder.h"
  35. #include "core/stream/bitStream.h"
  36. #include "math/mathIO.h"
  37. extern bool gEditingMission;
  38. IMPLEMENT_CO_NETOBJECT_V1(NavMesh);
  39. const U32 NavMesh::mMaxVertsPerPoly = 3;
  40. NavMesh::NavMesh()
  41. {
  42. mTypeMask |= StaticShapeObjectType | MarkerObjectType;
  43. mFileName = StringTable->insert("");
  44. mNetFlags.clear(Ghostable);
  45. nm = NULL;
  46. dMemset(&cfg, 0, sizeof(cfg));
  47. mCellSize = mCellHeight = 0.2f;
  48. mWalkableHeight = 2.0f;
  49. mWalkableClimb = 0.3f;
  50. mWalkableRadius = 0.5f;
  51. mWalkableSlope = 40.0f;
  52. mBorderSize = 1;
  53. mDetailSampleDist = 6.0f;
  54. mDetailSampleMaxError = 1.0f;
  55. mMaxEdgeLen = 12;
  56. mMaxSimplificationError = 1.3f;
  57. mMinRegionArea = 8;
  58. mMergeRegionArea = 20;
  59. mTileSize = 10.0f;
  60. mMaxPolysPerTile = 128;
  61. mAlwaysRender = false;
  62. mBuilding = false;
  63. }
  64. NavMesh::~NavMesh()
  65. {
  66. dtFreeNavMesh(nm);
  67. nm = NULL;
  68. }
  69. bool NavMesh::setProtectedDetailSampleDist(void *obj, const char *index, const char *data)
  70. {
  71. F32 dist = dAtof(data);
  72. if(dist == 0.0f || dist >= 0.9f)
  73. return true;
  74. Con::errorf("NavMesh::detailSampleDist must be 0 or greater than 0.9!");
  75. return false;
  76. }
  77. bool NavMesh::setProtectedAlwaysRender(void *obj, const char *index, const char *data)
  78. {
  79. NavMesh *mesh = static_cast<NavMesh*>(obj);
  80. bool always = dAtob(data);
  81. if(always)
  82. {
  83. if(!gEditingMission)
  84. mesh->mNetFlags.set(Ghostable);
  85. }
  86. else
  87. {
  88. if(!gEditingMission)
  89. mesh->mNetFlags.clear(Ghostable);
  90. }
  91. mesh->mAlwaysRender = always;
  92. mesh->setMaskBits(LoadFlag);
  93. return true;
  94. }
  95. FRangeValidator ValidCellSize(0.01f, 10.0f);
  96. FRangeValidator ValidSlopeAngle(0.0f, 89.9f);
  97. IRangeValidator PositiveInt(0, S32_MAX);
  98. IRangeValidator NaturalNumber(1, S32_MAX);
  99. FRangeValidator CornerAngle(0.0f, 90.0f);
  100. void NavMesh::initPersistFields()
  101. {
  102. addGroup("NavMesh Options");
  103. addField("fileName", TypeString, Offset(mFileName, NavMesh),
  104. "Name of the data file to store this navmesh in (relative to engine executable).");
  105. addFieldV("cellSize", TypeF32, Offset(mCellSize, NavMesh), &ValidCellSize,
  106. "Length/width of a voxel.");
  107. addFieldV("cellHeight", TypeF32, Offset(mCellHeight, NavMesh), &ValidCellSize,
  108. "Height of a voxel.");
  109. addFieldV("tileSize", TypeF32, Offset(mTileSize, NavMesh), &CommonValidators::PositiveNonZeroFloat,
  110. "The horizontal size of tiles.");
  111. addFieldV("actorHeight", TypeF32, Offset(mWalkableHeight, NavMesh), &CommonValidators::PositiveFloat,
  112. "Height of an actor.");
  113. addFieldV("actorClimb", TypeF32, Offset(mWalkableClimb, NavMesh), &CommonValidators::PositiveFloat,
  114. "Maximum climbing height of an actor.");
  115. addFieldV("actorRadius", TypeF32, Offset(mWalkableRadius, NavMesh), &CommonValidators::PositiveFloat,
  116. "Radius of an actor.");
  117. addFieldV("walkableSlope", TypeF32, Offset(mWalkableSlope, NavMesh), &ValidSlopeAngle,
  118. "Maximum walkable slope in degrees.");
  119. endGroup("NavMesh Options");
  120. addGroup("NavMesh Rendering");
  121. addProtectedField("alwaysRender", TypeBool, Offset(mAlwaysRender, NavMesh),
  122. &setProtectedAlwaysRender, &defaultProtectedGetFn,
  123. "Display this NavMesh even outside the editor.");
  124. endGroup("NavMesh Rendering");
  125. addGroup("NavMesh Advanced Options");
  126. addFieldV("borderSize", TypeS32, Offset(mBorderSize, NavMesh), &PositiveInt,
  127. "Size of the non-walkable border around the navigation mesh (in voxels).");
  128. addProtectedField("detailSampleDist", TypeF32, Offset(mDetailSampleDist, NavMesh),
  129. &setProtectedDetailSampleDist, &defaultProtectedGetFn,
  130. "Sets the sampling distance to use when generating the detail mesh.");
  131. addFieldV("detailSampleError", TypeF32, Offset(mDetailSampleMaxError, NavMesh), &CommonValidators::PositiveFloat,
  132. "The maximum distance the detail mesh surface should deviate from heightfield data.");
  133. addFieldV("maxEdgeLen", TypeS32, Offset(mDetailSampleDist, NavMesh), &PositiveInt,
  134. "The maximum allowed length for contour edges along the border of the mesh.");
  135. addFieldV("simplificationError", TypeF32, Offset(mMaxSimplificationError, NavMesh), &CommonValidators::PositiveFloat,
  136. "The maximum distance a simplfied contour's border edges should deviate from the original raw contour.");
  137. addFieldV("minRegionArea", TypeS32, Offset(mMinRegionArea, NavMesh), &PositiveInt,
  138. "The minimum number of cells allowed to form isolated island areas.");
  139. addFieldV("mergeRegionArea", TypeS32, Offset(mMergeRegionArea, NavMesh), &PositiveInt,
  140. "Any regions with a span count smaller than this value will, if possible, be merged with larger regions.");
  141. addFieldV("maxPolysPerTile", TypeS32, Offset(mMaxPolysPerTile, NavMesh), &NaturalNumber,
  142. "The maximum number of polygons allowed in a tile.");
  143. endGroup("NavMesh Advanced Options");
  144. Parent::initPersistFields();
  145. }
  146. bool NavMesh::onAdd()
  147. {
  148. if(!Parent::onAdd())
  149. return false;
  150. mObjBox.set(Point3F(-10.0f, -10.0f, -1.0f),
  151. Point3F( 10.0f, 10.0f, 1.0f));
  152. resetWorldBox();
  153. addToScene();
  154. if(gEditingMission || mAlwaysRender)
  155. {
  156. mNetFlags.set(Ghostable);
  157. if(isClientObject())
  158. renderToDrawer();
  159. }
  160. if(isServerObject())
  161. {
  162. setProcessTick(true);
  163. }
  164. load();
  165. return true;
  166. }
  167. void NavMesh::onRemove()
  168. {
  169. removeFromScene();
  170. Parent::onRemove();
  171. }
  172. void NavMesh::setTransform(const MatrixF &mat)
  173. {
  174. Parent::setTransform(mat);
  175. }
  176. void NavMesh::setScale(const VectorF &scale)
  177. {
  178. Parent::setScale(scale);
  179. }
  180. bool NavMesh::build(bool background, bool saveIntermediates)
  181. {
  182. if(mBuilding)
  183. cancelBuild();
  184. mBuilding = true;
  185. dtFreeNavMesh(nm);
  186. // Allocate a new navmesh.
  187. nm = dtAllocNavMesh();
  188. if(!nm)
  189. {
  190. Con::errorf("Could not allocate dtNavMesh for NavMesh %s", getIdString());
  191. return false;
  192. }
  193. updateConfig();
  194. // Build navmesh parameters from console members.
  195. dtNavMeshParams params;
  196. rcVcopy(params.orig, cfg.bmin);
  197. params.tileWidth = cfg.tileSize * mCellSize;
  198. params.tileHeight = cfg.tileSize * mCellSize;
  199. params.maxTiles = mCeil(getWorldBox().len_x() / params.tileWidth) * mCeil(getWorldBox().len_y() / params.tileHeight);
  200. params.maxPolys = mMaxPolysPerTile;
  201. // Initialise our navmesh.
  202. if(dtStatusFailed(nm->init(&params)))
  203. {
  204. Con::errorf("Could not init dtNavMesh for NavMesh %s", getIdString());
  205. return false;
  206. }
  207. updateTiles(true);
  208. if(!background)
  209. {
  210. while(mDirtyTiles.size())
  211. buildNextTile();
  212. }
  213. return true;
  214. }
  215. DefineEngineMethod(NavMesh, build, bool, (bool background, bool save), (true, false),
  216. "@brief Create a Recast nav mesh.")
  217. {
  218. return object->build(background, save);
  219. }
  220. void NavMesh::cancelBuild()
  221. {
  222. while(mDirtyTiles.size()) mDirtyTiles.pop();
  223. mBuilding = false;
  224. }
  225. DefineEngineMethod(NavMesh, cancelBuild, void, (),,
  226. "@brief Cancel the current NavMesh build.")
  227. {
  228. object->cancelBuild();
  229. }
  230. void NavMesh::inspectPostApply()
  231. {
  232. if(mBuilding)
  233. cancelBuild();
  234. }
  235. void NavMesh::updateConfig()
  236. {
  237. // Build rcConfig object from our console members.
  238. dMemset(&cfg, 0, sizeof(cfg));
  239. cfg.cs = mCellSize;
  240. cfg.ch = mCellHeight;
  241. Box3F box = DTStoRC(getWorldBox());
  242. rcVcopy(cfg.bmin, box.minExtents);
  243. rcVcopy(cfg.bmax, box.maxExtents);
  244. rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
  245. cfg.walkableHeight = mCeil(mWalkableHeight / mCellHeight);
  246. cfg.walkableClimb = mCeil(mWalkableClimb / mCellHeight);
  247. cfg.walkableRadius = mCeil(mWalkableRadius / mCellSize);
  248. cfg.walkableSlopeAngle = mWalkableSlope;
  249. cfg.borderSize = cfg.walkableRadius + 3;
  250. cfg.detailSampleDist = mDetailSampleDist;
  251. cfg.detailSampleMaxError = mDetailSampleMaxError;
  252. cfg.maxEdgeLen = mMaxEdgeLen;
  253. cfg.maxSimplificationError = mMaxSimplificationError;
  254. cfg.maxVertsPerPoly = mMaxVertsPerPoly;
  255. cfg.minRegionArea = mMinRegionArea;
  256. cfg.mergeRegionArea = mMergeRegionArea;
  257. cfg.tileSize = mTileSize / cfg.cs;
  258. }
  259. S32 NavMesh::getTile(Point3F pos)
  260. {
  261. if(mBuilding)
  262. return -1;
  263. for(U32 i = 0; i < mTiles.size(); i++)
  264. {
  265. if(mTiles[i].box.isContained(pos))
  266. return i;
  267. }
  268. return -1;
  269. }
  270. Box3F NavMesh::getTileBox(U32 id)
  271. {
  272. if(mBuilding || id >= mTiles.size())
  273. return Box3F::Invalid;
  274. return mTiles[id].box;
  275. }
  276. void NavMesh::updateTiles(bool dirty)
  277. {
  278. if(!isProperlyAdded())
  279. return;
  280. mTiles.clear();
  281. while(mDirtyTiles.size()) mDirtyTiles.pop();
  282. const Box3F &box = DTStoRC(getWorldBox());
  283. if(box.isEmpty())
  284. return;
  285. updateConfig();
  286. // Calculate tile dimensions.
  287. const U32 ts = cfg.tileSize;
  288. const U32 tw = (cfg.width + ts-1) / ts;
  289. const U32 th = (cfg.height + ts-1) / ts;
  290. const F32 tcs = cfg.tileSize * cfg.cs;
  291. // Iterate over tiles.
  292. F32 tileBmin[3], tileBmax[3];
  293. for(U32 y = 0; y < th; ++y)
  294. {
  295. for(U32 x = 0; x < tw; ++x)
  296. {
  297. tileBmin[0] = cfg.bmin[0] + x*tcs;
  298. tileBmin[1] = cfg.bmin[1];
  299. tileBmin[2] = cfg.bmin[2] + y*tcs;
  300. tileBmax[0] = cfg.bmin[0] + (x+1)*tcs;
  301. tileBmax[1] = cfg.bmax[1];
  302. tileBmax[2] = cfg.bmin[2] + (y+1)*tcs;
  303. mTiles.push_back(
  304. Tile(RCtoDTS(tileBmin, tileBmax),
  305. x, y,
  306. tileBmin, tileBmax));
  307. if(dirty)
  308. mDirtyTiles.push(mTiles.size() - 1);
  309. }
  310. }
  311. }
  312. void NavMesh::processTick(const Move *move)
  313. {
  314. buildNextTile();
  315. }
  316. void NavMesh::buildNextTile()
  317. {
  318. if(mDirtyTiles.size())
  319. {
  320. // Pop a single dirty tile and process it.
  321. U32 i = mDirtyTiles.front();
  322. mDirtyTiles.pop();
  323. const Tile &tile = mTiles[i];
  324. // Intermediate data for tile build.
  325. TileData tempdata;
  326. // Generate navmesh for this tile.
  327. U32 dataSize = 0;
  328. unsigned char* data = buildTileData(tile, tempdata, dataSize);
  329. if(data)
  330. {
  331. // Remove any previous data.
  332. nm->removeTile(nm->getTileRefAt(tile.x, tile.y, 0), 0, 0);
  333. // Add new data (navmesh owns and deletes the data).
  334. dtStatus status = nm->addTile(data, dataSize, DT_TILE_FREE_DATA, 0, 0);
  335. int success = 1;
  336. if(dtStatusFailed(status))
  337. {
  338. success = 0;
  339. dtFree(data);
  340. }
  341. }
  342. // Did we just build the last tile?
  343. if(!mDirtyTiles.size())
  344. {
  345. mBuilding = false;
  346. }
  347. setMaskBits(BuildFlag);
  348. }
  349. }
  350. static void buildCallback(SceneObject* object,void *key)
  351. {
  352. SceneContainer::CallbackInfo* info = reinterpret_cast<SceneContainer::CallbackInfo*>(key);
  353. object->buildPolyList(info->context,info->polyList,info->boundingBox,info->boundingSphere);
  354. }
  355. unsigned char *NavMesh::buildTileData(const Tile &tile, TileData &data, U32 &dataSize)
  356. {
  357. // Push out tile boundaries a bit.
  358. F32 tileBmin[3], tileBmax[3];
  359. rcVcopy(tileBmin, tile.bmin);
  360. rcVcopy(tileBmax, tile.bmax);
  361. tileBmin[0] -= cfg.borderSize * cfg.cs;
  362. tileBmin[2] -= cfg.borderSize * cfg.cs;
  363. tileBmax[0] += cfg.borderSize * cfg.cs;
  364. tileBmax[2] += cfg.borderSize * cfg.cs;
  365. // Parse objects from level into RC-compatible format.
  366. Box3F box = RCtoDTS(tileBmin, tileBmax);
  367. SceneContainer::CallbackInfo info;
  368. info.context = PLC_Navigation;
  369. info.boundingBox = box;
  370. info.polyList = &data.geom;
  371. getContainer()->findObjects(box, StaticObjectType, buildCallback, &info);
  372. // Check for no geometry.
  373. if(!data.geom.getVertCount())
  374. return false;
  375. // Figure out voxel dimensions of this tile.
  376. U32 width = 0, height = 0;
  377. width = cfg.tileSize + cfg.borderSize * 2;
  378. height = cfg.tileSize + cfg.borderSize * 2;
  379. // Create a dummy context.
  380. rcContext ctx(false);
  381. // Create a heightfield to voxelise our input geometry.
  382. data.hf = rcAllocHeightfield();
  383. if(!data.hf)
  384. {
  385. Con::errorf("Out of memory (rcHeightField) for NavMesh %s", getIdString());
  386. return NULL;
  387. }
  388. if(!rcCreateHeightfield(&ctx, *data.hf, width, height, tileBmin, tileBmax, cfg.cs, cfg.ch))
  389. {
  390. Con::errorf("Could not generate rcHeightField for NavMesh %s", getIdString());
  391. return NULL;
  392. }
  393. unsigned char *areas = new unsigned char[data.geom.getTriCount()];
  394. if(!areas)
  395. {
  396. Con::errorf("Out of memory (area flags) for NavMesh %s", getIdString());
  397. return NULL;
  398. }
  399. dMemset(areas, 0, data.geom.getTriCount() * sizeof(unsigned char));
  400. // Filter triangles by angle and rasterize.
  401. rcMarkWalkableTriangles(&ctx, cfg.walkableSlopeAngle,
  402. data.geom.getVerts(), data.geom.getVertCount(),
  403. data.geom.getTris(), data.geom.getTriCount(), areas);
  404. rcRasterizeTriangles(&ctx, data.geom.getVerts(), data.geom.getVertCount(),
  405. data.geom.getTris(), areas, data.geom.getTriCount(),
  406. *data.hf, cfg.walkableClimb);
  407. delete[] areas;
  408. // Filter out areas with low ceilings and other stuff.
  409. rcFilterLowHangingWalkableObstacles(&ctx, cfg.walkableClimb, *data.hf);
  410. rcFilterLedgeSpans(&ctx, cfg.walkableHeight, cfg.walkableClimb, *data.hf);
  411. rcFilterWalkableLowHeightSpans(&ctx, cfg.walkableHeight, *data.hf);
  412. data.chf = rcAllocCompactHeightfield();
  413. if(!data.chf)
  414. {
  415. Con::errorf("Out of memory (rcCompactHeightField) for NavMesh %s", getIdString());
  416. return NULL;
  417. }
  418. if(!rcBuildCompactHeightfield(&ctx, cfg.walkableHeight, cfg.walkableClimb, *data.hf, *data.chf))
  419. {
  420. Con::errorf("Could not generate rcCompactHeightField for NavMesh %s", getIdString());
  421. return NULL;
  422. }
  423. if(!rcErodeWalkableArea(&ctx, cfg.walkableRadius, *data.chf))
  424. {
  425. Con::errorf("Could not erode walkable area for NavMesh %s", getIdString());
  426. return NULL;
  427. }
  428. //--------------------------
  429. // Todo: mark areas here.
  430. //const ConvexVolume* vols = m_geom->getConvexVolumes();
  431. //for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i)
  432. //rcMarkConvexPolyArea(m_NULL, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);
  433. //--------------------------
  434. if(false)
  435. {
  436. if(!rcBuildRegionsMonotone(&ctx, *data.chf, cfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea))
  437. {
  438. Con::errorf("Could not build regions for NavMesh %s", getIdString());
  439. return NULL;
  440. }
  441. }
  442. else
  443. {
  444. if(!rcBuildDistanceField(&ctx, *data.chf))
  445. {
  446. Con::errorf("Could not build distance field for NavMesh %s", getIdString());
  447. return NULL;
  448. }
  449. if(!rcBuildRegions(&ctx, *data.chf, cfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea))
  450. {
  451. Con::errorf("Could not build regions for NavMesh %s", getIdString());
  452. return NULL;
  453. }
  454. }
  455. data.cs = rcAllocContourSet();
  456. if(!data.cs)
  457. {
  458. Con::errorf("Out of memory (rcContourSet) for NavMesh %s", getIdString());
  459. return NULL;
  460. }
  461. if(!rcBuildContours(&ctx, *data.chf, cfg.maxSimplificationError, cfg.maxEdgeLen, *data.cs))
  462. {
  463. Con::errorf("Could not construct rcContourSet for NavMesh %s", getIdString());
  464. return NULL;
  465. }
  466. if(data.cs->nconts <= 0)
  467. {
  468. Con::errorf("No contours in rcContourSet for NavMesh %s", getIdString());
  469. return NULL;
  470. }
  471. data.pm = rcAllocPolyMesh();
  472. if(!data.pm)
  473. {
  474. Con::errorf("Out of memory (rcPolyMesh) for NavMesh %s", getIdString());
  475. return NULL;
  476. }
  477. if(!rcBuildPolyMesh(&ctx, *data.cs, cfg.maxVertsPerPoly, *data.pm))
  478. {
  479. Con::errorf("Could not construct rcPolyMesh for NavMesh %s", getIdString());
  480. return NULL;
  481. }
  482. data.pmd = rcAllocPolyMeshDetail();
  483. if(!data.pmd)
  484. {
  485. Con::errorf("Out of memory (rcPolyMeshDetail) for NavMesh %s", getIdString());
  486. return NULL;
  487. }
  488. if(!rcBuildPolyMeshDetail(&ctx, *data.pm, *data.chf, cfg.detailSampleDist, cfg.detailSampleMaxError, *data.pmd))
  489. {
  490. Con::errorf("Could not construct rcPolyMeshDetail for NavMesh %s", getIdString());
  491. return NULL;
  492. }
  493. if(data.pm->nverts >= 0xffff)
  494. {
  495. Con::errorf("Too many vertices in rcPolyMesh for NavMesh %s", getIdString());
  496. return NULL;
  497. }
  498. for(U32 i = 0; i < data.pm->npolys; i++)
  499. {
  500. if(data.pm->areas[i] == RC_WALKABLE_AREA)
  501. data.pm->areas[i] = GroundArea;
  502. if(data.pm->areas[i] == GroundArea)
  503. data.pm->flags[i] |= WalkFlag;
  504. if(data.pm->areas[i] == WaterArea)
  505. data.pm->flags[i] |= SwimFlag;
  506. }
  507. unsigned char* navData = 0;
  508. int navDataSize = 0;
  509. dtNavMeshCreateParams params;
  510. dMemset(&params, 0, sizeof(params));
  511. params.verts = data.pm->verts;
  512. params.vertCount = data.pm->nverts;
  513. params.polys = data.pm->polys;
  514. params.polyAreas = data.pm->areas;
  515. params.polyFlags = data.pm->flags;
  516. params.polyCount = data.pm->npolys;
  517. params.nvp = data.pm->nvp;
  518. params.detailMeshes = data.pmd->meshes;
  519. params.detailVerts = data.pmd->verts;
  520. params.detailVertsCount = data.pmd->nverts;
  521. params.detailTris = data.pmd->tris;
  522. params.detailTriCount = data.pmd->ntris;
  523. params.walkableHeight = mWalkableHeight;
  524. params.walkableRadius = mWalkableRadius;
  525. params.walkableClimb = mWalkableClimb;
  526. params.tileX = tile.x;
  527. params.tileY = tile.y;
  528. params.tileLayer = 0;
  529. rcVcopy(params.bmin, data.pm->bmin);
  530. rcVcopy(params.bmax, data.pm->bmax);
  531. params.cs = cfg.cs;
  532. params.ch = cfg.ch;
  533. params.buildBvTree = true;
  534. if(!dtCreateNavMeshData(&params, &navData, &navDataSize))
  535. {
  536. Con::errorf("Could not create dtNavMeshData for tile (%d, %d) of NavMesh %s",
  537. tile.x, tile.y, getIdString());
  538. return NULL;
  539. }
  540. dataSize = navDataSize;
  541. return navData;
  542. }
  543. /// This method should never be called in a separate thread to the rendering
  544. /// or pathfinding logic. It directly replaces data in the dtNavMesh for
  545. /// this NavMesh object.
  546. void NavMesh::buildTiles(const Box3F &box)
  547. {
  548. // Make sure we've already built or loaded.
  549. if(!nm)
  550. return;
  551. // Iterate over tiles.
  552. for(U32 i = 0; i < mTiles.size(); i++)
  553. {
  554. const Tile &tile = mTiles[i];
  555. // Check tile box.
  556. if(!tile.box.isOverlapped(box))
  557. continue;
  558. // Mark as dirty.
  559. mDirtyTiles.push(i);
  560. }
  561. }
  562. DefineEngineMethod(NavMesh, buildTiles, void, (Box3F box),,
  563. "@brief Rebuild the tiles overlapped by the input box.")
  564. {
  565. return object->buildTiles(box);
  566. }
  567. void NavMesh::buildTile(const U32 &tile)
  568. {
  569. if(tile < mTiles.size())
  570. {
  571. mDirtyTiles.push(tile);
  572. }
  573. }
  574. void NavMesh::renderToDrawer()
  575. {
  576. dd.clear();
  577. // Recast debug draw
  578. NetObject *no = getServerObject();
  579. if(no)
  580. {
  581. NavMesh *n = static_cast<NavMesh*>(no);
  582. if(n->nm)
  583. {
  584. dd.beginGroup(0);
  585. duDebugDrawNavMesh (&dd, *n->nm, 0);
  586. dd.beginGroup(1);
  587. duDebugDrawNavMeshPortals(&dd, *n->nm);
  588. dd.beginGroup(2);
  589. duDebugDrawNavMeshBVTree (&dd, *n->nm);
  590. }
  591. }
  592. }
  593. void NavMesh::prepRenderImage(SceneRenderState *state)
  594. {
  595. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  596. ri->renderDelegate.bind(this, &NavMesh::render);
  597. ri->type = RenderPassManager::RIT_Object;
  598. ri->translucentSort = true;
  599. ri->defaultKey = 1;
  600. state->getRenderPass()->addInst(ri);
  601. }
  602. void NavMesh::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
  603. {
  604. if(overrideMat)
  605. return;
  606. if(state->isReflectPass())
  607. return;
  608. PROFILE_SCOPE(NavMesh_Render);
  609. // Recast debug draw
  610. NetObject *no = getServerObject();
  611. if(no)
  612. {
  613. NavMesh *n = static_cast<NavMesh*>(no);
  614. if(n->isSelected())
  615. {
  616. GFXDrawUtil *drawer = GFX->getDrawUtil();
  617. GFXStateBlockDesc desc;
  618. desc.setZReadWrite(true, false);
  619. desc.setBlend(true);
  620. desc.setCullMode(GFXCullNone);
  621. drawer->drawCube(desc, getWorldBox(), n->mBuilding
  622. ? ColorI(255, 0, 0, 80)
  623. : ColorI(136, 228, 255, 45));
  624. desc.setFillModeWireframe();
  625. drawer->drawCube(desc, getWorldBox(), ColorI::BLACK);
  626. }
  627. if(n->mBuilding)
  628. {
  629. int alpha = 80;
  630. if(!n->isSelected() || !Con::getBoolVariable("$Nav::EditorOpen"))
  631. alpha = 20;
  632. dd.overrideColor(duRGBA(255, 0, 0, alpha));
  633. }
  634. else
  635. {
  636. dd.cancelOverride();
  637. }
  638. if((!gEditingMission && n->mAlwaysRender) || (gEditingMission && Con::getBoolVariable("$Nav::Editor::renderMesh", 1))) dd.renderGroup(0);
  639. if(Con::getBoolVariable("$Nav::Editor::renderPortals")) dd.renderGroup(1);
  640. if(Con::getBoolVariable("$Nav::Editor::renderBVTree")) dd.renderGroup(2);
  641. }
  642. }
  643. void NavMesh::onEditorEnable()
  644. {
  645. mNetFlags.set(Ghostable);
  646. if(isClientObject() && !mAlwaysRender)
  647. addToScene();
  648. }
  649. void NavMesh::onEditorDisable()
  650. {
  651. if(!mAlwaysRender)
  652. {
  653. mNetFlags.clear(Ghostable);
  654. if(isClientObject())
  655. removeFromScene();
  656. }
  657. }
  658. U32 NavMesh::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
  659. {
  660. U32 retMask = Parent::packUpdate(conn, mask, stream);
  661. mathWrite(*stream, getTransform());
  662. mathWrite(*stream, getScale());
  663. stream->writeFlag(mAlwaysRender);
  664. return retMask;
  665. }
  666. void NavMesh::unpackUpdate(NetConnection *conn, BitStream *stream)
  667. {
  668. Parent::unpackUpdate(conn, stream);
  669. mathRead(*stream, &mObjToWorld);
  670. mathRead(*stream, &mObjScale);
  671. mAlwaysRender = stream->readFlag();
  672. setTransform(mObjToWorld);
  673. renderToDrawer();
  674. }
  675. static const int NAVMESHSET_MAGIC = 'M'<<24 | 'S'<<16 | 'E'<<8 | 'T'; //'MSET';
  676. static const int NAVMESHSET_VERSION = 1;
  677. struct NavMeshSetHeader
  678. {
  679. int magic;
  680. int version;
  681. int numTiles;
  682. dtNavMeshParams params;
  683. };
  684. struct NavMeshTileHeader
  685. {
  686. dtTileRef tileRef;
  687. int dataSize;
  688. };
  689. bool NavMesh::load()
  690. {
  691. if(!dStrlen(mFileName))
  692. return false;
  693. FILE* fp = fopen(mFileName, "rb");
  694. if(!fp)
  695. return false;
  696. // Read header.
  697. NavMeshSetHeader header;
  698. fread(&header, sizeof(NavMeshSetHeader), 1, fp);
  699. if(header.magic != NAVMESHSET_MAGIC)
  700. {
  701. fclose(fp);
  702. return 0;
  703. }
  704. if(header.version != NAVMESHSET_VERSION)
  705. {
  706. fclose(fp);
  707. return 0;
  708. }
  709. if(nm)
  710. dtFreeNavMesh(nm);
  711. nm = dtAllocNavMesh();
  712. if(!nm)
  713. {
  714. fclose(fp);
  715. return false;
  716. }
  717. dtStatus status = nm->init(&header.params);
  718. if(dtStatusFailed(status))
  719. {
  720. fclose(fp);
  721. return false;
  722. }
  723. // Read tiles.
  724. for(U32 i = 0; i < header.numTiles; ++i)
  725. {
  726. NavMeshTileHeader tileHeader;
  727. fread(&tileHeader, sizeof(tileHeader), 1, fp);
  728. if(!tileHeader.tileRef || !tileHeader.dataSize)
  729. break;
  730. unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
  731. if(!data) break;
  732. memset(data, 0, tileHeader.dataSize);
  733. fread(data, tileHeader.dataSize, 1, fp);
  734. nm->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);
  735. }
  736. fclose(fp);
  737. updateTiles();
  738. if(isServerObject())
  739. {
  740. setMaskBits(LoadFlag);
  741. }
  742. return true;
  743. }
  744. DefineEngineMethod(NavMesh, load, bool, (),,
  745. "@brief Load this NavMesh from its file.")
  746. {
  747. return object->load();
  748. }
  749. bool NavMesh::save()
  750. {
  751. if(!dStrlen(mFileName) || !nm)
  752. return false;
  753. // Save our navmesh into a file to load from next time
  754. FILE* fp = fopen(mFileName, "wb");
  755. if(!fp)
  756. return false;
  757. // Store header.
  758. NavMeshSetHeader header;
  759. header.magic = NAVMESHSET_MAGIC;
  760. header.version = NAVMESHSET_VERSION;
  761. header.numTiles = 0;
  762. for(U32 i = 0; i < nm->getMaxTiles(); ++i)
  763. {
  764. const dtMeshTile* tile = ((const dtNavMesh*)nm)->getTile(i);
  765. if (!tile || !tile->header || !tile->dataSize) continue;
  766. header.numTiles++;
  767. }
  768. memcpy(&header.params, nm->getParams(), sizeof(dtNavMeshParams));
  769. fwrite(&header, sizeof(NavMeshSetHeader), 1, fp);
  770. // Store tiles.
  771. for(U32 i = 0; i < nm->getMaxTiles(); ++i)
  772. {
  773. const dtMeshTile* tile = ((const dtNavMesh*)nm)->getTile(i);
  774. if(!tile || !tile->header || !tile->dataSize) continue;
  775. NavMeshTileHeader tileHeader;
  776. tileHeader.tileRef = nm->getTileRef(tile);
  777. tileHeader.dataSize = tile->dataSize;
  778. fwrite(&tileHeader, sizeof(tileHeader), 1, fp);
  779. fwrite(tile->data, tile->dataSize, 1, fp);
  780. }
  781. fclose(fp);
  782. return true;
  783. }
  784. DefineEngineMethod(NavMesh, save, void, (),,
  785. "@brief Save this NavMesh to its file.")
  786. {
  787. object->save();
  788. }
  789. void NavMesh::write(Stream &stream, U32 tabStop, U32 flags)
  790. {
  791. save();
  792. Parent::write(stream, tabStop, flags);
  793. }