SDL: Add scaleMode to SDL_SoftStretch(), remove SDL_SoftStretchLinear().

From ffd82fb7c447ad47c0298083a0c6ca2bcd7b9066 Mon Sep 17 00:00:00 2001
From: Sylvain <[EMAIL REDACTED]>
Date: Fri, 22 Dec 2023 15:02:43 +0100
Subject: [PATCH] Add scaleMode to SDL_SoftStretch(), remove
 SDL_SoftStretchLinear().

---
 build-scripts/SDL_migration.cocci | 10 ++++++++++
 docs/README-migration.md          |  5 +++++
 include/SDL3/SDL_surface.h        | 32 +++++++------------------------
 src/dynapi/SDL_dynapi.sym         |  1 -
 src/dynapi/SDL_dynapi_overrides.h |  1 -
 src/dynapi/SDL_dynapi_procs.h     |  3 +--
 src/render/SDL_yuv_sw.c           |  2 +-
 src/video/SDL_stretch.c           | 25 +++++++++++-------------
 src/video/SDL_surface.c           |  8 ++++----
 9 files changed, 39 insertions(+), 48 deletions(-)

diff --git a/build-scripts/SDL_migration.cocci b/build-scripts/SDL_migration.cocci
index 9220d4d31f3c..6cb692f30799 100644
--- a/build-scripts/SDL_migration.cocci
+++ b/build-scripts/SDL_migration.cocci
@@ -2754,3 +2754,13 @@ expression w, i, s;
 - SDL_GameControllerGetSteamHandle
 + SDL_GetGamepadSteamHandle
   (...)
+@@
+expression e1, e2, e3, e4;
+@@
+- SDL_SoftStretch(e1, e2, e3, e4)
++ SDL_SoftStretch(e1, e2, e3, e4, SDL_SCALEMODE_NEAREST)
+@@
+expression e1, e2, e3, e4;
+@@
+- SDL_SoftStretchLinear(e1, e2, e3, e4)
++ SDL_SoftStretch(e1, e2, e3, e4, SDL_SCALEMODE_LINEAR)
diff --git a/docs/README-migration.md b/docs/README-migration.md
index a90e32511d7c..7f554277a043 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -1160,6 +1160,8 @@ But if you're migrating your code which uses masks, you probably have a format i
 
 SDL_BlitSurfaceScaled() and SDL_BlitSurfaceUncheckedScaled() now take a scale paramater.
 
+SDL_SoftStretch() now takes a scale paramater.
+
 The following functions have been renamed:
 * SDL_FillRect() => SDL_FillSurfaceRect()
 * SDL_FillRects() => SDL_FillSurfaceRects()
@@ -1175,6 +1177,9 @@ The following functions have been renamed:
 * SDL_UpperBlit() => SDL_BlitSurface()
 * SDL_UpperBlitScaled() => SDL_BlitSurfaceScaled()
 
+The following functions have been removed:
+* SDL_SoftStretchLinear() - use SDL_SoftStretch() with SDL_SCALEMODE_LINEAR
+
 ## SDL_system.h
 
 SDL_WindowsMessageHook has changed signatures so the message may be modified and it can block further message processing.
diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h
index 42315073590b..e322d6ac0c0b 100644
--- a/include/SDL3/SDL_surface.h
+++ b/include/SDL3/SDL_surface.h
@@ -861,29 +861,10 @@ extern DECLSPEC int SDLCALL SDL_BlitSurfaceUnchecked
      SDL_Surface *dst, const SDL_Rect *dstrect);
 
 /**
- * Perform a fast, low quality, stretch blit between two surfaces of the same
- * format.
+ * Perform stretch blit between two surfaces of the same format.
  *
- * \param src the SDL_Surface structure to be copied from
- * \param srcrect the SDL_Rect structure representing the rectangle to be
- *                copied
- * \param dst the SDL_Surface structure that is the blit target
- * \param dstrect the SDL_Rect structure representing the target rectangle in
- *                the destination surface
- * \returns 0 on success or a negative error code on failure; call
- *          SDL_GetError() for more information.
- *
- * \since This function is available since SDL 3.0.0.
- *
- * \sa SDL_BlitSurfaceScaled
- */
-extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src,
-                                            const SDL_Rect *srcrect,
-                                            SDL_Surface *dst,
-                                            const SDL_Rect *dstrect);
-
-/**
- * Perform bilinear scaling between two surfaces of the same format, 32BPP.
+ * Using SDL_SCALEMODE_NEAREST: fast, low quality.
+ * Using SDL_SCALEMODE_LINEAR: bilinear scaling, slower, better quality, only 32BPP.
  *
  * \param src the SDL_Surface structure to be copied from
  * \param srcrect the SDL_Rect structure representing the rectangle to be
@@ -891,6 +872,7 @@ extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src,
  * \param dst the SDL_Surface structure that is the blit target
  * \param dstrect the SDL_Rect structure representing the target rectangle in
  *                the destination surface
+ * \param scaleMode scale algorithm to be used
  * \returns 0 on success or a negative error code on failure; call
  *          SDL_GetError() for more information.
  *
@@ -898,11 +880,11 @@ extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src,
  *
  * \sa SDL_BlitSurfaceScaled
  */
-extern DECLSPEC int SDLCALL SDL_SoftStretchLinear(SDL_Surface *src,
+extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src,
                                             const SDL_Rect *srcrect,
                                             SDL_Surface *dst,
-                                            const SDL_Rect *dstrect);
-
+                                            const SDL_Rect *dstrect,
+                                            SDL_ScaleMode scaleMode);
 
 /**
  * Perform a scaled surface copy to a destination surface.
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 2392a31bba5d..a72032cd281e 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -613,7 +613,6 @@ SDL3_0.0.0 {
     SDL_ShowWindow;
     SDL_SignalCondition;
     SDL_SoftStretch;
-    SDL_SoftStretchLinear;
     SDL_StartTextInput;
     SDL_StopTextInput;
     SDL_SurfaceHasColorKey;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 8482314dcb0e..451fadbd96e1 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -636,7 +636,6 @@
 #define SDL_ShowWindow SDL_ShowWindow_REAL
 #define SDL_SignalCondition SDL_SignalCondition_REAL
 #define SDL_SoftStretch SDL_SoftStretch_REAL
-#define SDL_SoftStretchLinear SDL_SoftStretchLinear_REAL
 #define SDL_StartTextInput SDL_StartTextInput_REAL
 #define SDL_StopTextInput SDL_StopTextInput_REAL
 #define SDL_SurfaceHasColorKey SDL_SurfaceHasColorKey_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 9cb62f4ba41a..5b3cb2d2025e 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -677,8 +677,7 @@ SDL_DYNAPI_PROC(int,SDL_ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,
 SDL_DYNAPI_PROC(int,SDL_ShowSimpleMessageBox,(Uint32 a, const char *b, const char *c, SDL_Window *d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(int,SDL_ShowWindow,(SDL_Window *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_SignalCondition,(SDL_Condition *a),(a),return)
-SDL_DYNAPI_PROC(int,SDL_SoftStretch,(SDL_Surface *a, const SDL_Rect *b, SDL_Surface *c, const SDL_Rect *d),(a,b,c,d),return)
-SDL_DYNAPI_PROC(int,SDL_SoftStretchLinear,(SDL_Surface *a, const SDL_Rect *b, SDL_Surface *c, const SDL_Rect *d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(int,SDL_SoftStretch,(SDL_Surface *a, const SDL_Rect *b, SDL_Surface *c, const SDL_Rect *d, SDL_ScaleMode e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(void,SDL_StartTextInput,(void),(),)
 SDL_DYNAPI_PROC(void,SDL_StopTextInput,(void),(),)
 SDL_DYNAPI_PROC(SDL_bool,SDL_SurfaceHasColorKey,(SDL_Surface *a),(a),return)
diff --git a/src/render/SDL_yuv_sw.c b/src/render/SDL_yuv_sw.c
index 9a4cc3ac2a3b..5761bcc58069 100644
--- a/src/render/SDL_yuv_sw.c
+++ b/src/render/SDL_yuv_sw.c
@@ -382,7 +382,7 @@ int SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture *swdata, const SDL_Rect *srcrect,
     }
     if (stretch) {
         SDL_Rect rect = *srcrect;
-        SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL);
+        SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL, SDL_SCALEMODE_NEAREST);
     }
     return 0;
 }
diff --git a/src/video/SDL_stretch.c b/src/video/SDL_stretch.c
index 3b628c262b10..1bc8c74f1fca 100644
--- a/src/video/SDL_stretch.c
+++ b/src/video/SDL_stretch.c
@@ -24,22 +24,10 @@
 
 static int SDL_LowerSoftStretchNearest(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
 static int SDL_LowerSoftStretchLinear(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
-static int SDL_UpperSoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode);
 
 int SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect,
-                    SDL_Surface *dst, const SDL_Rect *dstrect)
-{
-    return SDL_UpperSoftStretch(src, srcrect, dst, dstrect, SDL_SCALEMODE_NEAREST);
-}
-
-int SDL_SoftStretchLinear(SDL_Surface *src, const SDL_Rect *srcrect,
-                          SDL_Surface *dst, const SDL_Rect *dstrect)
-{
-    return SDL_UpperSoftStretch(src, srcrect, dst, dstrect, SDL_SCALEMODE_LINEAR);
-}
-
-static int SDL_UpperSoftStretch(SDL_Surface *src, const SDL_Rect *srcrect,
-                                SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode)
+                    SDL_Surface *dst, const SDL_Rect *dstrect,
+                    SDL_ScaleMode scaleMode)
 {
     int ret;
     int src_locked;
@@ -47,11 +35,20 @@ static int SDL_UpperSoftStretch(SDL_Surface *src, const SDL_Rect *srcrect,
     SDL_Rect full_src;
     SDL_Rect full_dst;
 
+
     if (src->format->format != dst->format->format) {
         return SDL_SetError("Only works with same format surfaces");
     }
 
+    if (scaleMode != SDL_SCALEMODE_NEAREST && scaleMode != SDL_SCALEMODE_LINEAR && scaleMode != SDL_SCALEMODE_BEST) {
+        return SDL_InvalidParamError("scaleMode");
+    }
+
     if (scaleMode != SDL_SCALEMODE_NEAREST) {
+        scaleMode = SDL_SCALEMODE_LINEAR;
+    }
+
+    if (scaleMode == SDL_SCALEMODE_LINEAR) {
         if (src->format->BytesPerPixel != 4 || src->format->format == SDL_PIXELFORMAT_ARGB2101010) {
             return SDL_SetError("Wrong format");
         }
diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index f4f0dbaea791..b0a57d4e6e5b 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -974,7 +974,7 @@ int SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect,
         if (!(src->map->info.flags & complex_copy_flags) &&
             src->format->format == dst->format->format &&
             !SDL_ISPIXELFORMAT_INDEXED(src->format->format)) {
-            return SDL_SoftStretch(src, srcrect, dst, dstrect);
+            return SDL_SoftStretch(src, srcrect, dst, dstrect, SDL_SCALEMODE_NEAREST);
         } else {
             return SDL_BlitSurfaceUnchecked(src, srcrect, dst, dstrect);
         }
@@ -985,7 +985,7 @@ int SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect,
             src->format->BytesPerPixel == 4 &&
             src->format->format != SDL_PIXELFORMAT_ARGB2101010) {
             /* fast path */
-            return SDL_SoftStretchLinear(src, srcrect, dst, dstrect);
+            return SDL_SoftStretch(src, srcrect, dst, dstrect, SDL_SCALEMODE_LINEAR);
         } else {
             /* Use intermediate surface(s) */
             SDL_Surface *tmp1 = NULL;
@@ -1035,7 +1035,7 @@ int SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect,
             if (is_complex_copy_flags || src->format->format != dst->format->format) {
                 SDL_Rect tmprect;
                 SDL_Surface *tmp2 = SDL_CreateSurface(dstrect->w, dstrect->h, src->format->format);
-                SDL_SoftStretchLinear(src, &srcrect2, tmp2, NULL);
+                SDL_SoftStretch(src, &srcrect2, tmp2, NULL, SDL_SCALEMODE_LINEAR);
 
                 SDL_SetSurfaceColorMod(tmp2, r, g, b);
                 SDL_SetSurfaceAlphaMod(tmp2, alpha);
@@ -1048,7 +1048,7 @@ int SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect,
                 ret = SDL_BlitSurfaceUnchecked(tmp2, &tmprect, dst, dstrect);
                 SDL_DestroySurface(tmp2);
             } else {
-                ret = SDL_SoftStretchLinear(src, &srcrect2, dst, dstrect);
+                ret = SDL_SoftStretch(src, &srcrect2, dst, dstrect, SDL_SCALEMODE_LINEAR);
             }
 
             SDL_DestroySurface(tmp1);