Browse Source

Added SDL_ScaleSurface()

Sam Lantinga 1 year ago
parent
commit
22ffb487d0

+ 19 - 1
include/SDL3/SDL_surface.h

@@ -691,6 +691,24 @@ extern SDL_DECLSPEC int SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipMo
  */
 extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_DuplicateSurface(SDL_Surface *surface);
 
+/**
+ * Creates a new surface identical to the existing surface, scaled to the desired size.
+ *
+ * The returned surface should be freed with SDL_DestroySurface().
+ *
+ * \param surface the surface to duplicate and scale.
+ * \param width the width of the new surface.
+ * \param height the height of the new surface.
+ * \param scaleMode the SDL_ScaleMode to be used.
+ * \returns a copy of the surface or NULL on failure; call SDL_GetError() for
+ *          more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_DestroySurface
+ */
+extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ScaleSurface(SDL_Surface *surface, int width, int height, SDL_ScaleMode scaleMode);
+
 /**
  * Copy an existing surface to a new surface of the specified format.
  *
@@ -1031,7 +1049,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src, const SD
  * \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, may not be NULL.
- * \param scaleMode scale algorithm to be used.
+ * \param scaleMode the SDL_ScaleMode to be used.
  * \returns 0 on success or a negative error code on failure; call
  *          SDL_GetError() for more information.
  *

+ 1 - 0
src/dynapi/SDL_dynapi.sym

@@ -687,6 +687,7 @@ SDL3_0.0.0 {
     SDL_RunHapticEffect;
     SDL_SaveBMP;
     SDL_SaveBMP_IO;
+    SDL_ScaleSurface;
     SDL_ScreenKeyboardShown;
     SDL_ScreenSaverEnabled;
     SDL_SeekIO;

+ 1 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -712,6 +712,7 @@
 #define SDL_RunHapticEffect SDL_RunHapticEffect_REAL
 #define SDL_SaveBMP SDL_SaveBMP_REAL
 #define SDL_SaveBMP_IO SDL_SaveBMP_IO_REAL
+#define SDL_ScaleSurface SDL_ScaleSurface_REAL
 #define SDL_ScreenKeyboardShown SDL_ScreenKeyboardShown_REAL
 #define SDL_ScreenSaverEnabled SDL_ScreenSaverEnabled_REAL
 #define SDL_SeekIO SDL_SeekIO_REAL

+ 1 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -723,6 +723,7 @@ SDL_DYNAPI_PROC(int,SDL_RunApp,(int a, char *b[], SDL_main_func c, void *d),(a,b
 SDL_DYNAPI_PROC(int,SDL_RunHapticEffect,(SDL_Haptic *a, int b, Uint32 c),(a,b,c),return)
 SDL_DYNAPI_PROC(int,SDL_SaveBMP,(SDL_Surface *a, const char *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SaveBMP_IO,(SDL_Surface *a, SDL_IOStream *b, SDL_bool c),(a,b,c),return)
+SDL_DYNAPI_PROC(SDL_Surface*,SDL_ScaleSurface,(SDL_Surface *a, int b, int c, SDL_ScaleMode d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_ScreenKeyboardShown,(SDL_Window *a),(a),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_ScreenSaverEnabled,(void),(),return)
 SDL_DYNAPI_PROC(Sint64,SDL_SeekIO,(SDL_IOStream *a, Sint64 b, SDL_IOWhence c),(a,b,c),return)

+ 82 - 0
src/video/SDL_surface.c

@@ -1968,6 +1968,88 @@ SDL_Surface *SDL_DuplicateSurface(SDL_Surface *surface)
     return SDL_ConvertSurfaceAndColorspace(surface, surface->format, surface->internal->palette, surface->internal->colorspace, surface->internal->props);
 }
 
+SDL_Surface *SDL_ScaleSurface(SDL_Surface *surface, int width, int height, SDL_ScaleMode scaleMode)
+{
+    SDL_Surface *convert = NULL;
+    Uint32 copy_flags;
+    SDL_Color copy_color;
+    int ret;
+
+    if (!SDL_SurfaceValid(surface)) {
+        SDL_InvalidParamError("surface");
+        goto error;
+    }
+
+    if (SDL_ISPIXELFORMAT_FOURCC(surface->format)) {
+        // We can't directly scale a YUV surface (yet!)
+        SDL_Surface *tmp = SDL_CreateSurface(surface->w, surface->h, SDL_PIXELFORMAT_ARGB8888);
+        if (!tmp) {
+            return NULL;
+        }
+
+        SDL_Surface *scaled = SDL_ScaleSurface(tmp, width, height, scaleMode);
+        SDL_DestroySurface(tmp);
+        if (!scaled) {
+            return NULL;
+        }
+        tmp = scaled;
+
+        SDL_Surface *result = SDL_ConvertSurfaceAndColorspace(tmp, surface->format, NULL, surface->internal->colorspace, surface->internal->props);
+        SDL_DestroySurface(tmp);
+        return result;
+    }
+
+    /* Create a new surface with the desired size */
+    convert = SDL_CreateSurface(width, height, surface->format);
+    if (!convert) {
+        goto error;
+    }
+    SDL_SetSurfacePalette(convert, surface->internal->palette);
+    SDL_SetSurfaceColorspace(convert, surface->internal->colorspace);
+
+    /* Save the original copy flags */
+    copy_flags = surface->internal->map.info.flags;
+    copy_color.r = surface->internal->map.info.r;
+    copy_color.g = surface->internal->map.info.g;
+    copy_color.b = surface->internal->map.info.b;
+    copy_color.a = surface->internal->map.info.a;
+    surface->internal->map.info.r = 0xFF;
+    surface->internal->map.info.g = 0xFF;
+    surface->internal->map.info.b = 0xFF;
+    surface->internal->map.info.a = 0xFF;
+    surface->internal->map.info.flags = (copy_flags & (SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY));
+    SDL_InvalidateMap(&surface->internal->map);
+
+    ret = SDL_BlitSurfaceScaled(surface, NULL, convert, NULL, scaleMode);
+
+    /* Clean up the original surface, and update converted surface */
+    convert->internal->map.info.r = copy_color.r;
+    convert->internal->map.info.g = copy_color.g;
+    convert->internal->map.info.b = copy_color.b;
+    convert->internal->map.info.a = copy_color.a;
+    convert->internal->map.info.flags = (copy_flags & ~(SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY));
+    surface->internal->map.info.r = copy_color.r;
+    surface->internal->map.info.g = copy_color.g;
+    surface->internal->map.info.b = copy_color.b;
+    surface->internal->map.info.a = copy_color.a;
+    surface->internal->map.info.flags = copy_flags;
+    SDL_InvalidateMap(&surface->internal->map);
+
+    /* SDL_BlitSurfaceScaled failed, and so the conversion */
+    if (ret < 0) {
+        goto error;
+    }
+
+    /* We're ready to go! */
+    return convert;
+
+error:
+    if (convert) {
+        SDL_DestroySurface(convert);
+    }
+    return NULL;
+}
+
 SDL_Surface *SDL_ConvertSurface(SDL_Surface *surface, SDL_PixelFormat format)
 {
     if (!SDL_SurfaceValid(surface)) {