draw_floodfill.hpp

Back to 2d drawing

pastel/gfx/drawing/

#ifndef PASTELGFX_DRAW_FLOODFILL_HPP
#define PASTELGFX_DRAW_FLOODFILL_HPP

#include "pastel/gfx/drawing/draw_floodfill.h"

#include <vector>

namespace Pastel
{

    template <typename Type, typename Image_View>
    void floodFill(
        integer xStart, integer yStart,
        const NoDeduction<Type>& color,
        const View<2, Type, Image_View>& image)
    {
        integer width = image.width();
        integer height = image.height();

        if (xStart < 0 || xStart >= width ||
            yStart < 0 || yStart >= height)
        {
            // Seed point out of range.
            return;
        }

        using Cursor = typename Image_View::Cursor;

        const Type source = *image.cursor(xStart, yStart);

        if (source == color)
        {
            // No need to do anything.
            return;
        }

        std::vector<Integer2> stack;
        stack.push_back(Integer2(xStart, yStart));

        while (!stack.empty())
        {
            Integer2 line = stack.back();
            stack.pop_back();

            // Find the extents of this scanline
            // and draw it.

            integer xLeft = line[0];
            integer xRight = line[0];
            integer y = line[1];

            Cursor yCursor = image.cursor(xLeft, y);

            if (*yCursor != source)
            {
                continue;
            }

            {
                Cursor leftCursor = yCursor;
                leftCursor.xDecrement();

                while(xLeft > 0 && *leftCursor == source)
                {
                    *leftCursor = color;

                    --xLeft;
                    leftCursor.xDecrement();
                }
            }

            {
                Cursor xyCursor = yCursor;

                while(xRight < width && *xyCursor == source)
                {
                    *xyCursor = color;

                    ++xRight;
                    xyCursor.xIncrement();
                }
            }

            // Recurse up and down.

            if (y < height - 1)
            {
                // Recurse top line.

                bool lineHandled = false;

                integer yTop = y + 1;

                Cursor xyCursor = image.cursor(xLeft, yTop);

                for (integer x = xLeft;x < xRight;++x)
                {

                    if (*xyCursor == source)
                    {
                        if (!lineHandled)
                        {
                            stack.push_back(Integer2(x, yTop));
                            lineHandled = true;
                        }
                    }
                    else
                    {
                        lineHandled = false;
                    }

                    xyCursor.xIncrement();
                }
            }
            if (y > 0)
            {
                // Recurse bottom line.

                bool lineHandled = false;

                integer yBottom = y - 1;

                Cursor xyCursor = image.cursor(xLeft, yBottom);

                for (integer x = xLeft;x < xRight;++x)
                {

                    if (*xyCursor == source)
                    {
                        if (!lineHandled)
                        {
                            stack.push_back(Integer2(x, yBottom));
                            lineHandled = true;
                        }
                    }
                    else
                    {
                        lineHandled = false;
                    }

                    xyCursor.xIncrement();
                }
            }
        }
    }

}

#endif