New eyedropper mode to pick colors from reference layers

This commit is contained in:
David Capello 2016-10-13 21:19:25 -03:00
parent 1b053de2f2
commit bc939d5638
9 changed files with 141 additions and 52 deletions

View File

@ -55,6 +55,7 @@
<enum id="EyedropperSample">
<value id="ALL_LAYERS" value="0" />
<value id="CURRENT_LAYER" value="1" />
<value id="FIRST_REFERENCE_LAYER" value="2" />
</enum>
<enum id="SelectionMode">
<value id="DEFAULT" value="0" />

View File

@ -23,6 +23,37 @@
namespace app {
namespace {
bool get_cel_pixel(const Cel* cel,
const double x,
const double y,
const frame_t frame,
color_t& output)
{
gfx::RectF celBounds;
if (cel->layer()->isReference())
celBounds = cel->boundsF();
else
celBounds = cel->bounds();
const doc::Image* image = cel->image();
gfx::PointF pos(x, y);
if (!celBounds.contains(pos))
return false;
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 false;
output = get_pixel(image, ipos.x, ipos.y);
return true;
}
}
ColorPicker::ColorPicker()
: m_alpha(0)
, m_layer(NULL)
@ -53,51 +84,64 @@ void ColorPicker::pickColor(const doc::Site& site,
}
// 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(), proj));
switch (mode) {
doc::CelList cels;
sprite->pickCels(pos.x, pos.y, site.frame(), 128, cels);
if (!cels.empty())
m_layer = cels.front()->layer();
}
else { // Pick from the current layer
const Cel* cel = site.cel();
if (cel) {
gfx::RectF celBounds;
if (cel->layer()->isReference())
celBounds = cel->boundsF();
else
celBounds = cel->bounds();
// Pick from the composed image
case FromComposition: {
m_color = app::Color::fromImage(
sprite->pixelFormat(),
render::get_sprite_pixel(sprite, pos.x, pos.y,
site.frame(), proj));
const doc::Image* image = cel->image();
doc::CelList cels;
sprite->pickCels(pos.x, pos.y, site.frame(), 128,
sprite->allVisibleLayers(), cels);
if (!cels.empty())
m_layer = cels.front()->layer();
break;
}
if (!celBounds.contains(pos))
return;
// Pick from the current layer
case FromActiveLayer: {
const Cel* cel = site.cel();
if (cel) {
doc::color_t imageColor;
if (!get_cel_pixel(cel, pos.x, pos.y,
site.frame(), imageColor))
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::Image* image = cel->image();
switch (image->pixelFormat()) {
case IMAGE_RGB:
m_alpha = doc::rgba_geta(imageColor);
break;
case IMAGE_GRAYSCALE:
m_alpha = doc::graya_geta(imageColor);
break;
}
const doc::color_t imageColor =
get_pixel(image, ipos.x, ipos.y);
switch (image->pixelFormat()) {
case IMAGE_RGB:
m_alpha = doc::rgba_geta(imageColor);
break;
case IMAGE_GRAYSCALE:
m_alpha = doc::graya_geta(imageColor);
break;
m_color = app::Color::fromImage(image->pixelFormat(), imageColor);
m_layer = const_cast<Layer*>(site.layer());
}
break;
}
m_color = app::Color::fromImage(image->pixelFormat(), imageColor);
m_layer = const_cast<Layer*>(site.layer());
case FromFirstReferenceLayer: {
doc::CelList cels;
sprite->pickCels(pos.x, pos.y, site.frame(), 128,
sprite->allVisibleReferenceLayers(), cels);
for (const Cel* cel : cels) {
doc::color_t imageColor;
if (get_cel_pixel(cel, pos.x, pos.y,
site.frame(), imageColor)) {
m_color = app::Color::fromImage(
cel->image()->pixelFormat(), imageColor);
m_layer = cel->layer();
break;
}
}
break;
}
}
}

View File

@ -24,7 +24,11 @@ namespace app {
class ColorPicker {
public:
enum Mode { FromComposition, FromActiveLayer };
enum Mode {
FromComposition,
FromActiveLayer,
FromFirstReferenceLayer
};
ColorPicker();

View File

@ -46,16 +46,21 @@ void EyedropperCommand::pickSample(const doc::Site& site,
{
// Check if we've to grab alpha channel or the merged color.
Preferences& pref = Preferences::instance();
bool allLayers =
(pref.eyedropper.sample() == app::gen::EyedropperSample::ALL_LAYERS);
ColorPicker::Mode mode = ColorPicker::FromComposition;
switch (pref.eyedropper.sample()) {
case app::gen::EyedropperSample::ALL_LAYERS:
mode = ColorPicker::FromComposition;
break;
case app::gen::EyedropperSample::CURRENT_LAYER:
mode = ColorPicker::FromActiveLayer;
break;
case app::gen::EyedropperSample::FIRST_REFERENCE_LAYER:
mode = ColorPicker::FromFirstReferenceLayer;
break;
}
ColorPicker picker;
picker.pickColor(site,
pixelPos,
proj,
(allLayers ?
ColorPicker::FromComposition:
ColorPicker::FromActiveLayer));
picker.pickColor(site, pixelPos, proj, mode);
app::gen::EyedropperChannel channel =
pref.eyedropper.channel();

View File

@ -1260,6 +1260,7 @@ public:
m_sample.addItem("All Layers");
m_sample.addItem("Current Layer");
m_sample.addItem("First Reference Layer");
addChild(new Label("Pick:"));
addChild(&m_channel);

View File

@ -391,6 +391,22 @@ void LayerGroup::allVisibleLayers(LayerList& list) const
}
}
void LayerGroup::allVisibleReferenceLayers(LayerList& list) const
{
for (Layer* child : m_layers) {
if (!child->isVisible())
continue;
if (child->isGroup())
static_cast<LayerGroup*>(child)->allVisibleReferenceLayers(list);
if (!child->isReference())
continue;
list.push_back(child);
}
}
void LayerGroup::allBrowsableLayers(LayerList& list) const
{
for (Layer* child : m_layers) {

View File

@ -192,6 +192,7 @@ namespace doc {
void allLayers(LayerList& list) const;
layer_t allLayersCount() const;
void allVisibleLayers(LayerList& list) const;
void allVisibleReferenceLayers(LayerList& list) const;
void allBrowsableLayers(LayerList& list) const;
void getCels(CelList& cels) const override;

View File

@ -449,13 +449,17 @@ void Sprite::remapImages(frame_t frameFrom, frame_t frameTo, const Remap& remap)
//////////////////////////////////////////////////////////////////////
// Drawing
void Sprite::pickCels(double x, double y, frame_t frame, int opacityThreshold, CelList& cels) const
void Sprite::pickCels(const double x,
const double y,
const frame_t frame,
const int opacityThreshold,
const LayerList& layers,
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];
const Layer* layer = layers[i];
if (!layer->isImage())
continue;
@ -463,7 +467,7 @@ void Sprite::pickCels(double x, double y, frame_t frame, int opacityThreshold, C
if (!cel)
continue;
Image* image = cel->image();
const Image* image = cel->image();
if (!image)
continue;
@ -522,6 +526,13 @@ LayerList Sprite::allVisibleLayers() const
return list;
}
LayerList Sprite::allVisibleReferenceLayers() const
{
LayerList list;
m_root->allVisibleReferenceLayers(list);
return list;
}
LayerList Sprite::allBrowsableLayers() const
{
LayerList list;

View File

@ -140,13 +140,19 @@ 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(double x, double y, frame_t frame, int opacityThreshold, CelList& cels) const;
void pickCels(const double x,
const double y,
const frame_t frame,
const int opacityThreshold,
const LayerList& layers,
CelList& cels) const;
////////////////////////////////////////
// Iterators
LayerList allLayers() const;
LayerList allVisibleLayers() const;
LayerList allVisibleReferenceLayers() const;
LayerList allBrowsableLayers() const;
CelsRange cels() const;