diff --git a/src/app/commands/filters/filter_manager_impl.cpp b/src/app/commands/filters/filter_manager_impl.cpp index 5db826cc7..f7a9a69ed 100644 --- a/src/app/commands/filters/filter_manager_impl.cpp +++ b/src/app/commands/filters/filter_manager_impl.cpp @@ -12,11 +12,13 @@ #include "app/cmd/copy_region.h" #include "app/cmd/patch_cel.h" +#include "app/cmd/set_palette.h" #include "app/cmd/unlink_cel.h" #include "app/context_access.h" #include "app/document.h" #include "app/ini_file.h" #include "app/modules/editors.h" +#include "app/modules/palettes.h" #include "app/transaction.h" #include "app/ui/editor/editor.h" #include "doc/algorithm/shrink_bounds.h" @@ -50,6 +52,7 @@ FilterManagerImpl::FilterManagerImpl(Context* context, Filter* filter) , m_dst(nullptr) , m_mask(nullptr) , m_previewMask(nullptr) + , m_oldPalette(nullptr) , m_progressDelegate(NULL) { m_row = 0; @@ -64,6 +67,14 @@ FilterManagerImpl::FilterManagerImpl(Context* context, Filter* filter) init(m_site.cel()); } +FilterManagerImpl::~FilterManagerImpl() +{ + if (m_oldPalette) { + restoreSpritePalette(); + set_current_palette(m_oldPalette.get(), false); + } +} + app::Document* FilterManagerImpl::document() { return static_cast(m_site.document()); @@ -211,6 +222,7 @@ void FilterManagerImpl::apply(Transaction& transaction) void FilterManagerImpl::applyToTarget() { + const bool paletteChange = paletteHasChanged(); bool cancelled = false; ImagesCollector images((m_target & TARGET_ALL_LAYERS ? @@ -219,7 +231,7 @@ void FilterManagerImpl::applyToTarget() m_site.frame(), (m_target & TARGET_ALL_FRAMES) == TARGET_ALL_FRAMES, true); // we will write in each image - if (images.empty()) + if (images.empty() && !paletteChange) return; // Initialize writting operation @@ -232,6 +244,15 @@ void FilterManagerImpl::applyToTarget() std::set visited; + // Palette change + if (paletteChange) { + Palette newPalette = *getNewPalette(); + restoreSpritePalette(); + transaction.execute( + new cmd::SetPalette(m_site.sprite(), + m_site.frame(), &newPalette)); + } + // For each target image for (auto it = images.begin(); it != images.end() && !cancelled; @@ -253,6 +274,9 @@ void FilterManagerImpl::applyToTarget() } transaction.commit(); + + // Reset m_oldPalette to avoid restoring the color palette + m_oldPalette.reset(nullptr); } void FilterManagerImpl::flush() @@ -262,6 +286,12 @@ void FilterManagerImpl::flush() if (m_row >= 0 && h > 0) { Editor* editor = current_editor; + // Redraw the color palette + if (m_nextRowToFlush == 0 && paletteHasChanged()) { + set_current_palette(getNewPalette(), false); + ColorBar::instance()->invalidate(); + } + // We expand the region one pixel at the top and bottom of the // region [m_row,m_nextRowToFlush) to be updated on the screen to // avoid screen artifacts when we apply filters like convolution @@ -310,16 +340,26 @@ bool FilterManagerImpl::skipPixel() return skip; } -Palette* FilterManagerImpl::getPalette() +const Palette* FilterManagerImpl::getPalette() const { - return m_site.sprite()->palette(m_site.frame()); + if (m_oldPalette) + return m_oldPalette.get(); + else + return m_site.sprite()->palette(m_site.frame()); } -RgbMap* FilterManagerImpl::getRgbMap() +const RgbMap* FilterManagerImpl::getRgbMap() const { return m_site.sprite()->rgbMap(m_site.frame()); } +Palette* FilterManagerImpl::getNewPalette() +{ + if (!m_oldPalette) + m_oldPalette.reset(new Palette(*getPalette())); + return m_site.sprite()->palette(m_site.frame()); +} + void FilterManagerImpl::init(Cel* cel) { ASSERT(cel); @@ -364,4 +404,18 @@ bool FilterManagerImpl::updateBounds(doc::Mask* mask) return !m_bounds.isEmpty(); } +bool FilterManagerImpl::paletteHasChanged() +{ + return + (m_oldPalette && + getPalette()->countDiff(getNewPalette(), nullptr, nullptr)); +} + +void FilterManagerImpl::restoreSpritePalette() +{ + // Restore the original palette to save the undoable "cmd" + if (m_oldPalette) + m_site.sprite()->setPalette(m_oldPalette.get(), false); +} + } // namespace app diff --git a/src/app/commands/filters/filter_manager_impl.h b/src/app/commands/filters/filter_manager_impl.h index aeab3e2c9..d0ea79a64 100644 --- a/src/app/commands/filters/filter_manager_impl.h +++ b/src/app/commands/filters/filter_manager_impl.h @@ -69,6 +69,7 @@ namespace app { }; FilterManagerImpl(Context* context, Filter* filter); + ~FilterManagerImpl(); void setProgressDelegate(IProgressDelegate* progressDelegate); @@ -100,18 +101,22 @@ namespace app { FilterIndexedData* getIndexedData() override { return this; } bool skipPixel() override; const doc::Image* getSourceImage() override { return m_src.get(); } - int x() override { return m_bounds.x; } - int y() override { return m_bounds.y+m_row; } + int x() const override { return m_bounds.x; } + int y() const override { return m_bounds.y+m_row; } + bool isFirstRow() const override { return m_row == 0; } // FilterIndexedData implementation - doc::Palette* getPalette() override; - doc::RgbMap* getRgbMap() override; + const doc::Palette* getPalette() const override; + const doc::RgbMap* getRgbMap() const override; + doc::Palette* getNewPalette() override; private: void init(doc::Cel* cel); void apply(Transaction& transaction); void applyToCel(Transaction& transaction, doc::Cel* cel); bool updateBounds(doc::Mask* mask); + bool paletteHasChanged(); + void restoreSpritePalette(); Context* m_context; doc::Site m_site; @@ -128,6 +133,7 @@ namespace app { doc::ImageBits::iterator m_maskIterator; Target m_targetOrig; // Original targets Target m_target; // Filtered targets + base::UniquePtr m_oldPalette; // Hooks float m_progressBase; diff --git a/src/filters/filter_indexed_data.h b/src/filters/filter_indexed_data.h index 239f20158..ead64184d 100644 --- a/src/filters/filter_indexed_data.h +++ b/src/filters/filter_indexed_data.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2017 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -20,8 +20,12 @@ namespace filters { class FilterIndexedData { public: virtual ~FilterIndexedData() { } - virtual doc::Palette* getPalette() = 0; - virtual doc::RgbMap* getRgbMap() = 0; + virtual const doc::Palette* getPalette() const = 0; + virtual const doc::RgbMap* getRgbMap() const = 0; + + // If a filter ask for a new palette, it means that the filter + // will modify the palette instead of pixels. + virtual doc::Palette* getNewPalette() = 0; }; } // namespace filters diff --git a/src/filters/filter_manager.h b/src/filters/filter_manager.h index ccf085eac..13e1c4d85 100644 --- a/src/filters/filter_manager.h +++ b/src/filters/filter_manager.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2017 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -64,10 +64,14 @@ namespace filters { virtual const doc::Image* getSourceImage() = 0; // Returns the first X coordinate of the row to apply the filter. - virtual int x() = 0; + virtual int x() const = 0; // Returns the Y coordinate of the row. - virtual int y() = 0; + virtual int y() const = 0; + + // Returns true if this is the first row. Useful to apply a filter + // to the palette in the first row. + virtual bool isFirstRow() const = 0; }; diff --git a/src/filters/hue_saturation_filter.cpp b/src/filters/hue_saturation_filter.cpp index f626649d2..89276d554 100644 --- a/src/filters/hue_saturation_filter.cpp +++ b/src/filters/hue_saturation_filter.cpp @@ -61,8 +61,8 @@ void HueSaturationFilter::applyToRgba(FilterManager* filterMgr) { const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress(); uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); - int w = filterMgr->getWidth(); - Target target = filterMgr->getTarget(); + const int w = filterMgr->getWidth(); + const Target target = filterMgr->getTarget(); int x, c, r, g, b, a; for (x=0; xgetSourceAddress(); uint16_t* dst_address = (uint16_t*)filterMgr->getDestinationAddress(); - int w = filterMgr->getWidth(); - Target target = filterMgr->getTarget(); + const int w = filterMgr->getWidth(); + const Target target = filterMgr->getTarget(); int x, c, k, a; for (x=0; xgetSourceAddress(); - uint8_t* dst_address = (uint8_t*)filterMgr->getDestinationAddress(); + if (!filterMgr->isFirstRow()) + return; + const Palette* pal = filterMgr->getIndexedData()->getPalette(); - const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap(); - int w = filterMgr->getWidth(); - Target target = filterMgr->getTarget(); - int x, c, r, g, b, a; + const Target target = filterMgr->getTarget(); + Palette* newPal = filterMgr->getIndexedData()->getNewPalette(); - for (x=0; xskipPixel()) { - ++src_address; - ++dst_address; - continue; - } - - c = *(src_address++); - c = pal->getEntry(c); - r = rgba_getr(c); - g = rgba_getg(c); - b = rgba_getb(c); - a = rgba_geta(c); + for (int i=0; isize(); ++i) { + color_t c = pal->getEntry(i); + int r = rgba_getr(c); + int g = rgba_getg(c); + int b = rgba_getb(c); + int a = rgba_geta(c); { gfx::Hsl hsl(gfx::Rgb(r, g, b)); @@ -194,13 +186,17 @@ void HueSaturationFilter::applyToIndexed(FilterManager* filterMgr) if (target & TARGET_RED_CHANNEL ) r = rgb.red(); if (target & TARGET_GREEN_CHANNEL) g = rgb.green(); if (target & TARGET_BLUE_CHANNEL ) b = rgb.blue(); - if (a && (target & TARGET_ALPHA_CHANNEL)) a = MID(0, a+m_a, 255); + + if (target & (TARGET_RED_CHANNEL | + TARGET_GREEN_CHANNEL | + TARGET_BLUE_CHANNEL | + TARGET_ALPHA_CHANNEL)) + c = rgba(r, g, b, a); } - c = rgbmap->mapColor(r, g, b, a); - *(dst_address++) = c; + newPal->setEntry(i, c); } }