mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-01 09:04:02 +00:00
Add support to fill with tiles
This commit is contained in:
parent
0e84e8642e
commit
0bca1de5c1
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit 01553b175b910a3a7225cdd37edf7798501972e3
|
||||
Subproject commit 7f0b6aea27195c8012a206a20108cb8743087fb6
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user