Handling high DPI (HiDPI) displays in SDL2 is crucial for ensuring your game looks crisp on modern screens. SDL2 provides built-in support for HiDPI, but you need to set it up correctly. Here's a comprehensive approach:
First, enable HiDPI support when creating your window:
#include <SDL.h>
#include <iostream>
int main() {
SDL_Init(SDL_INIT_VIDEO);
// Enable HiDPI support
SDL_SetHint(
SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
SDL_Window* window = SDL_CreateWindow(
"HiDPI Game", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 800, 600,
SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_RESIZABLE);
if (!window) {
std::cout << "Failed to create window: " <<
SDL_GetError() << "\n";
return 1;
}
SDL_Renderer* renderer = SDL_CreateRenderer(
window, -1,
SDL_RENDERER_ACCELERATED |
SDL_RENDERER_PRESENTVSYNC);
if (!renderer) {
std::cout << "Failed to create renderer: "
<< SDL_GetError() << "\n";
return 1;
}
// Rest of the code...
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
The window size reported by SDL might not match the actual pixel size on HiDPI displays. Use SDL_GetRendererOutputSize()
to get the true pixel size:
int windowWidth, windowHeight,
renderWidth, renderHeight;
SDL_GetWindowSize(
window, &windowWidth, &windowHeight);
SDL_GetRendererOutputSize(
renderer, &renderWidth, &renderHeight);
float scaleX = renderWidth
/ static_cast<float>(windowWidth);
float scaleY = renderHeight
/ static_cast<float>(windowHeight);
std::cout << "Window size: " << windowWidth
<< "x" << windowHeight << "\n";
std::cout << "Render size: " << renderWidth
<< "x" << renderHeight << "\n";
std::cout << "Scale factor: " << scaleX
<< "x" << scaleY << "\n";
Use the scale factor when rendering:
SDL_Rect GetScaledRect(int x, int y, int w,
int h, float scaleX,
float scaleY) {
return SDL_Rect{
static_cast<int>(x * scaleX),
static_cast<int>(y * scaleY),
static_cast<int>(w * scaleX),
static_cast<int>(h * scaleY)};
}
// In your render loop:
SDL_Rect rect = GetScaledRect(
100, 100, 200, 200, scaleX, scaleY);
SDL_RenderFillRect(renderer, &rect);
Mouse input coordinates are already adjusted by SDL2, but you might need to scale other input values:
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
float gameX = mouseX / scaleX;
float gameY = mouseY / scaleY;
For the best visual quality, provide high-resolution versions of your assets and scale them down as needed:
SDL_Surface* LoadScaledSurface(
const char* path, float scale) {
SDL_Surface* original = SDL_LoadBMP(path);
if (!original) return nullptr;
int newWidth = static_cast<int>(original->w *
scale);
int newHeight = static_cast<int>(original->h *
scale);
SDL_Surface* scaled =
SDL_CreateRGBSurface(0, newWidth, newHeight,
32, 0, 0, 0, 0);
SDL_BlitScaled(original, nullptr, scaled,
nullptr);
SDL_FreeSurface(original);
return scaled;
}
By following these steps, your SDL2 game will look great on both standard and HiDPI displays, providing a consistent experience across different screen resolutions.
Answers to questions are automatically generated and may not have been reviewed.
Learn techniques for scaling images and working with aspect ratios
Comprehensive course covering advanced concepts, and how to use them on large-scale projects.
View Course