From 1ae61f1009abff4cf7c5d85d33da4b3d7b4e208b Mon Sep 17 00:00:00 2001 From: Sylvain Becker Date: Mon, 30 Sep 2019 20:58:44 +0200 Subject: [PATCH] Added a helper function SDL_LockTextureToSurface() Similar to SDL_LockTexture(), except the locked area is exposed as a SDL surface. --- WhatsNew.txt | 7 +++++ include/SDL_render.h | 21 ++++++++++++++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/render/SDL_render.c | 46 +++++++++++++++++++++++++++++++ src/render/SDL_sysrender.h | 1 + 6 files changed, 77 insertions(+) diff --git a/WhatsNew.txt b/WhatsNew.txt index faecf1d38dddd..ef2b07b57df8c 100644 --- a/WhatsNew.txt +++ b/WhatsNew.txt @@ -1,6 +1,13 @@ This is a list of major changes in SDL's version history. +--------------------------------------------------------------------------- +2.0.11/12: +--------------------------------------------------------------------------- + +General: +* Added SDL_LockTextureToSurface(), similar to SDL_LockTexture() but the locked area is exposed as a SDL surface. + --------------------------------------------------------------------------- 2.0.10: --------------------------------------------------------------------------- diff --git a/include/SDL_render.h b/include/SDL_render.h index 096b4a5771070..c2a995afb576e 100644 --- a/include/SDL_render.h +++ b/include/SDL_render.h @@ -430,10 +430,31 @@ extern DECLSPEC int SDLCALL SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, void **pixels, int *pitch); +/** + * \brief Lock a portion of the texture for write-only pixel access. + * Expose it as a SDL surface. + * + * \param texture The texture to lock for access, which was created with + * ::SDL_TEXTUREACCESS_STREAMING. + * \param rect A pointer to the rectangle to lock for access. If the rect + * is NULL, the entire texture will be locked. + * \param surface This is filled in with a SDL surface representing the locked area + * Surface is freed internally after calling SDL_UnlockTexture or SDL_DestroyTexture. + * + * \return 0 on success, or -1 if the texture is not valid or was not created with ::SDL_TEXTUREACCESS_STREAMING. + * + * \sa SDL_UnlockTexture() + */ +extern DECLSPEC int SDLCALL SDL_LockTextureToSurface(SDL_Texture *texture, + const SDL_Rect *rect, + SDL_Surface **surface); + /** * \brief Unlock a texture, uploading the changes to video memory, if needed. + * If SDL_LockTextureToSurface() was called for locking, the SDL surface is freed. * * \sa SDL_LockTexture() + * \sa SDL_LockTextureToSurface() */ extern DECLSPEC void SDLCALL SDL_UnlockTexture(SDL_Texture * texture); diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index c769582fdc794..caab1c8e89a6a 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -315,6 +315,7 @@ #define SDL_UpdateTexture SDL_UpdateTexture_REAL #define SDL_UpdateYUVTexture SDL_UpdateYUVTexture_REAL #define SDL_LockTexture SDL_LockTexture_REAL +#define SDL_LockTextureToSurface SDL_LockTextureToSurface_REAL #define SDL_UnlockTexture SDL_UnlockTexture_REAL #define SDL_RenderTargetSupported SDL_RenderTargetSupported_REAL #define SDL_SetRenderTarget SDL_SetRenderTarget_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index e94d5de484dd6..01e1f39f6cb79 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -346,6 +346,7 @@ SDL_DYNAPI_PROC(int,SDL_GetTextureBlendMode,(SDL_Texture *a, SDL_BlendMode *b),( SDL_DYNAPI_PROC(int,SDL_UpdateTexture,(SDL_Texture *a, const SDL_Rect *b, const void *c, int d),(a,b,c,d),return) SDL_DYNAPI_PROC(int,SDL_UpdateYUVTexture,(SDL_Texture *a, const SDL_Rect *b, const Uint8 *c, int d, const Uint8 *e, int f, const Uint8 *g, int h),(a,b,c,d,e,f,g,h),return) SDL_DYNAPI_PROC(int,SDL_LockTexture,(SDL_Texture *a, const SDL_Rect *b, void **c, int *d),(a,b,c,d),return) +SDL_DYNAPI_PROC(int,SDL_LockTextureToSurface,(SDL_Texture *a, const SDL_Rect *b, SDL_Surface **c),(a,b,c),return) SDL_DYNAPI_PROC(void,SDL_UnlockTexture,(SDL_Texture *a),(a),) SDL_DYNAPI_PROC(SDL_bool,SDL_RenderTargetSupported,(SDL_Renderer *a),(a),return) SDL_DYNAPI_PROC(int,SDL_SetRenderTarget,(SDL_Renderer *a, SDL_Texture *b),(a,b),return) diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 2b5b4c2e2dc68..2ea2504a350f4 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -1680,6 +1680,45 @@ SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, } } +int +SDL_LockTextureToSurface(SDL_Texture *texture, const SDL_Rect *rect, + SDL_Surface **surface) +{ + SDL_Rect r; + void *pixels = NULL; + int pitch, ret; + + if (texture == NULL || surface == NULL) { + return -1; + } + + if (rect == NULL) { + r.x = 0; + r.y = 0; + r.w = texture->w; + r.h = texture->h; + } else { + r.x = rect->x; + r.y = rect->y; + r.w = SDL_min(texture->w - rect->x, rect->w); + r.h = SDL_min(texture->h - rect->y, rect->h); + } + + ret = SDL_LockTexture(texture, &r, &pixels, &pitch); + if (ret < 0) { + return ret; + } + + texture->locked_surface = SDL_CreateRGBSurfaceWithFormatFrom(pixels, r.w, r.h, 0, pitch, texture->format); + if (texture->locked_surface == NULL) { + SDL_UnlockTexture(texture); + return -1; + } + + *surface = texture->locked_surface; + return 0; +} + static void SDL_UnlockTextureYUV(SDL_Texture * texture) { @@ -1738,6 +1777,9 @@ SDL_UnlockTexture(SDL_Texture * texture) SDL_Renderer *renderer = texture->renderer; renderer->UnlockTexture(renderer, texture); } + + SDL_FreeSurface(texture->locked_surface); + texture->locked_surface = NULL; } SDL_bool @@ -3090,6 +3132,10 @@ SDL_DestroyTexture(SDL_Texture * texture) SDL_free(texture->pixels); renderer->DestroyTexture(renderer, texture); + + SDL_FreeSurface(texture->locked_surface); + texture->locked_surface = NULL; + SDL_free(texture); } diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index dedd64200d4ad..a93e21c589bbd 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -60,6 +60,7 @@ struct SDL_Texture void *pixels; int pitch; SDL_Rect locked_rect; + SDL_Surface *locked_surface; /**< Locked region exposed as a SDL surface */ Uint32 last_command_generation; /* last command queue generation this texture was in. */