Browse Source

Add 8-bit video mode for SDL2 and use it in DOS

There are still some glitches in screen transitions but that's probably
our fault. We can improve it later.
pull/8166/head
Gleb Mazovetskiy 7 months ago
parent
commit
50ac397013
  1. 4
      3rdParty/SDL2/CMakeLists.txt
  2. 3
      CMake/Definitions.cmake
  3. 1
      CMake/platforms/dos.cmake
  4. 7
      Source/engine/dx.cpp
  5. 23
      Source/storm/storm_svid.cpp
  6. 91
      Source/utils/display.cpp
  7. 4
      Source/utils/display.h

4
3rdParty/SDL2/CMakeLists.txt vendored

@ -19,8 +19,8 @@ if(TARGET_PLATFORM STREQUAL "dos")
set(DOS ON)
FetchContent_Declare(SDL2
# branch: dos-vbe-rebase
URL https://github.com/diasurgical/SDL/archive/d9cf9066d9cb796b56d1d70c9c560c055a32149b.tar.gz
URL_HASH MD5=9ad9ae69ee0266c895e79cf05a1e0e49
URL https://github.com/diasurgical/SDL/archive/b55cac0c06aa191dcc7a3e63ae6fe6656593026e.tar.gz
URL_HASH MD5=99eabd2fc675f5539e055b1d8fa519e4
)
else()
FetchContent_Declare(SDL2

3
CMake/Definitions.cmake

@ -93,7 +93,8 @@ foreach(
REMAP_KEYBOARD_KEYS
DEVILUTIONX_DEFAULT_RESAMPLER
STREAM_ALL_AUDIO_MIN_FILE_SIZE
DEVILUTIONX_DISPLAY_TEXTURE_FORMAT
DEVILUTIONX_DISPLAY_PIXELFORMAT # SDL2-only
DEVILUTIONX_DISPLAY_TEXTURE_FORMAT # SDL2-only
DEVILUTIONX_SCREENSHOT_FORMAT
DARWIN_MAJOR_VERSION
DARWIN_MINOR_VERSION

1
CMake/platforms/dos.cmake

@ -16,6 +16,7 @@ set(DEVILUTIONX_SYSTEM_SDL2 OFF)
set(DEVILUTIONX_STATIC_SDL2 ON)
set(DEVILUTIONX_SYSTEM_SDL_IMAGE OFF)
set(DEVILUTIONX_SYSTEM_LIBPNG OFF)
set(DEVILUTIONX_DISPLAY_PIXELFORMAT SDL_PIXELFORMAT_INDEX8)
set(DEVILUTIONX_PLATFORM_FILE_UTIL_LINK_LIBRARIES "")

7
Source/engine/dx.cpp

@ -63,7 +63,12 @@ bool CanRenderDirectlyToOutputSurface()
&& outputSurface->format->BitsPerPixel == 8);
#endif
#else // !USE_SDL1
return false;
if (renderer != nullptr) return false;
SDL_Surface *outputSurface = GetOutputSurface();
// Assumes double-buffering is available.
return outputSurface->w == static_cast<int>(gnScreenWidth)
&& outputSurface->h == static_cast<int>(gnScreenHeight)
&& outputSurface->format->BitsPerPixel == 8;
#endif
}

23
Source/storm/storm_svid.cpp

@ -180,6 +180,11 @@ void UpdatePalette()
if (SDL_SetSurfacePalette(SVidSurface.get(), SVidPalette.get()) <= -1) {
ErrSdl();
}
if (GetOutputSurface()->format->BitsPerPixel == 8) {
if (SDL_SetSurfacePalette(GetOutputSurface(), SVidPalette.get()) <= -1) {
ErrSdl();
}
}
#endif
}
@ -311,6 +316,15 @@ bool SVidPlayBegin(const char *filename, int flags)
ErrSdl();
}
}
#if defined(DEVILUTIONX_DISPLAY_PIXELFORMAT) && DEVILUTIONX_DISPLAY_PIXELFORMAT == SDL_PIXELFORMAT_INDEX8
else {
const Size windowSize = { static_cast<int>(SVidWidth), static_cast<int>(SVidHeight) };
SDL_DisplayMode nearestDisplayMode = GetNearestDisplayMode(windowSize, DEVILUTIONX_DISPLAY_PIXELFORMAT);
if (SDL_SetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0) {
ErrSdl();
}
}
#endif
#else
TrySetVideoModeToSVidForSDL1();
#endif
@ -405,6 +419,15 @@ void SVidPlayEnd()
ErrSdl();
}
}
#if defined(DEVILUTIONX_DISPLAY_PIXELFORMAT) && DEVILUTIONX_DISPLAY_PIXELFORMAT == SDL_PIXELFORMAT_INDEX8
else {
const Size windowSize = { static_cast<int>(gnScreenWidth), static_cast<int>(gnScreenHeight) };
SDL_DisplayMode nearestDisplayMode = GetNearestDisplayMode(windowSize, DEVILUTIONX_DISPLAY_PIXELFORMAT);
if (SDL_SetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0) {
ErrSdl();
}
}
#endif
#else
if (IsSVidVideoMode) {
SetVideoModeToPrimary(IsFullScreen(), gnScreenWidth, gnScreenHeight);

91
Source/utils/display.cpp

@ -107,37 +107,6 @@ void CalculatePreferredWindowSize(int &width, int &height)
height = mode.h * width / mode.w;
}
}
SDL_DisplayMode GetNearestDisplayMode(Size preferredSize)
{
SDL_DisplayMode nearestDisplayMode;
if (SDL_GetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0)
ErrSdl();
const int displayIndex = SDL_GetWindowDisplayIndex(ghMainWnd);
const int modeCount = SDL_GetNumDisplayModes(displayIndex);
for (int modeIndex = 0; modeIndex < modeCount; modeIndex++) {
SDL_DisplayMode displayMode;
if (SDL_GetDisplayMode(displayIndex, modeIndex, &displayMode) != 0)
continue;
const int diffHeight = std::abs(nearestDisplayMode.h - preferredSize.height) - std::abs(displayMode.h - preferredSize.height);
const int diffWidth = std::abs(nearestDisplayMode.w - preferredSize.width) - std::abs(displayMode.w - preferredSize.width);
if (diffHeight < 0)
continue;
if (diffHeight == 0 && diffWidth < 0)
continue;
nearestDisplayMode = displayMode;
}
LogVerbose("Nearest display mode to {}x{} is {}x{} {}bpp {}Hz",
preferredSize.width, preferredSize.height,
nearestDisplayMode.w, nearestDisplayMode.h,
SDL_BITSPERPIXEL(nearestDisplayMode.format),
nearestDisplayMode.refresh_rate);
return nearestDisplayMode;
}
#endif
void CalculateUIRectangle()
@ -299,6 +268,59 @@ const auto OptionChangeHandlerVSync = (GetOptions().Graphics.frameRateControl.Se
} // namespace
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_DisplayMode GetNearestDisplayMode(Size preferredSize, SDL_PixelFormatEnum preferredPixelFormat)
{
SDL_DisplayMode nearestDisplayMode;
if (SDL_GetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0)
ErrSdl();
const int displayIndex = SDL_GetWindowDisplayIndex(ghMainWnd);
const int modeCount = SDL_GetNumDisplayModes(displayIndex);
// First, find the best mode among the modes with the requested pixel format.
SDL_PixelFormatEnum bestPixelFormat = SDL_PIXELFORMAT_UNKNOWN;
for (int modeIndex = 0; modeIndex < modeCount; modeIndex++) {
SDL_DisplayMode displayMode;
if (SDL_GetDisplayMode(displayIndex, modeIndex, &displayMode) != 0)
continue;
const int diffHeight = std::abs(nearestDisplayMode.h - preferredSize.height) - std::abs(displayMode.h - preferredSize.height);
const int diffWidth = std::abs(nearestDisplayMode.w - preferredSize.width) - std::abs(displayMode.w - preferredSize.width);
if (diffHeight < 0)
continue;
if (diffHeight == 0 && diffWidth < 0)
continue;
if (preferredPixelFormat == SDL_PIXELFORMAT_UNKNOWN
|| displayMode.format == preferredPixelFormat) {
nearestDisplayMode = displayMode;
}
}
if (preferredPixelFormat != SDL_PIXELFORMAT_UNKNOWN && bestPixelFormat == SDL_PIXELFORMAT_UNKNOWN) {
// If no mode with the preferred pixel format was found, allow any pixel format:
for (int modeIndex = 0; modeIndex < modeCount; modeIndex++) {
SDL_DisplayMode displayMode;
if (SDL_GetDisplayMode(displayIndex, modeIndex, &displayMode) != 0)
continue;
const int diffHeight = std::abs(nearestDisplayMode.h - preferredSize.height) - std::abs(displayMode.h - preferredSize.height);
const int diffWidth = std::abs(nearestDisplayMode.w - preferredSize.width) - std::abs(displayMode.w - preferredSize.width);
if (diffHeight < 0)
continue;
if (diffHeight == 0 && diffWidth < 0)
continue;
nearestDisplayMode = displayMode;
}
}
LogVerbose("Nearest display mode to {}x{} is {}x{} {}bpp {}Hz",
preferredSize.width, preferredSize.height,
nearestDisplayMode.w, nearestDisplayMode.h,
SDL_BITSPERPIXEL(nearestDisplayMode.format),
nearestDisplayMode.refresh_rate);
return nearestDisplayMode;
}
#endif
void AdjustToScreenGeometry(Size windowSize)
{
gnScreenWidth = windowSize.width;
@ -455,6 +477,13 @@ bool SpawnWindow(const char *lpWindowName)
ghMainWnd = SDL_CreateWindow(lpWindowName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowSize.width, windowSize.height, flags);
#if defined(DEVILUTIONX_DISPLAY_PIXELFORMAT)
SDL_DisplayMode nearestDisplayMode = GetNearestDisplayMode(windowSize, DEVILUTIONX_DISPLAY_PIXELFORMAT);
if (SDL_SetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0) {
ErrSdl();
}
#endif
// Note: https://github.com/libsdl-org/SDL/issues/962
// This is a solution to a problem related to SDL mouse grab.
// See https://github.com/diasurgical/devilutionX/issues/4251

4
Source/utils/display.h

@ -109,4 +109,8 @@ void LogicalToOutput(T *x, T *y)
#endif
}
#if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_DisplayMode GetNearestDisplayMode(Size preferredSize, SDL_PixelFormatEnum preferredPixelFormat = SDL_PIXELFORMAT_UNKNOWN);
#endif
} // namespace devilution

Loading…
Cancel
Save