RecastDump.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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 <stdarg.h>
  22. #include <string.h>
  23. #include "Recast.h"
  24. #include "RecastAlloc.h"
  25. #include "RecastDump.h"
  26. duFileIO::~duFileIO()
  27. {
  28. // Empty
  29. }
  30. static void ioprintf(duFileIO* io, const char* format, ...)
  31. {
  32. char line[256];
  33. va_list ap;
  34. va_start(ap, format);
  35. const int n = vsnprintf(line, sizeof(line), format, ap);
  36. va_end(ap);
  37. if (n > 0)
  38. io->write(line, sizeof(char)*n);
  39. }
  40. bool duDumpPolyMeshToObj(rcPolyMesh& pmesh, duFileIO* io)
  41. {
  42. if (!io)
  43. {
  44. printf("duDumpPolyMeshToObj: input IO is null.\n");
  45. return false;
  46. }
  47. if (!io->isWriting())
  48. {
  49. printf("duDumpPolyMeshToObj: input IO not writing.\n");
  50. return false;
  51. }
  52. const int nvp = pmesh.nvp;
  53. const float cs = pmesh.cs;
  54. const float ch = pmesh.ch;
  55. const float* orig = pmesh.bmin;
  56. ioprintf(io, "# Recast Navmesh\n");
  57. ioprintf(io, "o NavMesh\n");
  58. ioprintf(io, "\n");
  59. for (int i = 0; i < pmesh.nverts; ++i)
  60. {
  61. const unsigned short* v = &pmesh.verts[i*3];
  62. const float x = orig[0] + v[0]*cs;
  63. const float y = orig[1] + (v[1]+1)*ch + 0.1f;
  64. const float z = orig[2] + v[2]*cs;
  65. ioprintf(io, "v %f %f %f\n", x,y,z);
  66. }
  67. ioprintf(io, "\n");
  68. for (int i = 0; i < pmesh.npolys; ++i)
  69. {
  70. const unsigned short* p = &pmesh.polys[i*nvp*2];
  71. for (int j = 2; j < nvp; ++j)
  72. {
  73. if (p[j] == RC_MESH_NULL_IDX) break;
  74. ioprintf(io, "f %d %d %d\n", p[0]+1, p[j-1]+1, p[j]+1);
  75. }
  76. }
  77. return true;
  78. }
  79. bool duDumpPolyMeshDetailToObj(rcPolyMeshDetail& dmesh, duFileIO* io)
  80. {
  81. if (!io)
  82. {
  83. printf("duDumpPolyMeshDetailToObj: input IO is null.\n");
  84. return false;
  85. }
  86. if (!io->isWriting())
  87. {
  88. printf("duDumpPolyMeshDetailToObj: input IO not writing.\n");
  89. return false;
  90. }
  91. ioprintf(io, "# Recast Navmesh\n");
  92. ioprintf(io, "o NavMesh\n");
  93. ioprintf(io, "\n");
  94. for (int i = 0; i < dmesh.nverts; ++i)
  95. {
  96. const float* v = &dmesh.verts[i*3];
  97. ioprintf(io, "v %f %f %f\n", v[0],v[1],v[2]);
  98. }
  99. ioprintf(io, "\n");
  100. for (int i = 0; i < dmesh.nmeshes; ++i)
  101. {
  102. const unsigned int* m = &dmesh.meshes[i*4];
  103. const unsigned int bverts = m[0];
  104. const unsigned int btris = m[2];
  105. const unsigned int ntris = m[3];
  106. const unsigned char* tris = &dmesh.tris[btris*4];
  107. for (unsigned int j = 0; j < ntris; ++j)
  108. {
  109. ioprintf(io, "f %d %d %d\n",
  110. (int)(bverts+tris[j*4+0])+1,
  111. (int)(bverts+tris[j*4+1])+1,
  112. (int)(bverts+tris[j*4+2])+1);
  113. }
  114. }
  115. return true;
  116. }
  117. static const int CSET_MAGIC = ('c' << 24) | ('s' << 16) | ('e' << 8) | 't';
  118. static const int CSET_VERSION = 2;
  119. bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
  120. {
  121. if (!io)
  122. {
  123. printf("duDumpContourSet: input IO is null.\n");
  124. return false;
  125. }
  126. if (!io->isWriting())
  127. {
  128. printf("duDumpContourSet: input IO not writing.\n");
  129. return false;
  130. }
  131. io->write(&CSET_MAGIC, sizeof(CSET_MAGIC));
  132. io->write(&CSET_VERSION, sizeof(CSET_VERSION));
  133. io->write(&cset.nconts, sizeof(cset.nconts));
  134. io->write(cset.bmin, sizeof(cset.bmin));
  135. io->write(cset.bmax, sizeof(cset.bmax));
  136. io->write(&cset.cs, sizeof(cset.cs));
  137. io->write(&cset.ch, sizeof(cset.ch));
  138. io->write(&cset.width, sizeof(cset.width));
  139. io->write(&cset.height, sizeof(cset.height));
  140. io->write(&cset.borderSize, sizeof(cset.borderSize));
  141. for (int i = 0; i < cset.nconts; ++i)
  142. {
  143. const rcContour& cont = cset.conts[i];
  144. io->write(&cont.nverts, sizeof(cont.nverts));
  145. io->write(&cont.nrverts, sizeof(cont.nrverts));
  146. io->write(&cont.reg, sizeof(cont.reg));
  147. io->write(&cont.area, sizeof(cont.area));
  148. io->write(cont.verts, sizeof(int)*4*cont.nverts);
  149. io->write(cont.rverts, sizeof(int)*4*cont.nrverts);
  150. }
  151. return true;
  152. }
  153. bool duReadContourSet(struct rcContourSet& cset, duFileIO* io)
  154. {
  155. if (!io)
  156. {
  157. printf("duReadContourSet: input IO is null.\n");
  158. return false;
  159. }
  160. if (!io->isReading())
  161. {
  162. printf("duReadContourSet: input IO not reading.\n");
  163. return false;
  164. }
  165. int magic = 0;
  166. int version = 0;
  167. io->read(&magic, sizeof(magic));
  168. io->read(&version, sizeof(version));
  169. if (magic != CSET_MAGIC)
  170. {
  171. printf("duReadContourSet: Bad voodoo.\n");
  172. return false;
  173. }
  174. if (version != CSET_VERSION)
  175. {
  176. printf("duReadContourSet: Bad version.\n");
  177. return false;
  178. }
  179. io->read(&cset.nconts, sizeof(cset.nconts));
  180. cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*cset.nconts, RC_ALLOC_PERM);
  181. if (!cset.conts)
  182. {
  183. printf("duReadContourSet: Could not alloc contours (%d)\n", cset.nconts);
  184. return false;
  185. }
  186. memset(cset.conts, 0, sizeof(rcContour)*cset.nconts);
  187. io->read(cset.bmin, sizeof(cset.bmin));
  188. io->read(cset.bmax, sizeof(cset.bmax));
  189. io->read(&cset.cs, sizeof(cset.cs));
  190. io->read(&cset.ch, sizeof(cset.ch));
  191. io->read(&cset.width, sizeof(cset.width));
  192. io->read(&cset.height, sizeof(cset.height));
  193. io->read(&cset.borderSize, sizeof(cset.borderSize));
  194. for (int i = 0; i < cset.nconts; ++i)
  195. {
  196. rcContour& cont = cset.conts[i];
  197. io->read(&cont.nverts, sizeof(cont.nverts));
  198. io->read(&cont.nrverts, sizeof(cont.nrverts));
  199. io->read(&cont.reg, sizeof(cont.reg));
  200. io->read(&cont.area, sizeof(cont.area));
  201. cont.verts = (int*)rcAlloc(sizeof(int)*4*cont.nverts, RC_ALLOC_PERM);
  202. if (!cont.verts)
  203. {
  204. printf("duReadContourSet: Could not alloc contour verts (%d)\n", cont.nverts);
  205. return false;
  206. }
  207. cont.rverts = (int*)rcAlloc(sizeof(int)*4*cont.nrverts, RC_ALLOC_PERM);
  208. if (!cont.rverts)
  209. {
  210. printf("duReadContourSet: Could not alloc contour rverts (%d)\n", cont.nrverts);
  211. return false;
  212. }
  213. io->read(cont.verts, sizeof(int)*4*cont.nverts);
  214. io->read(cont.rverts, sizeof(int)*4*cont.nrverts);
  215. }
  216. return true;
  217. }
  218. static const int CHF_MAGIC = ('r' << 24) | ('c' << 16) | ('h' << 8) | 'f';
  219. static const int CHF_VERSION = 3;
  220. bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
  221. {
  222. if (!io)
  223. {
  224. printf("duDumpCompactHeightfield: input IO is null.\n");
  225. return false;
  226. }
  227. if (!io->isWriting())
  228. {
  229. printf("duDumpCompactHeightfield: input IO not writing.\n");
  230. return false;
  231. }
  232. io->write(&CHF_MAGIC, sizeof(CHF_MAGIC));
  233. io->write(&CHF_VERSION, sizeof(CHF_VERSION));
  234. io->write(&chf.width, sizeof(chf.width));
  235. io->write(&chf.height, sizeof(chf.height));
  236. io->write(&chf.spanCount, sizeof(chf.spanCount));
  237. io->write(&chf.walkableHeight, sizeof(chf.walkableHeight));
  238. io->write(&chf.walkableClimb, sizeof(chf.walkableClimb));
  239. io->write(&chf.borderSize, sizeof(chf.borderSize));
  240. io->write(&chf.maxDistance, sizeof(chf.maxDistance));
  241. io->write(&chf.maxRegions, sizeof(chf.maxRegions));
  242. io->write(chf.bmin, sizeof(chf.bmin));
  243. io->write(chf.bmax, sizeof(chf.bmax));
  244. io->write(&chf.cs, sizeof(chf.cs));
  245. io->write(&chf.ch, sizeof(chf.ch));
  246. int tmp = 0;
  247. if (chf.cells) tmp |= 1;
  248. if (chf.spans) tmp |= 2;
  249. if (chf.dist) tmp |= 4;
  250. if (chf.areas) tmp |= 8;
  251. io->write(&tmp, sizeof(tmp));
  252. if (chf.cells)
  253. io->write(chf.cells, sizeof(rcCompactCell)*chf.width*chf.height);
  254. if (chf.spans)
  255. io->write(chf.spans, sizeof(rcCompactSpan)*chf.spanCount);
  256. if (chf.dist)
  257. io->write(chf.dist, sizeof(unsigned short)*chf.spanCount);
  258. if (chf.areas)
  259. io->write(chf.areas, sizeof(unsigned char)*chf.spanCount);
  260. return true;
  261. }
  262. bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
  263. {
  264. if (!io)
  265. {
  266. printf("duReadCompactHeightfield: input IO is null.\n");
  267. return false;
  268. }
  269. if (!io->isReading())
  270. {
  271. printf("duReadCompactHeightfield: input IO not reading.\n");
  272. return false;
  273. }
  274. int magic = 0;
  275. int version = 0;
  276. io->read(&magic, sizeof(magic));
  277. io->read(&version, sizeof(version));
  278. if (magic != CHF_MAGIC)
  279. {
  280. printf("duReadCompactHeightfield: Bad voodoo.\n");
  281. return false;
  282. }
  283. if (version != CHF_VERSION)
  284. {
  285. printf("duReadCompactHeightfield: Bad version.\n");
  286. return false;
  287. }
  288. io->read(&chf.width, sizeof(chf.width));
  289. io->read(&chf.height, sizeof(chf.height));
  290. io->read(&chf.spanCount, sizeof(chf.spanCount));
  291. io->read(&chf.walkableHeight, sizeof(chf.walkableHeight));
  292. io->read(&chf.walkableClimb, sizeof(chf.walkableClimb));
  293. io->read(&chf.borderSize, sizeof(chf.borderSize));
  294. io->read(&chf.maxDistance, sizeof(chf.maxDistance));
  295. io->read(&chf.maxRegions, sizeof(chf.maxRegions));
  296. io->read(chf.bmin, sizeof(chf.bmin));
  297. io->read(chf.bmax, sizeof(chf.bmax));
  298. io->read(&chf.cs, sizeof(chf.cs));
  299. io->read(&chf.ch, sizeof(chf.ch));
  300. int tmp = 0;
  301. io->read(&tmp, sizeof(tmp));
  302. if (tmp & 1)
  303. {
  304. chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*chf.width*chf.height, RC_ALLOC_PERM);
  305. if (!chf.cells)
  306. {
  307. printf("duReadCompactHeightfield: Could not alloc cells (%d)\n", chf.width*chf.height);
  308. return false;
  309. }
  310. io->read(chf.cells, sizeof(rcCompactCell)*chf.width*chf.height);
  311. }
  312. if (tmp & 2)
  313. {
  314. chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*chf.spanCount, RC_ALLOC_PERM);
  315. if (!chf.spans)
  316. {
  317. printf("duReadCompactHeightfield: Could not alloc spans (%d)\n", chf.spanCount);
  318. return false;
  319. }
  320. io->read(chf.spans, sizeof(rcCompactSpan)*chf.spanCount);
  321. }
  322. if (tmp & 4)
  323. {
  324. chf.dist = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_PERM);
  325. if (!chf.dist)
  326. {
  327. printf("duReadCompactHeightfield: Could not alloc dist (%d)\n", chf.spanCount);
  328. return false;
  329. }
  330. io->read(chf.dist, sizeof(unsigned short)*chf.spanCount);
  331. }
  332. if (tmp & 8)
  333. {
  334. chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_PERM);
  335. if (!chf.areas)
  336. {
  337. printf("duReadCompactHeightfield: Could not alloc areas (%d)\n", chf.spanCount);
  338. return false;
  339. }
  340. io->read(chf.areas, sizeof(unsigned char)*chf.spanCount);
  341. }
  342. return true;
  343. }
  344. static void logLine(rcContext& ctx, rcTimerLabel label, const char* name, const float pc)
  345. {
  346. const int t = ctx.getAccumulatedTime(label);
  347. if (t < 0) return;
  348. ctx.log(RC_LOG_PROGRESS, "%s:\t%.2fms\t(%.1f%%)", name, t/1000.0f, t*pc);
  349. }
  350. void duLogBuildTimes(rcContext& ctx, const int totalTimeUsec)
  351. {
  352. const float pc = 100.0f / totalTimeUsec;
  353. ctx.log(RC_LOG_PROGRESS, "Build Times");
  354. logLine(ctx, RC_TIMER_RASTERIZE_TRIANGLES, "- Rasterize", pc);
  355. logLine(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD, "- Build Compact", pc);
  356. logLine(ctx, RC_TIMER_FILTER_BORDER, "- Filter Border", pc);
  357. logLine(ctx, RC_TIMER_FILTER_WALKABLE, "- Filter Walkable", pc);
  358. logLine(ctx, RC_TIMER_ERODE_AREA, "- Erode Area", pc);
  359. logLine(ctx, RC_TIMER_MEDIAN_AREA, "- Median Area", pc);
  360. logLine(ctx, RC_TIMER_MARK_BOX_AREA, "- Mark Box Area", pc);
  361. logLine(ctx, RC_TIMER_MARK_CONVEXPOLY_AREA, "- Mark Convex Area", pc);
  362. logLine(ctx, RC_TIMER_MARK_CYLINDER_AREA, "- Mark Cylinder Area", pc);
  363. logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD, "- Build Distance Field", pc);
  364. logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST, " - Distance", pc);
  365. logLine(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR, " - Blur", pc);
  366. logLine(ctx, RC_TIMER_BUILD_REGIONS, "- Build Regions", pc);
  367. logLine(ctx, RC_TIMER_BUILD_REGIONS_WATERSHED, " - Watershed", pc);
  368. logLine(ctx, RC_TIMER_BUILD_REGIONS_EXPAND, " - Expand", pc);
  369. logLine(ctx, RC_TIMER_BUILD_REGIONS_FLOOD, " - Find Basins", pc);
  370. logLine(ctx, RC_TIMER_BUILD_REGIONS_FILTER, " - Filter", pc);
  371. logLine(ctx, RC_TIMER_BUILD_LAYERS, "- Build Layers", pc);
  372. logLine(ctx, RC_TIMER_BUILD_CONTOURS, "- Build Contours", pc);
  373. logLine(ctx, RC_TIMER_BUILD_CONTOURS_TRACE, " - Trace", pc);
  374. logLine(ctx, RC_TIMER_BUILD_CONTOURS_SIMPLIFY, " - Simplify", pc);
  375. logLine(ctx, RC_TIMER_BUILD_POLYMESH, "- Build Polymesh", pc);
  376. logLine(ctx, RC_TIMER_BUILD_POLYMESHDETAIL, "- Build Polymesh Detail", pc);
  377. logLine(ctx, RC_TIMER_MERGE_POLYMESH, "- Merge Polymeshes", pc);
  378. logLine(ctx, RC_TIMER_MERGE_POLYMESHDETAIL, "- Merge Polymesh Details", pc);
  379. ctx.log(RC_LOG_PROGRESS, "=== TOTAL:\t%.2fms", totalTimeUsec/1000.0f);
  380. }