Change ink processing impl

This commit is contained in:
David Capello 2017-04-27 18:57:47 -03:00
parent 3e3b0d8a35
commit 8de967dd37
2 changed files with 71 additions and 95 deletions

View File

@ -5,6 +5,7 @@
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#include "app/modules/palettes.h" #include "app/modules/palettes.h"
#include "base/unique_ptr.h"
#include "doc/blend_funcs.h" #include "doc/blend_funcs.h"
#include "doc/image_impl.h" #include "doc/image_impl.h"
#include "doc/layer.h" #include "doc/layer.h"
@ -28,10 +29,16 @@ namespace {
// Ink Processing // Ink Processing
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
template<typename Derived> class BaseInkProcessing {
class InkProcessing {
public: public:
void operator()(int x1, int y, int x2, ToolLoop* loop) { virtual ~BaseInkProcessing() { }
virtual void hline(int x1, int y, int x2, ToolLoop* loop) = 0;
};
template<typename Derived>
class InkProcessing : public BaseInkProcessing {
public:
void hline(int x1, int y, int x2, ToolLoop* loop) override {
int x; int x;
// Use mask // Use mask
@ -1066,22 +1073,15 @@ void BrushInkProcessing<IndexedTraits>::processPixel(int x, int y) {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
template<template<typename> class InkProcessing, typedef base::UniquePtr<BaseInkProcessing> InkProcessingPtr;
typename ImageTraits>
void ink_proc(int x1, int y, int x2, void* data)
{
ToolLoop* loop = reinterpret_cast<ToolLoop*>(data);
InkProcessing<ImageTraits> ink(loop);
ink(x1, y, x2, loop);
}
template<template<typename> class InkProcessing> template<template<typename> class T>
AlgoHLine get_ink_proc(PixelFormat pixelFormat) BaseInkProcessing* get_ink_proc(ToolLoop* loop)
{ {
switch (pixelFormat) { switch (loop->sprite()->pixelFormat()) {
case IMAGE_RGB: return ink_proc<InkProcessing, RgbTraits>; case IMAGE_RGB: return new T<RgbTraits>(loop);
case IMAGE_GRAYSCALE: return ink_proc<InkProcessing, GrayscaleTraits>; case IMAGE_GRAYSCALE: return new T<GrayscaleTraits>(loop);
case IMAGE_INDEXED: return ink_proc<InkProcessing, IndexedTraits>; case IMAGE_INDEXED: return new T<IndexedTraits>(loop);
} }
ASSERT(false); ASSERT(false);
return nullptr; return nullptr;

View File

@ -19,18 +19,36 @@
namespace app { namespace app {
namespace tools { namespace tools {
class BaseInk : public Ink {
public:
BaseInk() { }
BaseInk(const BaseInk& other) { }
void inkHline(int x1, int y, int x2, ToolLoop* loop) override {
ASSERT(m_proc);
m_proc->hline(x1, y, x2, loop);
}
protected:
void setProc(BaseInkProcessing* proc) {
m_proc.reset(proc);
}
private:
InkProcessingPtr m_proc;
};
// Ink used for tools which paint with primary/secondary // Ink used for tools which paint with primary/secondary
// (or foreground/background colors) // (or foreground/background colors)
class PaintInk : public Ink { class PaintInk : public BaseInk {
public: public:
enum Type { Simple, WithFg, WithBg, Copy, LockAlpha }; enum Type { Simple, WithFg, WithBg, Copy, LockAlpha };
private: private:
Type m_type; Type m_type;
AlgoHLine m_proc;
public: public:
PaintInk(Type type) : m_type(type), m_proc(nullptr) { } PaintInk(Type type) : m_type(type) { }
Ink* clone() override { return new PaintInk(*this); } Ink* clone() override { return new PaintInk(*this); }
@ -54,10 +72,8 @@ public:
break; break;
} }
auto pixelFormat = loop->sprite()->pixelFormat();
if (loop->getBrush()->type() == doc::kImageBrushType) if (loop->getBrush()->type() == doc::kImageBrushType)
m_proc = get_ink_proc<BrushInkProcessing>(pixelFormat); setProc(get_ink_proc<BrushInkProcessing>(loop));
else { else {
switch (m_type) { switch (m_type) {
case Simple: { case Simple: {
@ -82,50 +98,36 @@ public:
// Use a faster ink, direct copy // Use a faster ink, direct copy
if (opaque) if (opaque)
m_proc = get_ink_proc<CopyInkProcessing>(pixelFormat); setProc(get_ink_proc<CopyInkProcessing>(loop));
else else
m_proc = get_ink_proc<TransparentInkProcessing>(pixelFormat); setProc(get_ink_proc<TransparentInkProcessing>(loop));
break; break;
} }
case Copy: case Copy:
m_proc = get_ink_proc<CopyInkProcessing>(pixelFormat); setProc(get_ink_proc<CopyInkProcessing>(loop));
break; break;
case LockAlpha: case LockAlpha:
m_proc = get_ink_proc<LockAlphaInkProcessing>(pixelFormat); setProc(get_ink_proc<LockAlphaInkProcessing>(loop));
break; break;
default: default:
m_proc = get_ink_proc<TransparentInkProcessing>(pixelFormat); setProc(get_ink_proc<TransparentInkProcessing>(loop));
break; break;
} }
} }
} }
void inkHline(int x1, int y, int x2, ToolLoop* loop) override {
ASSERT(m_proc);
(*m_proc)(x1, y, x2, loop);
}
}; };
class ShadingInk : public Ink { class ShadingInk : public BaseInk {
private:
AlgoHLine m_proc;
public: public:
ShadingInk() { }
Ink* clone() override { return new ShadingInk(*this); } Ink* clone() override { return new ShadingInk(*this); }
bool isPaint() const override { return true; } bool isPaint() const override { return true; }
bool isShading() const override { return true; } bool isShading() const override { return true; }
void prepareInk(ToolLoop* loop) override { void prepareInk(ToolLoop* loop) override {
m_proc = get_ink_proc<ShadingInkProcessing>(loop->sprite()->pixelFormat()); setProc(get_ink_proc<ShadingInkProcessing>(loop));
}
void inkHline(int x1, int y, int x2, ToolLoop* loop) override {
(*m_proc)(x1, y, x2, loop);
} }
}; };
@ -168,15 +170,12 @@ public:
}; };
class SliceInk : public Ink { class SliceInk : public BaseInk {
AlgoHLine m_proc;
bool m_createSlice; bool m_createSlice;
gfx::Rect m_maxBounds; gfx::Rect m_maxBounds;
public: public:
SliceInk() { SliceInk() : m_createSlice(false) { }
m_createSlice = false;
}
Ink* clone() override { return new SliceInk(*this); } Ink* clone() override { return new SliceInk(*this); }
@ -186,14 +185,14 @@ public:
} }
void prepareInk(ToolLoop* loop) override { void prepareInk(ToolLoop* loop) override {
m_proc = get_ink_proc<XorInkProcessing>(loop->sprite()->pixelFormat()); setProc(get_ink_proc<XorInkProcessing>(loop));
} }
void inkHline(int x1, int y, int x2, ToolLoop* loop) override { void inkHline(int x1, int y, int x2, ToolLoop* loop) override {
if (m_createSlice) if (m_createSlice)
m_maxBounds |= gfx::Rect(x1, y, x2-x1+1, 1); m_maxBounds |= gfx::Rect(x1, y, x2-x1+1, 1);
else else
(*m_proc)(x1, y, x2, loop); BaseInk::inkHline(x1, y, x2, loop);
} }
void setFinalStep(ToolLoop* loop, bool state) override { void setFinalStep(ToolLoop* loop, bool state) override {
@ -211,12 +210,11 @@ public:
}; };
class EraserInk : public Ink { class EraserInk : public BaseInk {
public: public:
enum Type { Eraser, ReplaceFgWithBg, ReplaceBgWithFg }; enum Type { Eraser, ReplaceFgWithBg, ReplaceBgWithFg };
private: private:
AlgoHLine m_proc;
Type m_type; Type m_type;
public: public:
@ -232,58 +230,48 @@ public:
switch (m_type) { switch (m_type) {
case Eraser: { case Eraser: {
color_t primary = app_get_color_to_clear_layer(loop->getLayer()); // TODO app_get_color_to_clear_layer should receive the context as parameter
color_t secondary = app_get_color_to_clear_layer(loop->getLayer()); color_t clearColor = app_get_color_to_clear_layer(loop->getLayer());
loop->setPrimaryColor(clearColor);
loop->setSecondaryColor(clearColor);
if (loop->getOpacity() == 255) { if (loop->getOpacity() == 255) {
m_proc = get_ink_proc<CopyInkProcessing>(loop->sprite()->pixelFormat()); setProc(get_ink_proc<CopyInkProcessing>(loop));
} }
else { else {
// For opaque layers // For opaque layers
if (loop->getLayer()->isBackground()) { if (loop->getLayer()->isBackground()) {
m_proc = get_ink_proc<TransparentInkProcessing>(loop->sprite()->pixelFormat()); setProc(get_ink_proc<TransparentInkProcessing>(loop));
} }
// For transparent layers // For transparent layers
else { else {
m_proc = get_ink_proc<MergeInkProcessing>(loop->sprite()->pixelFormat()); if (loop->sprite()->pixelFormat() == IMAGE_INDEXED)
loop->setPrimaryColor(loop->sprite()->transparentColor());
if (loop->sprite()->pixelFormat() == IMAGE_INDEXED) { setProc(get_ink_proc<MergeInkProcessing>(loop));
primary = loop->sprite()->transparentColor();
}
} }
} }
// TODO app_get_color_to_clear_layer should receive the context as parameter
loop->setPrimaryColor(primary);
loop->setSecondaryColor(secondary);
break; break;
} }
case ReplaceFgWithBg: case ReplaceFgWithBg:
m_proc = get_ink_proc<ReplaceInkProcessing>(loop->sprite()->pixelFormat());
loop->setPrimaryColor(loop->getFgColor()); loop->setPrimaryColor(loop->getFgColor());
loop->setSecondaryColor(loop->getBgColor()); loop->setSecondaryColor(loop->getBgColor());
setProc(get_ink_proc<ReplaceInkProcessing>(loop));
break; break;
case ReplaceBgWithFg: case ReplaceBgWithFg:
m_proc = get_ink_proc<ReplaceInkProcessing>(loop->sprite()->pixelFormat());
loop->setPrimaryColor(loop->getBgColor()); loop->setPrimaryColor(loop->getBgColor());
loop->setSecondaryColor(loop->getFgColor()); loop->setSecondaryColor(loop->getFgColor());
setProc(get_ink_proc<ReplaceInkProcessing>(loop));
break; break;
} }
} }
void inkHline(int x1, int y, int x2, ToolLoop* loop) override {
(*m_proc)(x1, y, x2, loop);
}
}; };
class BlurInk : public Ink { class BlurInk : public BaseInk {
AlgoHLine m_proc;
public: public:
Ink* clone() override { return new BlurInk(*this); } Ink* clone() override { return new BlurInk(*this); }
@ -292,11 +280,7 @@ public:
bool needsSpecialSourceArea() const override { return true; } bool needsSpecialSourceArea() const override { return true; }
void prepareInk(ToolLoop* loop) override { void prepareInk(ToolLoop* loop) override {
m_proc = get_ink_proc<BlurInkProcessing>(loop->sprite()->pixelFormat()); setProc(get_ink_proc<BlurInkProcessing>(loop));
}
void inkHline(int x1, int y, int x2, ToolLoop* loop) override {
(*m_proc)(x1, y, x2, loop);
} }
void createSpecialSourceArea(const gfx::Region& dirtyArea, gfx::Region& sourceArea) const override { void createSpecialSourceArea(const gfx::Region& dirtyArea, gfx::Region& sourceArea) const override {
@ -309,9 +293,7 @@ public:
}; };
class JumbleInk : public Ink { class JumbleInk : public BaseInk {
AlgoHLine m_proc;
public: public:
Ink* clone() override { return new JumbleInk(*this); } Ink* clone() override { return new JumbleInk(*this); }
@ -320,11 +302,7 @@ public:
bool needsSpecialSourceArea() const override { return true; } bool needsSpecialSourceArea() const override { return true; }
void prepareInk(ToolLoop* loop) override { void prepareInk(ToolLoop* loop) override {
m_proc = get_ink_proc<JumbleInkProcessing>(loop->sprite()->pixelFormat()); setProc(get_ink_proc<JumbleInkProcessing>(loop));
}
void inkHline(int x1, int y, int x2, ToolLoop* loop) override {
(*m_proc)(x1, y, x2, loop);
} }
void createSpecialSourceArea(const gfx::Region& dirtyArea, gfx::Region& sourceArea) const override { void createSpecialSourceArea(const gfx::Region& dirtyArea, gfx::Region& sourceArea) const override {
@ -338,21 +316,19 @@ public:
// Ink used for selection tools (like Rectangle Marquee, Lasso, Magic Wand, etc.) // Ink used for selection tools (like Rectangle Marquee, Lasso, Magic Wand, etc.)
class SelectionInk : public Ink { class SelectionInk : public BaseInk {
bool m_modify_selection; bool m_modify_selection;
Mask m_mask; Mask m_mask;
Rect m_maxBounds; Rect m_maxBounds;
AlgoHLine m_proc;
public: public:
SelectionInk() { SelectionInk()
m_modify_selection = false; : m_modify_selection(false) { }
}
Ink* clone() override { return new SelectionInk(*this); } Ink* clone() override { return new SelectionInk(*this); }
void prepareInk(ToolLoop* loop) override { void prepareInk(ToolLoop* loop) override {
m_proc = get_ink_proc<XorInkProcessing>(loop->sprite()->pixelFormat()); setProc(get_ink_proc<XorInkProcessing>(loop));
} }
bool isSelection() const override { return true; } bool isSelection() const override { return true; }
@ -375,7 +351,7 @@ public:
m_maxBounds |= gfx::Rect(x1, y, x2-x1+1, 1); m_maxBounds |= gfx::Rect(x1, y, x2-x1+1, 1);
} }
else { else {
(*m_proc)(x1, y, x2, loop); BaseInk::inkHline(x1, y, x2, loop);
} }
} }