diff --git a/DebugUtils/Include/RecastDebugDraw.h b/DebugUtils/Include/RecastDebugDraw.h index d14517c..8c81a3e 100644 --- a/DebugUtils/Include/RecastDebugDraw.h +++ b/DebugUtils/Include/RecastDebugDraw.h @@ -34,6 +34,9 @@ void duDebugDrawLeanHeightfieldSolid(duDebugDraw* dd, const struct rcLeanHeightf void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset); void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset); +void duDebugDrawLayerContours(duDebugDraw* dd, const struct rcLayerContourSet& lcset); + + void duDebugDrawRegionConnections(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f); void duDebugDrawRawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f); void duDebugDrawContours(struct duDebugDraw* dd, const struct rcContourSet& cset, const float alpha = 1.0f); diff --git a/DebugUtils/Source/RecastDebugDraw.cpp b/DebugUtils/Source/RecastDebugDraw.cpp index 50edfee..a44069f 100644 --- a/DebugUtils/Source/RecastDebugDraw.cpp +++ b/DebugUtils/Source/RecastDebugDraw.cpp @@ -323,17 +323,61 @@ void duDebugDrawLeanHeightfieldSolid(duDebugDraw* dd, const rcLeanHeightfield& l dd->end(); } +static void drawLayerPortals(duDebugDraw* dd, const rcHeightfieldLayer* layer, const unsigned int color) +{ + const float cs = layer->cs; + const float ch = layer->ch; + const float h = (layer->ymax-layer->ymin+1)*ch; + + unsigned int pcol = duLerpCol(color,duRGBA(255,255,255,255),64); + dd->begin(DU_DRAW_LINES, 2.0f); + for (int j = 0; j < layer->nportals; ++j) + { + const rcHeightfieldLayerPortal* portal = &layer->portals[j]; + if (portal->dir == 0 || portal->dir == 2) + { + const int xx = portal->dir == 0 ? (int)portal->pos : (int)portal->pos+1; + const float fx = layer->bmin[0] + xx*cs; + const float fya = layer->bmin[1] + (layer->ymin)*ch; + const float fyb = layer->bmin[1] + (layer->ymin)*ch; + const float fza = layer->bmin[2] + portal->smin*cs; + const float fzb = layer->bmin[2] + portal->smax*cs; + dd->vertex(fx, fya+h, fza, pcol); + dd->vertex(fx, fyb+h, fzb, pcol); + dd->vertex(fx, fya, fza, pcol); + dd->vertex(fx, fya+h, fza, pcol); + dd->vertex(fx, fyb, fzb, pcol); + dd->vertex(fx, fyb+h, fzb, pcol); + } + else if (portal->dir == 3 || portal->dir == 1) + { + const int yy = portal->dir == 3 ? (int)portal->pos : (int)portal->pos+1; + const float fxa = layer->bmin[0] + portal->smin*cs; + const float fxb = layer->bmin[0] + portal->smax*cs; + const float fya = layer->bmin[1] + (layer->ymin)*ch; + const float fyb = layer->bmin[1] + (layer->ymin)*ch; + const float fz = layer->bmin[2] + yy*cs; + dd->vertex(fxa, fya+h, fz, pcol); + dd->vertex(fxb, fyb+h, fz, pcol); + dd->vertex(fxa, fya, fz, pcol); + dd->vertex(fxa, fya+h, fz, pcol); + dd->vertex(fxb, fyb, fz, pcol); + dd->vertex(fxb, fyb+h, fz, pcol); + } + } + dd->end(); +} + void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLayerSet& lset) { if (!dd) return; - const float cs = lset.cs; - const float ch = lset.ch; - 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; @@ -341,10 +385,10 @@ void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLay // Layer bounds float bmin[3], bmax[3]; - rcVcopy(bmin, lset.bmin); - rcVcopy(bmax, lset.bmax); - bmin[1] = lset.bmin[1] + (layer->ymin-1)*ch; - bmax[1] = lset.bmin[1] + (layer->ymax+1)*ch; + rcVcopy(bmin, layer->bmin); + rcVcopy(bmax, layer->bmax); + bmin[1] = layer->bmin[1] + (layer->ymin-1)*ch; + bmax[1] = layer->bmin[1] + (layer->ymax+1)*ch; duDebugDrawBoxWire(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duTransCol(color,128), 2.0f); // Layer height @@ -366,9 +410,9 @@ void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLay else col = duLerpCol(color, duIntToCol(area, 255), 32); - const float fx = lset.bmin[0] + x*cs; - const float fy = lset.bmin[1] + (h+1)*ch; - const float fz = lset.bmin[2] + y*cs; + 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); @@ -379,39 +423,7 @@ void duDebugDrawHeightfieldLayers(duDebugDraw* dd, const struct rcHeightfieldLay dd->end(); // Portals - unsigned int pcol = duLerpCol(color,duRGBA(255,255,255,255),128); - dd->begin(DU_DRAW_LINES, 2.0f); - for (int j = 0; j < layer->nportals; ++j) - { - const rcHeightfieldLayerPortal* portal = &layer->portals[j]; - if (portal->dir == 0 || portal->dir == 2) - { - const int ha = (int)layer->heights[portal->pos + portal->smin*w]; - const int hb = (int)layer->heights[portal->pos + (portal->smax-1)*w]; - const int xx = (portal->dir == 0) ? portal->pos : portal->pos+1; - const float fx = lset.bmin[0] + xx*cs; - const float fya = lset.bmin[1] + (ha+4)*ch; - const float fyb = lset.bmin[1] + (hb+4)*ch; - const float fza = lset.bmin[2] + portal->smin*cs; - const float fzb = lset.bmin[2] + portal->smax*cs; - dd->vertex(fx, fya, fza, pcol); - dd->vertex(fx, fyb, fzb, pcol); - } - else if (portal->dir == 3 || portal->dir == 1) - { - const int ha = (int)layer->heights[portal->smin + portal->pos*w]; - const int hb = (int)layer->heights[(portal->smax-1) + portal->pos*w]; - const int yy = (portal->dir == 3) ? portal->pos : portal->pos+1; - const float fxa = lset.bmin[0] + portal->smin*cs; - const float fxb = lset.bmin[0] + portal->smax*cs; - const float fya = lset.bmin[1] + (ha+3)*ch; - const float fyb = lset.bmin[1] + (hb+3)*ch; - const float fz = lset.bmin[2] + yy*cs; - dd->vertex(fxa, fya, fz, pcol); - dd->vertex(fxb, fyb, fz, pcol); - } - } - dd->end(); + drawLayerPortals(dd, layer, color); } } @@ -420,13 +432,12 @@ void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightf { if (!dd) return; - const float cs = lset.cs; - const float ch = lset.ch; - 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; @@ -434,10 +445,10 @@ void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightf // Layer bounds float bmin[3], bmax[3]; - rcVcopy(bmin, lset.bmin); - rcVcopy(bmax, lset.bmax); - bmin[1] = lset.bmin[1] + (layer->ymin-1)*ch; - bmax[1] = lset.bmin[1] + (layer->ymax+1)*ch; + rcVcopy(bmin, layer->bmin); + rcVcopy(bmax, layer->bmax); + bmin[1] = layer->bmin[1] + (layer->ymin-1)*ch; + bmax[1] = layer->bmin[1] + (layer->ymax+1)*ch; duDebugDrawBoxWire(dd, bmin[0],bmin[1],bmin[2], bmax[0],bmax[1],bmax[2], duTransCol(color,128), 2.0f); // Layer height @@ -453,9 +464,9 @@ void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightf unsigned int col = duLerpCol(color, duIntToCol(area, 255), 128); - const float fx = lset.bmin[0] + x*cs; - const float fy = lset.bmin[1] + (h+1)*ch; - const float fz = lset.bmin[2] + y*cs; + 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); @@ -464,45 +475,74 @@ void duDebugDrawHeightfieldLayersRegions(duDebugDraw* dd, const struct rcHeightf } } dd->end(); - -/* // Portals - unsigned int pcol = duLerpCol(color,duRGBA(255,255,255,255),128); - dd->begin(DU_DRAW_LINES, 2.0f); - for (int j = 0; j < layer->nportals; ++j) - { - const rcHeightfieldLayerPortal* portal = &layer->portals[j]; - if (portal->dir == 0 || portal->dir == 2) - { - const int ha = (int)layer->heights[portal->pos + portal->smin*w]; - const int hb = (int)layer->heights[portal->pos + (portal->smax-1)*w]; - const int xx = (portal->dir == 0) ? portal->pos : portal->pos+1; - const float fx = lset.bmin[0] + xx*cs; - const float fya = lset.bmin[1] + (ha+4)*ch; - const float fyb = lset.bmin[1] + (hb+4)*ch; - const float fza = lset.bmin[2] + portal->smin*cs; - const float fzb = lset.bmin[2] + portal->smax*cs; - dd->vertex(fx, fya, fza, pcol); - dd->vertex(fx, fyb, fzb, pcol); - } - else if (portal->dir == 3 || portal->dir == 1) - { - const int ha = (int)layer->heights[portal->smin + portal->pos*w]; - const int hb = (int)layer->heights[(portal->smax-1) + portal->pos*w]; - const int yy = (portal->dir == 3) ? portal->pos : portal->pos+1; - const float fxa = lset.bmin[0] + portal->smin*cs; - const float fxb = lset.bmin[0] + portal->smax*cs; - const float fya = lset.bmin[1] + (ha+3)*ch; - const float fyb = lset.bmin[1] + (hb+3)*ch; - const float fz = lset.bmin[2] + yy*cs; - dd->vertex(fxa, fya, fz, pcol); - dd->vertex(fxb, fyb, fz, pcol); - } - } - dd->end();*/ + + // Portals + drawLayerPortals(dd, layer, color); } } +void duDebugDrawLayerContours(duDebugDraw* dd, const struct rcLayerContourSet& lcset) +{ + if (!dd) return; + + const float* orig = lcset.bmin; + const float cs = lcset.cs; + const float ch = lcset.ch; + + const unsigned char a = 255;// (unsigned char)(alpha*255.0f); + + dd->begin(DU_DRAW_LINES, 2.0f); + + for (int i = 0; i < lcset.nconts; ++i) + { + const rcLayerContour& c = lcset.conts[i]; + unsigned int color = 0; + + for (int j = 0; j < c.nverts; ++j) + { + const int k = (j+1) % c.nverts; + const unsigned char* va = &c.verts[j*4]; + const unsigned char* vb = &c.verts[k*4]; + 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; + color = duIntToCol(vb[3], a); + dd->vertex(ax,ay,az,color); + dd->vertex(bx,by,bz,duDarkenCol(color)); + } + } + dd->end(); + + dd->begin(DU_DRAW_POINTS, 4.0f); + + for (int i = 0; i < lcset.nconts; ++i) + { + const rcLayerContour& c = lcset.conts[i]; + unsigned int color = 0; + + for (int j = 0; j < c.nverts; ++j) + { + const int k = (j+1) % c.nverts; + const unsigned char* va = &c.verts[j*4]; + const unsigned char* vb = &c.verts[k*4]; + + color = duDarkenCol(duIntToCol(va[3], a)); + if (va[3] != vb[3]) + color = duRGBA(255,255,255,a); + + float fx = orig[0] + va[0]*cs; + float fy = orig[1] + (va[1]+1+(i&1))*ch; + float fz = orig[2] + va[2]*cs; + dd->vertex(fx,fy,fz, color); + } + } + dd->end(); +} + static void getContourCenter(const rcContour* cont, const float* orig, float cs, float ch, float* center) { center[0] = 0; diff --git a/Recast/Include/Recast.h b/Recast/Include/Recast.h index a267eca..945a5f3 100644 --- a/Recast/Include/Recast.h +++ b/Recast/Include/Recast.h @@ -224,15 +224,19 @@ struct rcLeanHeightfield struct rcHeightfieldLayerPortal { - unsigned short pos; // Position of the portal. - unsigned short smin, smax; // Span min/max of the portal. + unsigned char pos; // Position of the portal. unsigned char dir; // Direction of the portal (same as used by rcGetCon()). + unsigned char smin, smax; // Span min/max of the portal. + unsigned short hmin, hmax; // Span min/max of the portal. }; 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 short ymin, ymax; // Height min/max range. unsigned short* heights; // Heighfield. unsigned char* areas; // Area types. @@ -244,8 +248,6 @@ struct rcHeightfieldLayerSet { rcHeightfieldLayer* layers; // Pointer to layers. int nlayers; // Number of layers. - float bmin[3], bmax[3]; // Bounding box of the heightfield. - float cs, ch; // Cell size and height. }; rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet(); @@ -751,6 +753,34 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, 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); + + + + // Builds simplified contours from the regions outlines. // Params: // chf - (in) compact heightfield which has regions set. diff --git a/Recast/Source/Recast.cpp b/Recast/Source/Recast.cpp index 1e70a0d..733eaaf 100644 --- a/Recast/Source/Recast.cpp +++ b/Recast/Source/Recast.cpp @@ -112,6 +112,28 @@ void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset) rcFree(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); +} + + + rcContourSet* rcAllocContourSet() { rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM); diff --git a/Recast/Source/RecastContour.cpp b/Recast/Source/RecastContour.cpp index 1906b6e..630784a 100644 --- a/Recast/Source/RecastContour.cpp +++ b/Recast/Source/RecastContour.cpp @@ -340,7 +340,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, endi = ai; } - // Tessellate only outer edges oredges between areas. + // Tessellate only outer edges or edges between areas. if ((points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0 || (points[ci*4+3] & RC_AREA_BORDER)) { diff --git a/Recast/Source/RecastLayers.cpp b/Recast/Source/RecastLayers.cpp index e321f3f..f30a151 100644 --- a/Recast/Source/RecastLayers.cpp +++ b/Recast/Source/RecastLayers.cpp @@ -476,15 +476,16 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, const int lw = w - borderSize*2; const int lh = h - borderSize*2; + // Build contracted bbox for layers. + float bmin[3], bmax[3]; + rcVcopy(bmin, chf.bmin); + rcVcopy(bmax, chf.bmax); + bmin[0] += borderSize*chf.cs; + bmin[2] += borderSize*chf.cs; + bmax[0] -= borderSize*chf.cs; + bmax[2] -= borderSize*chf.cs; + lset.nlayers = (int)layerId; - rcVcopy(lset.bmin, chf.bmin); - rcVcopy(lset.bmax, chf.bmax); - lset.bmin[0] += borderSize*chf.cs; - lset.bmin[2] += borderSize*chf.cs; - lset.bmax[0] -= borderSize*chf.cs; - lset.bmax[2] -= borderSize*chf.cs; - lset.cs = chf.cs; - lset.ch = chf.ch; lset.layers = (rcHeightfieldLayer*)rcAlloc(sizeof(rcHeightfieldLayer)*lset.nlayers, RC_ALLOC_PERM); if (!lset.layers) @@ -512,6 +513,11 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, layer->width = lw; layer->height = lh; + layer->cs = chf.cs; + layer->ch = chf.ch; + // TODO: Should this be local bbox instead? + rcVcopy(layer->bmin, bmin); + rcVcopy(layer->bmax, bmax); layer->heights = (unsigned short*)rcAlloc(sizeof(unsigned short)*lw*lh, RC_ALLOC_PERM); if (!layer->heights) @@ -622,15 +628,15 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, if (start[j] != -1) { // Add portal. - rcHeightfieldLayerPortal* portal = allocPortal(&layer->portals,layer->nportals,cportals); + rcHeightfieldLayerPortal* portal = allocPortal(&layer->portals, layer->nportals, cportals); if (!portal) { ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'portals' (%d).", cportals); return false; } - portal->pos = (unsigned short)y; - portal->smin = (unsigned short)start[j]; - portal->smax = (unsigned short)x; + portal->pos = (unsigned char)y/*+off[j]*/; + portal->smin = (unsigned char)start[j]; + portal->smax = (unsigned char)x; portal->dir = dir[j]; start[j] = -1; @@ -669,9 +675,9 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'portals' (%d).", cportals); return false; } - portal->pos = (unsigned short)x; - portal->smin = (unsigned short)start[j]; - portal->smax = (unsigned short)y; + portal->pos = (unsigned char)x/*+off[j]*/; + portal->smin = (unsigned char)start[j]; + portal->smax = (unsigned char)y; portal->dir = dir[j]; start[j] = -1; @@ -690,7 +696,7 @@ bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, inline bool isConnected(rcHeightfieldLayer& layer, const int ia, const int ib, const int walkableClimb) { - if (layer.areas[ib] == RC_NULL_AREA) return false; + if (layer.areas[ia] != layer.areas[ib]) return false; if (rcAbs((int)layer.heights[ia] - (int)layer.heights[ib]) > walkableClimb) return false; return true; } @@ -927,6 +933,8 @@ bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int wa for (int i = 0; i < nregs; ++i) regs[i].regId = remap[regs[i].regId]; + layer.regCount = regId; + for (int i = 0; i < w*h; ++i) { if (layer.regs[i] != 0xff) @@ -935,3 +943,489 @@ bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int wa return true; } + +static bool allocVert(rcLayerContour& cont, int& cverts) +{ + if (cont.nverts+1 > cverts) + { + cverts = !cverts ? 16 : cverts*2; + unsigned char* nv = (unsigned char*)rcAlloc(cverts*4, RC_ALLOC_TEMP); + if (!nv) return false; + if (cont.nverts) + memcpy(nv, cont.verts, cont.nverts*4); + rcFree(cont.verts); + cont.verts = nv; + } + return true; +} + +static bool addVertex(rcLayerContour& cont, int x, int y, int z, int r, int& cverts) +{ + // Try to merge with existing segments. + if (cont.nverts > 1) + { + unsigned char* pa = &cont.verts[(cont.nverts-2)*4]; + unsigned char* pb = &cont.verts[(cont.nverts-1)*4]; + if ((int)pb[3] == r) + { + if (pa[0] == pb[0] && (int)pb[0] == x) + { + // The verts are aligned aling x-axis, update z. + pb[1] = (unsigned char)y; + pb[2] = (unsigned char)z; + pb[3] = (unsigned char)r; + return true; + } + else if (pa[2] == pb[2] && (int)pb[2] == z) + { + // The verts are aligned aling z-axis, update x. + pb[0] = (unsigned char)x; + pb[1] = (unsigned char)y; + pb[3] = (unsigned char)r; + return true; + } + } + } + + // Add new point. + if (!allocVert(cont, cverts)) + return false; + + unsigned char* v = &cont.verts[cont.nverts*4]; + v[0] = (unsigned char)x; + v[1] = (unsigned char)y; + v[2] = (unsigned char)z; + v[3] = (unsigned char)r; + cont.nverts++; + + return true; +} + + +static unsigned char getNeighbourReg(rcHeightfieldLayer& layer, + const unsigned char* cons, + const int ax, const int ay, const int dir, + const int walkableClimb) +{ + const int ia = ax+ay*layer.width; + + const int bx = ax + rcGetDirOffsetX(dir); + const int by = ay + rcGetDirOffsetY(dir); + if (bx < 0 || by < 0 || bx >= layer.width || by >= layer.height) + { + if (cons[ia] & (1<