Preventing Cursor Blur When Scaling

Why does my custom cursor look blurry/pixelated when I scale my window? How can I make it stay sharp?

When working with custom cursors in SDL2, maintaining cursor sharpness during window scaling involves several considerations and potential solutions.

Understanding the Problem

Custom cursors can become blurry for two main reasons:

  • Window scaling causing pixel interpolation
  • Using cursor images at the wrong resolution for your display

Solution 1: Multi-Resolution Cursors

Create a system that loads different cursor sizes based on the window scale:

#include <SDL.h>
#include <SDL_image.h>
#include <unordered_map>
#include <string>

class ScalableCursor {
public:
  struct CursorSize {
    int width;
    int height;
    SDL_Cursor* cursor;
  };

  ScalableCursor() {
    // Load cursor variants
    LoadCursorVariant("cursor_16.png", 16, 16);
    LoadCursorVariant("cursor_32.png", 32, 32);
    LoadCursorVariant("cursor_64.png", 64, 64);
  }

  void UpdateForScale(float windowScale) {
    // Choose best cursor size for current scale
    int targetSize = static_cast<int>(16.0f * windowScale);

    SDL_Cursor* bestCursor{nullptr};
    int smallestDiff{INT_MAX};

    for (const auto& [size, cursorInfo] : Cursors) {
      int diff{std::abs(size - targetSize)};
      if (diff < smallestDiff) {
        smallestDiff = diff;
        bestCursor = cursorInfo.cursor;
      }
    }

    if (bestCursor) {
      SDL_SetCursor(bestCursor);
    }
  }

private:
  void LoadCursorVariant(
    const std::string& path,
    int width,
    int height
  ) {
    SDL_Surface* surface{IMG_Load(path.c_str())};
    if (!surface) {
      return;
    }

    SDL_Cursor* cursor{SDL_CreateColorCursor(
      surface, width/2, height/2)};
    SDL_FreeSurface(surface);

    if (cursor) {
      Cursors[width] = {width, height, cursor};
    }
  }

  std::unordered_map<int, CursorSize> Cursors;
};

Solution 2: Custom Rendering with Pixel-Perfect Scaling

If you're using custom cursor rendering, maintain pixel-perfect scaling:

class PixelPerfectCursor {
public:
  void Render(
    SDL_Renderer* renderer,
    int mouseX,
    int mouseY,
    float scale
  ) {
    // Calculate pixel-aligned position
    int alignedX{static_cast<int>(
      std::round(mouseX / scale) * scale)};
    int alignedY{static_cast<int>(
      std::round(mouseY / scale) * scale)};

    // Set nearest-neighbor scaling
    SDL_SetHint(
      SDL_HINT_RENDER_SCALE_QUALITY, "0");

    SDL_Rect destRect{
      alignedX,
      alignedY,
      static_cast<int>(CursorWidth * scale),
      static_cast<int>(CursorHeight * scale)
    };

    SDL_RenderCopy(
      renderer,
      CursorTexture,
      nullptr,
      &destRect
    );
  }

private:
  SDL_Texture* CursorTexture;
  int CursorWidth{16};
  int CursorHeight{16};
};

Both solutions help maintain cursor sharpness during scaling. The first approach is better for traditional cursor implementation, while the second works well with custom rendering.

Remember to create your cursor images with clean, pixel-art style edges for best results when scaling.

Customising Mouse Cursors

Learn how to control cursor visibility, switch between default system cursors, and create custom cursors

Questions & Answers

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

Changing Cursor Appearance on Hover
Can I make the cursor change appearance when it hovers over different game objects? Like showing a sword over enemies?
Creating Cursor Trail Effects
How can I implement a cursor trail effect, where the cursor leaves a temporary trail as it moves?
Animating Custom Cursors
Can I animate my custom cursor by loading multiple images? How would I implement a cursor that changes appearance?
Adding Physics to Cursor Movement
Is there a way to limit how fast the cursor can move across the screen? Like adding weight/momentum to it?
Or Ask your Own Question
Purchase the course to ask your own questions