diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h index 552b0acc10..6bde401785 100644 --- a/include/SDL3/SDL_surface.h +++ b/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. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 299fb40380..49a9f25843 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/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; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 6c7b6b158d..b1e0dce8e1 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/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 diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index d66790999b..be11aa8eb6 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/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) diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index c41b850723..7f83fd6fa3 100644 --- a/src/video/SDL_surface.c +++ b/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)) {