Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00032 #include <math.h> 00033 #include <stdlib.h> 00034 00035 #include "MEM_guardedalloc.h" 00036 00037 #include "DNA_meshdata_types.h" 00038 00039 #include "BKE_navmesh_conversion.h" 00040 #include "BKE_cdderivedmesh.h" 00041 00042 #include "BLI_utildefines.h" 00043 #include "BLI_math.h" 00044 00045 #include "recast-capi.h" 00046 00047 BM_INLINE float area2(const float* a, const float* b, const float* c) 00048 { 00049 return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]); 00050 } 00051 00052 BM_INLINE int left(const float* a, const float* b, const float* c) 00053 { 00054 return area2(a, b, c) < 0; 00055 } 00056 00057 int polyNumVerts(const unsigned short* p, const int vertsPerPoly) 00058 { 00059 int i, nv = 0; 00060 for (i=0; i<vertsPerPoly; i++) 00061 { 00062 if (p[i]==0xffff) 00063 break; 00064 nv++; 00065 } 00066 return nv; 00067 } 00068 00069 int polyIsConvex(const unsigned short* p, const int vertsPerPoly, const float* verts) 00070 { 00071 int j, nv = polyNumVerts(p, vertsPerPoly); 00072 if (nv<3) 00073 return 0; 00074 for (j=0; j<nv; j++) 00075 { 00076 const float* v = &verts[3*p[j]]; 00077 const float* v_next = &verts[3*p[(j+1)%nv]]; 00078 const float* v_prev = &verts[3*p[(nv+j-1)%nv]]; 00079 if (!left(v_prev, v, v_next)) 00080 return 0; 00081 00082 } 00083 return 1; 00084 } 00085 00086 float distPointToSegmentSq(const float* point, const float* a, const float* b) 00087 { 00088 float abx[3], dx[3]; 00089 float d, t; 00090 00091 sub_v3_v3v3(abx, b,a); 00092 sub_v3_v3v3(dx, point,a); 00093 00094 d = abx[0]*abx[0]+abx[2]*abx[2]; 00095 t = abx[0]*dx[0]+abx[2]*dx[2]; 00096 00097 if (d > 0) 00098 t /= d; 00099 if (t < 0) 00100 t = 0; 00101 else if (t > 1) 00102 t = 1; 00103 dx[0] = a[0] + t*abx[0] - point[0]; 00104 dx[2] = a[2] + t*abx[2] - point[2]; 00105 00106 return dx[0]*dx[0] + dx[2]*dx[2]; 00107 } 00108 00109 int buildRawVertIndicesData(DerivedMesh* dm, int *nverts_r, float **verts_r, 00110 int *ntris_r, unsigned short **tris_r, int **trisToFacesMap_r, 00111 int **recastData) 00112 { 00113 int vi, fi, triIdx; 00114 int nverts, ntris; 00115 int *trisToFacesMap; 00116 float *verts; 00117 unsigned short *tris, *tri; 00118 int nfaces; 00119 MFace *faces; 00120 00121 nverts = dm->getNumVerts(dm); 00122 if (nverts>=0xffff) 00123 { 00124 printf("Converting navmesh: Error! Too many vertices. Max number of vertices %d\n", 0xffff); 00125 return 0; 00126 } 00127 verts = MEM_callocN(sizeof(float)*3*nverts, "buildRawVertIndicesData verts"); 00128 dm->getVertCos(dm, (float(*)[3])verts); 00129 00130 //flip coordinates 00131 for (vi=0; vi<nverts; vi++) 00132 { 00133 SWAP(float, verts[3*vi+1], verts[3*vi+2]); 00134 } 00135 00136 //calculate number of tris 00137 nfaces = dm->getNumFaces(dm); 00138 faces = dm->getFaceArray(dm); 00139 ntris = nfaces; 00140 for (fi=0; fi<nfaces; fi++) 00141 { 00142 MFace* face = &faces[fi]; 00143 if (face->v4) 00144 ntris++; 00145 } 00146 00147 //copy and transform to triangles (reorder on the run) 00148 trisToFacesMap = MEM_callocN(sizeof(int)*ntris, "buildRawVertIndicesData trisToFacesMap"); 00149 tris = MEM_callocN(sizeof(unsigned short)*3*ntris, "buildRawVertIndicesData tris"); 00150 tri = tris; 00151 triIdx = 0; 00152 for (fi=0; fi<nfaces; fi++) 00153 { 00154 MFace* face = &faces[fi]; 00155 tri[3*triIdx+0] = (unsigned short) face->v1; 00156 tri[3*triIdx+1] = (unsigned short) face->v3; 00157 tri[3*triIdx+2] = (unsigned short) face->v2; 00158 trisToFacesMap[triIdx++]=fi; 00159 if (face->v4) 00160 { 00161 tri[3*triIdx+0] = (unsigned short) face->v1; 00162 tri[3*triIdx+1] = (unsigned short) face->v4; 00163 tri[3*triIdx+2] = (unsigned short) face->v3; 00164 trisToFacesMap[triIdx++]=fi; 00165 } 00166 } 00167 00168 //carefully, recast data is just reference to data in derived mesh 00169 *recastData = (int*)CustomData_get_layer(&dm->faceData, CD_RECAST); 00170 00171 *nverts_r = nverts; 00172 *verts_r = verts; 00173 *ntris_r = ntris; 00174 *tris_r = tris; 00175 *trisToFacesMap_r = trisToFacesMap; 00176 00177 return 1; 00178 } 00179 00180 int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys, 00181 unsigned short* polys, const unsigned short* dmeshes, 00182 const float* verts, const unsigned short* dtris, 00183 const int* dtrisToPolysMap) 00184 { 00185 int polyidx; 00186 int capacity = vertsPerPoly; 00187 unsigned short* newPoly = MEM_callocN(sizeof(unsigned short)*capacity, "buildPolygonsByDetailedMeshes newPoly"); 00188 memset(newPoly, 0xff, sizeof(unsigned short)*capacity); 00189 00190 for (polyidx=0; polyidx<npolys; polyidx++) 00191 { 00192 size_t i; 00193 int j, k; 00194 int nv = 0; 00195 //search border 00196 int tri, btri = -1; 00197 int edge, bedge = -1; 00198 int dtrisNum = dmeshes[polyidx*4+3]; 00199 int dtrisBase = dmeshes[polyidx*4+2]; 00200 unsigned char *traversedTris = MEM_callocN(sizeof(unsigned char)*dtrisNum, "buildPolygonsByDetailedMeshes traversedTris"); 00201 unsigned short* adjustedPoly; 00202 int adjustedNv; 00203 int allBorderTraversed; 00204 00205 for (j=0; j<dtrisNum && btri==-1;j++) 00206 { 00207 int curpolytri = dtrisBase+j; 00208 for (k=0; k<3; k++) 00209 { 00210 unsigned short neighbortri = dtris[curpolytri*3*2+3+k]; 00211 if ( neighbortri==0xffff || dtrisToPolysMap[neighbortri]!=polyidx+1) 00212 { 00213 btri = curpolytri; 00214 bedge = k; 00215 break; 00216 } 00217 } 00218 } 00219 if (btri==-1 || bedge==-1) 00220 { 00221 //can't find triangle with border edge 00222 MEM_freeN(traversedTris); 00223 MEM_freeN(newPoly); 00224 00225 return 0; 00226 } 00227 00228 newPoly[nv++] = dtris[btri*3*2+bedge]; 00229 tri = btri; 00230 edge = (bedge+1)%3; 00231 traversedTris[tri-dtrisBase] = 1; 00232 while (tri!=btri || edge!=bedge) 00233 { 00234 int neighbortri = dtris[tri*3*2+3+edge]; 00235 if (neighbortri==0xffff || dtrisToPolysMap[neighbortri]!=polyidx+1) 00236 { 00237 if (nv==capacity) 00238 { 00239 unsigned short* newPolyBig; 00240 capacity += vertsPerPoly; 00241 newPolyBig = MEM_callocN(sizeof(unsigned short)*capacity, "buildPolygonsByDetailedMeshes newPolyBig"); 00242 memset(newPolyBig, 0xff, sizeof(unsigned short)*capacity); 00243 memcpy(newPolyBig, newPoly, sizeof(unsigned short)*nv); 00244 MEM_freeN(newPoly); 00245 newPoly = newPolyBig; 00246 } 00247 newPoly[nv++] = dtris[tri*3*2+edge]; 00248 //move to next edge 00249 edge = (edge+1)%3; 00250 } 00251 else 00252 { 00253 //move to next tri 00254 int twinedge = -1; 00255 for (k=0; k<3; k++) 00256 { 00257 if (dtris[neighbortri*3*2+3+k] == tri) 00258 { 00259 twinedge = k; 00260 break; 00261 } 00262 } 00263 if (twinedge==-1) 00264 { 00265 printf("Converting navmesh: Error! Can't find neighbor edge - invalid adjacency info\n"); 00266 MEM_freeN(traversedTris); 00267 goto returnLabel; 00268 } 00269 tri = neighbortri; 00270 edge = (twinedge+1)%3; 00271 traversedTris[tri-dtrisBase] = 1; 00272 } 00273 } 00274 00275 adjustedPoly = MEM_callocN(sizeof(unsigned short)*nv, "buildPolygonsByDetailedMeshes adjustedPoly"); 00276 adjustedNv = 0; 00277 for (i=0; i<nv; i++) 00278 { 00279 unsigned short prev = newPoly[(nv+i-1)%nv]; 00280 unsigned short cur = newPoly[i]; 00281 unsigned short next = newPoly[(i+1)%nv]; 00282 float distSq = distPointToSegmentSq(&verts[3*cur], &verts[3*prev], &verts[3*next]); 00283 static const float tolerance = 0.001f; 00284 if (distSq>tolerance) 00285 adjustedPoly[adjustedNv++] = cur; 00286 } 00287 memcpy(newPoly, adjustedPoly, adjustedNv*sizeof(unsigned short)); 00288 MEM_freeN(adjustedPoly); 00289 nv = adjustedNv; 00290 00291 allBorderTraversed = 1; 00292 for (i=0; i<dtrisNum; i++) 00293 { 00294 if (traversedTris[i]==0) 00295 { 00296 //check whether it has border edges 00297 int curpolytri = dtrisBase+i; 00298 for (k=0; k<3; k++) 00299 { 00300 unsigned short neighbortri = dtris[curpolytri*3*2+3+k]; 00301 if ( neighbortri==0xffff || dtrisToPolysMap[neighbortri]!=polyidx+1) 00302 { 00303 allBorderTraversed = 0; 00304 break; 00305 } 00306 } 00307 } 00308 } 00309 00310 if (nv<=vertsPerPoly && allBorderTraversed) 00311 { 00312 for (i=0; i<nv; i++) 00313 { 00314 polys[polyidx*vertsPerPoly*2+i] = newPoly[i]; 00315 } 00316 } 00317 00318 MEM_freeN(traversedTris); 00319 } 00320 00321 returnLabel: 00322 MEM_freeN(newPoly); 00323 00324 return 1; 00325 } 00326 00327 struct SortContext 00328 { 00329 const int* recastData; 00330 const int* trisToFacesMap; 00331 }; 00332 00333 static int compareByData(void *ctx, const void * a, const void * b) 00334 { 00335 return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int*)a]] - 00336 ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int*)b]] ); 00337 } 00338 00339 int buildNavMeshData(const int nverts, const float* verts, 00340 const int ntris, const unsigned short *tris, 00341 const int* recastData, const int* trisToFacesMap, 00342 int *ndtris_r, unsigned short **dtris_r, 00343 int *npolys_r, unsigned short **dmeshes_r, unsigned short **polys_r, 00344 int *vertsPerPoly_r, int **dtrisToPolysMap_r, int **dtrisToTrisMap_r) 00345 00346 { 00347 int *trisMapping = MEM_callocN(sizeof(int)*ntris, "buildNavMeshData trisMapping"); 00348 int i; 00349 struct SortContext context; 00350 int validTriStart, prevPolyIdx, curPolyIdx, newPolyIdx, prevpolyidx; 00351 unsigned short *dmesh; 00352 00353 int ndtris, npolys, vertsPerPoly; 00354 unsigned short *dtris, *dmeshes, *polys; 00355 int *dtrisToPolysMap, *dtrisToTrisMap; 00356 00357 if (!recastData) 00358 { 00359 printf("Converting navmesh: Error! Can't find recast custom data\n"); 00360 return 0; 00361 } 00362 00363 //sort the triangles by polygon idx 00364 for (i=0; i<ntris; i++) 00365 trisMapping[i]=i; 00366 context.recastData = recastData; 00367 context.trisToFacesMap = trisToFacesMap; 00368 recast_qsort(trisMapping, ntris, sizeof(int), &context, compareByData); 00369 00370 //search first valid triangle - triangle of convex polygon 00371 validTriStart = -1; 00372 for (i=0; i< ntris; i++) 00373 { 00374 if (recastData[trisToFacesMap[trisMapping[i]]]>0) 00375 { 00376 validTriStart = i; 00377 break; 00378 } 00379 } 00380 00381 if (validTriStart<0) 00382 { 00383 printf("Converting navmesh: Error! No valid polygons in mesh\n"); 00384 MEM_freeN(trisMapping); 00385 return 0; 00386 } 00387 00388 ndtris = ntris-validTriStart; 00389 //fill dtris to faces mapping 00390 dtrisToTrisMap = MEM_callocN(sizeof(int)*ndtris, "buildNavMeshData dtrisToTrisMap"); 00391 memcpy(dtrisToTrisMap, &trisMapping[validTriStart], ndtris*sizeof(int)); 00392 MEM_freeN(trisMapping); 00393 00394 //create detailed mesh triangles - copy only valid triangles 00395 //and reserve memory for adjacency info 00396 dtris = MEM_callocN(sizeof(unsigned short)*3*2*ndtris, "buildNavMeshData dtris"); 00397 memset(dtris, 0xffff, sizeof(unsigned short)*3*2*ndtris); 00398 for (i=0; i<ndtris; i++) 00399 { 00400 memcpy(dtris+3*2*i, tris+3*dtrisToTrisMap[i], sizeof(unsigned short)*3); 00401 } 00402 00403 //create new recast data corresponded to dtris and renumber for continuous indices 00404 prevPolyIdx = -1; 00405 newPolyIdx = 0; 00406 dtrisToPolysMap = MEM_callocN(sizeof(int)*ndtris, "buildNavMeshData dtrisToPolysMap"); 00407 for (i=0; i<ndtris; i++) 00408 { 00409 curPolyIdx = recastData[trisToFacesMap[dtrisToTrisMap[i]]]; 00410 if (curPolyIdx!=prevPolyIdx) 00411 { 00412 newPolyIdx++; 00413 prevPolyIdx=curPolyIdx; 00414 } 00415 dtrisToPolysMap[i] = newPolyIdx; 00416 } 00417 00418 00419 //build adjacency info for detailed mesh triangles 00420 recast_buildMeshAdjacency(dtris, ndtris, nverts, 3); 00421 00422 //create detailed mesh description for each navigation polygon 00423 npolys = dtrisToPolysMap[ndtris-1]; 00424 dmeshes = MEM_callocN(sizeof(unsigned short)*npolys*4, "buildNavMeshData dmeshes"); 00425 memset(dmeshes, 0, npolys*4*sizeof(unsigned short)); 00426 dmesh = NULL; 00427 prevpolyidx = 0; 00428 for (i=0; i<ndtris; i++) 00429 { 00430 int curpolyidx = dtrisToPolysMap[i]; 00431 if (curpolyidx!=prevpolyidx) 00432 { 00433 if (curpolyidx!=prevpolyidx+1) 00434 { 00435 printf("Converting navmesh: Error! Wrong order of detailed mesh faces\n"); 00436 return 0; 00437 } 00438 dmesh = dmesh==NULL ? dmeshes : dmesh+4; 00439 dmesh[2] = (unsigned short)i; //tbase 00440 dmesh[3] = 0; //tnum 00441 prevpolyidx = curpolyidx; 00442 } 00443 dmesh[3]++; 00444 } 00445 00446 //create navigation polygons 00447 vertsPerPoly = 6; 00448 polys = MEM_callocN(sizeof(unsigned short)*npolys*vertsPerPoly*2, "buildNavMeshData polys"); 00449 memset(polys, 0xff, sizeof(unsigned short)*vertsPerPoly*2*npolys); 00450 00451 buildPolygonsByDetailedMeshes(vertsPerPoly, npolys, polys, dmeshes, verts, dtris, dtrisToPolysMap); 00452 00453 *ndtris_r = ndtris; 00454 *npolys_r = npolys; 00455 *vertsPerPoly_r = vertsPerPoly; 00456 *dtris_r = dtris; 00457 *dmeshes_r = dmeshes; 00458 *polys_r = polys; 00459 *dtrisToPolysMap_r = dtrisToPolysMap; 00460 *dtrisToTrisMap_r = dtrisToTrisMap; 00461 00462 return 1; 00463 } 00464 00465 00466 int buildNavMeshDataByDerivedMesh(DerivedMesh *dm, int *vertsPerPoly, 00467 int *nverts, float **verts, 00468 int *ndtris, unsigned short **dtris, 00469 int *npolys, unsigned short **dmeshes, 00470 unsigned short **polys, int **dtrisToPolysMap, 00471 int **dtrisToTrisMap, int **trisToFacesMap) 00472 { 00473 int res = 1; 00474 int ntris = 0, *recastData=NULL; 00475 unsigned short *tris=NULL; 00476 00477 res = buildRawVertIndicesData(dm, nverts, verts, &ntris, &tris, trisToFacesMap, &recastData); 00478 if (!res) 00479 { 00480 printf("Converting navmesh: Error! Can't get vertices and indices from mesh\n"); 00481 goto exit; 00482 } 00483 00484 res = buildNavMeshData(*nverts, *verts, ntris, tris, recastData, *trisToFacesMap, 00485 ndtris, dtris, npolys, dmeshes,polys, vertsPerPoly, 00486 dtrisToPolysMap, dtrisToTrisMap); 00487 if (!res) 00488 { 00489 printf("Converting navmesh: Error! Can't get vertices and indices from mesh\n"); 00490 goto exit; 00491 } 00492 00493 exit: 00494 if (tris) 00495 MEM_freeN(tris); 00496 00497 return res; 00498 } 00499 00500 int polyFindVertex(const unsigned short* p, const int vertsPerPoly, unsigned short vertexIdx) 00501 { 00502 int i, res = -1; 00503 for(i=0; i<vertsPerPoly; i++) 00504 { 00505 if (p[i]==0xffff) 00506 break; 00507 if (p[i]==vertexIdx) 00508 { 00509 res = i; 00510 break; 00511 } 00512 } 00513 return res; 00514 }