Beispiel #1
0
        public override void FloodFill(System.Drawing.Point pt)
        {
            pts.Clear();
            watch.Reset();
            watch.Start();
            PrepareForFloodFill(pt);

            unsafe
            {
                bitmapStride = bitmap.Stride;
                scan0        = (byte *)bitmap.Iptr;
                int   x = pt.X; int y = pt.Y;
                int   loc      = CoordsToIndex(ref x, ref y);
                byte *colorPtr = ((byte *)(scan0 + loc));
                startColor = new byte[] { colorPtr[0], colorPtr[1], colorPtr[2] };
                LinearFloodFill4(ref x, ref y);

                bool[] pixelsChecked = this.pixelsChecked;

                while (ranges.Count > 0)
                {
                    FloodFillRange range = ranges.Dequeue();

                    //START THE LOOP UPWARDS AND DOWNWARDS
                    int   upY       = range.Y - 1;//so we can pass the y coord by ref
                    int   downY     = range.Y + 1;
                    byte *upPtr     = (byte *)(scan0 + CoordsToIndex(ref range.StartX, ref upY));
                    byte *downPtr   = (byte *)(scan0 + CoordsToIndex(ref range.StartX, ref downY));
                    int   downPxIdx = (bitmapWidth * (range.Y + 1)) + range.StartX; //CoordsToPixelIndex(range.StartX,range.Y+1);
                    int   upPxIdx   = (bitmapWidth * (range.Y - 1)) + range.StartX; //CoordsToPixelIndex(range.StartX, range.Y - 1);
                    for (int i = range.StartX; i <= range.EndX; i++)
                    {
                        //START LOOP UPWARDS
                        //if we're not above the top of the bitmap and the pixel above this one is within the color tolerance
                        if (range.Y > 0 && CheckPixel(ref upPtr) && (!(pixelsChecked[upPxIdx])))
                        {
                            LinearFloodFill4(ref i, ref upY);
                        }
                        //START LOOP DOWNWARDS
                        if (range.Y < (bitmapHeight - 1) && CheckPixel(ref downPtr) && (!(pixelsChecked[downPxIdx])))
                        {
                            LinearFloodFill4(ref i, ref downY);
                        }
                        upPtr   += bitmapPixelFormatSize;
                        downPtr += bitmapPixelFormatSize;
                        downPxIdx++;
                        upPxIdx++;
                    }
                }
            }
            watch.Stop();
        }
        /// <summary>Removes and returns the <see cref="FloodFillRange"/> at the beginning of the queue.</summary>
        public FloodFillRange Dequeue()
        {
            FloodFillRange range = new FloodFillRange();

            if (size > 0)
            {
                range       = array[head];
                array[head] = new FloodFillRange();
                head++; //advance head position
                size--; //update size to exclude dequeued item
            }
            return(range);
        }
Beispiel #3
0
        /// <summary>
        /// Fills the specified point on the bitmap with the fill value.
        /// </summary>
        /// <param name="pt">The starting point for the fill.</param>
        public override FillData FloodFill(Vector2Int pt)
        {
            ranges = new FloodFillRangeQueue(((gridWidth + gridHeight) / 2) * 5);

            int x = pt.x; int y = pt.y;

            //***Do first call to floodfill.
            LinearFill(ref x, ref y);

            //***Call floodfill routine while floodfill ranges still exist on the queue
            while (ranges.Count > 0)
            {
                //**Get Next Range Off the Queue
                FloodFillRange range = ranges.Dequeue();

                //**Check Above and Below Each cell in the Floodfill Range
                int upY   = range.Y - 1;//so we can pass the y coord by ref
                int downY = range.Y + 1;
                int i     = range.StartX;
                if (range.StartX > 0)
                {
                    i--;                    //check the diagonals
                }
                int downPxIdx = (gridWidth * (range.Y + 1)) + i;
                int upPxIdx   = (gridWidth * (range.Y - 1)) + i;
                while (i <= range.EndX + 1 && i < gridWidth)
                {
                    //*Start Fill Upwards
                    //if we're not above the top of the grid and the cell above this one is free
                    if (range.Y > 0 && (!gridCells[upPxIdx]) && CheckCell(ref upPxIdx))
                    {
                        LinearFill(ref i, ref upY);
                    }

                    //*Start Fill Downwards
                    //if we're not below the bottom of the grid and the pixel below this one is free
                    if (range.Y < (gridHeight - 1) && (!gridCells[downPxIdx]) && CheckCell(ref downPxIdx))
                    {
                        LinearFill(ref i, ref downY);
                    }
                    downPxIdx++;
                    upPxIdx++;
                    i++;
                }
            }

            return(new FillData(gridWidth, gridCells));
        }
Beispiel #4
0
        /// <summary>
        /// Finds the furthermost left and right boundaries of the fill area
        /// on a given y coordinate, starting from a given x coordinate, filling as it goes.
        /// Adds the resulting horizontal range to the queue of floodfill ranges,
        /// to be processed in the main loop.
        /// </summary>
        /// <param name="x">The x coordinate to start from.</param>
        /// <param name="y">The y coordinate to check at.</param>
        void LinearFill(ref int x, ref int y)
        {
            //***Find Left Edge of fill area
            int lFillLoc = x;                           //the location to check/fill on the left
            int idx      = CoordsToIndex(ref x, ref y); //the index of the current location

            while (true)
            {
                //**fill with the fillValue
                gridCells[idx] = true;
                //**de-increment
                lFillLoc--; //de-increment counter
                idx -= 1;   //de-increment index
                //**exit loop if we're at edge of fill area
                if (lFillLoc <= 0 || (gridCells[idx]) || !CheckCell(ref idx))
                {
                    break;
                }
            }
            lFillLoc++;

            //***Find Right Edge of free area
            int rFillLoc = x; //the location to check/fill on the right

            idx = CoordsToIndex(ref x, ref y);
            while (true)
            {
                //**fill with the fillValue
                gridCells[idx] = true;
                //**increment
                rFillLoc++; //increment counter
                idx += 1;   //increment index
                //**exit loop if we're at edge of fill area
                if (rFillLoc >= gridWidth || gridCells[idx] || !CheckCell(ref idx))
                {
                    break;
                }
            }
            rFillLoc--;

            //add range to queue
            FloodFillRange r = new FloodFillRange(lFillLoc, rFillLoc, y);

            ranges.Enqueue(ref r);
        }
        /// <summary>
        /// Finds the furthermost left and right boundaries of the fill area
        /// on a given y coordinate, starting from a given x coordinate, filling as it goes.
        /// Adds the resulting horizontal range to the queue of floodfill ranges,
        /// to be processed in the main loop.
        /// </summary>
        /// <param name="x">The x coordinate to start from.</param>
        /// <param name="y">The y coordinate to check at.</param>
        void LinearFill(ref int x, ref int y)
        {
            //cache some bitmap and fill info in local variables for a little extra speed
            byte[] bitmapBits            = this.bitmapBits;
            bool[] pixelsChecked         = this.pixelsChecked;
            byte[] byteFillColor         = this.byteFillColor;
            int    bitmapPixelFormatSize = this.bitmapPixelFormatSize;
            int    bitmapWidth           = this.bitmapWidth;

            //***Find Left Edge of Color Area
            int lFillLoc = x;                               //the location to check/fill on the left
            int idx      = CoordsToByteIndex(ref x, ref y); //the byte index of the current location
            int pxIdx    = (bitmapWidth * y) + x;           //CoordsToPixelIndex(x,y);

            while (true)
            {
                //**fill with the color
                bitmapBits[idx]     = byteFillColor[0];
                bitmapBits[idx + 1] = byteFillColor[1];
                bitmapBits[idx + 2] = byteFillColor[2];
                //**indicate that this pixel has already been checked and filled
                pixelsChecked[pxIdx] = true;
                //**screen update for 'slow' fill
                if (slow)
                {
                    UpdateScreen(ref lFillLoc, ref y);
                }
                //**de-increment
                lFillLoc--;                   //de-increment counter
                pxIdx--;                      //de-increment pixel index
                idx -= bitmapPixelFormatSize; //de-increment byte index
                //**exit loop if we're at edge of bitmap or color area
                if (lFillLoc <= 0 || (pixelsChecked[pxIdx]) || !CheckPixel(ref idx))
                {
                    break;
                }
            }
            lFillLoc++;

            //***Find Right Edge of Color Area
            int rFillLoc = x; //the location to check/fill on the left

            idx   = CoordsToByteIndex(ref x, ref y);
            pxIdx = (bitmapWidth * y) + x;
            while (true)
            {
                //**fill with the color
                bitmapBits[idx]     = byteFillColor[0];
                bitmapBits[idx + 1] = byteFillColor[1];
                bitmapBits[idx + 2] = byteFillColor[2];
                //**indicate that this pixel has already been checked and filled
                pixelsChecked[pxIdx] = true;
                //**screen update for 'slow' fill
                if (slow)
                {
                    UpdateScreen(ref rFillLoc, ref y);
                }
                //**increment
                rFillLoc++;                   //increment counter
                pxIdx++;                      //increment pixel index
                idx += bitmapPixelFormatSize; //increment byte index
                //**exit loop if we're at edge of bitmap or color area
                if (rFillLoc >= bitmapWidth || pixelsChecked[pxIdx] || !CheckPixel(ref idx))
                {
                    break;
                }
            }
            rFillLoc--;

            //add range to queue
            FloodFillRange r = new FloodFillRange(lFillLoc, rFillLoc, y);

            ranges.Enqueue(ref r);
        }
Beispiel #6
0
        unsafe void LinearFloodFill4(ref int x, ref int y)
        {
            //offset the pointer to the point passed in
            byte *p = (byte *)(scan0 + (CoordsToIndex(ref x, ref y)));

            //cache some bitmap and fill info in local variables for a little extra speed
            bool[] pixelsChecked         = this.pixelsChecked;
            byte[] byteFillColor         = this.byteFillColor;
            int    bitmapPixelFormatSize = this.bitmapPixelFormatSize;
            int    bitmapWidth           = this.bitmapWidth;

            //FIND LEFT EDGE OF COLOR AREA
            int   lFillLoc = x; //the location to check/fill on the left
            byte *ptr      = p; //the pointer to the current location
            int   pxIdx    = (bitmapWidth * y) + x;

            while (true)
            {
                ptr[0] = byteFillColor[0];       //fill with the color
                ptr[1] = byteFillColor[1];
                ptr[2] = byteFillColor[2];
                if (bitmapPixelFormatSize == 4)
                {
                    ptr[3] = byteFillColor[3];
                }
                pixelsChecked[pxIdx] = true;
                lFillLoc--;                      //de-increment counter
                ptr -= bitmapPixelFormatSize;    //de-increment pointer
                pxIdx--;
                if (lFillLoc <= 0 || !CheckPixel(ref ptr) || (pixelsChecked[pxIdx]))
                {
                    break;                               //exit loop if we're at edge of bitmap or color area
                }
            }
            lFillLoc++;

            //FIND RIGHT EDGE OF COLOR AREA
            int rFillLoc = x; //the location to check/fill on the left

            ptr   = p;
            pxIdx = (bitmapWidth * y) + x;
            while (true)
            {
                ptr[0] = byteFillColor[0];       //fill with the color
                ptr[1] = byteFillColor[1];
                ptr[2] = byteFillColor[2];
                if (bitmapPixelFormatSize == 4)
                {
                    ptr[3] = byteFillColor[3];
                }

                pixelsChecked[pxIdx] = true;
                rFillLoc++;                   //increment counter
                ptr += bitmapPixelFormatSize; //increment pointer
                pxIdx++;
                if (rFillLoc >= bitmapWidth || !CheckPixel(ref ptr) || (pixelsChecked[pxIdx]))
                {
                    break;                       //exit loop if we're at edge of bitmap or color area
                }
            }
            rFillLoc--;

            FloodFillRange r = new FloodFillRange(lFillLoc, rFillLoc, y);

            ranges.Enqueue(ref r);
        }