diff --git a/src/app/tools/ink_processing.h b/src/app/tools/ink_processing.h index 6c1620c31..d2c574d1c 100644 --- a/src/app/tools/ink_processing.h +++ b/src/app/tools/ink_processing.h @@ -6,7 +6,6 @@ #include "app/modules/palettes.h" #include "base/unique_ptr.h" -#include "base/vector2d.h" #include "doc/blend_funcs.h" #include "doc/image_impl.h" #include "doc/layer.h" @@ -18,6 +17,7 @@ #include "gfx/hsv.h" #include "gfx/rgb.h" #include "render/dithering.h" +#include "render/gradient.h" namespace app { namespace tools { @@ -897,83 +897,12 @@ public: return; } - // If there is no vector defining the gradient (just one point), - // the "gradient" will be just "c0" - if (strokes[0].firstPoint().x == strokes[0].lastPoint().x && - strokes[0].firstPoint().y == strokes[0].lastPoint().y) { - m_tmpImage->clear(c0); - return; - } - - const render::DitheringMatrix& m_matrix = - loop->getDitheringMatrix(); - - base::Vector2d - u(strokes[0].firstPoint().x, - strokes[0].firstPoint().y), - v(strokes[0].lastPoint().x, - strokes[0].lastPoint().y), w; - w = v - u; - - // As we use non-premultiplied RGB values, we need correct RGB - // values on each stop. So in case that one color has alpha=0 - // (complete transparent), use the RGB values of the - // non-transparent color in the other stop point. - if (doc::rgba_geta(c0) == 0 && - doc::rgba_geta(c1) != 0) { - c0 = (c1 & rgba_rgb_mask); - } - else if (doc::rgba_geta(c0) != 0 && - doc::rgba_geta(c1) == 0) { - c1 = (c0 & rgba_rgb_mask); - } - - const double r0 = double(doc::rgba_getr(c0)) / 255.0; - const double g0 = double(doc::rgba_getg(c0)) / 255.0; - const double b0 = double(doc::rgba_getb(c0)) / 255.0; - const double a0 = double(doc::rgba_geta(c0)) / 255.0; - - const double r1 = double(doc::rgba_getr(c1)) / 255.0; - const double g1 = double(doc::rgba_getg(c1)) / 255.0; - const double b1 = double(doc::rgba_getb(c1)) / 255.0; - const double a1 = double(doc::rgba_geta(c1)) / 255.0; - - doc::LockImageBits bits(m_tmpImage.get()); - auto it = bits.begin(); - const int width = m_tmpImage->width(); - const int height = m_tmpImage->height(); - - if (m_matrix.rows() == 1 && m_matrix.cols() == 1) { - for (int y=0; y q(x, y); - q -= u; - double f = (q * w.normalize()) / (w.magnitude()); - - doc::color_t c; - if (f < 0.0) c = c0; - else if (f > 1.0) c = c1; - else { - c = doc::rgba(int(255.0 * (r0 + f*(r1-r0))), - int(255.0 * (g0 + f*(g1-g0))), - int(255.0 * (b0 + f*(b1-b0))), - int(255.0 * (a0 + f*(a1-a0)))); - } - - *it = c; - } - } - } - else { - for (int y=0; y q(x, y); - q -= u; - double f = (q * w.normalize()) / (w.magnitude()); - *it = (f*m_matrix.maxValue() < m_matrix(y, x) ? c0: c1); - } - } - } + render::render_rgba_linear_gradient( + m_tmpImage.get(), + strokes[0].firstPoint(), + strokes[0].lastPoint(), + c0, c1, + loop->getDitheringMatrix()); } protected: diff --git a/src/render/CMakeLists.txt b/src/render/CMakeLists.txt index a2e882fa0..811b0c9a3 100644 --- a/src/render/CMakeLists.txt +++ b/src/render/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(render-lib get_sprite_pixel.cpp + gradient.cpp ordered_dither.cpp quantization.cpp render.cpp diff --git a/src/render/LICENSE.txt b/src/render/LICENSE.txt index 220ac0d42..dce2ee200 100644 --- a/src/render/LICENSE.txt +++ b/src/render/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2001-2014 David Capello +Copyright (c) 2001-2017 David Capello Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/src/render/README.md b/src/render/README.md index 2f7c6cc85..1ec9f7ce7 100644 --- a/src/render/README.md +++ b/src/render/README.md @@ -1,4 +1,4 @@ # Aseprite Render Library -*Copyright (C) 2001-2014 David Capello* +*Copyright (C) 2001-2017 David Capello* > Distributed under [MIT license](LICENSE.txt) diff --git a/src/render/gradient.cpp b/src/render/gradient.cpp new file mode 100644 index 000000000..ac0061822 --- /dev/null +++ b/src/render/gradient.cpp @@ -0,0 +1,106 @@ +// Aseprite Render Library +// Copyright (c) 2017 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "render/gradient.h" + +#include "base/vector2d.h" +#include "doc/image.h" +#include "doc/image_impl.h" +#include "render/dithering_matrix.h" + +namespace render { + +void render_rgba_linear_gradient( + doc::Image* img, + const gfx::Point p0, + const gfx::Point p1, + doc::color_t c0, + doc::color_t c1, + const render::DitheringMatrix& matrix) +{ + ASSERT(img->pixelFormat() == doc::IMAGE_RGB); + if (img->pixelFormat() != doc::IMAGE_RGB) { + return; + } + + // If there is no vector defining the gradient (just one point), + // the "gradient" will be just "c0" + if (p0 == p1) { + img->clear(c0); + return; + } + + base::Vector2d + u(p0.x, p0.y), + v(p1.x, p1.y), w; + w = v - u; + + // As we use non-premultiplied RGB values, we need correct RGB + // values on each stop. So in case that one color has alpha=0 + // (complete transparent), use the RGB values of the + // non-transparent color in the other stop point. + if (doc::rgba_geta(c0) == 0 && + doc::rgba_geta(c1) != 0) { + c0 = (c1 & doc::rgba_rgb_mask); + } + else if (doc::rgba_geta(c0) != 0 && + doc::rgba_geta(c1) == 0) { + c1 = (c0 & doc::rgba_rgb_mask); + } + + const double r0 = double(doc::rgba_getr(c0)) / 255.0; + const double g0 = double(doc::rgba_getg(c0)) / 255.0; + const double b0 = double(doc::rgba_getb(c0)) / 255.0; + const double a0 = double(doc::rgba_geta(c0)) / 255.0; + + const double r1 = double(doc::rgba_getr(c1)) / 255.0; + const double g1 = double(doc::rgba_getg(c1)) / 255.0; + const double b1 = double(doc::rgba_getb(c1)) / 255.0; + const double a1 = double(doc::rgba_geta(c1)) / 255.0; + + doc::LockImageBits bits(img); + auto it = bits.begin(); + const int width = img->width(); + const int height = img->height(); + + if (matrix.rows() == 1 && matrix.cols() == 1) { + for (int y=0; y q(x, y); + q -= u; + double f = (q * w.normalize()) / (w.magnitude()); + + doc::color_t c; + if (f < 0.0) c = c0; + else if (f > 1.0) c = c1; + else { + c = doc::rgba(int(255.0 * (r0 + f*(r1-r0))), + int(255.0 * (g0 + f*(g1-g0))), + int(255.0 * (b0 + f*(b1-b0))), + int(255.0 * (a0 + f*(a1-a0)))); + } + + *it = c; + } + } + } + else { + for (int y=0; y q(x, y); + q -= u; + double f = (q * w.normalize()) / (w.magnitude()); + *it = (f*matrix.maxValue() < matrix(y, x) ? c0: c1); + } + } + } +} + +} // namespace render diff --git a/src/render/gradient.h b/src/render/gradient.h new file mode 100644 index 000000000..8aaa2ca63 --- /dev/null +++ b/src/render/gradient.h @@ -0,0 +1,32 @@ +// Aseprite Render Library +// Copyright (c) 2017 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifndef RENDER_GRADIENT_H_INCLUDED +#define RENDER_GRADIENT_H_INCLUDED +#pragma once + +#include "doc/color.h" +#include "gfx/point.h" + +namespace doc { + class Image; +} + +namespace render { + +class DitheringMatrix; + +void render_rgba_linear_gradient( + doc::Image* img, + const gfx::Point p0, + const gfx::Point p1, + doc::color_t c0, + doc::color_t c1, + const render::DitheringMatrix& matrix); + +} // namespace render + +#endif