Added ugly, but functional version of TiledNavMesh and a builder for the same.

Fixed a cost bug in the dtStatNavMesh::findPolysAround.
Added debug draw functions for tiled navmesh.
This commit is contained in:
Mikko Mononen 2009-07-09 08:32:30 +00:00
parent 9edeccea35
commit 4787a8d223
8 changed files with 2431 additions and 32 deletions

View File

@ -20,9 +20,13 @@
#define DETOURDEBUGDRAW_H
#include "DetourStatNavMesh.h"
#include "DetourTiledNavMesh.h"
void dtDebugDrawStatNavMeshPoly(const dtStatNavMesh* mesh, dtPolyRef ref, const float* col);
void dtDebugDrawStatNavMeshBVTree(const dtStatNavMesh* mesh);
void dtDebugDrawStatNavMesh(const dtStatNavMesh* mesh);
void dtDebugDrawTiledNavMesh(const dtTiledNavMesh* mesh);
void dtDebugDrawTiledNavMeshPoly(const dtTiledNavMesh* mesh, dtTilePolyRef ref, const float* col);
#endif // DETOURDEBUGDRAW_H

View File

@ -84,7 +84,7 @@ public:
// maxPolys - (in) The max number of polygons the polys array can hold.
// Returns: Number of polygons in search result array.
int queryPolygons(const float* center, const float* extents,
unsigned short* polys, const int maxPolys);
dtPolyRef* polys, const int maxPolys);
// Finds path from start polygon to end polygon.
// If target polygon canno be reached through the navigation graph,
@ -184,8 +184,6 @@ private:
float getCost(dtPolyRef prev, dtPolyRef from, dtPolyRef to) const;
float getHeuristic(dtPolyRef from, dtPolyRef to) const;
bool getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const;
// Copies the locations of vertices of a polygon to an array.
int getPolyVerts(dtPolyRef ref, float* verts) const;
// Returns portal points between two polygons.

View File

@ -0,0 +1,209 @@
//
// 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.
//
#ifndef DETOURTILEDNAVMESH_H
#define DETOURTILEDNAVMESH_H
// Reference to navigation polygon.
typedef unsigned int dtTilePolyRef;
static const int DT_TILE_REF_SALT_BITS = 12;
static const int DT_TILE_REF_SALT_MASK = (1<<DT_TILE_REF_SALT_BITS)-1;
static const int DT_TILE_REF_TILE_BITS = 12;
static const int DT_TILE_REF_TILE_MASK = (1<<DT_TILE_REF_TILE_BITS)-1;
static const int DT_TILE_REF_POLY_BITS = 8;
static const int DT_TILE_REF_POLY_MASK = (1<<DT_TILE_REF_POLY_BITS)-1;
// Maximum number of vertices per navigation polygon.
static const int DT_TILE_VERTS_PER_POLYGON = 6;
static const int DT_MAX_TILES = 1 << DT_TILE_REF_TILE_BITS;
static const int DT_MAX_POLYGONS = 1 << DT_TILE_REF_POLY_BITS;
// Structure holding the navigation polygon data.
struct dtTilePoly
{
unsigned short v[DT_TILE_VERTS_PER_POLYGON]; // Indices to vertices of the poly.
unsigned short n[DT_TILE_VERTS_PER_POLYGON]; // Refs to neighbours of the poly.
unsigned short links;
unsigned char nlinks;
unsigned char nv; // Number of vertices.
unsigned char flags; // Flags (not used).
};
struct dtTileLink
{
dtTilePolyRef ref;
unsigned short p;
unsigned char e;
unsigned char side;
float bmin, bmax;
};
static const int DT_TILE_NAVMESH_MAGIC = 'NAVT';
static const int DT_TILE_NAVMESH_VERSION = 1;
struct dtTileHeader
{
int magic;
int version;
int npolys;
int nverts;
int nportals[4];
int nlinks;
int maxlinks;
float cs;
float bmin[3], bmax[3];
dtTilePoly* polys;
float* verts;
dtTileLink* links;
struct dtTile* nei[4];
};
struct dtTile
{
int salt;
int x,y;
dtTileHeader* header;
dtTile* next;
};
inline dtTilePolyRef encodeId(unsigned int salt, unsigned int it, unsigned int ip)
{
return (salt << (DT_TILE_REF_POLY_BITS+DT_TILE_REF_TILE_BITS)) | ((it+1) << DT_TILE_REF_POLY_BITS) | ip;
}
inline void decodeId(dtTilePolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip)
{
salt = (ref >> (DT_TILE_REF_POLY_BITS+DT_TILE_REF_TILE_BITS)) & DT_TILE_REF_SALT_MASK;
it = ((ref >> DT_TILE_REF_POLY_BITS) & DT_TILE_REF_TILE_MASK) - 1;
ip = ref & DT_TILE_REF_POLY_MASK;
}
static const int DT_TILE_LOOKUP_SIZE = DT_MAX_TILES/4;
class dtTiledNavMesh
{
public:
dtTiledNavMesh();
~dtTiledNavMesh();
bool init(const float* orig, float tileSize, float portalHeight);
bool addTile(int x, int y, unsigned char* data, int dataSize);
bool removeTile(int x, int y);
dtTile* getTile(int x, int y);
const dtTile* getTile(int i) const { return &m_tiles[i]; }
// Finds the nearest navigation polygon around the center location.
// Params:
// center - (in) The center of the search box.
// extents - (in) The extents of the search box.
// Returns: Reference identifier for the polygon, or 0 if no polygons found.
dtTilePolyRef findNearestPoly(const float* center, const float* extents);
// Returns polygons which touch the query box.
// Params:
// center - (in) the center of the search box.
// extents - (in) the extents of the search box.
// polys - (out) array holding the search result.
// maxPolys - (in) The max number of polygons the polys array can hold.
// Returns: Number of polygons in search result array.
int queryPolygons(const float* center, const float* extents,
dtTilePolyRef* polys, const int maxPolys);
bool closestPointToPoly(dtTilePolyRef ref, const float* pos, float* closest) const;
int getPolyNeighbours(dtTilePolyRef ref, dtTilePolyRef* nei, int maxNei) const;
int findPath(dtTilePolyRef startRef, dtTilePolyRef endRef,
dtTilePolyRef* path, const int maxPathSize);
int findStraightPath(const float* startPos, const float* endPos,
const dtTilePolyRef* path, const int pathSize,
float* straightPath, const int maxStraightPathSize);
int raycast(dtTilePolyRef startRef, const float* startPos, const float* endPos,
float& t, dtTilePolyRef* path, const int pathSize);
int findPolysAround(dtTilePolyRef centerRef, const float* centerPos, float radius,
dtTilePolyRef* resultRef, dtTilePolyRef* resultParent,
float* resultCost, unsigned short* resultDepth,
const int maxResult);
float findDistanceToWall(dtTilePolyRef centerRef, const float* centerPos, float maxRadius,
float* hitPos, float* hitNormal);
inline const dtTilePoly* getPolyByRef(dtTilePolyRef ref) const
{
unsigned int salt, it, ip;
decodeId(ref, salt, it, ip);
if (it >= DT_MAX_TILES) return 0;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0;
if (ip >= m_tiles[it].header->npolys) return 0;
return &m_tiles[it].header->polys[ip];
}
inline const float* getPolyVertsByRef(dtTilePolyRef ref) const
{
unsigned int salt, it, ip;
decodeId(ref, salt, it, ip);
if (it >= DT_MAX_TILES) return 0;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0;
if (ip >= m_tiles[it].header->npolys) return 0;
return m_tiles[it].header->verts;
}
private:
dtTilePolyRef getTileId(dtTile* tile);
dtTile* getNeighbourTile(int x, int y, int side);
void buildIntLinks(dtTile* tile);
void buildExtLinks(dtTile* tile, dtTile* target, int side);
void removeExtLinks(dtTile* tile, int side);
void createConnections(dtTile* tilea, dtTile* tileb, int sidea);
void removeConnections(dtTile* tile, int side);
int queryTilePolygons(dtTile* tile, const float* qmin, const float* qmax,
dtTilePolyRef* polys, const int maxPolys);
int findConnectingPolys(const float* va, const float* vb,
dtTile* tile, int side,
dtTilePolyRef* con, float* conarea, int maxcon);
float getCost(dtTilePolyRef prev, dtTilePolyRef from, dtTilePolyRef to) const;
float getHeuristic(dtTilePolyRef from, dtTilePolyRef to) const;
// Returns portal points between two polygons.
bool getPortalPoints(dtTilePolyRef from, dtTilePolyRef to, float* left, float* right) const;
float m_orig[3];
float m_tileSize;
float m_portalHeight;
dtTile* m_posLookup[DT_TILE_LOOKUP_SIZE];
dtTile* m_nextFree;
dtTile m_tiles[DT_MAX_TILES];
dtTileLink* m_tmpLinks;
int m_ntmpLinks;
class dtTileNodePool* m_nodePool;
class dtTileNodeQueue* m_openList;
};
#endif // DETOURTILEDNAVMESH_H

View File

@ -0,0 +1,9 @@
#ifndef DETOURTILEDNAVMESHBUILDER_H
#define DETOURTILEDNAVMESHBUILDER_H
bool dtCreateNavMeshTileData(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, int tileSize, int walkableClimb,
unsigned char** outData, int* outDataSize);
#endif // DETOURTILEDNAVMESHBUILDER_H

View File

@ -186,3 +186,244 @@ void dtDebugDrawStatNavMesh(const dtStatNavMesh* mesh)
glEnd();
glPointSize(1.0f);
}
static void drawTile(const dtTileHeader* header)
{
const float col[4] = {0,0,0,0.25f};
glBegin(GL_LINES);
drawBoxWire(header->bmin[0],header->bmin[1],header->bmin[2],
header->bmax[0],header->bmax[1],header->bmax[2], col);
glEnd();
glBegin(GL_TRIANGLES);
for (int i = 0; i < header->npolys; ++i)
{
const dtTilePoly* p = &header->polys[i];
glColor4ub(0,196,255,64);
unsigned short vi[3];
for (int j = 2; j < (int)p->nv; ++j)
{
vi[0] = p->v[0];
vi[1] = p->v[j-1];
vi[2] = p->v[j];
for (int k = 0; k < 3; ++k)
{
const float* v = &header->verts[vi[k]*3];
glVertex3f(v[0], v[1]+0.2f, v[2]);
}
}
}
glEnd();
// Draw tri boundaries
glLineWidth(1.5f);
glBegin(GL_LINES);
for (int i = 0; i < header->npolys; ++i)
{
const dtTilePoly* p = &header->polys[i];
for (int j = 0, nj = (int)p->nv; j < nj; ++j)
{
if (p->n[j] == 0) continue;
if (p->n[j] & 0x8000)
{
bool con = false;
for (int k = 0; k < p->nlinks; ++k)
{
if (header->links[p->links+k].e == j)
{
con = true;
break;
}
}
if (con)
glColor4ub(255,255,255,128);
else
glColor4ub(0,0,0,128);
}
else
glColor4ub(0,48,64,32);
/*
{
// Portal
int side = (p->n[j] >> 13) & 3;
int i = p->n[j] & 0x1fff;
if (!header->portals[side][i].ncon) continue;
}*/
int vi[2];
vi[0] = p->v[j];
vi[1] = p->v[(j+1) % nj];
for (int k = 0; k < 2; ++k)
{
const float* v = &header->verts[vi[k]*3];
glVertex3f(v[0], v[1]+0.21f, v[2]);
}
}
}
glEnd();
// Draw boundaries
glLineWidth(2.5f);
glColor4ub(0,48,64,220);
glBegin(GL_LINES);
for (int i = 0; i < header->npolys; ++i)
{
const dtTilePoly* p = &header->polys[i];
for (int j = 0, nj = (int)p->nv; j < nj; ++j)
{
if (p->n[j] != 0)
{
/* if (p->n[j] & 0x8000)
{
// Portal
int side = (p->n[j] >> 13) & 3;
int i = p->n[j] & 0x1fff;
if (header->portals[side][i].ncon) continue;
}
else*/
continue;
}
int vi[2];
vi[0] = p->v[j];
vi[1] = p->v[(j+1) % nj];
for (int k = 0; k < 2; ++k)
{
const float* v = &header->verts[vi[k]*3];
glVertex3f(v[0], v[1]+0.21f, v[2]);
}
}
}
glEnd();
glLineWidth(1.0f);
glPointSize(3.0f);
glColor4ub(0,0,0,196);
glBegin(GL_POINTS);
for (int i = 0; i < header->nverts; ++i)
{
const float* v = &header->verts[i*3];
glVertex3f(v[0], v[1]+0.21f, v[2]);
}
glEnd();
glPointSize(1.0f);
// Draw portals
/* glBegin(GL_LINES);
for (int i = 0; i < header->nportals[0]; ++i)
{
const dtTilePortal* p = &header->portals[0][i];
if (p->ncon)
glColor4ub(255,255,255,192);
else
glColor4ub(255,0,0,64);
glVertex3f(header->bmax[0]-0.1f, p->bmin[1], p->bmin[0]);
glVertex3f(header->bmax[0]-0.1f, p->bmax[1], p->bmin[0]);
glVertex3f(header->bmax[0]-0.1f, p->bmax[1], p->bmin[0]);
glVertex3f(header->bmax[0]-0.1f, p->bmax[1], p->bmax[0]);
glVertex3f(header->bmax[0]-0.1f, p->bmax[1], p->bmax[0]);
glVertex3f(header->bmax[0]-0.1f, p->bmin[1], p->bmax[0]);
glVertex3f(header->bmax[0]-0.1f, p->bmin[1], p->bmax[0]);
glVertex3f(header->bmax[0]-0.1f, p->bmin[1], p->bmin[0]);
}
for (int i = 0; i < header->nportals[1]; ++i)
{
const dtTilePortal* p = &header->portals[1][i];
if (p->ncon)
glColor4ub(255,255,255,192);
else
glColor4ub(255,0,0,64);
glVertex3f(p->bmin[0], p->bmin[1], header->bmax[2]-0.1f);
glVertex3f(p->bmin[0], p->bmax[1], header->bmax[2]-0.1f);
glVertex3f(p->bmin[0], p->bmax[1], header->bmax[2]-0.1f);
glVertex3f(p->bmax[0], p->bmax[1], header->bmax[2]-0.1f);
glVertex3f(p->bmax[0], p->bmax[1], header->bmax[2]-0.1f);
glVertex3f(p->bmax[0], p->bmin[1], header->bmax[2]-0.1f);
glVertex3f(p->bmax[0], p->bmin[1], header->bmax[2]-0.1f);
glVertex3f(p->bmin[0], p->bmin[1], header->bmax[2]-0.1f);
}
for (int i = 0; i < header->nportals[2]; ++i)
{
const dtTilePortal* p = &header->portals[2][i];
if (p->ncon)
glColor4ub(255,255,255,192);
else
glColor4ub(255,0,0,64);
glVertex3f(header->bmin[0]+0.1f, p->bmin[1], p->bmin[0]);
glVertex3f(header->bmin[0]+0.1f, p->bmax[1], p->bmin[0]);
glVertex3f(header->bmin[0]+0.1f, p->bmax[1], p->bmin[0]);
glVertex3f(header->bmin[0]+0.1f, p->bmax[1], p->bmax[0]);
glVertex3f(header->bmin[0]+0.1f, p->bmax[1], p->bmax[0]);
glVertex3f(header->bmin[0]+0.1f, p->bmin[1], p->bmax[0]);
glVertex3f(header->bmin[0]+0.1f, p->bmin[1], p->bmax[0]);
glVertex3f(header->bmin[0]+0.1f, p->bmin[1], p->bmin[0]);
}
for (int i = 0; i < header->nportals[3]; ++i)
{
const dtTilePortal* p = &header->portals[3][i];
if (p->ncon)
glColor4ub(255,255,255,192);
else
glColor4ub(255,0,0,64);
glVertex3f(p->bmin[0], p->bmin[1], header->bmin[2]+0.1f);
glVertex3f(p->bmin[0], p->bmax[1], header->bmin[2]+0.1f);
glVertex3f(p->bmin[0], p->bmax[1], header->bmin[2]+0.1f);
glVertex3f(p->bmax[0], p->bmax[1], header->bmin[2]+0.1f);
glVertex3f(p->bmax[0], p->bmax[1], header->bmin[2]+0.1f);
glVertex3f(p->bmax[0], p->bmin[1], header->bmin[2]+0.1f);
glVertex3f(p->bmax[0], p->bmin[1], header->bmin[2]+0.1f);
glVertex3f(p->bmin[0], p->bmin[1], header->bmin[2]+0.1f);
}
glEnd();*/
}
void dtDebugDrawTiledNavMesh(const dtTiledNavMesh* mesh)
{
if (!mesh) return;
for (int i = 0; i < DT_MAX_TILES; ++i)
{
const dtTile* tile = mesh->getTile(i);
if (!tile->header) continue;
drawTile(tile->header);
}
}
void dtDebugDrawTiledNavMeshPoly(const dtTiledNavMesh* mesh, dtTilePolyRef ref, const float* col)
{
const dtTilePoly* p = mesh->getPolyByRef(ref);
if (!p) return;
const float* verts = mesh->getPolyVertsByRef(ref);
glColor4f(col[0],col[1],col[2],0.25f);
glBegin(GL_TRIANGLES);
unsigned short vi[3];
for (int j = 2; j < (int)p->nv; ++j)
{
vi[0] = p->v[0];
vi[1] = p->v[j-1];
vi[2] = p->v[j];
for (int k = 0; k < 3; ++k)
{
const float* v = &verts[vi[k]*3];
glVertex3f(v[0], v[1]+0.2f, v[2]);
}
}
glEnd();
}

View File

@ -1204,7 +1204,7 @@ int dtStatNavMesh::findPolysAround(dtPolyRef centerRef, const float* centerPos,
if (resultCost)
resultCost[n] = actualNode->total;
if (resultDepth)
resultDepth[n] = (unsigned short)actualNode->cost;
resultDepth[n] = actualNode->cost;
++n;
}
actualNode->flags = dtNode::OPEN;
@ -1220,7 +1220,7 @@ int dtStatNavMesh::findPolysAround(dtPolyRef centerRef, const float* centerPos,
// Returns polygons which are withing certain radius from the query location.
int dtStatNavMesh::queryPolygons(const float* center, const float* extents,
unsigned short* ids, const int maxIds)
dtPolyRef* polys, const int maxIds)
{
if (!m_header) return 0;
@ -1256,7 +1256,7 @@ int dtStatNavMesh::queryPolygons(const float* center, const float* extents,
{
if (n < maxIds)
{
ids[n] = (unsigned short)node->i;
polys[n] = (dtPolyRef)node->i;
n++;
}
}
@ -1278,7 +1278,7 @@ dtPolyRef dtStatNavMesh::findNearestPoly(const float* center, const float* exten
if (!m_header) return 0;
// Get nearby polygons from proximity grid.
unsigned short polys[128];
dtPolyRef polys[128];
int npolys = queryPolygons(center, extents, polys, 128);
// Find nearest polygon amongst the nearby polygons.
@ -1286,7 +1286,7 @@ dtPolyRef dtStatNavMesh::findNearestPoly(const float* center, const float* exten
float nearestDistanceSqr = FLT_MAX;
for (int i = 0; i < npolys; ++i)
{
dtPolyRef ref = (dtPolyRef)polys[i];
dtPolyRef ref = polys[i];
float closest[3];
if (!closestPointToPoly(ref, center, closest))
continue;
@ -1301,30 +1301,6 @@ dtPolyRef dtStatNavMesh::findNearestPoly(const float* center, const float* exten
return nearest;
}
bool dtStatNavMesh::getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const
{
const dtPoly* fromPoly = getPolyByRef(from);
if (!fromPoly)
return false;
// Find common edge between the polygons and returns the segment end points.
for (unsigned i = 0, j = (int)fromPoly->nv - 1; i < (int)fromPoly->nv; j = i++)
{
unsigned short neighbour = fromPoly->n[j];
if (neighbour == to)
{
const float* left = getVertex(fromPoly->v[j]);
const float* right = getVertex(fromPoly->v[i]);
mid[0] = (left[0]+right[0])*0.5f;
mid[1] = (left[1]+right[1])*0.5f;
mid[2] = (left[2]+right[2])*0.5f;
return true;
}
}
return false;
}
bool dtStatNavMesh::getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right) const
{
const dtPoly* fromPoly = getPolyByRef(from);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,190 @@
//
// 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DetourTiledNavMesh.h"
template<class T> inline T abs(T a) { return a < 0 ? -a : a; }
template<class T> inline T min(T a, T b) { return a < b ? a : b; }
template<class T> inline T max(T a, T b) { return a > b ? a : b; }
bool dtCreateNavMeshTileData(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, 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;
/* int nportals[4] = {0,0,0,0};
// Find portals.
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];
if (va[0] == tileSize && vb[0] == tileSize)
nportals[0]++; // x+
else if (va[2] == tileSize && vb[2] == tileSize)
nportals[1]++; // z+
else if (va[0] == 0 && vb[0] == 0)
nportals[2]++; // x-
else if (va[2] == 0 && vb[2] == 0)
nportals[3]++; // z-
}
}
*/
// Find portals.
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-
}
}
// Calculate data size
const int headerSize = sizeof(dtTileHeader);
const int vertsSize = sizeof(float)*3*nverts;
const int polysSize = sizeof(dtTilePoly)*npolys;
// const int portalsSize = sizeof(dtTilePortal)*(nportals[0]+nportals[1]+nportals[2]+nportals[3]);
// const int dataSize = headerSize + vertsSize + polysSize + portalsSize;
const int linksSize = sizeof(dtTileLink)*(nedges + nportals*2);
const int dataSize = headerSize + vertsSize + polysSize + linksSize;
unsigned char* data = new unsigned char[dataSize];
if (!data)
return false;
memset(data, 0, dataSize);
dtTileHeader* header = (dtTileHeader*)(data);
float* navVerts = (float*)(data + headerSize);
dtTilePoly* navPolys = (dtTilePoly*)(data + headerSize + vertsSize);
/* dtTilePortal* portals[4];
portals[0] = (dtTilePortal*)(data + headerSize + vertsSize + polysSize);
portals[1] = portals[0] + nportals[0];
portals[2] = portals[1] + nportals[1];
portals[3] = portals[2] + nportals[2];*/
// Store header
header->magic = DT_TILE_NAVMESH_MAGIC;
header->version = DT_TILE_NAVMESH_VERSION;
header->npolys = npolys;
header->nverts = nverts;
header->maxlinks = nedges + nportals*2;
/* header->nportals[0] = nportals[0];
header->nportals[1] = nportals[1];
header->nportals[2] = nportals[2];
header->nportals[3] = nportals[3];*/
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];
// 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 portals.
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;
}
}
*outData = data;
*outDataSize = dataSize;
return true;
}