mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-04 05:50:15 +00:00
Add ‘color fit criteria’ implementation on Sprite > Color Mode > More Options
This commit is contained in:
parent
d730479e80
commit
8a17be1d11
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -73,7 +73,8 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
|
||||
const render::Dithering& dithering,
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate)
|
||||
render::TaskDelegate* delegate,
|
||||
const FitCriteria fitCriteria)
|
||||
: WithSprite(sprite)
|
||||
, m_oldFormat(sprite->pixelFormat())
|
||||
, m_newFormat(newFormat)
|
||||
@ -108,7 +109,8 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
|
||||
cel->layer()->isBackground(),
|
||||
mapAlgorithm,
|
||||
toGray,
|
||||
&superDel);
|
||||
&superDel,
|
||||
fitCriteria);
|
||||
|
||||
superDel.nextImage();
|
||||
}
|
||||
@ -208,7 +210,8 @@ void SetPixelFormat::convertImage(doc::Sprite* sprite,
|
||||
const bool isBackground,
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate)
|
||||
render::TaskDelegate* delegate,
|
||||
const doc::FitCriteria fitCriteria)
|
||||
{
|
||||
ASSERT(oldImage);
|
||||
ASSERT(oldImage->pixelFormat() != IMAGE_TILEMAP);
|
||||
@ -218,7 +221,10 @@ void SetPixelFormat::convertImage(doc::Sprite* sprite,
|
||||
RgbMap* rgbmap;
|
||||
int newMaskIndex = (isBackground ? -1 : 0);
|
||||
if (m_newFormat == IMAGE_INDEXED) {
|
||||
rgbmap = sprite->rgbMap(frame, sprite->rgbMapForSprite(), mapAlgorithm);
|
||||
rgbmap = sprite->rgbMap(frame,
|
||||
sprite->rgbMapForSprite(),
|
||||
mapAlgorithm,
|
||||
fitCriteria);
|
||||
if (m_oldFormat == IMAGE_INDEXED)
|
||||
newMaskIndex = sprite->transparentColor();
|
||||
else
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2017 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -12,6 +12,7 @@
|
||||
#include "app/cmd/with_sprite.h"
|
||||
#include "app/cmd_sequence.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/fit_criteria.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/image_ref.h"
|
||||
#include "doc/pixel_format.h"
|
||||
@ -37,7 +38,8 @@ namespace cmd {
|
||||
const render::Dithering& dithering,
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate);
|
||||
render::TaskDelegate* delegate,
|
||||
const doc::FitCriteria fitCriteria = doc::FitCriteria::DEFAULT);
|
||||
|
||||
protected:
|
||||
void onExecute() override;
|
||||
@ -56,7 +58,8 @@ namespace cmd {
|
||||
const bool isBackground,
|
||||
const doc::RgbMapAlgorithm mapAlgorithm,
|
||||
doc::rgba_to_graya_func toGray,
|
||||
render::TaskDelegate* delegate);
|
||||
render::TaskDelegate* delegate,
|
||||
const doc::FitCriteria fitCriteria = doc::FitCriteria::DEFAULT);
|
||||
|
||||
doc::PixelFormat m_oldFormat;
|
||||
doc::PixelFormat m_newFormat;
|
||||
|
@ -70,7 +70,6 @@ public:
|
||||
const doc::frame_t frame,
|
||||
const doc::PixelFormat pixelFormat,
|
||||
const render::Dithering& dithering,
|
||||
const doc::RgbMapAlgorithm rgbMapAlgorithm,
|
||||
const gen::ToGrayAlgorithm toGray,
|
||||
const gfx::Point& pos,
|
||||
const bool newBlend)
|
||||
@ -84,13 +83,11 @@ public:
|
||||
sprite, frame,
|
||||
pixelFormat,
|
||||
dithering,
|
||||
rgbMapAlgorithm,
|
||||
toGray,
|
||||
newBlend]() { // Copy the matrix
|
||||
run(sprite, frame,
|
||||
pixelFormat,
|
||||
dithering,
|
||||
rgbMapAlgorithm,
|
||||
toGray,
|
||||
newBlend);
|
||||
})
|
||||
@ -115,7 +112,6 @@ private:
|
||||
const doc::frame_t frame,
|
||||
const doc::PixelFormat pixelFormat,
|
||||
const render::Dithering& dithering,
|
||||
const doc::RgbMapAlgorithm rgbMapAlgorithm,
|
||||
const gen::ToGrayAlgorithm toGray,
|
||||
const bool newBlend) {
|
||||
doc::ImageRef tmp(
|
||||
@ -137,9 +133,7 @@ private:
|
||||
m_image.get(),
|
||||
pixelFormat,
|
||||
dithering,
|
||||
sprite->rgbMap(frame,
|
||||
sprite->rgbMapForSprite(),
|
||||
rgbMapAlgorithm),
|
||||
sprite->rgbMap(frame),
|
||||
sprite->palette(frame),
|
||||
(sprite->backgroundLayer() != nullptr),
|
||||
0,
|
||||
@ -251,6 +245,7 @@ public:
|
||||
// Signals
|
||||
m_ditheringSelector->Change.connect([this]{ onIndexParamChange(); });
|
||||
m_mapAlgorithmSelector->Change.connect([this]{ onIndexParamChange(); });
|
||||
m_bestFitCriteriaSelector->Change.connect([this]{ onIndexParamChange(); });
|
||||
factor()->Change.connect([this]{ onIndexParamChange(); });
|
||||
|
||||
advancedCheck()->Click.connect(
|
||||
@ -414,6 +409,12 @@ private:
|
||||
visibleBounds.origin(),
|
||||
doc::BlendMode::SRC);
|
||||
|
||||
m_editor->sprite()->rgbMap(
|
||||
0,
|
||||
m_editor->sprite()->rgbMapForSprite(),
|
||||
rgbMapAlgorithm(),
|
||||
fitCriteria());
|
||||
|
||||
m_editor->invalidate();
|
||||
progress()->setValue(0);
|
||||
progress()->setVisible(false);
|
||||
@ -426,7 +427,6 @@ private:
|
||||
m_editor->frame(),
|
||||
dstPixelFormat,
|
||||
dithering(),
|
||||
rgbMapAlgorithm(),
|
||||
toGray(),
|
||||
visibleBounds.origin(),
|
||||
Preferences::instance().experimental.newBlend()));
|
||||
@ -505,7 +505,7 @@ private:
|
||||
doc::PixelFormat m_format;
|
||||
render::Dithering m_dithering;
|
||||
doc::RgbMapAlgorithm m_rgbmap;
|
||||
doc::FitCriteria m_fitCriteria;
|
||||
doc::FitCriteria m_fitCriteria = FitCriteria::DEFAULT;
|
||||
gen::ToGrayAlgorithm m_toGray;
|
||||
};
|
||||
|
||||
@ -697,7 +697,8 @@ void ChangePixelFormatCommand::onExecute(Context* context)
|
||||
m_dithering,
|
||||
m_rgbmap,
|
||||
get_gray_func(m_toGray),
|
||||
&job)); // SpriteJob is a render::TaskDelegate
|
||||
&job,
|
||||
m_fitCriteria)); // SpriteJob is a render::TaskDelegate
|
||||
});
|
||||
job.waitJob();
|
||||
}
|
||||
|
@ -274,7 +274,9 @@ int OctreeMap::mapColor(color_t rgba) const
|
||||
this);
|
||||
}
|
||||
|
||||
void OctreeMap::regenerateMap(const Palette* palette, const int maskIndex)
|
||||
void OctreeMap::regenerateMap(const Palette* palette,
|
||||
const int maskIndex,
|
||||
const FitCriteria fitCriteria)
|
||||
{
|
||||
ASSERT(palette);
|
||||
if (!palette)
|
||||
@ -283,10 +285,12 @@ void OctreeMap::regenerateMap(const Palette* palette, const int maskIndex)
|
||||
// Skip useless regenerations
|
||||
if (m_palette == palette &&
|
||||
m_modifications == palette->getModifications() &&
|
||||
m_maskIndex == maskIndex)
|
||||
m_maskIndex == maskIndex &&
|
||||
m_fitCriteria == fitCriteria)
|
||||
return;
|
||||
|
||||
m_palette = palette;
|
||||
m_fitCriteria = fitCriteria;
|
||||
m_root = OctreeNode();
|
||||
m_leavesVector.clear();
|
||||
m_maskIndex = maskIndex;
|
||||
|
@ -141,12 +141,21 @@ public:
|
||||
const int levelDeep = 7);
|
||||
|
||||
// RgbMap impl
|
||||
void regenerateMap(const Palette* palette, const int maskIndex) override;
|
||||
void regenerateMap(const Palette* palette,
|
||||
const int maskIndex,
|
||||
const FitCriteria fitCriteria) override;
|
||||
void regenerateMap(const Palette* palette,
|
||||
const int maskIndex) override
|
||||
{
|
||||
regenerateMap(palette, maskIndex, m_fitCriteria);
|
||||
};
|
||||
|
||||
int mapColor(color_t rgba) const override;
|
||||
int maskIndex() const override { return m_maskIndex; }
|
||||
int modifications() const override { return m_modifications; };
|
||||
FitCriteria fitCriteria() const override { return m_fitCriteria; }
|
||||
void fitCriteria(const FitCriteria fitCriteria) override { m_fitCriteria = fitCriteria; }
|
||||
void fitCriteria(const FitCriteria fitCriteria) override { m_fitCriteria == fitCriteria; }
|
||||
RgbMapAlgorithm rgbamapAlgorithm() const override { return RgbMapAlgorithm::OCTREE; }
|
||||
|
||||
int mapColor(const int r, const int g,
|
||||
const int b, const int a) const
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "base/debug.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/fit_criteria.h"
|
||||
#include "doc/rgbmap_algorithm.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
@ -21,13 +22,20 @@ namespace doc {
|
||||
public:
|
||||
virtual ~RgbMap() { }
|
||||
|
||||
virtual void regenerateMap(const Palette* palette, const int maskIndex) = 0;
|
||||
virtual void regenerateMap(const Palette* palette,
|
||||
const int maskIndex,
|
||||
const FitCriteria fitCriteria) = 0;
|
||||
|
||||
virtual void regenerateMap(const Palette* palette,
|
||||
const int maskIndex) = 0;
|
||||
|
||||
// Should return the best index in a palette that matches the given RGBA values.
|
||||
virtual int mapColor(const color_t rgba) const = 0;
|
||||
|
||||
virtual int maskIndex() const = 0;
|
||||
|
||||
virtual RgbMapAlgorithm rgbamapAlgorithm() const = 0;
|
||||
|
||||
virtual int modifications() const = 0;
|
||||
|
||||
// Color Best Fit Criteria used to generate the rgbmap
|
||||
|
@ -99,7 +99,7 @@ int RgbMapBase::findBestfit(int r, int g, int b, int a,
|
||||
|
||||
int bestfit = 0;
|
||||
double lowest = std::numeric_limits<double>::max();
|
||||
int size = m_palette->size();
|
||||
const int size = m_palette->size();
|
||||
// Linearice:
|
||||
double x = double(r);
|
||||
double y = double(g);
|
||||
|
@ -24,15 +24,19 @@ namespace doc {
|
||||
|
||||
RgbMapRGB5A3::RgbMapRGB5A3() : m_map(MAPSIZE) {}
|
||||
|
||||
void RgbMapRGB5A3::regenerateMap(const Palette* palette, int maskIndex)
|
||||
void RgbMapRGB5A3::regenerateMap(const Palette* palette,
|
||||
const int maskIndex,
|
||||
const FitCriteria fitCriteria)
|
||||
{
|
||||
// Skip useless regenerations
|
||||
if (m_palette == palette &&
|
||||
m_modifications == palette->getModifications() &&
|
||||
m_maskIndex == maskIndex)
|
||||
m_maskIndex == maskIndex &&
|
||||
m_fitCriteria == fitCriteria)
|
||||
return;
|
||||
|
||||
m_palette = palette;
|
||||
m_fitCriteria = fitCriteria;
|
||||
m_modifications = palette->getModifications();
|
||||
m_maskIndex = maskIndex;
|
||||
|
||||
@ -44,7 +48,7 @@ void RgbMapRGB5A3::regenerateMap(const Palette* palette, int maskIndex)
|
||||
int RgbMapRGB5A3::generateEntry(int i, int r, int g, int b, int a) const
|
||||
{
|
||||
return m_map[i] =
|
||||
m_palette->findBestfit(
|
||||
findBestfit(
|
||||
scale_5bits_to_8bits(r>>3),
|
||||
scale_5bits_to_8bits(g>>3),
|
||||
scale_5bits_to_8bits(b>>3),
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/debug.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "doc/object.h"
|
||||
#include "doc/palette.h"
|
||||
#include "doc/rgbmap.h"
|
||||
#include "doc/rgbmap_base.h"
|
||||
|
||||
@ -31,7 +32,15 @@ namespace doc {
|
||||
RgbMapRGB5A3();
|
||||
|
||||
// RgbMap impl
|
||||
void regenerateMap(const Palette* palette, int maskIndex) override;
|
||||
void regenerateMap(const Palette* palette,
|
||||
const int maskIndex,
|
||||
const FitCriteria fitCriteria) override;
|
||||
void regenerateMap(const Palette* palette,
|
||||
const int maskIndex) override
|
||||
{
|
||||
regenerateMap(palette, maskIndex, m_fitCriteria);
|
||||
};
|
||||
|
||||
int mapColor(const color_t rgba) const override {
|
||||
const int r = rgba_getr(rgba);
|
||||
const int g = rgba_getg(rgba);
|
||||
@ -46,7 +55,8 @@ namespace doc {
|
||||
int modifications() const override { return m_modifications; };
|
||||
int maskIndex() const override { return m_maskIndex; }
|
||||
FitCriteria fitCriteria() const override { return m_fitCriteria; }
|
||||
void fitCriteria(const FitCriteria fitCriteria) override { m_fitCriteria = fitCriteria; }
|
||||
void fitCriteria(const FitCriteria fitCriteria) override { m_fitCriteria == fitCriteria; }
|
||||
RgbMapAlgorithm rgbamapAlgorithm() const override { return RgbMapAlgorithm::RGB5A3; }
|
||||
|
||||
private:
|
||||
int generateEntry(int i, int r, int g, int b, int a) const;
|
||||
|
@ -435,18 +435,24 @@ RgbMap* Sprite::rgbMap(const frame_t frame) const
|
||||
RgbMap* Sprite::rgbMap(const frame_t frame,
|
||||
const RgbMapFor forLayer) const
|
||||
{
|
||||
return rgbMap(frame,
|
||||
forLayer,
|
||||
g_rgbMapAlgorithm);
|
||||
FitCriteria fc = FitCriteria::DEFAULT;
|
||||
RgbMapAlgorithm algo = g_rgbMapAlgorithm;
|
||||
if (m_rgbMap) {
|
||||
fc = m_rgbMap->fitCriteria();
|
||||
algo = m_rgbMap->rgbamapAlgorithm();
|
||||
}
|
||||
return rgbMap(frame, forLayer, algo, fc);
|
||||
}
|
||||
|
||||
RgbMap* Sprite::rgbMap(const frame_t frame,
|
||||
const RgbMapFor forLayer,
|
||||
RgbMapAlgorithm mapAlgo) const
|
||||
const RgbMapAlgorithm mapAlgo,
|
||||
const FitCriteria fitCriteria) const
|
||||
{
|
||||
if (!m_rgbMap || m_rgbMapAlgorithm != mapAlgo) {
|
||||
m_rgbMapAlgorithm = mapAlgo;
|
||||
switch (m_rgbMapAlgorithm) {
|
||||
if (!m_rgbMap ||
|
||||
m_rgbMap->rgbamapAlgorithm() != mapAlgo ||
|
||||
m_rgbMap->fitCriteria() != fitCriteria) {
|
||||
switch (mapAlgo) {
|
||||
case RgbMapAlgorithm::RGB5A3: m_rgbMap.reset(new RgbMapRGB5A3); break;
|
||||
case RgbMapAlgorithm::DEFAULT:
|
||||
case RgbMapAlgorithm::OCTREE: m_rgbMap.reset(new OctreeMap); break;
|
||||
@ -455,6 +461,7 @@ RgbMap* Sprite::rgbMap(const frame_t frame,
|
||||
ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
m_rgbMap->fitCriteria(fitCriteria);
|
||||
}
|
||||
int maskIndex;
|
||||
if (forLayer == RgbMapFor::OpaqueLayer)
|
||||
@ -464,7 +471,7 @@ RgbMap* Sprite::rgbMap(const frame_t frame,
|
||||
if (maskIndex == -1)
|
||||
maskIndex = 0;
|
||||
}
|
||||
m_rgbMap->regenerateMap(palette(frame), maskIndex);
|
||||
m_rgbMap->regenerateMap(palette(frame), maskIndex, fitCriteria);
|
||||
return m_rgbMap.get();
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "doc/cel_data.h"
|
||||
#include "doc/cel_list.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/fit_criteria.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/image_buffer.h"
|
||||
#include "doc/image_ref.h"
|
||||
@ -160,7 +161,8 @@ namespace doc {
|
||||
const RgbMapFor forLayer) const;
|
||||
RgbMap* rgbMap(const frame_t frame,
|
||||
const RgbMapFor forLayer,
|
||||
RgbMapAlgorithm mapAlgo) const;
|
||||
const RgbMapAlgorithm mapAlgo,
|
||||
const FitCriteria fitCriteria = FitCriteria::DEFAULT) const;
|
||||
|
||||
////////////////////////////////////////
|
||||
// Frames
|
||||
@ -255,7 +257,6 @@ namespace doc {
|
||||
gfx::Rect m_gridBounds; // grid settings
|
||||
|
||||
// Current rgb map
|
||||
mutable RgbMapAlgorithm m_rgbMapAlgorithm;
|
||||
mutable std::unique_ptr<RgbMap> m_rgbMap;
|
||||
|
||||
Tags m_tags;
|
||||
|
Loading…
Reference in New Issue
Block a user