mirror of
https://github.com/Relintai/sdl2_frt.git
synced 2024-12-20 22:16:49 +01:00
Fixed bug 2687 - SDL_BlitScaled does not handle clipping correctly
Patch from Benoit Pierre: video: fix clipping handling in SDL_UpperBlitScaled - honor destination clipping rectangle - update both destination and source rectangles when clipping source rectangle to source surface and destination rectangle to destination clip rectangle - don't change scaling factors when clipping N.B.: - when no scaling is involved (source and destination width/height are the same), SDL_UpperBlit is used (so SDL_BlitScaled behaves like SDL_BlitSurface) - the final destination rectangle after all clipping is performed is saved back to dstrect (like for SDL_UpperBlit)
This commit is contained in:
parent
4e7db78ed9
commit
8272ed1819
@ -26,7 +26,6 @@
|
|||||||
#include "SDL_RLEaccel_c.h"
|
#include "SDL_RLEaccel_c.h"
|
||||||
#include "SDL_pixels_c.h"
|
#include "SDL_pixels_c.h"
|
||||||
|
|
||||||
|
|
||||||
/* Public routines */
|
/* Public routines */
|
||||||
/*
|
/*
|
||||||
* Create an empty RGB surface of the appropriate depth
|
* Create an empty RGB surface of the appropriate depth
|
||||||
@ -623,7 +622,12 @@ int
|
|||||||
SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
|
SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
|
||||||
SDL_Surface * dst, SDL_Rect * dstrect)
|
SDL_Surface * dst, SDL_Rect * dstrect)
|
||||||
{
|
{
|
||||||
SDL_Rect final_src, final_dst, fulldst;
|
double src_x0, src_y0, src_x1, src_y1;
|
||||||
|
double dst_x0, dst_y0, dst_x1, dst_y1;
|
||||||
|
SDL_Rect final_src, final_dst;
|
||||||
|
double scaling_w, scaling_h;
|
||||||
|
int src_w, src_h;
|
||||||
|
int dst_w, dst_h;
|
||||||
|
|
||||||
/* Make sure the surfaces aren't locked */
|
/* Make sure the surfaces aren't locked */
|
||||||
if (!src || !dst) {
|
if (!src || !dst) {
|
||||||
@ -633,78 +637,135 @@ SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
|
|||||||
return SDL_SetError("Surfaces must not be locked during blit");
|
return SDL_SetError("Surfaces must not be locked during blit");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the destination rectangle is NULL, use the entire dest surface */
|
if (NULL == srcrect) {
|
||||||
if (dstrect == NULL) {
|
src_w = src->w;
|
||||||
fulldst.x = fulldst.y = 0;
|
src_h = src->h;
|
||||||
fulldst.w = dst->w;
|
|
||||||
fulldst.h = dst->h;
|
|
||||||
dstrect = &fulldst;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clip the source rectangle to the source surface */
|
|
||||||
if (srcrect) {
|
|
||||||
int maxw, maxh;
|
|
||||||
|
|
||||||
final_src.x = srcrect->x;
|
|
||||||
final_src.w = srcrect->w;
|
|
||||||
if (final_src.x < 0) {
|
|
||||||
final_src.w += final_src.x;
|
|
||||||
final_src.x = 0;
|
|
||||||
}
|
|
||||||
maxw = src->w - final_src.x;
|
|
||||||
if (maxw < final_src.w)
|
|
||||||
final_src.w = maxw;
|
|
||||||
|
|
||||||
final_src.y = srcrect->y;
|
|
||||||
final_src.h = srcrect->h;
|
|
||||||
if (final_src.y < 0) {
|
|
||||||
final_src.h += final_src.y;
|
|
||||||
final_src.y = 0;
|
|
||||||
}
|
|
||||||
maxh = src->h - final_src.y;
|
|
||||||
if (maxh < final_src.h)
|
|
||||||
final_src.h = maxh;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
final_src.x = final_src.y = 0;
|
src_w = srcrect->w;
|
||||||
final_src.w = src->w;
|
src_h = srcrect->h;
|
||||||
final_src.h = src->h;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clip the destination rectangle against the clip rectangle */
|
if (NULL == dstrect) {
|
||||||
if (dstrect) {
|
dst_w = dst->w;
|
||||||
int maxw, maxh;
|
dst_h = dst->h;
|
||||||
|
|
||||||
final_dst.x = dstrect->x;
|
|
||||||
final_dst.w = dstrect->w;
|
|
||||||
if (final_dst.x < 0) {
|
|
||||||
final_dst.w += final_dst.x;
|
|
||||||
final_dst.x = 0;
|
|
||||||
}
|
|
||||||
maxw = dst->w - final_dst.x;
|
|
||||||
if (maxw < final_dst.w)
|
|
||||||
final_dst.w = maxw;
|
|
||||||
|
|
||||||
final_dst.y = dstrect->y;
|
|
||||||
final_dst.h = dstrect->h;
|
|
||||||
if (final_dst.y < 0) {
|
|
||||||
final_dst.h += final_dst.y;
|
|
||||||
final_dst.y = 0;
|
|
||||||
}
|
|
||||||
maxh = dst->h - final_dst.y;
|
|
||||||
if (maxh < final_dst.h)
|
|
||||||
final_dst.h = maxh;
|
|
||||||
} else {
|
} else {
|
||||||
final_dst.x = final_dst.y = 0;
|
dst_w = dstrect->w;
|
||||||
final_dst.w = dst->w;
|
dst_h = dstrect->h;
|
||||||
final_dst.h = dst->h;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (final_dst.w > 0 && final_dst.h > 0) {
|
if (dst_w == src_w && dst_h == src_h) {
|
||||||
return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
|
/* No scaling, defer to regular blit */
|
||||||
|
return SDL_BlitSurface(src, srcrect, dst, dstrect);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
scaling_w = (double)dst_w / src_w;
|
||||||
|
scaling_h = (double)dst_h / src_h;
|
||||||
|
|
||||||
|
if (NULL == dstrect) {
|
||||||
|
dst_x0 = 0;
|
||||||
|
dst_y0 = 0;
|
||||||
|
dst_x1 = dst_w - 1;
|
||||||
|
dst_y1 = dst_h - 1;
|
||||||
|
} else {
|
||||||
|
dst_x0 = dstrect->x;
|
||||||
|
dst_y0 = dstrect->y;
|
||||||
|
dst_x1 = dst_x0 + dst_w - 1;
|
||||||
|
dst_y1 = dst_y0 + dst_h - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == srcrect) {
|
||||||
|
src_x0 = 0;
|
||||||
|
src_y0 = 0;
|
||||||
|
src_x1 = src_w - 1;
|
||||||
|
src_y1 = src_h - 1;
|
||||||
|
} else {
|
||||||
|
src_x0 = srcrect->x;
|
||||||
|
src_y0 = srcrect->y;
|
||||||
|
src_x1 = src_x0 + src_w - 1;
|
||||||
|
src_y1 = src_y0 + src_h - 1;
|
||||||
|
|
||||||
|
/* Clip source rectangle to the source surface */
|
||||||
|
|
||||||
|
if (src_x0 < 0) {
|
||||||
|
dst_x0 -= src_x0 * scaling_w;
|
||||||
|
src_x0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_x1 >= src->w) {
|
||||||
|
dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
|
||||||
|
src_x1 = src->w - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_y0 < 0) {
|
||||||
|
dst_y0 -= src_y0 * scaling_h;
|
||||||
|
src_y0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_y1 >= src->h) {
|
||||||
|
dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
|
||||||
|
src_y1 = src->h - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clip destination rectangle to the clip rectangle */
|
||||||
|
|
||||||
|
/* Translate to clip space for easier calculations */
|
||||||
|
dst_x0 -= dst->clip_rect.x;
|
||||||
|
dst_x1 -= dst->clip_rect.x;
|
||||||
|
dst_y0 -= dst->clip_rect.y;
|
||||||
|
dst_y1 -= dst->clip_rect.y;
|
||||||
|
|
||||||
|
if (dst_x0 < 0) {
|
||||||
|
src_x0 -= dst_x0 / scaling_w;
|
||||||
|
dst_x0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst_x1 >= dst->clip_rect.w) {
|
||||||
|
src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
|
||||||
|
dst_x1 = dst->clip_rect.w - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst_y0 < 0) {
|
||||||
|
src_y0 -= dst_y0 / scaling_h;
|
||||||
|
dst_y0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dst_y1 >= dst->clip_rect.h) {
|
||||||
|
src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
|
||||||
|
dst_y1 = dst->clip_rect.h - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Translate back to surface coordinates */
|
||||||
|
dst_x0 += dst->clip_rect.x;
|
||||||
|
dst_x1 += dst->clip_rect.x;
|
||||||
|
dst_y0 += dst->clip_rect.y;
|
||||||
|
dst_y1 += dst->clip_rect.y;
|
||||||
|
|
||||||
|
final_src.x = SDL_round(src_x0);
|
||||||
|
final_src.y = SDL_round(src_y0);
|
||||||
|
final_src.w = SDL_round(src_x1 - src_x0 + 1);
|
||||||
|
final_src.h = SDL_round(src_y1 - src_y0 + 1);
|
||||||
|
|
||||||
|
final_dst.x = SDL_round(dst_x0);
|
||||||
|
final_dst.y = SDL_round(dst_y0);
|
||||||
|
final_dst.w = SDL_round(dst_x1 - dst_x0 + 1);
|
||||||
|
final_dst.h = SDL_round(dst_y1 - dst_y0 + 1);
|
||||||
|
|
||||||
|
if (final_dst.w < 0)
|
||||||
|
final_dst.w = 0;
|
||||||
|
if (final_dst.h < 0)
|
||||||
|
final_dst.h = 0;
|
||||||
|
|
||||||
|
if (dstrect)
|
||||||
|
*dstrect = final_dst;
|
||||||
|
|
||||||
|
if (final_dst.w == 0 || final_dst.h == 0 ||
|
||||||
|
final_src.w <= 0 || final_src.h <= 0) {
|
||||||
|
/* No-op. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -721,43 +782,6 @@ SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
|
|||||||
SDL_COPY_COLORKEY
|
SDL_COPY_COLORKEY
|
||||||
);
|
);
|
||||||
|
|
||||||
/* Save off the original dst width, height */
|
|
||||||
int dstW = dstrect->w;
|
|
||||||
int dstH = dstrect->h;
|
|
||||||
SDL_Rect full_rect;
|
|
||||||
SDL_Rect final_dst = *dstrect;
|
|
||||||
SDL_Rect final_src = *srcrect;
|
|
||||||
|
|
||||||
/* Clip the dst surface to the dstrect */
|
|
||||||
full_rect.x = 0;
|
|
||||||
full_rect.y = 0;
|
|
||||||
full_rect.w = dst->w;
|
|
||||||
full_rect.h = dst->h;
|
|
||||||
if (!SDL_IntersectRect(&final_dst, &full_rect, &final_dst)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Did the dst width change? */
|
|
||||||
if ( dstW != final_dst.w ) {
|
|
||||||
/* scale the src width appropriately */
|
|
||||||
final_src.w = final_src.w * dst->clip_rect.w / dstW;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Did the dst height change? */
|
|
||||||
if ( dstH != final_dst.h ) {
|
|
||||||
/* scale the src width appropriately */
|
|
||||||
final_src.h = final_src.h * dst->clip_rect.h / dstH;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clip the src surface to the srcrect */
|
|
||||||
full_rect.x = 0;
|
|
||||||
full_rect.y = 0;
|
|
||||||
full_rect.w = src->w;
|
|
||||||
full_rect.h = src->h;
|
|
||||||
if (!SDL_IntersectRect(&final_src, &full_rect, &final_src)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
|
if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
|
||||||
src->map->info.flags |= SDL_COPY_NEAREST;
|
src->map->info.flags |= SDL_COPY_NEAREST;
|
||||||
SDL_InvalidateMap(src->map);
|
SDL_InvalidateMap(src->map);
|
||||||
@ -766,9 +790,9 @@ SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
|
|||||||
if ( !(src->map->info.flags & complex_copy_flags) &&
|
if ( !(src->map->info.flags & complex_copy_flags) &&
|
||||||
src->format->format == dst->format->format &&
|
src->format->format == dst->format->format &&
|
||||||
!SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
|
!SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
|
||||||
return SDL_SoftStretch( src, &final_src, dst, &final_dst );
|
return SDL_SoftStretch( src, srcrect, dst, dstrect );
|
||||||
} else {
|
} else {
|
||||||
return SDL_LowerBlit( src, &final_src, dst, &final_dst );
|
return SDL_LowerBlit( src, srcrect, dst, dstrect );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user