DetourStatNavMeshBuilder.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. //
  2. // Copyright (c) 2009 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. #include <math.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "DetourStatNavMesh.h"
  22. struct BVItem
  23. {
  24. unsigned short bmin[3];
  25. unsigned short bmax[3];
  26. int i;
  27. };
  28. static int compareItemX(const void* va, const void* vb)
  29. {
  30. const BVItem* a = (const BVItem*)va;
  31. const BVItem* b = (const BVItem*)vb;
  32. if (a->bmin[0] < b->bmin[0])
  33. return -1;
  34. if (a->bmin[0] > b->bmin[0])
  35. return 1;
  36. return 0;
  37. }
  38. static int compareItemY(const void* va, const void* vb)
  39. {
  40. const BVItem* a = (const BVItem*)va;
  41. const BVItem* b = (const BVItem*)vb;
  42. if (a->bmin[1] < b->bmin[1])
  43. return -1;
  44. if (a->bmin[1] > b->bmin[1])
  45. return 1;
  46. return 0;
  47. }
  48. static int compareItemZ(const void* va, const void* vb)
  49. {
  50. const BVItem* a = (const BVItem*)va;
  51. const BVItem* b = (const BVItem*)vb;
  52. if (a->bmin[2] < b->bmin[2])
  53. return -1;
  54. if (a->bmin[2] > b->bmin[2])
  55. return 1;
  56. return 0;
  57. }
  58. static void calcExtends(BVItem* items, int nitems, int imin, int imax,
  59. unsigned short* bmin, unsigned short* bmax)
  60. {
  61. bmin[0] = items[imin].bmin[0];
  62. bmin[1] = items[imin].bmin[1];
  63. bmin[2] = items[imin].bmin[2];
  64. bmax[0] = items[imin].bmax[0];
  65. bmax[1] = items[imin].bmax[1];
  66. bmax[2] = items[imin].bmax[2];
  67. for (int i = imin+1; i < imax; ++i)
  68. {
  69. const BVItem& it = items[i];
  70. if (it.bmin[0] < bmin[0]) bmin[0] = it.bmin[0];
  71. if (it.bmin[1] < bmin[1]) bmin[1] = it.bmin[1];
  72. if (it.bmin[2] < bmin[2]) bmin[2] = it.bmin[2];
  73. if (it.bmax[0] > bmax[0]) bmax[0] = it.bmax[0];
  74. if (it.bmax[1] > bmax[1]) bmax[1] = it.bmax[1];
  75. if (it.bmax[2] > bmax[2]) bmax[2] = it.bmax[2];
  76. }
  77. }
  78. inline int longestAxis(unsigned short x, unsigned short y, unsigned short z)
  79. {
  80. int axis = 0;
  81. unsigned short maxVal = x;
  82. if (y > maxVal)
  83. {
  84. axis = 1;
  85. maxVal = y;
  86. }
  87. if (z > maxVal)
  88. {
  89. axis = 2;
  90. maxVal = z;
  91. }
  92. return axis;
  93. }
  94. static void subdivide(BVItem* items, int nitems, int imin, int imax, int& curNode, dtStatBVNode* nodes)
  95. {
  96. int inum = imax - imin;
  97. int icur = curNode;
  98. dtStatBVNode& node = nodes[curNode++];
  99. if (inum == 1)
  100. {
  101. // Leaf
  102. node.bmin[0] = items[imin].bmin[0];
  103. node.bmin[1] = items[imin].bmin[1];
  104. node.bmin[2] = items[imin].bmin[2];
  105. node.bmax[0] = items[imin].bmax[0];
  106. node.bmax[1] = items[imin].bmax[1];
  107. node.bmax[2] = items[imin].bmax[2];
  108. node.i = items[imin].i;
  109. }
  110. else
  111. {
  112. // Split
  113. calcExtends(items, nitems, imin, imax, node.bmin, node.bmax);
  114. int axis = longestAxis(node.bmax[0] - node.bmin[0],
  115. node.bmax[1] - node.bmin[1],
  116. node.bmax[2] - node.bmin[2]);
  117. if (axis == 0)
  118. {
  119. // Sort along x-axis
  120. qsort(items+imin, inum, sizeof(BVItem), compareItemX);
  121. }
  122. else if (axis == 1)
  123. {
  124. // Sort along y-axis
  125. qsort(items+imin, inum, sizeof(BVItem), compareItemY);
  126. }
  127. else
  128. {
  129. // Sort along z-axis
  130. qsort(items+imin, inum, sizeof(BVItem), compareItemZ);
  131. }
  132. int isplit = imin+inum/2;
  133. // Left
  134. subdivide(items, nitems, imin, isplit, curNode, nodes);
  135. // Right
  136. subdivide(items, nitems, isplit, imax, curNode, nodes);
  137. int iescape = curNode - icur;
  138. // Negative index means escape.
  139. node.i = -iescape;
  140. }
  141. }
  142. /*static*/ int createBVTree(const unsigned short* verts, const int nverts,
  143. const unsigned short* polys, const int npolys, const int nvp,
  144. float cs, float ch,
  145. int nnodes, dtStatBVNode* nodes)
  146. {
  147. // Build tree
  148. BVItem* items = new BVItem[npolys];
  149. for (int i = 0; i < npolys; i++)
  150. {
  151. BVItem& it = items[i];
  152. it.i = i+1;
  153. // Calc polygon bounds.
  154. const unsigned short* p = &polys[i*nvp*2];
  155. it.bmin[0] = it.bmax[0] = verts[p[0]*3+0];
  156. it.bmin[1] = it.bmax[1] = verts[p[0]*3+1];
  157. it.bmin[2] = it.bmax[2] = verts[p[0]*3+2];
  158. for (int j = 1; j < nvp; ++j)
  159. {
  160. if (p[j] == 0xffff) break;
  161. unsigned short x = verts[p[j]*3+0];
  162. unsigned short y = verts[p[j]*3+1];
  163. unsigned short z = verts[p[j]*3+2];
  164. if (x < it.bmin[0]) it.bmin[0] = x;
  165. if (y < it.bmin[1]) it.bmin[1] = y;
  166. if (z < it.bmin[2]) it.bmin[2] = z;
  167. if (x > it.bmax[0]) it.bmax[0] = x;
  168. if (y > it.bmax[1]) it.bmax[1] = y;
  169. if (z > it.bmax[2]) it.bmax[2] = z;
  170. }
  171. // Remap y
  172. it.bmin[1] = (unsigned short)floorf((float)it.bmin[1]*ch/cs);
  173. it.bmax[1] = (unsigned short)ceilf((float)it.bmax[1]*ch/cs);
  174. }
  175. int curNode = 0;
  176. subdivide(items, npolys, 0, npolys, curNode, nodes);
  177. delete [] items;
  178. return curNode;
  179. }
  180. bool dtCreateNavMeshData(const unsigned short* verts, const int nverts,
  181. const unsigned short* polys, const int npolys, const int nvp,
  182. const float* bmin, const float* bmax, float cs, float ch,
  183. const unsigned short* dmeshes, const float* dverts, const int ndverts,
  184. const unsigned char* dtris, const int ndtris,
  185. unsigned char** outData, int* outDataSize)
  186. {
  187. if (nvp > DT_STAT_VERTS_PER_POLYGON)
  188. return false;
  189. if (nverts >= 0xffff)
  190. return false;
  191. if (!nverts)
  192. return false;
  193. if (!npolys)
  194. return false;
  195. if (!dmeshes || !dverts || ! dtris)
  196. return false;
  197. // Find unique detail vertices.
  198. int uniqueDetailVerts = 0;
  199. if (dmeshes)
  200. {
  201. for (int i = 0; i < npolys; ++i)
  202. {
  203. const unsigned short* p = &polys[i*nvp*2];
  204. int ndv = dmeshes[i*4+1];
  205. int nv = 0;
  206. for (int j = 0; j < nvp; ++j)
  207. {
  208. if (p[j] == 0xffff) break;
  209. nv++;
  210. }
  211. ndv -= nv;
  212. uniqueDetailVerts += ndv;
  213. }
  214. }
  215. // Calculate data size
  216. const int headerSize = sizeof(dtStatNavMeshHeader);
  217. const int vertsSize = sizeof(float)*3*nverts;
  218. const int polysSize = sizeof(dtStatPoly)*npolys;
  219. const int nodesSize = sizeof(dtStatBVNode)*npolys*2;
  220. const int detailMeshesSize = sizeof(dtStatPolyDetail)*npolys;
  221. const int detailVertsSize = sizeof(float)*3*uniqueDetailVerts;
  222. const int detailTrisSize = sizeof(unsigned char)*4*ndtris;
  223. const int dataSize = headerSize + vertsSize + polysSize + nodesSize +
  224. detailMeshesSize + detailVertsSize + detailTrisSize;
  225. unsigned char* data = new unsigned char[dataSize];
  226. if (!data)
  227. return false;
  228. memset(data, 0, dataSize);
  229. unsigned char* d = data;
  230. dtStatNavMeshHeader* header = (dtStatNavMeshHeader*)d; d += headerSize;
  231. float* navVerts = (float*)d; d += vertsSize;
  232. dtStatPoly* navPolys = (dtStatPoly*)d; d += polysSize;
  233. dtStatBVNode* navNodes = (dtStatBVNode*)d; d += nodesSize;
  234. dtStatPolyDetail* navDMeshes = (dtStatPolyDetail*)d; d += detailMeshesSize;
  235. float* navDVerts = (float*)d; d += detailVertsSize;
  236. unsigned char* navDTris = (unsigned char*)d; d += detailTrisSize;
  237. // Store header
  238. header->magic = DT_STAT_NAVMESH_MAGIC;
  239. header->version = DT_STAT_NAVMESH_VERSION;
  240. header->npolys = npolys;
  241. header->nverts = nverts;
  242. header->cs = cs;
  243. header->bmin[0] = bmin[0];
  244. header->bmin[1] = bmin[1];
  245. header->bmin[2] = bmin[2];
  246. header->bmax[0] = bmax[0];
  247. header->bmax[1] = bmax[1];
  248. header->bmax[2] = bmax[2];
  249. header->ndmeshes = dmeshes ? npolys : 0;
  250. header->ndverts = dmeshes ? uniqueDetailVerts : 0;
  251. header->ndtris = dmeshes ? ndtris : 0;
  252. // Store vertices
  253. for (int i = 0; i < nverts; ++i)
  254. {
  255. const unsigned short* iv = &verts[i*3];
  256. float* v = &navVerts[i*3];
  257. v[0] = bmin[0] + iv[0] * cs;
  258. v[1] = bmin[1] + iv[1] * ch;
  259. v[2] = bmin[2] + iv[2] * cs;
  260. }
  261. // Store polygons
  262. const unsigned short* src = polys;
  263. for (int i = 0; i < npolys; ++i)
  264. {
  265. dtStatPoly* p = &navPolys[i];
  266. p->nv = 0;
  267. for (int j = 0; j < nvp; ++j)
  268. {
  269. if (src[j] == 0xffff) break;
  270. p->v[j] = src[j];
  271. p->n[j] = src[nvp+j]+1;
  272. p->nv++;
  273. }
  274. src += nvp*2;
  275. }
  276. header->nnodes = createBVTree(verts, nverts, polys, npolys, nvp,
  277. cs, ch, npolys*2, navNodes);
  278. // Store detail meshes and vertices.
  279. // The nav polygon vertices are stored as the first vertices on each mesh.
  280. // We compress the mesh data by skipping them and using the navmesh coordinates.
  281. unsigned short vbase = 0;
  282. for (int i = 0; i < npolys; ++i)
  283. {
  284. dtStatPolyDetail& dtl = navDMeshes[i];
  285. const int vb = dmeshes[i*4+0];
  286. const int ndv = dmeshes[i*4+1];
  287. const int nv = navPolys[i].nv;
  288. dtl.vbase = vbase;
  289. dtl.nverts = ndv-nv;
  290. dtl.tbase = dmeshes[i*4+2];
  291. dtl.ntris = dmeshes[i*4+3];
  292. // Copy vertices except the first 'nv' verts which are equal to nav poly verts.
  293. if (ndv-nv)
  294. {
  295. memcpy(&navDVerts[vbase*3], &dverts[(vb+nv)*3], sizeof(float)*3*(ndv-nv));
  296. vbase += ndv-nv;
  297. }
  298. }
  299. // Store triangles.
  300. memcpy(navDTris, dtris, sizeof(unsigned char)*4*ndtris);
  301. *outData = data;
  302. *outDataSize = dataSize;
  303. return true;
  304. }