Prevent overdraw with connected line segments

This commit is contained in:
Sam Lantinga 2022-01-08 12:02:08 -08:00
parent 63d10a0ac2
commit 4b71962031
1 changed files with 62 additions and 38 deletions

View File

@ -2807,7 +2807,7 @@ SDL_RenderDrawLineF(SDL_Renderer * renderer, float x1, float y1, float x2, float
return SDL_RenderDrawLinesF(renderer, points, 2); return SDL_RenderDrawLinesF(renderer, points, 2);
} }
static int plotLineLow(SDL_Renderer *renderer, float x0, float y0, float x1, float y1) static int plotLineLow(SDL_Renderer *renderer, float x0, float y0, float x1, float y1, SDL_bool draw_first, SDL_bool draw_last)
{ {
int retval = 0; int retval = 0;
float dx = x1 - x0; float dx = x1 - x0;
@ -2818,6 +2818,8 @@ static int plotLineLow(SDL_Renderer *renderer, float x0, float y0, float x1, flo
SDL_bool isstack; SDL_bool isstack;
SDL_FPoint *points = SDL_small_alloc(SDL_FPoint, count, &isstack); SDL_FPoint *points = SDL_small_alloc(SDL_FPoint, count, &isstack);
SDL_FPoint *tmp = points; SDL_FPoint *tmp = points;
SDL_FPoint *render_points;
int render_count;
if (!points) { if (!points) {
return SDL_OutOfMemory(); return SDL_OutOfMemory();
@ -2843,10 +2845,21 @@ static int plotLineLow(SDL_Renderer *renderer, float x0, float y0, float x1, flo
} }
SDL_assert((tmp - points) == count); SDL_assert((tmp - points) == count);
if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { if (draw_last) {
retval = RenderDrawPointsWithRectsF(renderer, points, count); render_count = count;
} else { } else {
retval = QueueCmdDrawPoints(renderer, points, count); render_count = count - 1;
}
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); SDL_small_free(points, isstack);
@ -2854,7 +2867,7 @@ static int plotLineLow(SDL_Renderer *renderer, float x0, float y0, float x1, flo
return retval; return retval;
} }
static int plotLineHigh(SDL_Renderer *renderer, float x0, float y0, float x1, float y1) 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; int retval = 0;
float dx = x1 - x0; float dx = x1 - x0;
@ -2865,6 +2878,8 @@ static int plotLineHigh(SDL_Renderer *renderer, float x0, float y0, float x1, fl
SDL_bool isstack; SDL_bool isstack;
SDL_FPoint *points = SDL_small_alloc(SDL_FPoint, count, &isstack); SDL_FPoint *points = SDL_small_alloc(SDL_FPoint, count, &isstack);
SDL_FPoint *tmp = points; SDL_FPoint *tmp = points;
SDL_FPoint *render_points;
int render_count;
if (!points) { if (!points) {
return SDL_OutOfMemory(); return SDL_OutOfMemory();
@ -2890,10 +2905,21 @@ static int plotLineHigh(SDL_Renderer *renderer, float x0, float y0, float x1, fl
} }
SDL_assert((tmp - points) == count); SDL_assert((tmp - points) == count);
if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { if (draw_last) {
retval = RenderDrawPointsWithRectsF(renderer, points, count); render_count = count;
} else { } else {
retval = QueueCmdDrawPoints(renderer, points, count); render_count = count - 1;
}
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); SDL_small_free(points, isstack);
@ -2901,48 +2927,35 @@ static int plotLineHigh(SDL_Renderer *renderer, float x0, float y0, float x1, fl
return retval; return retval;
} }
static int plotLineBresenham(SDL_Renderer *renderer, float x0, float y0, float x1, float y1) 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 (SDL_fabs(y1 - y0) < SDL_fabs(x1 - x0)) {
if (x0 > x1) { if (x0 > x1) {
return plotLineLow(renderer, x1, y1, x0, y0); return plotLineLow(renderer, x1, y1, x0, y0, draw_last, SDL_TRUE);
} else { } else {
return plotLineLow(renderer, x0, y0, x1, y1); return plotLineLow(renderer, x0, y0, x1, y1, SDL_TRUE, draw_last);
} }
} else { } else {
if (y0 > y1) { if (y0 > y1) {
return plotLineHigh(renderer, x1, y1, x0, y0); return plotLineHigh(renderer, x1, y1, x0, y0, draw_last, SDL_TRUE);
} else { } else {
return plotLineHigh(renderer, x0, y0, x1, y1); return plotLineHigh(renderer, x0, y0, x1, y1, SDL_TRUE, draw_last);
} }
} }
} }
static int
RenderDrawLinesWithPointsF(SDL_Renderer * renderer,
const SDL_FPoint * points, const int count)
{
int i;
int retval = 0;
for (i = 0; i < count-1; ++i, ++points) {
retval += plotLineBresenham(renderer, points[0].x, points[0].y, points[1].x, points[1].y);
}
if (retval < 0) {
retval = -1;
}
return retval;
}
static int static int
RenderDrawLinesWithRectsF(SDL_Renderer * renderer, RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
const SDL_FPoint * points, const int count) const SDL_FPoint * points, const int count)
{ {
const float scale_x = renderer->scale.x;
const float scale_y = renderer->scale.y;
SDL_FRect *frect; SDL_FRect *frect;
SDL_FRect *frects; SDL_FRect *frects;
int i, nrects = 0; int i, nrects = 0;
int retval = 0; int retval = 0;
SDL_bool isstack; SDL_bool isstack;
SDL_bool draw_last = SDL_FALSE;
frects = SDL_small_alloc(SDL_FRect, count-1, &isstack); frects = SDL_small_alloc(SDL_FRect, count-1, &isstack);
if (!frects) { if (!frects) {
@ -2950,26 +2963,37 @@ RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
} }
for (i = 0; i < count-1; ++i) { for (i = 0; i < count-1; ++i) {
if (i == count-2) {
if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
draw_last = SDL_TRUE;
}
}
if (points[i].x == points[i+1].x) { if (points[i].x == points[i+1].x) {
const float minY = SDL_min(points[i].y, points[i+1].y); const float minY = SDL_min(points[i].y, points[i+1].y);
const float maxY = SDL_max(points[i].y, points[i+1].y); const float maxY = SDL_max(points[i].y, points[i+1].y);
frect = &frects[nrects++]; frect = &frects[nrects++];
frect->x = points[i].x * renderer->scale.x; frect->x = points[i].x * scale_x;
frect->y = minY * renderer->scale.y; frect->y = minY * scale_y;
frect->w = renderer->scale.x; frect->w = scale_x;
frect->h = (maxY - minY + 1) * renderer->scale.y; frect->h = (maxY - minY + draw_last) * scale_y;
if (!draw_last && points[i+1].y < points[i].y) {
frect->y += scale_y;
}
} else if (points[i].y == points[i+1].y) { } else if (points[i].y == points[i+1].y) {
const float minX = SDL_min(points[i].x, points[i+1].x); const float minX = SDL_min(points[i].x, points[i+1].x);
const float maxX = SDL_max(points[i].x, points[i+1].x); const float maxX = SDL_max(points[i].x, points[i+1].x);
frect = &frects[nrects++]; frect = &frects[nrects++];
frect->x = minX * renderer->scale.x; frect->x = minX * scale_x;
frect->y = points[i].y * renderer->scale.y; frect->y = points[i].y * scale_y;
frect->w = (maxX - minX + 1) * renderer->scale.x; frect->w = (maxX - minX + draw_last) * scale_x;
frect->h = renderer->scale.y; frect->h = scale_y;
if (!draw_last && points[i+1].x < points[i].x) {
frect->x += scale_x;
}
} else { } else {
retval += RenderDrawLinesWithPointsF(renderer, &points[i], 2); retval += plotLineBresenham(renderer, points[i].x, points[i].y, points[i+1].x, points[i+1].y, draw_last);
} }
} }