mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-11 18:41:05 +00:00
Related to this bug report: https://community.aseprite.org/t/1045
This commit is contained in:
parent
8106aeee44
commit
7c2038e7b5
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2018 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -10,6 +11,7 @@
|
|||||||
|
|
||||||
#include "app/tools/intertwine.h"
|
#include "app/tools/intertwine.h"
|
||||||
|
|
||||||
|
#include "app/tools/controller.h"
|
||||||
#include "app/tools/point_shape.h"
|
#include "app/tools/point_shape.h"
|
||||||
#include "app/tools/stroke.h"
|
#include "app/tools/stroke.h"
|
||||||
#include "app/tools/symmetry.h"
|
#include "app/tools/symmetry.h"
|
||||||
@ -52,12 +54,23 @@ void Intertwine::doPointshapePoint(int x, int y, ToolLoop* loop)
|
|||||||
|
|
||||||
void Intertwine::doPointshapeHline(int x1, int y, int x2, ToolLoop* loop)
|
void Intertwine::doPointshapeHline(int x1, int y, int x2, ToolLoop* loop)
|
||||||
{
|
{
|
||||||
algo_line(x1, y, x2, y, loop, (AlgoPixel)doPointshapePoint);
|
algo_line_perfect(x1, y, x2, y, loop, (AlgoPixel)doPointshapePoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Intertwine::doPointshapeLine(int x1, int y1, int x2, int y2, ToolLoop* loop)
|
void Intertwine::doPointshapeLine(int x1, int y1, int x2, int y2, ToolLoop* loop)
|
||||||
{
|
{
|
||||||
algo_line(x1, y1, x2, y2, loop, (AlgoPixel)doPointshapePoint);
|
if (// When "Snap Angle" in being used or...
|
||||||
|
(int(loop->getModifiers()) & int(ToolLoopModifiers::kSquareAspect)) ||
|
||||||
|
// "Snap to Grid" is enabled
|
||||||
|
(loop->getController()->canSnapToGrid() && loop->getSnapToGrid())) {
|
||||||
|
// We prefer the perfect pixel lines that matches grid tiles
|
||||||
|
algo_line_perfect(x1, y1, x2, y2, loop, (AlgoPixel)doPointshapePoint);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// In other case we use the regular algorithm that is useful to
|
||||||
|
// draw continuous lines/strokes.
|
||||||
|
algo_line_continuous(x1, y1, x2, y2, loop, (AlgoPixel)doPointshapePoint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tools
|
} // namespace tools
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
|
// Copyright (C) 2018 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
@ -57,15 +58,15 @@ public:
|
|||||||
int x2 = stroke[c+1].x;
|
int x2 = stroke[c+1].x;
|
||||||
int y2 = stroke[c+1].y;
|
int y2 = stroke[c+1].y;
|
||||||
|
|
||||||
algo_line(x1, y1, x2, y2, loop, (AlgoPixel)doPointshapePoint);
|
doPointshapeLine(x1, y1, x2, y2, loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Closed shape (polygon outline)
|
// Closed shape (polygon outline)
|
||||||
if (loop->getFilled()) {
|
if (loop->getFilled()) {
|
||||||
algo_line(stroke[0].x, stroke[0].y,
|
doPointshapeLine(stroke[0].x, stroke[0].y,
|
||||||
stroke[stroke.size()-1].x,
|
stroke[stroke.size()-1].x,
|
||||||
stroke[stroke.size()-1].y, loop, (AlgoPixel)doPointshapePoint);
|
stroke[stroke.size()-1].y, loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,20 +309,22 @@ public:
|
|||||||
doPointshapePoint(stroke[c].x, stroke[c].y, loop);
|
doPointshapePoint(stroke[c].x, stroke[c].y, loop);
|
||||||
}
|
}
|
||||||
else if (stroke.size()-c == 2) {
|
else if (stroke.size()-c == 2) {
|
||||||
algo_line(stroke[c].x, stroke[c].y,
|
doPointshapeLine(stroke[c].x, stroke[c].y,
|
||||||
stroke[c+1].x, stroke[c+1].y, loop, (AlgoPixel)doPointshapePoint);
|
stroke[c+1].x, stroke[c+1].y, loop);
|
||||||
}
|
}
|
||||||
else if (stroke.size()-c == 3) {
|
else if (stroke.size()-c == 3) {
|
||||||
algo_spline(stroke[c ].x, stroke[c ].y,
|
algo_spline(stroke[c ].x, stroke[c ].y,
|
||||||
stroke[c+1].x, stroke[c+1].y,
|
stroke[c+1].x, stroke[c+1].y,
|
||||||
stroke[c+1].x, stroke[c+1].y,
|
stroke[c+1].x, stroke[c+1].y,
|
||||||
stroke[c+2].x, stroke[c+2].y, loop, (AlgoLine)doPointshapeLine);
|
stroke[c+2].x, stroke[c+2].y, loop,
|
||||||
|
(AlgoLine)doPointshapeLine);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
algo_spline(stroke[c ].x, stroke[c ].y,
|
algo_spline(stroke[c ].x, stroke[c ].y,
|
||||||
stroke[c+1].x, stroke[c+1].y,
|
stroke[c+1].x, stroke[c+1].y,
|
||||||
stroke[c+2].x, stroke[c+2].y,
|
stroke[c+2].x, stroke[c+2].y,
|
||||||
stroke[c+3].x, stroke[c+3].y, loop, (AlgoLine)doPointshapeLine);
|
stroke[c+3].x, stroke[c+3].y, loop,
|
||||||
|
(AlgoLine)doPointshapeLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -363,12 +366,16 @@ public:
|
|||||||
|
|
||||||
if (stroke.size() == 0)
|
if (stroke.size() == 0)
|
||||||
return;
|
return;
|
||||||
|
else if (stroke.size() == 2) {
|
||||||
|
doPointshapeLine(stroke[0].x, stroke[0].y,
|
||||||
|
stroke[1].x, stroke[1].y, loop);
|
||||||
|
}
|
||||||
else if (m_pts.empty() && stroke.size() == 1) {
|
else if (m_pts.empty() && stroke.size() == 1) {
|
||||||
m_pts = stroke;
|
m_pts = stroke;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (int c=0; c+1<stroke.size(); ++c) {
|
for (int c=0; c+1<stroke.size(); ++c) {
|
||||||
algo_line(
|
algo_line_continuous(
|
||||||
stroke[c].x,
|
stroke[c].x,
|
||||||
stroke[c].y,
|
stroke[c].y,
|
||||||
stroke[c+1].x,
|
stroke[c+1].x,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
|
// Copyright (C) 2018 Igara Studio S.A.
|
||||||
// Copyright (c) 2001-2018 David Capello
|
// Copyright (c) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -20,7 +21,7 @@
|
|||||||
|
|
||||||
namespace doc {
|
namespace doc {
|
||||||
|
|
||||||
void algo_line(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc)
|
void algo_line_perfect(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc)
|
||||||
{
|
{
|
||||||
bool yaxis;
|
bool yaxis;
|
||||||
|
|
||||||
@ -64,6 +65,32 @@ void algo_line(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Line code based on Alois Zingl work released under the
|
||||||
|
// MIT license http://members.chello.at/easyfilter/bresenham.html
|
||||||
|
void algo_line_continuous(int x0, int y0, int x1, int y1, void* data, AlgoPixel proc)
|
||||||
|
{
|
||||||
|
int dx = ABS(x1-x0), sx = (x0 < x1 ? 1: -1);
|
||||||
|
int dy = -ABS(y1-y0), sy = (y0 < y1 ? 1: -1);
|
||||||
|
int err = dx+dy, e2; // error value e_xy
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
proc(x0, y0, data);
|
||||||
|
e2 = 2*err;
|
||||||
|
if (e2 >= dy) { // e_xy+e_x > 0
|
||||||
|
if (x0 == x1)
|
||||||
|
break;
|
||||||
|
err += dy;
|
||||||
|
x0 += sx;
|
||||||
|
}
|
||||||
|
if (e2 <= dx) { // e_xy+e_y < 0
|
||||||
|
if (y0 == y1)
|
||||||
|
break;
|
||||||
|
err += dx;
|
||||||
|
y0 += sy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Additional helper functions for the ellipse-drawing helper function
|
/* Additional helper functions for the ellipse-drawing helper function
|
||||||
below corresponding to routines in Bresenham's algorithm. */
|
below corresponding to routines in Bresenham's algorithm. */
|
||||||
namespace {
|
namespace {
|
||||||
@ -132,11 +159,11 @@ void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc)
|
|||||||
rx = ABS(x1 - x2);
|
rx = ABS(x1 - x2);
|
||||||
ry = ABS(y1 - y2);
|
ry = ABS(y1 - y2);
|
||||||
|
|
||||||
if (rx == 1) { algo_line(x2, y1, x2, y2, data, proc); rx--; }
|
if (rx == 1) { algo_line_perfect(x2, y1, x2, y2, data, proc); rx--; }
|
||||||
if (rx == 0) { algo_line(x1, y1, x1, y2, data, proc); return; }
|
if (rx == 0) { algo_line_perfect(x1, y1, x1, y2, data, proc); return; }
|
||||||
|
|
||||||
if (ry == 1) { algo_line(x1, y2, x2, y2, data, proc); ry--; }
|
if (ry == 1) { algo_line_perfect(x1, y2, x2, y2, data, proc); ry--; }
|
||||||
if (ry == 0) { algo_line(x1, y1, x2, y1, data, proc); return; }
|
if (ry == 0) { algo_line_perfect(x1, y1, x2, y1, data, proc); return; }
|
||||||
|
|
||||||
rx /= 2;
|
rx /= 2;
|
||||||
ry /= 2;
|
ry /= 2;
|
||||||
@ -316,7 +343,7 @@ static void draw_quad_rational_bezier_seg(int x0, int y0,
|
|||||||
}
|
}
|
||||||
} while (dy <= xy && dx >= xy); // gradient negates -> algorithm fails
|
} while (dy <= xy && dx >= xy); // gradient negates -> algorithm fails
|
||||||
}
|
}
|
||||||
algo_line(x0, y0, x2, y2, data, proc); // plot remaining needle to end
|
algo_line_continuous(x0, y0, x2, y2, data, proc); // plot remaining needle to end
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_rotated_ellipse_rect(int x0, int y0, int x1, int y1, double zd, void* data, AlgoPixel proc)
|
static void draw_rotated_ellipse_rect(int x0, int y0, int x1, int y1, double zd, void* data, AlgoPixel proc)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
|
// Copyright (C) 2018 Igara Studio S.A.
|
||||||
// Copyright (c) 2001-2018 David Capello
|
// Copyright (c) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
@ -18,7 +19,22 @@ namespace doc {
|
|||||||
typedef void (*AlgoPixel)(int x, int y, void *data);
|
typedef void (*AlgoPixel)(int x, int y, void *data);
|
||||||
typedef void (*AlgoLine)(int x1, int y1, int x2, int y2, void *data);
|
typedef void (*AlgoLine)(int x1, int y1, int x2, int y2, void *data);
|
||||||
|
|
||||||
void algo_line(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc);
|
// Useful to create lines with more predictable behavior and perfect
|
||||||
|
// pixel block of lines where we'll have a number of lines/rows that
|
||||||
|
// looks the same.
|
||||||
|
//
|
||||||
|
// Related to: https://github.com/aseprite/aseprite/issues/1395
|
||||||
|
void algo_line_perfect(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc);
|
||||||
|
|
||||||
|
// Useful to create continuous lines (you can draw from one point to
|
||||||
|
// another, and continue from that point to another in the same
|
||||||
|
// angle and the line will look continous).
|
||||||
|
//
|
||||||
|
// Related to:
|
||||||
|
// https://community.aseprite.org/t/1045
|
||||||
|
// https://github.com/aseprite/aseprite/issues/1894
|
||||||
|
void algo_line_continuous(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc);
|
||||||
|
|
||||||
void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc);
|
void algo_ellipse(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc);
|
||||||
void algo_ellipsefill(int x1, int y1, int x2, int y2, void *data, AlgoHLine proc);
|
void algo_ellipsefill(int x1, int y1, int x2, int y2, void *data, AlgoHLine proc);
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ static void hline_for_image(int x1, int y, int x2, Data* data)
|
|||||||
void draw_line(Image* image, int x1, int y1, int x2, int y2, color_t color)
|
void draw_line(Image* image, int x1, int y1, int x2, int y2, color_t color)
|
||||||
{
|
{
|
||||||
Data data = { image, color };
|
Data data = { image, color };
|
||||||
algo_line(x1, y1, x2, y2, &data, (AlgoPixel)pixel_for_image);
|
algo_line_continuous(x1, y1, x2, y2, &data, (AlgoPixel)pixel_for_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t color)
|
void draw_ellipse(Image* image, int x1, int y1, int x2, int y2, color_t color)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user