Updated Bresenham line drawing to match software renderer output

This commit is contained in:
Sam Lantinga 2022-01-09 11:11:34 -08:00
parent b9d98331c5
commit a29d3acc9e
1 changed files with 61 additions and 114 deletions

View File

@ -2807,57 +2807,78 @@ SDL_RenderDrawLineF(SDL_Renderer * renderer, float x1, float y1, float x2, float
return SDL_RenderDrawLinesF(renderer, points, 2);
}
static int plotLineLow(SDL_Renderer *renderer, float x0, float y0, float x1, float y1, SDL_bool draw_first, SDL_bool draw_last)
static int RenderDrawLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2, int y2, SDL_bool draw_last)
{
int retval = 0;
float dx = x1 - x0;
float dy = y1 - y0;
int yi = 1;
float x, y, D;
int count = (int)SDL_ceilf(x1 - x0 + 1);
int i, deltax, deltay, numpixels;
int d, dinc1, dinc2;
int x, xinc1, xinc2;
int y, yinc1, yinc2;
int retval;
SDL_bool isstack;
SDL_FPoint *points = SDL_small_alloc(SDL_FPoint, count, &isstack);
SDL_FPoint *tmp = points;
SDL_FPoint *render_points;
int render_count;
SDL_FPoint *points;
deltax = SDL_abs(x2 - x1);
deltay = SDL_abs(y2 - y1);
if (deltax >= deltay) {
numpixels = deltax + 1;
d = (2 * deltay) - deltax;
dinc1 = deltay * 2;
dinc2 = (deltay - deltax) * 2;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
} else {
numpixels = deltay + 1;
d = (2 * deltax) - deltay;
dinc1 = deltax * 2;
dinc2 = (deltax - deltay) * 2;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
if (x1 > x2) {
xinc1 = -xinc1;
xinc2 = -xinc2;
}
if (y1 > y2) {
yinc1 = -yinc1;
yinc2 = -yinc2;
}
x = x1;
y = y1;
if (!draw_last) {
--numpixels;
}
points = SDL_small_alloc(SDL_FPoint, numpixels, &isstack);
if (!points) {
return SDL_OutOfMemory();
}
for (i = 0; i < numpixels; ++i) {
points[i].x = (float)x;
points[i].y = (float)y;
if (dy < 0) {
yi = -1;
dy = -dy;
}
D = (2 * dy) - dx;
y = y0;
for (x = x0; x <= x1; ++x) {
tmp->x = x;
tmp->y = y;
tmp++;
if (D > 0) {
y += yi;
D += 2 * (dy - dx);
if (d < 0) {
d += dinc1;
x += xinc1;
y += yinc1;
} else {
D += 2*dy;
d += dinc2;
x += xinc2;
y += yinc2;
}
}
render_count = (int)(tmp - points);
if (!draw_last) {
--render_count;
}
if (draw_first) {
render_points = points;
} else {
render_points = points+1;
--render_count;
}
if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
retval = RenderDrawPointsWithRectsF(renderer, render_points, render_count);
retval = RenderDrawPointsWithRectsF(renderer, points, numpixels);
} else {
retval = QueueCmdDrawPoints(renderer, render_points, render_count);
retval = QueueCmdDrawPoints(renderer, points, numpixels);
}
SDL_small_free(points, isstack);
@ -2865,81 +2886,6 @@ static int plotLineLow(SDL_Renderer *renderer, float x0, float y0, float x1, flo
return retval;
}
static int plotLineHigh(SDL_Renderer *renderer, float x0, float y0, float x1, float y1, SDL_bool draw_first, SDL_bool draw_last)
{
int retval = 0;
float dx = x1 - x0;
float dy = y1 - y0;
int xi = 1;
float x, y, D;
int count = (int)SDL_ceilf(y1 - y0 + 1);
SDL_bool isstack;
SDL_FPoint *points = SDL_small_alloc(SDL_FPoint, count, &isstack);
SDL_FPoint *tmp = points;
SDL_FPoint *render_points;
int render_count;
if (!points) {
return SDL_OutOfMemory();
}
if (dx < 0) {
xi = -1;
dx = -dx;
}
D = (2 * dx) - dy;
x = x0;
for (y = y0; y <= y1; ++y) {
tmp->x = x;
tmp->y = y;
tmp++;
if (D > 0) {
x += xi;
D += 2 * (dx - dy);
} else {
D += 2*dx;
}
}
render_count = (int)(tmp - points);
if (!draw_last) {
--render_count;
}
if (draw_first) {
render_points = points;
} else {
render_points = points+1;
--render_count;
}
if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) {
retval = RenderDrawPointsWithRectsF(renderer, render_points, render_count);
} else {
retval = QueueCmdDrawPoints(renderer, render_points, render_count);
}
SDL_small_free(points, isstack);
return retval;
}
static int plotLineBresenham(SDL_Renderer *renderer, float x0, float y0, float x1, float y1, SDL_bool draw_last)
{
if (SDL_fabs(y1 - y0) < SDL_fabs(x1 - x0)) {
if (x0 > x1) {
return plotLineLow(renderer, x1, y1, x0, y0, draw_last, SDL_TRUE);
} else {
return plotLineLow(renderer, x0, y0, x1, y1, SDL_TRUE, draw_last);
}
} else {
if (y0 > y1) {
return plotLineHigh(renderer, x1, y1, x0, y0, draw_last, SDL_TRUE);
} else {
return plotLineHigh(renderer, x0, y0, x1, y1, SDL_TRUE, draw_last);
}
}
}
static int
RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
const SDL_FPoint * points, const int count)
@ -2997,7 +2943,8 @@ RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
frect->x += scale_x;
}
} else {
retval += plotLineBresenham(renderer, points[i].x, points[i].y, points[i+1].x, points[i+1].y, draw_last);
retval += RenderDrawLineBresenham(renderer, (int)points[i].x, (int)points[i].y,
(int)points[i+1].x, (int)points[i+1].y, draw_last);
}
drew_line = SDL_TRUE;
}