123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- //
- // 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 <math.h>
- #include <stdlib.h>
- #include <string.h>
- #include "DetourStatNavMesh.h"
- struct BVItem
- {
- unsigned short bmin[3];
- unsigned short bmax[3];
- int i;
- };
- static int compareItemX(const void* va, const void* vb)
- {
- const BVItem* a = (const BVItem*)va;
- const BVItem* b = (const BVItem*)vb;
- if (a->bmin[0] < b->bmin[0])
- return -1;
- if (a->bmin[0] > b->bmin[0])
- return 1;
- return 0;
- }
- static int compareItemY(const void* va, const void* vb)
- {
- const BVItem* a = (const BVItem*)va;
- const BVItem* b = (const BVItem*)vb;
- if (a->bmin[1] < b->bmin[1])
- return -1;
- if (a->bmin[1] > b->bmin[1])
- return 1;
- return 0;
- }
- static int compareItemZ(const void* va, const void* vb)
- {
- const BVItem* a = (const BVItem*)va;
- const BVItem* b = (const BVItem*)vb;
- if (a->bmin[2] < b->bmin[2])
- return -1;
- if (a->bmin[2] > b->bmin[2])
- return 1;
- return 0;
- }
- static void calcExtends(BVItem* items, int nitems, int imin, int imax,
- unsigned short* bmin, unsigned short* bmax)
- {
- bmin[0] = items[imin].bmin[0];
- bmin[1] = items[imin].bmin[1];
- bmin[2] = items[imin].bmin[2];
-
- bmax[0] = items[imin].bmax[0];
- bmax[1] = items[imin].bmax[1];
- bmax[2] = items[imin].bmax[2];
-
- for (int i = imin+1; i < imax; ++i)
- {
- const BVItem& it = items[i];
- if (it.bmin[0] < bmin[0]) bmin[0] = it.bmin[0];
- if (it.bmin[1] < bmin[1]) bmin[1] = it.bmin[1];
- if (it.bmin[2] < bmin[2]) bmin[2] = it.bmin[2];
-
- if (it.bmax[0] > bmax[0]) bmax[0] = it.bmax[0];
- if (it.bmax[1] > bmax[1]) bmax[1] = it.bmax[1];
- if (it.bmax[2] > bmax[2]) bmax[2] = it.bmax[2];
- }
- }
- inline int longestAxis(unsigned short x, unsigned short y, unsigned short z)
- {
- int axis = 0;
- unsigned short maxVal = x;
- if (y > maxVal)
- {
- axis = 1;
- maxVal = y;
- }
- if (z > maxVal)
- {
- axis = 2;
- maxVal = z;
- }
- return axis;
- }
- static void subdivide(BVItem* items, int nitems, int imin, int imax, int& curNode, dtStatBVNode* nodes)
- {
- int inum = imax - imin;
- int icur = curNode;
-
- dtStatBVNode& node = nodes[curNode++];
-
- if (inum == 1)
- {
- // Leaf
- node.bmin[0] = items[imin].bmin[0];
- node.bmin[1] = items[imin].bmin[1];
- node.bmin[2] = items[imin].bmin[2];
-
- node.bmax[0] = items[imin].bmax[0];
- node.bmax[1] = items[imin].bmax[1];
- node.bmax[2] = items[imin].bmax[2];
-
- node.i = items[imin].i;
- }
- else
- {
- // Split
- calcExtends(items, nitems, imin, imax, node.bmin, node.bmax);
-
- int axis = longestAxis(node.bmax[0] - node.bmin[0],
- node.bmax[1] - node.bmin[1],
- node.bmax[2] - node.bmin[2]);
-
- if (axis == 0)
- {
- // Sort along x-axis
- qsort(items+imin, inum, sizeof(BVItem), compareItemX);
- }
- else if (axis == 1)
- {
- // Sort along y-axis
- qsort(items+imin, inum, sizeof(BVItem), compareItemY);
- }
- else
- {
- // Sort along z-axis
- qsort(items+imin, inum, sizeof(BVItem), compareItemZ);
- }
-
- int isplit = imin+inum/2;
-
- // Left
- subdivide(items, nitems, imin, isplit, curNode, nodes);
- // Right
- subdivide(items, nitems, isplit, imax, curNode, nodes);
-
- int iescape = curNode - icur;
- // Negative index means escape.
- node.i = -iescape;
- }
- }
- /*static*/ int createBVTree(const unsigned short* verts, const int nverts,
- const unsigned short* polys, const int npolys, const int nvp,
- float cs, float ch,
- int nnodes, dtStatBVNode* nodes)
- {
- // Build tree
- BVItem* items = new BVItem[npolys];
- for (int i = 0; i < npolys; i++)
- {
- BVItem& it = items[i];
- it.i = i+1;
- // Calc polygon bounds.
- const unsigned short* p = &polys[i*nvp*2];
- it.bmin[0] = it.bmax[0] = verts[p[0]*3+0];
- it.bmin[1] = it.bmax[1] = verts[p[0]*3+1];
- it.bmin[2] = it.bmax[2] = verts[p[0]*3+2];
-
- for (int j = 1; j < nvp; ++j)
- {
- if (p[j] == 0xffff) break;
- unsigned short x = verts[p[j]*3+0];
- unsigned short y = verts[p[j]*3+1];
- unsigned short z = verts[p[j]*3+2];
-
- if (x < it.bmin[0]) it.bmin[0] = x;
- if (y < it.bmin[1]) it.bmin[1] = y;
- if (z < it.bmin[2]) it.bmin[2] = z;
-
- if (x > it.bmax[0]) it.bmax[0] = x;
- if (y > it.bmax[1]) it.bmax[1] = y;
- if (z > it.bmax[2]) it.bmax[2] = z;
- }
- // Remap y
- it.bmin[1] = (unsigned short)floorf((float)it.bmin[1]*ch/cs);
- it.bmax[1] = (unsigned short)ceilf((float)it.bmax[1]*ch/cs);
- }
-
- int curNode = 0;
- subdivide(items, npolys, 0, npolys, curNode, nodes);
-
- delete [] items;
-
- return curNode;
- }
- bool dtCreateNavMeshData(const unsigned short* verts, const int nverts,
- const unsigned short* polys, const int npolys, const int nvp,
- const float* bmin, const float* bmax, float cs, float ch,
- const unsigned short* dmeshes, const float* dverts, const int ndverts,
- const unsigned char* dtris, const int ndtris,
- unsigned char** outData, int* outDataSize)
- {
- if (nvp > DT_STAT_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 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(dtStatNavMeshHeader);
- const int vertsSize = sizeof(float)*3*nverts;
- const int polysSize = sizeof(dtStatPoly)*npolys;
- const int nodesSize = sizeof(dtStatBVNode)*npolys*2;
- const int detailMeshesSize = sizeof(dtStatPolyDetail)*npolys;
- const int detailVertsSize = sizeof(float)*3*uniqueDetailVerts;
- const int detailTrisSize = sizeof(unsigned char)*4*ndtris;
-
- const int dataSize = headerSize + vertsSize + polysSize + nodesSize +
- detailMeshesSize + detailVertsSize + detailTrisSize;
- unsigned char* data = new unsigned char[dataSize];
- if (!data)
- return false;
- memset(data, 0, dataSize);
- unsigned char* d = data;
- dtStatNavMeshHeader* header = (dtStatNavMeshHeader*)d; d += headerSize;
- float* navVerts = (float*)d; d += vertsSize;
- dtStatPoly* navPolys = (dtStatPoly*)d; d += polysSize;
- dtStatBVNode* navNodes = (dtStatBVNode*)d; d += nodesSize;
- dtStatPolyDetail* navDMeshes = (dtStatPolyDetail*)d; d += detailMeshesSize;
- float* navDVerts = (float*)d; d += detailVertsSize;
- unsigned char* navDTris = (unsigned char*)d; d += detailTrisSize;
-
- // Store header
- header->magic = DT_STAT_NAVMESH_MAGIC;
- header->version = DT_STAT_NAVMESH_VERSION;
- header->npolys = npolys;
- header->nverts = nverts;
- header->cs = cs;
- 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 = dmeshes ? npolys : 0;
- header->ndverts = dmeshes ? uniqueDetailVerts : 0;
- header->ndtris = dmeshes ? ndtris : 0;
-
- // 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)
- {
- dtStatPoly* 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;
- p->nv++;
- }
- src += nvp*2;
- }
-
- header->nnodes = createBVTree(verts, nverts, polys, npolys, nvp,
- cs, ch, npolys*2, navNodes);
-
- // 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)
- {
- dtStatPolyDetail& 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;
- }
|