static rcSpan allocSpan(rcHeightfield hf)
        {
            // If running out of memory, allocate new page and update the freelist.
            if (hf.freelist == null || hf.freelist.next == null)
            {
                // Create new page.
                // Allocate memory for the new pool.
                rcSpanPool pool = new rcSpanPool();
                pool.next = null;
                // Add the pool into the list of pools.
                pool.next = hf.pools;
                hf.pools  = pool;
                // Add new items to the free list.
                rcSpan?freelist = hf.freelist;
                //rcSpan head = pool.items[0];
                //rcSpan it = pool.items[RC_SPANS_PER_POOL];
                int itIndex = RC_SPANS_PER_POOL;
                do
                {
                    --itIndex;
                    pool.items[itIndex].next = freelist;
                    freelist = pool.items[itIndex];
                }while (itIndex != 0);
                hf.freelist = pool.items[itIndex];
            }

            // Pop item from in front of the free list.
            rcSpan it = hf.freelist;

            hf.freelist = hf.freelist.next;
            return(it);
        }
 /// @par
 ///
 /// The span addition can be set to favor flags. If the span is merged to
 /// another span and the new @p smax is within @p flagMergeThr units
 /// from the existing span, the span flags are merged.
 ///
 /// @see rcHeightfield, rcSpan.
 static void rcAddSpan(rcContext ctx, rcHeightfield hf, int x, int y,
                       ushort smin, ushort smax,
                       byte area, int flagMergeThr)
 {
     //	Debug.Assert(ctx != null, "rcContext is null");
     addSpan(hf, x, y, smin, smax, area, flagMergeThr);
 }
 static void freeSpan(rcHeightfield hf, rcSpan ptr)
 {
     if (ptr == null)
     {
         return;
     }
     // Add the node in front of the free list.
     ptr.next    = hf.freelist;
     hf.freelist = ptr;
 }
    /// @par
    ///
    /// No spans will be added if the triangle does not overlap the heightfield grid.
    ///
    /// @see rcHeightfield
    public static void rcRasterizeTriangle(rcContext ctx, float[] v0, int v0Start, float[] v1, int v1Start, float[] v2, int v2Start,
						     byte area, rcHeightfield solid,
						     int flagMergeThr)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);

        float ics = 1.0f/solid.cs;
        float ich = 1.0f/solid.ch;
        rasterizeTri(v0, v0Start, v1, v1Start, v2, v2Start, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);

        ctx.stopTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
    }
        static void addSpan(rcHeightfield hf, int x, int y,
                            ushort smin, ushort smax,
                            byte area, int flagMergeThr)
        {
            int idx = x + y * hf.width;

            rcSpan s = allocSpan(hf);

            s.smin = smin;
            s.smax = smax;
            s.area = area;
            s.next = null;

            // Empty cell, add the first span.
            if (hf.spans ![idx] == null)
    /// @par
    ///
    /// No spans will be added if the triangle does not overlap the heightfield grid.
    ///
    /// @see rcHeightfield
    public static void rcRasterizeTriangle(rcContext ctx, float[] v0, int v0Start, float[] v1, int v1Start, float[] v2, int v2Start,
                                           byte area, rcHeightfield solid,
                                           int flagMergeThr)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);

        float ics = 1.0f / solid.cs;
        float ich = 1.0f / solid.ch;

        rasterizeTri(v0, v0Start, v1, v1Start, v2, v2Start, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);

        ctx.stopTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
    }
    /// @par
    ///
    /// Spans will only be added for triangles that overlap the heightfield grid.
    ///
    /// @see rcHeightfield
    public static void rcRasterizeTriangles(rcContext ctx, float[] verts, byte[] areas, int nt,
                                            rcHeightfield solid, int flagMergeThr)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);

        float ics = 1.0f / solid.cs;
        float ich = 1.0f / solid.ch;

        // Rasterize triangles.
        for (int i = 0; i < nt; ++i)
        {
            int v0Start = (i * 3 + 0) * 3;
            int v1Start = (i * 3 + 1) * 3;
            int v2Start = (i * 3 + 2) * 3;
            // Rasterize.
            rasterizeTri(verts, v0Start, verts, v1Start, verts, v2Start, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
        }

        ctx.stopTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
    }
    /// @par
    ///
    /// Spans will only be added for triangles that overlap the heightfield grid.
    ///
    /// @see rcHeightfield
    public static void rcRasterizeTriangles(rcContext ctx, float[] verts, int nv,
						      int[] tris, byte[] areas, int nt,
						      rcHeightfield solid, int flagMergeThr)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);

        float ics = 1.0f/solid.cs;
        float ich = 1.0f/solid.ch;
        // Rasterize triangles.
        for (int i = 0; i < nt; ++i)
        {
            int v0Start = tris[i*3+0]*3;
            int v1Start = tris[i*3+1]*3;
            int v2Start = tris[i*3+2]*3;
            // Rasterize.
            rasterizeTri(verts, v0Start, verts, v1Start, verts, v2Start, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
        }

        ctx.stopTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
    }
Exemple #9
0
    /// @par
    ///
    /// For this filter, the clearance above the span is the distance from the span's
    /// maximum to the next higher span's minimum. (Same grid column.)
    ///
    /// @see rcHeightfield, rcConfig
    public static void rcFilterWalkableLowHeightSpans(rcContext ctx, int walkableHeight, rcHeightfield solid)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_FILTER_WALKABLE);

        int w          = solid.width;
        int h          = solid.height;
        int MAX_HEIGHT = 0xffff;

        // Remove walkable flag from spans which do not have enough
        // space above them for the agent to stand there.
        for (int y = 0; y < h; ++y)
        {
            for (int x = 0; x < w; ++x)
            {
                for (rcSpan s = solid.spans[x + y * w]; s != null; s = s.next)
                {
                    int bot = (int)(s.smax);
                    int top = s.next != null ? (int)(s.next.smin) : MAX_HEIGHT;
                    if ((top - bot) <= walkableHeight)
                    {
                        s.area = RC_NULL_AREA;
                    }
                }
            }
        }

        ctx.stopTimer(rcTimerLabel.RC_TIMER_FILTER_WALKABLE);
    }
    static void addSpan(rcHeightfield hf, int x, int y,
                        ushort smin, ushort smax,
                        byte area, int flagMergeThr)
    {
        int idx = x + y * hf.width;

        rcSpan s = allocSpan(hf);

        s.smin = smin;
        s.smax = smax;
        s.area = area;
        s.next = null;

        // Empty cell, add the first span.
        if (hf.spans[idx] == null)
        {
            hf.spans[idx] = s;
            return;
        }
        rcSpan prev = null;
        rcSpan cur  = hf.spans[idx];

        // Insert and merge spans.
        while (cur != null)
        {
            if (cur.smin > s.smax)
            {
                // Current span is further than the new span, break.
                break;
            }
            else if (cur.smax < s.smin)
            {
                // Current span is before the new span advance.
                prev = cur;
                cur  = cur.next;
            }
            else
            {
                // Merge flags.
                if (Math.Abs((int)s.smax - (int)cur.smax) <= flagMergeThr)
                {
                    s.area = Math.Max(s.area, cur.area);
                }

                // Merge spans.
                if (cur.smin < s.smin)
                {
                    s.smin = cur.smin;
                }
                if (cur.smax > s.smax)
                {
                    s.smax = cur.smax;
                }

                // Remove current span.
                rcSpan next = cur.next;
                freeSpan(hf, cur);
                if (prev != null)
                {
                    prev.next = next;
                }
                else
                {
                    hf.spans[idx] = next;
                }
                cur = next;
            }
        }

        // Insert new span.
        if (prev != null)
        {
            s.next    = prev.next;
            prev.next = s;
        }
        else
        {
            s.next        = hf.spans[idx];
            hf.spans[idx] = s;
        }
    }
    static void rasterizeTri(float[] v0, int v0Start, float[] v1, int v1Start, float[] v2, int v2Start,
                             byte area, rcHeightfield hf,
                             float[] bmin, float[] bmax,
                             float cs, float ics, float ich,
                             int flagMergeThr)
    {
        int w = hf.width;
        int h = hf.height;

        float[] tmin = new float[3];
        float[] tmax = new float[3];
        float   by   = bmax[1] - bmin[1];

        // Calculate the bounding box of the triangle.
        rcVcopy(tmin, 0, v0, v0Start);
        rcVcopy(tmax, 0, v0, v0Start);
        rcVmin(tmin, 0, v1, v1Start);
        rcVmin(tmin, 0, v2, v2Start);
        rcVmax(tmax, 0, v1, v1Start);
        rcVmax(tmax, 0, v2, v2Start);

        // If the triangle does not touch the bbox of the heightfield, skip the triagle.
        if (!overlapBounds(bmin, bmax, tmin, tmax))
        {
            return;
        }

        // Calculate the footprint of the triangle on the grid's y-axis
        int y0 = (int)((tmin[2] - bmin[2]) * ics);
        int y1 = (int)((tmax[2] - bmin[2]) * ics);

        y0 = rcClamp(y0, 0, h - 1);
        y1 = rcClamp(y1, 0, h - 1);

        // Clip the triangle into all grid cells it touches.
        //float[] buf = new float[7*3*4];

        float[] _in   = new float[7 * 3];
        float[] inrow = new float[7 * 3];
        float[] p1    = new float[7 * 3];
        float[] p2    = new float[7 * 3];

        rcVcopy(_in, 0, v0, v0Start);
        rcVcopy(_in, 1 * 3, v1, v1Start);
        rcVcopy(_in, 2 * 3, v2, v2Start);

        int nvrow = 0;
        int nvIn  = 3;

        for (int y = y0; y <= y1; ++y)
        {
            // Clip polygon to row. Store the remaining polygon as well
            float cz = bmin[2] + y * cs;
            dividePoly(_in, nvIn, inrow, ref nvrow, p1, ref nvIn, cz + cs, 2);
            //rcSwap(_in, p1);
            float[] tmp = _in;
            _in = p1;
            p1  = tmp;

            if (nvrow < 3)
            {
                continue;
            }

            // find the horizontal bounds in the row
            float minX = inrow[0], maxX = inrow[0];
            for (int i = 1; i < nvrow; ++i)
            {
                if (minX > inrow[i * 3])
                {
                    minX = inrow[i * 3];
                }
                if (maxX < inrow[i * 3])
                {
                    maxX = inrow[i * 3];
                }
            }
            int x0 = (int)((minX - bmin[0]) * ics);
            int x1 = (int)((maxX - bmin[0]) * ics);
            x0 = rcClamp(x0, 0, w - 1);
            x1 = rcClamp(x1, 0, w - 1);

            int nv  = 0;
            int nv2 = nvrow;

            for (int x = x0; x <= x1; ++x)
            {
                // Clip polygon to column. store the remaining polygon as well
                float cx = bmin[0] + x * cs;
                dividePoly(inrow, nv2, p1, ref nv, p2, ref nv2, cx + cs, 0);
                //rcSwap(inrow, p2);
                tmp   = inrow;
                inrow = p2;
                p2    = tmp;
                if (nv < 3)
                {
                    continue;
                }

                // Calculate min and max of the span.
                float smin = p1[1], smax = p1[1];
                for (int i = 1; i < nv; ++i)
                {
                    smin = Math.Min(smin, p1[i * 3 + 1]);
                    smax = Math.Max(smax, p1[i * 3 + 1]);
                }
                smin -= bmin[1];
                smax -= bmin[1];
                // Skip the span if it is outside the heightfield bbox
                if (smax < 0.0f)
                {
                    continue;
                }
                if (smin > by)
                {
                    continue;
                }
                // Clamp the span to the heightfield bbox.
                if (smin < 0.0f)
                {
                    smin = 0;
                }
                if (smax > by)
                {
                    smax = by;
                }

                // Snap the span to the heightfield height grid.
                ushort ismin = (ushort)rcClamp((int)Math.Floor(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
                ushort ismax = (ushort)rcClamp((int)Math.Ceiling(smax * ich), (int)ismin + 1, RC_SPAN_MAX_HEIGHT);

                addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
            }
        }
    }
    static void addSpan(rcHeightfield hf, int x, int y,
					    ushort smin, ushort smax,
					    byte area, int flagMergeThr)
    {
        int idx = x + y*hf.width;

        rcSpan s = allocSpan(hf);
        s.smin = smin;
        s.smax = smax;
        s.area = area;
        s.next = null;

        // Empty cell, add the first span.
        if (hf.spans[idx] == null)
        {
            hf.spans[idx] = s;
            return;
        }
        rcSpan prev = null;
        rcSpan cur = hf.spans[idx];

        // Insert and merge spans.
        while (cur != null)
        {
            if (cur.smin > s.smax)
            {
                // Current span is further than the new span, break.
                break;
            }
            else if (cur.smax < s.smin)
            {
                // Current span is before the new span advance.
                prev = cur;
                cur = cur.next;
            }
            else
            {
                // Merge spans.
                if (cur.smin < s.smin)
                    s.smin = cur.smin;
                if (cur.smax > s.smax)
                    s.smax = cur.smax;

                // Merge flags.
                if (Math.Abs((int)s.smax - (int)cur.smax) <= flagMergeThr){
                    s.area = Math.Max(s.area, cur.area);
                }

                // Remove current span.
                rcSpan next = cur.next;
                freeSpan(hf, cur);
                if (prev != null)
                    prev.next = next;
                else
                    hf.spans[idx] = next;
                cur = next;
            }
        }

        // Insert new span.
        if (prev != null)
        {
            s.next = prev.next;
            prev.next = s;
        }
        else
        {
            s.next = hf.spans[idx];
            hf.spans[idx] = s;
        }
    }
Exemple #13
0
    /// @par
    ///
    /// For this filter, the clearance above the span is the distance from the span's 
    /// maximum to the next higher span's minimum. (Same grid column.)
    /// 
    /// @see rcHeightfield, rcConfig
    public static void rcFilterWalkableLowHeightSpans(rcContext ctx, int walkableHeight, rcHeightfield solid)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_FILTER_WALKABLE);

        int w = solid.width;
        int h = solid.height;
        int MAX_HEIGHT = 0xffff;

        // Remove walkable flag from spans which do not have enough
        // space above them for the agent to stand there.
        for (int y = 0; y < h; ++y)
        {
            for (int x = 0; x < w; ++x)
            {
                for (rcSpan s = solid.spans[x + y*w]; s != null; s = s.next)
                {
                    int bot = (int)(s.smax);
                    int top = s.next != null ? (int)(s.next.smin) : MAX_HEIGHT;
                    if ((top - bot) <= walkableHeight) {
                        s.area = RC_NULL_AREA;
                    }
                }
            }
        }

        ctx.stopTimer(rcTimerLabel.RC_TIMER_FILTER_WALKABLE);
    }
Exemple #14
0
    /// @par
    ///
    /// Allows the formation of walkable regions that will flow over low lying
    /// objects such as curbs, and up structures such as stairways.
    ///
    /// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt>
    ///
    /// @warning Will override the effect of #rcFilterLedgeSpans.  So if both filters are used, call
    /// #rcFilterLedgeSpans after calling this filter.
    ///
    /// @see rcHeightfield, rcConfig
    public static void rcFilterLowHangingWalkableObstacles(rcContext ctx, int walkableClimb, rcHeightfield solid)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_FILTER_LOW_OBSTACLES);

        int w = solid.width;
        int h = solid.height;

        for (int y = 0; y < h; ++y)
        {
            for (int x = 0; x < w; ++x)
            {
                rcSpan ps = null;
                bool   previousWalkable = false;
                byte   previousArea     = RC_NULL_AREA;

                for (rcSpan s = solid.spans[x + y * w]; s != null; ps = s, s = s.next)
                {
                    bool walkable = s.area != RC_NULL_AREA;
                    // If current span is not walkable, but there is walkable
                    // span just below it, mark the span above it walkable too.
                    if (!walkable && previousWalkable)
                    {
                        if (Math.Abs((int)s.smax - (int)ps.smax) <= walkableClimb)
                        {
                            s.area = previousArea;
                        }
                    }
                    // Copy walkable flag so that it cannot propagate
                    // past multiple non-walkable objects.
                    previousWalkable = walkable;
                    previousArea     = s.area;
                }
            }
        }

        ctx.stopTimer(rcTimerLabel.RC_TIMER_FILTER_LOW_OBSTACLES);
    }
    /// @par
    ///
    /// The span addition can be set to favor flags. If the span is merged to
    /// another span and the new @p smax is within @p flagMergeThr units
    /// from the existing span, the span flags are merged.
    ///
    /// @see rcHeightfield, rcSpan.
    static void rcAddSpan(rcContext ctx, rcHeightfield hf, int x, int y,
			       ushort smin, ushort smax,
			       byte area, int flagMergeThr)
    {
        //	Debug.Assert(ctx != null, "rcContext is null");
        addSpan(hf, x,y, smin, smax, area, flagMergeThr);
    }
    static void rasterizeTri(float[] v0, int v0Start, float[] v1, int v1Start, float[] v2, int v2Start,
						     byte area, rcHeightfield hf,
						     float[] bmin, float[] bmax,
						     float cs, float ics, float ich,
						     int flagMergeThr)
    {
        int w = hf.width;
        int h = hf.height;
        float[] tmin = new float[3];
        float[] tmax = new float[3];
        float by = bmax[1] - bmin[1];

        // Calculate the bounding box of the triangle.
        rcVcopy(tmin, 0, v0, v0Start);
        rcVcopy(tmax, 0, v0, v0Start);
        rcVmin(tmin, 0, v1, v1Start);
        rcVmin(tmin, 0, v2, v2Start);
        rcVmax(tmax, 0, v1, v1Start);
        rcVmax(tmax, 0, v2, v2Start);

        // If the triangle does not touch the bbox of the heightfield, skip the triagle.
        if (!overlapBounds(bmin, bmax, tmin, tmax))
            return;

        // Calculate the footprint of the triangle on the grid's y-axis
        int y0 = (int)((tmin[2] - bmin[2])*ics);
        int y1 = (int)((tmax[2] - bmin[2])*ics);
        y0 = rcClamp(y0, 0, h-1);
        y1 = rcClamp(y1, 0, h-1);

        // Clip the triangle into all grid cells it touches.
        //float[] buf = new float[7*3*4];

        float[] _in = new float[7*3];
        float[] inrow = new float[7*3];
        float[] p1 = new float[7*3];
        float[] p2 = new float[7*3];

        rcVcopy(_in,0  , v0, v0Start);
        rcVcopy(_in,1*3, v1, v1Start);
        rcVcopy(_in,2*3, v2, v2Start);

        int nvrow = 0;
        int nvIn = 3;

        for (int y = y0; y <= y1; ++y)
        {
            // Clip polygon to row. Store the remaining polygon as well
            float cz = bmin[2] + y*cs;
            dividePoly(_in, nvIn, inrow, ref nvrow, p1, ref nvIn, cz+cs, 2);
            //rcSwap(_in, p1);
            float[] tmp = _in;
            _in = p1;
            p1 = tmp;

            if (nvrow < 3)
                continue;

            // find the horizontal bounds in the row
            float minX = inrow[0], maxX = inrow[0];
            for (int i=1; i<nvrow; ++i)
            {
                if (minX > inrow[i*3])	minX = inrow[i*3];
                if (maxX < inrow[i*3])	maxX = inrow[i*3];
            }
            int x0 = (int)((minX - bmin[0])*ics);
            int x1 = (int)((maxX - bmin[0])*ics);
            x0 = rcClamp(x0, 0, w-1);
            x1 = rcClamp(x1, 0, w-1);

            int nv = 0;
            int nv2 = nvrow;

            for (int x = x0; x <= x1; ++x)
            {
                // Clip polygon to column. store the remaining polygon as well
                float cx = bmin[0] + x*cs;
                dividePoly(inrow, nv2, p1, ref nv, p2, ref nv2, cx+cs, 0);
                //rcSwap(inrow, p2);
                tmp = inrow;
                inrow = p2;
                p2 = tmp;
                if (nv < 3) {
                    continue;
                }

                // Calculate min and max of the span.
                float smin = p1[1], smax = p1[1];
                for (int i = 1; i < nv; ++i)
                {
                    smin = Math.Min(smin, p1[i*3+1]);
                    smax = Math.Max(smax, p1[i*3+1]);
                }
                smin -= bmin[1];
                smax -= bmin[1];
                // Skip the span if it is outside the heightfield bbox
                if (smax < 0.0f) continue;
                if (smin > by) continue;
                // Clamp the span to the heightfield bbox.
                if (smin < 0.0f) smin = 0;
                if (smax > by) smax = by;

                // Snap the span to the heightfield height grid.
                ushort ismin = (ushort)rcClamp((int)Math.Floor(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
                ushort ismax = (ushort)rcClamp((int)Math.Ceiling(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);

                addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
            }
        }
    }
 static void freeSpan(rcHeightfield hf, rcSpan ptr)
 {
     if (ptr == null) {
         return;
     }
     // Add the node in front of the free list.
     ptr.next = hf.freelist;
     hf.freelist = ptr;
 }
    static rcSpan allocSpan(rcHeightfield hf)
    {
        // If running out of memory, allocate new page and update the freelist.
        if (hf.freelist == null || hf.freelist.next == null)
        {
            // Create new page.
            // Allocate memory for the new pool.
            //rcSpanPool* pool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM);
            rcSpanPool pool = new rcSpanPool();
            if (pool == null)
                return null;
            pool.next = null;
            // Add the pool into the list of pools.
            pool.next = hf.pools;
            hf.pools = pool;
            // Add new items to the free list.
            rcSpan freelist = hf.freelist;
            //rcSpan head = pool.items[0];
            //rcSpan it = pool.items[RC_SPANS_PER_POOL];
            int itIndex = RC_SPANS_PER_POOL;
            do
            {
                --itIndex;
                pool.items[itIndex].next = freelist;
                freelist = pool.items[itIndex];
            }
            while (itIndex != 0);
            hf.freelist = pool.items[itIndex];
        }

        // Pop item from in front of the free list.
        rcSpan it = hf.freelist;
        hf.freelist = hf.freelist.next;
        return it;
    }
Exemple #19
0
    /// @par
    ///
    /// Allows the formation of walkable regions that will flow over low lying 
    /// objects such as curbs, and up structures such as stairways. 
    /// 
    /// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt>
    /// 
    /// @warning Will override the effect of #rcFilterLedgeSpans.  So if both filters are used, call
    /// #rcFilterLedgeSpans after calling this filter. 
    ///
    /// @see rcHeightfield, rcConfig
    public static void rcFilterLowHangingWalkableObstacles(rcContext ctx, int walkableClimb, rcHeightfield solid)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_FILTER_LOW_OBSTACLES);

        int w = solid.width;
        int h = solid.height;

        for (int y = 0; y < h; ++y)
        {
            for (int x = 0; x < w; ++x)
            {
                rcSpan ps = null;
                bool previousWalkable = false;
                byte previousArea = RC_NULL_AREA;

                for (rcSpan s = solid.spans[x + y*w]; s != null; ps = s, s = s.next)
                {
                    bool walkable = s.area != RC_NULL_AREA;
                    // If current span is not walkable, but there is walkable
                    // span just below it, mark the span above it walkable too.
                    if (!walkable && previousWalkable)
                    {
                        if (Math.Abs((int)s.smax - (int)ps.smax) <= walkableClimb){
                            s.area = previousArea;
                        }
                    }
                    // Copy walkable flag so that it cannot propagate
                    // past multiple non-walkable objects.
                    previousWalkable = walkable;
                    previousArea = s.area;
                }
            }
        }

        ctx.stopTimer(rcTimerLabel.RC_TIMER_FILTER_LOW_OBSTACLES);
    }
Exemple #20
0
    /// @par
    ///
    /// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb
    /// from the current span's maximum.
    /// This method removes the impact of the overestimation of conservative voxelization
    /// so the resulting mesh will not have regions hanging in the air over ledges.
    ///
    /// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
    ///
    /// @see rcHeightfield, rcConfig
    public static void rcFilterLedgeSpans(rcContext ctx, int walkableHeight, int walkableClimb,
                                          rcHeightfield solid)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_FILTER_BORDER);

        int w          = solid.width;
        int h          = solid.height;
        int MAX_HEIGHT = 0xffff;

        // Mark border spans.
        for (int y = 0; y < h; ++y)
        {
            for (int x = 0; x < w; ++x)
            {
                for (rcSpan s = solid.spans[x + y * w]; s != null; s = s.next)
                {
                    // Skip non walkable spans.
                    if (s.area == RC_NULL_AREA)
                    {
                        continue;
                    }

                    int bot = (int)(s.smax);
                    int top = s.next != null ? (int)(s.next.smin) : MAX_HEIGHT;

                    // Find neighbours minimum height.
                    int minh = MAX_HEIGHT;

                    // Min and max height of accessible neighbours.
                    int asmin = s.smax;
                    int asmax = s.smax;

                    for (int dir = 0; dir < 4; ++dir)
                    {
                        int dx = x + rcGetDirOffsetX(dir);
                        int dy = y + rcGetDirOffsetY(dir);
                        // Skip neighbours which are out of bounds.
                        if (dx < 0 || dy < 0 || dx >= w || dy >= h)
                        {
                            minh = Math.Min(minh, -walkableClimb - bot);
                            continue;
                        }

                        // From minus infinity to the first span.
                        rcSpan ns   = solid.spans[dx + dy * w];
                        int    nbot = -walkableClimb;
                        int    ntop = ns != null ? (int)ns.smin : MAX_HEIGHT;
                        // Skip neightbour if the gap between the spans is too small.
                        if (Math.Min(top, ntop) - Math.Max(bot, nbot) > walkableHeight)
                        {
                            minh = Math.Min(minh, nbot - bot);
                        }

                        // Rest of the spans.
                        for (ns = solid.spans[dx + dy * w]; ns != null; ns = ns.next)
                        {
                            nbot = (int)ns.smax;
                            ntop = ns.next != null ? (int)ns.next.smin : MAX_HEIGHT;
                            // Skip neightbour if the gap between the spans is too small.
                            if (Math.Min(top, ntop) - Math.Max(bot, nbot) > walkableHeight)
                            {
                                minh = Math.Min(minh, nbot - bot);

                                // Find min/max accessible neighbour height.
                                if (Math.Abs(nbot - bot) <= walkableClimb)
                                {
                                    if (nbot < asmin)
                                    {
                                        asmin = nbot;
                                    }
                                    if (nbot > asmax)
                                    {
                                        asmax = nbot;
                                    }
                                }
                            }
                        }
                    }

                    // The current span is close to a ledge if the drop to any
                    // neighbour span is less than the walkableClimb.
                    if (minh < -walkableClimb)
                    {
                        s.area = RC_NULL_AREA;
                    }

                    // If the difference between all neighbours is too large,
                    // we are at steep slope, mark the span as ledge.
                    if ((asmax - asmin) > walkableClimb)
                    {
                        s.area = RC_NULL_AREA;
                    }
                }
            }
        }

        ctx.stopTimer(rcTimerLabel.RC_TIMER_FILTER_BORDER);
    }
Exemple #21
0
    /// @par
    ///
    /// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb
    /// from the current span's maximum.
    /// This method removes the impact of the overestimation of conservative voxelization 
    /// so the resulting mesh will not have regions hanging in the air over ledges.
    /// 
    /// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt>
    /// 
    /// @see rcHeightfield, rcConfig
    public static void rcFilterLedgeSpans(rcContext ctx, int walkableHeight, int walkableClimb,
						    rcHeightfield solid)
    {
        Debug.Assert(ctx != null, "rcContext is null");

        ctx.startTimer(rcTimerLabel.RC_TIMER_FILTER_BORDER);

        int w = solid.width;
        int h = solid.height;
        int MAX_HEIGHT = 0xffff;

        // Mark border spans.
        for (int y = 0; y < h; ++y)
        {
            for (int x = 0; x < w; ++x)
            {
                for (rcSpan s = solid.spans[x + y*w]; s != null; s = s.next)
                {
                    // Skip non walkable spans.
                    if (s.area == RC_NULL_AREA){
                        continue;
                    }

                    int bot = (int)(s.smax);
                    int top = s.next != null ? (int)(s.next.smin) : MAX_HEIGHT;

                    // Find neighbours minimum height.
                    int minh = MAX_HEIGHT;

                    // Min and max height of accessible neighbours.
                    int asmin = s.smax;
                    int asmax = s.smax;

                    for (int dir = 0; dir < 4; ++dir)
                    {
                        int dx = x + rcGetDirOffsetX(dir);
                        int dy = y + rcGetDirOffsetY(dir);
                        // Skip neighbours which are out of bounds.
                        if (dx < 0 || dy < 0 || dx >= w || dy >= h)
                        {
                            minh = Math.Min(minh, -walkableClimb - bot);
                            continue;
                        }

                        // From minus infinity to the first span.
                        rcSpan ns = solid.spans[dx + dy*w];
                        int nbot = -walkableClimb;
                        int ntop = ns != null ? (int)ns.smin : MAX_HEIGHT;
                        // Skip neightbour if the gap between the spans is too small.
                        if (Math.Min(top,ntop) - Math.Max(bot,nbot) > walkableHeight)
                            minh = Math.Min(minh, nbot - bot);

                        // Rest of the spans.
                        for (ns = solid.spans[dx + dy*w]; ns != null; ns = ns.next)
                        {
                            nbot = (int)ns.smax;
                            ntop = ns.next != null ? (int)ns.next.smin : MAX_HEIGHT;
                            // Skip neightbour if the gap between the spans is too small.
                            if (Math.Min(top,ntop) - Math.Max(bot,nbot) > walkableHeight)
                            {
                                minh = Math.Min(minh, nbot - bot);

                                // Find min/max accessible neighbour height.
                                if (Math.Abs(nbot - bot) <= walkableClimb)
                                {
                                    if (nbot < asmin) asmin = nbot;
                                    if (nbot > asmax) asmax = nbot;
                                }

                            }
                        }
                    }

                    // The current span is close to a ledge if the drop to any
                    // neighbour span is less than the walkableClimb.
                    if (minh < -walkableClimb){
                        s.area = RC_NULL_AREA;
                    }

                    // If the difference between all neighbours is too large,
                    // we are at steep slope, mark the span as ledge.
                    if ((asmax - asmin) > walkableClimb)
                    {
                        s.area = RC_NULL_AREA;
                    }
                }
            }
        }

        ctx.stopTimer(rcTimerLabel.RC_TIMER_FILTER_BORDER);
    }
        /// @par
        ///
        /// Allows the formation of walkable regions that will flow over low lying
        /// objects such as curbs, and up structures such as stairways.
        ///
        /// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt>
        ///
        /// @warning Will override the effect of #rcFilterLedgeSpans.  So if both filters are used, call
        /// #rcFilterLedgeSpans after calling this filter.
        ///
        /// @see rcHeightfield, rcConfig
        public static void rcFilterLowHangingWalkableObstacles(rcContext ctx, int walkableClimb, rcHeightfield solid)
        {
            Debug.Assert(ctx != null, "rcContext is null");

            ctx.startTimer(rcTimerLabel.RC_TIMER_FILTER_LOW_OBSTACLES);

            int w = solid.width;
            int h = solid.height;

            for (int y = 0; y < h; ++y)
            {
                for (int x = 0; x < w; ++x)
                {
                    rcSpan?ps = null;
                    bool   previousWalkable = false;
                    byte   previousArea     = RC_NULL_AREA;

                    for (rcSpan?s = solid.spans ![x + y * w]; s != null; ps = s, s = s.next)