Image Scaling and DPI

If I'm loading images for my game, do I need different versions for different DPI settings?

The decision to provide multiple image versions depends on your specific needs. Let's explore the options and their implications:

Single Image Approach

The simplest approach is to provide a single high-resolution image and scale it down when needed:

#include <SDL.h>
#include <SDL_image.h>
#include <iostream>

float GetDPIScale(SDL_Window* Window) {/*...*/} class Sprite { SDL_Surface* Image; int BaseWidth; int BaseHeight; public: Sprite(const char* Path) { Image = IMG_Load(Path); BaseWidth = Image->w; BaseHeight = Image->h; } void Draw(SDL_Surface* Target, int x, int y, float Scale ) { SDL_Rect Dest{ x, y, int(BaseWidth * Scale), int(BaseHeight * Scale) }; SDL_BlitScaled(Image, nullptr, Target, &Dest); } ~Sprite() { SDL_FreeSurface(Image); } };

This approach is simple but has drawbacks:

  • Scaling down loses detail in a controlled way
  • Scaling up can look blurry
  • Memory usage is always at maximum resolution

Multiple Resolution Support

For better quality, you can provide multiple resolutions:

class MultiResSprite {
  std::vector<SDL_Surface*> Images;
  std::vector<float> Scales{
    1.0f, 1.5f, 2.0f, 4.0f};
  int BaseWidth;
  int BaseHeight;

public:
  MultiResSprite(
    const std::vector<const char*>& Paths) {
    for (auto Path : Paths) {
      Images.push_back(IMG_Load(Path));
    }
    BaseWidth = Images[0]->w;
    BaseHeight = Images[0]->h;
  }

  void Draw(
    SDL_Surface* Target,
    int x, int y, float Scale
  ) {
    // Find best matching image
    size_t Best{0};
    float BestDiff{std::abs(Scales[0] - Scale)};

    for (size_t i = 1; i < Scales.size(); ++i) {
      float Diff{std::abs(Scales[i] - Scale)};
      if (Diff < BestDiff) {
        Best = i;
        BestDiff = Diff;
      }
    }

    SDL_Rect Dest{
      x, y,
      int(BaseWidth * Scale),
      int(BaseHeight * Scale)
    };
    SDL_BlitScaled(
      Images[Best], nullptr, Target, &Dest);
  }

  ~MultiResSprite() {
    for (auto Image : Images) {
      SDL_FreeSurface(Image);
    }
  }
};

Recommendations

The best approach depends on your game:

  • For pixel art games, use a single resolution and integer scaling
  • For modern games, provide 2-3 resolutions (1x, 2x, 4x)
  • Consider memory constraints on your target platforms
  • Test with different DPI scales to ensure quality

Pixel Density and High-DPI Displays

Learn how to create SDL applications that look great on modern displays across different platforms

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Scaling Text in SDL
How can I make text scale properly with different DPI settings?
Why Handle DPI Scaling
Why do we need to handle DPI scaling at all? Can't we just let the operating system handle it?
DPI Scale Calculation
In GetDPIScale(), why do we only use the width to calculate the scale? What about height?
DPI with SDL_Renderer
The example uses SDL_Surface. Does DPI scaling work differently with SDL_Renderer or SDL_Texture?
UI Elements and DPI
How do I handle DPI scaling for UI elements like buttons that need to stay a specific physical size?
Or Ask your Own Question
Purchase the course to ask your own questions