navMesh.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938
  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. if(dtStatusFailed(status))
  336. {
  337. dtFree(data);
  338. }
  339. }
  340. // Did we just build the last tile?
  341. if(!mDirtyTiles.size())
  342. {
  343. mBuilding = false;
  344. }
  345. setMaskBits(BuildFlag);
  346. }
  347. }
  348. static void buildCallback(SceneObject* object,void *key)
  349. {
  350. SceneContainer::CallbackInfo* info = reinterpret_cast<SceneContainer::CallbackInfo*>(key);
  351. object->buildPolyList(info->context,info->polyList,info->boundingBox,info->boundingSphere);
  352. }
  353. unsigned char *NavMesh::buildTileData(const Tile &tile, TileData &data, U32 &dataSize)
  354. {
  355. // Push out tile boundaries a bit.
  356. F32 tileBmin[3], tileBmax[3];
  357. rcVcopy(tileBmin, tile.bmin);
  358. rcVcopy(tileBmax, tile.bmax);
  359. tileBmin[0] -= cfg.borderSize * cfg.cs;
  360. tileBmin[2] -= cfg.borderSize * cfg.cs;
  361. tileBmax[0] += cfg.borderSize * cfg.cs;
  362. tileBmax[2] += cfg.borderSize * cfg.cs;
  363. // Parse objects from level into RC-compatible format.
  364. Box3F box = RCtoDTS(tileBmin, tileBmax);
  365. SceneContainer::CallbackInfo info;
  366. info.context = PLC_Navigation;
  367. info.boundingBox = box;
  368. info.polyList = &data.geom;
  369. getContainer()->findObjects(box, StaticObjectType, buildCallback, &info);
  370. // Check for no geometry.
  371. if(!data.geom.getVertCount())
  372. return false;
  373. // Figure out voxel dimensions of this tile.
  374. U32 width = 0, height = 0;
  375. width = cfg.tileSize + cfg.borderSize * 2;
  376. height = cfg.tileSize + cfg.borderSize * 2;
  377. // Create a dummy context.
  378. rcContext ctx(false);
  379. // Create a heightfield to voxelise our input geometry.
  380. data.hf = rcAllocHeightfield();
  381. if(!data.hf)
  382. {
  383. Con::errorf("Out of memory (rcHeightField) for NavMesh %s", getIdString());
  384. return NULL;
  385. }
  386. if(!rcCreateHeightfield(&ctx, *data.hf, width, height, tileBmin, tileBmax, cfg.cs, cfg.ch))
  387. {
  388. Con::errorf("Could not generate rcHeightField for NavMesh %s", getIdString());
  389. return NULL;
  390. }
  391. unsigned char *areas = new unsigned char[data.geom.getTriCount()];
  392. if(!areas)
  393. {
  394. Con::errorf("Out of memory (area flags) for NavMesh %s", getIdString());
  395. return NULL;
  396. }
  397. dMemset(areas, 0, data.geom.getTriCount() * sizeof(unsigned char));
  398. // Filter triangles by angle and rasterize.
  399. rcMarkWalkableTriangles(&ctx, cfg.walkableSlopeAngle,
  400. data.geom.getVerts(), data.geom.getVertCount(),
  401. data.geom.getTris(), data.geom.getTriCount(), areas);
  402. rcRasterizeTriangles(&ctx, data.geom.getVerts(), data.geom.getVertCount(),
  403. data.geom.getTris(), areas, data.geom.getTriCount(),
  404. *data.hf, cfg.walkableClimb);
  405. delete[] areas;
  406. // Filter out areas with low ceilings and other stuff.
  407. rcFilterLowHangingWalkableObstacles(&ctx, cfg.walkableClimb, *data.hf);
  408. rcFilterLedgeSpans(&ctx, cfg.walkableHeight, cfg.walkableClimb, *data.hf);
  409. rcFilterWalkableLowHeightSpans(&ctx, cfg.walkableHeight, *data.hf);
  410. data.chf = rcAllocCompactHeightfield();
  411. if(!data.chf)
  412. {
  413. Con::errorf("Out of memory (rcCompactHeightField) for NavMesh %s", getIdString());
  414. return NULL;
  415. }
  416. if(!rcBuildCompactHeightfield(&ctx, cfg.walkableHeight, cfg.walkableClimb, *data.hf, *data.chf))
  417. {
  418. Con::errorf("Could not generate rcCompactHeightField for NavMesh %s", getIdString());
  419. return NULL;
  420. }
  421. if(!rcErodeWalkableArea(&ctx, cfg.walkableRadius, *data.chf))
  422. {
  423. Con::errorf("Could not erode walkable area for NavMesh %s", getIdString());
  424. return NULL;
  425. }
  426. //--------------------------
  427. // Todo: mark areas here.
  428. //const ConvexVolume* vols = m_geom->getConvexVolumes();
  429. //for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i)
  430. //rcMarkConvexPolyArea(m_NULL, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);
  431. //--------------------------
  432. if(false)
  433. {
  434. if(!rcBuildRegionsMonotone(&ctx, *data.chf, cfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea))
  435. {
  436. Con::errorf("Could not build regions for NavMesh %s", getIdString());
  437. return NULL;
  438. }
  439. }
  440. else
  441. {
  442. if(!rcBuildDistanceField(&ctx, *data.chf))
  443. {
  444. Con::errorf("Could not build distance field for NavMesh %s", getIdString());
  445. return NULL;
  446. }
  447. if(!rcBuildRegions(&ctx, *data.chf, cfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea))
  448. {
  449. Con::errorf("Could not build regions for NavMesh %s", getIdString());
  450. return NULL;
  451. }
  452. }
  453. data.cs = rcAllocContourSet();
  454. if(!data.cs)
  455. {
  456. Con::errorf("Out of memory (rcContourSet) for NavMesh %s", getIdString());
  457. return NULL;
  458. }
  459. if(!rcBuildContours(&ctx, *data.chf, cfg.maxSimplificationError, cfg.maxEdgeLen, *data.cs))
  460. {
  461. Con::errorf("Could not construct rcContourSet for NavMesh %s", getIdString());
  462. return NULL;
  463. }
  464. if(data.cs->nconts <= 0)
  465. {
  466. Con::errorf("No contours in rcContourSet for NavMesh %s", getIdString());
  467. return NULL;
  468. }
  469. data.pm = rcAllocPolyMesh();
  470. if(!data.pm)
  471. {
  472. Con::errorf("Out of memory (rcPolyMesh) for NavMesh %s", getIdString());
  473. return NULL;
  474. }
  475. if(!rcBuildPolyMesh(&ctx, *data.cs, cfg.maxVertsPerPoly, *data.pm))
  476. {
  477. Con::errorf("Could not construct rcPolyMesh for NavMesh %s", getIdString());
  478. return NULL;
  479. }
  480. data.pmd = rcAllocPolyMeshDetail();
  481. if(!data.pmd)
  482. {
  483. Con::errorf("Out of memory (rcPolyMeshDetail) for NavMesh %s", getIdString());
  484. return NULL;
  485. }
  486. if(!rcBuildPolyMeshDetail(&ctx, *data.pm, *data.chf, cfg.detailSampleDist, cfg.detailSampleMaxError, *data.pmd))
  487. {
  488. Con::errorf("Could not construct rcPolyMeshDetail for NavMesh %s", getIdString());
  489. return NULL;
  490. }
  491. if(data.pm->nverts >= 0xffff)
  492. {
  493. Con::errorf("Too many vertices in rcPolyMesh for NavMesh %s", getIdString());
  494. return NULL;
  495. }
  496. for(U32 i = 0; i < data.pm->npolys; i++)
  497. {
  498. if(data.pm->areas[i] == RC_WALKABLE_AREA)
  499. data.pm->areas[i] = GroundArea;
  500. if(data.pm->areas[i] == GroundArea)
  501. data.pm->flags[i] |= WalkFlag;
  502. if(data.pm->areas[i] == WaterArea)
  503. data.pm->flags[i] |= SwimFlag;
  504. }
  505. unsigned char* navData = 0;
  506. int navDataSize = 0;
  507. dtNavMeshCreateParams params;
  508. dMemset(&params, 0, sizeof(params));
  509. params.verts = data.pm->verts;
  510. params.vertCount = data.pm->nverts;
  511. params.polys = data.pm->polys;
  512. params.polyAreas = data.pm->areas;
  513. params.polyFlags = data.pm->flags;
  514. params.polyCount = data.pm->npolys;
  515. params.nvp = data.pm->nvp;
  516. params.detailMeshes = data.pmd->meshes;
  517. params.detailVerts = data.pmd->verts;
  518. params.detailVertsCount = data.pmd->nverts;
  519. params.detailTris = data.pmd->tris;
  520. params.detailTriCount = data.pmd->ntris;
  521. params.walkableHeight = mWalkableHeight;
  522. params.walkableRadius = mWalkableRadius;
  523. params.walkableClimb = mWalkableClimb;
  524. params.tileX = tile.x;
  525. params.tileY = tile.y;
  526. params.tileLayer = 0;
  527. rcVcopy(params.bmin, data.pm->bmin);
  528. rcVcopy(params.bmax, data.pm->bmax);
  529. params.cs = cfg.cs;
  530. params.ch = cfg.ch;
  531. params.buildBvTree = true;
  532. if(!dtCreateNavMeshData(&params, &navData, &navDataSize))
  533. {
  534. Con::errorf("Could not create dtNavMeshData for tile (%d, %d) of NavMesh %s",
  535. tile.x, tile.y, getIdString());
  536. return NULL;
  537. }
  538. dataSize = navDataSize;
  539. return navData;
  540. }
  541. /// This method should never be called in a separate thread to the rendering
  542. /// or pathfinding logic. It directly replaces data in the dtNavMesh for
  543. /// this NavMesh object.
  544. void NavMesh::buildTiles(const Box3F &box)
  545. {
  546. // Make sure we've already built or loaded.
  547. if(!nm)
  548. return;
  549. // Iterate over tiles.
  550. for(U32 i = 0; i < mTiles.size(); i++)
  551. {
  552. const Tile &tile = mTiles[i];
  553. // Check tile box.
  554. if(!tile.box.isOverlapped(box))
  555. continue;
  556. // Mark as dirty.
  557. mDirtyTiles.push(i);
  558. }
  559. }
  560. DefineEngineMethod(NavMesh, buildTiles, void, (Box3F box),,
  561. "@brief Rebuild the tiles overlapped by the input box.")
  562. {
  563. return object->buildTiles(box);
  564. }
  565. void NavMesh::buildTile(const U32 &tile)
  566. {
  567. if(tile < mTiles.size())
  568. {
  569. mDirtyTiles.push(tile);
  570. }
  571. }
  572. void NavMesh::renderToDrawer()
  573. {
  574. dd.clear();
  575. // Recast debug draw
  576. NetObject *no = getServerObject();
  577. if(no)
  578. {
  579. NavMesh *n = static_cast<NavMesh*>(no);
  580. if(n->nm)
  581. {
  582. dd.beginGroup(0);
  583. duDebugDrawNavMesh (&dd, *n->nm, 0);
  584. dd.beginGroup(1);
  585. duDebugDrawNavMeshPortals(&dd, *n->nm);
  586. dd.beginGroup(2);
  587. duDebugDrawNavMeshBVTree (&dd, *n->nm);
  588. }
  589. }
  590. }
  591. void NavMesh::prepRenderImage(SceneRenderState *state)
  592. {
  593. ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  594. ri->renderDelegate.bind(this, &NavMesh::render);
  595. ri->type = RenderPassManager::RIT_Object;
  596. ri->translucentSort = true;
  597. ri->defaultKey = 1;
  598. state->getRenderPass()->addInst(ri);
  599. }
  600. void NavMesh::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
  601. {
  602. if(overrideMat)
  603. return;
  604. if(state->isReflectPass())
  605. return;
  606. PROFILE_SCOPE(NavMesh_Render);
  607. // Recast debug draw
  608. NetObject *no = getServerObject();
  609. if(no)
  610. {
  611. NavMesh *n = static_cast<NavMesh*>(no);
  612. if(n->isSelected())
  613. {
  614. GFXDrawUtil *drawer = GFX->getDrawUtil();
  615. GFXStateBlockDesc desc;
  616. desc.setZReadWrite(true, false);
  617. desc.setBlend(true);
  618. desc.setCullMode(GFXCullNone);
  619. drawer->drawCube(desc, getWorldBox(), n->mBuilding
  620. ? ColorI(255, 0, 0, 80)
  621. : ColorI(136, 228, 255, 45));
  622. desc.setFillModeWireframe();
  623. drawer->drawCube(desc, getWorldBox(), ColorI::BLACK);
  624. }
  625. if(n->mBuilding)
  626. {
  627. int alpha = 80;
  628. if(!n->isSelected() || !Con::getBoolVariable("$Nav::EditorOpen"))
  629. alpha = 20;
  630. dd.overrideColor(duRGBA(255, 0, 0, alpha));
  631. }
  632. else
  633. {
  634. dd.cancelOverride();
  635. }
  636. if((!gEditingMission && n->mAlwaysRender) || (gEditingMission && Con::getBoolVariable("$Nav::Editor::renderMesh", 1))) dd.renderGroup(0);
  637. if(Con::getBoolVariable("$Nav::Editor::renderPortals")) dd.renderGroup(1);
  638. if(Con::getBoolVariable("$Nav::Editor::renderBVTree")) dd.renderGroup(2);
  639. }
  640. }
  641. void NavMesh::onEditorEnable()
  642. {
  643. mNetFlags.set(Ghostable);
  644. if(isClientObject() && !mAlwaysRender)
  645. addToScene();
  646. }
  647. void NavMesh::onEditorDisable()
  648. {
  649. if(!mAlwaysRender)
  650. {
  651. mNetFlags.clear(Ghostable);
  652. if(isClientObject())
  653. removeFromScene();
  654. }
  655. }
  656. U32 NavMesh::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
  657. {
  658. U32 retMask = Parent::packUpdate(conn, mask, stream);
  659. mathWrite(*stream, getTransform());
  660. mathWrite(*stream, getScale());
  661. stream->writeFlag(mAlwaysRender);
  662. return retMask;
  663. }
  664. void NavMesh::unpackUpdate(NetConnection *conn, BitStream *stream)
  665. {
  666. Parent::unpackUpdate(conn, stream);
  667. mathRead(*stream, &mObjToWorld);
  668. mathRead(*stream, &mObjScale);
  669. mAlwaysRender = stream->readFlag();
  670. setTransform(mObjToWorld);
  671. renderToDrawer();
  672. }
  673. static const int NAVMESHSET_MAGIC = 'M'<<24 | 'S'<<16 | 'E'<<8 | 'T'; //'MSET';
  674. static const int NAVMESHSET_VERSION = 1;
  675. struct NavMeshSetHeader
  676. {
  677. int magic;
  678. int version;
  679. int numTiles;
  680. dtNavMeshParams params;
  681. };
  682. struct NavMeshTileHeader
  683. {
  684. dtTileRef tileRef;
  685. int dataSize;
  686. };
  687. bool NavMesh::load()
  688. {
  689. if(!dStrlen(mFileName))
  690. return false;
  691. FILE* fp = fopen(mFileName, "rb");
  692. if(!fp)
  693. return false;
  694. // Read header.
  695. NavMeshSetHeader header;
  696. fread(&header, sizeof(NavMeshSetHeader), 1, fp);
  697. if(header.magic != NAVMESHSET_MAGIC)
  698. {
  699. fclose(fp);
  700. return 0;
  701. }
  702. if(header.version != NAVMESHSET_VERSION)
  703. {
  704. fclose(fp);
  705. return 0;
  706. }
  707. if(nm)
  708. dtFreeNavMesh(nm);
  709. nm = dtAllocNavMesh();
  710. if(!nm)
  711. {
  712. fclose(fp);
  713. return false;
  714. }
  715. dtStatus status = nm->init(&header.params);
  716. if(dtStatusFailed(status))
  717. {
  718. fclose(fp);
  719. return false;
  720. }
  721. // Read tiles.
  722. for(U32 i = 0; i < header.numTiles; ++i)
  723. {
  724. NavMeshTileHeader tileHeader;
  725. fread(&tileHeader, sizeof(tileHeader), 1, fp);
  726. if(!tileHeader.tileRef || !tileHeader.dataSize)
  727. break;
  728. unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
  729. if(!data) break;
  730. memset(data, 0, tileHeader.dataSize);
  731. fread(data, tileHeader.dataSize, 1, fp);
  732. nm->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);
  733. }
  734. fclose(fp);
  735. updateTiles();
  736. if(isServerObject())
  737. {
  738. setMaskBits(LoadFlag);
  739. }
  740. return true;
  741. }
  742. DefineEngineMethod(NavMesh, load, bool, (),,
  743. "@brief Load this NavMesh from its file.")
  744. {
  745. return object->load();
  746. }
  747. bool NavMesh::save()
  748. {
  749. if(!dStrlen(mFileName) || !nm)
  750. return false;
  751. // Save our navmesh into a file to load from next time
  752. FILE* fp = fopen(mFileName, "wb");
  753. if(!fp)
  754. return false;
  755. // Store header.
  756. NavMeshSetHeader header;
  757. header.magic = NAVMESHSET_MAGIC;
  758. header.version = NAVMESHSET_VERSION;
  759. header.numTiles = 0;
  760. for(U32 i = 0; i < nm->getMaxTiles(); ++i)
  761. {
  762. const dtMeshTile* tile = ((const dtNavMesh*)nm)->getTile(i);
  763. if (!tile || !tile->header || !tile->dataSize) continue;
  764. header.numTiles++;
  765. }
  766. memcpy(&header.params, nm->getParams(), sizeof(dtNavMeshParams));
  767. fwrite(&header, sizeof(NavMeshSetHeader), 1, fp);
  768. // Store tiles.
  769. for(U32 i = 0; i < nm->getMaxTiles(); ++i)
  770. {
  771. const dtMeshTile* tile = ((const dtNavMesh*)nm)->getTile(i);
  772. if(!tile || !tile->header || !tile->dataSize) continue;
  773. NavMeshTileHeader tileHeader;
  774. tileHeader.tileRef = nm->getTileRef(tile);
  775. tileHeader.dataSize = tile->dataSize;
  776. fwrite(&tileHeader, sizeof(tileHeader), 1, fp);
  777. fwrite(tile->data, tile->dataSize, 1, fp);
  778. }
  779. fclose(fp);
  780. return true;
  781. }
  782. DefineEngineMethod(NavMesh, save, void, (),,
  783. "@brief Save this NavMesh to its file.")
  784. {
  785. object->save();
  786. }
  787. void NavMesh::write(Stream &stream, U32 tabStop, U32 flags)
  788. {
  789. save();
  790. Parent::write(stream, tabStop, flags);
  791. }