Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean aaline #596

Merged
merged 15 commits into from
Nov 5, 2018
221 changes: 109 additions & 112 deletions src_c/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ clip_and_draw_line_width(SDL_Surface *surf, SDL_Rect *rect, Uint32 color,
static int
clipline(int *pts, int left, int top, int right, int bottom);
static int
clipaaline(float *pts, int left, int top, int right, int bottom);
clip_aaline(float *pts, int left, int top, int right, int bottom);
static void
drawline(SDL_Surface *surf, Uint32 color, int startx, int starty, int endx,
int endy);
static void
drawaaline(SDL_Surface *surf, Uint32 color, float startx, float starty,
draw_aaline(SDL_Surface *surf, Uint32 color, float startx, float starty,
float endx, float endy, int blend);
static void
drawhorzline(SDL_Surface *surf, Uint32 color, int startx, int starty,
Expand Down Expand Up @@ -683,10 +683,10 @@ static int
clip_and_draw_aaline(SDL_Surface *surf, SDL_Rect *rect, Uint32 color,
float *pts, int blend)
{
if (!clipaaline(pts, rect->x + 1, rect->y + 1, rect->x + rect->w - 2,
if (!clip_aaline(pts, rect->x + 1, rect->y + 1, rect->x + rect->w - 2,
rect->y + rect->h - 2))
return 0;
drawaaline(surf, color, pts[0], pts[1], pts[2], pts[3], blend);
draw_aaline(surf, color, pts[0], pts[1], pts[2], pts[3], blend);
return 1;
}

Expand Down Expand Up @@ -807,14 +807,23 @@ encodeFloat(float x, float y, int left, int top, int right, int bottom)
}

static int
clipaaline(float *pts, int left, int top, int right, int bottom)
clip_aaline(float *segment, int left, int top, int right, int bottom)
{
float x1 = pts[0];
float y1 = pts[1];
float x2 = pts[2];
float y2 = pts[3];
/*
* Algorithm to calculate the clipped anti-aliased line.
*
* We write the coordinates of the part of the line
* segment within the bounding box defined
* by (left, top, right, bottom) into the "segment" array.
* Returns 0 if we don't have to draw anything, eg if the
* segment = [from_x, from_y, to_x, to_y]
* doesn't cross the bounding box.
*/
float x1 = segment[0];
float y1 = segment[1];
float x2 = segment[2];
float y2 = segment[3];
int code1, code2;
int draw = 0;
float swaptmp;
int intswaptmp;
float m; /*slope*/
Expand All @@ -823,23 +832,20 @@ clipaaline(float *pts, int left, int top, int right, int bottom)
code1 = encodeFloat(x1, y1, left, top, right, bottom);
code2 = encodeFloat(x2, y2, left, top, right, bottom);
if (ACCEPT(code1, code2)) {
draw = 1;
break;
segment[0] = x1;
segment[1] = y1;
segment[2] = x2;
segment[3] = y2;
return 1;
}
else if (REJECT(code1, code2)) {
break;
return 0;
}
else {
if (INSIDE(code1)) {
swaptmp = x2;
x2 = x1;
x1 = swaptmp;
swaptmp = y2;
y2 = y1;
y1 = swaptmp;
intswaptmp = code2;
code2 = code1;
code1 = intswaptmp;
SWAP(x1, x2, swaptmp)
SWAP(y1, y2, swaptmp)
SWAP(code1, code2, intswaptmp)
}
if (x2 != x1)
m = (y2 - y1) / (x2 - x1);
Expand All @@ -865,49 +871,35 @@ clipaaline(float *pts, int left, int top, int right, int bottom)
}
}
}
if (draw) {
pts[0] = x1;
pts[1] = y1;
pts[2] = x2;
pts[3] = y2;
}
return draw;
}

static int
clipline(int *pts, int left, int top, int right, int bottom)
clipline(int *segment, int left, int top, int right, int bottom)
{
/*
* Algorithm to calculate the clipped line.
*
* We write the coordinates of the part of the line
* segment within the bounding box defined
* by (left, top, right, bottom) into the "pts" array.
* Returns 0 if we don't have to draw anything, eg if the
* segment defined throuth "pts" doesn't cross the bounding box.
* It's like clip_aaline, but for integer coordinate endpoints.
*/
int x1 = pts[0];
int y1 = pts[1];
int x2 = pts[2];
int y2 = pts[3];
int x1 = segment[0];
int y1 = segment[1];
int x2 = segment[2];
int y2 = segment[3];
int code1, code2;
int draw = 0;
int swaptmp;
float m; /*slope*/

while (1) {
code1 = encode(x1, y1, left, top, right, bottom);
code2 = encode(x2, y2, left, top, right, bottom);
if (ACCEPT(code1, code2)) {
draw = 1;
pts[0] = x1;
pts[1] = y1;
pts[2] = x2;
pts[3] = y2;
break;
segment[0] = x1;
segment[1] = y1;
segment[2] = x2;
segment[3] = y2;
return 1;
}
else if (REJECT(code1, code2))
break;
return 0;
else {
if (INSIDE(code1)) {
SWAP(x1, x2, swaptmp)
Expand Down Expand Up @@ -938,7 +930,6 @@ clipline(int *pts, int left, int top, int right, int bottom)
}
}
}
return draw;
}

static int
Expand Down Expand Up @@ -1057,19 +1048,19 @@ draw_pixel_blended_32(Uint8 *pixels, Uint8 *colors, float br,

/* Adapted from http://freespace.virgin.net/hugo.elias/graphics/x_wuline.htm */
static void
drawaaline(SDL_Surface *surf, Uint32 color, float x1, float y1, float x2,
float y2, int blend)
draw_aaline(SDL_Surface *surf, Uint32 color, float from_x, float from_y, float to_x,
float to_y, int blend)
{
float grad, xd, yd;
float xgap, ygap, xend, yend, xf, yf;
float slope, dx, dy;
float xgap, ygap, pt_x, pt_y, xf, yf;
float brightness1, brightness2;
float swaptmp;
int x, y, ix1, ix2, iy1, iy2;
int x, y, ifrom_x, ito_x, ifrom_y, ito_y;
int pixx, pixy;
Uint8 colorptr[4];

Uint8 *pixel;
Uint8 *pm = (Uint8 *)surf->pixels;
Uint8 *surf_pmap = (Uint8 *)surf->pixels;
SDL_GetRGBA(color, surf->format, &colorptr[0], &colorptr[1], &colorptr[2],
&colorptr[3]);
if (!blend)
Expand All @@ -1078,96 +1069,102 @@ drawaaline(SDL_Surface *surf, Uint32 color, float x1, float y1, float x2,
pixx = surf->format->BytesPerPixel;
pixy = surf->pitch;

xd = x2 - x1;
yd = y2 - y1;
dx = to_x - from_x;
dy = to_y - from_y;

if (xd == 0 && yd == 0) {
if (dx == 0 && dy == 0) {
/* Single point. Due to the nature of the aaline clipping, this
* is less exact than the normal line. */
set_at(surf, x1, y1, color);
set_at(surf, from_x, from_y, color);
return;
}

if (fabs(xd) > fabs(yd)) {
if (x1 > x2) {
SWAP(x1, x2, swaptmp)
SWAP(y1, y2, swaptmp)
xd = (x2 - x1);
yd = (y2 - y1);
if (fabs(dx) > fabs(dy)) {
if (from_x > to_x) {
SWAP(from_x, to_x, swaptmp)
SWAP(from_y, to_y, swaptmp)
dx = -dx;
dy = -dy;
}
grad = yd / xd;
xend = trunc(x1) + 0.5; /* This makes more sense than trunc(x1+0.5) */
yend = y1 + grad * (xend - x1);
xgap = INVFRAC(x1);
ix1 = (int)xend;
iy1 = (int)yend;
yf = yend + grad;
brightness1 = INVFRAC(yend) * xgap;
brightness2 = FRAC(yend) * xgap;
pixel = pm + pixx * ix1 + pixy * iy1;
slope = dy / dx;
// 1. Draw start of the segment
pt_x = trunc(from_x) + 0.5; /* This makes more sense than trunc(from_x+0.5) */
pt_y = from_y + slope * (pt_x - from_x);
xgap = INVFRAC(from_x);
ifrom_x = (int)pt_x;
ifrom_y = (int)pt_y;
yf = pt_y + slope;
brightness1 = INVFRAC(pt_y) * xgap;
brightness2 = FRAC(pt_y) * xgap;
pixel = surf_pmap + pixx * ifrom_x + pixy * ifrom_y;
DRAWPIX32(pixel, colorptr, brightness1, blend)
pixel += pixy;
DRAWPIX32(pixel, colorptr, brightness2, blend)
xend = trunc(x2) + 0.5;
yend = y2 + grad * (xend - x2);
xgap = FRAC(x2); /* this also differs from Hugo's description. */
ix2 = (int)xend;
iy2 = (int)yend;
brightness1 = INVFRAC(yend) * xgap;
brightness2 = FRAC(yend) * xgap;
pixel = pm + pixx * ix2 + pixy * iy2;
// 2. Draw end of the segment
pt_x = trunc(to_x) + 0.5;
pt_y = to_y + slope * (pt_x - to_x);
xgap = FRAC(to_x); /* this also differs from Hugo's description. */
ito_x = (int)pt_x;
ito_y = (int)pt_y;
brightness1 = INVFRAC(pt_y) * xgap;
brightness2 = FRAC(pt_y) * xgap;
pixel = surf_pmap + pixx * ito_x + pixy * ito_y;
DRAWPIX32(pixel, colorptr, brightness1, blend)
pixel += pixy;
DRAWPIX32(pixel, colorptr, brightness2, blend)
for (x = ix1 + 1; x < ix2; ++x) {
// 3. loop for other points
for (x = ifrom_x + 1; x < ito_x; ++x) {
brightness1 = INVFRAC(yf);
brightness2 = FRAC(yf);
pixel = pm + pixx * x + pixy * (int)yf;
pixel = surf_pmap + pixx * x + pixy * (int)yf;
DRAWPIX32(pixel, colorptr, brightness1, blend)
pixel += pixy;
DRAWPIX32(pixel, colorptr, brightness2, blend)
yf += grad;
yf += slope;
}
}
else {
if (y1 > y2) {
SWAP(x1, x2, swaptmp)
SWAP(y1, y2, swaptmp)
yd = (y2 - y1);
xd = (x2 - x1);
if (from_y > to_y) {
SWAP(from_x, to_x, swaptmp)
SWAP(from_y, to_y, swaptmp)
dx = -dx;
dy = -dy;
}
grad = xd / yd;
yend = trunc(y1) + 0.5; /* This makes more sense than trunc(x1+0.5) */
xend = x1 + grad * (yend - y1);
ygap = INVFRAC(y1);
iy1 = (int)yend;
ix1 = (int)xend;
xf = xend + grad;
brightness1 = INVFRAC(xend) * ygap;
brightness2 = FRAC(xend) * ygap;
pixel = pm + pixx * ix1 + pixy * iy1;
slope = dx / dy;
// 1. Draw start of the segment
pt_y = trunc(from_y) + 0.5; /* This makes more sense than trunc(from_x+0.5) */
pt_x = from_x + slope * (pt_y - from_y);
ygap = INVFRAC(from_y);
ifrom_y = (int)pt_y;
ifrom_x = (int)pt_x;
xf = pt_x + slope;
brightness1 = INVFRAC(pt_x) * ygap;
brightness2 = FRAC(pt_x) * ygap;
pixel = surf_pmap + pixx * ifrom_x + pixy * ifrom_y;
DRAWPIX32(pixel, colorptr, brightness1, blend)
pixel += pixx;
DRAWPIX32(pixel, colorptr, brightness2, blend)
yend = trunc(y2) + 0.5;
xend = x2 + grad * (yend - y2);
ygap = FRAC(y2);
iy2 = (int)yend;
ix2 = (int)xend;
brightness1 = INVFRAC(xend) * ygap;
brightness2 = FRAC(xend) * ygap;
pixel = pm + pixx * ix2 + pixy * iy2;
// 2. Draw end of the segment
pt_y = trunc(to_y) + 0.5;
pt_x = to_x + slope * (pt_y - to_y);
ygap = FRAC(to_y);
ito_y = (int)pt_y;
ito_x = (int)pt_x;
brightness1 = INVFRAC(pt_x) * ygap;
brightness2 = FRAC(pt_x) * ygap;
pixel = surf_pmap + pixx * ito_x + pixy * ito_y;
DRAWPIX32(pixel, colorptr, brightness1, blend)
pixel += pixx;
DRAWPIX32(pixel, colorptr, brightness2, blend)
for (y = iy1 + 1; y < iy2; ++y) {
// 3. loop for other points
for (y = ifrom_y + 1; y < ito_y; ++y) {
brightness1 = INVFRAC(xf);
brightness2 = FRAC(xf);
pixel = pm + pixx * (int)xf + pixy * y;
pixel = surf_pmap + pixx * (int)xf + pixy * y;
DRAWPIX32(pixel, colorptr, brightness1, blend)
pixel += pixx;
DRAWPIX32(pixel, colorptr, brightness2, blend)
xf += grad;
xf += slope;
}
}
}
Expand Down
Loading