private int[] BoxBlur(int thr, int[] src, ref int[] dst) { int w = Width; int h = Height; thr *= 2; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { CompactSpan s = Spans[i]; int cd = src[i]; if (cd <= thr) { dst[i] = cd; continue; } int d = cd; for (int dir = 0; dir < 4; dir++) { if (s.GetCon(dir) != NotConnected) { int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(dir); d += src[ai]; CompactSpan aspan = Spans[ai]; int dir2 = (dir + 1) & 0x3; if (aspan.GetCon(dir2) != NotConnected) { int ax2 = ax + Helper.GetDirOffsetX(dir2); int ay2 = ay + Helper.GetDirOffsetY(dir2); int ai2 = (int)Cells[ax2 + ay2 * w].Index + aspan.GetCon(dir2); d += src[ai2]; } else { d += cd; } } else { d += cd * 2; } } dst[i] = (d + 5) / 9; } } } return(dst); }
private bool IsSolidEdge(int[] srcReg, int x, int y, int i, int dir) { CompactSpan s = Spans[i]; int r = 0; if (s.GetCon(dir) != NotConnected) { int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)Cells[ax + ay * Width].Index + s.GetCon(dir); r = srcReg[ai]; } if (r == srcReg[i]) { return(false); } return(true); }
private void GetHeightData(CompactHeightfield chf, int[] p, int npoly, int[] verts, int bs, ref HeightPatch hp, ref IntArray stack) { for (int i = 0; i < hp.Width * hp.Height; i++) { hp.Data[i] = 0; } stack.Resize(0); int[] offset = { 0, 0, -1, -1, 0, -1, 1, -1, 1, 0, 1, 1, 0, 1, -1, 1, -1, 0 }; for (int j = 0; j < npoly; j++) { int cx = 0, cz = 0, ci = -1; int dmin = UnsetHeight; for (int k = 0; k < 9; k++) { int ax = verts[p[j] * 3 + 0] + offset[k * 2 + 0]; int ay = verts[p[j] * 3 + 1]; int az = verts[p[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; } CompactCell c = chf.Cells[(ax + bs) + (az + bs) * chf.Width]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { CompactSpan s = chf.Spans[i]; int d = Math.Abs(ay - 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); } } int pcx = 0, pcz = 0; for (int j = 0; j < npoly; j++) { pcx += verts[p[j] * 3 + 0]; pcz += verts[p[j] * 3 + 2]; } pcx /= 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(); if (Math.Abs(cx - pcx) <= 1 && Math.Abs(cy - pcz) <= 1) { stack.Resize(0); stack.Push(cx); stack.Push(cy); stack.Push(ci); break; } CompactSpan cs = chf.Spans[ci]; for (int dir = 0; dir < 4; dir++) { if (cs.GetCon(dir) == CompactHeightfield.NotConnected) { continue; } int ax = cx + Helper.GetDirOffsetX(dir); int ay = cy + Helper.GetDirOffsetY(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; } int ai = (int)chf.Cells[(ax + bs) + (ay + bs) * chf.Width].Index + cs.GetCon(dir); int idx = ax - hp.XMin + (ay - hp.YMin) * hp.Width; hp.Data[idx] = 1; stack.Push(ax); stack.Push(ay); stack.Push(ai); } } for (int i = 0; i < hp.Data.Length; i++) { hp.Data[i] = UnsetHeight; } for (int i = 0; i < stack.Size; i += 3) { int cx = stack[i + 0]; int cy = stack[i + 1]; int ci = stack[i + 2]; int idx = cx - hp.XMin + (cy - hp.YMin) * hp.Width; CompactSpan cs = chf.Spans[ci]; hp.Data[idx] = cs.Y; } int RetractSize = 256; int head = 0; while (head * 3 < stack.Size) { int cx = stack[head * 3 + 0]; int cy = stack[head * 3 + 1]; int ci = stack[head * 3 + 2]; head++; if (head >= RetractSize) { head = 0; if (stack.Size > RetractSize * 3) { Array.Copy(stack.Data, RetractSize * 3, stack.Data, 0, stack.Size - RetractSize * 3); } stack.Resize(stack.Size - RetractSize * 3); } CompactSpan cs = chf.Spans[ci]; for (int dir = 0; dir < 4; dir++) { if (cs.GetCon(dir) == CompactHeightfield.NotConnected) { continue; } int ax = cx + Helper.GetDirOffsetX(dir); int ay = cy + Helper.GetDirOffsetY(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] != UnsetHeight) { continue; } int ai = (int)chf.Cells[(ax + bs) + (ay + bs) * chf.Width].Index + cs.GetCon(dir); CompactSpan aspan = chf.Spans[ai]; int idx = ax - hp.XMin + (ay - hp.YMin) * hp.Width; hp.Data[idx] = aspan.Y; stack.Push(ax); stack.Push(ay); stack.Push(ai); } } }
public ContourSet(CompactHeightfield cfh, float maxError, int maxEdgeLen, int buildFlags = BuildContourFlags.ContourTessWallEdges) { int w = cfh.Width; int h = cfh.Height; int borderSize = cfh.BorderSize; BMin = new float[3]; BMax = new float[3]; Array.Copy(cfh.BMin, BMin, 3); Array.Copy(cfh.BMax, BMax, 3); if (borderSize > 0) { float pad = borderSize * cfh.Cs; BMin[0] += pad; BMin[2] += pad; BMax[0] -= pad; BMax[2] -= pad; } Cs = cfh.Cs; Ch = cfh.Ch; Width = cfh.Width - cfh.BorderSize * 2; Height = cfh.Height - cfh.BorderSize * 2; BorderSize = cfh.BorderSize; int maxContours = Math.Max(cfh.MaxRegions, 8); Conts = new Contour[maxContours]; for (int i = 0; i < maxContours; i++) { Conts[i] = new Contour(); } NConts = 0; char[] flags = new char[cfh.SpanCount]; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = cfh.Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { if (i == 4782) { int z = 0; } int res = 0; CompactSpan s = cfh.Spans[i]; if (s.Reg == 0 || (s.Reg & CompactHeightfield.BorderReg) != 0) { flags[i] = (char)0; continue; } for (int dir = 0; dir < 4; dir++) { int r = 0; if (s.GetCon(dir) != CompactHeightfield.NotConnected) { int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)cfh.Cells[ax + ay * w].Index + s.GetCon(dir); r = cfh.Spans[ai].Reg; } if (r == cfh.Spans[i].Reg) { res |= (1 << dir); } } flags[i] = (char)(res ^ 0xf); } } } IntArray verts = new IntArray(256); IntArray simplified = new IntArray(64); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = cfh.Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { if (flags[i] == 0 || flags[i] == 0xf) { flags[i] = (char)0; continue; } int reg = cfh.Spans[i].Reg; if (reg == 0 || (reg & CompactHeightfield.BorderReg) != 0) { continue; } uint area = cfh.Areas[i]; verts.Resize(0); simplified.Resize(0); WalkContour(x, y, i, cfh, ref flags, ref verts); SimplifyContour(ref verts, ref simplified, maxError, maxEdgeLen, buildFlags); RemoveDegenerateSegments(ref simplified); if ((simplified.Size / 4) >= 3) { // We need more space than we allocated... if (NConts >= maxContours) { int oldMax = maxContours; maxContours *= 2; Contour[] newConts = new Contour[maxContours]; for (int j = 0; j < maxContours; j++) { newConts[j] = new Contour(); } for (int j = 0; j < NConts; j++) { newConts[j] = Conts[j]; } Conts = newConts; } Contour cont = Conts[NConts++]; cont.NVerts = simplified.Size / 4; cont.Verts = new int[cont.NVerts * 4]; Array.Copy(simplified.ToArray(), cont.Verts, cont.NVerts * 4); if (borderSize > 0) { for (int j = 0; j < cont.NVerts; j++) { int v = j * 4; cont.Verts[v + 0] -= borderSize; cont.Verts[v + 2] -= borderSize; } } cont.NRVerts = verts.Size / 4; cont.RVerts = new int[cont.NRVerts * 4]; Array.Copy(verts.ToArray(), cont.RVerts, cont.NRVerts * 4); if (borderSize > 0) { for (int j = 0; j < cont.NRVerts; j++) { int v = j * 4; cont.RVerts[v + 0] -= borderSize; cont.RVerts[v + 2] -= borderSize; } } cont.Reg = reg; cont.Area = (short)area; } } } } // check and merge droppings for (int i = 0; i < NConts; i++) { Contour cont = Conts[i]; if (CalcAreaOfPolygon2D(cont.Verts, cont.NVerts) < 0) { int mergeIdx = -1; for (int j = 0; j < NConts; j++) { if (i == j) { continue; } if (Conts[j].NVerts > 0 && Conts[j].Reg == cont.Reg) { if (CalcAreaOfPolygon2D(Conts[j].Verts, Conts[j].NVerts) > 0) { mergeIdx = j; break; } } } if (mergeIdx == -1) { // error } else { Contour mcont = Conts[mergeIdx]; int ia = 0, ib = 0; GetClosestIndices(mcont.Verts, mcont.NVerts, cont.Verts, cont.NVerts, ref ia, ref ib); if (ia == -1 || ib == -1) { // bad merge continue; } if (!MergeContours(ref mcont, ref cont, ia, ib)) { // Merge failed continue; } } } } }
private int GetCornerHeight(int x, int y, int i, int dir, CompactHeightfield cfh, ref bool isBorderVertex) { CompactSpan s = cfh.Spans[i]; int ch = s.Y; int dirp = (dir + 1) & 0x3; uint[] regs = { 0, 0, 0, 0 }; regs[0] = (uint)(cfh.Spans[i].Reg | (cfh.Areas[i] << 16)); if (s.GetCon(dir) != CompactHeightfield.NotConnected) { int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)cfh.Cells[ax + ay * cfh.Width].Index + s.GetCon(dir); CompactSpan aspan = cfh.Spans[ai]; ch = Math.Max(ch, aspan.Y); regs[1] = (uint)(cfh.Spans[ai].Reg | (cfh.Areas[ai] << 16)); if (aspan.GetCon(dirp) != CompactHeightfield.NotConnected) { int ax2 = ax + Helper.GetDirOffsetX(dirp); int ay2 = ay + Helper.GetDirOffsetY(dirp); int ai2 = (int)cfh.Cells[ax2 + ay2 * cfh.Width].Index + aspan.GetCon(dirp); CompactSpan as2 = cfh.Spans[ai2]; ch = Math.Max(ch, as2.Y); regs[2] = (uint)(cfh.Spans[ai2].Reg | (cfh.Areas[ai2] << 16)); } } if (s.GetCon(dirp) != CompactHeightfield.NotConnected) { int ax = x + Helper.GetDirOffsetX(dirp); int ay = y + Helper.GetDirOffsetY(dirp); int ai = (int)cfh.Cells[ax + ay * cfh.Width].Index + s.GetCon(dirp); CompactSpan aspan = cfh.Spans[ai]; ch = Math.Max(ch, aspan.Y); regs[3] = (uint)(cfh.Spans[ai].Reg | (cfh.Areas[ai] << 16)); if (aspan.GetCon(dir) != CompactHeightfield.NotConnected) { int ax2 = ax + Helper.GetDirOffsetX(dir); int ay2 = ay + Helper.GetDirOffsetY(dir); int ai2 = (int)cfh.Cells[ax2 + ay2 * cfh.Width].Index + aspan.GetCon(dir); CompactSpan as2 = cfh.Spans[ai2]; ch = Math.Max(ch, as2.Y); regs[2] = (uint)(cfh.Spans[ai2].Reg | (cfh.Areas[ai2] << 16)); } } for (int j = 0; j < 4; j++) { int a = j; int b = (j + 1) & 0x3; int c = (j + 2) & 0x3; int d = (j + 3) & 0x3; bool twoSameExts = (regs[a] & regs[b] & CompactHeightfield.BorderReg) != 0 && regs[a] == regs[b]; bool twoInts = ((regs[c] | regs[d]) & CompactHeightfield.BorderReg) == 0; bool intsSameArea = (regs[c] >> 16) == (regs[d] >> 16); bool noZeros = regs[a] != 0 && regs[b] != 0 && regs[c] != 0 && regs[d] != 0; if (twoSameExts && twoInts && intsSameArea && noZeros) { isBorderVertex = true; break; } } return(ch); }
private void WalkContour(int x, int y, int i, CompactHeightfield cfh, ref char[] flags, ref IntArray points) { char dir = (char)0; while ((flags[i] & (1 << dir)) == 0) { dir++; } char startDir = dir; char tempDir = dir; int starti = i; uint area = cfh.Areas[i]; int iter = 0; while (++iter < 40000) { if ((flags[i] & (1 << dir)) > 0) { bool isBorderVertex = false; bool isAreaBorder = false; int px = x; int py = GetCornerHeight(x, y, i, tempDir, cfh, ref isBorderVertex); int pz = y; if (dir == (char)0) { pz++; } else if (dir == (char)1) { px++; pz++; } else if (dir == (char)2) { px++; } int r = 0; CompactSpan s = cfh.Spans[i]; if (s.GetCon(dir) != CompactHeightfield.NotConnected) { int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)cfh.Cells[ax + ay * cfh.Width].Index + s.GetCon(dir); r = cfh.Spans[ai].Reg; if (area != cfh.Areas[ai]) { isAreaBorder = true; } } if (isBorderVertex) { r |= BorderVertex; } if (isAreaBorder) { r |= AreaBorder; } points.Push(px); points.Push(py); points.Push(pz); points.Push(r); flags[i] &= (char)~(1 << dir); dir = (char)((dir + 1) & 0x3); // rotate CW } else { int ni = -1; int nx = x + Helper.GetDirOffsetX(dir); int ny = y + Helper.GetDirOffsetY(dir); CompactSpan s = cfh.Spans[i]; if (s.GetCon(dir) != CompactHeightfield.NotConnected) { CompactCell nc = cfh.Cells[nx + ny * cfh.Width]; ni = (int)nc.Index + s.GetCon(dir); } if (ni == -1) { // error return; } x = nx; y = ny; i = ni; dir = (char)((dir + 3) & 0x3); } if (starti == i && startDir == dir) { break; } } }
public CompactHeightfield(int walkableHeight, int walkableClimb, HeightField hf) { int w = hf.Width; int h = hf.Height; int spanCount = hf.GetHeightFieldSpanCount(); Width = w; Height = h; SpanCount = spanCount; WalkableHeight = walkableHeight; WalkableClimb = walkableClimb; MaxRegions = 0; BMin = new float[3]; BMax = new float[3]; Array.Copy(hf.Bmin, 0, BMin, 0, 3); Array.Copy(hf.Bmax, 0, BMax, 0, 3); BMax[1] += walkableHeight * hf.Ch; Cs = hf.Cs; Ch = hf.Ch; Cells = new CompactCell[w * h]; Spans = new CompactSpan[spanCount]; Areas = new uint[spanCount]; int MaxHeight = 0xffff; int idx = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { Span s = hf.Spans[x + y * w]; if (s == null) { continue; } Cells[x + y * w].Index = (uint)idx; Cells[x + y * w].Count = 0; while (s != null) { if (s.Area != HeightField.NullArea) { int bot = (int)s.SMax; int top = s.Next != null ? (int)s.Next.SMin : MaxHeight; Spans[idx].Y = Math.Max(0, Math.Min(bot, MaxHeight)); Spans[idx].H = Math.Max(0, Math.Min(top - bot, 255)); Areas[idx] = s.Area; idx++; Cells[x + y * w].Count++; } s = s.Next; } } } int MaxLayers = NotConnected - 1; int tooHighNeighbor = 0; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { for (int dir = 0; dir < 4; dir++) { Spans[i].SetCon(dir, NotConnected); int nx = x + Helper.GetDirOffsetX(dir); int ny = y + Helper.GetDirOffsetY(dir); if (nx < 0 || ny < 0 || nx >= w || ny >= h) { continue; } CompactCell nc = Cells[nx + ny * w]; for (int k = (int)nc.Index, nk = (int)(nc.Index + nc.Count); k < nk; k++) { CompactSpan ns = Spans[k]; int bot = Math.Max(Spans[i].Y, ns.Y); int top = Math.Min(Spans[i].Y + Spans[i].H, ns.Y + ns.H); if ((top - bot) >= walkableHeight && Math.Abs(ns.Y - Spans[i].Y) <= walkableClimb) { int lidx = k - (int)nc.Index; if (lidx < 0 || lidx > MaxLayers) { tooHighNeighbor = Math.Max(tooHighNeighbor, lidx); continue; } Spans[i].SetCon(dir, lidx); break; } } } } } } }
private void CalculateDistanceField(ref int[] src, ref int maxDist) { int w = Width; int h = Height; for (int i = 0; i < SpanCount; i++) { src[i] = 0xffff; } for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { CompactSpan s = Spans[i]; uint area = Areas[i]; int nc = 0; for (int dir = 0; dir < 4; dir++) { if (s.GetCon(dir) != NotConnected) { int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(dir); if (area == Areas[ai]) { nc++; } } } if (nc != 4) { src[i] = 0; } } } } for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { CompactSpan s = Spans[i]; if (s.GetCon(0) != NotConnected) { int ax = x + Helper.GetDirOffsetX(0); int ay = y + Helper.GetDirOffsetY(0); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(0); CompactSpan aspan = Spans[ai]; if (src[ai] + 2 < src[i]) { src[i] = src[ai] + 2; } if (aspan.GetCon(3) != NotConnected) { int aax = ax + Helper.GetDirOffsetX(3); int aay = ay + Helper.GetDirOffsetY(3); int aai = (int)Cells[aax + aay * w].Index + aspan.GetCon(3); if (src[aai] + 3 < src[i]) { src[i] = src[aai] + 3; } } } if (s.GetCon(3) != NotConnected) { int ax = x + Helper.GetDirOffsetX(3); int ay = y + Helper.GetDirOffsetY(3); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(3); CompactSpan aspan = Spans[ai]; if (src[ai] + 2 < src[i]) { src[i] = src[ai] + 2; } if (aspan.GetCon(2) != NotConnected) { int aax = ax + Helper.GetDirOffsetX(2); int aay = ay + Helper.GetDirOffsetY(2); int aai = (int)Cells[aax + aay * w].Index + aspan.GetCon(2); if (src[aai] + 3 < src[i]) { src[i] = src[aai] + 3; } } } } } } //pass 2 for (int y = h - 1; y >= 0; y--) { for (int x = w - 1; x >= 0; x--) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { CompactSpan s = Spans[i]; if (s.GetCon(2) != NotConnected) { int ax = x + Helper.GetDirOffsetX(2); int ay = y + Helper.GetDirOffsetY(2); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(2); CompactSpan aspan = Spans[ai]; if (src[ai] + 2 < src[i]) { src[i] = src[ai] + 2; } if (aspan.GetCon(1) != NotConnected) { int aax = ax + Helper.GetDirOffsetX(1); int aay = ay + Helper.GetDirOffsetY(1); int aai = (int)Cells[aax + aay * w].Index + aspan.GetCon(1); if (src[aai] + 3 < src[i]) { src[i] = src[aai] + 3; } } } if (s.GetCon(1) != NotConnected) { int ax = x + Helper.GetDirOffsetX(1); int ay = y + Helper.GetDirOffsetY(1); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(1); CompactSpan aspan = Spans[ai]; if (src[ai] + 2 < src[i]) { src[i] = src[ai] + 2; } if (aspan.GetCon(0) != NotConnected) { int aax = ax + Helper.GetDirOffsetX(0); int aay = ay + Helper.GetDirOffsetY(0); int aai = (int)Cells[aax + aay * w].Index + aspan.GetCon(0); if (src[aai] + 3 < src[i]) { src[i] = src[aai] + 3; } } } } } } maxDist = 0; for (int i = 0; i < SpanCount; i++) { maxDist = Math.Max(src[i], maxDist); } }
public bool ErodeWalkableArea(int radius) { int w = Width; int h = Height; short[] dist = new short[SpanCount]; for (int i = 0; i < SpanCount; i++) { dist[i] = 0xff; } for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { if (Areas[i] == HeightField.NullArea) { dist[i] = 0; } else { CompactSpan s = Spans[i]; int nc = 0; for (int dir = 0; dir < 4; dir++) { if (s.GetCon(dir) != NotConnected) { int nx = x + Helper.GetDirOffsetX(dir); int ny = y + Helper.GetDirOffsetY(dir); int nidx = (int)Cells[nx + ny * w].Index + s.GetCon(dir); if (Areas[nidx] != HeightField.NullArea) { nc++; } } } if (nc != 4) { dist[i] = 0; } } } } } short nd; for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { CompactSpan s = Spans[i]; if (s.GetCon(0) != NotConnected) { int ax = x + Helper.GetDirOffsetX(0); int ay = y + Helper.GetDirOffsetY(0); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(0); CompactSpan aspan = Spans[ai]; nd = (short)Math.Min((int)dist[ai] + 2, 255); if (nd < dist[i]) { dist[i] = nd; } if (aspan.GetCon(3) != NotConnected) { int aax = ax + Helper.GetDirOffsetX(3); int aay = ay + Helper.GetDirOffsetY(3); int aai = (int)Cells[aax + aay * w].Index + aspan.GetCon(3); nd = (short)Math.Min(dist[aai] + 3, 255); if (nd < dist[i]) { dist[i] = nd; } } } if (s.GetCon(3) != NotConnected) { int ax = x + Helper.GetDirOffsetX(3); int ay = y + Helper.GetDirOffsetY(3); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(3); CompactSpan aspan = Spans[ai]; nd = (short)Math.Min((int)dist[ai] + 2, 255); if (nd < dist[i]) { dist[i] = nd; } if (aspan.GetCon(2) != NotConnected) { int aax = ax + Helper.GetDirOffsetX(2); int aay = ay + Helper.GetDirOffsetY(2); int aai = (int)Cells[aax + aay * w].Index + aspan.GetCon(2); nd = (short)Math.Min(dist[aai] + 3, 255); if (nd < dist[i]) { dist[i] = nd; } } } } } } for (int y = h - 1; y >= 0; y--) { for (int x = w - 1; x >= 0; x--) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { CompactSpan s = Spans[i]; if (s.GetCon(2) != NotConnected) { int ax = x + Helper.GetDirOffsetX(2); int ay = y + Helper.GetDirOffsetY(2); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(2); CompactSpan aspan = Spans[ai]; nd = (short)Math.Min((int)dist[ai] + 2, 255); if (nd < dist[i]) { dist[i] = nd; } if (aspan.GetCon(1) != NotConnected) { int aax = ax + Helper.GetDirOffsetX(1); int aay = ay + Helper.GetDirOffsetY(1); int aai = (int)Cells[aax + aay * w].Index + aspan.GetCon(1); nd = (short)Math.Min(dist[aai] + 3, 255); if (nd < dist[i]) { dist[i] = nd; } } } if (s.GetCon(1) != NotConnected) { int ax = x + Helper.GetDirOffsetX(1); int ay = y + Helper.GetDirOffsetY(1); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(1); CompactSpan aspan = Spans[ai]; nd = (short)Math.Min((int)dist[ai] + 2, 255); if (nd < dist[i]) { dist[i] = nd; } if (aspan.GetCon(0) != NotConnected) { int aax = ax + Helper.GetDirOffsetX(0); int aay = ay + Helper.GetDirOffsetY(0); int aai = (int)Cells[aax + aay * w].Index + aspan.GetCon(0); nd = (short)Math.Min(dist[aai] + 3, 255); if (nd < dist[i]) { dist[i] = nd; } } } } } } short thr = (short)(radius * 2); for (int i = 0; i < SpanCount; i++) { if (dist[i] < thr) { Areas[i] = HeightField.NullArea; } } return(true); }
private int[] ExpandRegions(int maxIter, int level, ref int[] srcReg, ref int[] srcDist, ref int[] dstReg, ref int[] dstDist, ref IntArray stack) { int w = Width; int h = Height; stack.Resize(0); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { CompactCell c = Cells[x + y * w]; for (int i = (int)c.Index, ni = (int)(c.Index + c.Count); i < ni; i++) { if (Dist[i] >= level && srcReg[i] == 0 && Areas[i] != HeightField.NullArea) { stack.Push(x); stack.Push(y); stack.Push(i); } } } } int iter = 0; while (stack.Size > 0) { int failed = 0; Buffer.BlockCopy(srcReg, 0, dstReg, 0, sizeof(int) * SpanCount); Buffer.BlockCopy(srcDist, 0, dstDist, 0, sizeof(int) * SpanCount); //Array.Copy(srcReg, dstReg, SpanCount); //Array.Copy(srcDist, dstDist, SpanCount); for (int j = 0; j < stack.Size; j += 3) { int x = stack[j + 0]; int y = stack[j + 1]; int i = stack[j + 2]; if (i < 0) { failed++; continue; } int r = srcReg[i]; int d2 = short.MaxValue; uint area = Areas[i]; CompactSpan s = Spans[i]; for (int dir = 0; dir < 4; dir++) { if (s.GetCon(dir) == NotConnected) { continue; } int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)Cells[ax + ay * w].Index + s.GetCon(dir); if (Areas[ai] != area) { continue; } if (srcReg[ai] > 0 && (srcReg[ai] & BorderReg) == 0) { if (srcDist[ai] + 2 < d2) { r = srcReg[ai]; d2 = srcDist[ai] + 2; } } } if (r != 0) { stack[j + 2] = -1; dstReg[i] = r; dstDist[i] = d2; } else { failed++; } } int[] temp = srcReg; srcReg = dstReg; dstReg = temp; temp = srcDist; srcDist = dstDist; dstDist = temp; if (failed * 3 == stack.Size) { break; } if (level > 0) { ++iter; if (iter >= maxIter) { break; } } } return(srcReg); }
private bool FloodRegion(int x, int y, int i, int level, int r, ref int[] srcReg, ref int[] srcDist, ref IntArray stack) { int w = Width; uint area = Areas[i]; stack.Resize(0); stack.Push(x); stack.Push(y); stack.Push(i); srcReg[i] = r; srcDist[i] = 0; int lev = level >= 2 ? level - 2 : 0; int count = 0; while (stack.Size > 0) { int ci = stack.Pop(); int cy = stack.Pop(); int cx = stack.Pop(); CompactSpan cs = Spans[ci]; int ar = 0; for (int dir = 0; dir < 4; dir++) { if (cs.GetCon(dir) != NotConnected) { int ax = cx + Helper.GetDirOffsetX(dir); int ay = cy + Helper.GetDirOffsetY(dir); int ai = (int)Cells[ax + ay * w].Index + cs.GetCon(dir); if (Areas[ai] != area) { continue; } int nr = srcReg[ai]; if ((nr & BorderReg) != 0) { continue; } if (nr != 0 && nr != r) { ar = nr; } CompactSpan aspan = Spans[ai]; int dir2 = (dir + 1) & 0x3; if (aspan.GetCon(dir2) != NotConnected) { int ax2 = ax + Helper.GetDirOffsetX(dir2); int ay2 = ay + Helper.GetDirOffsetY(dir2); int ai2 = (int)Cells[ax2 + ay2 * w].Index + aspan.GetCon(dir2); if (Areas[ai2] != area) { continue; } int nr2 = srcReg[ai2]; if (nr2 != 0 && nr2 != r) { ar = nr2; } } } } if (ar != 0) { srcReg[ci] = 0; continue; } count++; for (int dir = 0; dir < 4; dir++) { if (cs.GetCon(dir) != NotConnected) { int ax = cx + Helper.GetDirOffsetX(dir); int ay = cy + Helper.GetDirOffsetY(dir); int ai = (int)Cells[ax + ay * w].Index + cs.GetCon(dir); if (Areas[ai] != area) { continue; } if (Dist[ai] >= lev && srcReg[ai] == 0) { srcReg[ai] = r; srcDist[ai] = 0; stack.Push(ax); stack.Push(ay); stack.Push(ai); } } } } return(count > 0); }
private void WalkContour(int x, int y, int i, int dir, ref int[] srcReg, ref Region cont) { int startDir = dir; int starti = i; CompactSpan ss = Spans[i]; int curReg = 0; if (ss.GetCon(dir) != NotConnected) { int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)Cells[ax + ay * Width].Index + ss.GetCon(dir); curReg = srcReg[ai]; } cont.Connections.Push(curReg); int iter = 0; while (++iter < 40000) { CompactSpan s = Spans[i]; if (IsSolidEdge(srcReg, x, y, i, dir)) { int r = 0; if (s.GetCon(dir) != NotConnected) { int ax = x + Helper.GetDirOffsetX(dir); int ay = y + Helper.GetDirOffsetY(dir); int ai = (int)Cells[ax + ay * Width].Index + s.GetCon(dir); r = srcReg[ai]; } if (r != curReg) { curReg = r; cont.Connections.Push(curReg); } dir = (dir + 1) & 0x3; // rotate CW } else { int ni = -1; int nx = x + Helper.GetDirOffsetX(dir); int ny = y + Helper.GetDirOffsetY(dir); if (s.GetCon(dir) != NotConnected) { CompactCell nc = Cells[nx + ny * Width]; ni = (int)nc.Index + s.GetCon(dir); } if (ni == -1) { // Should no happen return; } x = nx; y = ny; i = ni; dir = (dir + 3) & 0x3; // rotate CCW } if (starti == i && startDir == dir) { break; } } // Remove adjecent duplicates if (cont.Connections.Size > 1) { for (int j = 0; j < cont.Connections.Size;) { int nj = (j + 1) % cont.Connections.Size; if (cont.Connections[j] == cont.Connections[nj]) { for (int k = j; k < cont.Connections.Size - 1; k++) { cont.Connections[k] = cont.Connections[k + 1]; } cont.Connections.Pop(); } else { j++; } } } }