Fix copying irregular areas of tiles in "tiles mode"

Now we can use the lasso tool in tiles mode, select an
irregular (non-rectangular) area and move that area of tiles
correctly.
This commit is contained in:
David Capello 2021-03-22 20:20:20 -03:00
parent 5cd66b58f1
commit 726065164f
3 changed files with 55 additions and 23 deletions

View File

@ -1032,10 +1032,16 @@ void PixelsMovement::drawImage(
dst->setMaskColor(doc::notile);
dst->clear(dst->maskColor());
if (renderOriginalLayer && m_site.cel()) {
doc::Grid grid = m_site.grid();
dst->copy(m_site.cel()->image(),
gfx::Clip(0, 0, grid.canvasToTile(bounds)));
}
drawTransformedTilemap(
transformation,
dst, m_originalImage.get(),
m_initialMask.get(), corners, pt);
m_initialMask.get());
}
else {
dst->setMaskColor(m_site.sprite()->transparentColor());
@ -1163,11 +1169,31 @@ retry:; // In case that we don't have enough memory for RotSprite
}
}
static void merge_tilemaps(Image* dst, const Image* src, gfx::Clip area)
{
if (!area.clip(dst->width(), dst->height(), src->width(), src->height()))
return;
ImageConstIterator<TilemapTraits> src_it(src, area.srcBounds(), area.src.x, area.src.y);
ImageIterator<TilemapTraits> dst_it(dst, area.dstBounds(), area.dst.x, area.dst.y);
int end_x = area.dst.x+area.size.w;
for (int end_y=area.dst.y+area.size.h;
area.dst.y<end_y;
++area.dst.y, ++area.src.y) {
for (int x=area.dst.x; x<end_x; ++x) {
if (*src_it != doc::notile)
*dst_it = *src_it;
++src_it;
++dst_it;
}
}
}
void PixelsMovement::drawTransformedTilemap(
const Transformation& transformation,
doc::Image* dst, const doc::Image* src, const doc::Mask* mask,
const Transformation::Corners& corners,
const gfx::PointF& leftTop)
doc::Image* dst, const doc::Image* src, const doc::Mask* mask)
{
const int boxw = std::max(1, src->width()-2);
const int boxh = std::max(1, src->height()-2);
@ -1175,13 +1201,13 @@ void PixelsMovement::drawTransformedTilemap(
// Function to copy a whole row of tiles (h=number of tiles in Y axis)
auto draw_row =
[dst, src, boxw](int y, int v, int h) {
dst->copy(src, gfx::Clip(0, y, 0, v, 1, h));
merge_tilemaps(dst, src, gfx::Clip(0, y, 0, v, 1, h));
if (boxw) {
const int u = std::min(1, src->width()-1);
for (int x=1; x<dst->width()-1; x+=boxw)
dst->copy(src, gfx::Clip(x, y, u, v, boxw, h));
merge_tilemaps(dst, src, gfx::Clip(x, y, u, v, boxw, h));
}
dst->copy(src, gfx::Clip(dst->width()-1, y, src->width()-1, v, 1, h));
merge_tilemaps(dst, src, gfx::Clip(dst->width()-1, y, src->width()-1, v, 1, h));
};
draw_row(0, 0, 1);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -140,7 +140,7 @@ namespace app {
void redrawCurrentMask();
void drawImage(
const Transformation& transformation,
doc::Image* dst, const gfx::PointF& pos,
doc::Image* dst, const gfx::PointF& pt,
const bool renderOriginalLayer);
void drawMask(doc::Mask* dst, bool shrink);
void drawParallelogram(
@ -150,9 +150,7 @@ namespace app {
const gfx::PointF& leftTop);
void drawTransformedTilemap(
const Transformation& transformation,
doc::Image* dst, const doc::Image* src, const doc::Mask* mask,
const Transformation::Corners& corners,
const gfx::PointF& leftTop);
doc::Image* dst, const doc::Image* src, const doc::Mask* mask);
void updateDocumentMask();
void hideDocumentMask();

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2020 Igara Studio S.A.
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -123,6 +123,10 @@ doc::Image* new_tilemap_from_mask(const Site& site,
ASSERT(srcSprite);
ASSERT(srcMask);
const Cel* srcCel = site.cel();
if (!srcCel)
return nullptr;
const doc::Grid grid = site.grid();
const Image* srcMaskBitmap = srcMask->bitmap();
const gfx::Rect& srcBounds = srcMask->bounds();
@ -141,28 +145,32 @@ doc::Image* new_tilemap_from_mask(const Site& site,
// Clear the new tilemap
clear_image(dst.get(), dst->maskColor());
if (auto cel = site.cel()) {
// Just copy tilemap data
dst->copy(cel->image(), gfx::Clip(0, 0, srcTilesBounds));
}
// Copy the masked zones
if (srcMaskBitmap) {
// Copy active layer with mask
const LockImageBits<BitmapTraits> maskBits(srcMaskBitmap, gfx::Rect(0, 0, srcBounds.w, srcBounds.h));
LockImageBits<BitmapTraits>::const_iterator mask_it = maskBits.begin();
auto mask_it = maskBits.begin();
const gfx::Point originPt = grid.canvasToTile(srcBounds.origin());
for (int v=0; v<srcBounds.h; ++v) {
for (int u=0; u<srcBounds.w; ++u, ++mask_it) {
ASSERT(mask_it != maskBits.end());
if (!*mask_it) {
gfx::Point pt = grid.canvasToTile(gfx::Point(srcBounds.x+u, srcBounds.y+v));
if (dst->bounds().contains(pt))
dst->putPixel(pt.x, pt.y, dst->maskColor());
if (*mask_it) {
gfx::Point srcPt = grid.canvasToTile(gfx::Point(srcBounds.x+u, srcBounds.y+v));
gfx::Point dstPt = srcPt - originPt;
if (dst->bounds().contains(dstPt) &&
srcCel->image()->bounds().contains(srcPt)) {
dst->putPixel(dstPt.x, dstPt.y, srcCel->image()->getPixel(srcPt.x, srcPt.y));
}
}
}
}
}
else {
// Just copy tilemap data
dst->copy(srcCel->image(), gfx::Clip(0, 0, srcTilesBounds));
}
return dst.release();
}