SDL: Fixed rendering diagonal lines within a viewport

From 6a00ae7e58a702a9cba9689a4b9d23639079f9dc Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 19 Jan 2024 16:28:00 -0800
Subject: [PATCH] Fixed rendering diagonal lines within a viewport

The drawing uses the origin of the viewport as the coordinate origin, so we only need to clip against the size of the viewport.

Also added a unit test to catch this case in the future
---
 src/render/SDL_render.c      |  2 ++
 test/testautomation_render.c | 54 ++++++++++++++++++++++++++++++++----
 2 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 27ddbc132070..06da0b920fbe 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -2776,6 +2776,8 @@ static int RenderLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2, i
        just want a basic safety against generating millions of points for
        massive lines. */
     GetRenderViewportInPixels(renderer, &viewport);
+    viewport.x = 0;
+    viewport.y = 0;
     if (!SDL_GetRectAndLineIntersection(&viewport, &x1, &y1, &x2, &y2)) {
         return 0;
     }
diff --git a/test/testautomation_render.c b/test/testautomation_render.c
index 67b1f4124cde..b9546efd736e 100644
--- a/test/testautomation_render.c
+++ b/test/testautomation_render.c
@@ -332,6 +332,44 @@ static int render_testPrimitivesBlend(void *arg)
     return TEST_COMPLETED;
 }
 
+/**
+ * Tests the SDL primitives for rendering within a viewport.
+ *
+ * \sa SDL_SetRenderDrawColor
+ * \sa SDL_RenderFillRect
+ * \sa SDL_RenderLine
+ *
+ */
+static int render_testPrimitivesWithViewport(void *arg)
+{
+    SDL_Rect viewport;
+    Uint32 pixel;
+
+    /* Clear surface. */
+    clearScreen();
+
+    viewport.x = 2;
+    viewport.y = 2;
+    viewport.w = 2;
+    viewport.h = 2;
+    CHECK_FUNC(SDL_SetRenderViewport, (renderer, &viewport));
+
+    CHECK_FUNC(SDL_SetRenderDrawColor, (renderer, 255, 255, 255, SDL_ALPHA_OPAQUE))
+    CHECK_FUNC(SDL_RenderLine, (renderer, 0.0f, 0.0f, 1.0f, 1.0f));
+
+    viewport.x = 3;
+    viewport.y = 3;
+    viewport.w = 1;
+    viewport.h = 1;
+    CHECK_FUNC(SDL_SetRenderViewport, (renderer, &viewport));
+
+    pixel = 0;
+    CHECK_FUNC(SDL_RenderReadPixels, (renderer, NULL, SDL_PIXELFORMAT_RGBA8888, &pixel, sizeof(pixel)));
+    SDLTest_AssertCheck(pixel == 0xFFFFFFFF, "Validate diagonal line drawing with viewport, expected 0xFFFFFFFF, got 0x%.8x", pixel);
+
+    return TEST_COMPLETED;
+}
+
 /**
  * Tests some blitting routines.
  *
@@ -1250,28 +1288,32 @@ static const SDLTest_TestCaseReference renderTest3 = {
 };
 
 static const SDLTest_TestCaseReference renderTest4 = {
-    (SDLTest_TestCaseFp)render_testBlit, "render_testBlit", "Tests blitting", TEST_ENABLED
+    (SDLTest_TestCaseFp)render_testPrimitivesWithViewport, "render_testPrimitivesWithViewport", "Tests rendering primitives within a viewport", TEST_ENABLED
 };
 
 static const SDLTest_TestCaseReference renderTest5 = {
+    (SDLTest_TestCaseFp)render_testBlit, "render_testBlit", "Tests blitting", TEST_ENABLED
+};
+
+static const SDLTest_TestCaseReference renderTest6 = {
     (SDLTest_TestCaseFp)render_testBlitColor, "render_testBlitColor", "Tests blitting with color", TEST_ENABLED
 };
 
 /* TODO: rewrite test case, define new test data and re-enable; current implementation fails */
-static const SDLTest_TestCaseReference renderTest6 = {
+static const SDLTest_TestCaseReference renderTest7 = {
     (SDLTest_TestCaseFp)render_testBlitAlpha, "render_testBlitAlpha", "Tests blitting with alpha", TEST_DISABLED
 };
 
 /* TODO: rewrite test case, define new test data and re-enable; current implementation fails */
-static const SDLTest_TestCaseReference renderTest7 = {
+static const SDLTest_TestCaseReference renderTest8 = {
     (SDLTest_TestCaseFp)render_testBlitBlend, "render_testBlitBlend", "Tests blitting with blending", TEST_DISABLED
 };
 
-static const SDLTest_TestCaseReference renderTest8 = {
+static const SDLTest_TestCaseReference renderTest9 = {
     (SDLTest_TestCaseFp)render_testViewport, "render_testViewport", "Tests viewport", TEST_ENABLED
 };
 
-static const SDLTest_TestCaseReference renderTest9 = {
+static const SDLTest_TestCaseReference renderTest10 = {
     (SDLTest_TestCaseFp)render_testLogicalSize, "render_testLogicalSize", "Tests logical size", TEST_ENABLED
 };
 
@@ -1279,7 +1321,7 @@ static const SDLTest_TestCaseReference renderTest9 = {
 static const SDLTest_TestCaseReference *renderTests[] = {
     &renderTest1, &renderTest2, &renderTest3, &renderTest4,
     &renderTest5, &renderTest6, &renderTest7, &renderTest8,
-    &renderTest9, NULL
+    &renderTest9, &renderTest10, NULL
 };
 
 /* Render test suite (global) */