Add ‘color fit criteria’ implementation on Sprite > Color Mode > More Options

This commit is contained in:
Gaspar Capello 2024-04-26 16:20:06 -03:00
parent d730479e80
commit 8a17be1d11
11 changed files with 92 additions and 39 deletions

View File

@ -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

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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),

View File

@ -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;

View File

@ -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();
}

View File

@ -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;