Skip to content

Commit 4fc37dd

Browse files
authored
Merge pull request #1998 from Temmie3754/draw-fixes
Fix issues and inconsistency with draw_line_width
2 parents 57358a8 + ec7714f commit 4fc37dd

File tree

2 files changed

+182
-154
lines changed

2 files changed

+182
-154
lines changed

src_c/draw.c

Lines changed: 127 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,12 +1003,6 @@ compare_int(const void *a, const void *b)
10031003
return (*(const int *)a) - (*(const int *)b);
10041004
}
10051005

1006-
static int
1007-
sign(int x, int y)
1008-
{
1009-
return (x > 0) ? 1 : ((x < 0) ? -1 : y);
1010-
}
1011-
10121006
static Uint32
10131007
get_antialiased_color(SDL_Surface *surf, int x, int y, Uint32 original_color,
10141008
float brightness, int blend)
@@ -1064,7 +1058,7 @@ add_pixel_to_drawn_list(int x, int y, int *pts)
10641058
}
10651059

10661060
static void
1067-
add_line_to_drawn_list(int x1, int y1, int x2, int *pts)
1061+
add_line_to_drawn_list(int x1, int y1, int x2, int y2, int *pts)
10681062
{
10691063
if (x1 < pts[0]) {
10701064
pts[0] = x1;
@@ -1075,72 +1069,34 @@ add_line_to_drawn_list(int x1, int y1, int x2, int *pts)
10751069
if (x2 > pts[2]) {
10761070
pts[2] = x2;
10771071
}
1078-
if (y1 > pts[3]) {
1079-
pts[3] = y1;
1072+
if (y2 > pts[3]) {
1073+
pts[3] = y2;
10801074
}
10811075
}
10821076

10831077
static int
1084-
clip_line(SDL_Surface *surf, int *x1, int *y1, int *x2, int *y2)
1078+
clip_line(SDL_Surface *surf, int *x1, int *y1, int *x2, int *y2, int width,
1079+
int xinc)
10851080
{
1086-
int p1 = *x1 - *x2;
1087-
int p2 = -p1;
1088-
int p3 = *y1 - *y2;
1089-
int p4 = -p3;
1090-
int q1 = *x1 - surf->clip_rect.x;
1091-
int q2 = surf->clip_rect.w + surf->clip_rect.x - *x1;
1092-
int q3 = *y1 - surf->clip_rect.y;
1093-
int q4 = surf->clip_rect.h + surf->clip_rect.y - *y1;
1094-
int old_x1 = *x1;
1095-
int old_y1 = *y1;
1096-
double nmax = 0;
1097-
double pmin = 1;
1098-
double r1, r2;
1099-
if ((p1 == 0 && q1 < 0) || (p2 == 0 && q2 < 0) || (p3 == 0 && q3 < 0) ||
1100-
(p4 == 0 && q4 < 0))
1101-
return 0;
1102-
if (p1) {
1103-
r1 = (double)q1 / p1;
1104-
r2 = (double)q2 / p2;
1105-
if (p1 < 0) {
1106-
if (r1 > nmax)
1107-
nmax = r1;
1108-
if (r2 < pmin)
1109-
pmin = r2;
1110-
}
1111-
else {
1112-
if (r2 > nmax)
1113-
nmax = r2;
1114-
if (r1 < pmin)
1115-
pmin = r1;
1116-
}
1081+
int left, right, top, bottom;
1082+
if (xinc) {
1083+
left = MIN(*x1, *x2) - width;
1084+
right = MAX(*x1, *x2) + width;
1085+
top = MIN(*y1, *y2);
1086+
bottom = MAX(*y1, *y2);
11171087
}
1118-
if (p3) {
1119-
r1 = (double)q3 / p3;
1120-
r2 = (double)q4 / p4;
1121-
if (p3 < 0) {
1122-
if (r1 > nmax)
1123-
nmax = r1;
1124-
if (r2 < pmin)
1125-
pmin = r2;
1126-
}
1127-
else {
1128-
if (r2 > nmax)
1129-
nmax = r2;
1130-
if (r1 < pmin)
1131-
pmin = r1;
1132-
}
1133-
}
1134-
if (nmax > pmin)
1088+
else {
1089+
left = MIN(*x1, *x2);
1090+
right = MAX(*x1, *x2);
1091+
top = MIN(*y1, *y2) - width;
1092+
bottom = MAX(*y1, *y2) + width;
1093+
}
1094+
if (surf->clip_rect.x > right || surf->clip_rect.y > bottom ||
1095+
surf->clip_rect.x + surf->clip_rect.w <= left ||
1096+
surf->clip_rect.y + surf->clip_rect.h <= top) {
11351097
return 0;
1136-
*x1 =
1137-
old_x1 + (int)(p2 * nmax < 0 ? (p2 * nmax - 0.5) : (p2 * nmax + 0.5));
1138-
*y1 =
1139-
old_y1 + (int)(p4 * nmax < 0 ? (p4 * nmax - 0.5) : (p4 * nmax + 0.5));
1140-
*x2 =
1141-
old_x1 + (int)(p2 * pmin < 0 ? (p2 * pmin - 0.5) : (p2 * pmin + 0.5));
1142-
*y2 =
1143-
old_y1 + (int)(p4 * pmin < 0 ? (p4 * pmin - 0.5) : (p4 * pmin + 0.5));
1098+
}
1099+
11441100
return 1;
11451101
}
11461102

@@ -1425,6 +1381,42 @@ drawhorzline(SDL_Surface *surf, Uint32 color, int x1, int y1, int x2)
14251381
}
14261382
}
14271383

1384+
static void
1385+
drawvertline(SDL_Surface *surf, Uint32 color, int y1, int x1, int y2)
1386+
{
1387+
Uint8 *pixel, *end;
1388+
1389+
pixel = ((Uint8 *)surf->pixels) + surf->pitch * y1;
1390+
end = ((Uint8 *)surf->pixels) + surf->pitch * y2 +
1391+
x1 * surf->format->BytesPerPixel;
1392+
pixel += x1 * surf->format->BytesPerPixel;
1393+
switch (surf->format->BytesPerPixel) {
1394+
case 1:
1395+
for (; pixel <= end; pixel += surf->pitch) {
1396+
*pixel = (Uint8)color;
1397+
}
1398+
break;
1399+
case 2:
1400+
for (; pixel <= end; pixel += surf->pitch) {
1401+
*(Uint16 *)pixel = (Uint16)color;
1402+
}
1403+
break;
1404+
case 3:
1405+
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
1406+
color <<= 8;
1407+
#endif
1408+
for (; pixel <= end; pixel += surf->pitch) {
1409+
memcpy(pixel, &color, 3 * sizeof(Uint8));
1410+
}
1411+
break;
1412+
default: /*case 4*/
1413+
for (; pixel <= end; pixel += surf->pitch) {
1414+
*(Uint32 *)pixel = color;
1415+
}
1416+
break;
1417+
}
1418+
}
1419+
14281420
static void
14291421
drawhorzlineclip(SDL_Surface *surf, Uint32 color, int x1, int y1, int x2)
14301422
{
@@ -1474,117 +1466,98 @@ drawhorzlineclipbounding(SDL_Surface *surf, Uint32 color, int x1, int y1,
14741466
return;
14751467
}
14761468

1477-
add_line_to_drawn_list(x1, y1, x2, pts);
1469+
add_line_to_drawn_list(x1, y1, x2, y1, pts);
14781470

14791471
drawhorzline(surf, color, x1, y1, x2);
14801472
}
14811473

1482-
int
1483-
inside_clip(SDL_Surface *surf, int x, int y)
1484-
{
1485-
if (x < surf->clip_rect.x || x >= surf->clip_rect.x + surf->clip_rect.w ||
1486-
y < surf->clip_rect.y || y >= surf->clip_rect.y + surf->clip_rect.h)
1487-
return 0;
1488-
return 1;
1489-
}
1490-
14911474
static void
14921475
draw_line_width(SDL_Surface *surf, Uint32 color, int x1, int y1, int x2,
14931476
int y2, int width, int *drawn_area)
14941477
{
1495-
int dx, dy, err, e2, sx, sy, y;
1496-
int left_top, right_bottom;
1497-
int end_x = x2;
1498-
int end_y = y2;
1478+
int dx, dy, err, e2, sx, sy, start_draw, end_draw;
1479+
int end_x = surf->clip_rect.x + surf->clip_rect.w - 1;
1480+
int end_y = surf->clip_rect.y + surf->clip_rect.h - 1;
14991481
int xinc = 0;
1482+
int extra_width = 1 - (width % 2);
1483+
1484+
if (width < 1)
1485+
return;
1486+
if (width == 1) {
1487+
draw_line(surf, x1, y1, x2, y2, color, drawn_area);
1488+
return;
1489+
}
1490+
1491+
width = (width / 2);
1492+
15001493
/* Decide which direction to grow (width/thickness). */
15011494
if (abs(x1 - x2) <= abs(y1 - y2)) {
15021495
/* The line's thickness will be in the x direction. The top/bottom
15031496
* ends of the line will be flat. */
15041497
xinc = 1;
15051498
}
1499+
1500+
if (!clip_line(surf, &x1, &y1, &x2, &y2, width, xinc))
1501+
return;
1502+
1503+
if (x1 == x2 && y1 == y2) { /* Single point */
1504+
start_draw = MAX((x1 - width) + extra_width, surf->clip_rect.x);
1505+
end_draw = MIN(end_x, x1 + width);
1506+
if (start_draw <= end_draw) {
1507+
drawhorzline(surf, color, start_draw, y1, end_draw);
1508+
add_line_to_drawn_list(start_draw, y1, end_draw, y1, drawn_area);
1509+
}
1510+
return;
1511+
}
1512+
// Bresenham's line algorithm
15061513
dx = abs(x2 - x1);
1507-
sx = x1 < x2 ? 1 : -1;
15081514
dy = abs(y2 - y1);
1509-
sy = y1 < y2 ? 1 : -1;
1515+
sx = x2 > x1 ? 1 : -1;
1516+
sy = y2 > y1 ? 1 : -1;
15101517
err = (dx > dy ? dx : -dy) / 2;
1511-
if (clip_line(surf, &x1, &y1, &x2, &y2)) {
1512-
if (width == 1)
1513-
draw_line(surf, x1, y1, x2, y2, color, drawn_area);
1514-
else {
1515-
if (xinc) {
1516-
left_top = x1 - (width - 1) / 2;
1517-
right_bottom = x1 + width / 2;
1518+
if (xinc) {
1519+
while (y1 != (y2 + sy)) {
1520+
if (surf->clip_rect.y <= y1 && y1 <= end_y) {
1521+
start_draw =
1522+
MAX((x1 - width) + extra_width, surf->clip_rect.x);
1523+
end_draw = MIN(end_x, x1 + width);
1524+
if (start_draw <= end_draw) {
1525+
drawhorzline(surf, color, start_draw, y1, end_draw);
1526+
add_line_to_drawn_list(start_draw, y1, end_draw, y1,
1527+
drawn_area);
1528+
}
15181529
}
1519-
else {
1520-
left_top = y1 - (width - 1) / 2;
1521-
right_bottom = y1 + width / 2;
1530+
e2 = err;
1531+
if (e2 > -dx) {
1532+
err -= dy;
1533+
x1 += sx;
15221534
}
1523-
while ((sign(x1 - x2, sx) != sx) || (sign(y1 - y2, sy) != sy)) {
1524-
if (xinc)
1525-
drawhorzlineclipbounding(surf, color, left_top, y1,
1526-
right_bottom, drawn_area);
1527-
else {
1528-
for (y = left_top; y <= right_bottom; y++)
1529-
set_and_check_rect(surf, x1, y, color, drawn_area);
1530-
}
1531-
e2 = err;
1532-
if (e2 > -dx) {
1533-
err -= dy;
1534-
x1 += sx;
1535-
if (xinc) {
1536-
left_top += sx;
1537-
right_bottom += sx;
1538-
}
1539-
}
1540-
if (e2 < dy) {
1541-
err += dx;
1542-
y1 += sy;
1543-
if (!xinc) {
1544-
left_top += sy;
1545-
right_bottom += sy;
1546-
}
1547-
}
1535+
if (e2 < dy) {
1536+
err += dx;
1537+
y1 += sy;
15481538
}
1549-
if (xinc) {
1550-
while (y1 != end_y && (inside_clip(surf, left_top, y1) ||
1551-
inside_clip(surf, right_bottom, y1))) {
1552-
drawhorzlineclipbounding(surf, color, left_top, y1,
1553-
right_bottom, drawn_area);
1554-
e2 = err;
1555-
if (e2 > -dx) {
1556-
err -= dy;
1557-
x1 += sx;
1558-
left_top += sx;
1559-
right_bottom += sx;
1560-
}
1561-
if (e2 < dy) {
1562-
err += dx;
1563-
y1 += sy;
1564-
}
1539+
}
1540+
}
1541+
else {
1542+
while (x1 != (x2 + sx)) {
1543+
if (surf->clip_rect.x <= x1 && x1 <= end_x) {
1544+
start_draw =
1545+
MAX((y1 - width) + extra_width, surf->clip_rect.y);
1546+
end_draw = MIN(end_y, y1 + width);
1547+
if (start_draw <= end_draw) {
1548+
drawvertline(surf, color, start_draw, x1, end_draw);
1549+
add_line_to_drawn_list(x1, start_draw, x1, end_draw,
1550+
drawn_area);
15651551
}
1566-
drawhorzlineclipbounding(surf, color, left_top, y1,
1567-
right_bottom, drawn_area);
15681552
}
1569-
else {
1570-
while (x1 != end_x && (inside_clip(surf, x1, left_top) ||
1571-
inside_clip(surf, x1, right_bottom))) {
1572-
for (y = left_top; y <= right_bottom; y++)
1573-
set_and_check_rect(surf, x1, y, color, drawn_area);
1574-
e2 = err;
1575-
if (e2 > -dx) {
1576-
err -= dy;
1577-
x1 += sx;
1578-
}
1579-
if (e2 < dy) {
1580-
err += dx;
1581-
y1 += sy;
1582-
left_top += sy;
1583-
right_bottom += sy;
1584-
}
1585-
}
1586-
for (y = left_top; y <= right_bottom; y++)
1587-
set_and_check_rect(surf, x1, y, color, drawn_area);
1553+
e2 = err;
1554+
if (e2 > -dx) {
1555+
err -= dy;
1556+
x1 += sx;
1557+
}
1558+
if (e2 < dy) {
1559+
err += dx;
1560+
y1 += sy;
15881561
}
15891562
}
15901563
}

0 commit comments

Comments
 (0)