mirror of https://github.com/aseprite/aseprite.git
Fix rounded rect drawing with max corner radius
This commit is contained in:
parent
8ff57810a9
commit
7e8ccb55b8
|
@ -149,7 +149,7 @@ public:
|
||||||
private:
|
private:
|
||||||
static int maxRadius(const Stroke& stroke)
|
static int maxRadius(const Stroke& stroke)
|
||||||
{
|
{
|
||||||
return std::min(ABS(stroke[1].x - stroke[0].x), ABS(stroke[1].y - stroke[0].y)) / 2;
|
return std::min(ABS(stroke[1].x - stroke[0].x + 1), ABS(stroke[1].y - stroke[0].y + 1)) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool m_modifying = false;
|
bool m_modifying = false;
|
||||||
|
|
|
@ -160,13 +160,19 @@ doc::AlgoLineWithAlgoPixel Intertwine::getLineAlgo(ToolLoop* loop,
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Intertwine::doPointshapeCircle(int xm, int ym, int r, int sx, int sy, ToolLoop* loop, bool fill)
|
void Intertwine::doPointshapeSlicedCircle(int x1,
|
||||||
|
int y1,
|
||||||
|
int x2,
|
||||||
|
int y2,
|
||||||
|
int r,
|
||||||
|
ToolLoop* loop,
|
||||||
|
bool fill)
|
||||||
{
|
{
|
||||||
if (fill) {
|
if (fill) {
|
||||||
algo_circlefill(xm, ym, sx, sy, r, loop, (AlgoHLine)doPointshapeHline);
|
algo_sliced_circlefill(x1, y1, x2, y2, r, loop, (AlgoHLine)doPointshapeHline);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
algo_circle(xm, ym, sx, sy, r, loop, (AlgoPixel)doPointshapePoint);
|
algo_sliced_circle(x1, y1, x2, y2, r, loop, (AlgoPixel)doPointshapePoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,13 @@ protected:
|
||||||
const Stroke::Pt& a,
|
const Stroke::Pt& a,
|
||||||
const Stroke::Pt& b);
|
const Stroke::Pt& b);
|
||||||
|
|
||||||
static void
|
static void doPointshapeSlicedCircle(int x1,
|
||||||
doPointshapeCircle(int xm, int ym, int r, int sx, int sy, ToolLoop* loop, bool fill = false);
|
int y1,
|
||||||
|
int x2,
|
||||||
|
int y2,
|
||||||
|
int r,
|
||||||
|
ToolLoop* loop,
|
||||||
|
bool fill = false);
|
||||||
|
|
||||||
static void doPointshapeArc(int xm, int ym, double sa, double ea, int r, ToolLoop* loop);
|
static void doPointshapeArc(int xm, int ym, double sa, double ea, int r, ToolLoop* loop);
|
||||||
};
|
};
|
||||||
|
|
|
@ -197,12 +197,10 @@ public:
|
||||||
if (ABS(angle) < 0.001) {
|
if (ABS(angle) < 0.001) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
if (cornerRadius > 0) {
|
if (cornerRadius > 0) {
|
||||||
int w = x2 - x1;
|
int w = x2 - x1 + 1;
|
||||||
int h = y2 - y1;
|
int h = y2 - y1 + 1;
|
||||||
int xm = x1 + w / 2;
|
|
||||||
int ym = y1 + h / 2;
|
|
||||||
r = std::min(w, std::min(h, 2 * cornerRadius)) / 2;
|
r = std::min(w, std::min(h, 2 * cornerRadius)) / 2;
|
||||||
doPointshapeCircle(xm, ym, r, w - r * 2, h - r * 2, loop);
|
doPointshapeSlicedCircle(x1, y1, x2, y2, r, loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
doPointshapeLineWithoutDynamics(x1 + r, y1, x2 - r, y1, loop);
|
doPointshapeLineWithoutDynamics(x1 + r, y1, x2 - r, y1, loop);
|
||||||
|
@ -223,8 +221,8 @@ public:
|
||||||
doPointshapeLine(p[n - 1], p[0], loop);
|
doPointshapeLine(p[n - 1], p[0], loop);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int w = x2 - x1;
|
int w = x2 - x1 + 1;
|
||||||
int h = y2 - y1;
|
int h = y2 - y1 + 1;
|
||||||
int r = std::min(w, std::min(h, 2 * cornerRadius)) / 2;
|
int r = std::min(w, std::min(h, 2 * cornerRadius)) / 2;
|
||||||
Stroke p = rotateRectangle(x1, y1, x2, y2, angle, r);
|
Stroke p = rotateRectangle(x1, y1, x2, y2, angle, r);
|
||||||
int n = p.size();
|
int n = p.size();
|
||||||
|
@ -268,12 +266,10 @@ public:
|
||||||
if (ABS(angle) < 0.001) {
|
if (ABS(angle) < 0.001) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
if (cornerRadius > 0) {
|
if (cornerRadius > 0) {
|
||||||
int w = x2 - x1;
|
int w = x2 - x1 + 1;
|
||||||
int h = y2 - y1;
|
int h = y2 - y1 + 1;
|
||||||
int xm = x1 + w / 2;
|
|
||||||
int ym = y1 + h / 2;
|
|
||||||
r = std::min(w, std::min(h, 2 * cornerRadius)) / 2;
|
r = std::min(w, std::min(h, 2 * cornerRadius)) / 2;
|
||||||
doPointshapeCircle(xm, ym, r, w - r * 2, h - r * 2, loop, true);
|
doPointshapeSlicedCircle(x1, y1, x2, y2, r, loop, true);
|
||||||
|
|
||||||
for (y = y1; y < y1 + r; y++)
|
for (y = y1; y < y1 + r; y++)
|
||||||
doPointshapeLineWithoutDynamics(x1 + r, y, x2 - r, y, loop);
|
doPointshapeLineWithoutDynamics(x1 + r, y, x2 - r, y, loop);
|
||||||
|
@ -291,16 +287,22 @@ public:
|
||||||
doc::algorithm::polygon(v.size() / 2, &v[0], loop, (AlgoHLine)doPointshapeHline);
|
doc::algorithm::polygon(v.size() / 2, &v[0], loop, (AlgoHLine)doPointshapeHline);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int w = x2 - x1;
|
int w = x2 - x1 + 1;
|
||||||
int h = y2 - y1;
|
int h = y2 - y1 + 1;
|
||||||
int r = std::min(w, std::min(h, 2 * cornerRadius)) / 2;
|
int r = std::min(w, std::min(h, 2 * cornerRadius)) / 2;
|
||||||
Stroke p = rotateRectangle(x1, y1, x2, y2, angle, cornerRadius);
|
Stroke p = rotateRectangle(x1, y1, x2, y2, angle, cornerRadius);
|
||||||
auto v = p.toXYInts();
|
auto v = p.toXYInts();
|
||||||
doc::algorithm::polygon(v.size() / 2, &v[0], loop, (AlgoHLine)doPointshapeHline);
|
doc::algorithm::polygon(v.size() / 2, &v[0], loop, (AlgoHLine)doPointshapeHline);
|
||||||
doPointshapeCircle(p[2].x, p[2].y, r, 0, 0, loop, true);
|
doPointshapeSlicedCircle(p[2].x - r, p[2].y - r, p[2].x + r, p[2].y + r, r, loop, true);
|
||||||
doPointshapeCircle(p[5].x, p[5].y, r, 0, 0, loop, true);
|
doPointshapeSlicedCircle(p[5].x - r, p[5].y - r, p[5].x + r, p[5].y + r, r, loop, true);
|
||||||
doPointshapeCircle(p[8].x, p[8].y, r, 0, 0, loop, true);
|
doPointshapeSlicedCircle(p[8].x - r, p[8].y - r, p[8].x + r, p[8].y + r, r, loop, true);
|
||||||
doPointshapeCircle(p[11].x, p[11].y, r, 0, 0, loop, true);
|
doPointshapeSlicedCircle(p[11].x - r,
|
||||||
|
p[11].y - r,
|
||||||
|
p[11].x + r,
|
||||||
|
p[11].y + r,
|
||||||
|
r,
|
||||||
|
loop,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
// Copyright (c) 2018-2022 Igara Studio S.A.
|
// Copyright (c) 2018-2025 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.
|
||||||
|
@ -186,40 +186,30 @@ void algo_line_continuous_with_fix_for_line_brush(int x0,
|
||||||
//
|
//
|
||||||
// Adapted for Aseprite by Igara Studio S.A.
|
// Adapted for Aseprite by Igara Studio S.A.
|
||||||
//
|
//
|
||||||
// Draws a circle divided in 4 parts, separated sx pixels horizontally and sy
|
// Draws a circle of the specified radius divided in 4 slices, adjusting each
|
||||||
// pixels vertically:
|
// slice inside the specified rectangle.
|
||||||
// |---sx---|
|
// |--r --|
|
||||||
//
|
//
|
||||||
// OOO OOO
|
// x1,y1 --> * OOO OOO
|
||||||
// O O
|
// O O
|
||||||
// O O
|
// O O
|
||||||
// T
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// sy xm,xy
|
|
||||||
// |
|
|
||||||
// |
|
|
||||||
// _
|
|
||||||
// O O
|
|
||||||
// O O
|
|
||||||
// OOO OOO
|
|
||||||
//
|
//
|
||||||
// If sx and sy are 0, it draws a regular circle.
|
//
|
||||||
void algo_circle(int xm, int ym, int sx, int sy, int r, void* data, AlgoPixel proc)
|
//
|
||||||
|
// T O O
|
||||||
|
// r | O O
|
||||||
|
// _ OOO OOO * <-- x2,y2
|
||||||
|
//
|
||||||
|
// If the rectangle is smaller than the circle, it doesn't make any clipping.
|
||||||
|
void algo_sliced_circle(int x1, int y1, int x2, int y2, int r, void* data, AlgoPixel proc)
|
||||||
{
|
{
|
||||||
int x = -r, y = 0, err = 2 - 2 * r; /* II. Quadrant */
|
int x = -r, y = 0, err = 2 - 2 * r; /* II. Quadrant */
|
||||||
sx = sx < 0 ? 0 : sx;
|
const int r0 = r;
|
||||||
sy = sy < 0 ? 0 : sy;
|
|
||||||
int offsetx = sx / 2;
|
|
||||||
int offsety = sy / 2;
|
|
||||||
// Fix the position when sx or sy are not even.
|
|
||||||
int fixx = sx - 2 * offsetx;
|
|
||||||
int fixy = sy - 2 * offsety;
|
|
||||||
do {
|
do {
|
||||||
proc(xm - x + offsetx + fixx, ym + y + offsety + fixy, data); /* I. Quadrant */
|
proc(x2 - r0 - x, y2 - r0 + y, data); /* I. Quadrant */
|
||||||
proc(xm - y - offsetx, ym - x + offsety + fixy, data); /* II. Quadrant */
|
proc(x1 + r0 - y, y2 - r0 - x, data); /* II. Quadrant */
|
||||||
proc(xm + x - offsetx, ym - y - offsety, data); /* III. Quadrant */
|
proc(x1 + r0 + x, y1 + r0 - y, data); /* III. Quadrant */
|
||||||
proc(xm + y + offsetx + fixx, ym + x - offsety, data); /* IV. Quadrant */
|
proc(x2 - r0 + y, y1 + r0 + x, data); /* IV. Quadrant */
|
||||||
r = err;
|
r = err;
|
||||||
if (r <= y)
|
if (r <= y)
|
||||||
err += ++y * 2 + 1; /* e_xy+e_y < 0 */
|
err += ++y * 2 + 1; /* e_xy+e_y < 0 */
|
||||||
|
@ -228,22 +218,16 @@ void algo_circle(int xm, int ym, int sx, int sy, int r, void* data, AlgoPixel pr
|
||||||
} while (x < 0);
|
} while (x < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as algo_circle but with the parts filled.
|
// Same as algo_sliced_circle but with the parts filled.
|
||||||
void algo_circlefill(int xm, int ym, int sx, int sy, int r, void* data, AlgoHLine proc)
|
void algo_sliced_circlefill(int x1, int y1, int x2, int y2, int r, void* data, AlgoHLine proc)
|
||||||
{
|
{
|
||||||
int x = -r, y = 0, err = 2 - 2 * r; /* II. Quadrant */
|
int x = -r, y = 0, err = 2 - 2 * r; /* II. Quadrant */
|
||||||
sx = sx < 0 ? 0 : sx;
|
const int r0 = r;
|
||||||
sy = sy < 0 ? 0 : sy;
|
|
||||||
int offsetx = sx / 2;
|
|
||||||
int offsety = sy / 2;
|
|
||||||
// Fix the position when sx or sy are not even.
|
|
||||||
int fixx = sx - 2 * offsetx;
|
|
||||||
int fixy = sy - 2 * offsety;
|
|
||||||
do {
|
do {
|
||||||
proc(xm, ym + y + offsety + fixy, xm - x + offsetx + fixx, data); /* I. Quadrant */
|
proc(x2 - r0, y2 - r0 + y, x2 - r0 - x, data); /* I. Quadrant */
|
||||||
proc(xm - y - offsetx, ym - x + offsety + fixy, xm, data); /* II. Quadrant */
|
proc(x1 + r0 - y, y2 - r0 - x, x1 + r0, data); /* II. Quadrant */
|
||||||
proc(xm + x - offsetx, ym - y - offsety, xm, data); /* III. Quadrant */
|
proc(x1 + r0 + x, y1 + r0 - y, x1 + r0, data); /* III. Quadrant */
|
||||||
proc(xm, ym + x - offsety, xm + y + offsetx + fixx, data); /* IV. Quadrant */
|
proc(x2 - r0, y1 + r0 + x, x2 - r0 + y, data); /* IV. Quadrant */
|
||||||
r = err;
|
r = err;
|
||||||
if (r <= y)
|
if (r <= y)
|
||||||
err += ++y * 2 + 1; /* e_xy+e_y < 0 */
|
err += ++y * 2 + 1; /* e_xy+e_y < 0 */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
// Copyright (C) 2018-2021 Igara Studio S.A.
|
// Copyright (C) 2018-2025 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.
|
||||||
|
@ -48,9 +48,9 @@ void algo_line_continuous_with_fix_for_line_brush(int x1,
|
||||||
void* data,
|
void* data,
|
||||||
AlgoPixel proc);
|
AlgoPixel proc);
|
||||||
|
|
||||||
void algo_circle(int xm, int ym, int sx, int sy, int r, void* data, AlgoPixel proc);
|
void algo_sliced_circle(int x1, int y1, int x2, int y2, int r, void* data, AlgoPixel proc);
|
||||||
|
|
||||||
void algo_circlefill(int xm, int ym, int sx, int sy, int r, void* data, AlgoHLine proc);
|
void algo_sliced_circlefill(int x1, int y1, int x2, int y2, int r, void* data, AlgoHLine proc);
|
||||||
|
|
||||||
void algo_arc(int xm, int ym, double sa, double ea, int r, void* data, AlgoPixel proc);
|
void algo_arc(int xm, int ym, double sa, double ea, int r, void* data, AlgoPixel proc);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue