mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-21 21:41:02 +00:00
New eyedropper mode to pick colors from reference layers
This commit is contained in:
parent
1b053de2f2
commit
bc939d5638
@ -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" />
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,11 @@ namespace app {
|
||||
|
||||
class ColorPicker {
|
||||
public:
|
||||
enum Mode { FromComposition, FromActiveLayer };
|
||||
enum Mode {
|
||||
FromComposition,
|
||||
FromActiveLayer,
|
||||
FromFirstReferenceLayer
|
||||
};
|
||||
|
||||
ColorPicker();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user