Merge branch 'master' of https://github.com/axelrodR/recastnavigation into axelrodR-master
This commit is contained in:
commit
1b04dc9c80
@ -744,60 +744,20 @@ static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin,
|
|||||||
static void getHeightData(const rcCompactHeightfield& chf,
|
static void getHeightData(const rcCompactHeightfield& chf,
|
||||||
const unsigned short* poly, const int npoly,
|
const unsigned short* poly, const int npoly,
|
||||||
const unsigned short* verts, const int bs,
|
const unsigned short* verts, const int bs,
|
||||||
rcHeightPatch& hp, rcIntArray& stack)
|
rcHeightPatch& hp, rcIntArray& stack,
|
||||||
|
int region)
|
||||||
{
|
{
|
||||||
// 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)
|
// Note: Reads to the compact heightfield are offset by border size (bs)
|
||||||
// since border size offset is already removed from the polymesh vertices.
|
// 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);
|
stack.resize(0);
|
||||||
|
|
||||||
static const int offset[9*2] =
|
static const int offset[9*2] =
|
||||||
{
|
{
|
||||||
0,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0,
|
0,0, -1,0, 0,1, 1,0, 0,-1, -1,-1, -1,1, 1,1, 1,-1
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use poly vertices as seed points for the flood fill.
|
// find the center of the polygon
|
||||||
for (int j = 0; j < npoly; ++j)
|
|
||||||
{
|
|
||||||
int cx = 0, cz = 0, ci =-1;
|
|
||||||
int dmin = RC_UNSET_HEIGHT;
|
|
||||||
for (int k = 0; k < 9; ++k)
|
|
||||||
{
|
|
||||||
const int ax = (int)verts[poly[j]*3+0] + offset[k*2+0];
|
|
||||||
const int ay = (int)verts[poly[j]*3+1];
|
|
||||||
const int az = (int)verts[poly[j]*3+2] + offset[k*2+1];
|
|
||||||
if (ax < hp.xmin || ax >= hp.xmin+hp.width ||
|
|
||||||
az < hp.ymin || az >= hp.ymin+hp.height)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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];
|
|
||||||
int d = rcAbs(ay - (int)s.y);
|
|
||||||
if (d < dmin)
|
|
||||||
{
|
|
||||||
cx = ax;
|
|
||||||
cz = az;
|
|
||||||
ci = i;
|
|
||||||
dmin = d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ci != -1)
|
|
||||||
{
|
|
||||||
stack.push(cx);
|
|
||||||
stack.push(cz);
|
|
||||||
stack.push(ci);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find center of the polygon using flood fill.
|
|
||||||
int pcx = 0, pcz = 0;
|
int pcx = 0, pcz = 0;
|
||||||
for (int j = 0; j < npoly; ++j)
|
for (int j = 0; j < npoly; ++j)
|
||||||
{
|
{
|
||||||
@ -806,58 +766,37 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
|||||||
}
|
}
|
||||||
pcx /= npoly;
|
pcx /= npoly;
|
||||||
pcz /= npoly;
|
pcz /= npoly;
|
||||||
|
|
||||||
for (int i = 0; i < stack.size(); i += 3)
|
|
||||||
{
|
|
||||||
int cx = stack[i+0];
|
|
||||||
int cy = stack[i+1];
|
|
||||||
int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width;
|
|
||||||
hp.data[idx] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (stack.size() > 0)
|
|
||||||
{
|
|
||||||
int ci = stack.pop();
|
|
||||||
int cy = stack.pop();
|
|
||||||
int cx = stack.pop();
|
|
||||||
|
|
||||||
// Check if close to center of the polygon.
|
|
||||||
if (rcAbs(cx-pcx) <= 1 && rcAbs(cy-pcz) <= 1)
|
|
||||||
{
|
|
||||||
stack.resize(0);
|
|
||||||
stack.push(cx);
|
|
||||||
stack.push(cy);
|
|
||||||
stack.push(ci);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rcCompactSpan& cs = chf.spans[ci];
|
|
||||||
|
|
||||||
for (int dir = 0; dir < 4; ++dir)
|
|
||||||
{
|
|
||||||
if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue;
|
|
||||||
|
|
||||||
const int ax = cx + rcGetDirOffsetX(dir);
|
|
||||||
const int ay = cy + rcGetDirOffsetY(dir);
|
|
||||||
|
|
||||||
if (ax < hp.xmin || ax >= (hp.xmin+hp.width) ||
|
|
||||||
ay < hp.ymin || ay >= (hp.ymin+hp.height))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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;
|
// find a span with the right region around this point
|
||||||
hp.data[idx] = 1;
|
// No need to check for connectivity because the region ensures it
|
||||||
|
for (int dir = 0; dir < 9; ++dir)
|
||||||
stack.push(ax);
|
{
|
||||||
stack.push(ay);
|
int ax = pcx + offset[dir*2+0];
|
||||||
stack.push(ai);
|
int az = pcz + offset[dir*2+1];
|
||||||
|
|
||||||
|
if (ax < hp.xmin || ax >= hp.xmin+hp.width ||
|
||||||
|
az < hp.ymin || az >= hp.ymin+hp.height)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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];
|
||||||
|
if (s.reg == region)
|
||||||
|
{
|
||||||
|
stack.push(ax);
|
||||||
|
stack.push(az);
|
||||||
|
stack.push(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (stack.size() > 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Floodfill the heightfield to get 2D height data,
|
||||||
|
// starting at center location found above as seed.
|
||||||
|
|
||||||
memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
|
memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height);
|
||||||
|
|
||||||
// Mark start locations.
|
// Mark start locations.
|
||||||
@ -914,7 +853,6 @@ static void getHeightData(const rcCompactHeightfield& chf,
|
|||||||
stack.push(ai);
|
stack.push(ai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char getEdgeFlags(const float* va, const float* vb,
|
static unsigned char getEdgeFlags(const float* va, const float* vb,
|
||||||
@ -1072,7 +1010,7 @@ bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompa
|
|||||||
hp.ymin = bounds[i*4+2];
|
hp.ymin = bounds[i*4+2];
|
||||||
hp.width = bounds[i*4+1]-bounds[i*4+0];
|
hp.width = bounds[i*4+1]-bounds[i*4+0];
|
||||||
hp.height = bounds[i*4+3]-bounds[i*4+2];
|
hp.height = bounds[i*4+3]-bounds[i*4+2];
|
||||||
getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack);
|
getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack, mesh.regs[i]);
|
||||||
|
|
||||||
// Build detail mesh.
|
// Build detail mesh.
|
||||||
int nverts = 0;
|
int nverts = 0;
|
||||||
|
@ -95,7 +95,7 @@ static void addSpan(rcHeightfield& hf, const int x, const int y,
|
|||||||
s->area = area;
|
s->area = area;
|
||||||
s->next = 0;
|
s->next = 0;
|
||||||
|
|
||||||
// Empty cell, add he first span.
|
// Empty cell, add the first span.
|
||||||
if (!hf.spans[idx])
|
if (!hf.spans[idx])
|
||||||
{
|
{
|
||||||
hf.spans[idx] = s;
|
hf.spans[idx] = s;
|
||||||
@ -169,36 +169,53 @@ void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y,
|
|||||||
addSpan(hf, x,y, smin, smax, area, flagMergeThr);
|
addSpan(hf, x,y, smin, smax, area, flagMergeThr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd)
|
// divides a convex polygons into two convex polygons on both sides of a line
|
||||||
|
static void dividePoly(const float* in, int nbIn,
|
||||||
|
float* out1, int* nb1,
|
||||||
|
float* out2, int* nb2,
|
||||||
|
float x, int axis)
|
||||||
{
|
{
|
||||||
float d[12];
|
float d[12];
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < nbIn; ++i)
|
||||||
d[i] = pnx*in[i*3+0] + pnz*in[i*3+2] + pd;
|
d[i] = x - in[i*3+axis];
|
||||||
|
|
||||||
int m = 0;
|
int m = 0, n = 0;
|
||||||
for (int i = 0, j = n-1; i < n; j=i, ++i)
|
for (int i = 0, j = nbIn-1; i < nbIn; j=i, ++i)
|
||||||
{
|
{
|
||||||
bool ina = d[j] >= 0;
|
bool ina = d[j] >= 0;
|
||||||
bool inb = d[i] >= 0;
|
bool inb = d[i] >= 0;
|
||||||
if (ina != inb)
|
if (ina != inb)
|
||||||
{
|
{
|
||||||
float s = d[j] / (d[j] - d[i]);
|
float s = d[j] / (d[j] - d[i]);
|
||||||
out[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
|
out1[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
|
||||||
out[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
|
out1[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
|
||||||
out[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
|
out1[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
|
||||||
|
rcVcopy(out2 + n*3, out1 + m*3);
|
||||||
m++;
|
m++;
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
if (inb)
|
if (inb)
|
||||||
{
|
{
|
||||||
out[m*3+0] = in[i*3+0];
|
out1[m*3+0] = in[i*3+0];
|
||||||
out[m*3+1] = in[i*3+1];
|
out1[m*3+1] = in[i*3+1];
|
||||||
out[m*3+2] = in[i*3+2];
|
out1[m*3+2] = in[i*3+2];
|
||||||
m++;
|
m++;
|
||||||
|
if (d[0] != 0) // not on the line
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// i-th point is on the other half plane or on the line
|
||||||
|
out2[n*3+0] = in[i*3+0];
|
||||||
|
out2[n*3+1] = in[i*3+1];
|
||||||
|
out2[n*3+2] = in[i*3+2];
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
return m;
|
|
||||||
|
*nb1 = m;
|
||||||
|
*nb2 = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
||||||
const unsigned char area, rcHeightfield& hf,
|
const unsigned char area, rcHeightfield& hf,
|
||||||
const float* bmin, const float* bmax,
|
const float* bmin, const float* bmax,
|
||||||
@ -222,48 +239,57 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2,
|
|||||||
if (!overlapBounds(bmin, bmax, tmin, tmax))
|
if (!overlapBounds(bmin, bmax, tmin, tmax))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Calculate the footpring of the triangle on the grid.
|
// Calculate the footprint of the triangle on the grid's y-axis
|
||||||
int x0 = (int)((tmin[0] - bmin[0])*ics);
|
|
||||||
int y0 = (int)((tmin[2] - bmin[2])*ics);
|
int y0 = (int)((tmin[2] - bmin[2])*ics);
|
||||||
int x1 = (int)((tmax[0] - bmin[0])*ics);
|
|
||||||
int y1 = (int)((tmax[2] - bmin[2])*ics);
|
int y1 = (int)((tmax[2] - bmin[2])*ics);
|
||||||
x0 = rcClamp(x0, 0, w-1);
|
|
||||||
y0 = rcClamp(y0, 0, h-1);
|
y0 = rcClamp(y0, 0, h-1);
|
||||||
x1 = rcClamp(x1, 0, w-1);
|
|
||||||
y1 = rcClamp(y1, 0, h-1);
|
y1 = rcClamp(y1, 0, h-1);
|
||||||
|
|
||||||
// Clip the triangle into all grid cells it touches.
|
// Clip the triangle into all grid cells it touches.
|
||||||
float in[7*3], out[7*3], inrow[7*3];
|
float buf[7*3*4];
|
||||||
|
float *in = buf, *inrow = buf+7*3, *p1 = inrow+7*3, *p2 = p1+7*3;
|
||||||
|
|
||||||
|
rcVcopy(&in[0], v0);
|
||||||
|
rcVcopy(&in[1*3], v1);
|
||||||
|
rcVcopy(&in[2*3], v2);
|
||||||
|
int nvrow, nvIn = 3;
|
||||||
|
|
||||||
for (int y = y0; y <= y1; ++y)
|
for (int y = y0; y <= y1; ++y)
|
||||||
{
|
{
|
||||||
// Clip polygon to row.
|
// Clip polygon to row. Store the remaining polygon as well
|
||||||
rcVcopy(&in[0], v0);
|
|
||||||
rcVcopy(&in[1*3], v1);
|
|
||||||
rcVcopy(&in[2*3], v2);
|
|
||||||
int nvrow = 3;
|
|
||||||
const float cz = bmin[2] + y*cs;
|
const float cz = bmin[2] + y*cs;
|
||||||
nvrow = clipPoly(in, nvrow, out, 0, 1, -cz);
|
dividePoly(in, nvIn, inrow, &nvrow, p1, &nvIn, cz+cs, 2);
|
||||||
if (nvrow < 3) continue;
|
rcSwap(in, p1);
|
||||||
nvrow = clipPoly(out, nvrow, inrow, 0, -1, cz+cs);
|
|
||||||
if (nvrow < 3) continue;
|
if (nvrow < 3) continue;
|
||||||
|
|
||||||
|
// find the horizontal bounds in the row
|
||||||
|
float minX = inrow[0], maxX = inrow[0];
|
||||||
|
for (int i=1; i<nvrow; ++i)
|
||||||
|
{
|
||||||
|
if (minX > inrow[i*3]) minX = inrow[i*3];
|
||||||
|
if (maxX < inrow[i*3]) maxX = inrow[i*3];
|
||||||
|
}
|
||||||
|
int x0 = (int)((minX - bmin[0])*ics);
|
||||||
|
int x1 = (int)((maxX - bmin[0])*ics);
|
||||||
|
x0 = rcClamp(x0, 0, w-1);
|
||||||
|
x1 = rcClamp(x1, 0, w-1);
|
||||||
|
|
||||||
|
int nv, nv2 = nvrow;
|
||||||
|
|
||||||
for (int x = x0; x <= x1; ++x)
|
for (int x = x0; x <= x1; ++x)
|
||||||
{
|
{
|
||||||
// Clip polygon to column.
|
// Clip polygon to column. store the remaining polygon as well
|
||||||
int nv = nvrow;
|
|
||||||
const float cx = bmin[0] + x*cs;
|
const float cx = bmin[0] + x*cs;
|
||||||
nv = clipPoly(inrow, nv, out, 1, 0, -cx);
|
dividePoly(inrow, nv2, p1, &nv, p2, &nv2, cx+cs, 0);
|
||||||
if (nv < 3) continue;
|
rcSwap(inrow, p2);
|
||||||
nv = clipPoly(out, nv, in, -1, 0, cx+cs);
|
|
||||||
if (nv < 3) continue;
|
if (nv < 3) continue;
|
||||||
|
|
||||||
// Calculate min and max of the span.
|
// Calculate min and max of the span.
|
||||||
float smin = in[1], smax = in[1];
|
float smin = p1[1], smax = p1[1];
|
||||||
for (int i = 1; i < nv; ++i)
|
for (int i = 1; i < nv; ++i)
|
||||||
{
|
{
|
||||||
smin = rcMin(smin, in[i*3+1]);
|
smin = rcMin(smin, p1[i*3+1]);
|
||||||
smax = rcMax(smax, in[i*3+1]);
|
smax = rcMax(smax, p1[i*3+1]);
|
||||||
}
|
}
|
||||||
smin -= bmin[1];
|
smin -= bmin[1];
|
||||||
smax -= bmin[1];
|
smax -= bmin[1];
|
||||||
|
@ -286,7 +286,10 @@ static bool floodRegion(int x, int y, int i,
|
|||||||
if (nr & RC_BORDER_REG) // Do not take borders into account.
|
if (nr & RC_BORDER_REG) // Do not take borders into account.
|
||||||
continue;
|
continue;
|
||||||
if (nr != 0 && nr != r)
|
if (nr != 0 && nr != r)
|
||||||
|
{
|
||||||
ar = nr;
|
ar = nr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const rcCompactSpan& as = chf.spans[ai];
|
const rcCompactSpan& as = chf.spans[ai];
|
||||||
|
|
||||||
@ -300,7 +303,10 @@ static bool floodRegion(int x, int y, int i,
|
|||||||
continue;
|
continue;
|
||||||
unsigned short nr2 = srcReg[ai2];
|
unsigned short nr2 = srcReg[ai2];
|
||||||
if (nr2 != 0 && nr2 != r)
|
if (nr2 != 0 && nr2 != r)
|
||||||
|
{
|
||||||
ar = nr2;
|
ar = nr2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,30 +346,44 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
|
|||||||
rcCompactHeightfield& chf,
|
rcCompactHeightfield& chf,
|
||||||
unsigned short* srcReg, unsigned short* srcDist,
|
unsigned short* srcReg, unsigned short* srcDist,
|
||||||
unsigned short* dstReg, unsigned short* dstDist,
|
unsigned short* dstReg, unsigned short* dstDist,
|
||||||
rcIntArray& stack)
|
rcIntArray& stack,
|
||||||
|
bool fillStack)
|
||||||
{
|
{
|
||||||
const int w = chf.width;
|
const int w = chf.width;
|
||||||
const int h = chf.height;
|
const int h = chf.height;
|
||||||
|
|
||||||
// Find cells revealed by the raised level.
|
if (fillStack)
|
||||||
stack.resize(0);
|
|
||||||
for (int y = 0; y < h; ++y)
|
|
||||||
{
|
{
|
||||||
for (int x = 0; x < w; ++x)
|
// Find cells revealed by the raised level.
|
||||||
|
stack.resize(0);
|
||||||
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
const rcCompactCell& c = chf.cells[x+y*w];
|
for (int x = 0; x < w; ++x)
|
||||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
|
||||||
{
|
{
|
||||||
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
|
const rcCompactCell& c = chf.cells[x+y*w];
|
||||||
|
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
||||||
{
|
{
|
||||||
stack.push(x);
|
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
|
||||||
stack.push(y);
|
{
|
||||||
stack.push(i);
|
stack.push(x);
|
||||||
|
stack.push(y);
|
||||||
|
stack.push(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // use cells in the input stack
|
||||||
|
{
|
||||||
|
// mark all cells which already have a region
|
||||||
|
for (int j=0; j<stack.size(); j+=3)
|
||||||
|
{
|
||||||
|
int i = stack[j+2];
|
||||||
|
if (srcReg[i] != 0)
|
||||||
|
stack[j+2] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int iter = 0;
|
int iter = 0;
|
||||||
while (stack.size() > 0)
|
while (stack.size() > 0)
|
||||||
{
|
{
|
||||||
@ -434,6 +454,61 @@ static unsigned short* expandRegions(int maxIter, unsigned short level,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void sortCellsByLevel(unsigned short startLevel,
|
||||||
|
rcCompactHeightfield& chf,
|
||||||
|
unsigned short* srcReg,
|
||||||
|
unsigned int nbStacks, rcIntArray* stacks,
|
||||||
|
unsigned short loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift
|
||||||
|
{
|
||||||
|
const int w = chf.width;
|
||||||
|
const int h = chf.height;
|
||||||
|
startLevel = startLevel >> loglevelsPerStack;
|
||||||
|
|
||||||
|
for (unsigned int j=0; j<nbStacks; ++j)
|
||||||
|
stacks[j].resize(0);
|
||||||
|
|
||||||
|
// put all cells in the level range into the appropriate stacks
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (chf.areas[i] == RC_NULL_AREA || srcReg[i] != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int level = chf.dist[i] >> loglevelsPerStack;
|
||||||
|
int sId = startLevel - level;
|
||||||
|
if (sId >= (int)nbStacks)
|
||||||
|
continue;
|
||||||
|
if (sId < 0)
|
||||||
|
sId = 0;
|
||||||
|
|
||||||
|
stacks[sId].push(x);
|
||||||
|
stacks[sId].push(y);
|
||||||
|
stacks[sId].push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void appendStacks(rcIntArray& srcStack, rcIntArray& dstStack,
|
||||||
|
unsigned short* srcReg)
|
||||||
|
{
|
||||||
|
for (int j=0; j<srcStack.size(); j+=3)
|
||||||
|
{
|
||||||
|
int i = srcStack[j+2];
|
||||||
|
if ((i < 0) || (srcReg[i] != 0))
|
||||||
|
continue;
|
||||||
|
dstStack.push(srcStack[j]);
|
||||||
|
dstStack.push(srcStack[j+1]);
|
||||||
|
dstStack.push(srcStack[j+2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct rcRegion
|
struct rcRegion
|
||||||
{
|
{
|
||||||
inline rcRegion(unsigned short i) :
|
inline rcRegion(unsigned short i) :
|
||||||
@ -1236,7 +1311,13 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
|
ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
|
||||||
|
|
||||||
|
const int LOG_NB_STACKS = 3;
|
||||||
|
const int NB_STACKS = 1 << LOG_NB_STACKS;
|
||||||
|
rcIntArray lvlStacks[NB_STACKS];
|
||||||
|
for (int i=0; i<NB_STACKS; ++i)
|
||||||
|
lvlStacks[i].resize(1024);
|
||||||
|
|
||||||
rcIntArray stack(1024);
|
rcIntArray stack(1024);
|
||||||
rcIntArray visited(1024);
|
rcIntArray visited(1024);
|
||||||
|
|
||||||
@ -1271,14 +1352,25 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
|||||||
chf.borderSize = borderSize;
|
chf.borderSize = borderSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sId = -1;
|
||||||
while (level > 0)
|
while (level > 0)
|
||||||
{
|
{
|
||||||
level = level >= 2 ? level-2 : 0;
|
level = level >= 2 ? level-2 : 0;
|
||||||
|
sId = (sId+1) & (NB_STACKS-1);
|
||||||
|
|
||||||
|
// ctx->startTimer(RC_TIMER_DIVIDE_TO_LEVELS);
|
||||||
|
|
||||||
|
if (sId == 0)
|
||||||
|
sortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
|
||||||
|
else
|
||||||
|
appendStacks(lvlStacks[sId-1], lvlStacks[sId], srcReg); // copy left overs from last level
|
||||||
|
|
||||||
|
// ctx->stopTimer(RC_TIMER_DIVIDE_TO_LEVELS);
|
||||||
|
|
||||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_EXPAND);
|
ctx->startTimer(RC_TIMER_BUILD_REGIONS_EXPAND);
|
||||||
|
|
||||||
// Expand current regions until no empty connected cells found.
|
// Expand current regions until no empty connected cells found.
|
||||||
if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
|
if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, lvlStacks[sId], false) != srcReg)
|
||||||
{
|
{
|
||||||
rcSwap(srcReg, dstReg);
|
rcSwap(srcReg, dstReg);
|
||||||
rcSwap(srcDist, dstDist);
|
rcSwap(srcDist, dstDist);
|
||||||
@ -1289,18 +1381,15 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
|||||||
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
|
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
|
||||||
|
|
||||||
// Mark new regions with IDs.
|
// Mark new regions with IDs.
|
||||||
for (int y = 0; y < h; ++y)
|
for (int j=0; j<lvlStacks[sId].size(); j+=3)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < w; ++x)
|
int x = lvlStacks[sId][j];
|
||||||
|
int y = lvlStacks[sId][j+1];
|
||||||
|
int i = lvlStacks[sId][j+2];
|
||||||
|
if (i >= 0 && srcReg[i] == 0)
|
||||||
{
|
{
|
||||||
const rcCompactCell& c = chf.cells[x+y*w];
|
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
||||||
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
|
regionId++;
|
||||||
{
|
|
||||||
if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA)
|
|
||||||
continue;
|
|
||||||
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
|
|
||||||
regionId++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1308,7 +1397,7 @@ bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Expand current regions until no empty connected cells found.
|
// Expand current regions until no empty connected cells found.
|
||||||
if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
|
if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack, true) != srcReg)
|
||||||
{
|
{
|
||||||
rcSwap(srcReg, dstReg);
|
rcSwap(srcReg, dstReg);
|
||||||
rcSwap(srcDist, dstDist);
|
rcSwap(srcDist, dstDist);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user