Fix gradient fill on tiled mode

This commit is contained in:
David Capello 2017-11-10 12:19:44 -03:00
parent ee3ade44b8
commit 392312d687
11 changed files with 138 additions and 60 deletions

View File

@ -521,6 +521,7 @@ add_library(app-lib
util/pic_file.cpp util/pic_file.cpp
util/pixel_ratio.cpp util/pixel_ratio.cpp
util/range_utils.cpp util/range_utils.cpp
util/wrap_point.cpp
webserver.cpp webserver.cpp
widget_loader.cpp widget_loader.cpp
xml_document.cpp xml_document.cpp

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2016 David Capello // Copyright (C) 2001-2017 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -12,7 +12,7 @@
#include "app/document.h" #include "app/document.h"
#include "app/pref/preferences.h" #include "app/pref/preferences.h"
#include "app/util/wrap_value.h" #include "app/util/wrap_point.h"
#include "doc/cel.h" #include "doc/cel.h"
#include "doc/image.h" #include "doc/image.h"
#include "doc/primitives.h" #include "doc/primitives.h"
@ -76,11 +76,8 @@ void ColorPicker::pickColor(const doc::Site& site,
const app::Document* doc = static_cast<const app::Document*>(site.document()); const app::Document* doc = static_cast<const app::Document*>(site.document());
DocumentPreferences& docPref = Preferences::instance().document(doc); DocumentPreferences& docPref = Preferences::instance().document(doc);
if (int(docPref.tiled.mode()) & int(filters::TiledMode::X_AXIS)) pos = wrap_pointF(docPref.tiled.mode(),
pos.x = wrap_value<double>(pos.x, site.sprite()->width()); site.sprite()->size(), pos);
if (int(docPref.tiled.mode()) & int(filters::TiledMode::Y_AXIS))
pos.y = wrap_value<double>(pos.y, site.sprite()->height());
} }
// Get the color from the image // Get the color from the image

View File

@ -5,6 +5,8 @@
// 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 "app/util/wrap_point.h"
#include "app/util/wrap_value.h"
#include "base/unique_ptr.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"
@ -638,29 +640,17 @@ public:
private: private:
void pickColorFromArea(int x, int y) { void pickColorFromArea(int x, int y) {
int u = x + (rand() % 3)-1 - m_speed.x; gfx::Point pt(x + (rand() % 3)-1 - m_speed.x,
int v = y + (rand() % 3)-1 - m_speed.y; y + (rand() % 3)-1 - m_speed.y);
if (int(m_tiledMode) & int(TiledMode::X_AXIS)) { pt = wrap_point(m_tiledMode,
if (u < 0) gfx::Size(m_srcImageWidth,
u = m_srcImageWidth - (-(u+1) % m_srcImageWidth) - 1; m_srcImageHeight), pt);
else if (u >= m_srcImageWidth)
u %= m_srcImageWidth;
}
else {
u = MID(0, u, m_srcImageWidth-1);
}
if (int(m_tiledMode) & int(TiledMode::Y_AXIS)) { pt.x = MID(0, pt.x, m_srcImageWidth-1);
if (v < 0) pt.y = MID(0, pt.y, m_srcImageHeight-1);
v = m_srcImageHeight - (-(v+1) % m_srcImageHeight) - 1;
else if (v >= m_srcImageHeight) m_color = get_pixel(m_srcImage, pt.x, pt.y);
v %= m_srcImageHeight;
}
else {
v = MID(0, v, m_srcImageHeight-1);
}
m_color = get_pixel(m_srcImage, u, v);
} }
const Palette* m_palette; const Palette* m_palette;
@ -878,7 +868,9 @@ static ImageBufferPtr tmpGradientBuffer; // TODO non-thread safe
class GradientRenderer { class GradientRenderer {
public: public:
GradientRenderer(ToolLoop* loop) { GradientRenderer(ToolLoop* loop)
: m_tiledMode(loop->getTiledMode())
{
if (!tmpGradientBuffer) if (!tmpGradientBuffer)
tmpGradientBuffer.reset(new ImageBuffer(1)); tmpGradientBuffer.reset(new ImageBuffer(1));
@ -898,17 +890,32 @@ public:
return; return;
} }
const gfx::Point u = strokes[0].firstPoint();
const gfx::Point v = strokes[0].lastPoint();
// The image position for the gradient depends on the first user
// click. The gradient depends on the first clicked tile.
gfx::Point imgPos(0, 0);
if (int(m_tiledMode) & int(TiledMode::X_AXIS)) {
const int w = loop->sprite()->width();
imgPos.x = u.x / w;
imgPos.x *= w;
}
if (int(m_tiledMode) & int(TiledMode::Y_AXIS)) {
const int h = loop->sprite()->height();
imgPos.y = u.y / h;
imgPos.y *= h;
}
render::render_rgba_linear_gradient( render::render_rgba_linear_gradient(
m_tmpImage.get(), m_tmpImage.get(), imgPos, u, v, c0, c1,
strokes[0].firstPoint(),
strokes[0].lastPoint(),
c0, c1,
loop->getDitheringMatrix()); loop->getDitheringMatrix());
} }
protected: protected:
ImageRef m_tmpImage; ImageRef m_tmpImage;
RgbTraits::address_t m_tmpAddress; RgbTraits::address_t m_tmpAddress;
TiledMode m_tiledMode;
}; };
template<typename ImageTraits> template<typename ImageTraits>

View File

@ -4,6 +4,8 @@
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
#include "app/util/wrap_point.h"
namespace app { namespace app {
namespace tools { namespace tools {
@ -88,30 +90,17 @@ public:
void transformPoint(ToolLoop* loop, int x, int y) override { void transformPoint(ToolLoop* loop, int x, int y) override {
const doc::Image* srcImage = loop->getFloodFillSrcImage(); const doc::Image* srcImage = loop->getFloodFillSrcImage();
filters::TiledMode tiledMode = loop->getTiledMode(); gfx::Point pt = wrap_point(loop->getTiledMode(),
const bool xTiled = ((int(tiledMode) & int(filters::TiledMode::X_AXIS)) ? true: false); gfx::Size(srcImage->width(),
const bool yTiled = ((int(tiledMode) & int(filters::TiledMode::Y_AXIS)) ? true: false); srcImage->height()),
const int w = srcImage->width(); gfx::Point(x, y));
const int h = srcImage->height();
if (xTiled) {
if (x < 0)
x = (w - (-x % w));
x %= w;
}
if (yTiled) {
if (y < 0)
y = (h - (-y % h));
y %= h;
}
doc::algorithm::floodfill( doc::algorithm::floodfill(
srcImage, srcImage,
(loop->useMask() ? loop->getMask(): nullptr), (loop->useMask() ? loop->getMask(): nullptr),
x, y, pt.x, pt.y,
floodfillBounds(loop, x, y), floodfillBounds(loop, pt.x, pt.y),
get_pixel(srcImage, x, y), get_pixel(srcImage, pt.x, pt.y),
loop->getTolerance(), loop->getTolerance(),
loop->getContiguous(), loop->getContiguous(),
loop, (AlgoHLine)doInkHline); loop, (AlgoHLine)doInkHline);

View File

@ -86,6 +86,7 @@ private:
render_rgba_linear_gradient( render_rgba_linear_gradient(
image1.get(), image1.get(),
gfx::Point(0, 0), gfx::Point(0, 0),
gfx::Point(0, 0),
gfx::Point(w-1, 0), gfx::Point(w-1, 0),
doc::rgba(0, 0, 0, 255), doc::rgba(0, 0, 0, 255),
doc::rgba(255, 255, 255, 255), doc::rgba(255, 255, 255, 255),

View File

@ -24,6 +24,7 @@
#include "app/ui/editor/editor.h" #include "app/ui/editor/editor.h"
#include "app/ui/editor/tool_loop_impl.h" #include "app/ui/editor/tool_loop_impl.h"
#include "app/ui_context.h" #include "app/ui_context.h"
#include "app/util/wrap_value.h"
#include "doc/algo.h" #include "doc/algo.h"
#include "doc/blend_internals.h" #include "doc/blend_internals.h"
#include "doc/brush.h" #include "doc/brush.h"
@ -186,9 +187,7 @@ void BrushPreview::show(const gfx::Point& screenPos)
// Tiled mode might require a bigger extra cel (to show the tiled) // Tiled mode might require a bigger extra cel (to show the tiled)
if (int(m_editor->docPref().tiled.mode()) & int(filters::TiledMode::X_AXIS)) { if (int(m_editor->docPref().tiled.mode()) & int(filters::TiledMode::X_AXIS)) {
if (brushBounds.x < 0) brushBounds.x = wrap_value(brushBounds.x, sprite->width());
brushBounds.x = (sprite->width() - (-brushBounds.x % sprite->width()));
brushBounds.x %= sprite->width();
extraCelBounds.x = brushBounds.x; extraCelBounds.x = brushBounds.x;
if ((extraCelBounds.x < 0 && extraCelBounds.x2() > 0) || if ((extraCelBounds.x < 0 && extraCelBounds.x2() > 0) ||
(extraCelBounds.x < sprite->width() && extraCelBounds.x2() > sprite->width())) { (extraCelBounds.x < sprite->width() && extraCelBounds.x2() > sprite->width())) {
@ -197,9 +196,7 @@ void BrushPreview::show(const gfx::Point& screenPos)
} }
} }
if (int(m_editor->docPref().tiled.mode()) & int(filters::TiledMode::Y_AXIS)) { if (int(m_editor->docPref().tiled.mode()) & int(filters::TiledMode::Y_AXIS)) {
if (brushBounds.y < 0) brushBounds.y = wrap_value(brushBounds.y, sprite->height());
brushBounds.y = (sprite->height() - (-brushBounds.y % sprite->height()));
brushBounds.y %= sprite->height();
extraCelBounds.y = brushBounds.y; extraCelBounds.y = brushBounds.y;
if ((extraCelBounds.y < 0 && extraCelBounds.y2() > 0) || if ((extraCelBounds.y < 0 && extraCelBounds.y2() > 0) ||
(extraCelBounds.y < sprite->height() && extraCelBounds.y2() > sprite->height())) { (extraCelBounds.y < sprite->height() && extraCelBounds.y2() > sprite->height())) {

View File

@ -0,0 +1,55 @@
// Aseprite
// Copyright (C) 2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/util/wrap_point.h"
#include "app/util/wrap_value.h"
namespace app {
gfx::Point wrap_point(const filters::TiledMode tiledMode,
const gfx::Size& spriteSize,
const gfx::Point& pt)
{
gfx::Point out;
if (int(tiledMode) & int(filters::TiledMode::X_AXIS))
out.x = wrap_value(pt.x, spriteSize.w);
else
out.x = pt.x;
if (int(tiledMode) & int(filters::TiledMode::Y_AXIS))
out.y = wrap_value(pt.y, spriteSize.h);
else
out.y = pt.y;
return out;
}
gfx::PointF wrap_pointF(const filters::TiledMode tiledMode,
const gfx::Size& spriteSize,
const gfx::PointF& pt)
{
gfx::PointF out;
if (int(tiledMode) & int(filters::TiledMode::X_AXIS))
out.x = wrap_value<double>(pt.x, spriteSize.w);
else
out.x = pt.x;
if (int(tiledMode) & int(filters::TiledMode::Y_AXIS))
out.y = wrap_value<double>(pt.y, spriteSize.h);
else
out.y = pt.y;
return out;
}
} // namespace app

27
src/app/util/wrap_point.h Normal file
View File

@ -0,0 +1,27 @@
// Aseprite
// Copyright (C) 2017 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_WRAP_POINT_H_INCLUDED
#define APP_WRAP_POINT_H_INCLUDED
#pragma once
#include "filters/tiled_mode.h"
#include "gfx/point.h"
#include "gfx/size.h"
namespace app {
gfx::Point wrap_point(const filters::TiledMode tiledMode,
const gfx::Size& spriteSize,
const gfx::Point& pt);
gfx::PointF wrap_pointF(const filters::TiledMode tiledMode,
const gfx::Size& spriteSize,
const gfx::PointF& pt);
} // namespace app
#endif

View File

@ -68,6 +68,7 @@ namespace doc {
PixelFormat pixelFormat() const { return (PixelFormat)m_spec.colorMode(); } PixelFormat pixelFormat() const { return (PixelFormat)m_spec.colorMode(); }
const PixelRatio& pixelRatio() const { return m_pixelRatio; } const PixelRatio& pixelRatio() const { return m_pixelRatio; }
gfx::Size size() const { return m_spec.size(); }
gfx::Rect bounds() const { return m_spec.bounds(); } gfx::Rect bounds() const { return m_spec.bounds(); }
int width() const { return m_spec.width(); } int width() const { return m_spec.width(); }
int height() const { return m_spec.height(); } int height() const { return m_spec.height(); }

View File

@ -19,6 +19,7 @@ namespace render {
void render_rgba_linear_gradient( void render_rgba_linear_gradient(
doc::Image* img, doc::Image* img,
const gfx::Point imgPos,
const gfx::Point p0, const gfx::Point p0,
const gfx::Point p1, const gfx::Point p1,
doc::color_t c0, doc::color_t c0,
@ -75,7 +76,8 @@ void render_rgba_linear_gradient(
if (matrix.rows() == 1 && matrix.cols() == 1) { if (matrix.rows() == 1 && matrix.cols() == 1) {
for (int y=0; y<height; ++y) { for (int y=0; y<height; ++y) {
for (int x=0; x<width; ++x, ++it) { for (int x=0; x<width; ++x, ++it) {
base::Vector2d<double> q(x, y); base::Vector2d<double> q(imgPos.x+x,
imgPos.y+y);
q -= u; q -= u;
double f = (q * w) / wmag; double f = (q * w) / wmag;

View File

@ -21,6 +21,7 @@ class DitheringMatrix;
void render_rgba_linear_gradient( void render_rgba_linear_gradient(
doc::Image* img, doc::Image* img,
const gfx::Point imgPos,
const gfx::Point p0, const gfx::Point p0,
const gfx::Point p1, const gfx::Point p1,
doc::color_t c0, doc::color_t c0,