diff --git a/data/extensions/aseprite-theme/sheet.png b/data/extensions/aseprite-theme/sheet.png
index 0ee7e6ff0..83fd82294 100644
Binary files a/data/extensions/aseprite-theme/sheet.png and b/data/extensions/aseprite-theme/sheet.png differ
diff --git a/data/extensions/aseprite-theme/theme.xml b/data/extensions/aseprite-theme/theme.xml
index ef67eeaf1..74e5849e8 100644
--- a/data/extensions/aseprite-theme/theme.xml
+++ b/data/extensions/aseprite-theme/theme.xml
@@ -402,6 +402,8 @@
+
+
diff --git a/src/app/tools/ink_processing.h b/src/app/tools/ink_processing.h
index 784ce4df9..c2953b825 100644
--- a/src/app/tools/ink_processing.h
+++ b/src/app/tools/ink_processing.h
@@ -908,9 +908,10 @@ public:
imgPos.y *= h;
}
- render::render_rgba_linear_gradient(
+ render::render_rgba_gradient(
m_tmpImage.get(), imgPos, u, v, c0, c1,
- loop->getDitheringMatrix());
+ loop->getDitheringMatrix(),
+ loop->getGradientType());
}
protected:
diff --git a/src/app/tools/tool_loop.h b/src/app/tools/tool_loop.h
index b71327cef..eb6726ac8 100644
--- a/src/app/tools/tool_loop.h
+++ b/src/app/tools/tool_loop.h
@@ -16,6 +16,7 @@
#include "filters/tiled_mode.h"
#include "gfx/point.h"
#include "gfx/rect.h"
+#include "render/gradient.h"
namespace gfx {
class Region;
@@ -233,6 +234,7 @@ namespace app {
// For gradients
virtual render::DitheringMatrix getDitheringMatrix() = 0;
virtual render::DitheringAlgorithmBase* getDitheringAlgorithm() = 0;
+ virtual render::GradientType getGradientType() = 0;
};
} // namespace tools
diff --git a/src/app/ui/context_bar.cpp b/src/app/ui/context_bar.cpp
index f3dcbc491..6a4710def 100644
--- a/src/app/ui/context_bar.cpp
+++ b/src/app/ui/context_bar.cpp
@@ -933,6 +933,27 @@ protected:
}
};
+class ContextBar::GradientTypeField : public ButtonSet {
+public:
+ GradientTypeField() : ButtonSet(2) {
+ SkinTheme* theme = static_cast(this->theme());
+
+ addItem(theme->parts.linearGradient());
+ addItem(theme->parts.radialGradient());
+
+ setSelectedItem(0);
+ }
+
+ void setupTooltips(TooltipManager* tooltipManager) {
+ tooltipManager->addTooltipFor(at(0), "Linear Gradient", BOTTOM);
+ tooltipManager->addTooltipFor(at(1), "Radial Gradient", BOTTOM);
+ }
+
+ render::GradientType gradientType() const {
+ return (render::GradientType)selectedItem();
+ }
+};
+
class ContextBar::DropPixelsField : public ButtonSet {
public:
DropPixelsField() : ButtonSet(2) {
@@ -1100,6 +1121,7 @@ ContextBar::ContextBar(TooltipManager* tooltipManager)
addChild(m_tolerance = new ToleranceField());
addChild(m_contiguous = new ContiguousField());
addChild(m_paintBucketSettings = new PaintBucketSettingsField());
+ addChild(m_gradientType = new GradientTypeField());
addChild(m_ditheringSelector = new DitheringSelector(DitheringSelector::SelectMatrix));
m_ditheringSelector->setUseCustomWidget(false); // Disable custom widget because the context bar is too small
@@ -1428,6 +1450,7 @@ void ContextBar::updateForTool(tools::Tool* tool)
m_paintBucketSettings->setVisible(hasTolerance);
m_sprayBox->setVisible(hasSprayOptions);
m_selectionOptionsBox->setVisible(hasSelectOptions);
+ m_gradientType->setVisible(withDithering);
m_ditheringSelector->setVisible(withDithering);
m_selectionMode->setVisible(true);
m_pivot->setVisible(true);
@@ -1718,6 +1741,11 @@ render::DitheringAlgorithmBase* ContextBar::ditheringAlgorithm()
return s_dither.get();
}
+render::GradientType ContextBar::gradientType()
+{
+ return m_gradientType->gradientType();
+}
+
void ContextBar::setupTooltips(TooltipManager* tooltipManager)
{
tooltipManager->addTooltipFor(m_brushBack->at(0), "Discard Brush (Esc)", BOTTOM);
@@ -1741,6 +1769,7 @@ void ContextBar::setupTooltips(TooltipManager* tooltipManager)
"Extra paint bucket options", BOTTOM);
m_selectionMode->setupTooltips(tooltipManager);
+ m_gradientType->setupTooltips(tooltipManager);
m_dropPixels->setupTooltips(tooltipManager);
m_symmetry->setupTooltips(tooltipManager);
}
diff --git a/src/app/ui/context_bar.h b/src/app/ui/context_bar.h
index 23223f282..fc360dce4 100644
--- a/src/app/ui/context_bar.h
+++ b/src/app/ui/context_bar.h
@@ -1,5 +1,5 @@
// Aseprite
-// Copyright (C) 2018 Igara Studio S.A.
+// Copyright (C) 2018-2019 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@@ -19,6 +19,7 @@
#include "obs/connection.h"
#include "obs/observable.h"
#include "obs/signal.h"
+#include "render/gradient.h"
#include "ui/box.h"
#include
@@ -48,6 +49,7 @@ namespace app {
class BrushSlot;
class DitheringSelector;
+ class GradientTypeSelector;
class ContextBar : public ui::Box
, public obs::observable
@@ -83,6 +85,7 @@ namespace app {
// For gradients
render::DitheringMatrix ditheringMatrix();
render::DitheringAlgorithmBase* ditheringAlgorithm();
+ render::GradientType gradientType();
// Signals
obs::signal BrushChange;
@@ -122,6 +125,7 @@ namespace app {
class SprayWidthField;
class SpraySpeedField;
class SelectionModeField;
+ class GradientTypeField;
class TransparentColorField;
class PivotField;
class RotAlgorithmField;
@@ -157,6 +161,7 @@ namespace app {
ui::Box* m_selectionOptionsBox;
DitheringSelector* m_ditheringSelector;
SelectionModeField* m_selectionMode;
+ GradientTypeField* m_gradientType;
TransparentColorField* m_transparentColor;
PivotField* m_pivot;
RotAlgorithmField* m_rotAlgo;
diff --git a/src/app/ui/editor/tool_loop_impl.cpp b/src/app/ui/editor/tool_loop_impl.cpp
index 4703d5e97..5e22109fb 100644
--- a/src/app/ui/editor/tool_loop_impl.cpp
+++ b/src/app/ui/editor/tool_loop_impl.cpp
@@ -330,6 +330,15 @@ public:
#endif
}
+ render::GradientType getGradientType() override {
+#ifdef ENABLE_UI // TODO add support when UI is not enabled
+ return App::instance()->contextBar()->gradientType();
+#else
+ return render::GradientType::Linear;
+#endif
+ }
+
+
};
//////////////////////////////////////////////////////////////////////
diff --git a/src/render/LICENSE.txt b/src/render/LICENSE.txt
index dce2ee200..8e8e061eb 100644
--- a/src/render/LICENSE.txt
+++ b/src/render/LICENSE.txt
@@ -1,4 +1,5 @@
-Copyright (c) 2001-2017 David Capello
+Copyright (c) 2019 Igara Studio S.A.
+Copyright (c) 2001-2018 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/gradient.cpp b/src/render/gradient.cpp
index b35e3751d..e509771c6 100644
--- a/src/render/gradient.cpp
+++ b/src/render/gradient.cpp
@@ -1,4 +1,5 @@
// Aseprite Render Library
+// Copyright (c) 2019 Igara Studio S.A.
// Copyright (c) 2017 David Capello
//
// This file is released under the terms of the MIT license.
@@ -17,6 +18,26 @@
namespace render {
+void render_rgba_gradient(
+ doc::Image* img,
+ const gfx::Point imgPos,
+ const gfx::Point p0,
+ const gfx::Point p1,
+ doc::color_t c0,
+ doc::color_t c1,
+ const render::DitheringMatrix& matrix,
+ const GradientType type)
+{
+ switch (type) {
+ case GradientType::Linear:
+ render_rgba_linear_gradient(img, imgPos, p0, p1, c0, c1, matrix);
+ break;
+ case GradientType::Radial:
+ render_rgba_radial_gradient(img, imgPos, p0, p1, c0, c1, matrix);
+ break;
+ }
+}
+
void render_rgba_linear_gradient(
doc::Image* img,
const gfx::Point imgPos,
@@ -98,7 +119,8 @@ void render_rgba_linear_gradient(
else {
for (int y=0; y q(x, y);
+ base::Vector2d q(imgPos.x+x,
+ imgPos.y+y);
q -= u;
double f = (q * w) / wmag;
@@ -108,4 +130,98 @@ void render_rgba_linear_gradient(
}
}
+void render_rgba_radial_gradient(
+ doc::Image* img,
+ const gfx::Point imgPos,
+ 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) / 2;
+
+ // 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(imgPos.x+x,
+ imgPos.y+y);
+ q -= (u+v)/2;
+ q.x /= std::fabs(w.x);
+ q.y /= std::fabs(w.y);
+ double f = std::sqrt(q.x*q.x + q.y*q.y);
+
+ 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(imgPos.x+x,
+ imgPos.y+y);
+ q -= (u+v)/2;
+ q.x /= std::fabs(w.x);
+ q.y /= std::fabs(w.y);
+ double f = std::sqrt(q.x*q.x + q.y*q.y);
+
+ *it = (f*(matrix.maxValue()+2) < matrix(y, x)+1 ? c0: c1);
+ }
+ }
+ }
+}
+
} // namespace render
diff --git a/src/render/gradient.h b/src/render/gradient.h
index 45bf0e41c..b71820f69 100644
--- a/src/render/gradient.h
+++ b/src/render/gradient.h
@@ -1,4 +1,5 @@
// Aseprite Render Library
+// Copyright (c) 2019 Igara Studio S.A.
// Copyright (c) 2017 David Capello
//
// This file is released under the terms of the MIT license.
@@ -19,6 +20,21 @@ namespace render {
class DitheringMatrix;
+enum class GradientType {
+ Linear,
+ Radial,
+};
+
+void render_rgba_gradient(
+ doc::Image* img,
+ const gfx::Point imgPos,
+ const gfx::Point p0,
+ const gfx::Point p1,
+ doc::color_t c0,
+ doc::color_t c1,
+ const render::DitheringMatrix& matrix,
+ const GradientType type);
+
void render_rgba_linear_gradient(
doc::Image* img,
const gfx::Point imgPos,
@@ -28,6 +44,15 @@ void render_rgba_linear_gradient(
doc::color_t c1,
const render::DitheringMatrix& matrix);
+void render_rgba_radial_gradient(
+ doc::Image* img,
+ const gfx::Point imgPos,
+ const gfx::Point p0,
+ const gfx::Point p1,
+ doc::color_t c0,
+ doc::color_t c1,
+ const render::DitheringMatrix& matrix);
+
} // namespace render
#endif