Blender V2.61 - r43446

navmesh_conversion.c

Go to the documentation of this file.
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 }