Pixel Density and High-DPI Displays

Image Scaling and DPI

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

Abstract art representing computer programming

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

Answers to questions are automatically generated and may not have been reviewed.

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 71 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved