SDL: Split the GraphicsManager into Surface and OpenGL

This commit is contained in:
Bastien Bouclet 2016-06-17 19:59:42 +02:00
parent 36c45b7f0b
commit 52f2dfc869
9 changed files with 1405 additions and 1035 deletions

View File

@ -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<char *>("SDL_VIDEO_WINDOW_POS=9000,9000"));
SDL_SetVideoMode(32, 32, 0, SDL_OPENGL);
SDL_putenv(const_cast<char *>("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<OpenGLPixelFormat> 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<OpenGLPixelFormat>::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<int16>(point.x, 0, _frameBuffer->getWidth() - 1);
point.y = CLIP<int16>(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

View File

@ -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<OpenGL::Texture *> _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

View File

@ -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<Graphics::PixelFormat> 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);
}

View File

@ -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<Graphics::PixelFormat> 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<Graphics::PixelFormat> _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

File diff suppressed because it is too large Load Diff

View File

@ -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<Graphics::PixelFormat> 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<Graphics::PixelFormat> _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<OpenGL::Texture *> _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

View File

@ -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

View File

@ -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 <time.h> // 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<OpenGLSdlGraphicsManager *>(_graphicsManager)) {
switchedManager = true;
} else if (!accel3d && !dynamic_cast<SurfaceSdlGraphicsManager *>(_graphicsManager)) {
switchedManager = true;
}
if (switchedManager) {
SdlGraphicsManager *sdlGraphicsManager = dynamic_cast<SdlGraphicsManager *>(_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);

View File

@ -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;