mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-06-05 15:29:17 +08:00
Prefer downscaling in SDL_GetSurfaceImage.
This implements the ideas described in #10536
This commit is contained in:
@@ -423,8 +423,9 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 * data,
|
|||||||
* situations. For example, if the original surface is 32x32, then on a 2x
|
* situations. For example, if the original surface is 32x32, then on a 2x
|
||||||
* macOS display or 200% display scale on Windows, a 64x64 version of the
|
* macOS display or 200% display scale on Windows, a 64x64 version of the
|
||||||
* image will be used, if available. If a matching version of the image isn't
|
* image will be used, if available. If a matching version of the image isn't
|
||||||
* available, the closest size image will be scaled to the appropriate size
|
* available, the closest larger size image will be downscaled to the
|
||||||
* and be used instead.
|
* appropriate size and be used instead, if available. Otherwise, the closest
|
||||||
|
* smaller image will be upscaled and be used instead.
|
||||||
*
|
*
|
||||||
* \param surface an SDL_Surface structure representing the cursor image.
|
* \param surface an SDL_Surface structure representing the cursor image.
|
||||||
* \param hot_x the x position of the cursor hot spot.
|
* \param hot_x the x position of the cursor hot spot.
|
||||||
|
|||||||
@@ -1341,8 +1341,9 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetWindowTitle(SDL_Window *window);
|
|||||||
* situations. For example, if the original surface is 32x32, then on a 2x
|
* situations. For example, if the original surface is 32x32, then on a 2x
|
||||||
* macOS display or 200% display scale on Windows, a 64x64 version of the
|
* macOS display or 200% display scale on Windows, a 64x64 version of the
|
||||||
* image will be used, if available. If a matching version of the image isn't
|
* image will be used, if available. If a matching version of the image isn't
|
||||||
* available, the closest size image will be scaled to the appropriate size
|
* available, the closest larger size image will be downscaled to the
|
||||||
* and be used instead.
|
* appropriate size and be used instead, if available. Otherwise, the closest
|
||||||
|
* smaller image will be upscaled and be used instead.
|
||||||
*
|
*
|
||||||
* \param window the window to change.
|
* \param window the window to change.
|
||||||
* \param icon an SDL_Surface structure containing the icon for the window.
|
* \param icon an SDL_Surface structure containing the icon for the window.
|
||||||
|
|||||||
+25
-3
@@ -514,18 +514,25 @@ SDL_Surface *SDL_GetSurfaceImage(SDL_Surface *surface, float display_scale)
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find closest image. Images that are larger than the
|
||||||
|
// desired size are preferred over images that are smaller.
|
||||||
SDL_Surface *closest = NULL;
|
SDL_Surface *closest = NULL;
|
||||||
int desired_w = (int)SDL_round(surface->w * display_scale);
|
int desired_w = (int)SDL_round(surface->w * display_scale);
|
||||||
int desired_h = (int)SDL_round(surface->h * display_scale);
|
int desired_h = (int)SDL_round(surface->h * display_scale);
|
||||||
|
int desired_size = desired_w * desired_h;
|
||||||
int closest_distance = -1;
|
int closest_distance = -1;
|
||||||
|
int closest_size = -1;
|
||||||
for (int i = 0; images[i]; ++i) {
|
for (int i = 0; images[i]; ++i) {
|
||||||
SDL_Surface *candidate = images[i];
|
SDL_Surface *candidate = images[i];
|
||||||
|
int size = candidate->w * candidate->h;
|
||||||
int delta_w = (candidate->w - desired_w);
|
int delta_w = (candidate->w - desired_w);
|
||||||
int delta_h = (candidate->h - desired_h);
|
int delta_h = (candidate->h - desired_h);
|
||||||
int distance = (delta_w * delta_w) + (delta_h * delta_h);
|
int distance = (delta_w * delta_w) + (delta_h * delta_h);
|
||||||
if (closest_distance < 0 || distance < closest_distance) {
|
if (closest_distance < 0 || distance < closest_distance ||
|
||||||
|
(size > desired_size && closest_size < desired_size)) {
|
||||||
closest = candidate;
|
closest = candidate;
|
||||||
closest_distance = distance;
|
closest_distance = distance;
|
||||||
|
closest_size = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_free(images);
|
SDL_free(images);
|
||||||
@@ -536,8 +543,23 @@ SDL_Surface *SDL_GetSurfaceImage(SDL_Surface *surface, float display_scale)
|
|||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to scale an image to the correct size
|
// We need to scale the image to the correct size. To maintain good image quality, downscaling
|
||||||
return SDL_ScaleSurface(closest, desired_w, desired_h, SDL_SCALEMODE_LINEAR);
|
// is done in steps, never reducing the width and height by more than half each time.
|
||||||
|
SDL_Surface *scaled = closest;
|
||||||
|
do {
|
||||||
|
int next_scaled_w = SDL_max(desired_w, (scaled->w + 1) / 2);
|
||||||
|
int next_scaled_h = SDL_max(desired_h, (scaled->h + 1) / 2);
|
||||||
|
SDL_Surface *next_scaled = SDL_ScaleSurface(scaled, next_scaled_w, next_scaled_h, SDL_SCALEMODE_LINEAR);
|
||||||
|
if (scaled != closest) {
|
||||||
|
SDL_DestroySurface(scaled);
|
||||||
|
}
|
||||||
|
scaled = next_scaled;
|
||||||
|
if (!scaled) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} while (scaled->w != desired_w || scaled->h != desired_h);
|
||||||
|
|
||||||
|
return scaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDL_RemoveSurfaceAlternateImages(SDL_Surface *surface)
|
void SDL_RemoveSurfaceAlternateImages(SDL_Surface *surface)
|
||||||
|
|||||||
Reference in New Issue
Block a user