SDL: Add a OpenGL SDL backend and hook it into the SDL backend.

The hooking code is nearly exactly the old hooking code. Only the OpenGL SDL
creation has been adapted since it uses a different constructor now.
This commit is contained in:
Johannes Schickel 2013-08-18 16:56:34 +02:00
parent 46323074e7
commit 5ce830b976
7 changed files with 861 additions and 4 deletions

View file

@ -106,6 +106,10 @@ const OSystem::GraphicsMode glGraphicsModes[] = {
} // End of anonymous namespace
const OSystem::GraphicsMode *OpenGLGraphicsManager::supportedGraphicsModes() {
return glGraphicsModes;
}
const OSystem::GraphicsMode *OpenGLGraphicsManager::getSupportedGraphicsModes() const {
return glGraphicsModes;
}

View file

@ -47,6 +47,10 @@ public:
virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f);
// HACK: This is required for the SDL backend to switch between OpenGL SDL
// and Surface SDL.
static const OSystem::GraphicsMode *supportedGraphicsModes();
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
virtual int getDefaultGraphicsMode() const;
virtual bool setGraphicsMode(int mode);

View file

@ -0,0 +1,487 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "backends/graphics/openglsdl/openglsdl-graphics.h"
#include "common/textconsole.h"
#include "common/config-manager.h"
OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(uint desktopWidth, uint desktopHeight, SdlEventSource *eventSource)
: SdlGraphicsManager(eventSource), _lastVideoModeLoad(0), _hwScreen(nullptr), _lastRequestedWidth(0), _lastRequestedHeight(0),
_graphicsScale(2), _ignoreLoadVideoMode(false), _gotResize(false), _wantsFullScreen(false), _ignoreResizeEvents(0),
_desiredFullscreenWidth(0), _desiredFullscreenHeight(0) {
// Initialize SDL video subsystem
if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
error("Could not initialize SDL: %s", SDL_GetError());
}
// Setup OpenGL attributes for SDL
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// This is also called in initSDL(), but initializing graphics
// may reset it.
SDL_EnableUNICODE(1);
// Disable OS cursor
SDL_ShowCursor(SDL_DISABLE);
// Retrieve a list of working fullscreen modes
const SDL_Rect *const *availableModes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN);
if (availableModes != (void *)-1) {
for (;*availableModes; ++availableModes) {
const SDL_Rect *mode = *availableModes;
_fullscreenVideoModes.push_back(VideoMode(mode->w, mode->h));
}
// Sort the modes in ascending order.
Common::sort(_fullscreenVideoModes.begin(), _fullscreenVideoModes.end());
}
// In case SDL is fine with every mode we will force the desktop mode.
// TODO? We could also try to add some default resolutions here.
if (_fullscreenVideoModes.empty() && desktopWidth && desktopHeight) {
_fullscreenVideoModes.push_back(VideoMode(desktopWidth, desktopHeight));
}
// Get information about display sizes from the previous runs.
if (ConfMan.hasKey("last_fullscreen_mode_width", Common::ConfigManager::kApplicationDomain) && ConfMan.hasKey("last_fullscreen_mode_height", Common::ConfigManager::kApplicationDomain)) {
_desiredFullscreenWidth = ConfMan.getInt("last_fullscreen_mode_width", Common::ConfigManager::kApplicationDomain);
_desiredFullscreenHeight = ConfMan.getInt("last_fullscreen_mode_height", Common::ConfigManager::kApplicationDomain);
} else {
// Use the desktop resolutions when no previous default has been setup.
_desiredFullscreenWidth = desktopWidth;
_desiredFullscreenHeight = desktopHeight;
}
}
OpenGLSdlGraphicsManager::~OpenGLSdlGraphicsManager() {
// Unregister the event observer
if (g_system->getEventManager()->getEventDispatcher()) {
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
}
}
void OpenGLSdlGraphicsManager::initEventObserver() {
// Register the graphics manager as a event observer
g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
}
bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) {
switch (f) {
case OSystem::kFeatureFullscreenMode:
case OSystem::kFeatureIconifyWindow:
return true;
default:
return OpenGLGraphicsManager::hasFeature(f);
}
}
void OpenGLSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
switch (f) {
case OSystem::kFeatureFullscreenMode:
assert(getTransactionMode() != kTransactionNone);
_wantsFullScreen = enable;
// When we switch to windowed mode we will ignore resize events. This
// avoids bad resizes to the (former) fullscreen resolution.
if (!enable) {
_ignoreResizeEvents = 10;
}
break;
case OSystem::kFeatureIconifyWindow:
if (enable) {
SDL_WM_IconifyWindow();
}
break;
default:
OpenGLGraphicsManager::setFeatureState(f, enable);
}
}
bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) {
switch (f) {
case OSystem::kFeatureFullscreenMode:
if (_hwScreen) {
return (_hwScreen->flags & SDL_FULLSCREEN) != 0;
} else {
return _wantsFullScreen;
}
default:
return OpenGLGraphicsManager::getFeatureState(f);
}
}
bool OpenGLSdlGraphicsManager::setGraphicsMode(int mode) {
// HACK: This is stupid but the SurfaceSDL backend defaults to 2x. This
// assures that the launcher (which requests 320x200) has a reasonable
// size. It also makes small games have a reasonable size (i.e. at least
// 640x400). We follow the same logic here until we have a better way to
// give hints to our backend for that.
_graphicsScale = 2;
return OpenGLGraphicsManager::setGraphicsMode(mode);
}
void OpenGLSdlGraphicsManager::resetGraphicsScale() {
OpenGLGraphicsManager::resetGraphicsScale();
// HACK: See OpenGLSdlGraphicsManager::setGraphicsMode.
_graphicsScale = 1;
}
#ifdef USE_RGB_COLOR
Common::List<Graphics::PixelFormat> OpenGLSdlGraphicsManager::getSupportedFormats() const {
Common::List<Graphics::PixelFormat> formats;
// RGBA8888
formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
// RGB565
formats.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
// RGBA5551
formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
// RGBA4444
formats.push_back(Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0));
#ifndef USE_GLES
// ARGB8888, this should not be here, but Sword25 requires it. :-/
formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24));
// RGB555, this is used by SCUMM HE 16 bit games.
formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
#endif
formats.push_back(Graphics::PixelFormat::createFormatCLUT8());
return formats;
}
#endif
void OpenGLSdlGraphicsManager::updateScreen() {
if (_ignoreResizeEvents) {
--_ignoreResizeEvents;
}
OpenGLGraphicsManager::updateScreen();
// Swap OpenGL buffers
SDL_GL_SwapBuffers();
}
void OpenGLSdlGraphicsManager::notifyVideoExpose() {
}
void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height) {
if (!_ignoreResizeEvents && _hwScreen && !(_hwScreen->flags & SDL_FULLSCREEN)) {
// We save that we handled a resize event here. We need to know this
// so we do not overwrite the users requested window size whenever we
// switch aspect ratio or similar.
_gotResize = true;
if (!setupMode(width, height)) {
warning("OpenGLSdlGraphicsManager::notifyResize: Resize failed ('%s')", SDL_GetError());
g_system->quit();
}
}
}
void OpenGLSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) {
adjustMousePosition(point.x, point.y);
}
void OpenGLSdlGraphicsManager::notifyMousePos(Common::Point mouse) {
setMousePosition(mouse.x, mouse.y);
}
void OpenGLSdlGraphicsManager::setInternalMousePosition(int x, int y) {
SDL_WarpMouse(x, y);
}
bool OpenGLSdlGraphicsManager::loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format) {
// In some cases we might not want to load the requested video mode. This
// will assure that the window size is not altered.
if (_ignoreLoadVideoMode) {
_ignoreLoadVideoMode = false;
return true;
}
// This function should never be called from notifyResize thus we know
// that the requested size came from somewhere else.
_gotResize = false;
// Save the requested dimensions.
_lastRequestedWidth = requestedWidth;
_lastRequestedHeight = requestedHeight;
// Apply the currently saved scale setting.
requestedWidth *= _graphicsScale;
requestedHeight *= _graphicsScale;
// Set up the mode.
return setupMode(requestedWidth, requestedHeight);
}
bool OpenGLSdlGraphicsManager::setupMode(uint width, uint height) {
// In case we request a fullscreen mode we will use the mode the user
// has chosen last time or the biggest mode available.
if (_wantsFullScreen) {
if (_desiredFullscreenWidth && _desiredFullscreenHeight) {
// In case only a distinct set of modes is available we check
// whether the requested mode is actually available.
if (!_fullscreenVideoModes.empty()) {
VideoModeArray::const_iterator i = Common::find(_fullscreenVideoModes.begin(),
_fullscreenVideoModes.end(),
VideoMode(_desiredFullscreenWidth, _desiredFullscreenHeight));
// It's not available fall back to default.
if (i == _fullscreenVideoModes.end()) {
_desiredFullscreenWidth = 0;
_desiredFullscreenHeight = 0;
}
}
}
// In case no desired mode has been set we default to the biggest mode
// available or the requested mode in case we don't know any
// any fullscreen modes.
if (!_desiredFullscreenWidth || !_desiredFullscreenHeight) {
if (!_fullscreenVideoModes.empty()) {
VideoModeArray::const_iterator i = _fullscreenVideoModes.end();
--i;
_desiredFullscreenWidth = i->width;
_desiredFullscreenHeight = i->height;
} else {
_desiredFullscreenWidth = width;
_desiredFullscreenHeight = height;
}
}
// Remember our choice.
ConfMan.setInt("last_fullscreen_mode_width", _desiredFullscreenWidth, Common::ConfigManager::kApplicationDomain);
ConfMan.setInt("last_fullscreen_mode_height", _desiredFullscreenHeight, Common::ConfigManager::kApplicationDomain);
// Use our choice.
width = _desiredFullscreenWidth;
height = _desiredFullscreenHeight;
}
// WORKAROUND: Working around infamous SDL bugs when switching
// resolutions too fast. This might cause the event system to supply
// incorrect mouse position events otherwise.
// Reference: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=665779
const uint32 curTime = SDL_GetTicks();
if (_hwScreen && (curTime < _lastVideoModeLoad || curTime - _lastVideoModeLoad < 100)) {
for (int i = 10; i > 0; --i) {
SDL_PumpEvents();
SDL_Delay(10);
}
}
_lastVideoModeLoad = curTime;
uint32 flags = SDL_OPENGL;
if (_wantsFullScreen) {
flags |= SDL_FULLSCREEN;
} else {
flags |= SDL_RESIZABLE;
}
_hwScreen = SDL_SetVideoMode(width, height, 32, flags);
if (!_hwScreen) {
// We treat fullscreen requests as a "hint" for now. This means in
// case it is not available we simply ignore it.
if (_wantsFullScreen) {
_hwScreen = SDL_SetVideoMode(width, height, 32, SDL_OPENGL | SDL_RESIZABLE);
}
}
if (_hwScreen) {
const Graphics::PixelFormat rgba8888 = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
notifyContextChange(rgba8888, rgba8888);
setActualScreenSize(_hwScreen->w, _hwScreen->h);
}
return _hwScreen != nullptr;
}
bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) {
switch (event.type) {
case Common::EVENT_KEYUP:
return isHotkey(event);
case Common::EVENT_KEYDOWN:
if (event.kbd.hasFlags(Common::KBD_ALT)) {
if ( event.kbd.keycode == Common::KEYCODE_RETURN
|| event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER) {
// Alt-Return and Alt-Enter toggle full screen mode
beginGFXTransaction();
setFeatureState(OSystem::kFeatureFullscreenMode, !getFeatureState(OSystem::kFeatureFullscreenMode));
endGFXTransaction();
return true;
}
} else if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_ALT)) {
if ( event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS
|| event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS) {
// Ctrl+Alt+Plus/Minus Increase/decrease the size
const int direction = (event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_KP_PLUS) ? +1 : -1;
if (getFeatureState(OSystem::kFeatureFullscreenMode)) {
// In case we are in fullscreen we will choose the previous
// or next mode.
// In case no modes are available we do nothing.
if (_fullscreenVideoModes.empty()) {
return true;
}
// Look for the current mode.
VideoModeArray::const_iterator i = Common::find(_fullscreenVideoModes.begin(),
_fullscreenVideoModes.end(),
VideoMode(_desiredFullscreenWidth, _desiredFullscreenHeight));
if (i == _fullscreenVideoModes.end()) {
return true;
}
// Cycle through the modes in the specified direction.
if (direction > 0) {
++i;
if (i == _fullscreenVideoModes.end()) {
i = _fullscreenVideoModes.begin();
}
} else {
if (i == _fullscreenVideoModes.begin()) {
i = _fullscreenVideoModes.end();
}
--i;
}
_desiredFullscreenWidth = i->width;
_desiredFullscreenHeight = i->height;
// Try to setup the mode.
if (!setupMode(_lastRequestedWidth, _lastRequestedHeight)) {
warning("OpenGLSdlGraphicsManager::notifyEvent: Fullscreen resize failed ('%s')", SDL_GetError());
g_system->quit();
}
} else {
// Calculate the next scaling setting. We approximate the
// current scale setting in case the user resized the
// window. Then we apply the direction change.
_graphicsScale = MAX<int>(_hwScreen->w / _lastRequestedWidth, _hwScreen->h / _lastRequestedHeight);
_graphicsScale = MAX<int>(_graphicsScale + direction, 1);
// Since we overwrite a user resize here we reset its
// flag here. This makes enabling AR smoother because it
// will change the window size like in surface SDL.
_gotResize = false;
// Try to setup the mode.
if (!setupMode(_lastRequestedWidth * _graphicsScale, _lastRequestedHeight * _graphicsScale)) {
warning("OpenGLSdlGraphicsManager::notifyEvent: Window resize failed ('%s')", SDL_GetError());
g_system->quit();
}
}
return true;
} else if (event.kbd.keycode == Common::KEYCODE_a) {
// In case the user changed the window size manually we will
// not change the window size again here.
_ignoreLoadVideoMode = _gotResize;
// Ctrl+Alt+a toggles the aspect ratio correction state.
beginGFXTransaction();
setFeatureState(OSystem::kFeatureAspectRatioCorrection, !getFeatureState(OSystem::kFeatureAspectRatioCorrection));
endGFXTransaction();
// Make sure we do not ignore the next resize. This
// effectively checks whether loadVideoMode has been called.
assert(!_ignoreLoadVideoMode);
return true;
} else if (event.kbd.keycode == Common::KEYCODE_f) {
// Ctrl+Alt+f toggles the graphics modes.
// We are crazy we will allow the OpenGL base class to
// introduce new graphics modes like shaders for special
// filtering. If some other OpenGL subclass needs this,
// we can think of refactoring this.
int mode = getGraphicsMode();
const OSystem::GraphicsMode *supportedModes = getSupportedGraphicsModes();
const OSystem::GraphicsMode *modeDesc = nullptr;
// Search the current mode.
for (; supportedModes->name; ++supportedModes) {
if (supportedModes->id == mode) {
modeDesc = supportedModes;
break;
}
}
assert(modeDesc);
// Try to use the next mode in the list.
++modeDesc;
if (!modeDesc->name) {
modeDesc = getSupportedGraphicsModes();
}
// Never ever try to resize the window when we simply want to
// switch the graphics mode. This assures that the window size
// does not change.
_ignoreLoadVideoMode = true;
beginGFXTransaction();
setGraphicsMode(modeDesc->id);
endGFXTransaction();
// Make sure we do not ignore the next resize. This
// effectively checks whether loadVideoMode has been called.
assert(!_ignoreLoadVideoMode);
return true;
}
}
// Fall through
default:
return false;
}
}
bool OpenGLSdlGraphicsManager::isHotkey(const Common::Event &event) {
if (event.kbd.hasFlags(Common::KBD_ALT)) {
return event.kbd.keycode == Common::KEYCODE_RETURN
|| event.kbd.keycode == (Common::KeyCode)SDLK_KP_ENTER;
} else if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_ALT)) {
return event.kbd.keycode == Common::KEYCODE_PLUS || event.kbd.keycode == Common::KEYCODE_MINUS
|| event.kbd.keycode == Common::KEYCODE_KP_PLUS || event.kbd.keycode == Common::KEYCODE_KP_MINUS
|| event.kbd.keycode == Common::KEYCODE_a
|| event.kbd.keycode == Common::KEYCODE_f;
}
return false;
}

View file

@ -0,0 +1,115 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef BACKENDS_GRAPHICS_OPENGLSDL_OPENGLSDL_GRAPHICS_H
#define BACKENDS_GRAPHICS_OPENGLSDL_OPENGLSDL_GRAPHICS_H
#include "backends/graphics/opengl/opengl-graphics.h"
#include "backends/graphics/sdl/sdl-graphics.h"
#include "backends/platform/sdl/sdl-sys.h"
#include "common/array.h"
#include "common/events.h"
class OpenGLSdlGraphicsManager : public OpenGL::OpenGLGraphicsManager, public SdlGraphicsManager, public Common::EventObserver {
public:
OpenGLSdlGraphicsManager(uint desktopWidth, uint desktopHeight, SdlEventSource *eventSource);
virtual ~OpenGLSdlGraphicsManager();
void initEventObserver();
// GraphicsManager API
virtual bool hasFeature(OSystem::Feature f);
virtual void setFeatureState(OSystem::Feature f, bool enable);
virtual bool getFeatureState(OSystem::Feature f);
virtual bool setGraphicsMode(int mode);
virtual void resetGraphicsScale();
#ifdef USE_RGB_COLOR
virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const;
#endif
virtual void updateScreen();
// EventObserver API
virtual bool notifyEvent(const Common::Event &event);
// SdlGraphicsManager API
virtual void notifyVideoExpose();
virtual void notifyResize(const uint width, const uint height);
virtual void transformMouseCoordinates(Common::Point &point);
virtual void notifyMousePos(Common::Point mouse);
protected:
virtual void setInternalMousePosition(int x, int y);
virtual bool loadVideoMode(uint requestedWidth, uint requestedHeight, const Graphics::PixelFormat &format);
private:
bool setupMode(uint width, uint height);
uint32 _lastVideoModeLoad;
SDL_Surface *_hwScreen;
uint _lastRequestedWidth;
uint _lastRequestedHeight;
uint _graphicsScale;
bool _ignoreLoadVideoMode;
bool _gotResize;
bool _wantsFullScreen;
uint _ignoreResizeEvents;
struct VideoMode {
VideoMode() : width(0), height(0) {}
VideoMode(uint w, uint h) : width(w), height(h) {}
bool operator<(const VideoMode &right) const {
if (width < right.width) {
return true;
} else if (width == right.width && height < right.height) {
return true;
} else {
return false;
}
}
bool operator==(const VideoMode &right) const {
return width == right.width && height == right.height;
}
bool operator!=(const VideoMode &right) const {
return !(*this == right);
}
uint width, height;
};
typedef Common::Array<VideoMode> VideoModeArray;
VideoModeArray _fullscreenVideoModes;
uint _desiredFullscreenWidth;
uint _desiredFullscreenHeight;
virtual bool isHotkey(const Common::Event &event);
};
#endif

View file

@ -77,6 +77,11 @@ ifndef USE_SDL13
MODULE_OBJS += \
audiocd/sdl/sdl-audiocd.o
endif
ifdef USE_OPENGL
MODULE_OBJS += \
graphics/openglsdl/openglsdl-graphics.o
endif
endif
ifdef POSIX

View file

@ -47,6 +47,10 @@
#include "backends/mutex/sdl/sdl-mutex.h"
#include "backends/timer/sdl/sdl-timer.h"
#include "backends/graphics/surfacesdl/surfacesdl-graphics.h"
#ifdef USE_OPENGL
#include "backends/graphics/openglsdl/openglsdl-graphics.h"
#include "graphics/cursorman.h"
#endif
#include "icons/scummvm.xpm"
@ -60,6 +64,14 @@
OSystem_SDL::OSystem_SDL()
:
#ifdef USE_OPENGL
_desktopWidth(0),
_desktopHeight(0),
_graphicsModes(0),
_graphicsMode(0),
_sdlModesCount(0),
_glModesCount(0),
#endif
_inited(false),
_initedSDL(false),
_logger(0),
@ -100,6 +112,10 @@ OSystem_SDL::~OSystem_SDL() {
delete _mutexManager;
_mutexManager = 0;
#ifdef USE_OPENGL
delete[] _graphicsModes;
#endif
delete _logger;
_logger = 0;
@ -129,6 +145,11 @@ void OSystem_SDL::init() {
if (_taskbarManager == 0)
_taskbarManager = new Common::TaskbarManager();
#endif
#ifdef USE_OPENGL
// Setup a list with both SDL and OpenGL graphics modes
setupGraphicsModes();
#endif
}
void OSystem_SDL::initBackend() {
@ -140,8 +161,46 @@ void OSystem_SDL::initBackend() {
if (_eventSource == 0)
_eventSource = new SdlEventSource();
int graphicsManagerType = 0;
#ifdef USE_OPENGL
// Query the desktop resolution. We simply hope nothing tried to change
// the resolution so far.
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
if (videoInfo && videoInfo->current_w > 0 && videoInfo->current_h > 0) {
_desktopWidth = videoInfo->current_w;
_desktopHeight = videoInfo->current_h;
}
#endif
if (_graphicsManager == 0) {
#ifdef USE_OPENGL
if (ConfMan.hasKey("gfx_mode")) {
Common::String gfxMode(ConfMan.get("gfx_mode"));
bool use_opengl = false;
const OSystem::GraphicsMode *mode = OpenGLSdlGraphicsManager::supportedGraphicsModes();
int i = 0;
while (mode->name) {
if (scumm_stricmp(mode->name, gfxMode.c_str()) == 0) {
_graphicsMode = i + _sdlModesCount;
use_opengl = true;
}
mode++;
++i;
}
// If the gfx_mode is from OpenGL, create the OpenGL graphics manager
if (use_opengl) {
_graphicsManager = new OpenGLSdlGraphicsManager(_desktopWidth, _desktopHeight, _eventSource);
graphicsManagerType = 1;
}
}
#endif
if (_graphicsManager == 0) {
_graphicsManager = new SurfaceSdlGraphicsManager(_eventSource);
graphicsManagerType = 0;
}
}
if (_savefileManager == 0)
@ -183,7 +242,13 @@ void OSystem_SDL::initBackend() {
// so the virtual keyboard can be initialized, but we have to add the
// graphics manager as an event observer after initializing the event
// manager.
if (graphicsManagerType == 0)
((SurfaceSdlGraphicsManager *)_graphicsManager)->initEventObserver();
#ifdef USE_OPENGL
else if (graphicsManagerType == 1)
((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver();
#endif
}
#if defined(USE_TASKBAR)
@ -208,8 +273,9 @@ void OSystem_SDL::initSDL() {
if (ConfMan.hasKey("disable_sdl_parachute"))
sdlFlags |= SDL_INIT_NOPARACHUTE;
#ifdef WEBOS
// WebOS needs this flag or otherwise the application won't start
#if defined(WEBOS) || defined(USE_OPENGL)
// WebOS needs this flag or otherwise the application won't start.
// OpenGL SDL needs this to query the desktop resolution on startup.
sdlFlags |= SDL_INIT_VIDEO;
#endif
@ -478,3 +544,160 @@ Common::TimerManager *OSystem_SDL::getTimerManager() {
return _timerManager;
#endif
}
#ifdef USE_OPENGL
const OSystem::GraphicsMode *OSystem_SDL::getSupportedGraphicsModes() const {
return _graphicsModes;
}
int OSystem_SDL::getDefaultGraphicsMode() const {
// Return the default graphics mode from the current graphics manager
if (_graphicsMode < _sdlModesCount)
return _graphicsManager->getDefaultGraphicsMode();
else
return _graphicsManager->getDefaultGraphicsMode() + _sdlModesCount;
}
bool OSystem_SDL::setGraphicsMode(int mode) {
const OSystem::GraphicsMode *srcMode;
int i;
// Check if mode is from SDL or OpenGL
if (mode < _sdlModesCount) {
srcMode = SurfaceSdlGraphicsManager::supportedGraphicsModes();
i = 0;
} else {
srcMode = OpenGLSdlGraphicsManager::supportedGraphicsModes();
i = _sdlModesCount;
}
// Very hacky way to set up the old graphics manager state, in case we
// switch from SDL->OpenGL or OpenGL->SDL.
//
// This is a probably temporary workaround to fix bugs like #3368143
// "SDL/OpenGL: Crash when switching renderer backend".
const int screenWidth = _graphicsManager->getWidth();
const int screenHeight = _graphicsManager->getHeight();
const bool arState = _graphicsManager->getFeatureState(kFeatureAspectRatioCorrection);
const bool fullscreen = _graphicsManager->getFeatureState(kFeatureFullscreenMode);
const bool cursorPalette = _graphicsManager->getFeatureState(kFeatureCursorPalette);
#ifdef USE_RGB_COLOR
const Graphics::PixelFormat pixelFormat = _graphicsManager->getScreenFormat();
#endif
bool switchedManager = false;
// Loop through modes
while (srcMode->name) {
if (i == mode) {
// If the new mode and the current mode are not from the same graphics
// manager, delete and create the new mode graphics manager
if (_graphicsMode >= _sdlModesCount && mode < _sdlModesCount) {
debug(1, "switching to plain SDL graphics");
delete _graphicsManager;
_graphicsManager = new SurfaceSdlGraphicsManager(_eventSource);
((SurfaceSdlGraphicsManager *)_graphicsManager)->initEventObserver();
_graphicsManager->beginGFXTransaction();
switchedManager = true;
} else if (_graphicsMode < _sdlModesCount && mode >= _sdlModesCount) {
debug(1, "switching to OpenGL graphics");
delete _graphicsManager;
_graphicsManager = new OpenGLSdlGraphicsManager(_desktopWidth, _desktopHeight, _eventSource);
((OpenGLSdlGraphicsManager *)_graphicsManager)->initEventObserver();
_graphicsManager->beginGFXTransaction();
switchedManager = true;
}
_graphicsMode = mode;
if (switchedManager) {
#ifdef USE_RGB_COLOR
_graphicsManager->initSize(screenWidth, screenHeight, &pixelFormat);
#else
_graphicsManager->initSize(screenWidth, screenHeight, 0);
#endif
_graphicsManager->setFeatureState(kFeatureAspectRatioCorrection, arState);
_graphicsManager->setFeatureState(kFeatureFullscreenMode, fullscreen);
_graphicsManager->setFeatureState(kFeatureCursorPalette, cursorPalette);
// Worst part about this right now, tell the cursor manager to
// resetup the cursor + cursor palette if necessarily
// First we need to try to setup the old state on the new manager...
if (_graphicsManager->endGFXTransaction() != kTransactionSuccess) {
// Oh my god if this failed the client code might just explode.
return false;
}
// Next setup the cursor again
CursorMan.pushCursor(0, 0, 0, 0, 0, 0);
CursorMan.popCursor();
// Next setup cursor palette if needed
if (cursorPalette) {
CursorMan.pushCursorPalette(0, 0, 0);
CursorMan.popCursorPalette();
}
_graphicsManager->beginGFXTransaction();
// Oh my god if this failed the client code might just explode.
return _graphicsManager->setGraphicsMode(srcMode->id);
} else {
return _graphicsManager->setGraphicsMode(srcMode->id);
}
}
i++;
srcMode++;
}
return false;
}
int OSystem_SDL::getGraphicsMode() const {
return _graphicsMode;
}
void OSystem_SDL::setupGraphicsModes() {
const OSystem::GraphicsMode *sdlGraphicsModes = SurfaceSdlGraphicsManager::supportedGraphicsModes();
const OSystem::GraphicsMode *openglGraphicsModes = OpenGLSdlGraphicsManager::supportedGraphicsModes();
_sdlModesCount = 0;
_glModesCount = 0;
// Count the number of graphics modes
const OSystem::GraphicsMode *srcMode = sdlGraphicsModes;
while (srcMode->name) {
_sdlModesCount++;
srcMode++;
}
srcMode = openglGraphicsModes;
while (srcMode->name) {
_glModesCount++;
srcMode++;
}
// Allocate enough space for merged array of modes
_graphicsModes = new OSystem::GraphicsMode[_glModesCount + _sdlModesCount + 1];
// Copy SDL graphics modes
memcpy((void *)_graphicsModes, sdlGraphicsModes, _sdlModesCount * sizeof(OSystem::GraphicsMode));
// Copy OpenGL graphics modes
memcpy((void *)(_graphicsModes + _sdlModesCount), openglGraphicsModes, _glModesCount * sizeof(OSystem::GraphicsMode));
// Set a null mode at the end
memset((void *)(_graphicsModes + _sdlModesCount + _glModesCount), 0, sizeof(OSystem::GraphicsMode));
// Set new internal ids for all modes
int i = 0;
OSystem::GraphicsMode *mode = _graphicsModes;
while (mode->name) {
mode->id = i++;
mode++;
}
}
#endif

View file

@ -104,6 +104,25 @@ protected:
// Logging
virtual Common::WriteStream *createLogFile() { return 0; }
Backends::Log::Log *_logger;
#ifdef USE_OPENGL
int _desktopWidth, _desktopHeight;
OSystem::GraphicsMode *_graphicsModes;
int _graphicsMode;
int _sdlModesCount;
int _glModesCount;
/**
* Creates the merged graphics modes list
*/
virtual void setupGraphicsModes();
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const;
virtual int getDefaultGraphicsMode() const;
virtual bool setGraphicsMode(int mode);
virtual int getGraphicsMode() const;
#endif
};
#endif