|
@@ -1089,15 +1089,42 @@ bool SDL_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst
|
|
return SDL_BlitSurfaceUnchecked(src, &r_src, dst, &r_dst);
|
|
return SDL_BlitSurfaceUnchecked(src, &r_src, dst, &r_dst);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool SDL_BlitSurfaceClippedScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode)
|
|
|
|
+{
|
|
|
|
+ // We need to scale first, then blit into dst because we're clipping in the destination surface pixel coordinates
|
|
|
|
+ if (SDL_MUSTLOCK(src)) {
|
|
|
|
+ if (!SDL_LockSurface(src)) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bool result;
|
|
|
|
+ int saved_w = src->w;
|
|
|
|
+ int saved_h = src->h;
|
|
|
|
+ void *saved_pixels = src->pixels;
|
|
|
|
+ src->w = srcrect->w;
|
|
|
|
+ src->h = srcrect->h;
|
|
|
|
+ src->pixels = (Uint8 *)src->pixels + srcrect->y * src->pitch + srcrect->x * SDL_BYTESPERPIXEL(src->format);
|
|
|
|
+ SDL_Surface *scaled = SDL_ScaleSurface(src, dstrect->w, dstrect->h, scaleMode);
|
|
|
|
+ if (scaled) {
|
|
|
|
+ result = SDL_BlitSurface(scaled, NULL, dst, dstrect);
|
|
|
|
+ SDL_DestroySurface(scaled);
|
|
|
|
+ } else {
|
|
|
|
+ result = false;
|
|
|
|
+ }
|
|
|
|
+ src->w = saved_w;
|
|
|
|
+ src->h = saved_h;
|
|
|
|
+ src->pixels = saved_pixels;
|
|
|
|
+
|
|
|
|
+ if (SDL_MUSTLOCK(src)) {
|
|
|
|
+ SDL_UnlockSurface(src);
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
bool SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode)
|
|
bool SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode)
|
|
{
|
|
{
|
|
- SDL_Rect *clip_rect;
|
|
|
|
- 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;
|
|
|
|
|
|
+ SDL_Rect r_src, r_dst;
|
|
|
|
|
|
// Make sure the surfaces aren't locked
|
|
// Make sure the surfaces aren't locked
|
|
if (!SDL_SurfaceValid(src) || !src->pixels) {
|
|
if (!SDL_SurfaceValid(src) || !src->pixels) {
|
|
@@ -1120,148 +1147,70 @@ bool SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surfac
|
|
return SDL_InvalidParamError("scaleMode");
|
|
return SDL_InvalidParamError("scaleMode");
|
|
}
|
|
}
|
|
|
|
|
|
- if (!srcrect) {
|
|
|
|
- src_w = src->w;
|
|
|
|
- src_h = src->h;
|
|
|
|
- } else {
|
|
|
|
- src_w = srcrect->w;
|
|
|
|
- src_h = srcrect->h;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!dstrect) {
|
|
|
|
- dst_w = dst->w;
|
|
|
|
- dst_h = dst->h;
|
|
|
|
- } else {
|
|
|
|
- dst_w = dstrect->w;
|
|
|
|
- dst_h = dstrect->h;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (dst_w == src_w && dst_h == src_h) {
|
|
|
|
|
|
+ int src_w = srcrect ? srcrect->w : src->w;
|
|
|
|
+ int src_h = srcrect ? srcrect->h : src->h;
|
|
|
|
+ int dst_w = dstrect ? dstrect->w : dst->w;
|
|
|
|
+ int dst_h = dstrect ? dstrect->h : dst->h;
|
|
|
|
+ if (src_w == dst_w && src_h == dst_h) {
|
|
// No scaling, defer to regular blit
|
|
// No scaling, defer to regular blit
|
|
return SDL_BlitSurface(src, srcrect, dst, dstrect);
|
|
return SDL_BlitSurface(src, srcrect, dst, dstrect);
|
|
}
|
|
}
|
|
|
|
|
|
- if (src_w == 0) {
|
|
|
|
- src_w = 1;
|
|
|
|
- }
|
|
|
|
- if (src_h == 0) {
|
|
|
|
- src_h = 1;
|
|
|
|
|
|
+ if (src->w == 0 || src->h == 0) {
|
|
|
|
+ // Nothing to do
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
|
|
|
|
- scaling_w = (double)dst_w / src_w;
|
|
|
|
- scaling_h = (double)dst_h / src_h;
|
|
|
|
|
|
+ // Full src surface
|
|
|
|
+ r_src.x = 0;
|
|
|
|
+ r_src.y = 0;
|
|
|
|
+ r_src.w = src->w;
|
|
|
|
+ r_src.h = src->h;
|
|
|
|
|
|
- if (!dstrect) {
|
|
|
|
- dst_x0 = 0;
|
|
|
|
- dst_y0 = 0;
|
|
|
|
- dst_x1 = dst_w;
|
|
|
|
- dst_y1 = dst_h;
|
|
|
|
|
|
+ if (dstrect) {
|
|
|
|
+ r_dst.x = dstrect->x;
|
|
|
|
+ r_dst.y = dstrect->y;
|
|
|
|
+ r_dst.w = dstrect->w;
|
|
|
|
+ r_dst.h = dstrect->h;
|
|
} else {
|
|
} else {
|
|
- dst_x0 = dstrect->x;
|
|
|
|
- dst_y0 = dstrect->y;
|
|
|
|
- dst_x1 = dst_x0 + dst_w;
|
|
|
|
- dst_y1 = dst_y0 + dst_h;
|
|
|
|
|
|
+ r_dst.x = 0;
|
|
|
|
+ r_dst.y = 0;
|
|
|
|
+ r_dst.w = dst->w;
|
|
|
|
+ r_dst.h = dst->h;
|
|
}
|
|
}
|
|
|
|
|
|
- if (!srcrect) {
|
|
|
|
- src_x0 = 0;
|
|
|
|
- src_y0 = 0;
|
|
|
|
- src_x1 = src_w;
|
|
|
|
- src_y1 = src_h;
|
|
|
|
- } else {
|
|
|
|
- src_x0 = srcrect->x;
|
|
|
|
- src_y0 = srcrect->y;
|
|
|
|
- src_x1 = src_x0 + src_w;
|
|
|
|
- src_y1 = src_y0 + src_h;
|
|
|
|
-
|
|
|
|
- // 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) * scaling_w;
|
|
|
|
- src_x1 = src->w;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (src_y0 < 0) {
|
|
|
|
- dst_y0 -= src_y0 * scaling_h;
|
|
|
|
- src_y0 = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (src_y1 > src->h) {
|
|
|
|
- dst_y1 -= (src_y1 - src->h) * scaling_h;
|
|
|
|
- src_y1 = src->h;
|
|
|
|
|
|
+ // clip the source rectangle to the source surface
|
|
|
|
+ if (srcrect) {
|
|
|
|
+ SDL_Rect desired, tmp;
|
|
|
|
+ desired.x = srcrect->x;
|
|
|
|
+ desired.y = srcrect->y;
|
|
|
|
+ desired.w = SDL_max(srcrect->w, 1);
|
|
|
|
+ desired.h = SDL_max(srcrect->h, 1);
|
|
|
|
+ if (SDL_GetRectIntersection(&desired, &r_src, &tmp) == false) {
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
- }
|
|
|
|
-
|
|
|
|
- // Clip destination rectangle to the clip rectangle
|
|
|
|
- clip_rect = &dst->clip_rect;
|
|
|
|
|
|
|
|
- // Translate to clip space for easier calculations
|
|
|
|
- dst_x0 -= clip_rect->x;
|
|
|
|
- dst_x1 -= clip_rect->x;
|
|
|
|
- dst_y0 -= clip_rect->y;
|
|
|
|
- dst_y1 -= clip_rect->y;
|
|
|
|
-
|
|
|
|
- if (dst_x0 < 0) {
|
|
|
|
- src_x0 -= dst_x0 / scaling_w;
|
|
|
|
- dst_x0 = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (dst_x1 > clip_rect->w) {
|
|
|
|
- src_x1 -= (dst_x1 - clip_rect->w) / scaling_w;
|
|
|
|
- dst_x1 = clip_rect->w;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (dst_y0 < 0) {
|
|
|
|
- src_y0 -= dst_y0 / scaling_h;
|
|
|
|
- dst_y0 = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ // Shift dstrect, if srcrect origin has changed
|
|
|
|
+ r_dst.x += (tmp.x - desired.x) * r_dst.w / desired.w;
|
|
|
|
+ r_dst.y += (tmp.y - desired.y) * r_dst.h / desired.h;
|
|
|
|
+ r_dst.w += (tmp.w - desired.w) * r_dst.w / desired.w;
|
|
|
|
+ r_dst.h += (tmp.h - desired.h) * r_dst.h / desired.h;
|
|
|
|
|
|
- if (dst_y1 > clip_rect->h) {
|
|
|
|
- src_y1 -= (dst_y1 - clip_rect->h) / scaling_h;
|
|
|
|
- dst_y1 = clip_rect->h;
|
|
|
|
|
|
+ // Update srcrect
|
|
|
|
+ r_src = tmp;
|
|
}
|
|
}
|
|
|
|
|
|
- // Translate back to surface coordinates
|
|
|
|
- dst_x0 += clip_rect->x;
|
|
|
|
- dst_x1 += clip_rect->x;
|
|
|
|
- dst_y0 += clip_rect->y;
|
|
|
|
- dst_y1 += clip_rect->y;
|
|
|
|
-
|
|
|
|
- final_src.x = (int)SDL_round(src_x0);
|
|
|
|
- final_src.y = (int)SDL_round(src_y0);
|
|
|
|
- final_src.w = (int)SDL_round(src_x1 - src_x0);
|
|
|
|
- final_src.h = (int)SDL_round(src_y1 - src_y0);
|
|
|
|
-
|
|
|
|
- final_dst.x = (int)SDL_round(dst_x0);
|
|
|
|
- final_dst.y = (int)SDL_round(dst_y0);
|
|
|
|
- final_dst.w = (int)SDL_round(dst_x1 - dst_x0);
|
|
|
|
- final_dst.h = (int)SDL_round(dst_y1 - dst_y0);
|
|
|
|
-
|
|
|
|
- // Clip again
|
|
|
|
- {
|
|
|
|
- SDL_Rect tmp;
|
|
|
|
- tmp.x = 0;
|
|
|
|
- tmp.y = 0;
|
|
|
|
- tmp.w = src->w;
|
|
|
|
- tmp.h = src->h;
|
|
|
|
- SDL_GetRectIntersection(&tmp, &final_src, &final_src);
|
|
|
|
|
|
+ SDL_Rect tmp;
|
|
|
|
+ if (SDL_GetRectIntersection(&r_dst, &dst->clip_rect, &tmp) == false) {
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
|
|
|
|
- // Clip again
|
|
|
|
- SDL_GetRectIntersection(clip_rect, &final_dst, &final_dst);
|
|
|
|
-
|
|
|
|
- if (final_dst.w <= 0 || final_dst.h <= 0 ||
|
|
|
|
- final_src.w < 0 || final_src.h < 0) {
|
|
|
|
- // No-op.
|
|
|
|
- return true;
|
|
|
|
|
|
+ if (tmp.x != r_dst.x || tmp.y != r_dst.y || tmp.w != r_dst.w || tmp.h != r_dst.h) {
|
|
|
|
+ // Need to do a clipped and scaled blit
|
|
|
|
+ return SDL_BlitSurfaceClippedScaled(src, &r_src, dst, &r_dst, scaleMode);
|
|
}
|
|
}
|
|
|
|
|
|
- return SDL_BlitSurfaceUncheckedScaled(src, &final_src, dst, &final_dst, scaleMode);
|
|
|
|
|
|
+ return SDL_BlitSurfaceUncheckedScaled(src, &r_src, dst, &r_dst, scaleMode);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|