Fix eyedropper to pick colors/tiles correctly from flipped tiles

* Added a new app::Color type for tiles, to store the flags of the
  picked tile.
* Fixed color bar/status bar with a new draw_tile() to draw tiles
  with flip flags.
This commit is contained in:
David Capello 2023-07-27 13:29:13 -03:00
parent d3a8a10517
commit 3606a54826
9 changed files with 102 additions and 24 deletions

View File

@ -84,13 +84,21 @@ Color Color::fromGray(int g, int a)
// static
Color Color::fromIndex(int index)
{
ASSERT(index >= 0 || index == doc::notile);
ASSERT(index >= 0);
Color color(Color::IndexType);
color.m_value.index = index;
return color;
}
// static
Color Color::fromTile(doc::tile_t tile)
{
Color color(Color::TileType);
color.m_value.tile = tile;
return color;
}
// static
Color Color::fromImage(PixelFormat pixelFormat, color_t c)
{
@ -115,9 +123,12 @@ Color Color::fromImage(PixelFormat pixelFormat, color_t c)
break;
case IMAGE_INDEXED:
case IMAGE_TILEMAP:
color = Color::fromIndex(c);
break;
case IMAGE_TILEMAP:
color = Color::fromTile(c);
break;
}
return color;
@ -869,12 +880,28 @@ int Color::getIndex() const
case Color::IndexType:
return m_value.index;
case Color::TileType:
return doc::tile_geti(m_value.tile);
}
ASSERT(false);
return -1;
}
doc::tile_t Color::getTile() const
{
switch (getType()) {
case Color::TileType:
return m_value.tile;
}
ASSERT(false);
return doc::notile;
}
int Color::getAlpha() const
{
switch (getType()) {

View File

@ -11,6 +11,7 @@
#include "doc/color.h"
#include "doc/pixel_format.h"
#include "doc/tile.h"
#include <string>
@ -30,6 +31,7 @@ namespace app {
HslType,
GrayType,
IndexType,
TileType,
};
enum HumanReadableString {
@ -46,6 +48,7 @@ namespace app {
static Color fromHsl(double h, double s, double l, int a = 255); // h=[0,360], s=[0,1], v=[0,1]
static Color fromGray(int g, int a = 255);
static Color fromIndex(int index);
static Color fromTile(doc::tile_t tile);
static Color fromImage(doc::PixelFormat pixelFormat, doc::color_t c);
static Color fromImageGetPixel(doc::Image* image, int x, int y);
@ -79,6 +82,7 @@ namespace app {
double getHslLightness() const;
int getGray() const;
int getIndex() const;
doc::tile_t getTile() const;
int getAlpha() const;
// Setters
@ -107,6 +111,7 @@ namespace app {
int g, a;
} gray;
int index;
doc::tile_t tile;
} m_value;
};

View File

@ -63,10 +63,14 @@ bool get_cel_pixel(const Cel* cel,
if (!image->bounds().contains(tilePos))
return false;
const doc::tile_index ti =
const doc::tile_index t =
get_pixel(image, tilePos.x, tilePos.y);
PICKER_TRACE("PICKER: tile index=%d\n", ti);
// TODO take care of flip flags
const doc::tile_index ti = doc::tile_geti(t);
PICKER_TRACE("PICKER: tile=%d index=%d\n", t, ti);
doc::ImageRef tile = layerTilemap->tileset()->get(ti);
if (!tile)
@ -143,7 +147,7 @@ void ColorPicker::pickColor(const Site& site,
const gfx::Point tilePos = site.grid().canvasToTile(gfx::Point(pos));
if (cels.front()->image()->bounds().contains(tilePos)) {
m_tile = doc::get_pixel(cels.front()->image(), tilePos.x, tilePos.y);
m_color = app::Color::fromIndex(m_tile);
m_color = app::Color::fromTile(m_tile);
}
}
else if (site.tilemapMode() == TilemapMode::Pixels) {
@ -166,7 +170,7 @@ void ColorPicker::pickColor(const Site& site,
const gfx::Point tilePos = site.grid().canvasToTile(gfx::Point(pos));
if (cel->image()->bounds().contains(tilePos)) {
m_tile = doc::get_pixel(cel->image(), tilePos.x, tilePos.y);
m_color = app::Color::fromIndex(m_tile);
m_color = app::Color::fromTile(m_tile);
}
}
else if (site.tilemapMode() == TilemapMode::Pixels) {

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2018-2022 Igara Studio S.A.
// Copyright (C) 2018-2023 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -212,20 +212,22 @@ void draw_tile(ui::Graphics* g,
if (tile == doc::notile)
return;
doc::Tileset* ts = site.tileset();
const doc::Tileset* ts = site.tileset();
if (!ts)
return;
doc::tile_index ti = doc::tile_geti(tile);
const doc::tile_index ti = doc::tile_geti(tile);
if (ti < 0 || ti >= ts->size())
return;
doc::ImageRef tileImage = ts->get(ti);
const doc::ImageRef tileImage = ts->get(ti);
if (!tileImage)
return;
const int w = tileImage->width();
const int h = tileImage->height();
const doc::tile_index tf = doc::tile_getf(tile);
int w = tileImage->width();
int h = tileImage->height();
os::SurfaceRef surface = os::instance()->makeRgbaSurface(w, h);
convert_image_to_surface(tileImage.get(), get_current_palette(),
surface.get(), 0, 0, 0, 0, w, h);
@ -239,8 +241,41 @@ void draw_tile(ui::Graphics* g,
os::Sampling::Mipmap::Nearest);
}
g->drawSurface(surface.get(), gfx::Rect(0, 0, w, h), rc,
os::Sampling(), &paint);
gfx::Matrix m;
if (tf & doc::tile_f_dflip) {
gfx::Matrix rot;
rot.setRotate(90.0f);
rot.postConcat(gfx::Matrix::MakeScale(-1.0f, 1.0f));
m.preConcat(rot);
std::swap(w, h);
}
if (tf & doc::tile_f_xflip) {
gfx::Matrix flip;
flip.setScale(-1.0f, 1.0f, w/float(2.0f), 0.0f);
m.postConcat(flip);
}
if (tf & doc::tile_f_yflip) {
gfx::Matrix flip;
flip.setScale(1.0f, -1.0f, 0.0f, h/float(2.0f));
m.postConcat(flip);
}
m.postConcat(gfx::Matrix::MakeScale(float(rc.w) / w,
float(rc.h) / h));
// TODO integrate getInternalDeltaX/Y translation in ui::Graphics
m.postConcat(gfx::Matrix::MakeTrans(rc.x+g->getInternalDeltaX(),
rc.y+g->getInternalDeltaY()));
g->save();
g->setMatrix(m);
g->drawRgbaSurface(surface.get(),
-g->getInternalDeltaX(),
-g->getInternalDeltaY());
g->restore();
}
void draw_tile_button(ui::Graphics* g,

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019-2022 Igara Studio S.A.
// Copyright (C) 2019-2023 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of

View File

@ -856,8 +856,8 @@ tools::ToolLoop* create_tool_loop(
// Get fg/bg colors
ColorBar* colorbar = ColorBar::instance();
if (site.tilemapMode() == TilemapMode::Tiles) {
params.fg = app::Color::fromIndex(colorbar->getFgTile()); // TODO Color::fromTileIndex?
params.bg = app::Color::fromIndex(colorbar->getBgTile());
params.fg = app::Color::fromTile(colorbar->getFgTile());
params.bg = app::Color::fromTile(colorbar->getBgTile());
}
else {
params.fg = colorbar->getFgColor();
@ -1051,8 +1051,8 @@ tools::ToolLoop* create_tool_loop_preview(
// Get fg/bg colors
ColorBar* colorbar = ColorBar::instance();
if (site.tilemapMode() == TilemapMode::Tiles) {
params.fg = app::Color::fromIndex(colorbar->getFgTile()); // TODO Color::fromTileIndex?
params.bg = app::Color::fromIndex(colorbar->getBgTile());
params.fg = app::Color::fromTile(colorbar->getFgTile());
params.bg = app::Color::fromTile(colorbar->getBgTile());
}
else {
params.fg = colorbar->getFgColor();

View File

@ -472,6 +472,11 @@ public:
}
IndicatorsGeneration& add(const app::Color& color) {
// For Color::TileType, use the tile version
if (color.getType() == app::Color::TileType) {
return add(color.getTile());
}
auto theme = SkinTheme::get(m_indicators);
// Eyedropper icon

View File

@ -700,13 +700,14 @@ void Sprite::pickCels(const gfx::PointF& pos,
const Grid grid = cel->grid();
tile_t tile = notile;
gfx::Point tilePos = grid.canvasToTile(gfx::Point(pos));
const gfx::Point tilePos = grid.canvasToTile(gfx::Point(pos));
if (image->bounds().contains(tilePos.x, tilePos.y))
tile = image->getPixel(tilePos.x, tilePos.y);
if (tile == notile)
continue;
image = tileset->get(tile).get();
const tile_index ti = tile_geti(tile);
image = tileset->get(ti).get();
if (!image)
continue;

View File

@ -529,15 +529,16 @@ void composite_image_general_with_tile_flags(
int(std::ceil(area.dstBounds().w)),
int(std::ceil(area.dstBounds().h)));
gfx::Rect srcBounds = area.srcBounds();
const gfx::Rect srcImgBounds = src->bounds();
const gfx::Size srcMinSize = src->size();
dstBounds &= dst->bounds();
if (tileFlags & tile_f_xflip) {
srcBounds.x = src->bounds().x2()-srcBounds.w-srcBounds.x;
srcBounds.x = sx*srcImgBounds.x2() - srcBounds.x2();
}
if (tileFlags & tile_f_yflip) {
srcBounds.y = src->bounds().y2()-srcBounds.h-srcBounds.y;
srcBounds.y = sy*srcImgBounds.y2() - srcBounds.y2();
}
int dstY = dstBounds.y;
@ -558,7 +559,7 @@ void composite_image_general_with_tile_flags(
srcX = (srcBounds.x2()-1-x) / sx;
}
else {
srcX = srcBounds.x+x / sx;
srcX = (srcBounds.x+x) / sx;
}
if (tileFlags & tile_f_yflip) {
srcY = (srcBounds.y2()-1-y) / sy;