NavMeshPruneTool.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #define _USE_MATH_DEFINES
  19. #include <math.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <float.h>
  23. #include <vector>
  24. #include "SDL.h"
  25. #include "SDL_opengl.h"
  26. #include "imgui.h"
  27. #include "NavMeshPruneTool.h"
  28. #include "InputGeom.h"
  29. #include "Sample.h"
  30. #include "DetourNavMesh.h"
  31. #include "DetourCommon.h"
  32. #include "DetourAssert.h"
  33. #include "DetourDebugDraw.h"
  34. #ifdef WIN32
  35. # define snprintf _snprintf
  36. #endif
  37. class NavmeshFlags
  38. {
  39. struct TileFlags
  40. {
  41. inline void purge() { dtFree(flags); }
  42. unsigned char* flags;
  43. int nflags;
  44. dtPolyRef base;
  45. };
  46. const dtNavMesh* m_nav;
  47. TileFlags* m_tiles;
  48. int m_ntiles;
  49. public:
  50. NavmeshFlags() :
  51. m_nav(0), m_tiles(0), m_ntiles(0)
  52. {
  53. }
  54. ~NavmeshFlags()
  55. {
  56. for (int i = 0; i < m_ntiles; ++i)
  57. m_tiles[i].purge();
  58. dtFree(m_tiles);
  59. }
  60. bool init(const dtNavMesh* nav)
  61. {
  62. m_ntiles = nav->getMaxTiles();
  63. if (!m_ntiles)
  64. return true;
  65. m_tiles = (TileFlags*)dtAlloc(sizeof(TileFlags)*m_ntiles, DT_ALLOC_TEMP);
  66. if (!m_tiles)
  67. {
  68. return false;
  69. }
  70. memset(m_tiles, 0, sizeof(TileFlags)*m_ntiles);
  71. // Alloc flags for each tile.
  72. for (int i = 0; i < nav->getMaxTiles(); ++i)
  73. {
  74. const dtMeshTile* tile = nav->getTile(i);
  75. if (!tile->header) continue;
  76. TileFlags* tf = &m_tiles[i];
  77. tf->nflags = tile->header->polyCount;
  78. tf->base = nav->getPolyRefBase(tile);
  79. if (tf->nflags)
  80. {
  81. tf->flags = (unsigned char*)dtAlloc(tf->nflags, DT_ALLOC_TEMP);
  82. if (!tf->flags)
  83. return false;
  84. memset(tf->flags, 0, tf->nflags);
  85. }
  86. }
  87. m_nav = nav;
  88. return false;
  89. }
  90. inline void clearAllFlags()
  91. {
  92. for (int i = 0; i < m_ntiles; ++i)
  93. {
  94. TileFlags* tf = &m_tiles[i];
  95. if (tf->nflags)
  96. memset(tf->flags, 0, tf->nflags);
  97. }
  98. }
  99. inline unsigned char getFlags(dtPolyRef ref)
  100. {
  101. dtAssert(m_nav);
  102. dtAssert(m_ntiles);
  103. // Assume the ref is valid, no bounds checks.
  104. unsigned int salt, it, ip;
  105. m_nav->decodePolyId(ref, salt, it, ip);
  106. return m_tiles[it].flags[ip];
  107. }
  108. inline void setFlags(dtPolyRef ref, unsigned char flags)
  109. {
  110. dtAssert(m_nav);
  111. dtAssert(m_ntiles);
  112. // Assume the ref is valid, no bounds checks.
  113. unsigned int salt, it, ip;
  114. m_nav->decodePolyId(ref, salt, it, ip);
  115. m_tiles[it].flags[ip] = flags;
  116. }
  117. };
  118. static void floodNavmesh(dtNavMesh* nav, NavmeshFlags* flags, dtPolyRef start, unsigned char flag)
  119. {
  120. // If already visited, skip.
  121. if (flags->getFlags(start))
  122. return;
  123. flags->setFlags(start, flag);
  124. std::vector<dtPolyRef> openList;
  125. openList.push_back(start);
  126. while (openList.size())
  127. {
  128. const dtPolyRef ref = openList.back();
  129. openList.pop_back();
  130. // Get current poly and tile.
  131. // The API input has been cheked already, skip checking internal data.
  132. const dtMeshTile* tile = 0;
  133. const dtPoly* poly = 0;
  134. nav->getTileAndPolyByRefUnsafe(ref, &tile, &poly);
  135. // Visit linked polygons.
  136. for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = tile->links[i].next)
  137. {
  138. const dtPolyRef neiRef = tile->links[i].ref;
  139. // Skip invalid and already visited.
  140. if (!neiRef || flags->getFlags(neiRef))
  141. continue;
  142. // Mark as visited
  143. flags->setFlags(neiRef, flag);
  144. // Visit neighbours
  145. openList.push_back(neiRef);
  146. }
  147. }
  148. }
  149. static void disableUnvisitedPolys(dtNavMesh* nav, NavmeshFlags* flags)
  150. {
  151. for (int i = 0; i < nav->getMaxTiles(); ++i)
  152. {
  153. const dtMeshTile* tile = ((const dtNavMesh*)nav)->getTile(i);
  154. if (!tile->header) continue;
  155. const dtPolyRef base = nav->getPolyRefBase(tile);
  156. for (int j = 0; j < tile->header->polyCount; ++j)
  157. {
  158. const dtPolyRef ref = base | (unsigned int)j;
  159. if (!flags->getFlags(ref))
  160. {
  161. unsigned short f = 0;
  162. nav->getPolyFlags(ref, &f);
  163. nav->setPolyFlags(ref, f | SAMPLE_POLYFLAGS_DISABLED);
  164. }
  165. }
  166. }
  167. }
  168. NavMeshPruneTool::NavMeshPruneTool() :
  169. m_sample(0),
  170. m_flags(0),
  171. m_hitPosSet(false)
  172. {
  173. }
  174. NavMeshPruneTool::~NavMeshPruneTool()
  175. {
  176. delete m_flags;
  177. }
  178. void NavMeshPruneTool::init(Sample* sample)
  179. {
  180. m_sample = sample;
  181. }
  182. void NavMeshPruneTool::reset()
  183. {
  184. m_hitPosSet = false;
  185. delete m_flags;
  186. m_flags = 0;
  187. }
  188. void NavMeshPruneTool::handleMenu()
  189. {
  190. dtNavMesh* nav = m_sample->getNavMesh();
  191. if (!nav) return;
  192. if (!m_flags) return;
  193. if (imguiButton("Clear Selection"))
  194. {
  195. m_flags->clearAllFlags();
  196. }
  197. if (imguiButton("Prune Unselected"))
  198. {
  199. disableUnvisitedPolys(nav, m_flags);
  200. delete m_flags;
  201. m_flags = 0;
  202. }
  203. }
  204. void NavMeshPruneTool::handleClick(const float* s, const float* p, bool shift)
  205. {
  206. rcIgnoreUnused(s);
  207. rcIgnoreUnused(shift);
  208. if (!m_sample) return;
  209. InputGeom* geom = m_sample->getInputGeom();
  210. if (!geom) return;
  211. dtNavMesh* nav = m_sample->getNavMesh();
  212. if (!nav) return;
  213. dtNavMeshQuery* query = m_sample->getNavMeshQuery();
  214. if (!query) return;
  215. dtVcopy(m_hitPos, p);
  216. m_hitPosSet = true;
  217. if (!m_flags)
  218. {
  219. m_flags = new NavmeshFlags;
  220. m_flags->init(nav);
  221. }
  222. const float halfExtents[3] = { 2, 4, 2 };
  223. dtQueryFilter filter;
  224. dtPolyRef ref = 0;
  225. query->findNearestPoly(p, halfExtents, &filter, &ref, 0);
  226. floodNavmesh(nav, m_flags, ref, 1);
  227. }
  228. void NavMeshPruneTool::handleToggle()
  229. {
  230. }
  231. void NavMeshPruneTool::handleStep()
  232. {
  233. }
  234. void NavMeshPruneTool::handleUpdate(const float /*dt*/)
  235. {
  236. }
  237. void NavMeshPruneTool::handleRender()
  238. {
  239. duDebugDraw& dd = m_sample->getDebugDraw();
  240. if (m_hitPosSet)
  241. {
  242. const float s = m_sample->getAgentRadius();
  243. const unsigned int col = duRGBA(255,255,255,255);
  244. dd.begin(DU_DRAW_LINES);
  245. dd.vertex(m_hitPos[0]-s,m_hitPos[1],m_hitPos[2], col);
  246. dd.vertex(m_hitPos[0]+s,m_hitPos[1],m_hitPos[2], col);
  247. dd.vertex(m_hitPos[0],m_hitPos[1]-s,m_hitPos[2], col);
  248. dd.vertex(m_hitPos[0],m_hitPos[1]+s,m_hitPos[2], col);
  249. dd.vertex(m_hitPos[0],m_hitPos[1],m_hitPos[2]-s, col);
  250. dd.vertex(m_hitPos[0],m_hitPos[1],m_hitPos[2]+s, col);
  251. dd.end();
  252. }
  253. const dtNavMesh* nav = m_sample->getNavMesh();
  254. if (m_flags && nav)
  255. {
  256. for (int i = 0; i < nav->getMaxTiles(); ++i)
  257. {
  258. const dtMeshTile* tile = nav->getTile(i);
  259. if (!tile->header) continue;
  260. const dtPolyRef base = nav->getPolyRefBase(tile);
  261. for (int j = 0; j < tile->header->polyCount; ++j)
  262. {
  263. const dtPolyRef ref = base | (unsigned int)j;
  264. if (m_flags->getFlags(ref))
  265. {
  266. duDebugDrawNavMeshPoly(&dd, *nav, ref, duRGBA(255,255,255,128));
  267. }
  268. }
  269. }
  270. }
  271. }
  272. void NavMeshPruneTool::handleRenderOverlay(double* proj, double* model, int* view)
  273. {
  274. rcIgnoreUnused(model);
  275. rcIgnoreUnused(proj);
  276. // Tool help
  277. const int h = view[3];
  278. imguiDrawText(280, h-40, IMGUI_ALIGN_LEFT, "LMB: Click fill area.", imguiRGBA(255,255,255,192));
  279. }