mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-30 13:20:28 +00:00
Fix gradient fill on tiled mode
This commit is contained in:
parent
ee3ade44b8
commit
392312d687
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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())) {
|
||||
|
55
src/app/util/wrap_point.cpp
Normal file
55
src/app/util/wrap_point.cpp
Normal 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
27
src/app/util/wrap_point.h
Normal 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
|
@ -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(); }
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user