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/pixel_ratio.cpp
util/range_utils.cpp
util/wrap_point.cpp
webserver.cpp
widget_loader.cpp
xml_document.cpp

View File

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

View File

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

View File

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

View File

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

View File

@ -24,6 +24,7 @@
#include "app/ui/editor/editor.h"
#include "app/ui/editor/tool_loop_impl.h"
#include "app/ui_context.h"
#include "app/util/wrap_value.h"
#include "doc/algo.h"
#include "doc/blend_internals.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)
if (int(m_editor->docPref().tiled.mode()) & int(filters::TiledMode::X_AXIS)) {
if (brushBounds.x < 0)
brushBounds.x = (sprite->width() - (-brushBounds.x % sprite->width()));
brushBounds.x %= sprite->width();
brushBounds.x = wrap_value(brushBounds.x, sprite->width());
extraCelBounds.x = brushBounds.x;
if ((extraCelBounds.x < 0 && extraCelBounds.x2() > 0) ||
(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 (brushBounds.y < 0)
brushBounds.y = (sprite->height() - (-brushBounds.y % sprite->height()));
brushBounds.y %= sprite->height();
brushBounds.y = wrap_value(brushBounds.y, sprite->height());
extraCelBounds.y = brushBounds.y;
if ((extraCelBounds.y < 0 && extraCelBounds.y2() > 0) ||
(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(); }
const PixelRatio& pixelRatio() const { return m_pixelRatio; }
gfx::Size size() const { return m_spec.size(); }
gfx::Rect bounds() const { return m_spec.bounds(); }
int width() const { return m_spec.width(); }
int height() const { return m_spec.height(); }

View File

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

View File

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