Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hyperspace Delivery Boy [LGP] colorkeys are broken on >16bpp displays #317

Closed
sulix opened this issue Sep 4, 2023 · 2 comments
Closed

Comments

@sulix
Copy link
Contributor

sulix commented Sep 4, 2023

This looks like a game bug, not an sdl12-compat bug, but since it works with the bundled SDL 1.2, who knows.

Hyperspace Delivery Boy's colour keys do not work at all under sdl12-compat, or under a freshly built SDL 1.2, but do work with the game's bundled version of SDL 1.2.13.
Screenshot of the HDB title screen under sdl12-compat, with everything surrounded by magenta boxes

The game is setting the colour key to 0xF800F8, but the actual colour of the key in the images is 0xFFFF (they're 16-bit). This would work, but the game appears to be using SDL_ConvertSurface to convert the surfaces to the screen surface's colour depth, before calling SDL_MapRGB(screen_format, 0xF8, 0x00, 0xF8), so if the screen surface is >16-bit, the colour key no longer matches.

Hacking the game to use 16-bit (by modifying SDL_SetVideoMode()) fixes the issue, but it persists in using 32-bit by default, as it:

  • Calls SDL_GetVideoInfo() to get the default video format.
  • If the bpp of that format is >= 16, it calls SDL_SetVideoMode() with that bpp.
  • Otherwise, it calls SDL_SetVideoMode() with 16bpp.

The bundled version of SDL 1.2, however, does seem to return a 32-bit format from SDL_GetVideoInfo() as well, so maybe there's something else going on.

My feeling is that the closest thing to a "correct" hack here is to add a quirk which overrides the bit depth to 16, but I think what's going on with the bundled SDL 1.2 is possibly a bit more subtle.

@sulix
Copy link
Contributor Author

sulix commented Sep 4, 2023

Dropped my quick hack to force 16bpp here:
sulix@forcebpp

If I can't find a better solution, I'll clean this up, add a quirk, and send it in.

sulix added a commit to sulix/sdl12-compat that referenced this issue Sep 14, 2023
The LGP port of Hyperspace Delivery Boy has broken colour keys if run in
32-bpp mode (see bug libsdl-org#317). This is because it relies heavily on the
imprecise RGB565->RGB888 conversion in earlier SDL 1.2 versions, when
running in 32-bpp mode.

The game's assets are all in 565 format, and the game converts these to
the screen's format on load. It then sets a colour key. This presents a
problem, because:
- The generic BlitNToN implementation in SDL 1.2 just shifted the
  values, so the resulting image was not at full range. Magenta became
  (F800F8).
- Early versions of SDL 1.2 fell back to the BlitNToN blitter very
  frequently:
  libsdl-org/SDL-1.2@6f4a75d
- So, Hyperspace Delivery Boy calls SDL_MapRGB(0xF8, 0, 0xF8) to get the
  colour key, then sets it on the converted surface.
- In SDL 2.0, the blitters now properly do a full-range conversion, so
  the magenta becomes (FF00FF), which now doesn't match the hardcoded
  (F800F8).
- That being said, in general, it's not guaranteed that SDL_MapRGB()
  will do the same format conversion as SDL_CovertSurface(), so the
  "correct" way of handling this is to set the colour key before
  converting, which works (albeit slowly) in SDL2:
  libsdl-org/SDL#1854
- Since the conversion behaviour is different even between SDL 1.2
  versions, it's not worth trying to imitate it here, so we just force
  the game to run in 16-bpp mode, which works fine.
- (And the game's README recommends it, too.)
@sulix
Copy link
Contributor Author

sulix commented Sep 14, 2023

Okay, I've sent out #321 to report a max BPP of 16 to the game, which works around the issue.

The root cause is, as suspected, the game relying heavily on the imprecise RGB565->RGB888 conversion in earlier SDL 1.2 versions when running in 32-bpp mode.

The game's assets are all in 565 format, and the game converts these to the screen's format on load. It then sets a colour key. This presents a problem, because:

  • The generic BlitNToN implementation in SDL 1.2 just shifted the
    values, so the resulting image was not at full range. Magenta (F81F) became
    (F800F8) instead of (FF00FF).
  • Early versions of SDL 1.2 fell back to the BlitNToN blitter very
    frequently:
    libsdl-org/SDL-1.2@6f4a75d
  • So, Hyperspace Delivery Boy calls SDL_MapRGB(0xF8, 0, 0xF8) to get the
    colour key, then sets it on the converted surface.
  • In SDL 2.0, the blitters now properly do a full-range conversion, so
    the magenta becomes (FF00FF), which now doesn't match the hardcoded
    (F800F8).
  • That being said, in general, it's not guaranteed that SDL_MapRGB()
    will do the same format conversion as SDL_CovertSurface(), so the
    "correct" way of handling this is to set the colour key before
    converting, which works (albeit slowly) in SDL2:
    SDL_ConvertSurface does not convert color keys consistently SDL#1854

Since the conversion behaviour is different even between SDL 1.2 versions, it's not worth trying to imitate it here, so we just force the game to run in 16-bpp mode, which works fine.

(And the game's README recommends it, too.)

slouken pushed a commit that referenced this issue Sep 14, 2023
The LGP port of Hyperspace Delivery Boy has broken colour keys if run in
32-bpp mode (see bug #317). This is because it relies heavily on the
imprecise RGB565->RGB888 conversion in earlier SDL 1.2 versions, when
running in 32-bpp mode.

The game's assets are all in 565 format, and the game converts these to
the screen's format on load. It then sets a colour key. This presents a
problem, because:
- The generic BlitNToN implementation in SDL 1.2 just shifted the
  values, so the resulting image was not at full range. Magenta became
  (F800F8).
- Early versions of SDL 1.2 fell back to the BlitNToN blitter very
  frequently:
  libsdl-org/SDL-1.2@6f4a75d
- So, Hyperspace Delivery Boy calls SDL_MapRGB(0xF8, 0, 0xF8) to get the
  colour key, then sets it on the converted surface.
- In SDL 2.0, the blitters now properly do a full-range conversion, so
  the magenta becomes (FF00FF), which now doesn't match the hardcoded
  (F800F8).
- That being said, in general, it's not guaranteed that SDL_MapRGB()
  will do the same format conversion as SDL_CovertSurface(), so the
  "correct" way of handling this is to set the colour key before
  converting, which works (albeit slowly) in SDL2:
  libsdl-org/SDL#1854
- Since the conversion behaviour is different even between SDL 1.2
  versions, it's not worth trying to imitate it here, so we just force
  the game to run in 16-bpp mode, which works fine.
- (And the game's README recommends it, too.)
@sulix sulix closed this as completed Sep 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant