Add support to fill with tiles

This commit is contained in:
David Capello 2020-10-09 17:22:57 -03:00
parent 0e84e8642e
commit 0bca1de5c1
4 changed files with 73 additions and 17 deletions

2
laf

@ -1 +1 @@
Subproject commit 01553b175b910a3a7225cdd37edf7798501972e3
Subproject commit 7f0b6aea27195c8012a206a20108cb8743087fb6

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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<IndexedTraits>(color_t c1, color_t c2, int tolerance)
return color_equal_8(c1, c2, tolerance);
}
template<>
inline bool color_equal<TilemapTraits>(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<uint32_t*>(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<bounds.x2(); right++) {
if (!color_equal_32_raw((int)*(address+right), src_color))
break;
}
}
break;
default:
// Check start pixel
if (get_pixel(image, x, y) != src_color || MASKED(x, y))
@ -367,8 +402,9 @@ void floodfill(const Image* image,
case IMAGE_INDEXED:
replace_color<IndexedTraits>(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<TilemapTraits>(image, bounds, src_color, tolerance, data, proc);
break;
}
return;
}