Sample.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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 "Sample.h"
  22. #include "InputGeom.h"
  23. #include "Recast.h"
  24. #include "RecastDebugDraw.h"
  25. #include "DetourDebugDraw.h"
  26. #include "DetourNavMesh.h"
  27. #include "DetourNavMeshQuery.h"
  28. #include "DetourCrowd.h"
  29. #include "imgui.h"
  30. #include "SDL.h"
  31. #include "SDL_opengl.h"
  32. #ifdef WIN32
  33. # define snprintf _snprintf
  34. #endif
  35. unsigned int SampleDebugDraw::areaToCol(unsigned int area)
  36. {
  37. switch(area)
  38. {
  39. // Ground (0) : light blue
  40. case SAMPLE_POLYAREA_GROUND: return duRGBA(0, 192, 255, 255);
  41. // Water : blue
  42. case SAMPLE_POLYAREA_WATER: return duRGBA(0, 0, 255, 255);
  43. // Road : brown
  44. case SAMPLE_POLYAREA_ROAD: return duRGBA(50, 20, 12, 255);
  45. // Door : cyan
  46. case SAMPLE_POLYAREA_DOOR: return duRGBA(0, 255, 255, 255);
  47. // Grass : green
  48. case SAMPLE_POLYAREA_GRASS: return duRGBA(0, 255, 0, 255);
  49. // Jump : yellow
  50. case SAMPLE_POLYAREA_JUMP: return duRGBA(255, 255, 0, 255);
  51. // Unexpected : red
  52. default: return duRGBA(255, 0, 0, 255);
  53. }
  54. }
  55. Sample::Sample() :
  56. m_geom(0),
  57. m_navMesh(0),
  58. m_navQuery(0),
  59. m_crowd(0),
  60. m_navMeshDrawFlags(DU_DRAWNAVMESH_OFFMESHCONS|DU_DRAWNAVMESH_CLOSEDLIST),
  61. m_filterLowHangingObstacles(true),
  62. m_filterLedgeSpans(true),
  63. m_filterWalkableLowHeightSpans(true),
  64. m_tool(0),
  65. m_ctx(0)
  66. {
  67. resetCommonSettings();
  68. m_navQuery = dtAllocNavMeshQuery();
  69. m_crowd = dtAllocCrowd();
  70. for (int i = 0; i < MAX_TOOLS; i++)
  71. m_toolStates[i] = 0;
  72. }
  73. Sample::~Sample()
  74. {
  75. dtFreeNavMeshQuery(m_navQuery);
  76. dtFreeNavMesh(m_navMesh);
  77. dtFreeCrowd(m_crowd);
  78. delete m_tool;
  79. for (int i = 0; i < MAX_TOOLS; i++)
  80. delete m_toolStates[i];
  81. }
  82. void Sample::setTool(SampleTool* tool)
  83. {
  84. delete m_tool;
  85. m_tool = tool;
  86. if (tool)
  87. m_tool->init(this);
  88. }
  89. void Sample::handleSettings()
  90. {
  91. }
  92. void Sample::handleTools()
  93. {
  94. }
  95. void Sample::handleDebugMode()
  96. {
  97. }
  98. void Sample::handleRender()
  99. {
  100. if (!m_geom)
  101. return;
  102. // Draw mesh
  103. duDebugDrawTriMesh(&m_dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(),
  104. m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), 0, 1.0f);
  105. // Draw bounds
  106. const float* bmin = m_geom->getMeshBoundsMin();
  107. const float* bmax = m_geom->getMeshBoundsMax();
  108. duDebugDrawBoxWire(&m_dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duRGBA(255,255,255,128), 1.0f);
  109. }
  110. void Sample::handleRenderOverlay(double* /*proj*/, double* /*model*/, int* /*view*/)
  111. {
  112. }
  113. void Sample::handleMeshChanged(InputGeom* geom)
  114. {
  115. m_geom = geom;
  116. const BuildSettings* buildSettings = geom->getBuildSettings();
  117. if (buildSettings)
  118. {
  119. m_cellSize = buildSettings->cellSize;
  120. m_cellHeight = buildSettings->cellHeight;
  121. m_agentHeight = buildSettings->agentHeight;
  122. m_agentRadius = buildSettings->agentRadius;
  123. m_agentMaxClimb = buildSettings->agentMaxClimb;
  124. m_agentMaxSlope = buildSettings->agentMaxSlope;
  125. m_regionMinSize = buildSettings->regionMinSize;
  126. m_regionMergeSize = buildSettings->regionMergeSize;
  127. m_edgeMaxLen = buildSettings->edgeMaxLen;
  128. m_edgeMaxError = buildSettings->edgeMaxError;
  129. m_vertsPerPoly = buildSettings->vertsPerPoly;
  130. m_detailSampleDist = buildSettings->detailSampleDist;
  131. m_detailSampleMaxError = buildSettings->detailSampleMaxError;
  132. m_partitionType = buildSettings->partitionType;
  133. }
  134. }
  135. void Sample::collectSettings(BuildSettings& settings)
  136. {
  137. settings.cellSize = m_cellSize;
  138. settings.cellHeight = m_cellHeight;
  139. settings.agentHeight = m_agentHeight;
  140. settings.agentRadius = m_agentRadius;
  141. settings.agentMaxClimb = m_agentMaxClimb;
  142. settings.agentMaxSlope = m_agentMaxSlope;
  143. settings.regionMinSize = m_regionMinSize;
  144. settings.regionMergeSize = m_regionMergeSize;
  145. settings.edgeMaxLen = m_edgeMaxLen;
  146. settings.edgeMaxError = m_edgeMaxError;
  147. settings.vertsPerPoly = m_vertsPerPoly;
  148. settings.detailSampleDist = m_detailSampleDist;
  149. settings.detailSampleMaxError = m_detailSampleMaxError;
  150. settings.partitionType = m_partitionType;
  151. }
  152. void Sample::resetCommonSettings()
  153. {
  154. m_cellSize = 0.3f;
  155. m_cellHeight = 0.2f;
  156. m_agentHeight = 2.0f;
  157. m_agentRadius = 0.6f;
  158. m_agentMaxClimb = 0.9f;
  159. m_agentMaxSlope = 45.0f;
  160. m_regionMinSize = 8;
  161. m_regionMergeSize = 20;
  162. m_edgeMaxLen = 12.0f;
  163. m_edgeMaxError = 1.3f;
  164. m_vertsPerPoly = 6.0f;
  165. m_detailSampleDist = 6.0f;
  166. m_detailSampleMaxError = 1.0f;
  167. m_partitionType = SAMPLE_PARTITION_WATERSHED;
  168. }
  169. void Sample::handleCommonSettings()
  170. {
  171. imguiLabel("Rasterization");
  172. imguiSlider("Cell Size", &m_cellSize, 0.1f, 1.0f, 0.01f);
  173. imguiSlider("Cell Height", &m_cellHeight, 0.1f, 1.0f, 0.01f);
  174. if (m_geom)
  175. {
  176. const float* bmin = m_geom->getNavMeshBoundsMin();
  177. const float* bmax = m_geom->getNavMeshBoundsMax();
  178. int gw = 0, gh = 0;
  179. rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
  180. char text[64];
  181. snprintf(text, 64, "Voxels %d x %d", gw, gh);
  182. imguiValue(text);
  183. }
  184. imguiSeparator();
  185. imguiLabel("Agent");
  186. imguiSlider("Height", &m_agentHeight, 0.1f, 5.0f, 0.1f);
  187. imguiSlider("Radius", &m_agentRadius, 0.0f, 5.0f, 0.1f);
  188. imguiSlider("Max Climb", &m_agentMaxClimb, 0.1f, 5.0f, 0.1f);
  189. imguiSlider("Max Slope", &m_agentMaxSlope, 0.0f, 90.0f, 1.0f);
  190. imguiSeparator();
  191. imguiLabel("Region");
  192. imguiSlider("Min Region Size", &m_regionMinSize, 0.0f, 150.0f, 1.0f);
  193. imguiSlider("Merged Region Size", &m_regionMergeSize, 0.0f, 150.0f, 1.0f);
  194. imguiSeparator();
  195. imguiLabel("Partitioning");
  196. if (imguiCheck("Watershed", m_partitionType == SAMPLE_PARTITION_WATERSHED))
  197. m_partitionType = SAMPLE_PARTITION_WATERSHED;
  198. if (imguiCheck("Monotone", m_partitionType == SAMPLE_PARTITION_MONOTONE))
  199. m_partitionType = SAMPLE_PARTITION_MONOTONE;
  200. if (imguiCheck("Layers", m_partitionType == SAMPLE_PARTITION_LAYERS))
  201. m_partitionType = SAMPLE_PARTITION_LAYERS;
  202. imguiSeparator();
  203. imguiLabel("Filtering");
  204. if (imguiCheck("Low Hanging Obstacles", m_filterLowHangingObstacles))
  205. m_filterLowHangingObstacles = !m_filterLowHangingObstacles;
  206. if (imguiCheck("Ledge Spans", m_filterLedgeSpans))
  207. m_filterLedgeSpans= !m_filterLedgeSpans;
  208. if (imguiCheck("Walkable Low Height Spans", m_filterWalkableLowHeightSpans))
  209. m_filterWalkableLowHeightSpans = !m_filterWalkableLowHeightSpans;
  210. imguiSeparator();
  211. imguiLabel("Polygonization");
  212. imguiSlider("Max Edge Length", &m_edgeMaxLen, 0.0f, 50.0f, 1.0f);
  213. imguiSlider("Max Edge Error", &m_edgeMaxError, 0.1f, 3.0f, 0.1f);
  214. imguiSlider("Verts Per Poly", &m_vertsPerPoly, 3.0f, 12.0f, 1.0f);
  215. imguiSeparator();
  216. imguiLabel("Detail Mesh");
  217. imguiSlider("Sample Distance", &m_detailSampleDist, 0.0f, 16.0f, 1.0f);
  218. imguiSlider("Max Sample Error", &m_detailSampleMaxError, 0.0f, 16.0f, 1.0f);
  219. imguiSeparator();
  220. }
  221. void Sample::handleClick(const float* s, const float* p, bool shift)
  222. {
  223. if (m_tool)
  224. m_tool->handleClick(s, p, shift);
  225. }
  226. void Sample::handleToggle()
  227. {
  228. if (m_tool)
  229. m_tool->handleToggle();
  230. }
  231. void Sample::handleStep()
  232. {
  233. if (m_tool)
  234. m_tool->handleStep();
  235. }
  236. bool Sample::handleBuild()
  237. {
  238. return true;
  239. }
  240. void Sample::handleUpdate(const float dt)
  241. {
  242. if (m_tool)
  243. m_tool->handleUpdate(dt);
  244. updateToolStates(dt);
  245. }
  246. void Sample::updateToolStates(const float dt)
  247. {
  248. for (int i = 0; i < MAX_TOOLS; i++)
  249. {
  250. if (m_toolStates[i])
  251. m_toolStates[i]->handleUpdate(dt);
  252. }
  253. }
  254. void Sample::initToolStates(Sample* sample)
  255. {
  256. for (int i = 0; i < MAX_TOOLS; i++)
  257. {
  258. if (m_toolStates[i])
  259. m_toolStates[i]->init(sample);
  260. }
  261. }
  262. void Sample::resetToolStates()
  263. {
  264. for (int i = 0; i < MAX_TOOLS; i++)
  265. {
  266. if (m_toolStates[i])
  267. m_toolStates[i]->reset();
  268. }
  269. }
  270. void Sample::renderToolStates()
  271. {
  272. for (int i = 0; i < MAX_TOOLS; i++)
  273. {
  274. if (m_toolStates[i])
  275. m_toolStates[i]->handleRender();
  276. }
  277. }
  278. void Sample::renderOverlayToolStates(double* proj, double* model, int* view)
  279. {
  280. for (int i = 0; i < MAX_TOOLS; i++)
  281. {
  282. if (m_toolStates[i])
  283. m_toolStates[i]->handleRenderOverlay(proj, model, view);
  284. }
  285. }
  286. static const int NAVMESHSET_MAGIC = 'M'<<24 | 'S'<<16 | 'E'<<8 | 'T'; //'MSET';
  287. static const int NAVMESHSET_VERSION = 1;
  288. struct NavMeshSetHeader
  289. {
  290. int magic;
  291. int version;
  292. int numTiles;
  293. dtNavMeshParams params;
  294. };
  295. struct NavMeshTileHeader
  296. {
  297. dtTileRef tileRef;
  298. int dataSize;
  299. };
  300. dtNavMesh* Sample::loadAll(const char* path)
  301. {
  302. FILE* fp = fopen(path, "rb");
  303. if (!fp) return 0;
  304. // Read header.
  305. NavMeshSetHeader header;
  306. size_t readLen = fread(&header, sizeof(NavMeshSetHeader), 1, fp);
  307. if (readLen != 1)
  308. {
  309. fclose(fp);
  310. return 0;
  311. }
  312. if (header.magic != NAVMESHSET_MAGIC)
  313. {
  314. fclose(fp);
  315. return 0;
  316. }
  317. if (header.version != NAVMESHSET_VERSION)
  318. {
  319. fclose(fp);
  320. return 0;
  321. }
  322. dtNavMesh* mesh = dtAllocNavMesh();
  323. if (!mesh)
  324. {
  325. fclose(fp);
  326. return 0;
  327. }
  328. dtStatus status = mesh->init(&header.params);
  329. if (dtStatusFailed(status))
  330. {
  331. fclose(fp);
  332. return 0;
  333. }
  334. // Read tiles.
  335. for (int i = 0; i < header.numTiles; ++i)
  336. {
  337. NavMeshTileHeader tileHeader;
  338. readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp);
  339. if (readLen != 1)
  340. {
  341. fclose(fp);
  342. return 0;
  343. }
  344. if (!tileHeader.tileRef || !tileHeader.dataSize)
  345. break;
  346. unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
  347. if (!data) break;
  348. memset(data, 0, tileHeader.dataSize);
  349. readLen = fread(data, tileHeader.dataSize, 1, fp);
  350. if (readLen != 1)
  351. {
  352. dtFree(data);
  353. fclose(fp);
  354. return 0;
  355. }
  356. mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);
  357. }
  358. fclose(fp);
  359. return mesh;
  360. }
  361. void Sample::saveAll(const char* path, const dtNavMesh* mesh)
  362. {
  363. if (!mesh) return;
  364. FILE* fp = fopen(path, "wb");
  365. if (!fp)
  366. return;
  367. // Store header.
  368. NavMeshSetHeader header;
  369. header.magic = NAVMESHSET_MAGIC;
  370. header.version = NAVMESHSET_VERSION;
  371. header.numTiles = 0;
  372. for (int i = 0; i < mesh->getMaxTiles(); ++i)
  373. {
  374. const dtMeshTile* tile = mesh->getTile(i);
  375. if (!tile || !tile->header || !tile->dataSize) continue;
  376. header.numTiles++;
  377. }
  378. memcpy(&header.params, mesh->getParams(), sizeof(dtNavMeshParams));
  379. fwrite(&header, sizeof(NavMeshSetHeader), 1, fp);
  380. // Store tiles.
  381. for (int i = 0; i < mesh->getMaxTiles(); ++i)
  382. {
  383. const dtMeshTile* tile = mesh->getTile(i);
  384. if (!tile || !tile->header || !tile->dataSize) continue;
  385. NavMeshTileHeader tileHeader;
  386. tileHeader.tileRef = mesh->getTileRef(tile);
  387. tileHeader.dataSize = tile->dataSize;
  388. fwrite(&tileHeader, sizeof(tileHeader), 1, fp);
  389. fwrite(tile->data, tile->dataSize, 1, fp);
  390. }
  391. fclose(fp);
  392. }