Fixed out of bounds bug in rcBuildLayerRegions. Improved region merging.
This commit is contained in:
parent
ce6f2a52fc
commit
a1babd6803
@ -697,23 +697,30 @@ inline bool isConnected(rcHeightfieldLayer& layer, const int ia, const int ib, c
|
||||
|
||||
struct rcMonotoneRegion
|
||||
{
|
||||
int area;
|
||||
unsigned char neis[RC_MAX_NEIS];
|
||||
unsigned char nneis;
|
||||
unsigned char regId;
|
||||
};
|
||||
|
||||
static bool canMerge(rcMonotoneRegion* reg, unsigned char newRegId, const rcMonotoneRegion* regs, const int nregs)
|
||||
static bool canMerge(unsigned char oldRegId, unsigned char newRegId, const rcMonotoneRegion* regs, const int nregs)
|
||||
{
|
||||
int count = 0;
|
||||
const int nnei = (int)reg->nneis;
|
||||
for (int i = 0; i < nnei; ++i)
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
{
|
||||
if (regs[reg->neis[i]].regId == newRegId)
|
||||
const rcMonotoneRegion& reg = regs[i];
|
||||
if (reg.regId != oldRegId) continue;
|
||||
const int nnei = (int)reg.nneis;
|
||||
for (int j = 0; j < nnei; ++j)
|
||||
{
|
||||
if (regs[reg.neis[j]].regId == newRegId)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count == 1;
|
||||
}
|
||||
|
||||
|
||||
// TODO: move this somewhere else, once the layer meshing is done.
|
||||
bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int walkableClimb)
|
||||
{
|
||||
@ -741,7 +748,7 @@ bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int wa
|
||||
ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'sweeps' (%d).", nsweeps);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(sweeps,0,sizeof(rcLayerSweepSpan)*nsweeps);
|
||||
|
||||
// Partition walkable area into monotone regions.
|
||||
int prevCount[256];
|
||||
@ -749,6 +756,7 @@ bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int wa
|
||||
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
if (regId > 0)
|
||||
memset(prevCount,0,sizeof(int)*regId);
|
||||
unsigned char sweepId = 0;
|
||||
|
||||
@ -827,6 +835,7 @@ bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int wa
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
const int idx = x+y*w;
|
||||
if (layer.regs[idx] != 0xff)
|
||||
layer.regs[idx] = sweeps[layer.regs[idx]].id;
|
||||
}
|
||||
}
|
||||
@ -853,6 +862,9 @@ bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int wa
|
||||
if (ri == 0xff)
|
||||
continue;
|
||||
|
||||
// Update area.
|
||||
regs[ri].area++;
|
||||
|
||||
// Update neighbours
|
||||
const int ymi = x+(y-1)*w;
|
||||
if (y > 0 && isConnected(layer, idx, ymi, walkableClimb))
|
||||
@ -867,47 +879,53 @@ bool rcBuildLayerRegions(rcContext* ctx, rcHeightfieldLayer& layer, const int wa
|
||||
}
|
||||
}
|
||||
|
||||
// Merge regions.
|
||||
static const int MAX_STACK = 32;
|
||||
unsigned char stack[MAX_STACK];
|
||||
int nstack = 0;
|
||||
|
||||
unsigned char newRegId = 0;
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
regs[i].regId = (unsigned char)i;
|
||||
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
{
|
||||
if (regs[i].regId != 0xff)
|
||||
continue;
|
||||
|
||||
nstack = 0;
|
||||
stack[nstack++] = (unsigned char)i;
|
||||
|
||||
regs[i].regId = newRegId;
|
||||
|
||||
while (nstack)
|
||||
{
|
||||
rcMonotoneRegion& reg = regs[stack[0]];
|
||||
nstack--;
|
||||
for (int j = 0; j < nstack; ++j)
|
||||
stack[j] = stack[j+1];
|
||||
rcMonotoneRegion& reg = regs[i];
|
||||
|
||||
int merge = -1;
|
||||
int mergea = 0;
|
||||
for (int j = 0; j < (int)reg.nneis; ++j)
|
||||
{
|
||||
const unsigned char nei = reg.neis[j];
|
||||
rcMonotoneRegion& regn = regs[nei];
|
||||
if (regn.regId != 0xff)
|
||||
if (reg.regId == regn.regId)
|
||||
continue;
|
||||
if (canMerge(®n, newRegId, regs, nregs))
|
||||
if (regn.area > mergea)
|
||||
{
|
||||
regn.regId = newRegId;
|
||||
if (nstack < MAX_STACK)
|
||||
stack[nstack++] = nei;
|
||||
if (canMerge(reg.regId, regn.regId, regs, nregs))
|
||||
{
|
||||
mergea = regn.area;
|
||||
merge = (int)nei;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (merge != -1)
|
||||
{
|
||||
const unsigned char oldId = reg.regId;
|
||||
const unsigned char newId = regs[merge].regId;
|
||||
for (int j = 0; j < nregs; ++j)
|
||||
if (regs[j].regId == oldId)
|
||||
regs[j].regId = newId;
|
||||
}
|
||||
}
|
||||
|
||||
newRegId++;
|
||||
}
|
||||
// Compact ids.
|
||||
unsigned char remap[256];
|
||||
memset(remap, 0, 256);
|
||||
// Find number of unique regions.
|
||||
regId = 0;
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
remap[regs[i].regId] = 1;
|
||||
for (int i = 0; i < 256; ++i)
|
||||
if (remap[i])
|
||||
remap[i] = regId++;
|
||||
// Remap ids.
|
||||
for (int i = 0; i < nregs; ++i)
|
||||
regs[i].regId = remap[regs[i].regId];
|
||||
|
||||
for (int i = 0; i < w*h; ++i)
|
||||
{
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user