Skip to content

Commit

Permalink
Add ‘color fit criteria’ implementation on Sprite > Color Mode > More…
Browse files Browse the repository at this point in the history
… Options
  • Loading branch information
Gasparoken committed Apr 29, 2024
1 parent d730479 commit 8a17be1
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 39 deletions.
16 changes: 11 additions & 5 deletions src/app/cmd/set_pixel_format.cpp
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -108,7 +109,8 @@ SetPixelFormat::SetPixelFormat(Sprite* sprite,
cel->layer()->isBackground(),
mapAlgorithm,
toGray,
&superDel);
&superDel,
fitCriteria);

superDel.nextImage();
}
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down
9 changes: 6 additions & 3 deletions src/app/cmd/set_pixel_format.h
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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"
Expand All @@ -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;
Expand All @@ -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;
Expand Down
21 changes: 11 additions & 10 deletions src/app/commands/cmd_change_pixel_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ class ConvertThread : public render::TaskDelegate {
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)
Expand All @@ -84,13 +83,11 @@ class ConvertThread : public render::TaskDelegate {
sprite, frame,
pixelFormat,
dithering,
rgbMapAlgorithm,
toGray,
newBlend]() { // Copy the matrix
run(sprite, frame,
pixelFormat,
dithering,
rgbMapAlgorithm,
toGray,
newBlend);
})
Expand All @@ -115,7 +112,6 @@ class ConvertThread : public render::TaskDelegate {
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(
Expand All @@ -137,9 +133,7 @@ class ConvertThread : public render::TaskDelegate {
m_image.get(),
pixelFormat,
dithering,
sprite->rgbMap(frame,
sprite->rgbMapForSprite(),
rgbMapAlgorithm),
sprite->rgbMap(frame),
sprite->palette(frame),
(sprite->backgroundLayer() != nullptr),
0,
Expand Down Expand Up @@ -251,6 +245,7 @@ class ColorModeWindow : public app::gen::ColorMode {
// 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(
Expand Down Expand Up @@ -414,6 +409,12 @@ class ColorModeWindow : public app::gen::ColorMode {
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);
Expand All @@ -426,7 +427,6 @@ class ColorModeWindow : public app::gen::ColorMode {
m_editor->frame(),
dstPixelFormat,
dithering(),
rgbMapAlgorithm(),
toGray(),
visibleBounds.origin(),
Preferences::instance().experimental.newBlend()));
Expand Down Expand Up @@ -505,7 +505,7 @@ class ChangePixelFormatCommand : public Command {
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;
};

Expand Down Expand Up @@ -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();
}
Expand Down
8 changes: 6 additions & 2 deletions src/doc/octree_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand Down
13 changes: 11 additions & 2 deletions src/doc/octree_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,21 @@ class OctreeMap : public RgbMap
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
Expand Down
10 changes: 9 additions & 1 deletion src/doc/rgbmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "base/debug.h"
#include "doc/color.h"
#include "doc/fit_criteria.h"
#include "doc/rgbmap_algorithm.h"

namespace doc {

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/doc/rgbmap_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 7 additions & 3 deletions src/doc/rgbmap_rgb5a3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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),
Expand Down
14 changes: 12 additions & 2 deletions src/doc/rgbmap_rgb5a3.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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);
Expand All @@ -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;
Expand Down
23 changes: 15 additions & 8 deletions src/doc/sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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();
}

Expand Down
Loading

0 comments on commit 8a17be1

Please sign in to comment.