diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp new file mode 100644 index 00000000000..840cceeb53b --- /dev/null +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -0,0 +1,649 @@ +/* ResidualVM - A 3D game interpreter + * + * ResidualVM 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. + * + */ + +#define FORBIDDEN_SYMBOL_EXCEPTION_putenv + +#include "common/scummsys.h" + +#if defined(SDL_BACKEND) + +#include "backends/graphics/openglsdl/openglsdl-graphics.h" +#include "backends/events/sdl/sdl-events.h" +#include "backends/platform/sdl/sdl.h" +#include "common/config-manager.h" +#include "common/mutex.h" +#include "common/textconsole.h" +#include "common/translation.h" +#include "common/util.h" +#ifdef USE_RGB_COLOR +#include "common/list.h" +#endif +#include "graphics/font.h" +#include "graphics/fontman.h" +#include "graphics/scaler.h" +#include "graphics/surface.h" +#include "graphics/pixelbuffer.h" +#include "gui/EventRecorder.h" + +#include "graphics/opengl/context.h" + +OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window) + : + ResVmSdlGraphicsManager(sdlEventSource, window), +#if SDL_VERSION_ATLEAST(2, 0, 0) + _glContext(nullptr), +#endif + _overlayscreen(0), + _gameRect(), + _frameBuffer(nullptr), + _surfaceRenderer(nullptr) { + ConfMan.registerDefault("antialiasing", 0); + + _sideTextures[0] = _sideTextures[1] = nullptr; + + // Don't start at zero so that the value is never the same as the surface graphics manager + _screenChangeCount = 1 << (sizeof(int) * 8 - 2); +} + +OpenGLSdlGraphicsManager::~OpenGLSdlGraphicsManager() { + closeOverlay(); +} + +bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) { + return + (f == OSystem::kFeatureFullscreenMode) || + (f == OSystem::kFeatureOpenGL) || + (f == OSystem::kFeatureAspectRatioCorrection); +} + +void OpenGLSdlGraphicsManager::setupScreen(uint gameWidth, uint gameHeight, bool fullscreen, bool accel3d) { + assert(accel3d); + closeOverlay(); + + _antialiasing = ConfMan.getInt("antialiasing"); + _fullscreen = fullscreen; + _lockAspectRatio = ConfMan.getBool("aspect_ratio"); + + bool engineSupportsArbitraryResolutions = g_engine && g_engine->hasFeature(Engine::kSupportsArbitraryResolutions); + + // Detecting if OpenGL framebuffers are available relies on spawning an offscreen window + // thus it is only done when framebuffers may be used. + bool framebufferSupported = fullscreen && detectFramebufferSupport(); + + // Select how the game screen is going to be drawn + GameRenderTarget gameRenderTarget = selectGameRenderTarget(_fullscreen, true, engineSupportsArbitraryResolutions, + framebufferSupported, _lockAspectRatio); + + // Choose the effective window size or fullscreen mode + uint effectiveWidth; + uint effectiveHeight; + if (_fullscreen && canUsePreferredResolution(gameRenderTarget, engineSupportsArbitraryResolutions)) { + Common::Rect fullscreenResolution = getPreferredFullscreenResolution(); + effectiveWidth = fullscreenResolution.width(); + effectiveHeight = fullscreenResolution.height(); + } else { + effectiveWidth = gameWidth; + effectiveHeight = gameHeight; + } + + // Compute the rectangle where to draw the game inside the effective screen + _gameRect = computeGameRect(gameRenderTarget, gameWidth, gameHeight, effectiveWidth, effectiveHeight); + + if (!createScreenOpenGL(effectiveWidth, effectiveHeight, gameRenderTarget)) { + warning("Error: %s", SDL_GetError()); + g_system->quit(); + } + + int glflag; + const GLubyte *str; + + // apply atribute again for sure based on SDL docs + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + + str = glGetString(GL_VENDOR); + debug("INFO: OpenGL Vendor: %s", str); + str = glGetString(GL_RENDERER); + debug("INFO: OpenGL Renderer: %s", str); + str = glGetString(GL_VERSION); + debug("INFO: OpenGL Version: %s", str); + SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &glflag); + debug("INFO: OpenGL Red bits: %d", glflag); + SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &glflag); + debug("INFO: OpenGL Green bits: %d", glflag); + SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &glflag); + debug("INFO: OpenGL Blue bits: %d", glflag); + SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &glflag); + debug("INFO: OpenGL Alpha bits: %d", glflag); + SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &glflag); + debug("INFO: OpenGL Z buffer depth bits: %d", glflag); + SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &glflag); + debug("INFO: OpenGL Double Buffer: %d", glflag); + SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &glflag); + debug("INFO: OpenGL Stencil buffer bits: %d", glflag); + +#ifdef USE_GLEW + debug("INFO: GLEW Version: %s", glewGetString(GLEW_VERSION)); + GLenum err = glewInit(); + if (err != GLEW_OK) { + warning("Error: %s", glewGetErrorString(err)); + g_system->quit(); + } +#endif + +#ifdef USE_OPENGL_SHADERS + debug("INFO: GLSL version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); +#endif + + initializeOpenGLContext(); + _surfaceRenderer = OpenGL::createBestSurfaceRenderer(); + + uint32 rmask, gmask, bmask, amask; +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + rmask = 0x00001f00; + gmask = 0x000007e0; + bmask = 0x000000f8; + amask = 0x00000000; +#else + rmask = 0x0000f800; + gmask = 0x000007e0; + bmask = 0x0000001f; + amask = 0x00000000; +#endif + _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, effectiveWidth, effectiveHeight, 16, + rmask, gmask, bmask, amask); + _overlayFormat = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + + if (!_overlayscreen) { + warning("Error: %s", SDL_GetError()); + g_system->quit(); + } + + _overlayWidth = effectiveWidth; + _overlayHeight = effectiveHeight; + _screenFormat = _overlayFormat; + + _screenChangeCount++; + +#if !defined(AMIGAOS) + if (gameRenderTarget == kFramebuffer) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + _frameBuffer = createFramebuffer(gameWidth, gameHeight); + _frameBuffer->attach(); + } +#endif +} + +bool OpenGLSdlGraphicsManager::detectFramebufferSupport() { + bool framebufferSupported = false; +#if defined(USE_GLES2) + // Framebuffers are always available with GLES2 + framebufferSupported = true; +#elif !defined(AMIGAOS) + // Spawn a 32x32 window off-screen with a GL context to test if framebuffers are supported +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_Window *window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 32, 32, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); + if (window) { + SDL_GLContext glContext = SDL_GL_CreateContext(window); + if (glContext) { + initializeOpenGLContext(); + framebufferSupported = OpenGLContext.framebufferObjectSupported; + SDL_GL_DeleteContext(glContext); + } + SDL_DestroyWindow(window); + } +#else + SDL_putenv(const_cast("SDL_VIDEO_WINDOW_POS=9000,9000")); + SDL_SetVideoMode(32, 32, 0, SDL_OPENGL); + SDL_putenv(const_cast("SDL_VIDEO_WINDOW_POS=center")); + initializeOpenGLContext(); + framebufferSupported = OpenGLContext.framebufferObjectSupported; +#endif +#endif + return framebufferSupported; +} + +Graphics::PixelBuffer OpenGLSdlGraphicsManager::getScreenPixelBuffer() { + error("Direct screen buffer access is not allowed when using OpenGL"); +} + +void OpenGLSdlGraphicsManager::initializeOpenGLContext() const { + OpenGL::ContextType type; + +#ifdef USE_GLES2 + type = OpenGL::kContextGLES2; +#else + type = OpenGL::kContextGL; +#endif + + OpenGLContext.initialize(type); +} + +OpenGLSdlGraphicsManager::OpenGLPixelFormat::OpenGLPixelFormat(uint screenBytesPerPixel, uint red, uint blue, uint green, uint alpha, int samples) : + bytesPerPixel(screenBytesPerPixel), + redSize(red), + blueSize(blue), + greenSize(green), + alphaSize(alpha), + multisampleSamples(samples) { + +} + +bool OpenGLSdlGraphicsManager::createScreenOpenGL(uint effectiveWidth, uint effectiveHeight, GameRenderTarget gameRenderTarget) { + // Build a list of OpenGL pixel formats usable by ResidualVM + Common::Array pixelFormats; + if (_antialiasing > 0 && gameRenderTarget == kScreen) { + // Don't enable screen level multisampling when rendering to a framebuffer + pixelFormats.push_back(OpenGLPixelFormat(32, 8, 8, 8, 8, _antialiasing)); + pixelFormats.push_back(OpenGLPixelFormat(16, 5, 5, 5, 1, _antialiasing)); + pixelFormats.push_back(OpenGLPixelFormat(16, 5, 6, 5, 0, _antialiasing)); + } + pixelFormats.push_back(OpenGLPixelFormat(32, 8, 8, 8, 8, 0)); + pixelFormats.push_back(OpenGLPixelFormat(16, 5, 5, 5, 1, 0)); + pixelFormats.push_back(OpenGLPixelFormat(16, 5, 6, 5, 0, 0)); + + // Unfortunatly, SDL does not provide a list of valid pixel formats + // for the current OpenGL implementation and hardware. + // SDL may not be able to create a screen with the preferred pixel format. + // Try all the pixel formats in the list until SDL returns a valid screen. + Common::Array::const_iterator it = pixelFormats.begin(); + for (; it != pixelFormats.end(); it++) { + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, it->redSize); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, it->greenSize); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, it->blueSize); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, it->alphaSize); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, it->multisampleSamples > 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, it->multisampleSamples); +#if SDL_VERSION_ATLEAST(2, 0, 0) +#ifdef USE_GLES2 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); +#else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); +#endif +#endif + +#if SDL_VERSION_ATLEAST(2, 0, 0) + uint32 sdlflags = SDL_WINDOW_OPENGL; + if (_fullscreen) + sdlflags |= SDL_WINDOW_FULLSCREEN; + + if (_window->createWindow(effectiveWidth, effectiveHeight, sdlflags)) { + _glContext = SDL_GL_CreateContext(_window->getSDLWindow()); + if (_glContext) { + break; + } + } + + _window->destroyWindow(); +#else + uint32 sdlflags = SDL_OPENGL; + if (_fullscreen) + sdlflags |= SDL_FULLSCREEN; + + SDL_Surface *screen = SDL_SetVideoMode(effectiveWidth, effectiveHeight, it->bytesPerPixel, sdlflags); + if (screen) { + break; + } +#endif + } + + // Display a warning if the effective pixel format is not the preferred one + if (it != pixelFormats.begin() && it != pixelFormats.end()) { + bool wantsAA = pixelFormats.front().multisampleSamples > 0; + bool gotAA = it->multisampleSamples > 0; + + warning("Couldn't create a %d-bit visual%s, using to %d-bit%s instead", + pixelFormats.front().bytesPerPixel, + wantsAA && !gotAA ? " with AA" : "", + it->bytesPerPixel, + wantsAA && !gotAA ? " without AA" : ""); + } + + return it != pixelFormats.end(); +} + +#define BITMAP_TEXTURE_SIZE 256 + +void OpenGLSdlGraphicsManager::updateOverlayTextures() { + if (!_overlayscreen) + return; + + // remove if already exist + for (uint i = 0; i < _overlayTextures.size(); i++) { + delete _overlayTextures[i]; + } + _overlayTextures.clear(); + + Graphics::Surface overlaySurface; + overlaySurface.w = _overlayscreen->w; + overlaySurface.h = _overlayscreen->h; + overlaySurface.pitch = _overlayscreen->pitch; + overlaySurface.format = getOverlayFormat(); + overlaySurface.setPixels(_overlayscreen->pixels); + + for (int y = 0; y < _overlayHeight; y += BITMAP_TEXTURE_SIZE) { + for (int x = 0; x < _overlayWidth; x += BITMAP_TEXTURE_SIZE) { + int t_width = (x + BITMAP_TEXTURE_SIZE >= _overlayWidth) ? (_overlayWidth - x) : BITMAP_TEXTURE_SIZE; + int t_height = (y + BITMAP_TEXTURE_SIZE >= _overlayHeight) ? (_overlayHeight - y) : BITMAP_TEXTURE_SIZE; + + Common::Rect textureArea = Common::Rect(t_width, t_height); + textureArea.translate(x, y); + + const Graphics::Surface subSurface = overlaySurface.getSubArea(textureArea); + _overlayTextures.push_back(new OpenGL::Texture(subSurface)); + } + } +} + +void OpenGLSdlGraphicsManager::drawOverlayOpenGL() { + if (!_overlayscreen) + return; + + glViewport(0, 0, _overlayWidth, _overlayHeight); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + _surfaceRenderer->prepareState(); + + int curTexIdx = 0; + for (int y = 0; y < _overlayHeight; y += BITMAP_TEXTURE_SIZE) { + for (int x = 0; x < _overlayWidth; x += BITMAP_TEXTURE_SIZE) { + OpenGL::Texture *texture = _overlayTextures[curTexIdx]; + + Common::Rect textureArea = Common::Rect(texture->getWidth(), texture->getHeight()); + textureArea.translate(x, y); + + Math::Vector2d topLeft = Math::Vector2d(textureArea.left / (float)_overlayWidth, textureArea.top / (float)_overlayHeight); + Math::Vector2d bottomRight = Math::Vector2d(textureArea.right / (float)_overlayWidth, textureArea.bottom / (float)_overlayHeight); + + _surfaceRenderer->render(texture, Math::Rect2d(topLeft, bottomRight), true); + + curTexIdx++; + } + } + + _surfaceRenderer->restorePreviousState(); +} + +void OpenGLSdlGraphicsManager::drawSideTexturesOpenGL() { + if (_fullscreen && _lockAspectRatio) { + const Math::Vector2d nudge(1.0 / float(_overlayWidth), 0); + if (_sideTextures[0] != nullptr) { + float left = _gameRect.getBottomLeft().getX() - (float(_overlayHeight) / float(_sideTextures[0]->getHeight())) * _sideTextures[0]->getWidth() / float(_overlayWidth); + Math::Rect2d leftRect(Math::Vector2d(left, 0.0), _gameRect.getBottomLeft() + nudge); + _surfaceRenderer->render(_sideTextures[0], leftRect, true); + } + + if (_sideTextures[1] != nullptr) { + float right = _gameRect.getTopRight().getX() + (float(_overlayHeight) / float(_sideTextures[1]->getHeight())) * _sideTextures[1]->getWidth() / float(_overlayWidth); + Math::Rect2d rightRect(_gameRect.getTopRight() - nudge, Math::Vector2d(right, 1.0)); + _surfaceRenderer->render(_sideTextures[1], rightRect, true); + } + } +} + +#ifndef AMIGAOS +OpenGL::FrameBuffer *OpenGLSdlGraphicsManager::createFramebuffer(uint width, uint height) { +#if !defined(USE_GLES2) + if (_antialiasing && OpenGLContext.framebufferObjectMultisampleSupported) { + return new OpenGL::MultiSampleFrameBuffer(width, height, _antialiasing); + } else +#endif + { + return new OpenGL::FrameBuffer(width, height); + } +} +#endif // AMIGAOS + +void OpenGLSdlGraphicsManager::updateScreen() { + if (_frameBuffer) { + _frameBuffer->detach(); + glViewport(0, 0, _overlayWidth, _overlayHeight); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + _surfaceRenderer->prepareState(); + drawSideTexturesOpenGL(); + _surfaceRenderer->render(_frameBuffer, _gameRect); + _surfaceRenderer->restorePreviousState(); + } + + if (_overlayVisible) { + if (_overlayDirty) { + updateOverlayTextures(); + } + + drawOverlayOpenGL(); + } + +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_GL_SwapWindow(_window->getSDLWindow()); +#else + SDL_GL_SwapBuffers(); +#endif + + if (_frameBuffer) { + _frameBuffer->attach(); + } +} + +int16 OpenGLSdlGraphicsManager::getHeight() { + // ResidualVM specific + if (_frameBuffer) + return _frameBuffer->getHeight(); + else + return _overlayHeight; +} + +int16 OpenGLSdlGraphicsManager::getWidth() { + // ResidualVM specific + if (_frameBuffer) + return _frameBuffer->getWidth(); + else + return _overlayWidth; +} + +#pragma mark - +#pragma mark --- Overlays --- +#pragma mark - + +void OpenGLSdlGraphicsManager::clearOverlay() { + if (!_overlayscreen) + return; + + if (!_overlayVisible) + return; + + SDL_Surface *tmp = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth, _overlayHeight, + _overlayscreen->format->BytesPerPixel * 8, + _overlayscreen->format->Rmask, _overlayscreen->format->Gmask, + _overlayscreen->format->Bmask, _overlayscreen->format->Amask); + + SDL_LockSurface(tmp); + SDL_LockSurface(_overlayscreen); + + glReadPixels(0, 0, _overlayWidth, _overlayHeight, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tmp->pixels); + + // Flip pixels vertically + byte *src = (byte *)tmp->pixels; + byte *buf = (byte *)_overlayscreen->pixels + (_overlayHeight - 1) * _overlayscreen->pitch; + int h = _overlayHeight; + do { + memcpy(buf, src, _overlayWidth * _overlayscreen->format->BytesPerPixel); + src += tmp->pitch; + buf -= _overlayscreen->pitch; + } while (--h); + + SDL_UnlockSurface(_overlayscreen); + SDL_UnlockSurface(tmp); + + SDL_FreeSurface(tmp); + + _overlayDirty = true; +} + +void OpenGLSdlGraphicsManager::setSideTextures(Graphics::Surface *left, Graphics::Surface *right) { + delete _sideTextures[0]; + _sideTextures[0] = nullptr; + delete _sideTextures[1]; + _sideTextures[1] = nullptr; + if (left) { + _sideTextures[0] = new OpenGL::Texture(*left); + } + if (right) { + _sideTextures[1] = new OpenGL::Texture(*right); + } +} + +void OpenGLSdlGraphicsManager::grabOverlay(void *buf, int pitch) { + if (_overlayscreen == NULL) + return; + + if (SDL_LockSurface(_overlayscreen) == -1) + error("SDL_LockSurface failed: %s", SDL_GetError()); + + byte *src = (byte *)_overlayscreen->pixels; + byte *dst = (byte *)buf; + int h = _overlayHeight; + do { + memcpy(dst, src, _overlayWidth * _overlayscreen->format->BytesPerPixel); + src += _overlayscreen->pitch; + dst += pitch; + } while (--h); + + SDL_UnlockSurface(_overlayscreen); +} + +void OpenGLSdlGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { + if (_overlayscreen == NULL) + return; + + const byte *src = (const byte *)buf; + + // Clip the coordinates + if (x < 0) { + w += x; + src -= x * _overlayscreen->format->BytesPerPixel; + x = 0; + } + + if (y < 0) { + h += y; + src -= y * pitch; + y = 0; + } + + if (w > _overlayWidth - x) { + w = _overlayWidth - x; + } + + if (h > _overlayHeight - y) { + h = _overlayHeight - y; + } + + if (w <= 0 || h <= 0) + return; + + if (SDL_LockSurface(_overlayscreen) == -1) + error("SDL_LockSurface failed: %s", SDL_GetError()); + + byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * _overlayscreen->format->BytesPerPixel; + do { + memcpy(dst, src, w * _overlayscreen->format->BytesPerPixel); + dst += _overlayscreen->pitch; + src += pitch; + } while (--h); + + SDL_UnlockSurface(_overlayscreen); +} + +void OpenGLSdlGraphicsManager::closeOverlay() { + delete _sideTextures[0]; + delete _sideTextures[1]; + _sideTextures[0] = _sideTextures[1] = nullptr; + + if (_overlayscreen) { + SDL_FreeSurface(_overlayscreen); + _overlayscreen = nullptr; + } + + delete _surfaceRenderer; + _surfaceRenderer = nullptr; + + for (uint i = 0; i < _overlayTextures.size(); i++) { + delete _overlayTextures[i]; + } + _overlayTextures.clear(); + + delete _frameBuffer; + _frameBuffer = nullptr; + + OpenGL::Context::destroy(); + +#if SDL_VERSION_ATLEAST(2, 0, 0) + deinitializeRenderer(); +#endif +} + +void OpenGLSdlGraphicsManager::warpMouse(int x, int y) { + //ResidualVM specific + if (_frameBuffer) { + // Scale from game coordinates to screen coordinates + x = (x * _gameRect.getWidth() * _overlayWidth) / _frameBuffer->getWidth(); + y = (y * _gameRect.getHeight() * _overlayHeight) / _frameBuffer->getHeight(); + + x += _gameRect.getTopLeft().getX() * _overlayWidth; + y += _gameRect.getTopLeft().getY() * _overlayHeight; + } + + _window->warpMouseInWindow(x, y); +} + +void OpenGLSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) { + if (_overlayVisible || !_frameBuffer) + return; + + // Scale from screen coordinates to game coordinates + point.x -= _gameRect.getTopLeft().getX() * _overlayWidth; + point.y -= _gameRect.getTopLeft().getY() * _overlayHeight; + + point.x = (point.x * _frameBuffer->getWidth()) / (_gameRect.getWidth() * _overlayWidth); + point.y = (point.y * _frameBuffer->getHeight()) / (_gameRect.getHeight() * _overlayHeight); + + // Make sure we only supply valid coordinates. + point.x = CLIP(point.x, 0, _frameBuffer->getWidth() - 1); + point.y = CLIP(point.y, 0, _frameBuffer->getHeight() - 1); +} + +#if SDL_VERSION_ATLEAST(2, 0, 0) +void OpenGLSdlGraphicsManager::deinitializeRenderer() { + SDL_GL_DeleteContext(_glContext); + _glContext = nullptr; + + _window->destroyWindow(); +} +#endif // SDL_VERSION_ATLEAST(2, 0, 0) + +#endif diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h new file mode 100644 index 00000000000..e4a2e2092f7 --- /dev/null +++ b/backends/graphics/openglsdl/openglsdl-graphics.h @@ -0,0 +1,130 @@ +/* ResidualVM - A 3D game interpreter + * + * ResidualVM 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_GRAPHICS_H +#define BACKENDS_GRAPHICS_OPENGLSDL_GRAPHICS_H + +#include "graphics/opengl/system_headers.h" +#include "graphics/opengl/framebuffer.h" +#include "graphics/opengl/texture.h" +#include "graphics/opengl/surfacerenderer.h" + +#include "backends/graphics/graphics.h" +#include "backends/graphics/sdl/resvm-sdl-graphics.h" +#include "graphics/pixelformat.h" +#include "graphics/scaler.h" +#include "common/array.h" +#include "common/events.h" +#include "common/system.h" +#include "math/rect2d.h" + +#include "backends/events/sdl/sdl-events.h" + +#include "backends/platform/sdl/sdl-sys.h" + +/** + * SDL graphics manager + */ +class OpenGLSdlGraphicsManager : public ResVmSdlGraphicsManager { +public: + OpenGLSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window); + virtual ~OpenGLSdlGraphicsManager(); + + virtual bool hasFeature(OSystem::Feature f); + + virtual void setupScreen(uint gameWidth, uint gameHeight, bool fullscreen, bool accel3d); // ResidualVM specific method + virtual Graphics::PixelBuffer getScreenPixelBuffer(); // ResidualVM specific method + + virtual int16 getHeight(); + virtual int16 getWidth(); + + virtual void updateScreen(); + + virtual void clearOverlay(); + virtual void grabOverlay(void *buf, int pitch); + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); + + void closeOverlay(); // ResidualVM specific method + + /* Render the passed Surfaces besides the game texture. + * This is used for widescreen support in the Grim engine. + * Note: we must copy the Surfaces, as they are free()d after this call. + */ + virtual void setSideTextures(Graphics::Surface *left, Graphics::Surface *right); + + virtual void warpMouse(int x, int y); + + virtual void transformMouseCoordinates(Common::Point &point); + +protected: +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_GLContext _glContext; + void deinitializeRenderer(); + SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); +#endif + + // overlay + SDL_Surface *_overlayscreen; + + Math::Rect2d _gameRect; + + struct OpenGLPixelFormat { + uint bytesPerPixel; + uint redSize; + uint blueSize; + uint greenSize; + uint alphaSize; + int multisampleSamples; + + OpenGLPixelFormat(uint screenBytesPerPixel, uint red, uint blue, uint green, uint alpha, int samples); + }; + + /** + * Initialize an OpenGL window matching as closely as possible the required properties + * + * When unable to create a context with anti-aliasing this tries without. + * When unable to create a context with the desired pixel depth this tries lower values. + */ + bool createScreenOpenGL(uint effectiveWidth, uint effectiveHeight, GameRenderTarget gameRenderTarget); + + // Antialiasing + int _antialiasing; + + // Overlay + Common::Array _overlayTextures; + + OpenGL::Texture *_sideTextures[2]; + + void initializeOpenGLContext() const; + void updateOverlayTextures(); + void drawOverlayOpenGL(); + void drawSideTexturesOpenGL(); + + OpenGL::FrameBuffer *_frameBuffer; + OpenGL::FrameBuffer *createFramebuffer(uint width, uint height); + + OpenGL::SurfaceRenderer *_surfaceRenderer; + + bool detectFramebufferSupport(); +}; + +#endif diff --git a/backends/graphics/sdl/resvm-sdl-graphics.cpp b/backends/graphics/sdl/resvm-sdl-graphics.cpp new file mode 100644 index 00000000000..0fa23411863 --- /dev/null +++ b/backends/graphics/sdl/resvm-sdl-graphics.cpp @@ -0,0 +1,367 @@ +/* ResidualVM - A 3D game interpreter + * + * ResidualVM 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/sdl/resvm-sdl-graphics.h" + +#include "backends/platform/sdl/sdl-sys.h" +#include "backends/events/sdl/sdl-events.h" + +#include "common/config-manager.h" +#include "common/textconsole.h" + +static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { + {0, 0, 0} +}; + +ResVmSdlGraphicsManager::ResVmSdlGraphicsManager(SdlEventSource *source, SdlWindow *window) : + SdlGraphicsManager(source, window), + _fullscreen(false), + _lockAspectRatio(true), + _overlayVisible(false), + _overlayWidth(0), + _overlayHeight(0), + _overlayDirty(true), + _screenChangeCount(0), + _capabilities(capabilities) { + ConfMan.registerDefault("fullscreen_res", "desktop"); + ConfMan.registerDefault("aspect_ratio", true); + + detectDesktopResolution(); +} + +ResVmSdlGraphicsManager::~ResVmSdlGraphicsManager() { +} + +void ResVmSdlGraphicsManager::activateManager() { + SdlGraphicsManager::activateManager(); + + // Register the graphics manager as a event observer + g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false); +} + +void ResVmSdlGraphicsManager::deactivateManager() { + // Unregister the event observer + if (g_system->getEventManager()->getEventDispatcher()) { + g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); + } + + SdlGraphicsManager::deactivateManager(); +} + +ResVmSdlGraphicsManager::GameRenderTarget ResVmSdlGraphicsManager::selectGameRenderTarget(bool fullscreen, + bool accel3d, + bool engineSupportsArbitraryResolutions, + bool framebufferSupported, + bool lockAspectRatio) { + if (!fullscreen) { + return kScreen; + } + + if (!accel3d && lockAspectRatio) { + return kSubScreen; + } + + if (!engineSupportsArbitraryResolutions && framebufferSupported) { + return kFramebuffer; + } + + return kScreen; +} + +Math::Rect2d ResVmSdlGraphicsManager::computeGameRect(GameRenderTarget gameRenderTarget, uint gameWidth, uint gameHeight, + uint effectiveWidth, uint effectiveHeight) { + switch (gameRenderTarget) { + case kScreen: + // The game occupies the whole screen + return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1)); + case kSubScreen: + // The game is centered on the screen + return Math::Rect2d( + Math::Vector2d((effectiveWidth - gameWidth) / 2, (effectiveHeight - gameHeight) / 2), + Math::Vector2d((effectiveWidth + gameWidth) / 2, (effectiveHeight + gameHeight) / 2) + ); + case kFramebuffer: + if (_lockAspectRatio) { + // The game is scaled to fit the screen, keeping the same aspect ratio + float scale = MIN(effectiveHeight / float(gameHeight), effectiveWidth / float(gameWidth)); + float scaledW = scale * (gameWidth / float(effectiveWidth)); + float scaledH = scale * (gameHeight / float(effectiveHeight)); + return Math::Rect2d( + Math::Vector2d(0.5 - (0.5 * scaledW), 0.5 - (0.5 * scaledH)), + Math::Vector2d(0.5 + (0.5 * scaledW), 0.5 + (0.5 * scaledH)) + ); + } else { + // The game occupies the whole screen + return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1)); + } + default: + error("Unhandled game render target '%d'", gameRenderTarget); + } +} + +bool ResVmSdlGraphicsManager::canUsePreferredResolution(GameRenderTarget gameRenderTarget, + bool engineSupportsArbitraryResolutions) { + switch (gameRenderTarget) { + case kScreen: + // If the game supports arbitrary resolutions, use the preferred mode as the game mode + return engineSupportsArbitraryResolutions; + case kSubScreen: + case kFramebuffer: + return true; + default: + error("Unhandled game render target '%d'", gameRenderTarget); + } +} + +void ResVmSdlGraphicsManager::detectDesktopResolution() { +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_DisplayMode di; + if (SDL_GetCurrentDisplayMode(0, &di) != 0) { + warning("Error: %s", SDL_GetError()); + g_system->quit(); + } + _desktopW = di.w; + _desktopH = di.h; +#else + const SDL_VideoInfo *vi = SDL_GetVideoInfo(); + _desktopW = vi->current_w; + _desktopH = vi->current_h; +#endif +} + +Common::Rect ResVmSdlGraphicsManager::getPreferredFullscreenResolution() { + // Default to the desktop resolution ... + uint preferredWidth = _desktopW; + uint preferredHeight = _desktopH; + + // ... unless the user has set a resolution in the configuration file + const Common::String &fsres = ConfMan.get("fullscreen_res"); + if (fsres != "desktop") { + uint newW, newH; + int converted = sscanf(fsres.c_str(), "%ux%u", &newW, &newH); + if (converted == 2) { + preferredWidth = newW; + preferredHeight = newH; + } else { + warning("Could not parse 'fullscreen_res' option: expected WWWxHHH, got %s", fsres.c_str()); + } + } + + return Common::Rect(preferredWidth, preferredHeight); +} + +void ResVmSdlGraphicsManager::resetGraphicsScale() { + setGraphicsMode(0); +} + +void ResVmSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { + switch (f) { + case OSystem::kFeatureFullscreenMode: + _fullscreen = enable; + break; + case OSystem::kFeatureAspectRatioCorrection: + _lockAspectRatio = enable; + break; + default: + break; + } +} + +bool ResVmSdlGraphicsManager::getFeatureState(OSystem::Feature f) { + switch (f) { + case OSystem::kFeatureFullscreenMode: + return _fullscreen; + case OSystem::kFeatureAspectRatioCorrection: + return _lockAspectRatio; + default: + return false; + } +} + +const OSystem::GraphicsMode *ResVmSdlGraphicsManager::getSupportedGraphicsModes() const { + return s_supportedGraphicsModes; +} + +int ResVmSdlGraphicsManager::getDefaultGraphicsMode() const { + return 0;// ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::beginGFXTransaction() { + // ResidualVM: not use it +} + +OSystem::TransactionError ResVmSdlGraphicsManager::endGFXTransaction() { + // ResidualVM: not use it + return OSystem::kTransactionSuccess; +} + +#ifdef USE_RGB_COLOR +Common::List ResVmSdlGraphicsManager::getSupportedFormats() const { + // ResidualVM: not use it + return _supportedFormats; +} +#endif + +bool ResVmSdlGraphicsManager::setGraphicsMode(int mode) { + // ResidualVM: not use it + return true; +} + +int ResVmSdlGraphicsManager::getGraphicsMode() const { + // ResidualVM: not use it + return 0; +} + +void ResVmSdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *format) { + // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::launcherInitSize(uint w, uint h) { + closeOverlay(); + setupScreen(w, h, false, false); +} + +void ResVmSdlGraphicsManager::copyRectToScreen(const void *src, int pitch, int x, int y, int w, int h) { + // ResidualVM: not use it +} + +Graphics::Surface *ResVmSdlGraphicsManager::lockScreen() { + return NULL; // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::unlockScreen() { + // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::fillScreen(uint32 col) { + // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::setPalette(const byte *colors, uint start, uint num) { + // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::grabPalette(byte *colors, uint start, uint num) { + // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) { + // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::setShakePos(int shake_pos) { + // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::setFocusRectangle(const Common::Rect &rect) { + // ResidualVM: not use it +} + +void ResVmSdlGraphicsManager::clearFocusRectangle() { + // ResidualVM: not use it +} + +#pragma mark - +#pragma mark --- Overlays --- +#pragma mark - + +void ResVmSdlGraphicsManager::showOverlay() { + if (_overlayVisible) + return; + + _overlayVisible = true; + + clearOverlay(); +} + +void ResVmSdlGraphicsManager::hideOverlay() { + if (!_overlayVisible) + return; + + _overlayVisible = false; + + clearOverlay(); +} + +#pragma mark - +#pragma mark --- Mouse --- +#pragma mark - + +bool ResVmSdlGraphicsManager::showMouse(bool visible) { + SDL_ShowCursor(visible); + return true; +} + +// ResidualVM specific method +bool ResVmSdlGraphicsManager::lockMouse(bool lock) { +#if SDL_VERSION_ATLEAST(2, 0, 0) + if (lock) + SDL_SetRelativeMouseMode(SDL_TRUE); + else + SDL_SetRelativeMouseMode(SDL_FALSE); +#else + if (lock) + SDL_WM_GrabInput(SDL_GRAB_ON); + else + SDL_WM_GrabInput(SDL_GRAB_OFF); +#endif + return true; +} + +void ResVmSdlGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { + // ResidualVM: not use it +} + +#pragma mark - +#pragma mark --- On Screen Display --- +#pragma mark - + +#ifdef USE_OSD +void OpenGLResVmSdlGraphicsManager::displayMessageOnOSD(const char *msg) { + // ResidualVM: not use it +} +#endif + +bool ResVmSdlGraphicsManager::notifyEvent(const Common::Event &event) { + //ResidualVM specific: + switch ((int)event.type) { + case Common::EVENT_KEYDOWN: + break; + case Common::EVENT_KEYUP: + break; + default: + break; + } + + return false; +} + +void ResVmSdlGraphicsManager::notifyVideoExpose() { + //ResidualVM specific: + updateScreen(); +} + +void ResVmSdlGraphicsManager::notifyMousePos(Common::Point mouse) { + transformMouseCoordinates(mouse); + // ResidualVM: not use that: + //setMousePos(mouse.x, mouse.y); +} diff --git a/backends/graphics/sdl/resvm-sdl-graphics.h b/backends/graphics/sdl/resvm-sdl-graphics.h new file mode 100644 index 00000000000..0411b627698 --- /dev/null +++ b/backends/graphics/sdl/resvm-sdl-graphics.h @@ -0,0 +1,152 @@ +/* ResidualVM - A 3D game interpreter + * + * ResidualVM 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_SDL_RESVMSDLGRAPHICS_H +#define BACKENDS_GRAPHICS_SDL_RESVMSDLGRAPHICS_H + +#include "backends/graphics/sdl/sdl-graphics.h" + +#include "common/events.h" +#include "common/rect.h" + +#include "math/rect2d.h" + +class SdlEventSource; + +/** + * Base class for a SDL based graphics manager. + * + * It features a few extra a few extra features required by SdlEventSource. + */ +class ResVmSdlGraphicsManager : public SdlGraphicsManager, public Common::EventObserver { +public: + ResVmSdlGraphicsManager(SdlEventSource *source, SdlWindow *window); + virtual ~ResVmSdlGraphicsManager(); + + // SdlGraphicsManager API + virtual void activateManager() override; + virtual void deactivateManager() override; + virtual void notifyVideoExpose() override; + virtual void notifyMousePos(Common::Point mouse) override; + + virtual void setFeatureState(OSystem::Feature f, bool enable); + virtual bool getFeatureState(OSystem::Feature f); + + virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const; + virtual int getDefaultGraphicsMode() const; + virtual bool setGraphicsMode(int mode); + virtual int getGraphicsMode() const; + virtual void resetGraphicsScale(); +#ifdef USE_RGB_COLOR + virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; } + virtual Common::List getSupportedFormats() const; +#endif + virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL); + virtual void launcherInitSize(uint w, uint h); // ResidualVM specific method + virtual int getScreenChangeID() const { return _screenChangeCount; } + + virtual void beginGFXTransaction(); + virtual OSystem::TransactionError endGFXTransaction(); + +protected: + // PaletteManager API + virtual void setPalette(const byte *colors, uint start, uint num); + virtual void grabPalette(byte *colors, uint start, uint num); + +public: + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); + virtual Graphics::Surface *lockScreen(); + virtual void unlockScreen(); + virtual void fillScreen(uint32 col); + virtual void setShakePos(int shakeOffset); + virtual void setFocusRectangle(const Common::Rect& rect); + virtual void clearFocusRectangle(); + virtual void setCursorPalette(const byte *colors, uint start, uint num); + + //ResidualVM specific implementions: + virtual int16 getOverlayHeight() { return _overlayHeight; } + virtual int16 getOverlayWidth() { return _overlayWidth; } + virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; } + + virtual void showOverlay(); + virtual void hideOverlay(); + + virtual bool showMouse(bool visible); + virtual bool lockMouse(bool lock); // ResidualVM specific method + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); + +#ifdef USE_OSD + virtual void displayMessageOnOSD(const char *msg); +#endif + + // Override from Common::EventObserver + bool notifyEvent(const Common::Event &event) override; + +protected: + uint _desktopW, _desktopH; + + void detectDesktopResolution(); + + bool _fullscreen; + bool _lockAspectRatio; + + int _screenChangeCount; + + bool _overlayVisible; + Graphics::PixelFormat _overlayFormat; + int _overlayWidth, _overlayHeight; + bool _overlayDirty; + + virtual void closeOverlay() = 0; + +#ifdef USE_RGB_COLOR + Graphics::PixelFormat _screenFormat; + Common::List _supportedFormats; +#endif + + /** + * Places where the game can be drawn + */ + enum GameRenderTarget { + kScreen, /** The game is drawn directly on the screen */ + kSubScreen, /** The game is drawn to a surface, which is centered on the screen */ + kFramebuffer /** The game is drawn to a framebuffer, which is scaled to fit the screen */ + }; + + /** Select the best draw target according to the specified parameters */ + GameRenderTarget selectGameRenderTarget(bool fullscreen, bool accel3d, + bool engineSupportsArbitraryResolutions, + bool framebufferSupported, + bool lockAspectRatio); + + /** Compute the size and position of the game rectangle in the screen */ + Math::Rect2d computeGameRect(GameRenderTarget gameRenderTarget, uint gameWidth, uint gameHeight, + uint effectiveWidth, uint effectiveHeight); + + /** Checks if the render target supports drawing at arbitrary resolutions */ + bool canUsePreferredResolution(GameRenderTarget gameRenderTarget, bool engineSupportsArbitraryResolutions); + + /** Obtain the user configured fullscreen resolution, or default to the desktop resolution */ + Common::Rect getPreferredFullscreenResolution(); +}; + +#endif diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index f479a8ecbb6..24a7aa97ee1 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -44,185 +44,41 @@ #include "graphics/pixelbuffer.h" #include "gui/EventRecorder.h" -#ifdef USE_OPENGL -#include "graphics/opengl/context.h" -#endif - -static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { - {0, 0, 0} -}; - SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window) : - SdlGraphicsManager(sdlEventSource, window), + ResVmSdlGraphicsManager(sdlEventSource, window), #if SDL_VERSION_ATLEAST(2, 0, 0) _renderer(nullptr), _screenTexture(nullptr), - _glContext(nullptr), #endif _screen(0), _subScreen(0), - _overlayVisible(false), _overlayscreen(0), - _overlayWidth(0), _overlayHeight(0), - _overlayDirty(true), - _screenChangeCount(0), - _lockAspectRatio(true), _gameRect() -#ifdef USE_OPENGL - , _opengl(false) - , _frameBuffer(nullptr) - , _surfaceRenderer(nullptr) -#endif { - ConfMan.registerDefault("fullscreen_res", "desktop"); - ConfMan.registerDefault("aspect_ratio", true); - ConfMan.registerDefault("antialiasing", 0); - - detectDesktopResolution(); - _sideSurfaces[0] = _sideSurfaces[1] = nullptr; -#ifdef USE_OPENGL - _sideTextures[0] = _sideTextures[1] = nullptr; -#endif } SurfaceSdlGraphicsManager::~SurfaceSdlGraphicsManager() { closeOverlay(); } -void SurfaceSdlGraphicsManager::activateManager() { - SdlGraphicsManager::activateManager(); - - // Register the graphics manager as a event observer - g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false); -} - -void SurfaceSdlGraphicsManager::deactivateManager() { - // Unregister the event observer - if (g_system->getEventManager()->getEventDispatcher()) { - g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this); - } - - SdlGraphicsManager::deactivateManager(); -} - -void SurfaceSdlGraphicsManager::resetGraphicsScale() { - setGraphicsMode(0); -} - bool SurfaceSdlGraphicsManager::hasFeature(OSystem::Feature f) { return - (f == OSystem::kFeatureFullscreenMode) || -#ifdef USE_OPENGL - (f == OSystem::kFeatureOpenGL) || - (f == OSystem::kFeatureAspectRatioCorrection); -#else - false; -#endif -} - -void SurfaceSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { - switch (f) { - case OSystem::kFeatureFullscreenMode: - _fullscreen = enable; - break; - case OSystem::kFeatureAspectRatioCorrection: - _lockAspectRatio = enable; - break; - default: - break; - } -} - -bool SurfaceSdlGraphicsManager::getFeatureState(OSystem::Feature f) { - switch (f) { - case OSystem::kFeatureFullscreenMode: - return _fullscreen; - case OSystem::kFeatureAspectRatioCorrection: - return _lockAspectRatio; - default: - return false; - } -} - -const OSystem::GraphicsMode *SurfaceSdlGraphicsManager::getSupportedGraphicsModes() const { - return s_supportedGraphicsModes; -} - -int SurfaceSdlGraphicsManager::getDefaultGraphicsMode() const { - return 0;// ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::beginGFXTransaction() { - // ResidualVM: not use it -} - -OSystem::TransactionError SurfaceSdlGraphicsManager::endGFXTransaction() { - // ResidualVM: not use it - return OSystem::kTransactionSuccess; -} - -#ifdef USE_RGB_COLOR -Common::List SurfaceSdlGraphicsManager::getSupportedFormats() const { - // ResidualVM: not use it - return _supportedFormats; -} -#endif - -bool SurfaceSdlGraphicsManager::setGraphicsMode(int mode) { - // ResidualVM: not use it - return true; -} - -int SurfaceSdlGraphicsManager::getGraphicsMode() const { - // ResidualVM: not use it - return 0; -} - -void SurfaceSdlGraphicsManager::initSize(uint w, uint h, const Graphics::PixelFormat *format) { - // ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::launcherInitSize(uint w, uint h) { - closeOverlay(); - setupScreen(w, h, false, false); -} - -void SurfaceSdlGraphicsManager::detectDesktopResolution() { -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_DisplayMode di; - if (SDL_GetCurrentDisplayMode(0, &di) != 0) { - warning("Error: %s", SDL_GetError()); - g_system->quit(); - } - _desktopW = di.w; - _desktopH = di.h; -#else - const SDL_VideoInfo *vi = SDL_GetVideoInfo(); - _desktopW = vi->current_w; - _desktopH = vi->current_h; -#endif + (f == OSystem::kFeatureFullscreenMode); } void SurfaceSdlGraphicsManager::setupScreen(uint gameWidth, uint gameHeight, bool fullscreen, bool accel3d) { + assert(!accel3d); closeOverlay(); -#ifdef USE_OPENGL - _opengl = accel3d; - _antialiasing = ConfMan.getInt("antialiasing"); -#endif _fullscreen = fullscreen; _lockAspectRatio = ConfMan.getBool("aspect_ratio"); bool engineSupportsArbitraryResolutions = g_engine && g_engine->hasFeature(Engine::kSupportsArbitraryResolutions); - // Detecting if OpenGL framebuffers are available relies on spawning an offscreen window - // thus it is only done when framebuffers may be used. - bool framebufferSupported = accel3d && fullscreen && detectFramebufferSupport(); - // Select how the game screen is going to be drawn - GameRenderTarget gameRenderTarget = selectGameRenderTarget(_fullscreen, accel3d, engineSupportsArbitraryResolutions, - framebufferSupported, _lockAspectRatio); + GameRenderTarget gameRenderTarget = selectGameRenderTarget(_fullscreen, false, engineSupportsArbitraryResolutions, + false, _lockAspectRatio); // Choose the effective window size or fullscreen mode uint effectiveWidth; @@ -239,96 +95,23 @@ void SurfaceSdlGraphicsManager::setupScreen(uint gameWidth, uint gameHeight, boo // Compute the rectangle where to draw the game inside the effective screen _gameRect = computeGameRect(gameRenderTarget, gameWidth, gameHeight, effectiveWidth, effectiveHeight); -#ifdef USE_OPENGL - if (_opengl) { - if (!createScreenOpenGL(effectiveWidth, effectiveHeight, gameRenderTarget)) { - warning("Error: %s", SDL_GetError()); - g_system->quit(); - } - int glflag; - const GLubyte *str; + uint32 sdlflags = SDL_SWSURFACE; + if (_fullscreen) + sdlflags |= SDL_FULLSCREEN; - // apply atribute again for sure based on SDL docs - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - - str = glGetString(GL_VENDOR); - debug("INFO: OpenGL Vendor: %s", str); - str = glGetString(GL_RENDERER); - debug("INFO: OpenGL Renderer: %s", str); - str = glGetString(GL_VERSION); - debug("INFO: OpenGL Version: %s", str); - SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &glflag); - debug("INFO: OpenGL Red bits: %d", glflag); - SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &glflag); - debug("INFO: OpenGL Green bits: %d", glflag); - SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &glflag); - debug("INFO: OpenGL Blue bits: %d", glflag); - SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &glflag); - debug("INFO: OpenGL Alpha bits: %d", glflag); - SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &glflag); - debug("INFO: OpenGL Z buffer depth bits: %d", glflag); - SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &glflag); - debug("INFO: OpenGL Double Buffer: %d", glflag); - SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &glflag); - debug("INFO: OpenGL Stencil buffer bits: %d", glflag); - -#ifdef USE_GLEW - debug("INFO: GLEW Version: %s", glewGetString(GLEW_VERSION)); - GLenum err = glewInit(); - if (err != GLEW_OK) { - warning("Error: %s", glewGetErrorString(err)); - g_system->quit(); - } -#endif - -#ifdef USE_OPENGL_SHADERS - debug("INFO: GLSL version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); -#endif - - initializeOpenGLContext(); - _surfaceRenderer = OpenGL::createBestSurfaceRenderer(); - } else -#endif - { - uint32 sdlflags = SDL_SWSURFACE; - if (_fullscreen) - sdlflags |= SDL_FULLSCREEN; - - _screen = SDL_SetVideoMode(effectiveWidth, effectiveHeight, 16, sdlflags); - if (!_screen) { - warning("Error: %s", SDL_GetError()); - g_system->quit(); - } + _screen = SDL_SetVideoMode(effectiveWidth, effectiveHeight, 16, sdlflags); + if (!_screen) { + warning("Error: %s", SDL_GetError()); + g_system->quit(); } -#ifdef USE_OPENGL - if (_opengl) { - uint32 rmask, gmask, bmask, amask; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - rmask = 0x00001f00; - gmask = 0x000007e0; - bmask = 0x000000f8; - amask = 0x00000000; -#else - rmask = 0x0000f800; - gmask = 0x000007e0; - bmask = 0x0000001f; - amask = 0x00000000; -#endif - _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, effectiveWidth, effectiveHeight, 16, - rmask, gmask, bmask, amask); - _overlayFormat = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); - } else -#endif - { - SDL_PixelFormat *f = _screen->format; - _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, effectiveWidth, effectiveHeight, f->BitsPerPixel, - f->Rmask, f->Gmask, f->Bmask, f->Amask); + SDL_PixelFormat *f = _screen->format; + _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, effectiveWidth, effectiveHeight, f->BitsPerPixel, + f->Rmask, f->Gmask, f->Bmask, f->Amask); - _overlayFormat = Graphics::PixelFormat(f->BytesPerPixel, 8 - f->Rloss, 8 - f->Gloss, 8 - f->Bloss, 0, - f->Rshift, f->Gshift, f->Bshift, f->Ashift); - } + _overlayFormat = Graphics::PixelFormat(f->BytesPerPixel, 8 - f->Rloss, 8 - f->Gloss, 8 - f->Bloss, 0, + f->Rshift, f->Gshift, f->Bshift, f->Ashift); if (!_overlayscreen) { warning("Error: %s", SDL_GetError()); @@ -341,141 +124,12 @@ void SurfaceSdlGraphicsManager::setupScreen(uint gameWidth, uint gameHeight, boo _screenChangeCount++; -#if defined(USE_OPENGL) && !defined(AMIGAOS) - if (gameRenderTarget == kFramebuffer) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - _frameBuffer = createFramebuffer(gameWidth, gameHeight); - _frameBuffer->attach(); - } -#endif if (gameRenderTarget == kSubScreen) { - SDL_PixelFormat *f = _screen->format; _subScreen = SDL_CreateRGBSurface(SDL_SWSURFACE, gameWidth, gameHeight, f->BitsPerPixel, f->Rmask, f->Gmask, f->Bmask, f->Amask); } } -SurfaceSdlGraphicsManager::GameRenderTarget SurfaceSdlGraphicsManager::selectGameRenderTarget(bool fullscreen, - bool accel3d, - bool engineSupportsArbitraryResolutions, - bool framebufferSupported, - bool lockAspectRatio) { - if (!fullscreen) { - return kScreen; - } - - if (!accel3d && lockAspectRatio) { - return kSubScreen; - } - - if (!engineSupportsArbitraryResolutions && framebufferSupported) { - return kFramebuffer; - } - - return kScreen; -} - -Math::Rect2d SurfaceSdlGraphicsManager::computeGameRect(GameRenderTarget gameRenderTarget, uint gameWidth, uint gameHeight, - uint effectiveWidth, uint effectiveHeight) { - switch (gameRenderTarget) { - case kScreen: - // The game occupies the whole screen - return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1)); - case kSubScreen: - // The game is centered on the screen - return Math::Rect2d( - Math::Vector2d((effectiveWidth - gameWidth) / 2, (effectiveHeight - gameHeight) / 2), - Math::Vector2d((effectiveWidth + gameWidth) / 2, (effectiveHeight + gameHeight) / 2) - ); - case kFramebuffer: - if (_lockAspectRatio) { - // The game is scaled to fit the screen, keeping the same aspect ratio - float scale = MIN(effectiveHeight / float(gameHeight), effectiveWidth / float(gameWidth)); - float scaledW = scale * (gameWidth / float(effectiveWidth)); - float scaledH = scale * (gameHeight / float(effectiveHeight)); - return Math::Rect2d( - Math::Vector2d(0.5 - (0.5 * scaledW), 0.5 - (0.5 * scaledH)), - Math::Vector2d(0.5 + (0.5 * scaledW), 0.5 + (0.5 * scaledH)) - ); - } else { - // The game occupies the whole screen - return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1)); - } - default: - error("Unhandled game render target '%d'", gameRenderTarget); - } -} - -bool SurfaceSdlGraphicsManager::detectFramebufferSupport() { - bool framebufferSupported = false; -#if defined(USE_GLES2) - // Framebuffers are always available with GLES2 - framebufferSupported = true; -#elif defined(USE_OPENGL) && !defined(AMIGAOS) - // Spawn a 32x32 window off-screen with a GL context to test if framebuffers are supported -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_Window *window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 32, 32, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN); - if (window) { - SDL_GLContext glContext = SDL_GL_CreateContext(window); - if (glContext) { - initializeOpenGLContext(); - framebufferSupported = OpenGLContext.framebufferObjectSupported; - SDL_GL_DeleteContext(glContext); - } - SDL_DestroyWindow(window); - } -#else - SDL_putenv(const_cast("SDL_VIDEO_WINDOW_POS=9000,9000")); - SDL_SetVideoMode(32, 32, 0, SDL_OPENGL); - SDL_putenv(const_cast("SDL_VIDEO_WINDOW_POS=center")); - initializeOpenGLContext(); - framebufferSupported = OpenGLContext.framebufferObjectSupported; -#endif -#endif - return framebufferSupported; -} - -bool SurfaceSdlGraphicsManager::canUsePreferredResolution(GameRenderTarget gameRenderTarget, - bool engineSupportsArbitraryResolutions) { - switch (gameRenderTarget) { - case kScreen: - // If the game supports arbitrary resolutions, use the preferred mode as the game mode - return engineSupportsArbitraryResolutions; - case kSubScreen: - case kFramebuffer: - return true; - default: - error("Unhandled game render target '%d'", gameRenderTarget); - } -} - -Common::Rect SurfaceSdlGraphicsManager::getPreferredFullscreenResolution() { - // Default to the desktop resolution ... - uint preferredWidth = _desktopW; - uint preferredHeight = _desktopH; - - // ... unless the user has set a resolution in the configuration file - const Common::String &fsres = ConfMan.get("fullscreen_res"); - if (fsres != "desktop") { - uint newW, newH; - int converted = sscanf(fsres.c_str(), "%ux%u", &newW, &newH); - if (converted == 2) { - preferredWidth = newW; - preferredHeight = newH; - } else { - warning("Could not parse 'fullscreen_res' option: expected WWWxHHH, got %s", fsres.c_str()); - } - } - - return Common::Rect(preferredWidth, preferredHeight); -} - Graphics::PixelBuffer SurfaceSdlGraphicsManager::getScreenPixelBuffer() { -#ifdef USE_OPENGL - if (_opengl) { - error("Direct screen buffer access is not allowed when using OpenGL"); - } -#endif - if (_subScreen) { return Graphics::PixelBuffer(_screenFormat, (byte *)_subScreen->pixels); } @@ -483,204 +137,6 @@ Graphics::PixelBuffer SurfaceSdlGraphicsManager::getScreenPixelBuffer() { return Graphics::PixelBuffer(_screenFormat, (byte *)_screen->pixels); } -#ifdef USE_OPENGL - -void SurfaceSdlGraphicsManager::initializeOpenGLContext() const { - OpenGL::ContextType type; - -#ifdef USE_GLES2 - type = OpenGL::kContextGLES2; -#else - type = OpenGL::kContextGL; -#endif - - OpenGLContext.initialize(type); -} - -SurfaceSdlGraphicsManager::OpenGLPixelFormat::OpenGLPixelFormat(uint screenBytesPerPixel, uint red, uint blue, uint green, uint alpha, int samples) : - bytesPerPixel(screenBytesPerPixel), - redSize(red), - blueSize(blue), - greenSize(green), - alphaSize(alpha), - multisampleSamples(samples) { - -} - -bool SurfaceSdlGraphicsManager::createScreenOpenGL(uint effectiveWidth, uint effectiveHeight, GameRenderTarget gameRenderTarget) { - // Build a list of OpenGL pixel formats usable by ResidualVM - Common::Array pixelFormats; - if (_antialiasing > 0 && gameRenderTarget == kScreen) { - // Don't enable screen level multisampling when rendering to a framebuffer - pixelFormats.push_back(OpenGLPixelFormat(32, 8, 8, 8, 8, _antialiasing)); - pixelFormats.push_back(OpenGLPixelFormat(16, 5, 5, 5, 1, _antialiasing)); - pixelFormats.push_back(OpenGLPixelFormat(16, 5, 6, 5, 0, _antialiasing)); - } - pixelFormats.push_back(OpenGLPixelFormat(32, 8, 8, 8, 8, 0)); - pixelFormats.push_back(OpenGLPixelFormat(16, 5, 5, 5, 1, 0)); - pixelFormats.push_back(OpenGLPixelFormat(16, 5, 6, 5, 0, 0)); - - // Unfortunatly, SDL does not provide a list of valid pixel formats - // for the current OpenGL implementation and hardware. - // SDL may not be able to create a screen with the preferred pixel format. - // Try all the pixel formats in the list until SDL returns a valid screen. - Common::Array::const_iterator it = pixelFormats.begin(); - for (; it != pixelFormats.end(); it++) { - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, it->redSize); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, it->greenSize); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, it->blueSize); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, it->alphaSize); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, it->multisampleSamples > 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, it->multisampleSamples); -#if SDL_VERSION_ATLEAST(2, 0, 0) -#ifdef USE_GLES2 - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); -#else - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); -#endif -#endif - -#if SDL_VERSION_ATLEAST(2, 0, 0) - uint32 sdlflags = SDL_WINDOW_OPENGL; - if (_fullscreen) - sdlflags |= SDL_WINDOW_FULLSCREEN; - - if (_window->createWindow(effectiveWidth, effectiveHeight, sdlflags)) { - _glContext = SDL_GL_CreateContext(_window->getSDLWindow()); - if (_glContext) { - break; - } - } - - _window->destroyWindow(); -#else - uint32 sdlflags = SDL_OPENGL; - if (_fullscreen) - sdlflags |= SDL_FULLSCREEN; - - SDL_Surface *screen = SDL_SetVideoMode(effectiveWidth, effectiveHeight, it->bytesPerPixel, sdlflags); - if (screen) { - break; - } -#endif - } - - // Display a warning if the effective pixel format is not the preferred one - if (it != pixelFormats.begin() && it != pixelFormats.end()) { - bool wantsAA = pixelFormats.front().multisampleSamples > 0; - bool gotAA = it->multisampleSamples > 0; - - warning("Couldn't create a %d-bit visual%s, using to %d-bit%s instead", - pixelFormats.front().bytesPerPixel, - wantsAA && !gotAA ? " with AA" : "", - it->bytesPerPixel, - wantsAA && !gotAA ? " without AA" : ""); - } - - return it != pixelFormats.end(); -} - -#define BITMAP_TEXTURE_SIZE 256 - -void SurfaceSdlGraphicsManager::updateOverlayTextures() { - if (!_overlayscreen) - return; - - // remove if already exist - for (uint i = 0; i < _overlayTextures.size(); i++) { - delete _overlayTextures[i]; - } - _overlayTextures.clear(); - - Graphics::Surface overlaySurface; - overlaySurface.w = _overlayscreen->w; - overlaySurface.h = _overlayscreen->h; - overlaySurface.pitch = _overlayscreen->pitch; - overlaySurface.format = getOverlayFormat(); - overlaySurface.setPixels(_overlayscreen->pixels); - - for (int y = 0; y < _overlayHeight; y += BITMAP_TEXTURE_SIZE) { - for (int x = 0; x < _overlayWidth; x += BITMAP_TEXTURE_SIZE) { - int t_width = (x + BITMAP_TEXTURE_SIZE >= _overlayWidth) ? (_overlayWidth - x) : BITMAP_TEXTURE_SIZE; - int t_height = (y + BITMAP_TEXTURE_SIZE >= _overlayHeight) ? (_overlayHeight - y) : BITMAP_TEXTURE_SIZE; - - Common::Rect textureArea = Common::Rect(t_width, t_height); - textureArea.translate(x, y); - - const Graphics::Surface subSurface = overlaySurface.getSubArea(textureArea); - _overlayTextures.push_back(new OpenGL::Texture(subSurface)); - } - } -} - -void SurfaceSdlGraphicsManager::drawOverlayOpenGL() { - if (!_overlayscreen) - return; - - glViewport(0, 0, _overlayWidth, _overlayHeight); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - _surfaceRenderer->prepareState(); - - int curTexIdx = 0; - for (int y = 0; y < _overlayHeight; y += BITMAP_TEXTURE_SIZE) { - for (int x = 0; x < _overlayWidth; x += BITMAP_TEXTURE_SIZE) { - OpenGL::Texture *texture = _overlayTextures[curTexIdx]; - - Common::Rect textureArea = Common::Rect(texture->getWidth(), texture->getHeight()); - textureArea.translate(x, y); - - Math::Vector2d topLeft = Math::Vector2d(textureArea.left / (float)_overlayWidth, textureArea.top / (float)_overlayHeight); - Math::Vector2d bottomRight = Math::Vector2d(textureArea.right / (float)_overlayWidth, textureArea.bottom / (float)_overlayHeight); - - _surfaceRenderer->render(texture, Math::Rect2d(topLeft, bottomRight), true); - - curTexIdx++; - } - } - - _surfaceRenderer->restorePreviousState(); -} - -void SurfaceSdlGraphicsManager::drawSideTexturesOpenGL() { - if (_fullscreen && _lockAspectRatio) { - const Math::Vector2d nudge(1.0 / float(_overlayWidth), 0); - if (_sideTextures[0] != nullptr) { - float left = _gameRect.getBottomLeft().getX() - (float(_overlayHeight) / float(_sideTextures[0]->getHeight())) * _sideTextures[0]->getWidth() / float(_overlayWidth); - Math::Rect2d leftRect(Math::Vector2d(left, 0.0), _gameRect.getBottomLeft() + nudge); - _surfaceRenderer->render(_sideTextures[0], leftRect, true); - } - - if (_sideTextures[1] != nullptr) { - float right = _gameRect.getTopRight().getX() + (float(_overlayHeight) / float(_sideTextures[1]->getHeight())) * _sideTextures[1]->getWidth() / float(_overlayWidth); - Math::Rect2d rightRect(_gameRect.getTopRight() - nudge, Math::Vector2d(right, 1.0)); - _surfaceRenderer->render(_sideTextures[1], rightRect, true); - } - } -} - -#ifndef AMIGAOS -OpenGL::FrameBuffer *SurfaceSdlGraphicsManager::createFramebuffer(uint width, uint height) { -#if !defined(USE_GLES2) - if (_antialiasing && OpenGLContext.framebufferObjectMultisampleSupported) { - return new OpenGL::MultiSampleFrameBuffer(width, height, _antialiasing); - } else -#endif - { - return new OpenGL::FrameBuffer(width, height); - } -} -#endif // AMIGAOS - -#endif - void SurfaceSdlGraphicsManager::drawSideTextures() { if (_fullscreen && _lockAspectRatio) { if (_sideSurfaces[0]) { @@ -723,86 +179,32 @@ void SurfaceSdlGraphicsManager::drawOverlay() { } void SurfaceSdlGraphicsManager::updateScreen() { -#ifdef USE_OPENGL - if (_opengl) { - if (_frameBuffer) { - _frameBuffer->detach(); - glViewport(0, 0, _overlayWidth, _overlayHeight); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - _surfaceRenderer->prepareState(); - drawSideTexturesOpenGL(); - _surfaceRenderer->render(_frameBuffer, _gameRect); - _surfaceRenderer->restorePreviousState(); - } - - if (_overlayVisible) { - if (_overlayDirty) { - updateOverlayTextures(); - } - - drawOverlayOpenGL(); - } - -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_GL_SwapWindow(_window->getSDLWindow()); -#else - SDL_GL_SwapBuffers(); -#endif - - if (_frameBuffer) { - _frameBuffer->attach(); - } - } else -#endif - { - if (_subScreen) { - SDL_Rect dstrect; - dstrect.x = _gameRect.getTopLeft().getX(); - dstrect.y = _gameRect.getTopLeft().getY(); - dstrect.w = _gameRect.getWidth(); - dstrect.h = _gameRect.getHeight(); - SDL_BlitSurface(_subScreen, NULL, _screen, &dstrect); - } - if (_overlayVisible) { - drawOverlay(); - } - drawSideTextures(); - -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_UpdateTexture(_screenTexture, nullptr, _screen->pixels, _screen->pitch); - - SDL_RenderClear(_renderer); - SDL_RenderCopy(_renderer, _screenTexture, nullptr, nullptr); - SDL_RenderPresent(_renderer); -#else - SDL_Flip(_screen); -#endif + if (_subScreen) { + SDL_Rect dstrect; + dstrect.x = _gameRect.getTopLeft().getX(); + dstrect.y = _gameRect.getTopLeft().getY(); + dstrect.w = _gameRect.getWidth(); + dstrect.h = _gameRect.getHeight(); + SDL_BlitSurface(_subScreen, NULL, _screen, &dstrect); } -} + if (_overlayVisible) { + drawOverlay(); + } + drawSideTextures(); -void SurfaceSdlGraphicsManager::copyRectToScreen(const void *src, int pitch, int x, int y, int w, int h) { - // ResidualVM: not use it -} +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_UpdateTexture(_screenTexture, nullptr, _screen->pixels, _screen->pitch); -Graphics::Surface *SurfaceSdlGraphicsManager::lockScreen() { - return NULL; // ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::unlockScreen() { - // ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::fillScreen(uint32 col) { - // ResidualVM: not use it + SDL_RenderClear(_renderer); + SDL_RenderCopy(_renderer, _screenTexture, nullptr, nullptr); + SDL_RenderPresent(_renderer); +#else + SDL_Flip(_screen); +#endif } int16 SurfaceSdlGraphicsManager::getHeight() { // ResidualVM specific -#ifdef USE_OPENGL - if (_frameBuffer) - return _frameBuffer->getHeight(); - else -#endif if (_subScreen) return _subScreen->h; else @@ -811,63 +213,16 @@ int16 SurfaceSdlGraphicsManager::getHeight() { int16 SurfaceSdlGraphicsManager::getWidth() { // ResidualVM specific -#ifdef USE_OPENGL - if (_frameBuffer) - return _frameBuffer->getWidth(); - else -#endif if (_subScreen) return _subScreen->w; else return _overlayWidth; } -void SurfaceSdlGraphicsManager::setPalette(const byte *colors, uint start, uint num) { - // ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::grabPalette(byte *colors, uint start, uint num) { - // ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) { - // ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::setShakePos(int shake_pos) { - // ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::setFocusRectangle(const Common::Rect &rect) { - // ResidualVM: not use it -} - -void SurfaceSdlGraphicsManager::clearFocusRectangle() { - // ResidualVM: not use it -} - #pragma mark - #pragma mark --- Overlays --- #pragma mark - -void SurfaceSdlGraphicsManager::showOverlay() { - if (_overlayVisible) - return; - - _overlayVisible = true; - - clearOverlay(); -} - -void SurfaceSdlGraphicsManager::hideOverlay() { - if (!_overlayVisible) - return; - - _overlayVisible = false; - - clearOverlay(); -} - void SurfaceSdlGraphicsManager::clearOverlay() { if (!_overlayscreen) return; @@ -875,81 +230,36 @@ void SurfaceSdlGraphicsManager::clearOverlay() { if (!_overlayVisible) return; -#ifdef USE_OPENGL - if (_opengl) { - SDL_Surface *tmp = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth, _overlayHeight, - _overlayscreen->format->BytesPerPixel * 8, - _overlayscreen->format->Rmask, _overlayscreen->format->Gmask, - _overlayscreen->format->Bmask, _overlayscreen->format->Amask); + SDL_LockSurface(_screen); + SDL_LockSurface(_overlayscreen); + Graphics::PixelBuffer srcBuf(_screenFormat, (byte *)_screen->pixels); + Graphics::PixelBuffer dstBuf(_overlayFormat, (byte *)_overlayscreen->pixels); + int h = _overlayHeight; - SDL_LockSurface(tmp); - SDL_LockSurface(_overlayscreen); + do { + dstBuf.copyBuffer(0, _overlayWidth, srcBuf); - glReadPixels(0, 0, _overlayWidth, _overlayHeight, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, tmp->pixels); + srcBuf.shiftBy(_overlayWidth); + dstBuf.shiftBy(_overlayWidth); + } while (--h); + SDL_UnlockSurface(_screen); + SDL_UnlockSurface(_overlayscreen); - // Flip pixels vertically - byte *src = (byte *)tmp->pixels; - byte *buf = (byte *)_overlayscreen->pixels + (_overlayHeight - 1) * _overlayscreen->pitch; - int h = _overlayHeight; - do { - memcpy(buf, src, _overlayWidth * _overlayscreen->format->BytesPerPixel); - src += tmp->pitch; - buf -= _overlayscreen->pitch; - } while (--h); - - SDL_UnlockSurface(_overlayscreen); - SDL_UnlockSurface(tmp); - - SDL_FreeSurface(tmp); - } else -#endif - { - SDL_LockSurface(_screen); - SDL_LockSurface(_overlayscreen); - Graphics::PixelBuffer srcBuf(_screenFormat, (byte *)_screen->pixels); - Graphics::PixelBuffer dstBuf(_overlayFormat, (byte *)_overlayscreen->pixels); - int h = _overlayHeight; - - do { - dstBuf.copyBuffer(0, _overlayWidth, srcBuf); - - srcBuf.shiftBy(_overlayWidth); - dstBuf.shiftBy(_overlayWidth); - } while (--h); - SDL_UnlockSurface(_screen); - SDL_UnlockSurface(_overlayscreen); - } _overlayDirty = true; } void SurfaceSdlGraphicsManager::setSideTextures(Graphics::Surface *left, Graphics::Surface *right) { -#ifdef USE_OPENGL - if (_opengl) { - delete _sideTextures[0]; - _sideTextures[0] = nullptr; - delete _sideTextures[1]; - _sideTextures[1] = nullptr; - if (left) { - _sideTextures[0] = new OpenGL::Texture(*left); - } - if (right) { - _sideTextures[1] = new OpenGL::Texture(*right); - } - } else -#endif - { - delete _sideSurfaces[0]; - _sideSurfaces[0] = nullptr; - delete _sideSurfaces[1]; - _sideSurfaces[1] = nullptr; - if (left) { - _sideSurfaces[0] = SDL_CreateRGBSurface(SDL_SWSURFACE, left->w, left->h, 32, 0xff << left->format.rShift, 0xff << left->format.gShift, 0xff << left->format.bShift, 0xff << left->format.aShift); - memcpy(_sideSurfaces[0]->pixels, left->getPixels(), left->w * left->h * 4); - } - if (right) { - _sideSurfaces[1] = SDL_CreateRGBSurface(SDL_SWSURFACE, right->w, right->h, 32, 0xff << right->format.rShift, 0xff << right->format.gShift, 0xff << right->format.bShift, 0xff << right->format.aShift); - memcpy(_sideSurfaces[1]->pixels, right->getPixels(), right->w * right->h * 4); - } + delete _sideSurfaces[0]; + _sideSurfaces[0] = nullptr; + delete _sideSurfaces[1]; + _sideSurfaces[1] = nullptr; + if (left) { + _sideSurfaces[0] = SDL_CreateRGBSurface(SDL_SWSURFACE, left->w, left->h, 32, 0xff << left->format.rShift, 0xff << left->format.gShift, 0xff << left->format.bShift, 0xff << left->format.aShift); + memcpy(_sideSurfaces[0]->pixels, left->getPixels(), left->w * left->h * 4); + } + if (right) { + _sideSurfaces[1] = SDL_CreateRGBSurface(SDL_SWSURFACE, right->w, right->h, 32, 0xff << right->format.rShift, 0xff << right->format.gShift, 0xff << right->format.bShift, 0xff << right->format.aShift); + memcpy(_sideSurfaces[1]->pixels, right->getPixels(), right->w * right->h * 4); } } @@ -1019,11 +329,6 @@ void SurfaceSdlGraphicsManager::closeOverlay() { SDL_FreeSurface(_sideSurfaces[0]); SDL_FreeSurface(_sideSurfaces[1]); _sideSurfaces[0] = _sideSurfaces[1] = nullptr; -#ifdef USE_OPENGL - delete _sideTextures[0]; - delete _sideTextures[1]; - _sideTextures[0] = _sideTextures[1] = nullptr; -#endif if (_overlayscreen) { SDL_FreeSurface(_overlayscreen); _overlayscreen = nullptr; @@ -1039,63 +344,13 @@ void SurfaceSdlGraphicsManager::closeOverlay() { _screen = nullptr; } -#ifdef USE_OPENGL - delete _surfaceRenderer; - _surfaceRenderer = nullptr; - - for (uint i = 0; i < _overlayTextures.size(); i++) { - delete _overlayTextures[i]; - } - _overlayTextures.clear(); - - delete _frameBuffer; - _frameBuffer = nullptr; - - OpenGL::Context::destroy(); -#endif - #if SDL_VERSION_ATLEAST(2, 0, 0) deinitializeRenderer(); #endif } -#pragma mark - -#pragma mark --- Mouse --- -#pragma mark - - -bool SurfaceSdlGraphicsManager::showMouse(bool visible) { - SDL_ShowCursor(visible); - return true; -} - -// ResidualVM specific method -bool SurfaceSdlGraphicsManager::lockMouse(bool lock) { -#if SDL_VERSION_ATLEAST(2, 0, 0) - if (lock) - SDL_SetRelativeMouseMode(SDL_TRUE); - else - SDL_SetRelativeMouseMode(SDL_FALSE); -#else - if (lock) - SDL_WM_GrabInput(SDL_GRAB_ON); - else - SDL_WM_GrabInput(SDL_GRAB_OFF); -#endif - return true; -} - void SurfaceSdlGraphicsManager::warpMouse(int x, int y) { //ResidualVM specific -#ifdef USE_OPENGL - if (_frameBuffer) { - // Scale from game coordinates to screen coordinates - x = (x * _gameRect.getWidth() * _overlayWidth) / _frameBuffer->getWidth(); - y = (y * _gameRect.getHeight() * _overlayHeight) / _frameBuffer->getHeight(); - - x += _gameRect.getTopLeft().getX() * _overlayWidth; - y += _gameRect.getTopLeft().getY() * _overlayHeight; - } else -#endif if (_subScreen) { // Scale from game coordinates to screen coordinates x = (x * _gameRect.getWidth()) / _subScreen->w; @@ -1108,90 +363,24 @@ void SurfaceSdlGraphicsManager::warpMouse(int x, int y) { _window->warpMouseInWindow(x, y); } -void SurfaceSdlGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { - // ResidualVM: not use it -} - -#pragma mark - -#pragma mark --- On Screen Display --- -#pragma mark - - -#ifdef USE_OSD -void SurfaceSdlGraphicsManager::displayMessageOnOSD(const char *msg) { - // ResidualVM: not use it -} -#endif - -bool SurfaceSdlGraphicsManager::notifyEvent(const Common::Event &event) { - //ResidualVM specific: - switch ((int)event.type) { - case Common::EVENT_KEYDOWN: - break; - case Common::EVENT_KEYUP: - break; - default: - break; - } - - return false; -} - -void SurfaceSdlGraphicsManager::notifyVideoExpose() { - _forceFull = true; - //ResidualVM specific: - updateScreen(); -} - void SurfaceSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) { - bool frames = _subScreen -#ifdef USE_OPENGL - || _frameBuffer -#endif - ; - if (_overlayVisible || !frames) + if (_overlayVisible || !_subScreen) return; -#ifdef USE_OPENGL - if (_frameBuffer) { - // Scale from screen coordinates to game coordinates - point.x -= _gameRect.getTopLeft().getX() * _overlayWidth; - point.y -= _gameRect.getTopLeft().getY() * _overlayHeight; + // Scale from screen coordinates to game coordinates + point.x -= _gameRect.getTopLeft().getX(); + point.y -= _gameRect.getTopLeft().getY(); - point.x = (point.x * _frameBuffer->getWidth()) / (_gameRect.getWidth() * _overlayWidth); - point.y = (point.y * _frameBuffer->getHeight()) / (_gameRect.getHeight() * _overlayHeight); + point.x = (point.x * _subScreen->w) / _gameRect.getWidth(); + point.y = (point.y * _subScreen->h) / _gameRect.getHeight(); - // Make sure we only supply valid coordinates. - point.x = CLIP(point.x, 0, _frameBuffer->getWidth() - 1); - point.y = CLIP(point.y, 0, _frameBuffer->getHeight() - 1); - } else -#endif - { - // Scale from screen coordinates to game coordinates - point.x -= _gameRect.getTopLeft().getX(); - point.y -= _gameRect.getTopLeft().getY(); - - point.x = (point.x * _subScreen->w) / _gameRect.getWidth(); - point.y = (point.y * _subScreen->h) / _gameRect.getHeight(); - - // Make sure we only supply valid coordinates. - point.x = CLIP(point.x, 0, _subScreen->w - 1); - point.y = CLIP(point.y, 0, _subScreen->h - 1); - } -} - -void SurfaceSdlGraphicsManager::notifyMousePos(Common::Point mouse) { - transformMouseCoordinates(mouse); - // ResidualVM: not use that: - //setMousePos(mouse.x, mouse.y); + // Make sure we only supply valid coordinates. + point.x = CLIP(point.x, 0, _subScreen->w - 1); + point.y = CLIP(point.y, 0, _subScreen->h - 1); } #if SDL_VERSION_ATLEAST(2, 0, 0) void SurfaceSdlGraphicsManager::deinitializeRenderer() { -#ifdef USE_OPENGL - SDL_GL_DeleteContext(_glContext); - _glContext = nullptr; -#endif - SDL_DestroyTexture(_screenTexture); _screenTexture = nullptr; diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index 7baf6b104d7..1ffb6ac5458 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -23,17 +23,8 @@ #ifndef BACKENDS_GRAPHICS_SURFACESDL_GRAPHICS_H #define BACKENDS_GRAPHICS_SURFACESDL_GRAPHICS_H -#ifdef USE_OPENGL -#include "graphics/opengl/system_headers.h" -#include "graphics/opengl/framebuffer.h" -#include "graphics/opengl/texture.h" -#include "graphics/opengl/surfacerenderer.h" -#endif - -#undef ARRAYSIZE - #include "backends/graphics/graphics.h" -#include "backends/graphics/sdl/sdl-graphics.h" +#include "backends/graphics/sdl/resvm-sdl-graphics.h" #include "graphics/pixelformat.h" #include "graphics/scaler.h" #include "common/array.h" @@ -45,72 +36,28 @@ #include "backends/platform/sdl/sdl-sys.h" -#ifndef RELEASE_BUILD -// Define this to allow for focus rectangle debugging -#define USE_SDL_DEBUG_FOCUSRECT -#endif - /** * SDL graphics manager */ -class SurfaceSdlGraphicsManager : public SdlGraphicsManager, public Common::EventObserver { +class SurfaceSdlGraphicsManager : public ResVmSdlGraphicsManager { public: SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window); virtual ~SurfaceSdlGraphicsManager(); - virtual void activateManager(); - virtual void deactivateManager(); - virtual bool hasFeature(OSystem::Feature f); - virtual void setFeatureState(OSystem::Feature f, bool enable); - virtual bool getFeatureState(OSystem::Feature f); - virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const; - virtual int getDefaultGraphicsMode() const; - virtual bool setGraphicsMode(int mode); - virtual int getGraphicsMode() const; - virtual void resetGraphicsScale(); -#ifdef USE_RGB_COLOR - virtual Graphics::PixelFormat getScreenFormat() const { return _screenFormat; } - virtual Common::List getSupportedFormats() const; -#endif - virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL); - virtual void launcherInitSize(uint w, uint h); // ResidualVM specific method virtual void setupScreen(uint gameWidth, uint gameHeight, bool fullscreen, bool accel3d); // ResidualVM specific method virtual Graphics::PixelBuffer getScreenPixelBuffer(); // ResidualVM specific method - virtual int getScreenChangeID() const { return _screenChangeCount; } - - virtual void beginGFXTransaction(); - virtual OSystem::TransactionError endGFXTransaction(); virtual int16 getHeight(); virtual int16 getWidth(); -protected: - // PaletteManager API - virtual void setPalette(const byte *colors, uint start, uint num); - virtual void grabPalette(byte *colors, uint start, uint num); - -public: - virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); - virtual Graphics::Surface *lockScreen(); - virtual void unlockScreen(); - virtual void fillScreen(uint32 col); virtual void updateScreen(); - virtual void setShakePos(int shakeOffset); - virtual void setFocusRectangle(const Common::Rect& rect); - virtual void clearFocusRectangle(); - virtual void showOverlay(); - virtual void hideOverlay(); - virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; } virtual void clearOverlay(); virtual void grabOverlay(void *buf, int pitch); virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); - //ResidualVM specific implementions: - virtual int16 getOverlayHeight() { return _overlayHeight; } - virtual int16 getOverlayWidth() { return _overlayWidth; } void closeOverlay(); // ResidualVM specific method /* Render the passed Surfaces besides the game texture. @@ -119,133 +66,32 @@ public: */ virtual void setSideTextures(Graphics::Surface *left, Graphics::Surface *right); - virtual bool showMouse(bool visible); virtual void warpMouse(int x, int y); - virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); - virtual void setCursorPalette(const byte *colors, uint start, uint num); - virtual bool lockMouse(bool lock); // ResidualVM specific method -#ifdef USE_OSD - virtual void displayMessageOnOSD(const char *msg); -#endif - - // Override from Common::EventObserver - bool notifyEvent(const Common::Event &event); // SdlGraphicsManager interface - virtual void notifyVideoExpose(); virtual void transformMouseCoordinates(Common::Point &point); - virtual void notifyMousePos(Common::Point mouse); protected: - /** - * Places where the game can be drawn - */ - enum GameRenderTarget { - kScreen, /** The game is drawn directly on the screen */ - kSubScreen, /** The game is drawn to a surface, which is centered on the screen */ - kFramebuffer /** The game is drawn to a framebuffer, which is scaled to fit the screen */ - }; - - /** Select the best draw target according to the specified parameters */ - GameRenderTarget selectGameRenderTarget(bool fullscreen, bool accel3d, - bool engineSupportsArbitraryResolutions, - bool framebufferSupported, - bool lockAspectRatio); - - /** Compute the size and position of the game rectangle in the screen */ - Math::Rect2d computeGameRect(GameRenderTarget gameRenderTarget, uint gameWidth, uint gameHeight, - uint effectiveWidth, uint effectiveHeight); - - /** Checks if the render target supports drawing at arbitrary resolutions */ - bool canUsePreferredResolution(GameRenderTarget gameRenderTarget, bool engineSupportsArbitraryResolutions); - - /** Obtain the user configured fullscreen resolution, or default to the desktop resolution */ - Common::Rect getPreferredFullscreenResolution(); - #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_Renderer *_renderer; SDL_Texture *_screenTexture; - SDL_GLContext _glContext; void deinitializeRenderer(); SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); #endif SDL_Surface *_screen; SDL_Surface *_subScreen; -#ifdef USE_RGB_COLOR - Graphics::PixelFormat _screenFormat; - Common::List _supportedFormats; -#endif - -#ifdef USE_OPENGL - bool _opengl; -#endif - bool _lockAspectRatio; - bool _fullscreen; // overlay SDL_Surface *_overlayscreen; - bool _overlayVisible; - Graphics::PixelFormat _overlayFormat; - int _overlayWidth, _overlayHeight; - bool _overlayDirty; - uint _desktopW, _desktopH; Math::Rect2d _gameRect; -#ifdef USE_OPENGL - struct OpenGLPixelFormat { - uint bytesPerPixel; - uint redSize; - uint blueSize; - uint greenSize; - uint alphaSize; - int multisampleSamples; - - OpenGLPixelFormat(uint screenBytesPerPixel, uint red, uint blue, uint green, uint alpha, int samples); - }; - - /** - * Initialize an OpenGL window matching as closely as possible the required properties - * - * When unable to create a context with anti-aliasing this tries without. - * When unable to create a context with the desired pixel depth this tries lower values. - */ - bool createScreenOpenGL(uint effectiveWidth, uint effectiveHeight, GameRenderTarget gameRenderTarget); - - // Antialiasing - int _antialiasing; - - // Overlay - Common::Array _overlayTextures; - - OpenGL::Texture *_sideTextures[2]; - - void initializeOpenGLContext() const; - void updateOverlayTextures(); - void drawOverlayOpenGL(); - void drawSideTexturesOpenGL(); - - OpenGL::FrameBuffer *_frameBuffer; - OpenGL::FrameBuffer *createFramebuffer(uint width, uint height); - - OpenGL::SurfaceRenderer *_surfaceRenderer; - -#endif - SDL_Surface *_sideSurfaces[2]; - /** Force full redraw on next updateScreen */ - bool _forceFull; - - int _screenChangeCount; - void drawOverlay(); void drawSideTextures(); - - bool detectFramebufferSupport(); - void detectDesktopResolution(); }; #endif diff --git a/backends/module.mk b/backends/module.mk index 5a01924ac1d..1efda75d7ca 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -57,6 +57,7 @@ MODULE_OBJS += \ events/sdl/sdl-events.o \ events/sdl/resvm-sdl-events.o \ graphics/sdl/sdl-graphics.o \ + graphics/sdl/resvm-sdl-graphics.o \ graphics/surfacesdl/surfacesdl-graphics.o \ mixer/doublebuffersdl/doublebuffersdl-mixer.o \ mixer/sdl/sdl-mixer.o \ @@ -69,6 +70,11 @@ ifndef USE_SDL2 MODULE_OBJS += \ audiocd/sdl/sdl-audiocd.o endif + +ifdef USE_OPENGL +MODULE_OBJS += \ + graphics/openglsdl/openglsdl-graphics.o +endif endif ifdef POSIX diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 2e7e47162e1..723299ae4f6 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -48,6 +48,7 @@ #include "backends/mutex/sdl/sdl-mutex.h" #include "backends/timer/sdl/sdl-timer.h" #include "backends/graphics/surfacesdl/surfacesdl-graphics.h" +#include "backends/graphics/openglsdl/openglsdl-graphics.h" #include // for getTimeAndDate() @@ -283,6 +284,32 @@ void OSystem_SDL::setWindowCaption(const char *caption) { _window->setWindowCaption(cap); } +void OSystem_SDL::setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) { +#ifdef USE_OPENGL + bool switchedManager = false; + if (accel3d && !dynamic_cast(_graphicsManager)) { + switchedManager = true; + } else if (!accel3d && !dynamic_cast(_graphicsManager)) { + switchedManager = true; + } + + if (switchedManager) { + SdlGraphicsManager *sdlGraphicsManager = dynamic_cast(_graphicsManager); + sdlGraphicsManager->deactivateManager(); + delete _graphicsManager; + + if (accel3d) { + _graphicsManager = sdlGraphicsManager = new OpenGLSdlGraphicsManager(_eventSource, _window); + } else { + _graphicsManager = sdlGraphicsManager = new SurfaceSdlGraphicsManager(_eventSource, _window); + } + sdlGraphicsManager->activateManager(); + } +#endif + + ModularBackend::setupScreen(screenW, screenH, fullscreen, accel3d); +} + void OSystem_SDL::quit() { delete this; exit(0); diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 9d249d6eab9..bd4dda71e3a 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -82,6 +82,10 @@ public: // ResidualVM specific code virtual void suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right) override; + + // ResidualVM specific code + virtual void setupScreen(uint screenW, uint screenH, bool fullscreen, bool accel3d) override; + protected: bool _inited; bool _initedSDL;