DETOUR API CHANGE!

- Detour Navmesh supports layers
- Allow to disable Navmesh BV-tree
- Added DetourTileCache
- Cleaned up Recast layer code
- Moved portal edge detection to Recast
- Removed polymesh border offset
- Removed lean heighfield
This commit is contained in:
Mikko Mononen 2011-03-25 09:16:38 +00:00
parent 838d0657bd
commit 1de5e2f119
29 changed files with 3246 additions and 3574 deletions

View File

@ -21,11 +21,13 @@
#include "DetourNavMesh.h"
#include "DetourNavMeshQuery.h"
#include "DetourTileCacheBuilder.h"
enum DrawNavMeshFlags
{
DU_DRAWNAVMESH_OFFMESHCONS = 0x01,
DU_DRAWNAVMESH_CLOSEDLIST = 0x02,
DU_DRAWNAVMESH_COLOR_TILES = 0x04,
};
void duDebugDrawNavMesh(struct duDebugDraw* dd, const dtNavMesh& mesh, unsigned char flags);
@ -35,4 +37,8 @@ void duDebugDrawNavMeshBVTree(struct duDebugDraw* dd, const dtNavMesh& mesh);
void duDebugDrawNavMeshPortals(struct duDebugDraw* dd, const dtNavMesh& mesh);
void duDebugDrawNavMeshPoly(struct duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef ref, const unsigned int col);
void duDebugDrawTileCacheLayer(struct duDebugDraw* dd, const dtTileCacheLayer& layer,
const float* bmin, const float* bmax,
const float cs, const float ch, const int idx);
#endif // DETOURDEBUGDRAW_H

View File

@ -29,8 +29,7 @@ void duDebugDrawCompactHeightfieldSolid(struct duDebugDraw* dd, const struct rcC
void duDebugDrawCompactHeightfieldRegions(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
void duDebugDrawCompactHeightfieldDistance(struct duDebugDraw* dd, const struct rcCompactHeightfield& chf);
void duDebugDrawLeanHeightfieldSolid(duDebugDraw* dd, const struct rcLeanHeightfield& lhf);
void duDebugDrawHeightfieldLayer(duDebugDraw* dd, const struct rcHeightfieldLayer& layer, const int idx);
void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset);
void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset);

View File

@ -130,7 +130,7 @@ void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
{
if (!dd) return;
dd->begin(DU_DRAW_TRIS);
dd->begin(DU_DRAW_QUADS);
duAppendBox(dd, minx,miny,minz, maxx,maxy,maxz, fcol);
dd->end();
}

View File

@ -121,6 +121,8 @@ static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMesh
{
dtPolyRef base = mesh.getPolyRefBase(tile);
int tileNum = mesh.decodePolyIdTile(base);
dd->depthMask(false);
dd->begin(DU_DRAW_TRIS);
@ -137,10 +139,17 @@ static void drawMeshTile(duDebugDraw* dd, const dtNavMesh& mesh, const dtNavMesh
col = duRGBA(255,196,0,64);
else
{
if (p->getArea() == 0) // Treat zero area type as default.
col = duRGBA(0,192,255,64);
if (flags & DU_DRAWNAVMESH_COLOR_TILES)
{
col = duIntToCol(tileNum, 128);
}
else
col = duIntToCol(p->getArea(), 64);
{
if (p->getArea() == 0) // Treat zero area type as default.
col = duRGBA(0,192,255,64);
else
col = duIntToCol(p->getArea(), 64);
}
}
for (int j = 0; j < pd->triCount; ++j)
@ -334,7 +343,7 @@ void duDebugDrawNavMeshBVTree(duDebugDraw* dd, const dtNavMesh& mesh)
static void drawMeshTilePortal(duDebugDraw* dd, const dtMeshTile* tile)
{
// Draw portals
const float padx = 0.02f;
const float padx = 0.04f;
const float pady = tile->header->walkableClimb;
dd->begin(DU_DRAW_LINES, 2.0f);
@ -464,3 +473,87 @@ void duDebugDrawNavMeshPoly(duDebugDraw* dd, const dtNavMesh& mesh, dtPolyRef re
}
void duDebugDrawTileCacheLayer(struct duDebugDraw* dd, const dtTileCacheLayer& layer,
const float* bmin, const float* bmax,
const float cs, const float ch, const int idx)
{
const int w = (int)layer.header->width;
const int h = (int)layer.header->height;
unsigned int color = duIntToCol(idx+1, 255);
// Layer bounds
float lbmin[3], lbmax[3];
lbmin[0] = bmin[0] + layer.header->minx*cs;
lbmin[1] = bmin[1];
lbmin[2] = bmin[2] + layer.header->miny*cs;
lbmax[0] = bmin[0] + (layer.header->maxx+1)*cs;
lbmax[1] = bmax[1];
lbmax[2] = bmin[2] + (layer.header->maxy+1)*cs;
duDebugDrawBoxWire(dd, lbmin[0],lbmin[1],lbmin[2], lbmax[0],lbmax[1],lbmax[2], duTransCol(color,128), 2.0f);
// Layer height
dd->begin(DU_DRAW_QUADS);
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
const int idx = x+y*w;
const int h = (int)layer.heights[idx];
if (h == 0xff) continue;
const unsigned char area = layer.areas[idx];
unsigned int col;
if (area == 63)
col = duLerpCol(color, duRGBA(0,192,255,64), 32);
else if (area == 0)
col = duLerpCol(color, duRGBA(0,0,0,64), 32);
else
col = duLerpCol(color, duIntToCol(area, 255), 32);
const float fx = bmin[0] + x*cs;
const float fy = bmin[1] + (h+1)*ch;
const float fz = bmin[2] + y*cs;
dd->vertex(fx, fy, fz, col);
dd->vertex(fx, fy, fz+cs, col);
dd->vertex(fx+cs, fy, fz+cs, col);
dd->vertex(fx+cs, fy, fz, col);
}
}
dd->end();
// Portals
unsigned int pcol = duRGBA(255,255,255,255);
const int segs[4*4] = {0,0,0,1, 0,1,1,1, 1,1,1,0, 1,0,0,0};
// Layer portals
dd->begin(DU_DRAW_LINES, 2.0f);
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
const int idx = x+y*w;
const int h = (int)layer.heights[idx];
if (h == 0xff) continue;
for (int dir = 0; dir < 4; ++dir)
{
if (layer.cons[idx] & (1<<(dir+4)))
{
const int* seg = &segs[dir*4];
const float ax = bmin[0] + (x+seg[0])*cs;
const float ay = bmin[1] + (h+2)*ch;
const float az = bmin[2] + (y+seg[1])*cs;
const float bx = bmin[0] + (x+seg[2])*cs;
const float by = bmin[1] + (h+2)*ch;
const float bz = bmin[2] + (y+seg[3])*cs;
dd->vertex(ax, ay, az, pcol);
dd->vertex(bx, by, bz, pcol);
}
}
}
}
dd->end();
}

View File

@ -326,61 +326,6 @@ void duDebugDrawCompactHeightfieldDistance(duDebugDraw* dd, const rcCompactHeigh
dd->end();
}
void duDebugDrawLeanHeightfieldSolid(duDebugDraw* dd, const rcLeanHeightfield& lhf)
{
if (!dd) return;
const float cs = lhf.cs;
const float ch = lhf.ch;
const int headerSize = rcAlign4(sizeof(rcLeanHeightfield));
const int countsSize = rcAlign4(sizeof(unsigned char)*lhf.width*lhf.height);
const int floorsSize = rcAlign4(sizeof(unsigned short)*lhf.spanCount);
const unsigned char* data = (const unsigned char*)&lhf;
const unsigned char* counts = (const unsigned char*)&data[headerSize];
const unsigned short* floors = (const unsigned short*)&data[headerSize+countsSize];
const unsigned char* areas = (const unsigned char*)&data[headerSize+countsSize+floorsSize];
dd->begin(DU_DRAW_QUADS);
unsigned short mask = (1<<RC_SPAN_HEIGHT_BITS)-1;
int idx = 0;
for (int y = 0; y < lhf.height; ++y)
{
for (int x = 0; x < lhf.width; ++x)
{
const float fx = lhf.bmin[0] + x*cs;
const float fz = lhf.bmin[2] + y*cs;
const int count = counts[x+y*lhf.width];
for (int i = idx, ni = idx+count; i < ni; ++i)
{
const int h = floors[i] & mask;
unsigned char area = areas[i];
unsigned int color;
if (area == RC_WALKABLE_AREA)
color = duRGBA(0,192,255,64);
else if (area == RC_NULL_AREA)
color = duRGBA(0,0,0,64);
else
color = duIntToCol(area, 255);
const float fy = lhf.bmin[1] + (h+1)*ch;
dd->vertex(fx, fy, fz, color);
dd->vertex(fx, fy, fz+cs, color);
dd->vertex(fx+cs, fy, fz+cs, color);
dd->vertex(fx+cs, fy, fz, color);
}
idx += count;
}
}
dd->end();
}
static void drawLayerPortals(duDebugDraw* dd, const rcHeightfieldLayer* layer, const unsigned int color)
{
const float cs = layer->cs;
@ -422,116 +367,68 @@ static void drawLayerPortals(duDebugDraw* dd, const rcHeightfieldLayer* layer, c
dd->end();
}
void duDebugDrawHeightfieldLayer(duDebugDraw* dd, const struct rcHeightfieldLayer& layer, const int idx)
{
const float cs = layer.cs;
const float ch = layer.ch;
const int w = layer.width;
const int h = layer.height;
unsigned int color = duIntToCol(idx+1, 255);
// Layer bounds
float bmin[3], bmax[3];
bmin[0] = layer.bmin[0] + layer.minx*cs;
bmin[1] = layer.bmin[1];
bmin[2] = layer.bmin[2] + layer.miny*cs;
bmax[0] = layer.bmin[0] + (layer.maxx+1)*cs;
bmax[1] = layer.bmax[1];
bmax[2] = layer.bmin[2] + (layer.maxy+1)*cs;
duDebugDrawBoxWire(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duTransCol(color,128), 2.0f);
// Layer height
dd->begin(DU_DRAW_QUADS);
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
const int idx = x+y*w;
const int h = (int)layer.heights[idx];
if (h == 0xff) continue;
const unsigned char area = layer.areas[idx];
unsigned int col;
if (area == RC_WALKABLE_AREA)
col = duLerpCol(color, duRGBA(0,192,255,64), 32);
else if (area == RC_NULL_AREA)
col = duLerpCol(color, duRGBA(0,0,0,64), 32);
else
col = duLerpCol(color, duIntToCol(area, 255), 32);
const float fx = layer.bmin[0] + x*cs;
const float fy = layer.bmin[1] + (h+1)*ch;
const float fz = layer.bmin[2] + y*cs;
dd->vertex(fx, fy, fz, col);
dd->vertex(fx, fy, fz+cs, col);
dd->vertex(fx+cs, fy, fz+cs, col);
dd->vertex(fx+cs, fy, fz, col);
}
}
dd->end();
// Portals
drawLayerPortals(dd, &layer, color);
}
void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset)
{
if (!dd) return;
for (int i = 0; i < lset.nlayers; ++i)
{
const rcHeightfieldLayer* layer = &lset.layers[i];
const float cs = layer->cs;
const float ch = layer->ch;
const int w = layer->width;
const int h = layer->height;
unsigned int color = duIntToCol(i+1, 255);
// Layer bounds
float bmin[3], bmax[3];
rcVcopy(bmin, layer->bmin);
rcVcopy(bmax, layer->bmax);
duDebugDrawBoxWire(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duTransCol(color,128), 2.0f);
// Layer height
dd->begin(DU_DRAW_QUADS);
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
const int idx = x+y*w;
const int h = (int)layer->heights[idx];
if (h == 0xff) continue;
const unsigned char area = layer->areas[idx];
unsigned int col;
if (area == RC_WALKABLE_AREA)
col = duLerpCol(color, duRGBA(0,192,255,64), 32);
else if (area == RC_NULL_AREA)
col = duLerpCol(color, duRGBA(0,0,0,64), 32);
else
col = duLerpCol(color, duIntToCol(area, 255), 32);
const float fx = layer->bmin[0] + x*cs;
const float fy = layer->bmin[1] + (h+1)*ch;
const float fz = layer->bmin[2] + y*cs;
dd->vertex(fx, fy, fz, col);
dd->vertex(fx, fy, fz+cs, col);
dd->vertex(fx+cs, fy, fz+cs, col);
dd->vertex(fx+cs, fy, fz, col);
}
}
dd->end();
// Portals
drawLayerPortals(dd, layer, color);
}
}
void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset)
{
if (!dd) return;
for (int i = 0; i < lset.nlayers; ++i)
{
const rcHeightfieldLayer* layer = &lset.layers[i];
const float cs = layer->cs;
const float ch = layer->ch;
const int w = layer->width;
const int h = layer->height;
unsigned int color = duIntToCol(i+1, 255);
// Layer bounds
float bmin[3], bmax[3];
rcVcopy(bmin, layer->bmin);
rcVcopy(bmax, layer->bmax);
duDebugDrawBoxWire(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duTransCol(color,128), 2.0f);
// Layer height
dd->begin(DU_DRAW_QUADS);
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
const int idx = x+y*w;
const int h = (int)layer->heights[idx];
if (h == 0xff) continue;
const unsigned char area = layer->regs ? layer->regs[idx]+1 : 1;
unsigned int col = duLerpCol(color, duIntToCol(area, 255), 32);
const float fx = layer->bmin[0] + x*cs;
const float fy = layer->bmin[1] + (h+1)*ch;
const float fz = layer->bmin[2] + y*cs;
dd->vertex(fx, fy, fz, col);
dd->vertex(fx, fy, fz+cs, col);
dd->vertex(fx+cs, fy, fz+cs, col);
dd->vertex(fx+cs, fy, fz, col);
}
}
dd->end();
// Portals
drawLayerPortals(dd, layer, color);
}
duDebugDrawHeightfieldLayer(dd, lset.layers[i], i);
}
/*
void duDebugDrawLayerContours(duDebugDraw* dd, const struct rcLayerContourSet& lcset)
{
if (!dd) return;
@ -542,6 +439,8 @@ void duDebugDrawLayerContours(duDebugDraw* dd, const struct rcLayerContourSet& l
const unsigned char a = 255;// (unsigned char)(alpha*255.0f);
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
dd->begin(DU_DRAW_LINES, 2.0f);
for (int i = 0; i < lcset.nconts; ++i)
@ -564,7 +463,21 @@ void duDebugDrawLayerContours(duDebugDraw* dd, const struct rcLayerContourSet& l
const float bz = orig[2] + vb[2]*cs;
unsigned int col = color;
if ((va[3] & 0xf) != 0xf)
{
col = duRGBA(255,255,255,128);
int d = va[3] & 0xf;
const float cx = (ax+bx)*0.5f;
const float cy = (ay+by)*0.5f;
const float cz = (az+bz)*0.5f;
const float dx = cx + offs[d*2+0]*2*cs;
const float dy = cy;
const float dz = cz + offs[d*2+1]*2*cs;
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
}
duAppendArrow(dd, ax,ay,az, bx,by,bz, 0.0f, cs*0.5f, col);
}
@ -604,6 +517,8 @@ void duDebugDrawLayerPolyMesh(duDebugDraw* dd, const struct rcLayerPolyMesh& lme
const float ch = lmesh.ch;
const float* orig = lmesh.bmin;
const int offs[2*4] = {-1,0, 0,1, 1,0, 0,-1};
dd->begin(DU_DRAW_TRIS);
for (int i = 0; i < lmesh.npolys; ++i)
@ -647,13 +562,8 @@ void duDebugDrawLayerPolyMesh(duDebugDraw* dd, const struct rcLayerPolyMesh& lme
{
if (p[j] == RC_MESH_NULL_IDX) break;
if (p[nvp+j] & 0x8000) continue;
int vi[2];
vi[0] = p[j];
if (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX)
vi[1] = p[0];
else
vi[1] = p[j+1];
const int nj = (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX) ? 0 : j+1;
int vi[2] = {p[j], p[nj]};
for (int k = 0; k < 2; ++k)
{
@ -677,16 +587,37 @@ void duDebugDrawLayerPolyMesh(duDebugDraw* dd, const struct rcLayerPolyMesh& lme
{
if (p[j] == RC_MESH_NULL_IDX) break;
if ((p[nvp+j] & 0x8000) == 0) continue;
int vi[2];
vi[0] = p[j];
if (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX)
vi[1] = p[0];
else
vi[1] = p[j+1];
const int nj = (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX) ? 0 : j+1;
int vi[2] = {p[j], p[nj]};
unsigned int col = colb;
if ((p[nvp+j] & 0xff) != 0xff)
if ((p[nvp+j] & 0xf) != 0xf)
{
const unsigned short* va = &lmesh.verts[vi[0]*3];
const unsigned short* vb = &lmesh.verts[vi[1]*3];
const float ax = orig[0] + va[0]*cs;
const float ay = orig[1] + (va[1]+1+(i&1))*ch;
const float az = orig[2] + va[2]*cs;
const float bx = orig[0] + vb[0]*cs;
const float by = orig[1] + (vb[1]+1+(i&1))*ch;
const float bz = orig[2] + vb[2]*cs;
const float cx = (ax+bx)*0.5f;
const float cy = (ay+by)*0.5f;
const float cz = (az+bz)*0.5f;
int d = p[nvp+j] & 0xf;
const float dx = cx + offs[d*2+0]*2*cs;
const float dy = cy;
const float dz = cz + offs[d*2+1]*2*cs;
dd->vertex(cx,cy,cz,duRGBA(255,0,0,255));
dd->vertex(dx,dy,dz,duRGBA(255,0,0,255));
col = duRGBA(255,255,255,128);
}
for (int k = 0; k < 2; ++k)
{
@ -712,7 +643,7 @@ void duDebugDrawLayerPolyMesh(duDebugDraw* dd, const struct rcLayerPolyMesh& lme
}
dd->end();
}
*/
static void getContourCenter(const rcContour* cont, const float* orig, float cs, float ch, float* center)
{
@ -973,13 +904,10 @@ void duDebugDrawPolyMesh(duDebugDraw* dd, const struct rcPolyMesh& mesh)
for (int j = 0; j < nvp; ++j)
{
if (p[j] == RC_MESH_NULL_IDX) break;
if (p[nvp+j] == RC_MESH_NULL_IDX) continue;
int vi[2];
vi[0] = p[j];
if (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX)
vi[1] = p[0];
else
vi[1] = p[j+1];
if (p[nvp+j] & 0x8000) continue;
const int nj = (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX) ? 0 : j+1;
const int vi[2] = {p[j], p[nj]};
for (int k = 0; k < 2; ++k)
{
const unsigned short* v = &mesh.verts[vi[k]*3];
@ -1001,20 +929,20 @@ void duDebugDrawPolyMesh(duDebugDraw* dd, const struct rcPolyMesh& mesh)
for (int j = 0; j < nvp; ++j)
{
if (p[j] == RC_MESH_NULL_IDX) break;
if (p[nvp+j] != RC_MESH_NULL_IDX) continue;
int vi[2];
vi[0] = p[j];
if (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX)
vi[1] = p[0];
else
vi[1] = p[j+1];
if ((p[nvp+j] & 0x8000) == 0) continue;
const int nj = (j+1 >= nvp || p[j+1] == RC_MESH_NULL_IDX) ? 0 : j+1;
const int vi[2] = {p[j], p[nj]};
unsigned int col = colb;
if ((p[nvp+j] & 0xf) != 0xf)
col = duRGBA(255,255,255,128);
for (int k = 0; k < 2; ++k)
{
const unsigned short* v = &mesh.verts[vi[k]*3];
const float x = orig[0] + v[0]*cs;
const float y = orig[1] + (v[1]+1)*ch + 0.1f;
const float z = orig[2] + v[2]*cs;
dd->vertex(x, y, z, colb);
dd->vertex(x, y, z, col);
}
}
}

View File

@ -135,7 +135,7 @@ bool duDumpPolyMeshDetailToObj(rcPolyMeshDetail& dmesh, duFileIO* io)
}
static const int CSET_MAGIC = ('c' << 24) | ('s' << 16) | ('e' << 8) | 't';
static const int CSET_VERSION = 1;
static const int CSET_VERSION = 2;
bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
{
@ -161,6 +161,10 @@ bool duDumpContourSet(struct rcContourSet& cset, duFileIO* io)
io->write(&cset.cs, sizeof(cset.cs));
io->write(&cset.ch, sizeof(cset.ch));
io->write(&cset.width, sizeof(cset.width));
io->write(&cset.height, sizeof(cset.height));
io->write(&cset.borderSize, sizeof(cset.borderSize));
for (int i = 0; i < cset.nconts; ++i)
{
const rcContour& cont = cset.conts[i];
@ -221,6 +225,10 @@ bool duReadContourSet(struct rcContourSet& cset, duFileIO* io)
io->read(&cset.cs, sizeof(cset.cs));
io->read(&cset.ch, sizeof(cset.ch));
io->read(&cset.width, sizeof(cset.width));
io->read(&cset.height, sizeof(cset.height));
io->read(&cset.borderSize, sizeof(cset.borderSize));
for (int i = 0; i < cset.nconts; ++i)
{
rcContour& cont = cset.conts[i];
@ -251,7 +259,7 @@ bool duReadContourSet(struct rcContourSet& cset, duFileIO* io)
static const int CHF_MAGIC = ('r' << 24) | ('c' << 16) | ('h' << 8) | 'f';
static const int CHF_VERSION = 2;
static const int CHF_VERSION = 3;
bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
{
@ -275,6 +283,7 @@ bool duDumpCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
io->write(&chf.walkableHeight, sizeof(chf.walkableHeight));
io->write(&chf.walkableClimb, sizeof(chf.walkableClimb));
io->write(&chf.borderSize, sizeof(chf.borderSize));
io->write(&chf.maxDistance, sizeof(chf.maxDistance));
io->write(&chf.maxRegions, sizeof(chf.maxRegions));
@ -341,7 +350,8 @@ bool duReadCompactHeightfield(struct rcCompactHeightfield& chf, duFileIO* io)
io->read(&chf.walkableHeight, sizeof(chf.walkableHeight));
io->read(&chf.walkableClimb, sizeof(chf.walkableClimb));
io->write(&chf.borderSize, sizeof(chf.borderSize));
io->read(&chf.maxDistance, sizeof(chf.maxDistance));
io->read(&chf.maxRegions, sizeof(chf.maxRegions));
@ -412,7 +422,6 @@ void duLogBuildTimes(rcContext& ctx, const int totalTimeUsec)
ctx.log(RC_LOG_PROGRESS, "Build Times");
logLine(ctx, RC_TIMER_RASTERIZE_TRIANGLES, "- Rasterize", pc);
logLine(ctx, RC_TIMER_BUILD_LEANHEIGHTFIELD, "- Build Lean", pc);
logLine(ctx, RC_TIMER_BUILD_COMPACTHEIGHTFIELD, "- Build Compact", pc);
logLine(ctx, RC_TIMER_FILTER_BORDER, "- Filter Border", pc);
logLine(ctx, RC_TIMER_FILTER_WALKABLE, "- Filter Walkable", pc);

View File

@ -19,6 +19,7 @@
#ifndef DETOURCOMMON_H
#define DETOURCOMMON_H
template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }

View File

@ -20,6 +20,8 @@
#define DETOURNAVMESH_H
#include "DetourAlloc.h"
#include "DetourStatus.h"
// Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
// It is also recommended to change dtHashRef() to proper 64-bit hash too.
@ -34,7 +36,7 @@ typedef unsigned int dtTileRef;
static const int DT_VERTS_PER_POLYGON = 6;
static const int DT_NAVMESH_MAGIC = 'D'<<24 | 'N'<<16 | 'A'<<8 | 'V'; //'DNAV';
static const int DT_NAVMESH_VERSION = 6;
static const int DT_NAVMESH_VERSION = 7;
static const int DT_NAVMESH_STATE_MAGIC = 'D'<<24 | 'N'<<16 | 'M'<<8 | 'S'; //'DNMS';
static const int DT_NAVMESH_STATE_VERSION = 1;
@ -67,49 +69,6 @@ enum dtPolyTypes
};
typedef unsigned int dtStatus;
// High level status.
static const unsigned int DT_FAILURE = 1u << 31; // Operation failed.
static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed.
static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress.
// Detail information for status.
static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff;
static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
// Returns true of status is success.
inline bool dtStatusSucceed(dtStatus status)
{
return (status & DT_SUCCESS) != 0;
}
// Returns true of status is failure.
inline bool dtStatusFailed(dtStatus status)
{
return (status & DT_FAILURE) != 0;
}
// Returns true of status is in progress.
inline bool dtStatusInProgress(dtStatus status)
{
return (status & DT_IN_PROGRESS) != 0;
}
// Returns true if specific detail is set.
inline bool dtStatusDetail(dtStatus status, unsigned int detail)
{
return (status & detail) != 0;
}
// Structure describing the navigation polygon data.
struct dtPoly
{
@ -164,7 +123,7 @@ struct dtMeshHeader
{
int magic; // Magic number, used to identify the data.
int version; // Data version number.
int x, y; // Location of the time on the grid.
int x, y, layer; // Location of the tile on the grid.
unsigned int userId; // User ID of the tile.
int polyCount; // Number of polygons in the tile.
int vertCount; // Number of vertices in the tile.
@ -265,14 +224,17 @@ public:
// Params:
// x,y - (in) Location of the tile to get.
// Returns: pointer to tile if tile exists or 0 tile does not exists.
const dtMeshTile* getTileAt(int x, int y) const;
const dtMeshTile* getTileAt(const int x, const int y, const int layer) const;
int getTilesAt(const int x, const int y,
dtMeshTile const** tiles, const int maxTiles) const;
// Returns reference to tile at specified location.
// Params:
// x,y - (in) Location of the tile to get.
// Returns: reference to tile if tile exists or 0 tile does not exists.
dtTileRef getTileRefAt(int x, int y) const;
dtTileRef getTileRefAt(int x, int y, int layer) const;
// Returns tile references of a tile based on tile pointer.
dtTileRef getTileRef(const dtMeshTile* tile) const;
@ -388,7 +350,13 @@ private:
dtMeshTile* getTile(int i);
// Returns neighbour tile based on side.
dtMeshTile* getNeighbourTileAt(int x, int y, int side) const;
int getTilesAt(const int x, const int y,
dtMeshTile** tiles, const int maxTiles) const;
// Returns neighbour tile based on side.
int getNeighbourTilesAt(const int x, const int y, const int side,
dtMeshTile** tiles, const int maxTiles) const;
// Returns all polygons in neighbour tile based on portal defined by the segment.
int findConnectingPolys(const float* va, const float* vb,
const dtMeshTile* tile, int side,
@ -405,7 +373,7 @@ private:
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
// Removes external links at specified side.
void unconnectExtLinks(dtMeshTile* tile, int side);
void unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target);
// TODO: These methods are duplicates from dtNavMeshQuery, but are needed for off-mesh connection finding.

View File

@ -51,7 +51,7 @@ struct dtNavMeshCreateParams
int offMeshConCount; // Number of off-mesh connections
// Tile location
unsigned int userId; // User ID bound to the tile.
int tileX, tileY; // Tile location (tile coords).
int tileX, tileY, tileLayer; // Tile location (tile coords).
float bmin[3], bmax[3]; // Tile bounds (wu).
// Settings
float walkableHeight; // Agent height (wu).
@ -59,7 +59,7 @@ struct dtNavMeshCreateParams
float walkableClimb; // Agent max climb (wu).
float cs; // Cell size (xz) (wu).
float ch; // Cell height (y) (wu).
int tileSize; // Tile size (width & height) (vx).
bool buildBvTree; // Flag indicating if BVTree for polygon query should be build.
};
// Build navmesh data from given input data.

View File

@ -20,6 +20,7 @@
#define DETOURNAVMESHQUERY_H
#include "DetourNavMesh.h"
#include "DetourStatus.h"
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.

View File

@ -0,0 +1,64 @@
//
// Copyright (c) 2009-2010 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 DETOURSTATUS_H
#define DETOURSTATUS_H
typedef unsigned int dtStatus;
// High level status.
static const unsigned int DT_FAILURE = 1u << 31; // Operation failed.
static const unsigned int DT_SUCCESS = 1u << 30; // Operation succeed.
static const unsigned int DT_IN_PROGRESS = 1u << 29; // Operation still in progress.
// Detail information for status.
static const unsigned int DT_STATUS_DETAIL_MASK = 0x0ffffff;
static const unsigned int DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
static const unsigned int DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
static const unsigned int DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
static const unsigned int DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
// Returns true of status is success.
inline bool dtStatusSucceed(dtStatus status)
{
return (status & DT_SUCCESS) != 0;
}
// Returns true of status is failure.
inline bool dtStatusFailed(dtStatus status)
{
return (status & DT_FAILURE) != 0;
}
// Returns true of status is in progress.
inline bool dtStatusInProgress(dtStatus status)
{
return (status & DT_IN_PROGRESS) != 0;
}
// Returns true if specific detail is set.
inline bool dtStatusDetail(dtStatus status, unsigned int detail)
{
return (status & detail) != 0;
}
#endif // DETOURSTATUS_H

View File

@ -64,6 +64,15 @@ inline bool overlapSlabs(const float* amin, const float* amax,
return false;
}
static float getSlabCoord(const float* va, const int side)
{
if (side == 0 || side == 4)
return va[0];
else if (side == 2 || side == 6)
return va[2];
return 0;
}
static void calcSlabEndPoints(const float* va, const float* vb, float* bmin, float* bmax, const int side)
{
if (side == 0 || side == 4)
@ -251,6 +260,7 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
float amin[2], amax[2];
calcSlabEndPoints(va,vb, amin,amax, side);
const float apos = getSlabCoord(va, side);
// Remove links pointing to 'side' and compact the links array.
float bmin[2], bmax[2];
@ -267,11 +277,18 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
{
// Skip edges which do not point to the right side.
if (poly->neis[j] != m) continue;
// Check if the segments touch.
const float* vc = &tile->verts[poly->verts[j]*3];
const float* vd = &tile->verts[poly->verts[(j+1) % nv]*3];
const float bpos = getSlabCoord(vc, side);
// Segments are not close enough.
if (dtAbs(apos-bpos) > 0.01f)
continue;
// Check if the segments touch.
calcSlabEndPoints(vc,vd, bmin,bmax, side);
if (!overlapSlabs(amin,amax, bmin,bmax, 0.01f, tile->header->walkableClimb)) continue;
// Add return value.
@ -288,9 +305,11 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
return n;
}
void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, int side)
void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target)
{
if (!tile) return;
if (!tile || !target) return;
const unsigned int targetNum = decodePolyIdTile(getTileRef(target));
for (int i = 0; i < tile->header->polyCount; ++i)
{
@ -299,7 +318,8 @@ void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, int side)
unsigned int pj = DT_NULL_LINK;
while (j != DT_NULL_LINK)
{
if (tile->links[j].side == side)
if (tile->links[j].side != 0xff &&
decodePolyIdTile(tile->links[j].ref) == targetNum)
{
// Revove link.
unsigned int nj = tile->links[j].next;
@ -330,19 +350,25 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
dtPoly* poly = &tile->polys[i];
// Create new links.
unsigned short m = DT_EXT_LINK | (unsigned short)side;
// unsigned short m = DT_EXT_LINK | (unsigned short)side;
const int nv = poly->vertCount;
for (int j = 0; j < nv; ++j)
{
// Skip edges which do not point to the right side.
if (poly->neis[j] != m) continue;
// Skip non-portal edges.
if ((poly->neis[j] & DT_EXT_LINK) == 0)
continue;
const int dir = (int)(poly->neis[j] & 0xff);
if (side != -1 && dir != side)
continue;
// Create new links
const float* va = &tile->verts[poly->verts[j]*3];
const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3];
dtPolyRef nei[4];
float neia[4*2];
int nnei = findConnectingPolys(va,vb, target, dtOppositeTile(side), nei,neia,4);
int nnei = findConnectingPolys(va,vb, target, dtOppositeTile(dir), nei,neia,4);
for (int k = 0; k < nnei; ++k)
{
unsigned int idx = allocLink(tile);
@ -351,13 +377,13 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
dtLink* link = &tile->links[idx];
link->ref = nei[k];
link->edge = (unsigned char)j;
link->side = (unsigned char)side;
link->side = (unsigned char)dir;
link->next = poly->firstLink;
poly->firstLink = idx;
// Compress portal limits to a byte value.
if (side == 0 || side == 4)
if (dir == 0 || dir == 4)
{
float tmin = (neia[k*2+0]-va[2]) / (vb[2]-va[2]);
float tmax = (neia[k*2+1]-va[2]) / (vb[2]-va[2]);
@ -366,7 +392,7 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
link->bmin = (unsigned char)(dtClamp(tmin, 0.0f, 1.0f)*255.0f);
link->bmax = (unsigned char)(dtClamp(tmax, 0.0f, 1.0f)*255.0f);
}
else if (side == 2 || side == 6)
else if (dir == 2 || dir == 6)
{
float tmin = (neia[k*2+0]-va[0]) / (vb[0]-va[0]);
float tmax = (neia[k*2+1]-va[0]) / (vb[0]-va[0]);
@ -711,7 +737,7 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
return DT_FAILURE | DT_WRONG_VERSION;
// Make sure the location is free.
if (getTileAt(header->x, header->y))
if (getTileAt(header->x, header->y, header->layer))
return DT_FAILURE;
// Allocate a tile.
@ -783,6 +809,10 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
tile->bvTree = (dtBVNode*)d; d += bvtreeSize;
tile->offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize;
// If there are no items in the bvtree, reset the tree pointer.
if (!bvtreeSize)
tile->bvTree = 0;
// Build links freelist
tile->linksFreeList = 0;
tile->links[header->maxLinkCount-1].next = DT_NULL_LINK;
@ -798,16 +828,32 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
connectIntLinks(tile);
connectIntOffMeshLinks(tile);
// Create connections connections.
// Create connections with neighbour tiles.
static const int MAX_NEIS = 32;
dtMeshTile* neis[MAX_NEIS];
int nneis;
// Connect with layers in current tile.
nneis = getTilesAt(header->x, header->y, neis, MAX_NEIS);
for (int j = 0; j < nneis; ++j)
{
if (neis[j] == tile) continue;
connectExtLinks(tile, neis[j], -1);
connectExtLinks(neis[j], tile, -1);
connectExtOffMeshLinks(tile, neis[j], -1);
connectExtOffMeshLinks(neis[j], tile, -1);
}
// Connect with neighbour tiles.
for (int i = 0; i < 8; ++i)
{
dtMeshTile* nei = getNeighbourTileAt(header->x, header->y, i);
if (nei)
nneis = getNeighbourTilesAt(header->x, header->y, i, neis, MAX_NEIS);
for (int j = 0; j < nneis; ++j)
{
connectExtLinks(tile, nei, i);
connectExtLinks(nei, tile, dtOppositeTile(i));
connectExtOffMeshLinks(tile, nei, i);
connectExtOffMeshLinks(nei, tile, dtOppositeTile(i));
connectExtLinks(tile, neis[j], i);
connectExtLinks(neis[j], tile, dtOppositeTile(i));
connectExtOffMeshLinks(tile, neis[j], i);
connectExtOffMeshLinks(neis[j], tile, dtOppositeTile(i));
}
}
@ -817,55 +863,102 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
return DT_SUCCESS;
}
const dtMeshTile* dtNavMesh::getTileAt(int x, int y) const
const dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer) const
{
// Find tile based on hash.
int h = computeTileHash(x,y,m_tileLutMask);
dtMeshTile* tile = m_posLookup[h];
while (tile)
{
if (tile->header && tile->header->x == x && tile->header->y == y)
if (tile->header &&
tile->header->x == x &&
tile->header->y == y &&
tile->header->layer == layer)
{
return tile;
}
tile = tile->next;
}
return 0;
}
dtMeshTile* dtNavMesh::getNeighbourTileAt(int x, int y, int side) const
int dtNavMesh::getNeighbourTilesAt(const int x, const int y, const int side, dtMeshTile** tiles, const int maxTiles) const
{
int nx = x, ny = y;
switch (side)
{
case 0: x++; break;
case 1: x++; y++; break;
case 2: y++; break;
case 3: x--; y++; break;
case 4: x--; break;
case 5: x--; y--; break;
case 6: y--; break;
case 7: x++; y--; break;
case 0: nx++; break;
case 1: nx++; ny++; break;
case 2: ny++; break;
case 3: nx--; ny++; break;
case 4: nx--; break;
case 5: nx--; ny--; break;
case 6: ny--; break;
case 7: nx++; ny--; break;
};
return getTilesAt(nx, ny, tiles, maxTiles);
}
int dtNavMesh::getTilesAt(const int x, const int y, dtMeshTile** tiles, const int maxTiles) const
{
int n = 0;
// Find tile based on hash.
int h = computeTileHash(x,y,m_tileLutMask);
dtMeshTile* tile = m_posLookup[h];
while (tile)
{
if (tile->header && tile->header->x == x && tile->header->y == y)
return tile;
if (tile->header &&
tile->header->x == x &&
tile->header->y == y)
{
if (n < maxTiles)
tiles[n++] = tile;
}
tile = tile->next;
}
return 0;
return n;
}
dtTileRef dtNavMesh::getTileRefAt(int x, int y) const
int dtNavMesh::getTilesAt(const int x, const int y, dtMeshTile const** tiles, const int maxTiles) const
{
int n = 0;
// Find tile based on hash.
int h = computeTileHash(x,y,m_tileLutMask);
dtMeshTile* tile = m_posLookup[h];
while (tile)
{
if (tile->header &&
tile->header->x == x &&
tile->header->y == y)
{
if (n < maxTiles)
tiles[n++] = tile;
}
tile = tile->next;
}
return n;
}
dtTileRef dtNavMesh::getTileRefAt(const int x, const int y, const int layer) const
{
// Find tile based on hash.
int h = computeTileHash(x,y,m_tileLutMask);
dtMeshTile* tile = m_posLookup[h];
while (tile)
{
if (tile->header && tile->header->x == x && tile->header->y == y)
if (tile->header &&
tile->header->x == x &&
tile->header->y == y &&
tile->header->layer == layer)
{
return getTileRef(tile);
}
tile = tile->next;
}
return 0;
@ -969,14 +1062,27 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz
}
// Remove connections to neighbour tiles.
for (int i = 0; i < 8; ++i)
// Create connections with neighbour tiles.
static const int MAX_NEIS = 32;
dtMeshTile* neis[MAX_NEIS];
int nneis;
// Connect with layers in current tile.
nneis = getTilesAt(tile->header->x, tile->header->y, neis, MAX_NEIS);
for (int j = 0; j < nneis; ++j)
{
dtMeshTile* nei = getNeighbourTileAt(tile->header->x,tile->header->y,i);
if (!nei) continue;
unconnectExtLinks(nei, dtOppositeTile(i));
if (neis[j] == tile) continue;
unconnectExtLinks(neis[j], tile);
}
// Connect with neighbour tiles.
for (int i = 0; i < 8; ++i)
{
nneis = getNeighbourTilesAt(tile->header->x, tile->header->y, i, neis, MAX_NEIS);
for (int j = 0; j < nneis; ++j)
unconnectExtLinks(neis[j], tile);
}
// Reset tile.
if (tile->flags & DT_TILE_FREE_DATA)
{

View File

@ -252,8 +252,6 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
return false;
if (!params->polyCount || !params->polys)
return false;
// if (!params->detailMeshes || !params->detailVerts || !params->detailTris)
// return false;
const int nvp = params->nvp;
@ -298,23 +296,13 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
for (int j = 0; j < nvp; ++j)
{
if (p[j] == MESH_NULL_IDX) break;
int nj = j+1;
if (nj >= nvp || p[nj] == MESH_NULL_IDX) nj = 0;
const unsigned short* va = &params->verts[p[j]*3];
const unsigned short* vb = &params->verts[p[nj]*3];
edgeCount++;
if (params->tileSize > 0)
if (p[nvp+j] & 0x8000)
{
if (va[0] == params->tileSize && vb[0] == params->tileSize)
portalCount++; // x+
else if (va[2] == params->tileSize && vb[2] == params->tileSize)
portalCount++; // z+
else if (va[0] == 0 && vb[0] == 0)
portalCount++; // x-
else if (va[2] == 0 && vb[2] == 0)
portalCount++; // z-
unsigned short dir = p[nvp+j] & 0xf;
if (dir != 0xf)
portalCount++;
}
}
}
@ -368,7 +356,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount);
const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount);
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*detailTriCount);
const int bvTreeSize = dtAlign4(sizeof(dtBVNode)*params->polyCount*2);
const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode)*params->polyCount*2) : 0;
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection)*storedOffMeshConCount);
const int dataSize = headerSize + vertsSize + polysSize + linksSize +
@ -400,6 +388,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
header->version = DT_NAVMESH_VERSION;
header->x = params->tileX;
header->y = params->tileY;
header->layer = params->tileLayer;
header->userId = params->userId;
header->polyCount = totPolyCount;
header->vertCount = totVertCount;
@ -415,7 +404,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
header->walkableRadius = params->walkableRadius;
header->walkableClimb = params->walkableClimb;
header->offMeshConCount = storedOffMeshConCount;
header->bvNodeCount = params->polyCount*2;
header->bvNodeCount = params->buildBvTree ? params->polyCount*2 : 0;
const int offMeshVertsBase = params->vertCount;
const int offMeshPolyBase = params->polyCount;
@ -459,7 +448,27 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
{
if (src[j] == MESH_NULL_IDX) break;
p->verts[j] = src[j];
p->neis[j] = (src[nvp+j]+1) & 0xffff;
if (src[nvp+j] & 0x8000)
{
// Border or portal edge.
unsigned short dir = src[nvp+j] & 0xf;
if (dir == 0xf) // Border
p->neis[j] = 0;
else if (dir == 0) // Portal x-
p->neis[j] = DT_EXT_LINK | 4;
else if (dir == 1) // Portal z+
p->neis[j] = DT_EXT_LINK | 2;
else if (dir == 2) // Portal x+
p->neis[j] = DT_EXT_LINK | 0;
else if (dir == 3) // Portal z-
p->neis[j] = DT_EXT_LINK | 6;
}
else
{
// Normal connection
p->neis[j] = src[nvp+j]+1;
}
p->vertCount++;
}
src += nvp*2;
@ -481,32 +490,6 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
n++;
}
}
// Store portal edges.
if (params->tileSize > 0)
{
for (int i = 0; i < params->polyCount; ++i)
{
dtPoly* poly = &navPolys[i];
for (int j = 0; j < poly->vertCount; ++j)
{
int nj = j+1;
if (nj >= poly->vertCount) nj = 0;
const unsigned short* va = &params->verts[poly->verts[j]*3];
const unsigned short* vb = &params->verts[poly->verts[nj]*3];
if (va[0] == params->tileSize && vb[0] == params->tileSize) // x+
poly->neis[j] = DT_EXT_LINK | 0;
else if (va[2] == params->tileSize && vb[2] == params->tileSize) // z+
poly->neis[j] = DT_EXT_LINK | 2;
else if (va[0] == 0 && vb[0] == 0) // x-
poly->neis[j] = DT_EXT_LINK | 4;
else if (va[2] == 0 && vb[2] == 0) // z-
poly->neis[j] = DT_EXT_LINK | 6;
}
}
}
// Store detail meshes and vertices.
// The nav polygon vertices are stored as the first vertices on each mesh.
@ -564,8 +547,11 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
// Store and create BVtree.
// TODO: take detail mesh into account! use byte per bbox extent?
createBVTree(params->verts, params->vertCount, params->polys, params->polyCount,
nvp, params->cs, params->ch, params->polyCount*2, navBvtree);
if (params->buildBvTree)
{
createBVTree(params->verts, params->vertCount, params->polys, params->polyCount,
nvp, params->cs, params->ch, params->polyCount*2, navBvtree);
}
// Store Off-Mesh connections.
n = 0;
@ -653,6 +639,7 @@ bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
swapEndian(&header->version);
swapEndian(&header->x);
swapEndian(&header->y);
swapEndian(&header->layer);
swapEndian(&header->userId);
swapEndian(&header->polyCount);
swapEndian(&header->vertCount);

View File

@ -494,8 +494,12 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi
const dtPolyRef base = m_nav->getPolyRefBase(tile);
for (int i = 0; i < tile->header->polyCount; ++i)
{
const dtPoly* p = &tile->polys[i];
const dtPolyRef ref = base | (dtPolyRef)i;
if (!filter->passFilter(ref, tile, p))
continue;
// Calc polygon bounds.
dtPoly* p = &tile->polys[i];
const float* v = &tile->verts[p->verts[0]*3];
dtVcopy(bmin, v);
dtVcopy(bmax, v);
@ -507,12 +511,8 @@ int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmi
}
if (dtOverlapBounds(qmin,qmax, bmin,bmax))
{
const dtPolyRef ref = base | (dtPolyRef)i;
if (filter->passFilter(ref, tile, p))
{
if (n < maxPolys)
polys[n++] = ref;
}
if (n < maxPolys)
polys[n++] = ref;
}
}
return n;
@ -534,18 +534,23 @@ dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents
m_nav->calcTileLoc(bmin, &minx, &miny);
m_nav->calcTileLoc(bmax, &maxx, &maxy);
static const int MAX_NEIS = 32;
const dtMeshTile* neis[MAX_NEIS];
int n = 0;
for (int y = miny; y <= maxy; ++y)
{
for (int x = minx; x <= maxx; ++x)
{
const dtMeshTile* tile = m_nav->getTileAt(x,y);
if (!tile) continue;
n += queryPolygonsInTile(tile, bmin, bmax, filter, polys+n, maxPolys-n);
if (n >= maxPolys)
const int nneis = m_nav->getTilesAt(x,y,neis,MAX_NEIS);
for (int j = 0; j < nneis; ++j)
{
*polyCount = n;
return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
n += queryPolygonsInTile(neis[j], bmin, bmax, filter, polys+n, maxPolys-n);
if (n >= maxPolys)
{
*polyCount = n;
return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
//
// Copyright (c) 2009-2010 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 DETOURTILECACHEBUILDER_H
#define DETOURTILECACHEBUILDER_H
#include "DetourAlloc.h"
#include "DetourStatus.h"
static const int DT_TILECACHE_MAGIC = 'D'<<24 | 'T'<<16 | 'I'<<8 | 'C'; //'DTIC';
static const int DT_TILECACHE_VERSION = 1;
struct dtTileCacheLayerParams
{
float bmin[3], bmax[3]; // Bounding box of the heightfield.
float cs, ch; // Cell size and height.
};
struct dtTileCacheLayerHeader
{
int magic; // Data magic
int version; // Data version
unsigned short hmin, hmax; // Height min/max range
unsigned char width, height; // Dimension of the layer.
unsigned char minx, maxx, miny, maxy; // Usable sub-region.
};
struct dtTileCacheLayer
{
dtTileCacheLayerHeader* header;
unsigned char regCount; // Region count.
unsigned char* heights;
unsigned char* areas;
unsigned char* cons;
unsigned char* regs;
};
struct dtTileCacheContour
{
int nverts;
unsigned char* verts;
unsigned char reg;
unsigned char area;
};
struct dtTileCacheContourSet
{
int nconts;
dtTileCacheContour* conts;
};
struct dtTileCachePolyMesh
{
int nverts; // Number of vertices.
int npolys; // Number of polygons.
unsigned short* verts; // Vertices of the mesh, 3 elements per vertex.
unsigned short* polys; // Polygons of the mesh, nvp*2 elements per polygon.
unsigned short* flags; // Per polygon flags.
unsigned char* areas; // Area ID of polygons.
};
struct dtTileCacheAlloc
{
virtual void* alloc(const int size)
{
return dtAlloc(size, DT_ALLOC_TEMP);
}
virtual void free(void* ptr)
{
dtFree(ptr);
}
};
dtStatus dtCastTileCacheLayer(dtTileCacheLayer& layer, unsigned char* buffer, const int bufferSize);
// Returns the amount of memory requires for specific grid size.
int dtCalcTileCacheLayerBufferSize(const int gridWidth, const int gridHeight);
dtTileCacheContourSet* dtAllocTileCacheContourSet(dtTileCacheAlloc* alloc);
void dtFreeTileCacheContourSet(dtTileCacheAlloc* alloc, dtTileCacheContourSet* cset);
dtTileCachePolyMesh* dtAllocTileCachePolyMesh(dtTileCacheAlloc* alloc);
void dtFreeTileCachePolyMesh(dtTileCacheAlloc* alloc, dtTileCachePolyMesh* lmesh);
dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc,
dtTileCacheLayer& layer,
const int walkableClimb);
dtStatus dtBuildTileCacheContours(dtTileCacheAlloc* alloc,
dtTileCacheLayer& layer,
const int walkableClimb, const float maxError,
dtTileCacheContourSet& lcset);
dtStatus dtBuildTileCachePolyMesh(dtTileCacheAlloc* alloc,
dtTileCacheContourSet& lcset,
dtTileCachePolyMesh& mesh);
#endif // DETOURTILECACHEBUILDER_H

View File

@ -34,7 +34,6 @@ enum rcTimerLabel
RC_TIMER_TOTAL,
RC_TIMER_TEMP,
RC_TIMER_RASTERIZE_TRIANGLES,
RC_TIMER_BUILD_LEANHEIGHTFIELD,
RC_TIMER_BUILD_COMPACTHEIGHTFIELD,
RC_TIMER_BUILD_CONTOURS,
RC_TIMER_BUILD_CONTOURS_TRACE,
@ -184,6 +183,7 @@ struct rcCompactHeightfield
int width, height; // Width and height of the heightfield.
int spanCount; // Number of spans in the heightfield.
int walkableHeight, walkableClimb; // Agent properties.
int borderSize; // Border size of the heighfield.
unsigned short maxDistance; // Maximum distance value stored in heightfield.
unsigned short maxRegions; // Maximum Region Id stored in heightfield.
float bmin[3], bmax[3]; // Bounding box of the heightfield.
@ -198,41 +198,16 @@ rcCompactHeightfield* rcAllocCompactHeightfield();
void rcFreeCompactHeightfield(rcCompactHeightfield* chf);
// Lean heightfield stores minimal information to create rcCompactNeighfield
// in one continuous chunk of memory. The header and data are both laid out
// in the memory one after each other. The data is accessed as follows:
// const int headerSize = rcAlign4(sizeof(rcLeanHeightfield));
// const int countsSize = rcAlign4(sizeof(unsigned char)*lhf.width*lhf.height);
// const int floorsSize = rcAlign4(sizeof(unsigned short)*lhf.spanCount);
// const unsigned char* data = (const unsigned char*)&lhf;
// const unsigned char* counts = (const unsigned char*)&data[headerSize];
// const unsigned short* floors = (const unsigned short*)&data[headerSize+countsSize];
// const unsigned char* areas = (const unsigned char*)&data[headerSize+countsSize+floorsSize];
// This allows the heighfield to be read and written or compressed as one chunk, i.e.:
// fwrite(lhf, lhf->size, 1, fp);
// Use rcFree() to free the memory occupied by rcLeanHeightfield.
struct rcLeanHeightfield
{
int width, height; // Width and height of the heightfield.
int spanCount; // Number of spans in the heightfield.
float bmin[3], bmax[3]; // Bounding box of the heightfield.
float cs, ch; // Cell size and height.
int size; // Memory required by the heighfield.
};
struct rcHeightfieldLayer
{
float bmin[3], bmax[3]; // Bounding box of the heightfield.
float cs, ch; // Cell size and height.
int width, height; // Width and height of the layer.
int nportals; // Number of portals.
unsigned char regCount;
unsigned char maxHeight; // Height min/max range.
int minx,maxx,miny,maxy; // Bounding box of usable data.
int hmin, hmax; // Height min/max
unsigned char* heights; // Heighfield.
unsigned char* areas; // Area types.
unsigned char* regs; // Regions.
unsigned char* cons; // Connections.
};
@ -263,6 +238,8 @@ struct rcContourSet
int nconts; // Number of contours.
float bmin[3], bmax[3]; // Bounding box of the heightfield.
float cs, ch; // Cell size and height.
int width, height; // Region where the contours were build.
int borderSize; // Border size of the heighfield where the contours were build from.
};
rcContourSet* rcAllocContourSet();
@ -293,6 +270,7 @@ struct rcPolyMesh
int nvp; // Max number of vertices per polygon.
float bmin[3], bmax[3]; // Bounding box of the mesh.
float cs, ch; // Cell size and height.
int borderSize; // Border size of the heighfield where the mesh was build from.
};
rcPolyMesh* rcAllocPolyMesh();
@ -620,13 +598,6 @@ void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeight
// Returns number of spans.
int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf);
// Builds minimal representation of the heighfield.
// Params:
// hf - (in) heightfield to be compacted
// chf - (out) lean heightfield representing the open space.
// Returns pointer to the created lean heighfield.
rcLeanHeightfield* rcBuildLeanHeightfield(rcContext* ctx, rcHeightfield& hf, const int walkableHeight);
// Builds compact representation of the heightfield.
// Params:
// walkableHeight - (in) minimum height where the agent can still walk
@ -637,16 +608,6 @@ rcLeanHeightfield* rcBuildLeanHeightfield(rcContext* ctx, rcHeightfield& hf, con
bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
rcHeightfield& hf, rcCompactHeightfield& chf);
// Builds compact representation of the heightfield from lean data.
// Params:
// walkableHeight - (in) minimum height where the agent can still walk
// walkableClimb - (in) maximum height between grid cells the agent can climb
// lhf - (in) lean heightfield to be used as input
// chf - (out) compact heightfield representing the open space.
// Returns false if operation ran out of memory.
bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
rcLeanHeightfield& lhf, rcCompactHeightfield& chf);
// Erodes walkable area.
// Params:
// radius - (in) radius of erosion (max 255).
@ -741,60 +702,6 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf,
const int borderSize, const int walkableHeight,
rcHeightfieldLayerSet& lset);
// TODO: move this somewhere else, once the layer meshing is done.
bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int walkableClimb);
struct rcLayerContour
{
int nverts;
unsigned char* verts;
unsigned char reg, area;
};
struct rcLayerContourSet
{
float bmin[3], bmax[3]; // Bounding box of the heightfield.
float cs, ch; // Cell size and height.
int nconts;
rcLayerContour* conts;
};
rcLayerContourSet* rcAllocLayerContourSet();
void rcFreeLayerContourSet(rcLayerContourSet* lset);
// TODO: move this somewhere else, once the layer meshing is done.
bool rcBuildLayerContours(rcContext* ctx,
rcHeightfieldLayer& layer,
const int walkableClimb, const float maxError,
rcLayerContourSet& lcset);
struct rcLayerPolyMesh
{
unsigned short* verts; // Vertices of the mesh, 3 elements per vertex.
unsigned short* polys; // Polygons of the mesh, nvp*2 elements per polygon.
unsigned short* flags; // Per polygon flags.
unsigned char* areas; // Area ID of polygons.
int nverts; // Number of vertices.
int npolys; // Number of polygons.
int maxpolys; // Number of allocated polygons.
int nvp; // Max number of vertices per polygon.
float bmin[3], bmax[3]; // Bounding box of the mesh.
float cs, ch; // Cell size and height.
};
rcLayerPolyMesh* rcAllocLayerPolyMesh();
void rcFreeLayerPolyMesh(rcLayerPolyMesh* lmesh);
bool rcBuildLayerPolyMesh(rcContext* ctx,
rcLayerContourSet& lcset,
const int maxVertsPerPoly,
rcLayerPolyMesh& lmesh);
// Builds simplified contours from the regions outlines.
// Params:
// chf - (in) compact heightfield which has regions set.
@ -813,7 +720,7 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
// nvp - (in) maximum number of vertices per polygon.
// mesh - (out) poly mesh.
// Returns false if operation ran out of memory.
bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& mesh);
bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh);
bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh);

View File

@ -105,7 +105,6 @@ void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset)
{
rcFree(lset->layers[i].heights);
rcFree(lset->layers[i].areas);
rcFree(lset->layers[i].regs);
rcFree(lset->layers[i].cons);
}
rcFree(lset->layers);
@ -113,44 +112,6 @@ void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset)
}
rcLayerContourSet* rcAllocLayerContourSet()
{
rcLayerContourSet* cset = (rcLayerContourSet*)rcAlloc(sizeof(rcLayerContourSet), RC_ALLOC_PERM);
memset(cset, 0, sizeof(rcLayerContourSet));
return cset;
}
void rcFreeLayerContourSet(rcLayerContourSet* cset)
{
if (!cset) return;
for (int i = 0; i < cset->nconts; ++i)
{
rcFree(cset->conts[i].verts);
// rcFree(cset->conts[i].rverts);
}
rcFree(cset->conts);
rcFree(cset);
}
rcLayerPolyMesh* rcAllocLayerPolyMesh()
{
rcLayerPolyMesh* lmesh = (rcLayerPolyMesh*)rcAlloc(sizeof(rcLayerPolyMesh), RC_ALLOC_PERM);
memset(lmesh, 0, sizeof(rcLayerPolyMesh));
return lmesh;
}
void rcFreeLayerPolyMesh(rcLayerPolyMesh* lmesh)
{
if (!lmesh) return;
rcFree(lmesh->verts);
rcFree(lmesh->polys);
rcFree(lmesh->flags);
rcFree(lmesh->areas);
rcFree(lmesh);
}
rcContourSet* rcAllocContourSet()
{
rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM);
@ -457,237 +418,6 @@ bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const i
return true;
}
rcLeanHeightfield* rcBuildLeanHeightfield(rcContext* ctx, rcHeightfield& hf, const int walkableHeight)
{
rcAssert(ctx);
ctx->startTimer(RC_TIMER_BUILD_LEANHEIGHTFIELD);
const int w = hf.width;
const int h = hf.height;
const int spanCount = rcGetHeightFieldSpanCount(ctx, hf);
const int headerSize = rcAlign4(sizeof(rcLeanHeightfield));
const int countsSize = rcAlign4(sizeof(unsigned char)*w*h);
const int floorsSize = rcAlign4(sizeof(unsigned short)*spanCount);
const int areasSize = rcAlign4(sizeof(unsigned char)*spanCount);
const int dataSize = headerSize + countsSize + floorsSize + areasSize;
unsigned char* data = (unsigned char*)rcAlloc(dataSize, RC_ALLOC_PERM);
if (!data)
{
ctx->log(RC_LOG_ERROR, "rcBuildLeanHeightfield: Out of memory (%d)", dataSize);
return 0;
}
rcLeanHeightfield* lhf = (rcLeanHeightfield*)&data[0];
unsigned char* counts = (unsigned char*)&data[headerSize];
unsigned short* floors = (unsigned short*)&data[headerSize+countsSize];
unsigned char* areas = (unsigned char*)&data[headerSize+countsSize+floorsSize];
// Fill in header.
lhf->width = w;
lhf->height = h;
lhf->spanCount = spanCount;
rcVcopy(lhf->bmin, hf.bmin);
rcVcopy(lhf->bmax, hf.bmax);
lhf->cs = hf.cs;
lhf->ch = hf.ch;
lhf->size = dataSize;
memset(counts, 0, w*h);
memset(floors, 0, sizeof(unsigned short)*spanCount);
memset(areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount);
const int MAX_HEIGHT = 0xffff;
const int MAX_Y = (1<<RC_SPAN_HEIGHT_BITS)-1;
const int MAX_H = (1<<(16-RC_SPAN_HEIGHT_BITS))-1;
// Fill in cells and spans.
int idx = 0;
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
const rcSpan* s = hf.spans[x+y*w];
unsigned char& count = counts[x+y*w];
count = 0;
while (s)
{
if (s->area != RC_NULL_AREA)
{
const int bot = (int)s->smax;
const int top = s->next ? (int)s->next->smin : MAX_HEIGHT;
const int space = top - bot;
unsigned short y = (unsigned short)rcClamp(bot, 0, MAX_Y);
// TODO: Make sure 'h' can encode at least walkableClimb worth of values.
unsigned short h = 0; // Height stores the space above the walkable height.
if (space >= walkableHeight)
h = (unsigned short)rcClamp(1+(space - walkableHeight)/2, 0, MAX_H);
floors[idx] = y | (h << RC_SPAN_HEIGHT_BITS);
areas[idx] = s->area;
idx++;
count++;
}
s = s->next;
}
}
}
ctx->stopTimer(RC_TIMER_BUILD_LEANHEIGHTFIELD);
return lhf;
}
bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb,
rcLeanHeightfield& lhf, rcCompactHeightfield& chf)
{
rcAssert(ctx);
ctx->startTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
const int w = lhf.width;
const int h = lhf.height;
const int spanCount = lhf.spanCount;
// Fill in header.
chf.width = w;
chf.height = h;
chf.spanCount = spanCount;
chf.walkableHeight = walkableHeight;
chf.walkableClimb = walkableClimb;
chf.maxRegions = 0;
rcVcopy(chf.bmin, lhf.bmin);
rcVcopy(chf.bmax, lhf.bmax);
chf.bmax[1] += walkableHeight*lhf.ch;
chf.cs = lhf.cs;
chf.ch = lhf.ch;
chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM);
if (!chf.cells)
{
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h);
return false;
}
memset(chf.cells, 0, sizeof(rcCompactCell)*w*h);
chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM);
if (!chf.spans)
{
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount);
return false;
}
memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount);
chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM);
if (!chf.areas)
{
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount);
return false;
}
memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount);
const int headerSize = rcAlign4(sizeof(rcLeanHeightfield));
const int countsSize = rcAlign4(sizeof(unsigned char)*lhf.width*lhf.height);
const int floorsSize = rcAlign4(sizeof(unsigned short)*lhf.spanCount);
const unsigned char* data = (const unsigned char*)&lhf;
const unsigned char* counts = (const unsigned char*)&data[headerSize];
const unsigned short* floors = (const unsigned short*)&data[headerSize+countsSize];
const unsigned char* areas = (const unsigned char*)&data[headerSize+countsSize+floorsSize];
const unsigned short MASK_Y = (1<<RC_SPAN_HEIGHT_BITS)-1;
const unsigned short MASK_H = (1<<(16-RC_SPAN_HEIGHT_BITS))-1;
// Fill in cells and spans.
int idx = 0;
for (int y = 0; y < chf.height; ++y)
{
for (int x = 0; x < chf.width; ++x)
{
const int count = counts[x+y*chf.width];
rcCompactCell& c = chf.cells[x+y*w];
c.index = idx;
c.count = count;
for (int i = idx, ni = idx+count; i < ni; ++i)
{
unsigned short y = (unsigned short)(floors[i] & MASK_Y);
unsigned char h = (unsigned char)((floors[i]>>RC_SPAN_HEIGHT_BITS) & MASK_H);
chf.spans[i].y = y;
chf.spans[i].h = h == 0 ? 0 : (unsigned char)(walkableHeight + (h-1)*2);
chf.areas[i] = areas[i];
}
idx += count;
}
}
// Find neighbour connections.
const int MAX_LAYERS = RC_NOT_CONNECTED-1;
int tooHighNeighbour = 0;
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
const rcCompactCell& c = chf.cells[x+y*w];
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
{
rcCompactSpan& s = chf.spans[i];
for (int dir = 0; dir < 4; ++dir)
{
rcSetCon(s, dir, RC_NOT_CONNECTED);
const int nx = x + rcGetDirOffsetX(dir);
const int ny = y + rcGetDirOffsetY(dir);
// First check that the neighbour cell is in bounds.
if (nx < 0 || ny < 0 || nx >= w || ny >= h)
continue;
// Iterate over all neighbour spans and check if any of the is
// accessible from current cell.
const rcCompactCell& nc = chf.cells[nx+ny*w];
for (int k = (int)nc.index, nk = (int)(nc.index+nc.count); k < nk; ++k)
{
const rcCompactSpan& ns = chf.spans[k];
const int bot = rcMax(s.y, ns.y);
const int top = rcMin(s.y+s.h, ns.y+ns.h);
// Check that the gap between the spans is walkable,
// and that the climb height between the gaps is not too high.
if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb)
{
// Mark direction as walkable.
const int idx = k - (int)nc.index;
if (idx < 0 || idx > MAX_LAYERS)
{
tooHighNeighbour = rcMax(tooHighNeighbour, idx);
continue;
}
rcSetCon(s, dir, idx);
break;
}
}
}
}
}
}
if (tooHighNeighbour > MAX_LAYERS)
{
ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)",
tooHighNeighbour, MAX_LAYERS);
}
ctx->stopTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD);
return true;
}
/*
static int getHeightfieldMemoryUsage(const rcHeightfield& hf)
{

View File

@ -600,13 +600,26 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
const int w = chf.width;
const int h = chf.height;
const int borderSize = chf.borderSize;
ctx->startTimer(RC_TIMER_BUILD_CONTOURS);
rcVcopy(cset.bmin, chf.bmin);
rcVcopy(cset.bmax, chf.bmax);
if (borderSize > 0)
{
// If the heightfield was build with bordersize, remove the offset.
const float pad = borderSize*chf.cs;
cset.bmin[0] += pad;
cset.bmin[2] += pad;
cset.bmax[0] -= pad;
cset.bmax[2] -= pad;
}
cset.cs = chf.cs;
cset.ch = chf.ch;
cset.width = chf.width - chf.borderSize*2;
cset.height = chf.height - chf.borderSize*2;
cset.borderSize = chf.borderSize;
int maxContours = rcMax((int)chf.maxRegions, 8);
cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM);
@ -658,8 +671,6 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
rcIntArray verts(256);
rcIntArray simplified(64);
@ -682,10 +693,17 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
verts.resize(0);
simplified.resize(0);
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
walkContour(x, y, i, chf, flags, verts);
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE);
ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags);
removeDegenerateSegments(simplified);
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
// Store region->contour remap info.
// Create contour.
if (simplified.size()/4 >= 3)
@ -720,6 +738,16 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
return false;
}
memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4);
if (borderSize > 0)
{
// If the heightfield was build with bordersize, remove the offset.
for (int i = 0; i < cont->nverts; ++i)
{
int* v = &cont->verts[i*4];
v[0] -= borderSize;
v[2] -= borderSize;
}
}
cont->nrverts = verts.size()/4;
cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM);
@ -729,6 +757,16 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
return false;
}
memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4);
if (borderSize > 0)
{
// If the heightfield was build with bordersize, remove the offset.
for (int i = 0; i < cont->nrverts; ++i)
{
int* v = &cont->rverts[i*4];
v[0] -= borderSize;
v[2] -= borderSize;
}
}
/* cont->cx = cont->cy = cont->cz = 0;
for (int i = 0; i < cont->nverts; ++i)
@ -796,8 +834,6 @@ bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf,
}
}
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY);
ctx->stopTimer(RC_TIMER_BUILD_CONTOURS);
return true;

File diff suppressed because it is too large Load Diff

View File

@ -896,7 +896,7 @@ static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short
}
bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& mesh)
bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh)
{
rcAssert(ctx);
@ -906,6 +906,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
rcVcopy(mesh.bmax, cset.bmax);
mesh.cs = cset.cs;
mesh.ch = cset.ch;
mesh.borderSize = cset.borderSize;
int maxVertices = 0;
int maxTris = 0;
@ -939,7 +940,7 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices);
return false;
}
mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2*2, RC_ALLOC_PERM);
mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2, RC_ALLOC_PERM);
if (!mesh.polys)
{
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2);
@ -1156,6 +1157,37 @@ bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, int nvp, rcPolyMesh& me
ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed.");
return false;
}
// Find portal edges
if (mesh.borderSize > 0)
{
const int w = cset.width;
const int h = cset.height;
for (int i = 0; i < mesh.npolys; ++i)
{
unsigned short* p = &mesh.polys[i*2*nvp];
for (int j = 0; j < nvp; ++j)
{
if (p[j] == RC_MESH_NULL_IDX) break;
// Skip connected edges.
if (p[nvp+j] != RC_MESH_NULL_IDX)
continue;
int nj = j+1;
if (nj >= nvp || p[nj] == RC_MESH_NULL_IDX) nj = 0;
const unsigned short* va = &mesh.verts[p[j]*3];
const unsigned short* vb = &mesh.verts[p[nj]*3];
if ((int)va[0] == 0 && (int)vb[0] == 0)
p[nvp+j] = 0x8000 | 0;
else if ((int)va[2] == h && (int)vb[2] == h)
p[nvp+j] = 0x8000 | 1;
else if ((int)va[0] == w && (int)vb[0] == w)
p[nvp+j] = 0x8000 | 2;
else if ((int)va[2] == 0 && (int)vb[2] == 0)
p[nvp+j] = 0x8000 | 3;
}
}
}
// Just allocate the mesh flags array. The user is resposible to fill it.
mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM);

View File

@ -743,12 +743,15 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
static void getHeightData(const rcCompactHeightfield& chf,
const unsigned short* poly, const int npoly,
const unsigned short* verts,
const unsigned short* verts, const int bs,
rcHeightPatch& hp, rcIntArray& stack)
{
// Floodfill the heightfield to get 2D height data,
// starting at vertex locations as seeds.
// Note: Reads to the compact heightfield are offset by border size (bs)
// since border size offset is already removed from the polymesh vertices.
memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height);
stack.resize(0);
@ -772,7 +775,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
az < hp.ymin || az >= hp.ymin+hp.height)
continue;
const rcCompactCell& c = chf.cells[ax+az*chf.width];
const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width];
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
{
const rcCompactSpan& s = chf.spans[i];
@ -844,7 +847,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0)
continue;
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(cs, dir);
const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
hp.data[idx] = 1;
@ -900,7 +903,7 @@ static void getHeightData(const rcCompactHeightfield& chf,
if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != RC_UNSET_HEIGHT)
continue;
const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(cs, dir);
const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir);
const rcCompactSpan& as = chf.spans[ai];
int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width;
@ -955,6 +958,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
const float cs = mesh.cs;
const float ch = mesh.ch;
const float* orig = mesh.bmin;
const int borderSize = mesh.borderSize;
rcIntArray edges(64);
rcIntArray tris(512);
@ -1065,7 +1069,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
hp.ymin = bounds[i*4+2];
hp.width = bounds[i*4+1]-bounds[i*4+0];
hp.height = bounds[i*4+3]-bounds[i*4+2];
getHeightData(chf, p, npoly, mesh.verts, hp, stack);
getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack);
// Build detail mesh.
int nverts = 0;

View File

@ -1058,6 +1058,8 @@ bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
chf.borderSize = borderSize;
}
rcIntArray prev(256);
@ -1208,11 +1210,19 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
// const int expandIters = 4 + walkableRadius * 2;
const int expandIters = 8;
// Mark border regions.
paintRectRegion(0, borderSize, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
paintRectRegion(w-borderSize, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
paintRectRegion(0, w, 0, borderSize, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
paintRectRegion(0, w, h-borderSize, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
if (borderSize > 0)
{
// Make sure border will not overflow.
const int bw = rcMin(w, borderSize);
const int bh = rcMin(h, borderSize);
// Paint regions
paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
paintRectRegion(0, w, 0, bh, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
paintRectRegion(0, w, h-bh, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
chf.borderSize = borderSize;
}
while (level > 0)
{

View File

@ -27,6 +27,7 @@
6B3F9D6D13179EFC000B33D9 /* RecastLayers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B3F9D6C13179EFC000B33D9 /* RecastLayers.cpp */; };
6B555DB1100B212E00247EA3 /* imguiRenderGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B555DB0100B212E00247EA3 /* imguiRenderGL.cpp */; };
6B5683B812D9E7D3000B9960 /* Sample_TempObstacles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B5683B712D9E7D3000B9960 /* Sample_TempObstacles.cpp */; };
6B5DC3B713350E6300D33D05 /* DetourTileCacheBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B5DC3B513350E6300D33D05 /* DetourTileCacheBuilder.cpp */; };
6B62416A103434880002E346 /* RecastMeshDetail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B624169103434880002E346 /* RecastMeshDetail.cpp */; };
6B8036AE113BAABE005ED67B /* Sample_Debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B8036AD113BAABE005ED67B /* Sample_Debug.cpp */; };
6B847777122D221D00ADF63D /* ValueHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B847776122D221C00ADF63D /* ValueHistory.cpp */; };
@ -103,6 +104,8 @@
6B555DF6100B273500247EA3 /* stb_truetype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stb_truetype.h; path = ../../Contrib/stb_truetype.h; sourceTree = SOURCE_ROOT; };
6B5683B612D9E7D3000B9960 /* Sample_TempObstacles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Sample_TempObstacles.h; path = ../../Include/Sample_TempObstacles.h; sourceTree = SOURCE_ROOT; };
6B5683B712D9E7D3000B9960 /* Sample_TempObstacles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Sample_TempObstacles.cpp; path = ../../Source/Sample_TempObstacles.cpp; sourceTree = SOURCE_ROOT; };
6B5DC3B513350E6300D33D05 /* DetourTileCacheBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetourTileCacheBuilder.cpp; sourceTree = "<group>"; };
6B5DC3B613350E6300D33D05 /* DetourTileCacheBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetourTileCacheBuilder.h; sourceTree = "<group>"; };
6B624169103434880002E346 /* RecastMeshDetail.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecastMeshDetail.cpp; path = ../../../Recast/Source/RecastMeshDetail.cpp; sourceTree = SOURCE_ROOT; };
6B8036AC113BAABE005ED67B /* Sample_Debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Sample_Debug.h; path = ../../Include/Sample_Debug.h; sourceTree = SOURCE_ROOT; };
6B8036AD113BAABE005ED67B /* Sample_Debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Sample_Debug.cpp; path = ../../Source/Sample_Debug.cpp; sourceTree = SOURCE_ROOT; };
@ -110,6 +113,7 @@
6B847776122D221C00ADF63D /* ValueHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueHistory.cpp; path = ../../Source/ValueHistory.cpp; sourceTree = SOURCE_ROOT; };
6B8632D90F78122C00E2684A /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = Library/Frameworks/SDL.framework; sourceTree = SDKROOT; };
6B8632DB0F78123E00E2684A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
6B86B21213387FB200B14842 /* DetourStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DetourStatus.h; path = ../../../Detour/Include/DetourStatus.h; sourceTree = SOURCE_ROOT; };
6B86C9A812F69DD500C92D2E /* fastlz.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fastlz.c; path = ../../Contrib/fastlz/fastlz.c; sourceTree = SOURCE_ROOT; };
6B86C9A912F69DD500C92D2E /* fastlz.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fastlz.h; path = ../../Contrib/fastlz/fastlz.h; sourceTree = SOURCE_ROOT; };
6B8DE88710B69E3E00DF20FB /* DetourNavMesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DetourNavMesh.cpp; path = ../../../Detour/Source/DetourNavMesh.cpp; sourceTree = SOURCE_ROOT; };
@ -189,10 +193,11 @@
080E96DDFE201D6D7F000001 /* Classes */ = {
isa = PBXGroup;
children = (
6BB5012B12F458AE001B1957 /* DetourCrowd */,
6BB5012A12F45891001B1957 /* Contrib */,
6BB93C7610CFE1BD00F74F2B /* DebugUtils */,
6BDD9E030F91110C00904EEF /* Detour */,
6BB5012B12F458AE001B1957 /* DetourCrowd */,
6B5DC3B413350E6300D33D05 /* DetourTileCache */,
6B137C7D0F7FCBE800459200 /* Recast */,
6B555DF5100B25FC00247EA3 /* Samples */,
6BB7FE8E10F4A175006DA0A6 /* Tools */,
@ -330,6 +335,16 @@
name = Samples;
sourceTree = "<group>";
};
6B5DC3B413350E6300D33D05 /* DetourTileCache */ = {
isa = PBXGroup;
children = (
6B5DC3B613350E6300D33D05 /* DetourTileCacheBuilder.h */,
6B5DC3B513350E6300D33D05 /* DetourTileCacheBuilder.cpp */,
);
name = DetourTileCache;
path = ../../../DetourTileCache;
sourceTree = SOURCE_ROOT;
};
6BB5012A12F45891001B1957 /* Contrib */ = {
isa = PBXGroup;
children = (
@ -406,6 +421,7 @@
6B1185F41006895B0018F96F /* DetourNode.cpp */,
6B1185FC10068B040018F96F /* DetourCommon.h */,
6B1185FD10068B150018F96F /* DetourCommon.cpp */,
6B86B21213387FB200B14842 /* DetourStatus.h */,
);
name = Detour;
sourceTree = "<group>";
@ -515,6 +531,7 @@
6B86C9AA12F69DD500C92D2E /* fastlz.c in Sources */,
6B3F9D6D13179EFC000B33D9 /* RecastLayers.cpp in Sources */,
6BD1B1D01323E2EC00587F83 /* Sample_SoloMesh.cpp in Sources */,
6B5DC3B713350E6300D33D05 /* DetourTileCacheBuilder.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -30,7 +30,6 @@ class Sample_TempObstacles : public Sample
protected:
bool m_keepInterResults;
float m_cacheBuildTimeMs;
bool m_drawPortals;
class TileCache* m_tileCache;
class ObstacleSet* m_obs;
@ -44,6 +43,7 @@ protected:
DRAWMODE_NAVMESH_PORTALS,
DRAWMODE_NAVMESH_INVIS,
DRAWMODE_MESH,
DRAWMODE_CACHE_BOUNDS,
MAX_DRAWMODE
};

View File

@ -30,7 +30,6 @@ protected:
bool m_keepInterResults;
bool m_buildAll;
float m_totalBuildTimeMs;
bool m_drawPortals;
unsigned char* m_triareas;
rcHeightfield* m_solid;
@ -39,15 +38,6 @@ protected:
rcPolyMesh* m_pmesh;
rcPolyMeshDetail* m_dmesh;
rcConfig m_cfg;
static const int MAX_LAYERS = 128;
rcHeightfieldLayerSet* m_lset;
rcLayerContourSet* m_lcsets[MAX_LAYERS];
int m_nlcsets;
rcLayerPolyMesh* m_lmeshes[MAX_LAYERS];
int m_nlmeshes;
enum DrawMode
{
@ -68,12 +58,7 @@ protected:
DRAWMODE_BOTH_CONTOURS,
DRAWMODE_CONTOURS,
DRAWMODE_POLYMESH,
DRAWMODE_POLYMESH_DETAIL,
DRAWMODE_HEIGHFIELD_LAYERS,
DRAWMODE_LAYER_CONTOURS,
DRAWMODE_LAYER_MESHES,
DRAWMODE_POLYMESH_DETAIL,
MAX_DRAWMODE
};

View File

@ -486,7 +486,7 @@ bool Sample_SoloMesh::handleBuild()
{
// Partition the walkable surface into simple regions without holes.
// Monotone partitioning does not need distancefield.
if (!rcBuildRegionsMonotone(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
if (!rcBuildRegionsMonotone(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build regions.");
return false;
@ -502,7 +502,7 @@ bool Sample_SoloMesh::handleBuild()
}
// Partition the walkable surface into simple regions without holes.
if (!rcBuildRegions(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
if (!rcBuildRegions(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build regions.");
return false;
@ -633,6 +633,7 @@ bool Sample_SoloMesh::handleBuild()
rcVcopy(params.bmax, m_pmesh->bmax);
params.cs = m_cfg.cs;
params.ch = m_cfg.ch;
params.buildBvTree = true;
if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
{

File diff suppressed because it is too large Load Diff

View File

@ -175,16 +175,12 @@ Sample_TileMesh::Sample_TileMesh() :
m_keepInterResults(false),
m_buildAll(true),
m_totalBuildTimeMs(0),
m_drawPortals(false),
m_triareas(0),
m_solid(0),
m_chf(0),
m_cset(0),
m_pmesh(0),
m_dmesh(0),
m_lset(0),
m_nlcsets(0),
m_nlmeshes(0),
m_drawMode(DRAWMODE_NAVMESH),
m_maxTiles(0),
m_maxPolysPerTile(0),
@ -197,9 +193,6 @@ Sample_TileMesh::Sample_TileMesh() :
resetCommonSettings();
memset(m_tileBmin, 0, sizeof(m_tileBmin));
memset(m_tileBmax, 0, sizeof(m_tileBmax));
memset(m_lcsets, 0, sizeof(m_lcsets));
memset(m_lmeshes, 0, sizeof(m_lmeshes));
setTool(new NavMeshTileTool);
}
@ -225,23 +218,6 @@ void Sample_TileMesh::cleanup()
m_pmesh = 0;
rcFreePolyMeshDetail(m_dmesh);
m_dmesh = 0;
rcFreeHeightfieldLayerSet(m_lset);
m_lset = 0;
for (int i = 0; i < MAX_LAYERS; ++i)
{
rcFreeLayerContourSet(m_lcsets[i]);
m_lcsets[i] = 0;
}
m_nlcsets = 0;
for (int i = 0; i < MAX_LAYERS; ++i)
{
rcFreeLayerPolyMesh(m_lmeshes[i]);
m_lmeshes[i] = 0;
}
m_nlmeshes = 0;
}
@ -490,9 +466,6 @@ void Sample_TileMesh::handleDebugMode()
valid[DRAWMODE_CONTOURS] = m_cset != 0;
valid[DRAWMODE_POLYMESH] = m_pmesh != 0;
valid[DRAWMODE_POLYMESH_DETAIL] = m_dmesh != 0;
valid[DRAWMODE_HEIGHFIELD_LAYERS] = m_lset != 0;
valid[DRAWMODE_LAYER_CONTOURS] = m_nlcsets != 0;
valid[DRAWMODE_LAYER_MESHES] = m_nlmeshes != 0;
}
int unavail = 0;
@ -539,16 +512,7 @@ void Sample_TileMesh::handleDebugMode()
m_drawMode = DRAWMODE_POLYMESH;
if (imguiCheck("Poly Mesh Detail", m_drawMode == DRAWMODE_POLYMESH_DETAIL, valid[DRAWMODE_POLYMESH_DETAIL]))
m_drawMode = DRAWMODE_POLYMESH_DETAIL;
imguiSeparatorLine();
if (imguiCheck("Heighfield Layers", m_drawMode == DRAWMODE_HEIGHFIELD_LAYERS, valid[DRAWMODE_HEIGHFIELD_LAYERS]))
m_drawMode = DRAWMODE_HEIGHFIELD_LAYERS;
if (imguiCheck("Layer Contours", m_drawMode == DRAWMODE_LAYER_CONTOURS, valid[DRAWMODE_LAYER_CONTOURS]))
m_drawMode = DRAWMODE_LAYER_CONTOURS;
if (imguiCheck("Layer Meshes", m_drawMode == DRAWMODE_LAYER_MESHES, valid[DRAWMODE_LAYER_MESHES]))
m_drawMode = DRAWMODE_LAYER_MESHES;
if (unavail)
{
imguiValue("Tick 'Keep Itermediate Results'");
@ -575,13 +539,7 @@ void Sample_TileMesh::handleRender()
m_agentMaxSlope, texScale);
m_geom->drawOffMeshConnections(&dd);
}
/* duDebugDrawTriMesh(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(),
m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), 0);
m_geom->drawOffMeshConnections(&dd);*/
glDepthMask(GL_FALSE);
// Draw bounds
@ -598,15 +556,9 @@ void Sample_TileMesh::handleRender()
duDebugDrawGridXZ(&dd, bmin[0],bmin[1],bmin[2], tw,th, s, duRGBA(0,0,0,64), 1.0f);
// Draw active tile
duDebugDrawBoxWire(&dd, m_tileBmin[0],m_tileBmin[1],m_tileBmin[2], m_tileBmax[0],m_tileBmax[1],m_tileBmax[2], m_tileCol, 1.0f);
/* if (m_navMesh)
{
duDebugDrawNavMeshWithClosedList(&dd, *m_navMesh, *m_navQuery, m_navMeshDrawFlags);
if (m_drawPortals)
duDebugDrawNavMeshPortals(&dd, *m_navMesh);
}*/
duDebugDrawBoxWire(&dd, m_tileBmin[0],m_tileBmin[1],m_tileBmin[2],
m_tileBmax[0],m_tileBmax[1],m_tileBmax[2], m_tileCol, 1.0f);
if (m_navMesh && m_navQuery &&
(m_drawMode == DRAWMODE_NAVMESH ||
m_drawMode == DRAWMODE_NAVMESH_TRANS ||
@ -688,30 +640,7 @@ void Sample_TileMesh::handleRender()
duDebugDrawPolyMeshDetail(&dd, *m_dmesh);
glDepthMask(GL_TRUE);
}
if (m_lset && m_drawMode == DRAWMODE_HEIGHFIELD_LAYERS)
{
glDepthMask(GL_FALSE);
duDebugDrawHeightfieldLayersRegions(&dd, *m_lset);
glDepthMask(GL_TRUE);
}
if (m_nlcsets && m_drawMode == DRAWMODE_LAYER_CONTOURS)
{
glDepthMask(GL_FALSE);
for (int i = 0; i < m_nlcsets; ++i)
duDebugDrawLayerContours(&dd, *m_lcsets[i]);
glDepthMask(GL_TRUE);
}
if (m_nlmeshes && m_drawMode == DRAWMODE_LAYER_MESHES)
{
glDepthMask(GL_FALSE);
for (int i = 0; i < m_nlmeshes; ++i)
duDebugDrawLayerPolyMesh(&dd, *m_lmeshes[i]);
glDepthMask(GL_TRUE);
}
m_geom->drawConvexVolumes(&dd);
if (m_tool)
@ -725,32 +654,12 @@ void Sample_TileMesh::handleRenderOverlay(double* proj, double* model, int* view
GLdouble x, y, z;
// Draw start and end point labels
/* if (m_tileBuildTime > 0.0f && gluProject((GLdouble)(m_tileBmin[0]+m_tileBmax[0])/2, (GLdouble)(m_tileBmin[1]+m_tileBmax[1])/2, (GLdouble)(m_tileBmin[2]+m_tileBmax[2])/2,
if (m_tileBuildTime > 0.0f && gluProject((GLdouble)(m_tileBmin[0]+m_tileBmax[0])/2, (GLdouble)(m_tileBmin[1]+m_tileBmax[1])/2, (GLdouble)(m_tileBmin[2]+m_tileBmax[2])/2,
model, proj, view, &x, &y, &z))
{
char text[32];
snprintf(text,32,"%.3fms / %dTris / %.1fkB", m_tileBuildTime, m_tileTriCount, m_tileMemUsage);
imguiDrawText((int)x, (int)y-25, IMGUI_ALIGN_CENTER, text, imguiRGBA(0,0,0,220));
}*/
if (m_lset && m_drawMode == DRAWMODE_HEIGHFIELD_LAYERS)
{
for (int i = 0; i < m_lset->nlayers; ++i)
{
const rcHeightfieldLayer* layer = &m_lset->layers[i];
unsigned int color = duIntToCol(i+1, 255);
float pos[3];
rcVcopy(pos, layer->bmin);
pos[1] = (layer->bmin[1] + layer->bmax[1])*0.5f;
if (gluProject((GLdouble)pos[0], (GLdouble)pos[1], (GLdouble)pos[2], model, proj, view, &x, &y, &z))
{
char text[32];
snprintf(text,32,"Layer %d", i+1);
imguiDrawRoundedRect(x+10-6,y-6,100,20, 4, duTransCol(color,128));
imguiDrawText((int)x+10, (int)y, IMGUI_ALIGN_LEFT, text, imguiRGBA(255,255,255,255));
}
}
}
if (m_tool)
@ -852,7 +761,7 @@ void Sample_TileMesh::buildTile(const float* pos)
if (data)
{
// Remove any previous data (navmesh owns and deletes the data).
m_navMesh->removeTile(m_navMesh->getTileRefAt(tx,ty),0,0);
m_navMesh->removeTile(m_navMesh->getTileRefAt(tx,ty,0),0,0);
// Let the navmesh own the data.
dtStatus status = m_navMesh->addTile(data,dataSize,DT_TILE_FREE_DATA,0,0);
@ -896,7 +805,7 @@ void Sample_TileMesh::removeTile(const float* pos)
m_tileCol = duRGBA(128,32,16,64);
m_navMesh->removeTile(m_navMesh->getTileRefAt(tx,ty),0,0);
m_navMesh->removeTile(m_navMesh->getTileRefAt(tx,ty,0),0,0);
}
void Sample_TileMesh::buildAllTiles()
@ -934,7 +843,7 @@ void Sample_TileMesh::buildAllTiles()
if (data)
{
// Remove any previous data (navmesh owns and deletes the data).
m_navMesh->removeTile(m_navMesh->getTileRefAt(x,y),0,0);
m_navMesh->removeTile(m_navMesh->getTileRefAt(x,y,0),0,0);
// Let the navmesh own the data.
dtStatus status = m_navMesh->addTile(data,dataSize,DT_TILE_FREE_DATA,0,0);
if (dtStatusFailed(status))
@ -962,7 +871,7 @@ void Sample_TileMesh::removeAllTiles()
for (int y = 0; y < th; ++y)
for (int x = 0; x < tw; ++x)
m_navMesh->removeTile(m_navMesh->getTileRefAt(x,y),0,0);
m_navMesh->removeTile(m_navMesh->getTileRefAt(x,y,0),0,0);
}
@ -1109,7 +1018,7 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const
if (!rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, *m_chf))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not erode.");
return false;
return 0;
}
// (Optional) Mark areas.
@ -1142,53 +1051,7 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const
return 0;
}
}
// TODO: Remove
// NOTE! This is for heighfield layer testing only, not needed for general build process!
{
m_lset = rcAllocHeightfieldLayerSet();
if (!m_lset)
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'lset'.");
return 0;
}
if (!rcBuildHeightfieldLayers(m_ctx, *m_chf, m_cfg.borderSize, m_cfg.walkableHeight, *m_lset))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build heighfield layers.");
return 0;
}
m_nlcsets = 0;
m_nlmeshes = 0;
for (int i = 0; i < m_lset->nlayers; ++i)
{
rcBuildLayerRegions(m_ctx, m_lset->layers[i], m_cfg.walkableClimb);
m_lcsets[m_nlcsets] = rcAllocLayerContourSet();
if (!rcBuildLayerContours(m_ctx, m_lset->layers[i],
m_cfg.walkableClimb, m_cfg.maxSimplificationError,
*m_lcsets[m_nlcsets]))
{
break;
}
m_lmeshes[m_nlmeshes] = rcAllocLayerPolyMesh();
if (!rcBuildLayerPolyMesh(m_ctx, *m_lcsets[m_nlcsets],
m_cfg.maxVertsPerPoly,
*m_lmeshes[m_nlmeshes]))
{
break;
}
m_nlcsets++;
m_nlmeshes++;
}
}
// Create contours.
m_cset = rcAllocContourSet();
if (!m_cset)
@ -1248,14 +1111,6 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const
int navDataSize = 0;
if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON)
{
// Remove padding from the polymesh data. TODO: Remove this odditity.
for (int i = 0; i < m_pmesh->nverts; ++i)
{
unsigned short* v = &m_pmesh->verts[i*3];
v[0] -= (unsigned short)m_cfg.borderSize;
v[2] -= (unsigned short)m_cfg.borderSize;
}
if (m_pmesh->nverts >= 0xffff)
{
// The vertex indices are ushorts, and cannot point to more than 0xffff vertices.
@ -1311,26 +1166,18 @@ unsigned char* Sample_TileMesh::buildTileMesh(const int tx, const int ty, const
params.walkableClimb = m_agentMaxClimb;
params.tileX = tx;
params.tileY = ty;
rcVcopy(params.bmin, bmin);
rcVcopy(params.bmax, bmax);
params.tileLayer = 0;
rcVcopy(params.bmin, m_pmesh->bmin);
rcVcopy(params.bmax, m_pmesh->bmax);
params.cs = m_cfg.cs;
params.ch = m_cfg.ch;
params.tileSize = m_cfg.tileSize;
params.buildBvTree = true;
if (!dtCreateNavMeshData(&params, &navData, &navDataSize))
{
m_ctx->log(RC_LOG_ERROR, "Could not build Detour navmesh.");
return 0;
}
// Restore padding so that the debug visualization is correct.
for (int i = 0; i < m_pmesh->nverts; ++i)
{
unsigned short* v = &m_pmesh->verts[i*3];
v[0] += (unsigned short)m_cfg.borderSize;
v[2] += (unsigned short)m_cfg.borderSize;
}
}
}
m_tileMemUsage = navDataSize/1024.0f;