diff --git a/src/app/tools/ink_processing.h b/src/app/tools/ink_processing.h index 862ae69d1..d3304dcd7 100644 --- a/src/app/tools/ink_processing.h +++ b/src/app/tools/ink_processing.h @@ -9,6 +9,7 @@ #include "app/util/wrap_point.h" #include "app/util/wrap_value.h" #include "doc/blend_funcs.h" +#include "doc/blend_internals.h" #include "doc/image_impl.h" #include "doc/layer.h" #include "doc/palette.h" @@ -1125,7 +1126,7 @@ public: color_t getTransparentColor() { return m_transparentColor; } -private: +protected: void alignPixelPoint(int& x, int& y) { x = (x - m_u) % m_width; y = (y - m_v) % m_height; @@ -1363,6 +1364,174 @@ void BrushLockAlphaInkProcessing::processPixel(int x, int y) { *m_dstAddress = graya(graya_getv(c), graya_geta(*m_srcAddress)); } +////////////////////////////////////////////////////////////////////// +// Brush Ink - Eraser Tool +////////////////////////////////////////////////////////////////////// + +template +class BrushEraserInkProcessing : public BrushInkProcessingBase { +public: + BrushEraserInkProcessing(ToolLoop* loop) : BrushInkProcessingBase(loop) { + } + + void processPixel(int x, int y) override { + // Do nothing + } +}; + +template<> +void BrushEraserInkProcessing::processPixel(int x, int y) { + alignPixelPoint(x, y); + if (m_brushMask && !get_pixel_fast(m_brushMask, x, y)) + return; + + color_t c; + switch (m_brushImage->pixelFormat()) { + case IMAGE_RGB: { + c = get_pixel_fast(m_brushImage, x, y); + int t; + c = rgba(rgba_getr(*m_srcAddress), + rgba_getg(*m_srcAddress), + rgba_getb(*m_srcAddress), + MUL_UN8(rgba_geta(*m_dstAddress), 255 - rgba_geta(c), t)); + break; + } + case IMAGE_INDEXED: { + c = get_pixel_fast(m_brushImage, x, y); + if (m_transparentColor == c) + c = 0; + else + // TODO m_palette->getEntry(c) does not work because the + // m_palette member is loaded the Rgba Palette, NOT the + // original Indexed Palette from where m_brushImage belongs. + // This conversion can be possible if we load the palette + // pointer in m_brush when is created the custom brush in the + // Indexed Sprite. + c = m_palette->getEntry(c); + int t; + c = rgba(rgba_getr(*m_srcAddress), + rgba_getg(*m_srcAddress), + rgba_getb(*m_srcAddress), + MUL_UN8(rgba_geta(*m_dstAddress), 255 - rgba_geta(c), t)); + break; + } + case IMAGE_GRAYSCALE: { + c = get_pixel_fast(m_brushImage, x, y); + int t; + c = rgba(rgba_getr(*m_srcAddress), + rgba_getg(*m_srcAddress), + rgba_getb(*m_srcAddress), + MUL_UN8(rgba_geta(*m_dstAddress), 255 - graya_geta(c), t)); + break; + } + case IMAGE_BITMAP: { + // TODO In which circuntance is possible this case? + c = get_pixel_fast(m_brushImage, x, y); + c = c ? m_bgColor : *m_srcAddress; + break; + } + default: + ASSERT(false); + return; + } + *m_dstAddress = c;; +} + +template<> +void BrushEraserInkProcessing::processPixel(int x, int y) { + alignPixelPoint(x, y); + if (m_brushMask && !get_pixel_fast(m_brushMask, x, y)) + return; + + color_t c; + switch (m_brushImage->pixelFormat()) { + case IMAGE_RGB: { + c = get_pixel_fast(m_brushImage, x, y); + int t; + c = graya(graya_getv(*m_srcAddress), + MUL_UN8(graya_geta(*m_dstAddress), 255 - rgba_geta(c), t)); + break; + } + case IMAGE_INDEXED: { + c = get_pixel_fast(m_brushImage, x, y); + if (m_transparentColor == c) + c = 0; + else + // TODO m_palette->getEntry(c) does not work because the + // m_palette member is loaded the Graya Palette, NOT the + // original Indexed Palette from where m_brushImage belongs. + // This conversion can be possible if we load the palette + // pointer in m_brush when is created the custom brush in the + // Indexed Sprite. + c = m_palette->getEntry(c); + int t; + c = graya(graya_getv(*m_srcAddress), + MUL_UN8(graya_geta(*m_dstAddress), 255 - rgba_geta(c), t)); + break; + } + case IMAGE_GRAYSCALE: { + c = get_pixel_fast(m_brushImage, x, y); + int t; + c = graya(graya_getv(*m_srcAddress), + MUL_UN8(graya_geta(*m_dstAddress), 255 - graya_geta(c), t)); + break; + } + case IMAGE_BITMAP: { + // TODO In which circuntance is possible this case? + c = get_pixel_fast(m_brushImage, x, y); + c = c ? m_bgColor : *m_srcAddress; + break; + } + default: + ASSERT(false); + return; + } + *m_dstAddress = c; +} + +template<> +void BrushEraserInkProcessing::processPixel(int x, int y) { + alignPixelPoint(x, y); + if (m_brushMask && !get_pixel_fast(m_brushMask, x, y)) + return; + + color_t c; + switch (m_brushImage->pixelFormat()) { + case IMAGE_RGB: { + c = get_pixel_fast(m_brushImage, x, y); + c = m_palette->findBestfit(rgba_getr(c), + rgba_getg(c), + rgba_getb(c), + rgba_geta(c), m_transparentColor); + break; + } + case IMAGE_INDEXED: { + c = get_pixel_fast(m_brushImage, x, y); + break; + } + case IMAGE_GRAYSCALE: { + c = get_pixel_fast(m_brushImage, x, y); + c = m_palette->findBestfit(graya_getv(c), + graya_getv(c), + graya_getv(c), + graya_geta(c), 0); + break; + } + case IMAGE_BITMAP: { + // TODO In which circuntance is possible this case? + c = get_pixel_fast(m_brushImage, x, y); + c = c ? m_fgColor: m_bgColor; + break; + } + default: + ASSERT(false); + return; + } + if (c != m_transparentColor) { + *m_dstAddress = m_transparentColor; + } +} + ////////////////////////////////////////////////////////////////////// template class T> diff --git a/src/app/tools/inks.h b/src/app/tools/inks.h index cc8a2420a..990c4529f 100644 --- a/src/app/tools/inks.h +++ b/src/app/tools/inks.h @@ -284,32 +284,35 @@ public: void prepareInk(ToolLoop* loop) override { switch (m_type) { - case Eraser: { - // TODO app_get_color_to_clear_layer should receive the context as parameter - color_t clearColor = app_get_color_to_clear_layer(loop->getLayer()); - loop->setPrimaryColor(clearColor); - loop->setSecondaryColor(clearColor); - - if (loop->getOpacity() == 255) { - setProc(get_ink_proc(loop)); + if (loop->getBrush()->type() == doc::kImageBrushType) { + setProc(get_ink_proc(loop)); } else { - // For opaque layers - if (loop->getLayer()->isBackground()) { - setProc(get_ink_proc(loop)); - } - // For transparent layers - else { - if (loop->sprite()->pixelFormat() == IMAGE_INDEXED) - loop->setPrimaryColor(loop->sprite()->transparentColor()); + // TODO app_get_color_to_clear_layer should receive the context as parameter + color_t clearColor = app_get_color_to_clear_layer(loop->getLayer()); + loop->setPrimaryColor(clearColor); + loop->setSecondaryColor(clearColor); - setProc(get_ink_proc(loop)); + if (loop->getOpacity() == 255) { + setProc(get_ink_proc(loop)); + } + else { + // For opaque layers + if (loop->getLayer()->isBackground()) { + setProc(get_ink_proc(loop)); + } + // For transparent layers + else { + if (loop->sprite()->pixelFormat() == IMAGE_INDEXED) + loop->setPrimaryColor(loop->sprite()->transparentColor()); + + setProc(get_ink_proc(loop)); + } } } break; } - case ReplaceFgWithBg: loop->setPrimaryColor(loop->getFgColor()); loop->setSecondaryColor(loop->getBgColor()); diff --git a/src/app/ui/editor/brush_preview.cpp b/src/app/ui/editor/brush_preview.cpp index 48cb8d241..022bc48cd 100644 --- a/src/app/ui/editor/brush_preview.cpp +++ b/src/app/ui/editor/brush_preview.cpp @@ -183,7 +183,8 @@ void BrushPreview::show(const gfx::Point& screenPos) // For cursor type 'bounds' we have to generate cursor boundaries if (m_type & BRUSH_BOUNDARIES) { - showPreview = false; + if (brush->type() != kImageBrushType) + showPreview = false; generateBoundaries(); }