Commit 0e4ce8480195a9c436ff0f484d808af7e8a63b60

Ryan C. Gordon 2020-11-08T20:57:17

opengl: Make diagonal lines match the software renderer. OpenGL leaves the final line segment open, SDL's software renderer does not, so we need a tiny bit of trigonometry here to move one more pixel in the right direction.

diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c
index f749ce3..364f9b3 100644
--- a/src/render/opengl/SDL_render_gl.c
+++ b/src/render/opengl/SDL_render_gl.c
@@ -865,15 +865,8 @@ GL_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPo
         *(verts++) = 0.5f + points[i].y;
     }
 
-    /* If the line segment is completely horizontal or vertical,
-       make it one pixel longer, to satisfy the diamond-exit rule.
-       We should probably do this for diagonal lines too, but we'd have to
-       do some trigonometry to figure out the correct pixel and generally
-       when we have problems with pixel perfection, it's for straight lines
-       that are missing a pixel that frames something and not arbitrary
-       angles. Maybe !!! FIXME for later, though. */
-
-    /* update the last line. */
+    /* Make the last line segment one pixel longer, to satisfy the
+       diamond-exit rule. */
     verts -= 4;
     {
         const GLfloat xstart = verts[0];
@@ -885,6 +878,12 @@ GL_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPo
             verts[2] += (xend > xstart) ? 1.0f : -1.0f;
         } else if (xstart == xend) {  /* vertical line */
             verts[3] += (yend > ystart) ? 1.0f : -1.0f;
+        } else {  /* bump a pixel in the direction we are moving in. */
+            const GLfloat deltax = xend - xstart;
+            const GLfloat deltay = yend - ystart;
+            const GLfloat angle = SDL_atan2f(deltay, deltax);
+            verts[2] += SDL_cosf(angle);
+            verts[3] += SDL_sinf(angle);
         }
     }
 
diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c
index a6cf22e..8525358 100644
--- a/src/render/opengles/SDL_render_gles.c
+++ b/src/render/opengles/SDL_render_gles.c
@@ -578,15 +578,8 @@ GLES_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_F
         *(verts++) = 0.5f + points[i].y;
     }
 
-    /* If the line segment is completely horizontal or vertical,
-       make it one pixel longer, to satisfy the diamond-exit rule.
-       We should probably do this for diagonal lines too, but we'd have to
-       do some trigonometry to figure out the correct pixel and generally
-       when we have problems with pixel perfection, it's for straight lines
-       that are missing a pixel that frames something and not arbitrary
-       angles. Maybe !!! FIXME for later, though. */
-
-    /* update the last line. */
+    /* Make the last line segment one pixel longer, to satisfy the
+       diamond-exit rule. */
     verts -= 4;
     {
         const GLfloat xstart = verts[0];
@@ -598,6 +591,12 @@ GLES_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_F
             verts[2] += (xend > xstart) ? 1.0f : -1.0f;
         } else if (xstart == xend) {  /* vertical line */
             verts[3] += (yend > ystart) ? 1.0f : -1.0f;
+        } else {  /* bump a pixel in the direction we are moving in. */
+            const GLfloat deltax = xend - xstart;
+            const GLfloat deltay = yend - ystart;
+            const GLfloat angle = SDL_atan2f(deltay, deltax);
+            verts[2] += SDL_cosf(angle);
+            verts[3] += SDL_sinf(angle);
         }
     }
 
diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c
index 7f24726..4f02a68 100644
--- a/src/render/opengles2/SDL_render_gles2.c
+++ b/src/render/opengles2/SDL_render_gles2.c
@@ -800,15 +800,8 @@ GLES2_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_
         *(verts++) = 0.5f + points[i].y;
     }
 
-    /* If the line segment is completely horizontal or vertical,
-       make it one pixel longer, to satisfy the diamond-exit rule.
-       We should probably do this for diagonal lines too, but we'd have to
-       do some trigonometry to figure out the correct pixel and generally
-       when we have problems with pixel perfection, it's for straight lines
-       that are missing a pixel that frames something and not arbitrary
-       angles. Maybe !!! FIXME for later, though. */
-
-    /* update the last line. */
+    /* Make the last line segment one pixel longer, to satisfy the
+       diamond-exit rule. */
     verts -= 4;
     {
         const GLfloat xstart = verts[0];
@@ -820,6 +813,12 @@ GLES2_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_
             verts[2] += (xend > xstart) ? 1.0f : -1.0f;
         } else if (xstart == xend) {  /* vertical line */
             verts[3] += (yend > ystart) ? 1.0f : -1.0f;
+        } else {  /* bump a pixel in the direction we are moving in. */
+            const GLfloat deltax = xend - xstart;
+            const GLfloat deltay = yend - ystart;
+            const GLfloat angle = SDL_atan2f(deltay, deltax);
+            verts[2] += SDL_cosf(angle);
+            verts[3] += SDL_sinf(angle);
         }
     }