From 4b71962031861c24bb0fe288782bfa7359e3d6ab Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 8 Jan 2022 12:02:08 -0800
Subject: [PATCH] Prevent overdraw with connected line segments
---
src/render/SDL_render.c | 96 +++++++++++++++++++++++++----------------
1 file changed, 60 insertions(+), 36 deletions(-)
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index a9251c27436..2ffdae508aa 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -2807,7 +2807,7 @@ 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)
+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;
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_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();
@@ -2843,10 +2845,21 @@ static int plotLineLow(SDL_Renderer *renderer, float x0, float y0, float x1, flo
}
SDL_assert((tmp - points) == count);
+ if (draw_last) {
+ render_count = count;
+ } else {
+ 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, points, count);
+ retval = RenderDrawPointsWithRectsF(renderer, render_points, render_count);
} else {
- retval = QueueCmdDrawPoints(renderer, points, count);
+ retval = QueueCmdDrawPoints(renderer, render_points, render_count);
}
SDL_small_free(points, isstack);
@@ -2854,7 +2867,7 @@ 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)
+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;
@@ -2865,6 +2878,8 @@ static int plotLineHigh(SDL_Renderer *renderer, float x0, float y0, float x1, fl
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();
@@ -2890,10 +2905,21 @@ static int plotLineHigh(SDL_Renderer *renderer, float x0, float y0, float x1, fl
}
SDL_assert((tmp - points) == count);
+ if (draw_last) {
+ render_count = count;
+ } else {
+ 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, points, count);
+ retval = RenderDrawPointsWithRectsF(renderer, render_points, render_count);
} else {
- retval = QueueCmdDrawPoints(renderer, points, count);
+ retval = QueueCmdDrawPoints(renderer, render_points, render_count);
}
SDL_small_free(points, isstack);
@@ -2901,48 +2927,35 @@ static int plotLineHigh(SDL_Renderer *renderer, float x0, float y0, float x1, fl
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 (x0 > x1) {
- return plotLineLow(renderer, x1, y1, x0, y0);
+ return plotLineLow(renderer, x1, y1, x0, y0, draw_last, SDL_TRUE);
} else {
- return plotLineLow(renderer, x0, y0, x1, y1);
+ return plotLineLow(renderer, x0, y0, x1, y1, SDL_TRUE, draw_last);
}
} else {
if (y0 > y1) {
- return plotLineHigh(renderer, x1, y1, x0, y0);
+ return plotLineHigh(renderer, x1, y1, x0, y0, draw_last, SDL_TRUE);
} 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
RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
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 *frects;
int i, nrects = 0;
int retval = 0;
SDL_bool isstack;
+ SDL_bool draw_last = SDL_FALSE;
frects = SDL_small_alloc(SDL_FRect, count-1, &isstack);
if (!frects) {
@@ -2950,26 +2963,37 @@ RenderDrawLinesWithRectsF(SDL_Renderer * renderer,
}
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) {
const float minY = SDL_min(points[i].y, points[i+1].y);
const float maxY = SDL_max(points[i].y, points[i+1].y);
frect = &frects[nrects++];
- frect->x = points[i].x * renderer->scale.x;
- frect->y = minY * renderer->scale.y;
- frect->w = renderer->scale.x;
- frect->h = (maxY - minY + 1) * renderer->scale.y;
+ frect->x = points[i].x * scale_x;
+ frect->y = minY * scale_y;
+ frect->w = scale_x;
+ 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) {
const float minX = SDL_min(points[i].x, points[i+1].x);
const float maxX = SDL_max(points[i].x, points[i+1].x);
frect = &frects[nrects++];
- frect->x = minX * renderer->scale.x;
- frect->y = points[i].y * renderer->scale.y;
- frect->w = (maxX - minX + 1) * renderer->scale.x;
- frect->h = renderer->scale.y;
+ frect->x = minX * scale_x;
+ frect->y = points[i].y * scale_y;
+ frect->w = (maxX - minX + draw_last) * scale_x;
+ frect->h = scale_y;
+ if (!draw_last && points[i+1].x < points[i].x) {
+ frect->x += scale_x;
+ }
} 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);
}
}