From 0bca1de5c1da30934067729802bfee75bcdb412b Mon Sep 17 00:00:00 2001 From: David Capello Date: Fri, 9 Oct 2020 17:22:57 -0300 Subject: [PATCH] Add support to fill with tiles --- laf | 2 +- src/app/tools/point_shapes.h | 30 ++++++++++++++------- src/app/ui/editor/tool_loop_impl.cpp | 18 +++++++++---- src/doc/algorithm/floodfill.cpp | 40 ++++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/laf b/laf index 01553b175..7f0b6aea2 160000 --- a/laf +++ b/laf @@ -1 +1 @@ -Subproject commit 01553b175b910a3a7225cdd37edf7798501972e3 +Subproject commit 7f0b6aea27195c8012a206a20108cb8743087fb6 diff --git a/src/app/tools/point_shapes.h b/src/app/tools/point_shapes.h index fb549228a..945f1a6cb 100644 --- a/src/app/tools/point_shapes.h +++ b/src/app/tools/point_shapes.h @@ -249,20 +249,27 @@ public: void transformPoint(ToolLoop* loop, const Stroke::Pt& pt) override { const doc::Image* srcImage = loop->getFloodFillSrcImage(); - gfx::Point wpt = wrap_point(loop->getTiledMode(), - gfx::Size(srcImage->width(), - srcImage->height()), - pt.toPoint(), true); + const bool tilesMode = (srcImage->pixelFormat() == IMAGE_TILEMAP); + gfx::Point wpt = pt.toPoint(); + if (tilesMode) { // Tiles mode + const doc::Grid& grid = loop->getGrid(); + wpt = grid.canvasToTile(wpt); + } + else { + wpt = wrap_point(loop->getTiledMode(), + gfx::Size(srcImage->width(), + srcImage->height()), + wpt, true); + } loop->getInk()->prepareForPointShape(loop, true, wpt.x, wpt.y); - ASSERT(srcImage->pixelFormat() != IMAGE_TILEMAP); - doc::algorithm::floodfill( srcImage, (loop->useMask() ? loop->getMask(): nullptr), wpt.x, wpt.y, - floodfillBounds(loop, wpt.x, wpt.y), + (tilesMode ? srcImage->bounds(): + floodfillBounds(loop, wpt.x, wpt.y)), get_pixel(srcImage, wpt.x, wpt.y), loop->getTolerance(), loop->getContiguous(), @@ -276,11 +283,16 @@ public: private: gfx::Rect floodfillBounds(ToolLoop* loop, int x, int y) const { + const doc::Image* srcImage = loop->getFloodFillSrcImage(); gfx::Rect bounds = loop->sprite()->bounds(); - bounds &= loop->getFloodFillSrcImage()->bounds(); + bounds &= srcImage->bounds(); + if (srcImage->pixelFormat() == IMAGE_TILEMAP) { // Tiles mode + const doc::Grid& grid = loop->getGrid(); + bounds = grid.tileToCanvas(bounds); + } // Limit the flood-fill to the current tile if the grid is visible. - if (loop->getStopAtGrid()) { + else if (loop->getStopAtGrid()) { gfx::Rect grid = loop->getGridBounds(); if (!grid.isEmpty()) { div_t d, dx, dy; diff --git a/src/app/ui/editor/tool_loop_impl.cpp b/src/app/ui/editor/tool_loop_impl.cpp index b8bcd9990..c1495edfd 100644 --- a/src/app/ui/editor/tool_loop_impl.cpp +++ b/src/app/ui/editor/tool_loop_impl.cpp @@ -179,8 +179,11 @@ public: ASSERT(m_controller); if (m_tilesMode) { - m_pointShape = App::instance()->toolBox()->getPointShapeById( - tools::WellKnownPointShapes::Tile); + // Use FloodFillPointShape or TilePointShape in tiles mode + if (!m_pointShape->isFloodFill()) { + m_pointShape = App::instance()->toolBox()->getPointShapeById( + tools::WellKnownPointShapes::Tile); + } // In selection ink, we need the Pixels tilemap mode so // ExpandCelCanvas uses the whole canvas for the selection @@ -488,9 +491,13 @@ public: , m_saveLastPoint(saveLastPoint) { if (m_pointShape->isFloodFill()) { + if (m_tilesMode) { + // This will be set later to getSrcImage() + m_floodfillSrcImage = nullptr; + } // Prepare a special image for floodfill when it's configured to // stop using all visible layers. - if (m_toolPref.floodfill.referTo() == gen::FillReferTo::ALL_LAYERS) { + else if (m_toolPref.floodfill.referTo() == gen::FillReferTo::ALL_LAYERS) { m_floodfillSrcImage = Image::create(m_sprite->pixelFormat(), m_sprite->width(), m_sprite->height()); @@ -945,8 +952,9 @@ public: tools::WellKnownPointShapes::Brush); } else if (m_pointShape->isFloodFill()) { - m_pointShape = App::instance()->toolBox()->getPointShapeById( - tools::WellKnownPointShapes::Pixel); + m_pointShape = App::instance()->toolBox()->getPointShapeById + (m_tilesMode ? tools::WellKnownPointShapes::Tile: + tools::WellKnownPointShapes::Pixel); } } diff --git a/src/doc/algorithm/floodfill.cpp b/src/doc/algorithm/floodfill.cpp index f647b1773..81c7b3e56 100644 --- a/src/doc/algorithm/floodfill.cpp +++ b/src/doc/algorithm/floodfill.cpp @@ -48,6 +48,11 @@ static int flood_count; /* number of flooded segments */ #define FLOOD_LINE(c) (&flood_buf[c]) +static inline bool color_equal_32_raw(color_t c1, color_t c2) +{ + return (c1 == c2); +} + static inline bool color_equal_32(color_t c1, color_t c2, int tolerance) { if (tolerance == 0) @@ -123,6 +128,12 @@ inline bool color_equal(color_t c1, color_t c2, int tolerance) return color_equal_8(c1, c2, tolerance); } +template<> +inline bool color_equal(color_t c1, color_t c2, int tolerance) +{ + return color_equal_32_raw(c1, c2); +} + /* flooder: @@ -216,6 +227,30 @@ static int flooder(const Image* image, } break; + case IMAGE_TILEMAP: + { + // TODO add support for mask + + uint32_t* address = reinterpret_cast(image->getPixelAddress(0, y)); + + // Check start pixel + if (!color_equal_32_raw((int)*(address+x), src_color)) + return x+1; + + // Work left from starting point + for (left=x-1; left>=bounds.x; left--) { + if (!color_equal_32_raw((int)*(address+left), src_color)) + break; + } + + // Work right from starting point + for (right=x+1; right(image, bounds, src_color, tolerance, data, proc); break; - // TODO We could add the case IMAGE_TILEMAP: ... break; - // to support replacing one tile with another one + case IMAGE_TILEMAP: + replace_color(image, bounds, src_color, tolerance, data, proc); + break; } return; }