2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/blenkernel/intern/navmesh_conversion.c
35 #include "MEM_guardedalloc.h"
37 #include "DNA_meshdata_types.h"
39 #include "BKE_navmesh_conversion.h"
40 #include "BKE_cdderivedmesh.h"
42 #include "BLI_utildefines.h"
45 #include "recast-capi.h"
47 BM_INLINE float area2(const float* a, const float* b, const float* c)
49 return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
52 BM_INLINE int left(const float* a, const float* b, const float* c)
54 return area2(a, b, c) < 0;
57 int polyNumVerts(const unsigned short* p, const int vertsPerPoly)
60 for (i=0; i<vertsPerPoly; i++)
69 int polyIsConvex(const unsigned short* p, const int vertsPerPoly, const float* verts)
71 int j, nv = polyNumVerts(p, vertsPerPoly);
76 const float* v = &verts[3*p[j]];
77 const float* v_next = &verts[3*p[(j+1)%nv]];
78 const float* v_prev = &verts[3*p[(nv+j-1)%nv]];
79 if (!left(v_prev, v, v_next))
86 float distPointToSegmentSq(const float* point, const float* a, const float* b)
91 sub_v3_v3v3(abx, b,a);
92 sub_v3_v3v3(dx, point,a);
94 d = abx[0]*abx[0]+abx[2]*abx[2];
95 t = abx[0]*dx[0]+abx[2]*dx[2];
103 dx[0] = a[0] + t*abx[0] - point[0];
104 dx[2] = a[2] + t*abx[2] - point[2];
106 return dx[0]*dx[0] + dx[2]*dx[2];
109 int buildRawVertIndicesData(DerivedMesh* dm, int *nverts_r, float **verts_r,
110 int *ntris_r, unsigned short **tris_r, int **trisToFacesMap_r,
117 unsigned short *tris, *tri;
121 nverts = dm->getNumVerts(dm);
124 printf("Converting navmesh: Error! Too many vertices. Max number of vertices %d\n", 0xffff);
127 verts = MEM_callocN(sizeof(float)*3*nverts, "buildRawVertIndicesData verts");
128 dm->getVertCos(dm, (float(*)[3])verts);
131 for (vi=0; vi<nverts; vi++)
133 SWAP(float, verts[3*vi+1], verts[3*vi+2]);
136 //calculate number of tris
137 nfaces = dm->getNumTessFaces(dm);
138 faces = dm->getTessFaceArray(dm);
140 for (fi=0; fi<nfaces; fi++)
142 MFace* face = &faces[fi];
147 //copy and transform to triangles (reorder on the run)
148 trisToFacesMap = MEM_callocN(sizeof(int)*ntris, "buildRawVertIndicesData trisToFacesMap");
149 tris = MEM_callocN(sizeof(unsigned short)*3*ntris, "buildRawVertIndicesData tris");
152 for (fi=0; fi<nfaces; fi++)
154 MFace* face = &faces[fi];
155 tri[3*triIdx+0] = (unsigned short) face->v1;
156 tri[3*triIdx+1] = (unsigned short) face->v3;
157 tri[3*triIdx+2] = (unsigned short) face->v2;
158 trisToFacesMap[triIdx++]=fi;
161 tri[3*triIdx+0] = (unsigned short) face->v1;
162 tri[3*triIdx+1] = (unsigned short) face->v4;
163 tri[3*triIdx+2] = (unsigned short) face->v3;
164 trisToFacesMap[triIdx++]=fi;
168 //carefully, recast data is just reference to data in derived mesh
169 *recastData = (int*)CustomData_get_layer(&dm->faceData, CD_RECAST);
175 *trisToFacesMap_r = trisToFacesMap;
180 int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys,
181 unsigned short* polys, const unsigned short* dmeshes,
182 const float* verts, const unsigned short* dtris,
183 const int* dtrisToPolysMap)
186 int capacity = vertsPerPoly;
187 unsigned short* newPoly = MEM_callocN(sizeof(unsigned short)*capacity, "buildPolygonsByDetailedMeshes newPoly");
188 memset(newPoly, 0xff, sizeof(unsigned short)*capacity);
190 for (polyidx=0; polyidx<npolys; polyidx++)
197 int edge, bedge = -1;
198 int dtrisNum = dmeshes[polyidx*4+3];
199 int dtrisBase = dmeshes[polyidx*4+2];
200 unsigned char *traversedTris = MEM_callocN(sizeof(unsigned char)*dtrisNum, "buildPolygonsByDetailedMeshes traversedTris");
201 unsigned short* adjustedPoly;
203 int allBorderTraversed;
205 for (j=0; j<dtrisNum && btri==-1;j++)
207 int curpolytri = dtrisBase+j;
210 unsigned short neighbortri = dtris[curpolytri*3*2+3+k];
211 if ( neighbortri==0xffff || dtrisToPolysMap[neighbortri]!=polyidx+1)
219 if (btri==-1 || bedge==-1)
221 //can't find triangle with border edge
222 MEM_freeN(traversedTris);
228 newPoly[nv++] = dtris[btri*3*2+bedge];
231 traversedTris[tri-dtrisBase] = 1;
232 while (tri!=btri || edge!=bedge)
234 int neighbortri = dtris[tri*3*2+3+edge];
235 if (neighbortri==0xffff || dtrisToPolysMap[neighbortri]!=polyidx+1)
239 unsigned short* newPolyBig;
240 capacity += vertsPerPoly;
241 newPolyBig = MEM_callocN(sizeof(unsigned short)*capacity, "buildPolygonsByDetailedMeshes newPolyBig");
242 memset(newPolyBig, 0xff, sizeof(unsigned short)*capacity);
243 memcpy(newPolyBig, newPoly, sizeof(unsigned short)*nv);
245 newPoly = newPolyBig;
247 newPoly[nv++] = dtris[tri*3*2+edge];
257 if (dtris[neighbortri*3*2+3+k] == tri)
265 printf("Converting navmesh: Error! Can't find neighbor edge - invalid adjacency info\n");
266 MEM_freeN(traversedTris);
270 edge = (twinedge+1)%3;
271 traversedTris[tri-dtrisBase] = 1;
275 adjustedPoly = MEM_callocN(sizeof(unsigned short)*nv, "buildPolygonsByDetailedMeshes adjustedPoly");
279 unsigned short prev = newPoly[(nv+i-1)%nv];
280 unsigned short cur = newPoly[i];
281 unsigned short next = newPoly[(i+1)%nv];
282 float distSq = distPointToSegmentSq(&verts[3*cur], &verts[3*prev], &verts[3*next]);
283 static const float tolerance = 0.001f;
284 if (distSq>tolerance)
285 adjustedPoly[adjustedNv++] = cur;
287 memcpy(newPoly, adjustedPoly, adjustedNv*sizeof(unsigned short));
288 MEM_freeN(adjustedPoly);
291 allBorderTraversed = 1;
292 for (i=0; i<dtrisNum; i++)
294 if (traversedTris[i]==0)
296 //check whether it has border edges
297 int curpolytri = dtrisBase+i;
300 unsigned short neighbortri = dtris[curpolytri*3*2+3+k];
301 if ( neighbortri==0xffff || dtrisToPolysMap[neighbortri]!=polyidx+1)
303 allBorderTraversed = 0;
310 if (nv<=vertsPerPoly && allBorderTraversed)
314 polys[polyidx*vertsPerPoly*2+i] = newPoly[i];
318 MEM_freeN(traversedTris);
329 const int* recastData;
330 const int* trisToFacesMap;
333 static int compareByData(void *ctx, const void * a, const void * b)
335 return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int*)a]] -
336 ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int*)b]] );
339 int buildNavMeshData(const int nverts, const float* verts,
340 const int ntris, const unsigned short *tris,
341 const int* recastData, const int* trisToFacesMap,
342 int *ndtris_r, unsigned short **dtris_r,
343 int *npolys_r, unsigned short **dmeshes_r, unsigned short **polys_r,
344 int *vertsPerPoly_r, int **dtrisToPolysMap_r, int **dtrisToTrisMap_r)
347 int *trisMapping = MEM_callocN(sizeof(int)*ntris, "buildNavMeshData trisMapping");
349 struct SortContext context;
350 int validTriStart, prevPolyIdx, curPolyIdx, newPolyIdx, prevpolyidx;
351 unsigned short *dmesh;
353 int ndtris, npolys, vertsPerPoly;
354 unsigned short *dtris, *dmeshes, *polys;
355 int *dtrisToPolysMap, *dtrisToTrisMap;
359 printf("Converting navmesh: Error! Can't find recast custom data\n");
363 //sort the triangles by polygon idx
364 for (i=0; i<ntris; i++)
366 context.recastData = recastData;
367 context.trisToFacesMap = trisToFacesMap;
368 recast_qsort(trisMapping, ntris, sizeof(int), &context, compareByData);
370 //search first valid triangle - triangle of convex polygon
372 for (i=0; i< ntris; i++)
374 if (recastData[trisToFacesMap[trisMapping[i]]]>0)
383 printf("Converting navmesh: Error! No valid polygons in mesh\n");
384 MEM_freeN(trisMapping);
388 ndtris = ntris-validTriStart;
389 //fill dtris to faces mapping
390 dtrisToTrisMap = MEM_callocN(sizeof(int)*ndtris, "buildNavMeshData dtrisToTrisMap");
391 memcpy(dtrisToTrisMap, &trisMapping[validTriStart], ndtris*sizeof(int));
392 MEM_freeN(trisMapping);
394 //create detailed mesh triangles - copy only valid triangles
395 //and reserve memory for adjacency info
396 dtris = MEM_callocN(sizeof(unsigned short)*3*2*ndtris, "buildNavMeshData dtris");
397 memset(dtris, 0xffff, sizeof(unsigned short)*3*2*ndtris);
398 for (i=0; i<ndtris; i++)
400 memcpy(dtris+3*2*i, tris+3*dtrisToTrisMap[i], sizeof(unsigned short)*3);
403 //create new recast data corresponded to dtris and renumber for continuous indices
406 dtrisToPolysMap = MEM_callocN(sizeof(int)*ndtris, "buildNavMeshData dtrisToPolysMap");
407 for (i=0; i<ndtris; i++)
409 curPolyIdx = recastData[trisToFacesMap[dtrisToTrisMap[i]]];
410 if (curPolyIdx!=prevPolyIdx)
413 prevPolyIdx=curPolyIdx;
415 dtrisToPolysMap[i] = newPolyIdx;
419 //build adjacency info for detailed mesh triangles
420 recast_buildMeshAdjacency(dtris, ndtris, nverts, 3);
422 //create detailed mesh description for each navigation polygon
423 npolys = dtrisToPolysMap[ndtris-1];
424 dmeshes = MEM_callocN(sizeof(unsigned short)*npolys*4, "buildNavMeshData dmeshes");
425 memset(dmeshes, 0, npolys*4*sizeof(unsigned short));
428 for (i=0; i<ndtris; i++)
430 int curpolyidx = dtrisToPolysMap[i];
431 if (curpolyidx!=prevpolyidx)
433 if (curpolyidx!=prevpolyidx+1)
435 printf("Converting navmesh: Error! Wrong order of detailed mesh faces\n");
438 dmesh = dmesh==NULL ? dmeshes : dmesh+4;
439 dmesh[2] = (unsigned short)i; //tbase
441 prevpolyidx = curpolyidx;
446 //create navigation polygons
448 polys = MEM_callocN(sizeof(unsigned short)*npolys*vertsPerPoly*2, "buildNavMeshData polys");
449 memset(polys, 0xff, sizeof(unsigned short)*vertsPerPoly*2*npolys);
451 buildPolygonsByDetailedMeshes(vertsPerPoly, npolys, polys, dmeshes, verts, dtris, dtrisToPolysMap);
455 *vertsPerPoly_r = vertsPerPoly;
457 *dmeshes_r = dmeshes;
459 *dtrisToPolysMap_r = dtrisToPolysMap;
460 *dtrisToTrisMap_r = dtrisToTrisMap;
466 int buildNavMeshDataByDerivedMesh(DerivedMesh *dm, int *vertsPerPoly,
467 int *nverts, float **verts,
468 int *ndtris, unsigned short **dtris,
469 int *npolys, unsigned short **dmeshes,
470 unsigned short **polys, int **dtrisToPolysMap,
471 int **dtrisToTrisMap, int **trisToFacesMap)
474 int ntris = 0, *recastData=NULL;
475 unsigned short *tris=NULL;
477 res = buildRawVertIndicesData(dm, nverts, verts, &ntris, &tris, trisToFacesMap, &recastData);
480 printf("Converting navmesh: Error! Can't get vertices and indices from mesh\n");
484 res = buildNavMeshData(*nverts, *verts, ntris, tris, recastData, *trisToFacesMap,
485 ndtris, dtris, npolys, dmeshes,polys, vertsPerPoly,
486 dtrisToPolysMap, dtrisToTrisMap);
489 printf("Converting navmesh: Error! Can't get vertices and indices from mesh\n");
500 int polyFindVertex(const unsigned short* p, const int vertsPerPoly, unsigned short vertexIdx)
503 for(i=0; i<vertsPerPoly; i++)