This patch implements mode switching (resolution changing) for full-screen games.

Hopefully, this should be platform agnostic. Requires WITH_GHOST_SDL.
This patch contains code from Quake 2 and bzflag.
Tracker: [#29839]
This commit is contained in:
Alex Fraser
2012-01-11 11:59:57 +00:00
parent 535d27eb49
commit 37fc8b4dbb

View File

@@ -17,6 +17,11 @@
*
* Contributor(s): Campbell Barton
*
* Mode switching
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (c) 1993-2011 Tim Riker
* Copyright (C) 2012 Alex Fraser
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -47,7 +52,19 @@ GHOST_TSuccess GHOST_DisplayManagerSDL::getNumDisplaySettings(GHOST_TUns8 displa
GHOST_TInt32& numSettings) const
{
GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
numSettings= GHOST_TInt32(1);
int i;
SDL_Rect **vidmodes;
vidmodes = SDL_ListModes(NULL, SDL_HWSURFACE | SDL_OPENGL |
SDL_FULLSCREEN | SDL_HWPALETTE);
if (!vidmodes) {
fprintf(stderr, "Could not get available video modes: %s.\n",
SDL_GetError());
return GHOST_kFailure;
}
for (i = 0; vidmodes[i]; i++);
numSettings = GHOST_TInt32(i);
return GHOST_kSuccess;
}
@@ -56,18 +73,38 @@ GHOST_DisplayManagerSDL::getDisplaySetting(GHOST_TUns8 display,
GHOST_TInt32 index,
GHOST_DisplaySetting& setting) const
{
GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
GHOST_ASSERT(index < 1, "Requested setting outside of valid range.\n");
SDL_DisplayMode mode;
SDL_GetDesktopDisplayMode(display, &mode);
int i;
SDL_Rect **vidmodes;
/* NULL is passed in here to get the modes for the current bit depth.
* Other bit depths may be possible; in that case, an SDL_PixelFormat struct
* should be passed in. To get a complete profile, all possible bit depths
* would need to be iterated over. - z0r */
vidmodes = SDL_ListModes(NULL, SDL_HWSURFACE | SDL_OPENGL |
SDL_FULLSCREEN | SDL_HWPALETTE);
if (!vidmodes) {
fprintf(stderr, "Could not get available video modes: %s.\n",
SDL_GetError());
return GHOST_kFailure;
}
for (i = 0; vidmodes[i]; i++);
GHOST_ASSERT(index < i, "Requested setting outside of valid range.\n");
setting.xPixels= mode.w;
setting.yPixels= mode.h;
setting.bpp= SDL_BYTESPERPIXEL(mode.format);
/* assume 60 when unset */
setting.frequency= mode.refresh_rate ? mode.refresh_rate : 60;
setting.xPixels = vidmodes[index]->w;
setting.yPixels = vidmodes[index]->h;
SDL_Surface *surf;
surf = SDL_GetVideoSurface();
if (surf == NULL) {
fprintf(stderr, "Getting display setting: %s\n", SDL_GetError());
/* Just guess the bit depth */
setting.bpp = 32;
} else {
setting.bpp = surf->format->BitsPerPixel;
}
/* Just guess the frequency :( */
setting.frequency = 60;
return GHOST_kSuccess;
}
@@ -76,17 +113,100 @@ GHOST_TSuccess
GHOST_DisplayManagerSDL::getCurrentDisplaySetting(GHOST_TUns8 display,
GHOST_DisplaySetting& setting) const
{
return getDisplaySetting(display,GHOST_TInt32(0),setting);
SDL_Surface *surf;
const SDL_VideoInfo *info;
/* Note: not using SDL_GetDesktopDisplayMode because that does not return
* the current mode. Try to use GetVideoSurface first, as it seems more
* accurate. If that fails, try other methods. - z0r */
surf = SDL_GetVideoSurface();
if (surf != NULL) {
setting.xPixels = surf->w;
setting.yPixels = surf->h;
setting.bpp = surf->format->BitsPerPixel;
/* Just guess the frequency :( */
setting.frequency = 60;
} else {
/* This may happen if the surface hasn't been created yet, e.g. on
* application startup. */
info = SDL_GetVideoInfo();
setting.xPixels = info->current_w;
setting.yPixels = info->current_h;
setting.bpp = info->vfmt->BitsPerPixel;
/* Just guess the frequency :( */
setting.frequency = 60;
}
return GHOST_kSuccess;
}
GHOST_TSuccess
GHOST_DisplayManagerSDL:: setCurrentDisplaySetting(GHOST_TUns8 display,
const GHOST_DisplaySetting& setting)
{
// This is never going to work robustly in X
// but it's currently part of the full screen interface
// we fudge it for now.
/*
* Mode switching code ported from Quake 2 version 3.21 and bzflag version
* 2.4.0:
* ftp://ftp.idsoftware.com/idstuff/source/q2source-3.21.zip
* See linux/gl_glx.c:GLimp_SetMode
* http://wiki.bzflag.org/BZFlag_Source
* See src/platform/SDLDisplay.cxx:SDLDisplay and createWindow
*/
SDL_Surface *surf;
int best_fit, best_dist, dist, x, y;
SDL_Rect **vidmodes = SDL_ListModes(NULL, SDL_HWSURFACE | SDL_OPENGL |
SDL_FULLSCREEN | SDL_HWPALETTE);
if (!vidmodes) {
fprintf(stderr, "Could not get available video modes: %s.\n",
SDL_GetError());
}
best_dist = 9999999;
best_fit = -1;
if (vidmodes == (SDL_Rect **) -1) {
/* Any mode is OK. */
x = setting.xPixels;
y = setting.yPixels;
} else {
for (int i = 0; vidmodes[i]; i++) {
if (setting.xPixels > vidmodes[i]->w ||
setting.yPixels > vidmodes[i]->h)
continue;
x = setting.xPixels - vidmodes[i]->w;
y = setting.yPixels - vidmodes[i]->h;
dist = (x * x) + (y * y);
if (dist < best_dist) {
best_dist = dist;
best_fit = i;
}
}
if (best_fit == -1)
return GHOST_kFailure;
x = vidmodes[best_fit]->w;
y = vidmodes[best_fit]->h;
}
# ifdef _DEBUG
printf("Switching to video mode %dx%d\n", x, y);
# endif
// limit us to the main display
static char singleDisplayEnv[] = "SDL_SINGLEDISPLAY=1";
putenv(singleDisplayEnv);
// change to the mode
surf = SDL_SetVideoMode(x, y, setting.bpp, SDL_OPENGL | SDL_FULLSCREEN);
if (surf == NULL) {
fprintf(stderr, "Could not set video mode: %s.\n", SDL_GetError());
return GHOST_kFailure;
}
return GHOST_kSuccess;
}