Skip to content

Commit

Permalink
Added SDL_BlitSurface9Grid() and SDL_RenderTexture9Grid()
Browse files Browse the repository at this point in the history
  • Loading branch information
slouken committed Jul 20, 2024
1 parent 7a19432 commit 8013ffe
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 0 deletions.
22 changes: 22 additions & 0 deletions include/SDL3/SDL_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -1898,6 +1898,28 @@ extern SDL_DECLSPEC int SDLCALL SDL_RenderTextureRotated(SDL_Renderer *renderer,
*/
extern SDL_DECLSPEC int SDLCALL SDL_RenderTextureTiled(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float scale, const SDL_FRect *dstrect);

/**
* Perform a scaled copy using the 9-grid algorithm to the current rendering target at subpixel precision.
*
* The pixels in the texture are split into a 3x3 grid, using the corner size for each corner, and the sides and center making up the remaining pixels. The corners are then scaled using `scale` and fit into the corners of the destination rectangle. The sides and center are then stretched into place to cover the remaining destination rectangle.
*
* \param renderer the renderer which should copy parts of a texture.
* \param texture the source texture.
* \param srcrect the SDL_Rect structure representing the rectangle to be
* used for the 9-grid, or NULL to use the entire texture.
* \param corner_size the size, in pixels, of the corner in `srcrect`.
* \param scale the scale used to transform the corner of `srcrect` into the corner of `dstrect`, or 0.0f for an unscaled copy.
* \param dstrect a pointer to the destination rectangle, or NULL for the
* entire rendering target.
* \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_RenderTexture
*/
extern SDL_DECLSPEC int SDLCALL SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float corner_size, float scale, const SDL_FRect *dstrect);

/**
* Render a list of triangles, optionally using a texture and indices into the
* vertex array Color and alpha modulation is done per vertex
Expand Down
28 changes: 28 additions & 0 deletions include/SDL3/SDL_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,34 @@ extern SDL_DECLSPEC int SDLCALL SDL_BlitSurfaceTiled(SDL_Surface *src, const SDL
*/
extern SDL_DECLSPEC int SDLCALL SDL_BlitSurfaceTiledWithScale(SDL_Surface *src, const SDL_Rect *srcrect, float scale, SDL_ScaleMode scaleMode, SDL_Surface *dst, const SDL_Rect *dstrect);

/**
* Perform a scaled blit using the 9-grid algorithm to a destination surface, which may be of a different
* format.
*
* The pixels in the source surface are split into a 3x3 grid, using the corner size for each corner, and the sides and center making up the remaining pixels. The corners are then scaled using `scale` and fit into the corners of the destination rectangle. The sides and center are then stretched into place to cover the remaining destination rectangle.
*
* \param src the SDL_Surface structure to be copied from.
* \param srcrect the SDL_Rect structure representing the rectangle to be
* used for the 9-grid, or NULL to use the entire surface.
* \param corner_size the size, in pixels, of the corner in `srcrect`.
* \param scale the scale used to transform the corner of `srcrect` into the corner of `dstrect`, or 0.0f for an unscaled blit.
* \param scaleMode scale algorithm to be used.
* \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, or NULL to fill the entire surface.
* \returns 0 on success or a negative error code on failure; call
* SDL_GetError() for more information.
*
* \threadsafety The same destination surface should not be used from two
* threads at once. It is safe to use the same source surface
* from multiple threads.
*
* \since This function is available since SDL 3.0.0.
*
* \sa SDL_BlitSurface
*/
extern SDL_DECLSPEC int SDLCALL SDL_BlitSurface9Grid(SDL_Surface *src, const SDL_Rect *srcrect, int corner_size, float scale, SDL_ScaleMode scaleMode, SDL_Surface *dst, const SDL_Rect *dstrect);

/**
* Map an RGB triple to an opaque pixel value for a surface.
*
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi.sym
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ SDL3_0.0.0 {
SDL_AudioDevicePaused;
SDL_BindAudioStream;
SDL_BindAudioStreams;
SDL_BlitSurface9Grid;
SDL_BlitSurface;
SDL_BlitSurfaceScaled;
SDL_BlitSurfaceTiled;
Expand Down Expand Up @@ -662,6 +663,7 @@ SDL3_0.0.0 {
SDL_RenderReadPixels;
SDL_RenderRect;
SDL_RenderRects;
SDL_RenderTexture9Grid;
SDL_RenderTexture;
SDL_RenderTextureRotated;
SDL_RenderTextureTiled;
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#define SDL_BindAudioStream SDL_BindAudioStream_REAL
#define SDL_BindAudioStreams SDL_BindAudioStreams_REAL
#define SDL_BlitSurface SDL_BlitSurface_REAL
#define SDL_BlitSurface9Grid SDL_BlitSurface9Grid_REAL
#define SDL_BlitSurfaceScaled SDL_BlitSurfaceScaled_REAL
#define SDL_BlitSurfaceTiled SDL_BlitSurfaceTiled_REAL
#define SDL_BlitSurfaceTiledWithScale SDL_BlitSurfaceTiledWithScale_REAL
Expand Down Expand Up @@ -688,6 +689,7 @@
#define SDL_RenderRect SDL_RenderRect_REAL
#define SDL_RenderRects SDL_RenderRects_REAL
#define SDL_RenderTexture SDL_RenderTexture_REAL
#define SDL_RenderTexture9Grid SDL_RenderTexture9Grid_REAL
#define SDL_RenderTextureRotated SDL_RenderTextureRotated_REAL
#define SDL_RenderTextureTiled SDL_RenderTextureTiled_REAL
#define SDL_RenderViewportSet SDL_RenderViewportSet_REAL
Expand Down
2 changes: 2 additions & 0 deletions src/dynapi/SDL_dynapi_procs.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_AudioDevicePaused,(SDL_AudioDeviceID a),(a),return)
SDL_DYNAPI_PROC(int,SDL_BindAudioStream,(SDL_AudioDeviceID a, SDL_AudioStream *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_BindAudioStreams,(SDL_AudioDeviceID a, SDL_AudioStream **b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_BlitSurface,(SDL_Surface *a, const SDL_Rect *b, SDL_Surface *c, const SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_BlitSurface9Grid,(SDL_Surface *a, const SDL_Rect *b, int c, float d, SDL_ScaleMode e, SDL_Surface *f, const SDL_Rect *g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(int,SDL_BlitSurfaceScaled,(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(int,SDL_BlitSurfaceTiled,(SDL_Surface *a, const SDL_Rect *b, SDL_Surface *c, const SDL_Rect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_BlitSurfaceTiledWithScale,(SDL_Surface *a, const SDL_Rect *b, float c, SDL_ScaleMode d, SDL_Surface *e, const SDL_Rect *f),(a,b,c,d,e,f),return)
Expand Down Expand Up @@ -699,6 +700,7 @@ SDL_DYNAPI_PROC(SDL_Surface*,SDL_RenderReadPixels,(SDL_Renderer *a, const SDL_Re
SDL_DYNAPI_PROC(int,SDL_RenderRect,(SDL_Renderer *a, const SDL_FRect *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_RenderRects,(SDL_Renderer *a, const SDL_FRect *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_RenderTexture,(SDL_Renderer *a, SDL_Texture *b, const SDL_FRect *c, const SDL_FRect *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_RenderTexture9Grid,(SDL_Renderer *a, SDL_Texture *b, const SDL_FRect *c, float d, float e, const SDL_FRect *f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(int,SDL_RenderTextureRotated,(SDL_Renderer *a, SDL_Texture *b, const SDL_FRect *c, const SDL_FRect *d, const double e, const SDL_FPoint *f, const SDL_FlipMode g),(a,b,c,d,e,f,g),return)
SDL_DYNAPI_PROC(int,SDL_RenderTextureTiled,(SDL_Renderer *a, SDL_Texture *b, const SDL_FRect *c, float d, const SDL_FRect *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_RenderViewportSet,(SDL_Renderer *a),(a),return)
Expand Down
117 changes: 117 additions & 0 deletions src/render/SDL_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -4160,6 +4160,123 @@ int SDL_RenderTextureTiled(SDL_Renderer *renderer, SDL_Texture *texture, const S
}
}

int SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float corner_size, float scale, const SDL_FRect *dstrect)
{
SDL_FRect full_src, full_dst;
SDL_FRect curr_src, curr_dst;
float dst_corner_size;

CHECK_RENDERER_MAGIC(renderer, -1);
CHECK_TEXTURE_MAGIC(texture, -1);

if (renderer != texture->renderer) {
return SDL_SetError("Texture was not created with this renderer");
}

if (!srcrect) {
full_src.x = 0;
full_src.y = 0;
full_src.w = (float)texture->w;
full_src.h = (float)texture->h;
srcrect = &full_src;
}

if (!dstrect) {
GetRenderViewportSize(renderer, &full_dst);
dstrect = &full_dst;
}

if (scale <= 0.0f || scale == 1.0f) {
dst_corner_size = corner_size;
} else {
dst_corner_size = (corner_size * scale);
}

// Upper-left corner
curr_src.x = srcrect->x;
curr_src.y = srcrect->y;
curr_src.w = corner_size;
curr_src.h = corner_size;
curr_dst.x = dstrect->x;
curr_dst.y = dstrect->y;
curr_dst.w = dst_corner_size;
curr_dst.h = dst_corner_size;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

// Upper-right corner
curr_src.x = srcrect->x + srcrect->w - corner_size;
curr_dst.x = dstrect->x + dstrect->w - dst_corner_size;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

// Lower-right corner
curr_src.y = srcrect->y + srcrect->h - corner_size;
curr_dst.y = dstrect->y + dstrect->h - dst_corner_size;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

// Lower-left corner
curr_src.x = srcrect->x;
curr_dst.x = dstrect->x;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

// Left
curr_src.y = srcrect->y + corner_size;
curr_src.h = srcrect->h - 2 * corner_size;
curr_dst.y = dstrect->y + dst_corner_size;
curr_dst.h = dstrect->h - 2 * dst_corner_size;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

// Right
curr_src.x = srcrect->x + srcrect->w - corner_size;
curr_dst.x = dstrect->x + dstrect->w - dst_corner_size;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

// Top
curr_src.x = srcrect->x + corner_size;
curr_src.y = srcrect->y;
curr_src.w = srcrect->w - 2 * corner_size;
curr_src.h = corner_size;
curr_dst.x = dstrect->x + dst_corner_size;
curr_dst.y = dstrect->y;
curr_dst.w = dstrect->w - 2 * dst_corner_size;
curr_dst.h = dst_corner_size;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

// Bottom
curr_src.y = srcrect->y + srcrect->h - corner_size;
curr_dst.y = dstrect->y + dstrect->h - dst_corner_size;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

// Center
curr_src.x = srcrect->x + corner_size;
curr_src.y = srcrect->y + corner_size;
curr_src.w = srcrect->w - 2 * corner_size;
curr_src.h = srcrect->h - 2 * corner_size;
curr_dst.x = dstrect->x + dst_corner_size;
curr_dst.y = dstrect->y + dst_corner_size;
curr_dst.w = dstrect->w - 2 * dst_corner_size;
curr_dst.h = dstrect->h - 2 * dst_corner_size;
if (SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst) < 0) {
return -1;
}

return 0;
}
int SDL_RenderGeometry(SDL_Renderer *renderer,
SDL_Texture *texture,
const SDL_Vertex *vertices, int num_vertices,
Expand Down
121 changes: 121 additions & 0 deletions src/video/SDL_surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,127 @@ int SDL_BlitSurfaceTiledWithScale(SDL_Surface *src, const SDL_Rect *srcrect, flo
return 0;
}

int SDL_BlitSurface9Grid(SDL_Surface *src, const SDL_Rect *srcrect, int corner_size, float scale, SDL_ScaleMode scaleMode, SDL_Surface *dst, const SDL_Rect *dstrect)
{
SDL_Rect full_src, full_dst;
SDL_Rect curr_src, curr_dst;
int dst_corner_size;

/* Make sure the surfaces aren't locked */
if (!SDL_SurfaceValid(src)) {
return SDL_InvalidParamError("src");
} else if (!SDL_SurfaceValid(dst)) {
return SDL_InvalidParamError("dst");
}

if (!srcrect) {
full_src.x = 0;
full_src.y = 0;
full_src.w = src->w;
full_src.h = src->h;
srcrect = &full_src;
}

if (!dstrect) {
full_dst.x = 0;
full_dst.y = 0;
full_dst.w = dst->w;
full_dst.h = dst->h;
dstrect = &full_dst;
}

if (scale <= 0.0f || scale == 1.0f) {
dst_corner_size = corner_size;
} else {
dst_corner_size = (int)SDL_roundf(corner_size * scale);
}

// Upper-left corner
curr_src.x = srcrect->x;
curr_src.y = srcrect->y;
curr_src.w = corner_size;
curr_src.h = corner_size;
curr_dst.x = dstrect->x;
curr_dst.y = dstrect->y;
curr_dst.w = dst_corner_size;
curr_dst.h = dst_corner_size;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

// Upper-right corner
curr_src.x = srcrect->x + srcrect->w - corner_size;
curr_dst.x = dstrect->x + dstrect->w - dst_corner_size;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

// Lower-right corner
curr_src.y = srcrect->y + srcrect->h - corner_size;
curr_dst.y = dstrect->y + dstrect->h - dst_corner_size;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

// Lower-left corner
curr_src.x = srcrect->x;
curr_dst.x = dstrect->x;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

// Left
curr_src.y = srcrect->y + corner_size;
curr_src.h = srcrect->h - 2 * corner_size;
curr_dst.y = dstrect->y + dst_corner_size;
curr_dst.h = dstrect->h - 2 * dst_corner_size;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

// Right
curr_src.x = srcrect->x + srcrect->w - corner_size;
curr_dst.x = dstrect->x + dstrect->w - dst_corner_size;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

// Top
curr_src.x = srcrect->x + corner_size;
curr_src.y = srcrect->y;
curr_src.w = srcrect->w - 2 * corner_size;
curr_src.h = corner_size;
curr_dst.x = dstrect->x + dst_corner_size;
curr_dst.y = dstrect->y;
curr_dst.w = dstrect->w - 2 * dst_corner_size;
curr_dst.h = dst_corner_size;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

// Bottom
curr_src.y = srcrect->y + srcrect->h - corner_size;
curr_dst.y = dstrect->y + dstrect->h - dst_corner_size;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

// Center
curr_src.x = srcrect->x + corner_size;
curr_src.y = srcrect->y + corner_size;
curr_src.w = srcrect->w - 2 * corner_size;
curr_src.h = srcrect->h - 2 * corner_size;
curr_dst.x = dstrect->x + dst_corner_size;
curr_dst.y = dstrect->y + dst_corner_size;
curr_dst.w = dstrect->w - 2 * dst_corner_size;
curr_dst.h = dstrect->h - 2 * dst_corner_size;
if (SDL_BlitSurfaceScaled(src, &curr_src, dst, &curr_dst, scaleMode) < 0) {
return -1;
}

return 0;
}

/*
* Lock a surface to directly access the pixels
*/
Expand Down

0 comments on commit 8013ffe

Please sign in to comment.