// // Copyright (c) 2009 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. // #include #include #include #include #include "DetourTileNavMesh.h" #include "DetourCommon.h" bool dtCreateNavMeshTileData(const unsigned short* verts, const int nverts, const unsigned short* polys, const int npolys, const int nvp, const unsigned short* dmeshes, const float* dverts, const int ndverts, const unsigned char* dtris, const int ndtris, const float* bmin, const float* bmax, float cs, float ch, int tileSize, int walkableClimb, unsigned char** outData, int* outDataSize) { if (nvp != DT_TILE_VERTS_PER_POLYGON) return false; if (nverts >= 0xffff) return false; if (!nverts) return false; if (!npolys) return false; if (!dmeshes || !dverts || ! dtris) return false; // Find portal edges which are at tile borders. int nedges = 0; int nportals = 0; for (int i = 0; i < npolys; ++i) { const unsigned short* p = &polys[i*2*nvp]; for (int j = 0; j < nvp; ++j) { if (p[j] == 0xffff) break; int nj = j+1; if (nj >= nvp || p[nj] == 0xffff) nj = 0; const unsigned short* va = &verts[p[j]*3]; const unsigned short* vb = &verts[p[nj]*3]; nedges++; if (va[0] == tileSize && vb[0] == tileSize) nportals++; // x+ else if (va[2] == tileSize && vb[2] == tileSize) nportals++; // z+ else if (va[0] == 0 && vb[0] == 0) nportals++; // x- else if (va[2] == 0 && vb[2] == 0) nportals++; // z- } } const int maxLinks = nedges + nportals*2; // Find unique detail vertices. int uniqueDetailVerts = 0; if (dmeshes) { for (int i = 0; i < npolys; ++i) { const unsigned short* p = &polys[i*nvp*2]; int ndv = dmeshes[i*4+1]; int nv = 0; for (int j = 0; j < nvp; ++j) { if (p[j] == 0xffff) break; nv++; } ndv -= nv; uniqueDetailVerts += ndv; } } // Calculate data size const int headerSize = sizeof(dtTileHeader); const int vertsSize = sizeof(float)*3*nverts; const int polysSize = sizeof(dtTilePoly)*npolys; const int linksSize = sizeof(dtTileLink)*maxLinks; const int detailMeshesSize = sizeof(dtTilePolyDetail)*npolys; const int detailVertsSize = sizeof(float)*3*uniqueDetailVerts; const int detailTrisSize = sizeof(unsigned char)*4*ndtris; const int dataSize = headerSize + vertsSize + polysSize + linksSize + detailMeshesSize + detailVertsSize + detailTrisSize; unsigned char* data = new unsigned char[dataSize]; if (!data) return false; memset(data, 0, dataSize); unsigned char* d = data; dtTileHeader* header = (dtTileHeader*)d; d += headerSize; float* navVerts = (float*)d; d += vertsSize; dtTilePoly* navPolys = (dtTilePoly*)d; d += polysSize; d += linksSize; dtTilePolyDetail* navDMeshes = (dtTilePolyDetail*)d; d += detailMeshesSize; float* navDVerts = (float*)d; d += detailVertsSize; unsigned char* navDTris = (unsigned char*)d; d += detailTrisSize; // Store header header->magic = DT_TILE_NAVMESH_MAGIC; header->version = DT_TILE_NAVMESH_VERSION; header->npolys = npolys; header->nverts = nverts; header->maxlinks = maxLinks; header->bmin[0] = bmin[0]; header->bmin[1] = bmin[1]; header->bmin[2] = bmin[2]; header->bmax[0] = bmax[0]; header->bmax[1] = bmax[1]; header->bmax[2] = bmax[2]; header->ndmeshes = npolys; header->ndverts = uniqueDetailVerts; header->ndtris = ndtris; // Store vertices for (int i = 0; i < nverts; ++i) { const unsigned short* iv = &verts[i*3]; float* v = &navVerts[i*3]; v[0] = bmin[0] + iv[0] * cs; v[1] = bmin[1] + iv[1] * ch; v[2] = bmin[2] + iv[2] * cs; } // Store polygons const unsigned short* src = polys; for (int i = 0; i < npolys; ++i) { dtTilePoly* p = &navPolys[i]; p->nv = 0; for (int j = 0; j < nvp; ++j) { if (src[j] == 0xffff) break; p->v[j] = src[j]; p->n[j] = (src[nvp+j]+1) & 0xffff; p->nv++; } src += nvp*2; } // Store portal edges. for (int i = 0; i < npolys; ++i) { dtTilePoly* poly = &navPolys[i]; for (int j = 0; j < poly->nv; ++j) { int nj = j+1; if (nj >= poly->nv) nj = 0; const unsigned short* va = &verts[poly->v[j]*3]; const unsigned short* vb = &verts[poly->v[nj]*3]; if (va[0] == tileSize && vb[0] == tileSize) // x+ poly->n[j] = 0x8000 | 0; else if (va[2] == tileSize && vb[2] == tileSize) // z+ poly->n[j] = 0x8000 | 1; else if (va[0] == 0 && vb[0] == 0) // x- poly->n[j] = 0x8000 | 2; else if (va[2] == 0 && vb[2] == 0) // z- poly->n[j] = 0x8000 | 3; } } // Store detail meshes and vertices. // The nav polygon vertices are stored as the first vertices on each mesh. // We compress the mesh data by skipping them and using the navmesh coordinates. unsigned short vbase = 0; for (int i = 0; i < npolys; ++i) { dtTilePolyDetail& dtl = navDMeshes[i]; const int vb = dmeshes[i*4+0]; const int ndv = dmeshes[i*4+1]; const int nv = navPolys[i].nv; dtl.vbase = vbase; dtl.nverts = ndv-nv; dtl.tbase = dmeshes[i*4+2]; dtl.ntris = dmeshes[i*4+3]; // Copy vertices except the first 'nv' verts which are equal to nav poly verts. if (ndv-nv) { memcpy(&navDVerts[vbase*3], &dverts[(vb+nv)*3], sizeof(float)*3*(ndv-nv)); vbase += ndv-nv; } } // Store triangles. memcpy(navDTris, dtris, sizeof(unsigned char)*4*ndtris); *outData = data; *outDataSize = dataSize; return true; }