Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        private void PaintRectRegion(int minx, int maxx, int miny, int maxy, int regId, ref int[] srcReg)
        {
            int w = Width;

            for (int y = miny; y < maxy; y++)
            {
                for (int x = minx; x < maxx; 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)
                        {
                            srcReg[i] = regId;
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
        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);
                }
            }
        }
Exemplo n.º 4
0
        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;
                        }
                    }
                }
            }
        }
Exemplo n.º 5
0
        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;
                }
            }
        }
Exemplo n.º 6
0
        private bool FilterSmallRegions(int minRegionArea, int mergeRegionArea, ref int[] srcReg)
        {
            int w = Width;
            int h = Height;

            int nreg = MaxRegions + 1;

            Region[] regions = new Region[nreg];

            for (int i = 0; i < nreg; i++)
            {
                regions[i] = new Region(i);
            }

            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++)
                    {
                        int r = srcReg[i];
                        if (r <= 0 || r >= nreg)
                        {
                            continue;
                        }
                        Region reg = regions[r];
                        reg.SpanCount++;

                        for (int j = (int)c.Index; j < ni; j++)
                        {
                            if (i == j)
                            {
                                continue;
                            }
                            int floorId = srcReg[j];
                            if (floorId <= 0 || floorId >= nreg)
                            {
                                continue;
                            }
                            AddUniqueFloorRegion(ref reg, floorId);
                        }

                        if (reg.Connections.Size > 0)
                        {
                            continue;
                        }

                        reg.AreaType = (short)Areas[i];

                        int ndir = -1;
                        for (int dir = 0; dir < 4; dir++)
                        {
                            if (IsSolidEdge(srcReg, x, y, i, dir))
                            {
                                ndir = dir;
                                break;
                            }
                        }

                        if (ndir != -1)
                        {
                            WalkContour(x, y, i, ndir, ref srcReg, ref reg);
                        }
                    }
                }
            }

            // remove too small regions.
            IntArray stack = new IntArray(32);
            IntArray trace = new IntArray(32);

            for (int i = 0; i < nreg; i++)
            {
                Region reg = regions[i];
                if (reg.Id <= 0 || (reg.Id & BorderReg) != 0)
                {
                    continue;
                }
                if (reg.SpanCount == 0)
                {
                    continue;
                }
                if (reg.Visited)
                {
                    continue;
                }

                bool connectsToBorder = false;
                int  spanCount        = 0;
                stack.Resize(0);
                trace.Resize(0);

                reg.Visited = true;
                stack.Push(i);

                while (stack.Size > 0)
                {
                    int ri = stack.Pop();

                    Region creg = regions[ri];
                    spanCount += creg.SpanCount;
                    trace.Push(ri);

                    for (int j = 0; j < creg.Connections.Size; j++)
                    {
                        if ((creg.Connections[j] & BorderReg) != 0)
                        {
                            connectsToBorder = true;
                            continue;
                        }
                        Region neireg = regions[creg.Connections[j]];
                        if (neireg.Visited)
                        {
                            continue;
                        }
                        if (neireg.Id <= 0 || (neireg.Id & BorderReg) != 0)
                        {
                            continue;
                        }
                        stack.Push(neireg.Id);
                        neireg.Visited = true;
                    }
                }

                // if the region's size is too small, remove it.
                if (spanCount < minRegionArea && !connectsToBorder)
                {
                    for (int j = 0; j < trace.Size; j++)
                    {
                        regions[trace[j]].SpanCount = 0;
                        regions[trace[j]].Id        = 0;
                    }
                }
            }

            int mergeCount = 0;

            do
            {
                mergeCount = 0;
                for (int i = 0; i < nreg; i++)
                {
                    Region reg = regions[i];
                    if (reg.Id <= 0 || (reg.Id & BorderReg) != 0)
                    {
                        continue;
                    }
                    if (reg.SpanCount == 0)
                    {
                        continue;
                    }

                    if (reg.SpanCount > mergeRegionArea && IsRegionConnectedToBorder(reg))
                    {
                        continue;
                    }

                    // small region with more than 1 connection
                    // or region which is not connected to a border at all.
                    // find smallest neighbor
                    int smallest = int.MaxValue;
                    int mergeId  = reg.Id;
                    for (int j = 0; j < reg.Connections.Size; j++)
                    {
                        if ((reg.Connections[j] & BorderReg) != 0)
                        {
                            continue;
                        }
                        Region mreg = regions[reg.Connections[j]];
                        if (mreg.Id <= 0 || (mreg.Id & BorderReg) != 0)
                        {
                            continue;
                        }
                        if (mreg.SpanCount < smallest && CanMergeWithRegion(reg, mreg) && CanMergeWithRegion(mreg, reg))
                        {
                            smallest = mreg.SpanCount;
                            mergeId  = mreg.Id;
                        }
                    }
                    if (mergeId != reg.Id)
                    {
                        int    oldId  = reg.Id;
                        Region target = regions[mergeId];

                        if (MergeRegions(ref target, ref reg))
                        {
                            for (int j = 0; j < nreg; j++)
                            {
                                if (regions[j].Id == 0 || (regions[j].Id & BorderReg) != 0)
                                {
                                    continue;
                                }
                                if (regions[j].Id == oldId)
                                {
                                    regions[j].Id = mergeId;
                                }
                                Region reg2 = regions[j];
                                ReplaceNeighbor(ref reg2, oldId, mergeId);
                            }
                            mergeCount++;
                        }
                    }
                }
            } while (mergeCount > 0);

            // compress regions Ids
            for (int i = 0; i < nreg; i++)
            {
                regions[i].Remap = false;
                if (regions[i].Id == 0 || (regions[i].Id & BorderReg) != 0)
                {
                    continue;
                }
                regions[i].Remap = true;
            }

            int regIdGen = 0;

            for (int i = 0; i < nreg; i++)
            {
                if (!regions[i].Remap)
                {
                    continue;
                }

                int oldId = regions[i].Id;
                int newId = ++regIdGen;
                for (int j = i; j < nreg; j++)
                {
                    if (regions[j].Id == oldId)
                    {
                        regions[j].Id    = newId;
                        regions[j].Remap = false;
                    }
                }
            }

            MaxRegions = regIdGen;

            // remap regions
            for (int i = 0; i < SpanCount; i++)
            {
                if ((srcReg[i] & BorderReg) == 0)
                {
                    srcReg[i] = regions[srcReg[i]].Id;
                }
            }

            return(true);
        }
Exemplo n.º 7
0
        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;
                                }
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 8
0
        public bool BuildRegions(int borderSize, int minRegionArea, int mergeRegionArea)
        {
            int w = Width;
            int h = Height;

            //int[] buf = new int[SpanCount*4];

            IntArray stack   = new IntArray(1024);
            IntArray visited = new IntArray(1024);

            int[] srcReg  = new int[SpanCount];
            int[] srcDist = new int[SpanCount];
            int[] dstReg  = new int[SpanCount];
            int[] dstDist = new int[SpanCount];

            int regionId = 1;
            int level    = (MaxDistance + 1) & ~1;

            int expandIters = 8;

            if (borderSize > 0)
            {
                int bw = Math.Min(w, borderSize);
                int bh = Math.Min(h, borderSize);

                PaintRectRegion(0, bw, 0, h, regionId | BorderReg, ref srcReg); regionId++;
                PaintRectRegion(w - bw, w, 0, h, regionId | BorderReg, ref srcReg); regionId++;
                PaintRectRegion(0, w, 0, bh, regionId | BorderReg, ref srcReg); regionId++;
                PaintRectRegion(0, w, h - bh, h, regionId | BorderReg, ref srcReg); regionId++;

                BorderSize = borderSize;
            }

            while (level > 0)
            {
                level = level >= 2 ? level - 2 : 0;

                if (ExpandRegions(expandIters, level, ref srcReg, ref srcDist, ref dstReg, ref dstDist, ref stack) != srcReg)
                {
                    int[] @t = srcReg;
                    srcReg  = dstReg;
                    dstReg  = @t;
                    @t      = srcDist;
                    srcDist = dstDist;
                    dstDist = @t;
                }

                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)
                            {
                                continue;
                            }
                            if (FloodRegion(x, y, i, level, regionId, ref srcReg, ref srcDist, ref stack))
                            {
                                regionId++;
                            }
                        }
                    }
                }
            }

            if (ExpandRegions(expandIters * 8, 0, ref srcReg, ref srcDist, ref dstReg, ref dstDist, ref stack) != srcReg)
            {
                int[] t = srcReg;
                srcReg  = dstReg;
                dstReg  = t;
                t       = srcDist;
                srcDist = dstDist;
                dstDist = t;
            }

            MaxRegions = regionId;
            if (!FilterSmallRegions(minRegionArea, mergeRegionArea, ref srcReg))
            {
                return(false);
            }

            for (int i = 0; i < SpanCount; i++)
            {
                Spans[i].Reg = srcReg[i];
            }
            return(true);
        }
Exemplo n.º 9
0
        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);
            }
        }
Exemplo n.º 10
0
        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);
        }
Exemplo n.º 11
0
        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);
        }
Exemplo n.º 12
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++;
                    }
                }
            }
        }