navmesh_conversion.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*
  2. * ***** BEGIN GPL LICENSE BLOCK *****
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software Foundation,
  16. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. *
  18. * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  19. * All rights reserved.
  20. *
  21. * The Original Code is: all of this file.
  22. *
  23. * Contributor(s): none yet.
  24. *
  25. * ***** END GPL LICENSE BLOCK *****
  26. */
  27. /** \file blender/blenkernel/intern/navmesh_conversion.c
  28. * \ingroup bke
  29. */
  30. #include <math.h>
  31. #include <stdlib.h>
  32. #include "MEM_guardedalloc.h"
  33. #include "DNA_meshdata_types.h"
  34. #include "BLI_utildefines.h"
  35. #include "BLI_math.h"
  36. #include "BLI_sort.h"
  37. #include "BKE_navmesh_conversion.h"
  38. #include "BKE_cdderivedmesh.h"
  39. #include "recast-capi.h"
  40. BLI_INLINE float area2(const float *a, const float *b, const float *c)
  41. {
  42. return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
  43. }
  44. BLI_INLINE int left(const float *a, const float *b, const float *c)
  45. {
  46. return area2(a, b, c) < 0;
  47. }
  48. int polyNumVerts(const unsigned short *p, const int vertsPerPoly)
  49. {
  50. int i, nv = 0;
  51. for (i = 0; i < vertsPerPoly; i++) {
  52. if (p[i] == 0xffff)
  53. break;
  54. nv++;
  55. }
  56. return nv;
  57. }
  58. int polyIsConvex(const unsigned short *p, const int vertsPerPoly, const float *verts)
  59. {
  60. int j, nv = polyNumVerts(p, vertsPerPoly);
  61. if (nv < 3)
  62. return 0;
  63. for (j = 0; j < nv; j++) {
  64. const float *v = &verts[3 * p[j]];
  65. const float *v_next = &verts[3 * p[(j + 1) % nv]];
  66. const float *v_prev = &verts[3 * p[(nv + j - 1) % nv]];
  67. if (!left(v_prev, v, v_next))
  68. return 0;
  69. }
  70. return 1;
  71. }
  72. /* XXX, could replace with #dist_to_line_segment_v3(), or add a squared version */
  73. float distPointToSegmentSq(const float point[3], const float a[3], const float b[3])
  74. {
  75. float abx[3], dx[3];
  76. float d, t;
  77. sub_v3_v3v3(abx, b, a);
  78. sub_v3_v3v3(dx, point, a);
  79. d = abx[0] * abx[0] + abx[2] * abx[2];
  80. t = abx[0] * dx[0] + abx[2] * dx[2];
  81. if (d > 0.0f)
  82. t /= d;
  83. if (t < 0.0f)
  84. t = 0.0f;
  85. else if (t > 1.0f)
  86. t = 1.0f;
  87. dx[0] = a[0] + t * abx[0] - point[0];
  88. dx[2] = a[2] + t * abx[2] - point[2];
  89. return dx[0] * dx[0] + dx[2] * dx[2];
  90. }
  91. int buildRawVertIndicesData(DerivedMesh *dm, int *nverts_r, float **verts_r,
  92. int *ntris_r, unsigned short **tris_r, int **trisToFacesMap_r,
  93. int **recastData)
  94. {
  95. int vi, fi, triIdx;
  96. int nverts, ntris;
  97. int *trisToFacesMap;
  98. float *verts;
  99. unsigned short *tris, *tri;
  100. int nfaces;
  101. MFace *faces;
  102. nverts = dm->getNumVerts(dm);
  103. if (nverts >= 0xffff) {
  104. printf("Converting navmesh: Error! Too many vertices. Max number of vertices %d\n", 0xffff);
  105. return 0;
  106. }
  107. if (nverts == 0) {
  108. printf("Converting navmesh: Error! There are no vertices!\n");
  109. return 0;
  110. }
  111. verts = MEM_mallocN(sizeof(float[3]) * nverts, "buildRawVertIndicesData verts");
  112. dm->getVertCos(dm, (float(*)[3])verts);
  113. /* flip coordinates */
  114. for (vi = 0; vi < nverts; vi++) {
  115. SWAP(float, verts[3 * vi + 1], verts[3 * vi + 2]);
  116. }
  117. /* calculate number of tris */
  118. dm->recalcTessellation(dm);
  119. nfaces = dm->getNumTessFaces(dm);
  120. if (nfaces == 0) {
  121. printf("Converting navmesh: Error! There are %i vertices, but no faces!\n", nverts);
  122. return 0;
  123. }
  124. faces = dm->getTessFaceArray(dm);
  125. ntris = nfaces;
  126. for (fi = 0; fi < nfaces; fi++) {
  127. MFace *face = &faces[fi];
  128. if (face->v4)
  129. ntris++;
  130. }
  131. /* copy and transform to triangles (reorder on the run) */
  132. trisToFacesMap = MEM_callocN(sizeof(int) * ntris, "buildRawVertIndicesData trisToFacesMap");
  133. tris = MEM_callocN(sizeof(unsigned short) * 3 * ntris, "buildRawVertIndicesData tris");
  134. tri = tris;
  135. triIdx = 0;
  136. for (fi = 0; fi < nfaces; fi++) {
  137. MFace *face = &faces[fi];
  138. tri[3 * triIdx + 0] = (unsigned short) face->v1;
  139. tri[3 * triIdx + 1] = (unsigned short) face->v3;
  140. tri[3 * triIdx + 2] = (unsigned short) face->v2;
  141. trisToFacesMap[triIdx++] = fi;
  142. if (face->v4) {
  143. tri[3 * triIdx + 0] = (unsigned short) face->v1;
  144. tri[3 * triIdx + 1] = (unsigned short) face->v4;
  145. tri[3 * triIdx + 2] = (unsigned short) face->v3;
  146. trisToFacesMap[triIdx++] = fi;
  147. }
  148. }
  149. /* carefully, recast data is just reference to data in derived mesh */
  150. *recastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
  151. *nverts_r = nverts;
  152. *verts_r = verts;
  153. *ntris_r = ntris;
  154. *tris_r = tris;
  155. *trisToFacesMap_r = trisToFacesMap;
  156. return 1;
  157. }
  158. int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys,
  159. unsigned short *polys, const unsigned short *dmeshes,
  160. const float *verts, const unsigned short *dtris,
  161. const int *dtrisToPolysMap)
  162. {
  163. int polyidx;
  164. int capacity = vertsPerPoly;
  165. unsigned short *newPoly = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPoly");
  166. memset(newPoly, 0xff, sizeof(unsigned short) * capacity);
  167. for (polyidx = 0; polyidx < npolys; polyidx++) {
  168. size_t i;
  169. int j, k;
  170. int nv = 0;
  171. /* search border */
  172. int tri, btri = -1;
  173. int edge, bedge = -1;
  174. int dtrisNum = dmeshes[polyidx * 4 + 3];
  175. int dtrisBase = dmeshes[polyidx * 4 + 2];
  176. unsigned char *traversedTris = MEM_callocN(sizeof(unsigned char) * dtrisNum, "buildPolygonsByDetailedMeshes traversedTris");
  177. unsigned short *adjustedPoly;
  178. int adjustedNv;
  179. int allBorderTraversed;
  180. for (j = 0; j < dtrisNum && btri == -1; j++) {
  181. int curpolytri = dtrisBase + j;
  182. for (k = 0; k < 3; k++) {
  183. unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k];
  184. if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
  185. btri = curpolytri;
  186. bedge = k;
  187. break;
  188. }
  189. }
  190. }
  191. if (btri == -1 || bedge == -1) {
  192. /* can't find triangle with border edge */
  193. MEM_freeN(traversedTris);
  194. MEM_freeN(newPoly);
  195. return 0;
  196. }
  197. newPoly[nv++] = dtris[btri * 3 * 2 + bedge];
  198. tri = btri;
  199. edge = (bedge + 1) % 3;
  200. traversedTris[tri - dtrisBase] = 1;
  201. while (tri != btri || edge != bedge) {
  202. int neighbortri = dtris[tri * 3 * 2 + 3 + edge];
  203. if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
  204. if (nv == capacity) {
  205. unsigned short *newPolyBig;
  206. capacity += vertsPerPoly;
  207. newPolyBig = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPolyBig");
  208. memset(newPolyBig, 0xff, sizeof(unsigned short) * capacity);
  209. memcpy(newPolyBig, newPoly, sizeof(unsigned short) * nv);
  210. MEM_freeN(newPoly);
  211. newPoly = newPolyBig;
  212. }
  213. newPoly[nv++] = dtris[tri * 3 * 2 + edge];
  214. /* move to next edge */
  215. edge = (edge + 1) % 3;
  216. }
  217. else {
  218. /* move to next tri */
  219. int twinedge = -1;
  220. for (k = 0; k < 3; k++) {
  221. if (dtris[neighbortri * 3 * 2 + 3 + k] == tri) {
  222. twinedge = k;
  223. break;
  224. }
  225. }
  226. if (twinedge == -1) {
  227. printf("Converting navmesh: Error! Can't find neighbor edge - invalid adjacency info\n");
  228. MEM_freeN(traversedTris);
  229. goto returnLabel;
  230. }
  231. tri = neighbortri;
  232. edge = (twinedge + 1) % 3;
  233. traversedTris[tri - dtrisBase] = 1;
  234. }
  235. }
  236. adjustedPoly = MEM_callocN(sizeof(unsigned short) * nv, "buildPolygonsByDetailedMeshes adjustedPoly");
  237. adjustedNv = 0;
  238. for (i = 0; i < nv; i++) {
  239. unsigned short prev = newPoly[(nv + i - 1) % nv];
  240. unsigned short cur = newPoly[i];
  241. unsigned short next = newPoly[(i + 1) % nv];
  242. float distSq = distPointToSegmentSq(&verts[3 * cur], &verts[3 * prev], &verts[3 * next]);
  243. static const float tolerance = 0.001f;
  244. if (distSq > tolerance)
  245. adjustedPoly[adjustedNv++] = cur;
  246. }
  247. memcpy(newPoly, adjustedPoly, adjustedNv * sizeof(unsigned short));
  248. MEM_freeN(adjustedPoly);
  249. nv = adjustedNv;
  250. allBorderTraversed = 1;
  251. for (i = 0; i < dtrisNum; i++) {
  252. if (traversedTris[i] == 0) {
  253. /* check whether it has border edges */
  254. int curpolytri = dtrisBase + i;
  255. for (k = 0; k < 3; k++) {
  256. unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k];
  257. if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
  258. allBorderTraversed = 0;
  259. break;
  260. }
  261. }
  262. }
  263. }
  264. if (nv <= vertsPerPoly && allBorderTraversed) {
  265. for (i = 0; i < nv; i++) {
  266. polys[polyidx * vertsPerPoly * 2 + i] = newPoly[i];
  267. }
  268. }
  269. MEM_freeN(traversedTris);
  270. }
  271. returnLabel:
  272. MEM_freeN(newPoly);
  273. return 1;
  274. }
  275. struct SortContext {
  276. const int *recastData;
  277. const int *trisToFacesMap;
  278. };
  279. static int compareByData(const void *a, const void *b, void *ctx)
  280. {
  281. return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)a]] -
  282. ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)b]]);
  283. }
  284. int buildNavMeshData(const int nverts, const float *verts,
  285. const int ntris, const unsigned short *tris,
  286. const int *recastData, const int *trisToFacesMap,
  287. int *ndtris_r, unsigned short **dtris_r,
  288. int *npolys_r, unsigned short **dmeshes_r, unsigned short **polys_r,
  289. int *vertsPerPoly_r, int **dtrisToPolysMap_r, int **dtrisToTrisMap_r)
  290. {
  291. int *trisMapping;
  292. int i;
  293. struct SortContext context;
  294. int validTriStart, prevPolyIdx, curPolyIdx, newPolyIdx, prevpolyidx;
  295. unsigned short *dmesh;
  296. int ndtris, npolys, vertsPerPoly;
  297. unsigned short *dtris, *dmeshes, *polys;
  298. int *dtrisToPolysMap, *dtrisToTrisMap;
  299. if (!recastData) {
  300. printf("Converting navmesh: Error! Can't find recast custom data\n");
  301. return 0;
  302. }
  303. trisMapping = MEM_callocN(sizeof(int) * ntris, "buildNavMeshData trisMapping");
  304. /* sort the triangles by polygon idx */
  305. for (i = 0; i < ntris; i++)
  306. trisMapping[i] = i;
  307. context.recastData = recastData;
  308. context.trisToFacesMap = trisToFacesMap;
  309. BLI_qsort_r(trisMapping, ntris, sizeof(int), compareByData, &context);
  310. /* search first valid triangle - triangle of convex polygon */
  311. validTriStart = -1;
  312. for (i = 0; i < ntris; i++) {
  313. if (recastData[trisToFacesMap[trisMapping[i]]] > 0) {
  314. validTriStart = i;
  315. break;
  316. }
  317. }
  318. if (validTriStart < 0) {
  319. printf("Converting navmesh: Error! No valid polygons in mesh\n");
  320. MEM_freeN(trisMapping);
  321. return 0;
  322. }
  323. ndtris = ntris - validTriStart;
  324. /* fill dtris to faces mapping */
  325. dtrisToTrisMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToTrisMap");
  326. memcpy(dtrisToTrisMap, &trisMapping[validTriStart], ndtris * sizeof(int));
  327. MEM_freeN(trisMapping);
  328. /* create detailed mesh triangles - copy only valid triangles
  329. * and reserve memory for adjacency info */
  330. dtris = MEM_callocN(sizeof(unsigned short) * 3 * 2 * ndtris, "buildNavMeshData dtris");
  331. memset(dtris, 0xff, sizeof(unsigned short) * 3 * 2 * ndtris);
  332. for (i = 0; i < ndtris; i++) {
  333. memcpy(dtris + 3 * 2 * i, tris + 3 * dtrisToTrisMap[i], sizeof(unsigned short) * 3);
  334. }
  335. /* create new recast data corresponded to dtris and renumber for continuous indices */
  336. prevPolyIdx = -1;
  337. newPolyIdx = 0;
  338. dtrisToPolysMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToPolysMap");
  339. for (i = 0; i < ndtris; i++) {
  340. curPolyIdx = recastData[trisToFacesMap[dtrisToTrisMap[i]]];
  341. if (curPolyIdx != prevPolyIdx) {
  342. newPolyIdx++;
  343. prevPolyIdx = curPolyIdx;
  344. }
  345. dtrisToPolysMap[i] = newPolyIdx;
  346. }
  347. /* build adjacency info for detailed mesh triangles */
  348. if (!recast_buildMeshAdjacency(dtris, ndtris, nverts, 3)) {
  349. printf("Converting navmesh: Error! Unable to build mesh adjacency information\n");
  350. MEM_freeN(trisMapping);
  351. MEM_freeN(dtrisToPolysMap);
  352. return 0;
  353. }
  354. /* create detailed mesh description for each navigation polygon */
  355. npolys = dtrisToPolysMap[ndtris - 1];
  356. dmeshes = MEM_callocN(sizeof(unsigned short) * npolys * 4, "buildNavMeshData dmeshes");
  357. memset(dmeshes, 0, npolys * 4 * sizeof(unsigned short));
  358. dmesh = NULL;
  359. prevpolyidx = 0;
  360. for (i = 0; i < ndtris; i++) {
  361. int curpolyidx = dtrisToPolysMap[i];
  362. if (curpolyidx != prevpolyidx) {
  363. if (curpolyidx != prevpolyidx + 1) {
  364. printf("Converting navmesh: Error! Wrong order of detailed mesh faces\n");
  365. goto fail;
  366. }
  367. dmesh = dmesh == NULL ? dmeshes : dmesh + 4;
  368. dmesh[2] = (unsigned short)i; /* tbase */
  369. dmesh[3] = 0; /* tnum */
  370. prevpolyidx = curpolyidx;
  371. }
  372. dmesh[3]++;
  373. }
  374. /* create navigation polygons */
  375. vertsPerPoly = 6;
  376. polys = MEM_callocN(sizeof(unsigned short) * npolys * vertsPerPoly * 2, "buildNavMeshData polys");
  377. memset(polys, 0xff, sizeof(unsigned short) * vertsPerPoly * 2 * npolys);
  378. if (!buildPolygonsByDetailedMeshes(vertsPerPoly, npolys, polys, dmeshes, verts, dtris, dtrisToPolysMap)) {
  379. printf("Converting navmesh: Error! Unable to build polygons from detailed mesh\n");
  380. goto fail;
  381. }
  382. *ndtris_r = ndtris;
  383. *npolys_r = npolys;
  384. *vertsPerPoly_r = vertsPerPoly;
  385. *dtris_r = dtris;
  386. *dmeshes_r = dmeshes;
  387. *polys_r = polys;
  388. *dtrisToPolysMap_r = dtrisToPolysMap;
  389. *dtrisToTrisMap_r = dtrisToTrisMap;
  390. return 1;
  391. fail:
  392. MEM_freeN(dmeshes);
  393. MEM_freeN(dtrisToPolysMap);
  394. MEM_freeN(dtrisToTrisMap);
  395. return 0;
  396. }
  397. int buildNavMeshDataByDerivedMesh(DerivedMesh *dm, int *vertsPerPoly,
  398. int *nverts, float **verts,
  399. int *ndtris, unsigned short **dtris,
  400. int *npolys, unsigned short **dmeshes,
  401. unsigned short **polys, int **dtrisToPolysMap,
  402. int **dtrisToTrisMap, int **trisToFacesMap)
  403. {
  404. int res;
  405. int ntris = 0, *recastData = NULL;
  406. unsigned short *tris = NULL;
  407. res = buildRawVertIndicesData(dm, nverts, verts, &ntris, &tris, trisToFacesMap, &recastData);
  408. if (!res) {
  409. printf("Converting navmesh: Error! Can't get raw vertices and indices from mesh\n");
  410. goto exit;
  411. }
  412. res = buildNavMeshData(*nverts, *verts, ntris, tris, recastData, *trisToFacesMap,
  413. ndtris, dtris, npolys, dmeshes, polys, vertsPerPoly,
  414. dtrisToPolysMap, dtrisToTrisMap);
  415. if (!res) {
  416. printf("Converting navmesh: Error! Can't build navmesh data from mesh\n");
  417. goto exit;
  418. }
  419. exit:
  420. if (tris)
  421. MEM_freeN(tris);
  422. return res;
  423. }
  424. int polyFindVertex(const unsigned short *p, const int vertsPerPoly, unsigned short vertexIdx)
  425. {
  426. int i, res = -1;
  427. for (i = 0; i < vertsPerPoly; i++) {
  428. if (p[i] == 0xffff)
  429. break;
  430. if (p[i] == vertexIdx) {
  431. res = i;
  432. break;
  433. }
  434. }
  435. return res;
  436. }