Fix eyedropper/move tool for reference layers

This commit is contained in:
David Capello 2016-10-13 19:58:42 -03:00
parent bf4d6f1e4e
commit 1b053de2f2
14 changed files with 131 additions and 48 deletions

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -30,10 +30,12 @@ ColorPicker::ColorPicker()
}
void ColorPicker::pickColor(const doc::Site& site,
const gfx::Point& _pos, Mode mode)
const gfx::PointF& _pos,
const render::Projection& proj,
const Mode mode)
{
const doc::Sprite* sprite = site.sprite();
gfx::Point pos = _pos;
gfx::PointF pos = _pos;
m_alpha = 255;
m_color = app::Color::fromMask();
@ -44,17 +46,18 @@ void ColorPicker::pickColor(const doc::Site& site,
DocumentPreferences& docPref = Preferences::instance().document(doc);
if (int(docPref.tiled.mode()) & int(filters::TiledMode::X_AXIS))
pos.x = wrap_value(pos.x, site.sprite()->width());
pos.x = wrap_value<double>(pos.x, site.sprite()->width());
if (int(docPref.tiled.mode()) & int(filters::TiledMode::Y_AXIS))
pos.y = wrap_value(pos.y, site.sprite()->height());
pos.y = wrap_value<double>(pos.y, site.sprite()->height());
}
// Get the color from the image
if (mode == FromComposition) { // Pick from the composed image
m_color = app::Color::fromImage(
sprite->pixelFormat(),
render::get_sprite_pixel(sprite, pos.x, pos.y, site.frame()));
render::get_sprite_pixel(sprite, pos.x, pos.y,
site.frame(), proj));
doc::CelList cels;
sprite->pickCels(pos.x, pos.y, site.frame(), 128, cels);
@ -62,12 +65,27 @@ void ColorPicker::pickColor(const doc::Site& site,
m_layer = cels.front()->layer();
}
else { // Pick from the current layer
int u, v;
doc::Image* image = site.image(&u, &v, NULL);
gfx::Point pt(pos.x-u, pos.y-v);
const Cel* cel = site.cel();
if (cel) {
gfx::RectF celBounds;
if (cel->layer()->isReference())
celBounds = cel->boundsF();
else
celBounds = cel->bounds();
if (image && image->bounds().contains(pt)) {
doc::color_t imageColor = get_pixel(image, pt.x, pt.y);
const doc::Image* image = cel->image();
if (!celBounds.contains(pos))
return;
pos.x = (pos.x-celBounds.x)*image->width()/celBounds.w;
pos.y = (pos.y-celBounds.y)*image->height()/celBounds.h;
const gfx::Point ipos(pos);
if (!image->bounds().contains(ipos))
return;
const doc::color_t imageColor =
get_pixel(image, ipos.x, ipos.y);
switch (image->pixelFormat()) {
case IMAGE_RGB:

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -16,6 +16,10 @@ namespace doc {
class Site;
}
namespace render {
class Projection;
}
namespace app {
class ColorPicker {
@ -25,7 +29,9 @@ namespace app {
ColorPicker();
void pickColor(const doc::Site& site,
const gfx::Point& pos, Mode mode);
const gfx::PointF& pos,
const render::Projection& proj,
const Mode mode);
app::Color color() const { return m_color; }
int alpha() const { return m_alpha; }

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -40,7 +40,8 @@ EyedropperCommand::EyedropperCommand()
}
void EyedropperCommand::pickSample(const doc::Site& site,
const gfx::Point& pixelPos,
const gfx::PointF& pixelPos,
const render::Projection& proj,
app::Color& color)
{
// Check if we've to grab alpha channel or the merged color.
@ -51,6 +52,7 @@ void EyedropperCommand::pickSample(const doc::Site& site,
ColorPicker picker;
picker.pickColor(site,
pixelPos,
proj,
(allLayers ?
ColorPicker::FromComposition:
ColorPicker::FromActiveLayer));
@ -171,7 +173,7 @@ void EyedropperCommand::onExecute(Context* context)
}
// Pixel position to get
gfx::Point pixelPos = editor->screenToEditor(ui::get_mouse_position());
gfx::PointF pixelPos = editor->screenToEditorF(ui::get_mouse_position());
// Start with fg/bg color
Preferences& pref = Preferences::instance();
@ -179,7 +181,10 @@ void EyedropperCommand::onExecute(Context* context)
m_background ? pref.colorBar.bgColor():
pref.colorBar.fgColor();
pickSample(editor->getSite(), pixelPos, color);
pickSample(editor->getSite(),
pixelPos,
editor->projection(),
color);
if (m_background)
pref.colorBar.bgColor(color);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -15,6 +15,10 @@ namespace doc {
class Site;
}
namespace render {
class Projection;
}
namespace app {
class EyedropperCommand : public Command {
@ -24,7 +28,8 @@ namespace app {
// Returns the color in the given sprite pos.
void pickSample(const doc::Site& site,
const gfx::Point& pixelPos,
const gfx::PointF& pixelPos,
const render::Projection& proj,
app::Color& color);
protected:

View File

@ -14,9 +14,11 @@
#include "app/color_utils.h"
#include "app/commands/command.h"
#include "app/context_access.h"
#include "app/modules/editors.h"
#include "app/modules/gui.h"
#include "app/tools/tool_box.h"
#include "app/transaction.h"
#include "app/ui/editor/editor.h"
#include "app/ui/toolbar.h"
#include "doc/algorithm/shrink_bounds.h"
#include "doc/cel.h"
@ -64,7 +66,10 @@ void MaskContentCommand::onExecute(Context* context)
gfx::Color color;
if (writer.layer()->isBackground()) {
ColorPicker picker;
picker.pickColor(*writer.site(), gfx::Point(0, 0), ColorPicker::FromComposition);
picker.pickColor(*writer.site(),
gfx::PointF(0.0, 0.0),
current_editor->projection(),
ColorPicker::FromComposition);
color = color_utils::color_for_layer(picker.color(), writer.layer());
}
else

View File

@ -1232,10 +1232,11 @@ app::Color Editor::getColorByPosition(const gfx::Point& mousePos)
{
Site site = getSite();
if (site.sprite()) {
gfx::Point editorPos = screenToEditor(mousePos);
gfx::PointF editorPos = screenToEditorF(mousePos);
ColorPicker picker;
picker.pickColor(site, editorPos, ColorPicker::FromComposition);
picker.pickColor(site, editorPos, m_proj,
ColorPicker::FromComposition);
return picker.color();
}
else

View File

@ -178,10 +178,11 @@ bool StandbyState::onMouseDown(Editor* editor, MouseMessage* msg)
if (clickedInk->isCelMovement()) {
// Handle "Auto Select Layer"
if (editor->isAutoSelectLayer()) {
gfx::Point cursor = editor->screenToEditor(msg->position());
gfx::PointF cursor = editor->screenToEditorF(msg->position());
ColorPicker picker;
picker.pickColor(site, cursor, ColorPicker::FromComposition);
picker.pickColor(site, cursor,
editor->projection(),
ColorPicker::FromComposition);
auto range = App::instance()->timeline()->range();
@ -447,7 +448,7 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
{
tools::Ink* ink = editor->getCurrentEditorInk();
const Sprite* sprite = editor->sprite();
gfx::Point spritePos = editor->screenToEditor(ui::get_mouse_position());
gfx::PointF spritePos = editor->screenToEditorF(ui::get_mouse_position());
if (!sprite) {
StatusBar::instance()->clearText();
@ -456,10 +457,15 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
else if (ink->isEyedropper()) {
EyedropperCommand cmd;
app::Color color = Preferences::instance().colorBar.fgColor();
cmd.pickSample(editor->getSite(), spritePos, color);
cmd.pickSample(editor->getSite(),
spritePos,
editor->projection(),
color);
char buf[256];
sprintf(buf, " :pos: %d %d", spritePos.x, spritePos.y);
sprintf(buf, " :pos: %d %d",
int(spritePos.x),
int(spritePos.y));
StatusBar::instance()->showColor(0, buf, color);
}
@ -471,7 +477,8 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
char buf[1024];
sprintf(
buf, ":pos: %d %d :%s: %d %d",
spritePos.x, spritePos.y,
int(spritePos.x),
int(spritePos.y),
(mask ? "selsize": "size"),
(mask ? mask->bounds().w: sprite->width()),
(mask ? mask->bounds().h: sprite->height()));
@ -485,8 +492,8 @@ bool StandbyState::onUpdateStatusBar(Editor* editor)
if (editor->docPref().show.grid()) {
auto gb = editor->docPref().grid.bounds();
int col = (spritePos.x - (gb.x % gb.w)) / gb.w;
int row = (spritePos.y - (gb.y % gb.h)) / gb.h;
int col = (int(spritePos.x) - (gb.x % gb.w)) / gb.w;
int row = (int(spritePos.y) - (gb.y % gb.h)) / gb.h;
sprintf(
buf+std::strlen(buf), " :grid: %d %d", col, row);
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -8,6 +8,8 @@
#define APP_WRAP_VALUE_H_INCLUDED
#pragma once
#include <cmath>
namespace app {
template<typename T>
@ -18,6 +20,14 @@ namespace app {
return x % size;
}
template<>
inline double wrap_value(const double x, const double size) {
if (x < 0.0)
return size - std::fmod(-(x+1.0), size) - 1.0;
else
return std::fmod(x, size);
}
} // namespace app
#endif

View File

@ -449,9 +449,10 @@ void Sprite::remapImages(frame_t frameFrom, frame_t frameTo, const Remap& remap)
//////////////////////////////////////////////////////////////////////
// Drawing
void Sprite::pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList& cels) const
void Sprite::pickCels(double x, double y, frame_t frame, int opacityThreshold, CelList& cels) const
{
LayerList layers = allVisibleLayers();
gfx::PointF pos(x, y);
for (int i=(int)layers.size()-1; i>=0; --i) {
Layer* layer = layers[i];
@ -466,13 +467,22 @@ void Sprite::pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList
if (!image)
continue;
if (!cel->bounds().contains(gfx::Point(x, y)))
gfx::RectF celBounds;
if (cel->layer()->isReference())
celBounds = cel->boundsF();
else
celBounds = cel->bounds();
if (!celBounds.contains(pos))
continue;
color_t color = get_pixel(image,
x - cel->x(),
y - cel->y());
const gfx::Point ipos(
(pos.x-celBounds.x)*image->width()/celBounds.w,
(pos.y-celBounds.y)*image->height()/celBounds.h);
if (!image->bounds().contains(ipos))
continue;
const color_t color = get_pixel(image, ipos.x, ipos.y);
bool isOpaque = true;
switch (image->pixelFormat()) {

View File

@ -140,7 +140,7 @@ namespace doc {
void replaceImage(ObjectId curImageId, const ImageRef& newImage);
void getImages(std::vector<Image*>& images) const;
void remapImages(frame_t frameFrom, frame_t frameTo, const Remap& remap);
void pickCels(int x, int y, frame_t frame, int opacityThreshold, CelList& cels) const;
void pickCels(double x, double y, frame_t frame, int opacityThreshold, CelList& cels) const;
////////////////////////////////////////
// Iterators

View File

@ -1,5 +1,5 @@
// Aseprite Render Library
// Copyright (c) 2001-2014 David Capello
// Copyright (c) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -16,15 +16,25 @@ namespace render {
using namespace doc;
color_t get_sprite_pixel(const Sprite* sprite, int x, int y, frame_t frame)
color_t get_sprite_pixel(const Sprite* sprite,
const double x,
const double y,
const frame_t frame,
const Projection& proj)
{
color_t color = 0;
if ((x >= 0) && (y >= 0) && (x < sprite->width()) && (y < sprite->height())) {
if ((x >= 0.0) && (x < sprite->width()) &&
(y >= 0.0) && (y < sprite->height())) {
base::UniquePtr<Image> image(Image::create(sprite->pixelFormat(), 1, 1));
render::Render().renderSprite(image, sprite, frame,
gfx::Clip(0, 0, x, y, 1, 1));
render::Render render;
render.setProjection(proj);
render.renderSprite(
image, sprite, frame,
gfx::ClipF(0, 0,
proj.applyX(x),
proj.applyY(y), 1, 1));
color = get_pixel(image, 0, 0);
}

View File

@ -1,5 +1,5 @@
// Aseprite Render Library
// Copyright (c) 2001-2014 David Capello
// Copyright (c) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -17,10 +17,16 @@ namespace doc {
namespace render {
using namespace doc;
class Projection;
// Gets a pixel from the sprite in the specified position. If in the
// specified coordinates there're background this routine will
// return the 0 color (the mask-color).
color_t get_sprite_pixel(const Sprite* sprite, int x, int y, frame_t frame);
color_t get_sprite_pixel(const Sprite* sprite,
const double x,
const double y,
const frame_t frame,
const Projection& proj);
} // namespace render

View File

@ -576,7 +576,7 @@ void Render::renderSprite(
{
renderSprite(
dstImage, sprite, frame,
gfx::Clip(sprite->bounds()));
gfx::ClipF(sprite->bounds()));
}
void Render::renderLayer(
@ -615,7 +615,7 @@ void Render::renderSprite(
Image* dstImage,
const Sprite* sprite,
frame_t frame,
const gfx::Clip& area)
const gfx::ClipF& area)
{
m_sprite = sprite;

View File

@ -155,7 +155,7 @@ namespace render {
Image* dstImage,
const Sprite* sprite,
frame_t frame,
const gfx::Clip& area);
const gfx::ClipF& area);
// Extra functions
void renderBackground(