SDL: Added SDL_SetSurfaceScaleMode() and SDL_GetSurfaceScaleMode() to control scale mode using SDL_BlitSurfaceScaled()

From 84a0d5f623b35952243aea737b2630ab5aa941e9 Mon Sep 17 00:00:00 2001
From: Sylvain <[EMAIL REDACTED]>
Date: Thu, 14 Dec 2023 21:26:18 +0100
Subject: [PATCH] Added SDL_SetSurfaceScaleMode() and SDL_GetSurfaceScaleMode()
 to control scale mode using SDL_BlitSurfaceScaled()

---
 WhatsNew.txt                      |  1 +
 include/SDL3/SDL_render.h         | 10 -------
 include/SDL3/SDL_surface.h        | 45 +++++++++++++++++++++++++++++++
 src/dynapi/SDL_dynapi.sym         |  2 ++
 src/dynapi/SDL_dynapi_overrides.h |  2 ++
 src/dynapi/SDL_dynapi_procs.h     |  2 ++
 src/video/SDL_surface.c           | 36 +++++++++++++++++++++++--
 7 files changed, 86 insertions(+), 12 deletions(-)

diff --git a/WhatsNew.txt b/WhatsNew.txt
index 1b84c49b9b06..18dfd84cbd62 100644
--- a/WhatsNew.txt
+++ b/WhatsNew.txt
@@ -30,3 +30,4 @@ General:
 * Added SDL_PlayAudioDevice() to start audio playback
 * Added SDL_ConvertAudioSamples() to convert audio samples from one format to another
 * Added the hint SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY to control re-creation of Android SDL activity.
+* Added SDL_SetSurfaceScaleMode() and SDL_GetSurfaceScaleMode() to control scale mode using SDL_BlitSurfaceScaled()
diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index af5889ba9de9..15b0836b485e 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -95,16 +95,6 @@ typedef struct SDL_Vertex
     SDL_FPoint tex_coord;       /**< Normalized texture coordinates, if needed */
 } SDL_Vertex;
 
-/**
- * The scaling mode for a texture.
- */
-typedef enum
-{
-    SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */
-    SDL_SCALEMODE_LINEAR,  /**< linear filtering */
-    SDL_SCALEMODE_BEST     /**< anisotropic filtering */
-} SDL_ScaleMode;
-
 /**
  * The access pattern allowed for a texture.
  */
diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h
index aefb4233844f..c9e5f765af7e 100644
--- a/include/SDL3/SDL_surface.h
+++ b/include/SDL3/SDL_surface.h
@@ -64,6 +64,17 @@ extern "C" {
 
 typedef struct SDL_BlitMap SDL_BlitMap;  /* this is an opaque type. */
 
+/**
+ * The scaling mode
+ */
+typedef enum
+{
+    SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */
+    SDL_SCALEMODE_LINEAR,  /**< linear filtering */
+    SDL_SCALEMODE_BEST     /**< anisotropic filtering */
+} SDL_ScaleMode;
+
+
 /**
  * A collection of pixels used in software blitting.
  *
@@ -104,6 +115,8 @@ typedef struct SDL_Surface
     /** clipping information */
     SDL_Rect clip_rect;         /**< Read-only */
 
+    SDL_ScaleMode scaleMode;    /**< The scale mode */
+
     /** info for fast blit mapping to other surfaces */
     SDL_BlitMap *map;           /**< Private */
 
@@ -903,6 +916,7 @@ extern DECLSPEC int SDLCALL SDL_SoftStretchLinear(SDL_Surface *src,
  * \since This function is available since SDL 3.0.0.
  *
  * \sa SDL_BlitSurface
+ * \sa SDL_SetSurfaceScaleMode
  */
 extern DECLSPEC int SDLCALL SDL_BlitSurfaceScaled
     (SDL_Surface *src, const SDL_Rect *srcrect,
@@ -926,11 +940,42 @@ extern DECLSPEC int SDLCALL SDL_BlitSurfaceScaled
  * \since This function is available since SDL 3.0.0.
  *
  * \sa SDL_BlitSurfaceScaled
+ * \sa SDL_SetSurfaceScaleMode
  */
 extern DECLSPEC int SDLCALL SDL_BlitSurfaceUncheckedScaled
     (SDL_Surface *src, const SDL_Rect *srcrect,
      SDL_Surface *dst, const SDL_Rect *dstrect);
 
+/**
+ * Set the scale mode used for surface scale operations.
+ *
+ * \param surface the surface to update.
+ * \param scaleMode the SDL_ScaleMode to use for scaling.
+ * \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_GetSurfaceScaleMode
+ * \sa SDL_BlitSurfaceScaled
+ */
+extern DECLSPEC int SDLCALL SDL_SetSurfaceScaleMode(SDL_Surface *surface, SDL_ScaleMode scaleMode);
+
+/**
+ * Get the scale mode used for surface scale operations.
+ *
+ * \param surface the surface to query.
+ * \param scaleMode a pointer filled in with the current scale mode.
+ * \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_SetSurfaceScaleMode
+ * \sa SDL_BlitSurfaceScaled
+ */
+extern DECLSPEC int SDLCALL SDL_GetSurfaceScaleMode(SDL_Surface *surface, SDL_ScaleMode *scaleMode);
+
 /**
  * Set the YUV conversion mode
  *
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index e4747421af62..7a68abb99806 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -963,6 +963,8 @@ SDL3_0.0.0 {
     SDL_strnstr;
     SDL_wcsnstr;
     SDL_SyncWindow;
+    SDL_SetSurfaceScaleMode;
+    SDL_GetSurfaceScaleMode;
     # extra symbols go here (don't modify this line)
   local: *;
 };
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 25d834ce6036..acfbb8c7cf90 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -988,3 +988,5 @@
 #define SDL_strnstr SDL_strnstr_REAL
 #define SDL_wcsnstr SDL_wcsnstr_REAL
 #define SDL_SyncWindow SDL_SyncWindow_REAL
+#define SDL_SetSurfaceScaleMode SDL_SetSurfaceScaleMode_REAL
+#define SDL_GetSurfaceScaleMode SDL_GetSurfaceScaleMode_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index e6d79cc035bf..faf3d553e2a0 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -1013,3 +1013,5 @@ SDL_DYNAPI_PROC(const char*,SDL_GetTouchDeviceName,(SDL_TouchID a),(a),return)
 SDL_DYNAPI_PROC(char*,SDL_strnstr,(const char *a, const char *b, size_t c),(a,b,c),return)
 SDL_DYNAPI_PROC(wchar_t*,SDL_wcsnstr,(const wchar_t *a, const wchar_t *b, size_t c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_SyncWindow,(SDL_Window *a),(a),return)
+SDL_DYNAPI_PROC(int,SDL_SetSurfaceScaleMode,(SDL_Surface *a, SDL_ScaleMode b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_GetSurfaceScaleMode,(SDL_Surface *a, SDL_ScaleMode *b),(a,b),return)
diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index 7b26b5e2eb41..a86f8e068af6 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -776,7 +776,7 @@ int SDL_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect,
 int SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect,
                         SDL_Surface *dst, SDL_Rect *dstrect)
 {
-    return SDL_PrivateBlitSurfaceScaled(src, srcrect, dst, dstrect, SDL_SCALEMODE_NEAREST);
+    return SDL_PrivateBlitSurfaceScaled(src, srcrect, dst, dstrect, src->scaleMode);
 }
 
 int SDL_PrivateBlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect,
@@ -944,7 +944,7 @@ int SDL_PrivateBlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect,
 int SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect,
                                    SDL_Surface *dst, const SDL_Rect *dstrect)
 {
-    return SDL_PrivateBlitSurfaceUncheckedScaled(src, srcrect, dst, dstrect, SDL_SCALEMODE_NEAREST);
+    return SDL_PrivateBlitSurfaceUncheckedScaled(src, srcrect, dst, dstrect, src->scaleMode);
 }
 
 int SDL_PrivateBlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect,
@@ -1051,6 +1051,38 @@ int SDL_PrivateBlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcr
     }
 }
 
+int SDL_SetSurfaceScaleMode(SDL_Surface *surface, SDL_ScaleMode scaleMode)
+{
+    if (!surface) {
+        return SDL_InvalidParamError("surface");
+    }
+
+    if (scaleMode != SDL_SCALEMODE_NEAREST && scaleMode != SDL_SCALEMODE_LINEAR && scaleMode != SDL_SCALEMODE_BEST) {
+        return SDL_InvalidParamError("scaleMode");
+    }
+
+    if (scaleMode == SDL_SCALEMODE_NEAREST) {
+        surface->scaleMode = SDL_SCALEMODE_NEAREST;
+    } else {
+        surface->scaleMode = SDL_SCALEMODE_LINEAR;
+    }
+
+    return 0;
+}
+
+int SDL_GetSurfaceScaleMode(SDL_Surface *surface, SDL_ScaleMode *scaleMode)
+{
+    if (!surface) {
+        return SDL_InvalidParamError("surface");
+    }
+
+    if (scaleMode) {
+        *scaleMode = surface->scaleMode;
+    }
+
+    return 0;
+}
+
 /*
  * Lock a surface to directly access the pixels
  */