Add support to TilemapMode::Tiles mode

When transforming slices in a tilemap layer while Tiles mode is active
This commit is contained in:
Martín Capello 2024-07-25 10:16:10 -03:00 committed by David Capello
parent f5baba389b
commit ca75a98679
5 changed files with 87 additions and 71 deletions

View File

@ -32,47 +32,45 @@ ClearSlices::ClearSlices(const Site& site,
: m_tilemapMode(site.tilemapMode())
, m_tilesetMode(site.tilesetMode())
{
//Doc* doc = static_cast<Doc*>(cel->document());
if (layers.empty())
return;
Doc* doc = static_cast<Doc*>((*layers.begin())->sprite()->document());
for (const auto& sk : slicesKeys) {
m_mask.add(sk.bounds());
}
const gfx::Rect maskBounds = m_mask.bounds();
// gfx::Rect maskBounds;
// if (image->pixelFormat() == IMAGE_TILEMAP) {
// auto grid = cel->grid();
// imageBounds = gfx::Rect(grid.canvasToTile(cel->position()),
// cel->image()->size());
// maskBounds = grid.canvasToTile(mask->bounds());
// m_bgcolor = doc::notile; // TODO configurable empty tile
// }
// else {
for (auto* layer : layers) {
SlicesContent sc;
for (const auto& sk : slicesKeys) {
sc.mask.add(sk.bounds());
}
gfx::Rect maskBounds = sc.mask.bounds();
Cel* cel = layer->cel(frame);
const gfx::Rect imageBounds = cel->bounds();
Image* image = cel->image();
assert(image);
if (!image)
continue;
gfx::Rect imageBounds = cel->bounds();
color_t bgcolor = doc->bgColor(layer);
if (image->pixelFormat() == IMAGE_TILEMAP) {
auto grid = cel->grid();
imageBounds = gfx::Rect(grid.canvasToTile(cel->position()),
cel->image()->size());
maskBounds = grid.canvasToTile(maskBounds);
bgcolor = doc::notile; // TODO configurable empty tile
}
gfx::Rect cropBounds = (imageBounds & maskBounds);
if (cropBounds.isEmpty())
continue;
cropBounds.offset(-imageBounds.origin());
Image* image = cel->image();
assert(image);
if (!image)
continue;
SlicesContent sc;
sc.cel = cel;
sc.cropPos = cropBounds.origin();
sc.bgcolor = doc->bgColor(layer);
sc.bgcolor = bgcolor;
sc.copy.reset(crop_image(image, cropBounds, sc.bgcolor));
m_slicesContents.push_back(sc);
}
}
@ -105,27 +103,19 @@ void ClearSlices::clear()
if (sc.cel->layer()->isTilemap() && m_tilemapMode == TilemapMode::Pixels) {
Doc* doc = static_cast<Doc*>(sc.cel->document());
/*
// Simple case (there is no visible selection, so we remove the
// whole cel)
if (!doc->isMaskVisible()) {
cmds->executeAndAdd(new cmd::ClearCel(cel));
return;
}
*/
color_t bgcolor = doc->bgColor(sc.cel->layer());
modify_tilemap_cel_region(
&m_seq, sc.cel, nullptr,
gfx::Region(m_mask.bounds()),
gfx::Region(sc.mask.bounds()),
m_tilesetMode,
[this, bgcolor](const doc::ImageRef& origTile,
[sc, bgcolor](const doc::ImageRef& origTile,
const gfx::Rect& tileBoundsInCanvas) -> doc::ImageRef {
doc::ImageRef modified(doc::Image::createCopy(origTile.get()));
doc::algorithm::fill_selection(
modified.get(),
tileBoundsInCanvas,
&m_mask,
&sc.mask,
bgcolor,
nullptr);
return modified;
@ -136,7 +126,7 @@ void ClearSlices::clear()
doc::algorithm::fill_selection(
sc.cel->image(),
sc.cel->bounds(),
&m_mask,
&sc.mask,
sc.bgcolor,
(sc.cel->image()->isTilemap() ? &grid: nullptr));
}

View File

@ -53,6 +53,7 @@ namespace cmd {
Cel* cel = nullptr;
// Image having a copy of the content of each selected slice.
ImageRef copy = nullptr;
Mask mask;
gfx::Point cropPos;
color_t bgcolor;
size_t memSize() const {
@ -63,7 +64,6 @@ namespace cmd {
void clear();
void restore();
Mask m_mask;
CmdSequence m_seq;
// Slices content for each selected layer's cel
std::vector<SlicesContent> m_slicesContents;

View File

@ -54,7 +54,6 @@ MovingSliceState::MovingSliceState(Editor* editor,
: m_frame(editor->frame())
, m_hit(hit)
, m_items(std::max<std::size_t>(1, selectedSlices.size()))
//, m_reader(UIContext::instance())
, m_tx(Tx::DontLockDoc, UIContext::instance(),
UIContext::instance()->activeDocument(),
(editor->slicesTransforms() ? "Slices Transformation" : "Slice Movement"))
@ -95,6 +94,12 @@ void MovingSliceState::onEnterState(Editor* editor)
{
if (editor->slicesTransforms() && !m_items.empty()) {
for (auto& item : m_items) {
// Align slice origin to tiles origin under Tiles mode.
if (m_site.tilemapMode() == TilemapMode::Tiles) {
auto origin = m_site.grid().tileToCanvas(m_site.grid().canvasToTile(item.newKey.bounds().origin()));
auto bounds = gfx::Rect(origin, item.newKey.bounds().size());
item.newKey.setBounds(bounds);
}
item.imgs.reserve(m_selectedLayers.size());
item.masks.reserve(m_selectedLayers.size());
int i = 0;
@ -106,7 +111,7 @@ void MovingSliceState::onEnterState(Editor* editor)
if (layer &&
layer->isTilemap() &&
m_site.tilemapMode() == TilemapMode::Tiles) {
//item.img.reset(new_tilemap_from_mask(m_site, item.mask.get()));
item.imgs[i].reset(new_tilemap_from_mask(m_site, item.masks[i].get()));
}
else {
item.imgs[i].reset(new_image_from_mask(
@ -152,22 +157,13 @@ void MovingSliceState::onEnterState(Editor* editor)
clearSlices();
if (editor->slicesTransforms()) {
drawSliceContents();
drawSliceContents();
// Redraw the editor.
editor->invalidate();
}
// Redraw the editor.
editor->invalidate();
}
}
EditorState::LeaveAction MovingSliceState::onLeaveState(Editor *editor, EditorState *newState)
{
//editor->document()->resetTransformation();
return StandbyState::onLeaveState(editor, newState);
}
bool MovingSliceState::onMouseUp(Editor* editor, MouseMessage* msg)
{
{
@ -211,7 +207,6 @@ void MovingSliceState::stampExtraCelImage()
TiledMode::NONE, m_tx,
ExpandCelCanvas::None);
gfx::Point dstPt;
gfx::Size canvasImageSize = image->size();
if (m_site.tilemapMode() == TilemapMode::Tiles) {
@ -308,16 +303,12 @@ void MovingSliceState::drawExtraCel(const gfx::Rect& bounds, DrawExtraCelContent
if (m_site.tilemapMode() == TilemapMode::Tiles) {
dst->setMaskColor(doc::notile);
dst->clear(dst->maskColor());
/*
TODO: Fix this when the TilemapMode::Pixels mode works
if (m_site.cel()) {
doc::Grid grid = m_site.grid();
dst->copy(m_site.cel()->image(),
gfx::Clip(0, 0, grid.canvasToTile(bounds)));
//dst->copy(item.img.get(),
// gfx::Clip(0, 0, grid.canvasToTile(bounds)));
}
*/
if (m_site.cel()) {
doc::Grid grid = m_site.grid();
dst->copy(m_site.cel()->image(),
gfx::Clip(0, 0, grid.canvasToTile(bounds)));
}
}
else {
dst->setMaskColor(m_site.sprite()->transparentColor());
@ -345,13 +336,14 @@ void MovingSliceState::drawImage(doc::Image* dst,
if (!src) return;
if (m_site.tilemapMode() == TilemapMode::Tiles) {
/* TODO: Finish this when TilemapMode::Pixels works
drawTransformedTilemap(
transformation,
dst, m_originalImage.get(),
m_initialMask.get());
*/
gfx::Rect tilesBounds = m_site.grid().canvasToTile(bounds);
doc::algorithm::parallelogram(
dst, src, nullptr,
tilesBounds.x , tilesBounds.y,
tilesBounds.x+tilesBounds.w, tilesBounds.y,
tilesBounds.x+tilesBounds.w, tilesBounds.y+tilesBounds.h,
tilesBounds.x , tilesBounds.y+tilesBounds.h
);
}
else {
doc::algorithm::parallelogram(
@ -370,6 +362,11 @@ bool MovingSliceState::onMouseMove(Editor* editor, MouseMessage* msg)
gfx::Point delta = newCursorPos - m_mouseStart;
gfx::Rect totalBounds = selectedSlicesBounds();
// Move by tile size under Tiles mode.
if (editor->slicesTransforms() && m_site.tilemapMode() == TilemapMode::Tiles) {
delta = m_site.grid().tileToCanvas(m_site.grid().canvasToTile(delta));
}
ASSERT(totalBounds.w > 0);
ASSERT(totalBounds.h > 0);
@ -447,6 +444,11 @@ bool MovingSliceState::onMouseMove(Editor* editor, MouseMessage* msg)
}
}
// Align slice origin to tiles origin under Tiles mode.
if (editor->slicesTransforms() && m_site.tilemapMode() == TilemapMode::Tiles) {
rc.setOrigin(m_site.grid().tileToCanvas(m_site.grid().canvasToTile(rc.origin())));
}
if (m_hit.type() == EditorHit::SliceCenter)
key.setCenter(rc);
else

View File

@ -30,7 +30,6 @@ namespace app {
const doc::SelectedObjects& selectedSlices);
void onEnterState(Editor* editor) override;
LeaveAction onLeaveState(Editor *editor, EditorState *newState) override;
bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;

View File

@ -314,6 +314,25 @@ public:
}
};
class TilemapDelegate : public GenericDelegate<TilemapTraits> {
public:
TilemapDelegate(color_t mask_color) :
m_mask_color(mask_color) {
}
void putPixel(const Image* spr, int spr_x, int spr_y) {
ASSERT(m_it != m_end);
color_t c = get_pixel_fast<TilemapTraits>(spr, spr_x, spr_y);
if (c != m_mask_color)
*m_it = c;
}
private:
color_t m_mask_color;
};
/* _parallelogram_map:
* Worker routine for drawing rotated and/or scaled and/or flipped sprites:
* It actually maps the sprite to any parallelogram-shaped area of the
@ -773,6 +792,12 @@ static void ase_parallelogram_map_standard(
ase_parallelogram_map<BitmapTraits, BitmapDelegate>(bmp, sprite, mask, xs, ys, false, delegate);
break;
}
case IMAGE_TILEMAP: {
TilemapDelegate delegate(sprite->maskColor());
ase_parallelogram_map<TilemapTraits, TilemapDelegate>(bmp, sprite, mask, xs, ys, false, delegate);
break;
}
}
}