From 18b76fcc5dca9c7f5c4ce1ac5eaee041e6d68bd3 Mon Sep 17 00:00:00 2001
From: Sylvain <[EMAIL REDACTED]>
Date: Tue, 15 Feb 2022 11:33:56 +0100
Subject: [PATCH] Fixed bug #3070 - SDL_RenderCopyEx rotation and global
scaling around the wrong way (software renderer)
---
src/render/SDL_render.c | 14 +++-------
src/render/SDL_sysrender.h | 2 +-
src/render/software/SDL_render_sw.c | 42 ++++++++++++++++++++++++-----
3 files changed, 39 insertions(+), 19 deletions(-)
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index f9f01fb99b9..09e216dbefb 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -611,12 +611,12 @@ QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture * texture, const SDL_Rect * src
static int
QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture * texture,
const SDL_Rect * srcquad, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y)
{
SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_COPY_EX, texture);
int retval = -1;
if (cmd != NULL) {
- retval = renderer->QueueCopyEx(renderer, cmd, texture, srcquad, dstrect, angle, center, flip);
+ retval = renderer->QueueCopyEx(renderer, cmd, texture, srcquad, dstrect, angle, center, flip, scale_x, scale_y);
if (retval < 0) {
cmd->command = SDL_RENDERCMD_NO_OP;
}
@@ -3734,15 +3734,7 @@ SDL_RenderCopyExF(SDL_Renderer * renderer, SDL_Texture * texture,
renderer->scale.x, renderer->scale.y);
} else {
- real_dstrect.x *= renderer->scale.x;
- real_dstrect.y *= renderer->scale.y;
- real_dstrect.w *= renderer->scale.x;
- real_dstrect.h *= renderer->scale.y;
-
- real_center.x *= renderer->scale.x;
- real_center.y *= renderer->scale.y;
-
- retval = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip);
+ retval = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip, renderer->scale.x, renderer->scale.y);
}
return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer);
}
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index ff38ed0dd69..5d92f6a26c6 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -143,7 +143,7 @@ struct SDL_Renderer
const SDL_Rect * srcrect, const SDL_FRect * dstrect);
int (*QueueCopyEx) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
const SDL_Rect * srcquad, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip);
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y);
int (*QueueGeometry) (SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
int num_vertices, const void *indices, int num_indices, int size_indices,
diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c
index 961aea2f3d0..4fabcee48a8 100644
--- a/src/render/software/SDL_render_sw.c
+++ b/src/render/software/SDL_render_sw.c
@@ -273,12 +273,14 @@ typedef struct CopyExData
double angle;
SDL_FPoint center;
SDL_RendererFlip flip;
+ float scale_x;
+ float scale_y;
} CopyExData;
static int
SW_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_FRect * dstrect,
- const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
+ const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y)
{
CopyExData *verts = (CopyExData *) SDL_AllocateRenderVertices(renderer, sizeof (CopyExData), 0, &cmd->data.draw.first);
@@ -297,14 +299,35 @@ SW_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * te
verts->angle = angle;
SDL_memcpy(&verts->center, center, sizeof (SDL_FPoint));
verts->flip = flip;
+ verts->scale_x = scale_x;
+ verts->scale_y = scale_y;
return 0;
}
+static int
+Blit_to_Screen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *surface, SDL_Rect *dstrect,
+ float scale_x, float scale_y, SDL_ScaleMode scaleMode)
+{
+ int retval;
+ /* Renderer scaling, if needed */
+ if (scale_x != 1.0f || scale_y != 1.0f) {
+ SDL_Rect r;
+ r.x = (int)((float) dstrect->x * scale_x);
+ r.y = (int)((float) dstrect->y * scale_y);
+ r.w = (int)((float) dstrect->w * scale_x);
+ r.h = (int)((float) dstrect->h * scale_y);
+ retval = SDL_PrivateUpperBlitScaled(src, srcrect, surface, &r, scaleMode);
+ } else {
+ retval = SDL_BlitSurface(src, srcrect, surface, dstrect);
+ }
+ return retval;
+}
+
static int
SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * texture,
const SDL_Rect * srcrect, const SDL_Rect * final_rect,
- const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
+ const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip, float scale_x, float scale_y)
{
SDL_Surface *src = (SDL_Surface *) texture->driverdata;
SDL_Rect tmp_rect;
@@ -475,7 +498,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex
SDL_SetSurfaceAlphaMod(src_rotated, alphaMod);
SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod);
}
- retval = SDL_BlitSurface(src_rotated, NULL, surface, &tmp_rect);
+ /* Renderer scaling, if needed */
+ retval = Blit_to_Screen(src_rotated, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode);
} else {
/* The NONE blend mode requires three steps to get the pixels onto the destination surface.
* First, the area where the rotated pixels will be blitted to get set to zero.
@@ -484,7 +508,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex
*/
SDL_Rect mask_rect = tmp_rect;
SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE);
- retval = SDL_BlitSurface(mask_rotated, NULL, surface, &mask_rect);
+ /* Renderer scaling, if needed */
+ retval = Blit_to_Screen(mask_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode);
if (!retval) {
/* The next step copies the alpha value. This is done with the BLEND blend mode and
* by modulating the source colors with 0. Since the destination is all zeros, this
@@ -492,7 +517,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex
*/
SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0);
mask_rect = tmp_rect;
- retval = SDL_BlitSurface(src_rotated, NULL, surface, &mask_rect);
+ /* Renderer scaling, if needed */
+ retval = Blit_to_Screen(src_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode);
if (!retval) {
/* The last step gets the color values in place. The ADD blend mode simply adds them to
* the destination (where the color values are all zero). However, because the ADD blend
@@ -508,7 +534,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex
retval = -1;
} else {
SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD);
- retval = SDL_BlitSurface(src_rotated_rgb, NULL, surface, &tmp_rect);
+ /* Renderer scaling, if needed */
+ retval = Blit_to_Screen(src_rotated_rgb, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode);
SDL_FreeSurface(src_rotated_rgb);
}
}
@@ -879,7 +906,8 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
}
SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, ©data->srcrect,
- ©data->dstrect, copydata->angle, ©data->center, copydata->flip);
+ ©data->dstrect, copydata->angle, ©data->center, copydata->flip,
+ copydata->scale_x, copydata->scale_y);
break;
}