Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Windows-Phone-7

WP7 FloodFill in Texture2D using Scan line Stack Algo

0.00/5 (No votes)
5 Feb 2012CPOL 27.6K  
WP7 FloodFill in Texture2D using Scan line Stack Algo
If you are in WP7 XNA, might be somewhere you need to FloodFill in a texture2D.

I have a simple class that flood fills in texture2D.

This class is using FloodFill Scan line Stack algo. it fills the object in this
manner
C#
using System;

using System.Collections.Generic;
using Microsoft.Xna.Framework;

public class FloodFill
    {
        Stack<Microsoft.Xna.Framework.Point> StkColoringPoints;
        
        public FloodFill()
        {
            StkColoringPoints = new Stack<Microsoft.Xna.Framework.Point>();
        }

        /// <summary>
        /// perform flood fill algorithm and return the updated buffer
        /// </summary>
        /// <param name="screenBuffer"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public Microsoft.Xna.Framework.Color[,] FloodFillToPoint(Microsoft.Xna.Framework.Color[,] screenBuffer, Vector2 point,Color newColor)
        {
            StkColoringPoints = new Stack<Microsoft.Xna.Framework.Point>();
            Microsoft.Xna.Framework.Point floodInvokePoint = new Microsoft.Xna.Framework.Point((int)point.X, (int)point.Y);

           return floodFillScanlineStack(screenBuffer, floodInvokePoint,newColor.PackedValue);
        }
        /// <summary>
        /// implements the flood fill scan line stack method to fill the color inside colosed boundry
        /// </summary>
        private Microsoft.Xna.Framework.Color[,] floodFillScanlineStack(Microsoft.Xna.Framework.Color[,] screenBuffer, Microsoft.Xna.Framework.Point floodInvokePoint, uint newColorCode)
        {
            uint oldColorCode = screenBuffer[floodInvokePoint.X, floodInvokePoint.Y].PackedValue;

            if (oldColorCode == newColorCode) 
                return screenBuffer;

            int y1;
            bool spanLeft, spanRight;

            int BUFFERWIDTH = screenBuffer.GetLength(0);
            int BUFFERHEIGHT = screenBuffer.GetLength(1);

            StkColoringPoints.Push(floodInvokePoint);

            while (StkColoringPoints.Count > 0)
            {
                floodInvokePoint = StkColoringPoints.Pop();
                y1 = floodInvokePoint.Y;

                while (y1 >= 0 && screenBuffer[floodInvokePoint.X, y1].PackedValue == oldColorCode) y1--;
                y1++;
                spanLeft = spanRight = false;
                while (y1 < BUFFERHEIGHT && screenBuffer[floodInvokePoint.X, y1].PackedValue == oldColorCode)
                {
                    screenBuffer[floodInvokePoint.X, y1].PackedValue = newColorCode;
                    if (!spanLeft && floodInvokePoint.X > 0 && screenBuffer[floodInvokePoint.X - 1, y1].PackedValue == oldColorCode)
                    {
                        StkColoringPoints.Push(new Microsoft.Xna.Framework.Point { X = floodInvokePoint.X - 1, Y = y1 });
                        spanLeft = true;
                    }
                    else if (spanLeft && floodInvokePoint.X > 0 && screenBuffer[floodInvokePoint.X - 1, y1].PackedValue != oldColorCode)
                    {
                        spanLeft = false;
                    }
                    if (!spanRight && floodInvokePoint.X < BUFFERWIDTH - 1 && screenBuffer[floodInvokePoint.X + 1, y1].PackedValue == oldColorCode)
                    {
                        StkColoringPoints.Push(new Microsoft.Xna.Framework.Point { X = floodInvokePoint.X + 1, Y = y1 });
                        spanRight = true;
                    }
                    else if (spanRight && floodInvokePoint.X < BUFFERWIDTH - 1 && screenBuffer[floodInvokePoint.X + 1, y1].PackedValue != oldColorCode)
                    {
                        spanRight = false;
                    }
                    y1++;
                }
            }
            return screenBuffer;
        }       
    }


Some utility functions:
C#
private Microsoft.Xna.Framework.Color[,] ConvertTo2DArray(Microsoft.Xna.Framework.Color[] data, int columns, int rows)
        {
            Microsoft.Xna.Framework.Color[,] data2d = new Microsoft.Xna.Framework.Color[columns, rows];
            int counter = 0;
            for (int h = 0; h < rows; h++)
            {
                for (int w = 0; w < columns; w++)
                    data2d[w, h] = data[counter++];
            }
            return data2d;
        }
        private Microsoft.Xna.Framework.Color[] ConvertTo1DArray(Microsoft.Xna.Framework.Color[,] data2d)
        {
            Microsoft.Xna.Framework.Color[] data = new Microsoft.Xna.Framework.Color[data2d.Length];
            int counter = 0;
            for (int h = 0; h < data2d.GetLength(1); h++)
            {
                for (int w = 0; w < data2d.GetLength(0); w++)
                    data[counter++] = data2d[w, h];
            }
            return data;
        }

Assuming ColoringObject.Texture is your texture.

C#
Microsoft.Xna.Framework.Color[] Texture1D = new  Microsoft.Xna.Framework.Color [ ColoringObject.Texture.Width * ColoringObject.Texture.Height];
            ColoringObject.Texture.GetData(Texture1D);
            FloodFill floodfill = new FloodFill(); 
            Microsoft.Xna.Framework.Color[,] Texture2D = ConvertTo2DArray(Texture1D, ColoringObject.Texture.Width, ColoringObject.Texture.Height);
            Texture2D = floodfill.FloodFillToPoint(Texture2D,touchPosition,this.fillingColor);
            Texture1D = ConvertTo1DArray(Texture2D);

            this.SpriteBatch.GraphicsDevice.Textures[0] = null;
            ColoringObject.Texture.SetData(Texture1D);


Happy coding...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)