diff options
author | Alex Fraser <alex@phatcore.com> | 2012-01-11 15:59:57 +0400 |
---|---|---|
committer | Alex Fraser <alex@phatcore.com> | 2012-01-11 15:59:57 +0400 |
commit | 37fc8b4dbbe2cb4b38c9c000834f0b10e1bf1ff0 (patch) | |
tree | 04101a0e40c154d8c1893ceb7a54cad4e285c66a /intern | |
parent | 535d27eb4923d5582ff16b4016344e8f712608d7 (diff) |
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]
Diffstat (limited to 'intern')
-rw-r--r-- | intern/ghost/intern/GHOST_DisplayManagerSDL.cpp | 148 |
1 files changed, 134 insertions, 14 deletions
diff --git a/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp b/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp index 4c67616a4c4..1b875e657d9 100644 --- a/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp +++ b/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp @@ -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 = vidmodes[index]->w; + setting.yPixels = vidmodes[index]->h; - 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; + 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; } |