SDL: SDL_RenderGeometry / software: TRIANGLE_GET_TEXTCOORD interpolates up to the max values included, so reduce by 1

From 8622eda9e9fe874826a51943570788486e0a9a9d Mon Sep 17 00:00:00 2001
From: Sylvain <[EMAIL REDACTED]>
Date: Sun, 2 Jan 2022 22:34:56 +0100
Subject: [PATCH] SDL_RenderGeometry / software: TRIANGLE_GET_TEXTCOORD
 interpolates up to the max values included, so reduce by 1

---
 src/render/software/SDL_triangle.c | 43 +++++++++++++++++++++++++-----
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/src/render/software/SDL_triangle.c b/src/render/software/SDL_triangle.c
index da8aa03ec19..36dc8c1bb57 100644
--- a/src/render/software/SDL_triangle.c
+++ b/src/render/software/SDL_triangle.c
@@ -119,8 +119,8 @@ void trianglepoint_2_fixedpoint(SDL_Point *a) {
     a->y <<= FP_BITS;
 }
 
-/* bounding rect of three points */
-static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r)
+/* bounding rect of three points (in fixed point) */
+static void bounding_rect_fixedpoint(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r)
 {
     int min_x = SDL_min(a->x, SDL_min(b->x, c->x));
     int max_x = SDL_max(a->x, SDL_max(b->x, c->x));
@@ -133,6 +133,20 @@ static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Poin
     r->h = (max_y - min_y) >> FP_BITS;
 }
 
+/* bounding rect of three points */
+static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r)
+{
+    int min_x = SDL_min(a->x, SDL_min(b->x, c->x));
+    int max_x = SDL_max(a->x, SDL_max(b->x, c->x));
+    int min_y = SDL_min(a->y, SDL_min(b->y, c->y));
+    int max_y = SDL_max(a->y, SDL_max(b->y, c->y));
+    r->x = min_x;
+    r->y = min_y;
+    r->w = (max_x - min_x);
+    r->h = (max_y - min_y);
+}
+
+
 /* Triangle rendering, using Barycentric coordinates (w0, w1, w2)
  *
  * The cross product isn't computed from scratch at each iteration,
@@ -232,7 +246,7 @@ int SDL_SW_FillTriangle(SDL_Surface *dst, SDL_Point *d0, SDL_Point *d1, SDL_Poin
         }
     }
 
-    bounding_rect(d0, d1, d2, &dstrect);
+    bounding_rect_fixedpoint(d0, d1, d2, &dstrect);
 
     {
         /* Clip triangle rect with surface rect */
@@ -438,7 +452,6 @@ int SDL_SW_BlitTriangle(
 
     SDL_BlendMode blend;
 
-    SDL_Rect srcrect;
     SDL_Rect dstrect;
 
     SDL_Point s2_x_area;
@@ -495,11 +508,29 @@ int SDL_SW_BlitTriangle(
 
     is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2);
 
-    bounding_rect(s0, s1, s2, &srcrect);
-    bounding_rect(d0, d1, d2, &dstrect);
+    bounding_rect_fixedpoint(d0, d1, d2, &dstrect);
 
     SDL_GetSurfaceBlendMode(src, &blend);
 
+    /* TRIANGLE_GET_TEXTCOORD interpolates up to the max values included, so reduce by 1 */
+    {
+        SDL_Rect srcrect;
+        int maxx, maxy;
+        bounding_rect(s0, s1, s2, &srcrect);
+        maxx = srcrect.x + srcrect.w;
+        maxy = srcrect.y + srcrect.h;
+        if (srcrect.w > 0) {
+            if (s0->x == maxx) s0->x--;
+            if (s1->x == maxx) s1->x--;
+            if (s2->x == maxx) s2->x--;
+        }
+        if (srcrect.h > 0) {
+            if (s0->y == maxy) s0->y--;
+            if (s1->y == maxy) s1->y--;
+            if (s2->y == maxy) s2->y--;
+        }
+    }
+
     if (is_uniform) {
         // SDL_GetSurfaceColorMod(src, &r, &g, &b);
         has_modulation = c0.r != 255 || c0.g != 255 || c0.b != 255 || c0.a != 255;;