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)main
parent
4e7db78ed9
commit
8272ed1819
|
@ -26,7 +26,6 @@
|
|||
#include "SDL_RLEaccel_c.h"
|
||||
#include "SDL_pixels_c.h"
|
||||
|
||||
|
||||
/* Public routines */
|
||||
/*
|
||||
* Create an empty RGB surface of the appropriate depth
|
||||
|
@ -623,7 +622,12 @@ int
|
|||
SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
|
||||
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 */
|
||||
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");
|
||||
}
|
||||
|
||||
/* If the destination rectangle is NULL, use the entire dest surface */
|
||||
if (dstrect == NULL) {
|
||||
fulldst.x = fulldst.y = 0;
|
||||
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;
|
||||
|
||||
if (NULL == srcrect) {
|
||||
src_w = src->w;
|
||||
src_h = src->h;
|
||||
} else {
|
||||
final_src.x = final_src.y = 0;
|
||||
final_src.w = src->w;
|
||||
final_src.h = src->h;
|
||||
src_w = srcrect->w;
|
||||
src_h = srcrect->h;
|
||||
}
|
||||
|
||||
/* clip the destination rectangle against the clip rectangle */
|
||||
if (dstrect) {
|
||||
int maxw, maxh;
|
||||
|
||||
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;
|
||||
if (NULL == dstrect) {
|
||||
dst_w = dst->w;
|
||||
dst_h = dst->h;
|
||||
} else {
|
||||
final_dst.x = final_dst.y = 0;
|
||||
final_dst.w = dst->w;
|
||||
final_dst.h = dst->h;
|
||||
dst_w = dstrect->w;
|
||||
dst_h = dstrect->h;
|
||||
}
|
||||
|
||||
if (final_dst.w > 0 && final_dst.h > 0) {
|
||||
return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
|
||||
if (dst_w == src_w && dst_h == src_h) {
|
||||
/* 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
|
||||
);
|
||||
|
||||
/* 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)) {
|
||||
src->map->info.flags |= SDL_COPY_NEAREST;
|
||||
SDL_InvalidateMap(src->map);
|
||||
|
@ -766,9 +790,9 @@ SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
|
|||
if ( !(src->map->info.flags & complex_copy_flags) &&
|
||||
src->format->format == dst->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 {
|
||||
return SDL_LowerBlit( src, &final_src, dst, &final_dst );
|
||||
return SDL_LowerBlit( src, srcrect, dst, dstrect );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue