340
347
rcCompactHeightfield& chf,
341
348
unsigned short* srcReg, unsigned short* srcDist,
342
349
unsigned short* dstReg, unsigned short* dstDist,
345
353
const int w = chf.width;
346
354
const int h = chf.height;
348
// Find cells revealed by the raised level.
350
for (int y = 0; y < h; ++y)
352
for (int x = 0; x < w; ++x)
358
// Find cells revealed by the raised level.
360
for (int y = 0; y < h; ++y)
354
const rcCompactCell& c = chf.cells[x+y*w];
355
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
362
for (int x = 0; x < w; ++x)
357
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
364
const rcCompactCell& c = chf.cells[x+y*w];
365
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
367
if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
377
else // use cells in the input stack
379
// mark all cells which already have a region
380
for (int j=0; j<stack.size(); j+=3)
368
389
while (stack.size() > 0)
459
static void sortCellsByLevel(unsigned short startLevel,
460
rcCompactHeightfield& chf,
461
unsigned short* srcReg,
462
unsigned int nbStacks, rcIntArray* stacks,
463
unsigned short loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift
465
const int w = chf.width;
466
const int h = chf.height;
467
startLevel = startLevel >> loglevelsPerStack;
469
for (unsigned int j=0; j<nbStacks; ++j)
472
// put all cells in the level range into the appropriate stacks
473
for (int y = 0; y < h; ++y)
475
for (int x = 0; x < w; ++x)
477
const rcCompactCell& c = chf.cells[x+y*w];
478
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
480
if (chf.areas[i] == RC_NULL_AREA || srcReg[i] != 0)
483
int level = chf.dist[i] >> loglevelsPerStack;
484
int sId = startLevel - level;
485
if (sId >= (int)nbStacks)
499
static void appendStacks(rcIntArray& srcStack, rcIntArray& dstStack,
500
unsigned short* srcReg)
502
for (int j=0; j<srcStack.size(); j+=3)
504
int i = srcStack[j+2];
505
if ((i < 0) || (srcReg[i] != 0))
507
dstStack.push(srcStack[j]);
508
dstStack.push(srcStack[j+1]);
509
dstStack.push(srcStack[j+2]);
439
515
inline rcRegion(unsigned short i) :
928
1015
if ((srcReg[i] & RC_BORDER_REG) == 0)
929
1016
srcReg[i] = regions[srcReg[i]].id;
932
for (int i = 0; i < nreg; ++i)
933
regions[i].~rcRegion();
1019
// Return regions that we found to be overlapping.
1020
for (int i = 0; i < nreg; ++i)
1021
if (regions[i].overlap)
1022
overlaps.push(regions[i].id);
1024
for (int i = 0; i < nreg; ++i)
1025
regions[i].~rcRegion();
1033
static void addUniqueConnection(rcRegion& reg, int n)
1035
for (int i = 0; i < reg.connections.size(); ++i)
1036
if (reg.connections[i] == n)
1038
reg.connections.push(n);
1041
static bool mergeAndFilterLayerRegions(rcContext* ctx, int minRegionArea,
1042
unsigned short& maxRegionId,
1043
rcCompactHeightfield& chf,
1044
unsigned short* srcReg, rcIntArray& overlaps)
1046
const int w = chf.width;
1047
const int h = chf.height;
1049
const int nreg = maxRegionId+1;
1050
rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP);
1053
ctx->log(RC_LOG_ERROR, "mergeAndFilterLayerRegions: Out of memory 'regions' (%d).", nreg);
1057
// Construct regions
1058
for (int i = 0; i < nreg; ++i)
1059
new(®ions[i]) rcRegion((unsigned short)i);
1061
// Find region neighbours and overlapping regions.
1062
rcIntArray lregs(32);
1063
for (int y = 0; y < h; ++y)
1065
for (int x = 0; x < w; ++x)
1067
const rcCompactCell& c = chf.cells[x+y*w];
1071
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1073
const rcCompactSpan& s = chf.spans[i];
1074
const unsigned short ri = srcReg[i];
1075
if (ri == 0 || ri >= nreg) continue;
1076
rcRegion& reg = regions[ri];
1080
reg.ymin = rcMin(reg.ymin, s.y);
1081
reg.ymax = rcMax(reg.ymax, s.y);
1083
// Collect all region layers.
1086
// Update neighbours
1087
for (int dir = 0; dir < 4; ++dir)
1089
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
1091
const int ax = x + rcGetDirOffsetX(dir);
1092
const int ay = y + rcGetDirOffsetY(dir);
1093
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
1094
const unsigned short rai = srcReg[ai];
1095
if (rai > 0 && rai < nreg && rai != ri)
1096
addUniqueConnection(reg, rai);
1097
if (rai & RC_BORDER_REG)
1098
reg.connectsToBorder = true;
1104
// Update overlapping regions.
1105
for (int i = 0; i < lregs.size()-1; ++i)
1107
for (int j = i+1; j < lregs.size(); ++j)
1109
if (lregs[i] != lregs[j])
1111
rcRegion& ri = regions[lregs[i]];
1112
rcRegion& rj = regions[lregs[j]];
1113
addUniqueFloorRegion(ri, lregs[j]);
1114
addUniqueFloorRegion(rj, lregs[i]);
1122
// Create 2D layers from regions.
1123
unsigned short layerId = 1;
1125
for (int i = 0; i < nreg; ++i)
1128
// Merge montone regions to create non-overlapping areas.
1129
rcIntArray stack(32);
1130
for (int i = 1; i < nreg; ++i)
1132
rcRegion& root = regions[i];
1133
// Skip already visited.
1143
while (stack.size() > 0)
1146
rcRegion& reg = regions[stack[0]];
1147
for (int j = 0; j < stack.size()-1; ++j)
1148
stack[j] = stack[j+1];
1149
stack.resize(stack.size()-1);
1151
const int ncons = (int)reg.connections.size();
1152
for (int j = 0; j < ncons; ++j)
1154
const int nei = reg.connections[j];
1155
rcRegion& regn = regions[nei];
1156
// Skip already visited.
1159
// Skip if the neighbour is overlapping root region.
1160
bool overlap = false;
1161
for (int k = 0; k < root.floors.size(); k++)
1163
if (root.floors[k] == nei)
1177
// Merge current layers to root.
1178
for (int k = 0; k < regn.floors.size(); ++k)
1179
addUniqueFloorRegion(root, regn.floors[k]);
1180
root.ymin = rcMin(root.ymin, regn.ymin);
1181
root.ymax = rcMax(root.ymax, regn.ymax);
1182
root.spanCount += regn.spanCount;
1184
root.connectsToBorder = root.connectsToBorder || regn.connectsToBorder;
1191
// Remove small regions
1192
for (int i = 0; i < nreg; ++i)
1194
if (regions[i].spanCount > 0 && regions[i].spanCount < minRegionArea && !regions[i].connectsToBorder)
1196
unsigned short reg = regions[i].id;
1197
for (int j = 0; j < nreg; ++j)
1198
if (regions[j].id == reg)
1203
// Compress region Ids.
1204
for (int i = 0; i < nreg; ++i)
1206
regions[i].remap = false;
1207
if (regions[i].id == 0) continue; // Skip nil regions.
1208
if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions.
1209
regions[i].remap = true;
1212
unsigned short regIdGen = 0;
1213
for (int i = 0; i < nreg; ++i)
1215
if (!regions[i].remap)
1217
unsigned short oldId = regions[i].id;
1218
unsigned short newId = ++regIdGen;
1219
for (int j = i; j < nreg; ++j)
1221
if (regions[j].id == oldId)
1223
regions[j].id = newId;
1224
regions[j].remap = false;
1228
maxRegionId = regIdGen;
1231
for (int i = 0; i < chf.spanCount; ++i)
1233
if ((srcReg[i] & RC_BORDER_REG) == 0)
1234
srcReg[i] = regions[srcReg[i]].id;
1237
for (int i = 0; i < nreg; ++i)
1238
regions[i].~rcRegion();
1271
1588
chf.borderSize = borderSize;
1274
1592
while (level > 0)
1276
1594
level = level >= 2 ? level-2 : 0;
1595
sId = (sId+1) & (NB_STACKS-1);
1597
// ctx->startTimer(RC_TIMER_DIVIDE_TO_LEVELS);
1600
sortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
1602
appendStacks(lvlStacks[sId-1], lvlStacks[sId], srcReg); // copy left overs from last level
1604
// ctx->stopTimer(RC_TIMER_DIVIDE_TO_LEVELS);
1278
1606
ctx->startTimer(RC_TIMER_BUILD_REGIONS_EXPAND);
1280
1608
// Expand current regions until no empty connected cells found.
1281
if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
1609
if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, lvlStacks[sId], false) != srcReg)
1283
1611
rcSwap(srcReg, dstReg);
1284
1612
rcSwap(srcDist, dstDist);
1289
1617
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD);
1291
1619
// Mark new regions with IDs.
1292
for (int y = 0; y < h; ++y)
1620
for (int j=0; j<lvlStacks[sId].size(); j+=3)
1294
for (int x = 0; x < w; ++x)
1622
int x = lvlStacks[sId][j];
1623
int y = lvlStacks[sId][j+1];
1624
int i = lvlStacks[sId][j+2];
1625
if (i >= 0 && srcReg[i] == 0)
1296
const rcCompactCell& c = chf.cells[x+y*w];
1297
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1299
if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA)
1301
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
1627
if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
1670
bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
1671
const int borderSize, const int minRegionArea)
1675
ctx->startTimer(RC_TIMER_BUILD_REGIONS);
1677
const int w = chf.width;
1678
const int h = chf.height;
1679
unsigned short id = 1;
1681
rcScopedDelete<unsigned short> srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
1684
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
1687
memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
1689
const int nsweeps = rcMax(chf.width,chf.height);
1690
rcScopedDelete<rcSweepSpan> sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP);
1693
ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
1698
// Mark border regions.
1701
// Make sure border will not overflow.
1702
const int bw = rcMin(w, borderSize);
1703
const int bh = rcMin(h, borderSize);
1705
paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
1706
paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
1707
paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
1708
paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
1710
chf.borderSize = borderSize;
1713
rcIntArray prev(256);
1715
// Sweep one line at a time.
1716
for (int y = borderSize; y < h-borderSize; ++y)
1718
// Collect spans from this row.
1720
memset(&prev[0],0,sizeof(int)*id);
1721
unsigned short rid = 1;
1723
for (int x = borderSize; x < w-borderSize; ++x)
1725
const rcCompactCell& c = chf.cells[x+y*w];
1727
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1729
const rcCompactSpan& s = chf.spans[i];
1730
if (chf.areas[i] == RC_NULL_AREA) continue;
1733
unsigned short previd = 0;
1734
if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
1736
const int ax = x + rcGetDirOffsetX(0);
1737
const int ay = y + rcGetDirOffsetY(0);
1738
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
1739
if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
1740
previd = srcReg[ai];
1746
sweeps[previd].rid = previd;
1747
sweeps[previd].ns = 0;
1748
sweeps[previd].nei = 0;
1752
if (rcGetCon(s,3) != RC_NOT_CONNECTED)
1754
const int ax = x + rcGetDirOffsetX(3);
1755
const int ay = y + rcGetDirOffsetY(3);
1756
const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
1757
if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
1759
unsigned short nr = srcReg[ai];
1760
if (!sweeps[previd].nei || sweeps[previd].nei == nr)
1762
sweeps[previd].nei = nr;
1763
sweeps[previd].ns++;
1768
sweeps[previd].nei = RC_NULL_NEI;
1777
// Create unique ID.
1778
for (int i = 1; i < rid; ++i)
1780
if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 &&
1781
prev[sweeps[i].nei] == (int)sweeps[i].ns)
1783
sweeps[i].id = sweeps[i].nei;
1787
sweeps[i].id = id++;
1792
for (int x = borderSize; x < w-borderSize; ++x)
1794
const rcCompactCell& c = chf.cells[x+y*w];
1796
for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
1798
if (srcReg[i] > 0 && srcReg[i] < rid)
1799
srcReg[i] = sweeps[srcReg[i]].id;
1805
ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER);
1807
// Merge monotone regions to layers and remove small regions.
1808
rcIntArray overlaps;
1809
chf.maxRegions = id;
1810
if (!mergeAndFilterLayerRegions(ctx, minRegionArea, chf.maxRegions, chf, srcReg, overlaps))
1813
ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER);
1816
// Store the result out.
1817
for (int i = 0; i < chf.spanCount; ++i)
1818
chf.spans[i].reg = srcReg[i];
1820
ctx->stopTimer(RC_TIMER_BUILD_REGIONS);