ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

openglsdl-graphics.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/scummsys.h"
00024 
00025 #if defined(SDL_BACKEND)
00026 
00027 #include "backends/graphics/openglsdl/openglsdl-graphics.h"
00028 
00029 #include "backends/events/sdl/sdl-events.h"
00030 #include "common/config-manager.h"
00031 #include "engines/engine.h"
00032 #include "graphics/pixelbuffer.h"
00033 #include "graphics/opengl/context.h"
00034 #include "graphics/opengl/framebuffer.h"
00035 #include "graphics/opengl/surfacerenderer.h"
00036 #include "graphics/opengl/system_headers.h"
00037 #include "graphics/opengl/texture.h"
00038 #include "graphics/opengl/tiledsurface.h"
00039 
00040 OpenGLSdlGraphicsManager::OpenGLSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window, const Capabilities &capabilities)
00041     :
00042     ResVmSdlGraphicsManager(sdlEventSource, window, capabilities),
00043 #if SDL_VERSION_ATLEAST(2, 0, 0)
00044     _glContext(nullptr),
00045 #endif
00046     _overlayScreen(nullptr),
00047     _overlayBackground(nullptr),
00048     _gameRect(),
00049     _frameBuffer(nullptr),
00050     _surfaceRenderer(nullptr) {
00051     ConfMan.registerDefault("antialiasing", 0);
00052 
00053     _sideTextures[0] = _sideTextures[1] = nullptr;
00054 
00055     // Don't start at zero so that the value is never the same as the surface graphics manager
00056     _screenChangeCount = 1 << (sizeof(int) * 8 - 2);
00057 }
00058 
00059 OpenGLSdlGraphicsManager::~OpenGLSdlGraphicsManager() {
00060     closeOverlay();
00061 #if SDL_VERSION_ATLEAST(2, 0, 0)
00062     deinitializeRenderer();
00063 #endif
00064 }
00065 
00066 bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) const {
00067     return
00068         (f == OSystem::kFeatureFullscreenMode) ||
00069         (f == OSystem::kFeatureOpenGL) ||
00070 #if SDL_VERSION_ATLEAST(2, 0, 0)
00071         (f == OSystem::kFeatureFullscreenToggleKeepsContext) ||
00072 #endif
00073         (f == OSystem::kFeatureVSync) ||
00074         (f == OSystem::kFeatureAspectRatioCorrection) ||
00075         (f == OSystem::kFeatureOverlaySupportsAlpha && _overlayFormat.aBits() > 3);
00076 }
00077 
00078 bool OpenGLSdlGraphicsManager::getFeatureState(OSystem::Feature f) const {
00079     switch (f) {
00080         case OSystem::kFeatureVSync:
00081             return isVSyncEnabled();
00082         default:
00083             return ResVmSdlGraphicsManager::getFeatureState(f);
00084     }
00085 }
00086 
00087 void OpenGLSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
00088     switch (f) {
00089         case OSystem::kFeatureFullscreenMode:
00090             if (_fullscreen != enable) {
00091                 _fullscreen = enable;
00092                 createOrUpdateScreen();
00093             }
00094             break;
00095         default:
00096             ResVmSdlGraphicsManager::setFeatureState(f, enable);
00097             break;
00098     }
00099 }
00100 
00101 void OpenGLSdlGraphicsManager::setupScreen(uint gameWidth, uint gameHeight, bool fullscreen, bool accel3d) {
00102     assert(accel3d);
00103     closeOverlay();
00104 
00105 #if SDL_VERSION_ATLEAST(2, 0, 0)
00106     // Clear the GL context when going from / to the launcher
00107     SDL_GL_DeleteContext(_glContext);
00108     _glContext = nullptr;
00109 #endif
00110 
00111     _engineRequestedWidth = gameWidth;
00112     _engineRequestedHeight = gameHeight;
00113     _antialiasing = ConfMan.getInt("antialiasing");
00114     _fullscreen = fullscreen;
00115     _lockAspectRatio = ConfMan.getBool("aspect_ratio");
00116     _vsync = ConfMan.getBool("vsync");
00117 
00118     createOrUpdateScreen();
00119 
00120     int glflag;
00121     const GLubyte *str;
00122 
00123     str = glGetString(GL_VENDOR);
00124     debug("INFO: OpenGL Vendor: %s", str);
00125     str = glGetString(GL_RENDERER);
00126     debug("INFO: OpenGL Renderer: %s", str);
00127     str = glGetString(GL_VERSION);
00128     debug("INFO: OpenGL Version: %s", str);
00129     SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &glflag);
00130     debug("INFO: OpenGL Red bits: %d", glflag);
00131     SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &glflag);
00132     debug("INFO: OpenGL Green bits: %d", glflag);
00133     SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &glflag);
00134     debug("INFO: OpenGL Blue bits: %d", glflag);
00135     SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &glflag);
00136     debug("INFO: OpenGL Alpha bits: %d", glflag);
00137     SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &glflag);
00138     debug("INFO: OpenGL Z buffer depth bits: %d", glflag);
00139     SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &glflag);
00140     debug("INFO: OpenGL Double Buffer: %d", glflag);
00141     SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &glflag);
00142     debug("INFO: OpenGL Stencil buffer bits: %d", glflag);
00143 #ifdef USE_GLEW
00144     debug("INFO: GLEW Version: %s", glewGetString(GLEW_VERSION));
00145 #endif
00146 #ifdef USE_OPENGL_SHADERS
00147     debug("INFO: GLSL version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
00148 #endif
00149 }
00150 
00151 void OpenGLSdlGraphicsManager::createOrUpdateScreen() {
00152     closeOverlay();
00153 
00154     // If the game can't adapt to any resolution, render it to a framebuffer
00155     // so it can be scaled to fill the available space.
00156     bool engineSupportsArbitraryResolutions = !g_engine || g_engine->hasFeature(Engine::kSupportsArbitraryResolutions);
00157     bool renderToFrameBuffer = !engineSupportsArbitraryResolutions && _capabilities.openGLFrameBuffer;
00158 
00159     // Choose the effective window size or fullscreen mode
00160     uint effectiveWidth;
00161     uint effectiveHeight;
00162     if (_fullscreen && (engineSupportsArbitraryResolutions || renderToFrameBuffer)) {
00163         Common::Rect fullscreenResolution = getPreferredFullscreenResolution();
00164         effectiveWidth = fullscreenResolution.width();
00165         effectiveHeight = fullscreenResolution.height();
00166     } else {
00167         effectiveWidth = _engineRequestedWidth;
00168         effectiveHeight = _engineRequestedHeight;
00169     }
00170 
00171     if (!createOrUpdateGLContext(_engineRequestedWidth, _engineRequestedHeight,
00172                                  effectiveWidth, effectiveHeight, renderToFrameBuffer)) {
00173         warning("SDL Error: %s", SDL_GetError());
00174         g_system->quit();
00175     }
00176 
00177 #ifdef USE_GLEW
00178     GLenum err = glewInit();
00179     if (err != GLEW_OK) {
00180         warning("Error: %s", glewGetErrorString(err));
00181         g_system->quit();
00182     }
00183 #endif
00184 
00185 #if SDL_VERSION_ATLEAST(2, 0, 1)
00186     int obtainedWidth = 0, obtainedHeight = 0;
00187     SDL_GL_GetDrawableSize(_window->getSDLWindow(), &obtainedWidth, &obtainedHeight);
00188 #else
00189     int obtainedWidth = effectiveWidth;
00190     int obtainedHeight = effectiveHeight;
00191 #endif
00192 
00193     // Compute the rectangle where to draw the game inside the effective screen
00194     _gameRect = computeGameRect(renderToFrameBuffer, _engineRequestedWidth, _engineRequestedHeight,
00195                                 obtainedWidth, obtainedHeight);
00196 
00197     initializeOpenGLContext();
00198     _surfaceRenderer = OpenGL::createBestSurfaceRenderer();
00199 
00200     _overlayFormat = OpenGL::Texture::getRGBAPixelFormat();
00201     _overlayScreen = new OpenGL::TiledSurface(obtainedWidth, obtainedHeight, _overlayFormat);
00202 
00203     _screenFormat = _overlayFormat;
00204 
00205     _screenChangeCount++;
00206 
00207     _eventSource->resetKeyboardEmulation(obtainedWidth - 1, obtainedHeight - 1);
00208 
00209 #if !defined(AMIGAOS)
00210     if (renderToFrameBuffer) {
00211         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
00212         _frameBuffer = createFramebuffer(_engineRequestedWidth, _engineRequestedHeight);
00213         _frameBuffer->attach();
00214     }
00215 #endif
00216 }
00217 
00218 Math::Rect2d OpenGLSdlGraphicsManager::computeGameRect(bool renderToFrameBuffer, uint gameWidth, uint gameHeight,
00219                                                       uint screenWidth, uint screenHeight) {
00220     if (renderToFrameBuffer) {
00221         if (_lockAspectRatio) {
00222             // The game is scaled to fit the screen, keeping the same aspect ratio
00223             float scale = MIN(screenHeight / float(gameHeight), screenWidth / float(gameWidth));
00224             float scaledW = scale * (gameWidth / float(screenWidth));
00225             float scaledH = scale * (gameHeight / float(screenHeight));
00226             return Math::Rect2d(
00227                     Math::Vector2d(0.5 - (0.5 * scaledW), 0.5 - (0.5 * scaledH)),
00228                     Math::Vector2d(0.5 + (0.5 * scaledW), 0.5 + (0.5 * scaledH))
00229             );
00230         } else {
00231             // The game occupies the whole screen
00232             return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1));
00233         }
00234     } else {
00235         return Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(1, 1));
00236     }
00237 }
00238 
00239 void OpenGLSdlGraphicsManager::notifyResize(const uint width, const uint height) {
00240 #if SDL_VERSION_ATLEAST(2, 0, 0)
00241     // Get the updated size directly from SDL, in case there are multiple
00242     // resize events in the message queue.
00243     int newWidth = 0, newHeight = 0;
00244     SDL_GL_GetDrawableSize(_window->getSDLWindow(), &newWidth, &newHeight);
00245 
00246     if (newWidth == _overlayScreen->getWidth() && newHeight == _overlayScreen->getHeight()) {
00247         return; // nothing to do
00248     }
00249 
00250     // Compute the rectangle where to draw the game inside the effective screen
00251     _gameRect = computeGameRect(_frameBuffer != nullptr,
00252                                 _engineRequestedWidth, _engineRequestedHeight,
00253                                 newWidth, newHeight);
00254 
00255     // Update the overlay
00256     delete _overlayScreen;
00257     _overlayScreen = new OpenGL::TiledSurface(newWidth, newHeight, _overlayFormat);
00258 
00259     // Clear the overlay background so it is not displayed distorted while resizing
00260     delete _overlayBackground;
00261     _overlayBackground = nullptr;
00262 
00263     _screenChangeCount++;
00264 
00265     _eventSource->resetKeyboardEmulation(newWidth - 1, newHeight- 1);
00266 #endif
00267 }
00268 
00269 Graphics::PixelBuffer OpenGLSdlGraphicsManager::getScreenPixelBuffer() {
00270     error("Direct screen buffer access is not allowed when using OpenGL");
00271 }
00272 
00273 void OpenGLSdlGraphicsManager::initializeOpenGLContext() const {
00274     OpenGL::ContextType type;
00275 
00276 #ifdef USE_GLES2
00277     type = OpenGL::kContextGLES2;
00278 #else
00279     type = OpenGL::kContextGL;
00280 #endif
00281 
00282     OpenGLContext.initialize(type);
00283 
00284 #if SDL_VERSION_ATLEAST(2, 0, 0)
00285     if (SDL_GL_SetSwapInterval(_vsync ? 1 : 0)) {
00286         warning("Unable to %s VSync: %s", _vsync ? "enable" : "disable", SDL_GetError());
00287     }
00288 #endif
00289 }
00290 
00291 OpenGLSdlGraphicsManager::OpenGLPixelFormat::OpenGLPixelFormat(uint screenBytesPerPixel, uint red, uint blue, uint green, uint alpha, int samples) :
00292         bytesPerPixel(screenBytesPerPixel),
00293         redSize(red),
00294         blueSize(blue),
00295         greenSize(green),
00296         alphaSize(alpha),
00297         multisampleSamples(samples) {
00298 
00299 }
00300 
00301 bool OpenGLSdlGraphicsManager::createOrUpdateGLContext(uint gameWidth, uint gameHeight,
00302                                                        uint effectiveWidth, uint effectiveHeight,
00303                                                        bool renderToFramebuffer) {
00304     // Build a list of OpenGL pixel formats usable by ResidualVM
00305     Common::Array<OpenGLPixelFormat> pixelFormats;
00306     if (_antialiasing > 0 && !renderToFramebuffer) {
00307         // Don't enable screen level multisampling when rendering to a framebuffer
00308         pixelFormats.push_back(OpenGLPixelFormat(32, 8, 8, 8, 8, _antialiasing));
00309         pixelFormats.push_back(OpenGLPixelFormat(16, 5, 5, 5, 1, _antialiasing));
00310         pixelFormats.push_back(OpenGLPixelFormat(16, 5, 6, 5, 0, _antialiasing));
00311     }
00312     pixelFormats.push_back(OpenGLPixelFormat(32, 8, 8, 8, 8, 0));
00313     pixelFormats.push_back(OpenGLPixelFormat(16, 5, 5, 5, 1, 0));
00314     pixelFormats.push_back(OpenGLPixelFormat(16, 5, 6, 5, 0, 0));
00315 
00316     // Unfortunatly, SDL does not provide a list of valid pixel formats
00317     // for the current OpenGL implementation and hardware.
00318     // SDL may not be able to create a screen with the preferred pixel format.
00319     // Try all the pixel formats in the list until SDL returns a valid screen.
00320     Common::Array<OpenGLPixelFormat>::const_iterator it = pixelFormats.begin();
00321     for (; it != pixelFormats.end(); it++) {
00322         SDL_GL_SetAttribute(SDL_GL_RED_SIZE, it->redSize);
00323         SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, it->greenSize);
00324         SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, it->blueSize);
00325         SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, it->alphaSize);
00326         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
00327         SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
00328         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
00329         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, it->multisampleSamples > 0);
00330         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, it->multisampleSamples);
00331 #if !SDL_VERSION_ATLEAST(2, 0, 0)
00332         SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, _vsync ? 1 : 0);
00333 #endif
00334 #if SDL_VERSION_ATLEAST(2, 0, 0)
00335 #ifdef USE_GLES2
00336         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
00337         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
00338         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
00339 #else
00340         // AmigaOS4's OpenGL implementation is close to 1.3. Until that changes we need
00341         // to use 1.3 as version or residualvm will cease working at all on that platform.
00342         // Profile Mask has to be 0 as well.
00343         // This will be revised and removed once AmigaOS4 supports 2.x or OpenGLES2.
00344         #ifdef __amigaos4__
00345             SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
00346             SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
00347         #else
00348             SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
00349             SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
00350         #endif
00351 #endif
00352 #endif
00353 
00354 #if SDL_VERSION_ATLEAST(2, 0, 0)
00355         uint32 sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
00356         if (_fullscreen) {
00357             // On Linux/X11, when toggling to fullscreen, the window manager saves
00358             // the window size to be able to restore it when going back to windowed mode.
00359             // If the user configured ResidualVM to start in fullscreen mode, we first
00360             // create a window and then toggle it to fullscreen to give the window manager
00361             // a chance to save the window size. That way if the user switches back
00362             // to windowed mode, the window manager has a window size to apply instead
00363             // of leaving the window at the fullscreen resolution size.
00364             if (!_window->getSDLWindow()) {
00365                 _window->createOrUpdateWindow(gameWidth, gameHeight, sdlflags);
00366             }
00367 
00368             sdlflags |= SDL_WINDOW_FULLSCREEN;
00369         }
00370 
00371         if (_window->createOrUpdateWindow(effectiveWidth, effectiveHeight, sdlflags)) {
00372             // Get the current GL context from SDL in case the previous one
00373             // was destroyed because the window was recreated.
00374             _glContext = SDL_GL_GetCurrentContext();
00375             if (!_glContext) {
00376                 _glContext = SDL_GL_CreateContext(_window->getSDLWindow());
00377             }
00378 
00379             if (_glContext) {
00380                 assert(SDL_GL_GetCurrentWindow() == _window->getSDLWindow());
00381                 break;
00382             }
00383         }
00384 
00385         _window->destroyWindow();
00386 #else
00387         uint32 sdlflags = SDL_OPENGL;
00388         if (_fullscreen)
00389             sdlflags |= SDL_FULLSCREEN;
00390 
00391         SDL_Surface *screen = SDL_SetVideoMode(effectiveWidth, effectiveHeight, it->bytesPerPixel, sdlflags);
00392         if (screen) {
00393             break;
00394         }
00395 #endif
00396     }
00397 
00398     // Display a warning if the effective pixel format is not the preferred one
00399     if (it != pixelFormats.begin() && it != pixelFormats.end()) {
00400         bool wantsAA = pixelFormats.front().multisampleSamples > 0;
00401         bool gotAA = it->multisampleSamples > 0;
00402 
00403         warning("Couldn't create a %d-bit visual%s, using to %d-bit%s instead",
00404                 pixelFormats.front().bytesPerPixel,
00405                 wantsAA && !gotAA ? " with AA" : "",
00406                 it->bytesPerPixel,
00407                 wantsAA && !gotAA ? " without AA" : "");
00408     }
00409 
00410     return it != pixelFormats.end();
00411 }
00412 
00413 bool OpenGLSdlGraphicsManager::isVSyncEnabled() const {
00414 #if SDL_VERSION_ATLEAST(2, 0, 0)
00415     return SDL_GL_GetSwapInterval() != 0;
00416 #else
00417     int swapControl = 0;
00418     SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &swapControl);
00419     return swapControl != 0;
00420 #endif
00421 }
00422 
00423 void OpenGLSdlGraphicsManager::drawOverlay() {
00424     glViewport(0, 0, _overlayScreen->getWidth(), _overlayScreen->getHeight());
00425     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
00426 
00427     _surfaceRenderer->prepareState();
00428 
00429     if (_overlayBackground) {
00430         _overlayBackground->draw(_surfaceRenderer);
00431     }
00432 
00433     _surfaceRenderer->enableAlphaBlending(true);
00434     _surfaceRenderer->setFlipY(true);
00435     _overlayScreen->draw(_surfaceRenderer);
00436 
00437     _surfaceRenderer->restorePreviousState();
00438 }
00439 
00440 void OpenGLSdlGraphicsManager::drawSideTextures() {
00441     if (_fullscreen && _lockAspectRatio) {
00442         _surfaceRenderer->setFlipY(true);
00443 
00444         const Math::Vector2d nudge(1.0 / float(_overlayScreen->getWidth()), 0);
00445         if (_sideTextures[0] != nullptr) {
00446             float left = _gameRect.getBottomLeft().getX() - (float(_overlayScreen->getHeight()) / float(_sideTextures[0]->getHeight())) * _sideTextures[0]->getWidth() / float(_overlayScreen->getWidth());
00447             Math::Rect2d leftRect(Math::Vector2d(left, 0.0), _gameRect.getBottomLeft() + nudge);
00448             _surfaceRenderer->render(_sideTextures[0], leftRect);
00449         }
00450 
00451         if (_sideTextures[1] != nullptr) {
00452             float right = _gameRect.getTopRight().getX() + (float(_overlayScreen->getHeight()) / float(_sideTextures[1]->getHeight())) * _sideTextures[1]->getWidth() / float(_overlayScreen->getWidth());
00453             Math::Rect2d rightRect(_gameRect.getTopRight() - nudge, Math::Vector2d(right, 1.0));
00454             _surfaceRenderer->render(_sideTextures[1], rightRect);
00455         }
00456 
00457         _surfaceRenderer->setFlipY(false);
00458     }
00459 }
00460 
00461 #ifndef AMIGAOS
00462 OpenGL::FrameBuffer *OpenGLSdlGraphicsManager::createFramebuffer(uint width, uint height) {
00463 #if !defined(USE_GLES2)
00464     if (_antialiasing && OpenGLContext.framebufferObjectMultisampleSupported) {
00465         return new OpenGL::MultiSampleFrameBuffer(width, height, _antialiasing);
00466     } else
00467 #endif
00468     {
00469         return new OpenGL::FrameBuffer(width, height);
00470     }
00471 }
00472 #endif // AMIGAOS
00473 
00474 void OpenGLSdlGraphicsManager::updateScreen() {
00475     if (_frameBuffer) {
00476         _frameBuffer->detach();
00477         glViewport(0, 0, _overlayScreen->getWidth(), _overlayScreen->getHeight());
00478         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
00479         _surfaceRenderer->prepareState();
00480         drawSideTextures();
00481         _surfaceRenderer->render(_frameBuffer, _gameRect);
00482         _surfaceRenderer->restorePreviousState();
00483     }
00484 
00485     if (_overlayVisible) {
00486         _overlayScreen->update();
00487 
00488         if (_overlayBackground) {
00489             _overlayBackground->update();
00490         }
00491 
00492         drawOverlay();
00493     }
00494 
00495 #if SDL_VERSION_ATLEAST(2, 0, 0)
00496     SDL_GL_SwapWindow(_window->getSDLWindow());
00497 #else
00498     SDL_GL_SwapBuffers();
00499 #endif
00500 
00501     if (_frameBuffer) {
00502         _frameBuffer->attach();
00503     }
00504 }
00505 
00506 int16 OpenGLSdlGraphicsManager::getHeight() const {
00507     // ResidualVM specific
00508     if (_frameBuffer)
00509         return _frameBuffer->getHeight();
00510     else
00511         return _overlayScreen->getHeight();
00512 }
00513 
00514 int16 OpenGLSdlGraphicsManager::getWidth() const {
00515     // ResidualVM specific
00516     if (_frameBuffer)
00517         return _frameBuffer->getWidth();
00518     else
00519         return _overlayScreen->getWidth();
00520 }
00521 
00522 #pragma mark -
00523 #pragma mark --- Overlays ---
00524 #pragma mark -
00525 
00526 void OpenGLSdlGraphicsManager::suggestSideTextures(Graphics::Surface *left, Graphics::Surface *right) {
00527     delete _sideTextures[0];
00528     _sideTextures[0] = nullptr;
00529     delete _sideTextures[1];
00530     _sideTextures[1] = nullptr;
00531     if (left) {
00532         _sideTextures[0] = new OpenGL::Texture(*left);
00533     }
00534     if (right) {
00535         _sideTextures[1] = new OpenGL::Texture(*right);
00536     }
00537 }
00538 
00539 void OpenGLSdlGraphicsManager::showOverlay() {
00540     if (_overlayVisible) {
00541         return;
00542     }
00543     _overlayVisible = true;
00544 
00545     delete _overlayBackground;
00546     _overlayBackground = nullptr;
00547 
00548     if (g_engine) {
00549         if (_frameBuffer)
00550             _frameBuffer->detach();
00551         // If there is a game running capture the screen, so that it can be shown "below" the overlay.
00552         _overlayBackground = new OpenGL::TiledSurface(_overlayScreen->getWidth(), _overlayScreen->getHeight(), _overlayFormat);
00553         Graphics::Surface *background = _overlayBackground->getBackingSurface();
00554         glReadPixels(0, 0, background->w, background->h, GL_RGBA, GL_UNSIGNED_BYTE, background->getPixels());
00555         if (_frameBuffer)
00556             _frameBuffer->attach();
00557     }
00558 }
00559 
00560 void OpenGLSdlGraphicsManager::hideOverlay() {
00561     if (!_overlayVisible) {
00562         return;
00563     }
00564     _overlayVisible = false;
00565 
00566     delete _overlayBackground;
00567     _overlayBackground = nullptr;
00568 }
00569 
00570 void OpenGLSdlGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
00571     _overlayScreen->copyRectToSurface(buf, pitch, x, y, w, h);
00572 }
00573 
00574 void OpenGLSdlGraphicsManager::clearOverlay() {
00575     _overlayScreen->fill(0);
00576 }
00577 
00578 void OpenGLSdlGraphicsManager::grabOverlay(void *buf, int pitch) const {
00579     const Graphics::Surface *overlayData = _overlayScreen->getBackingSurface();
00580 
00581     const byte *src = (const byte *)overlayData->getPixels();
00582     byte *dst = (byte *)buf;
00583 
00584     for (uint h = overlayData->h; h > 0; --h) {
00585         memcpy(dst, src, overlayData->w * overlayData->format.bytesPerPixel);
00586         dst += pitch;
00587         src += overlayData->pitch;
00588     }
00589 }
00590 
00591 void OpenGLSdlGraphicsManager::closeOverlay() {
00592     delete _sideTextures[0];
00593     delete _sideTextures[1];
00594     _sideTextures[0] = _sideTextures[1] = nullptr;
00595 
00596     if (_overlayScreen) {
00597         delete _overlayScreen;
00598         _overlayScreen = nullptr;
00599     }
00600 
00601     delete _surfaceRenderer;
00602     _surfaceRenderer = nullptr;
00603 
00604     delete _frameBuffer;
00605     _frameBuffer = nullptr;
00606 
00607     OpenGL::Context::destroy();
00608 }
00609 
00610 int16 OpenGLSdlGraphicsManager::getOverlayHeight() const {
00611     return _overlayScreen->getHeight();
00612 }
00613 
00614 int16 OpenGLSdlGraphicsManager::getOverlayWidth() const {
00615     return _overlayScreen->getWidth();
00616 }
00617 
00618 void OpenGLSdlGraphicsManager::warpMouse(int x, int y) {
00619     //ResidualVM specific
00620     if (_frameBuffer) {
00621         // Scale from game coordinates to screen coordinates
00622         x = (x * _gameRect.getWidth() * _overlayScreen->getWidth()) / _frameBuffer->getWidth();
00623         y = (y * _gameRect.getHeight() * _overlayScreen->getHeight()) / _frameBuffer->getHeight();
00624 
00625         x += _gameRect.getTopLeft().getX() * _overlayScreen->getWidth();
00626         y += _gameRect.getTopLeft().getY() * _overlayScreen->getHeight();
00627     }
00628 
00629     _window->warpMouseInWindow(x, y);
00630 }
00631 
00632 void OpenGLSdlGraphicsManager::transformMouseCoordinates(Common::Point &point) {
00633     if (_overlayVisible || !_frameBuffer)
00634         return;
00635 
00636     // Scale from screen coordinates to game coordinates
00637     point.x -= _gameRect.getTopLeft().getX() * _overlayScreen->getWidth();
00638     point.y -= _gameRect.getTopLeft().getY() * _overlayScreen->getHeight();
00639 
00640     point.x = (point.x * _frameBuffer->getWidth())  / (_gameRect.getWidth() * _overlayScreen->getWidth());
00641     point.y = (point.y * _frameBuffer->getHeight()) / (_gameRect.getHeight() * _overlayScreen->getHeight());
00642 
00643     // Make sure we only supply valid coordinates.
00644     point.x = CLIP<int16>(point.x, 0, _frameBuffer->getWidth() - 1);
00645     point.y = CLIP<int16>(point.y, 0, _frameBuffer->getHeight() - 1);
00646 }
00647 
00648 #if SDL_VERSION_ATLEAST(2, 0, 0)
00649 void OpenGLSdlGraphicsManager::deinitializeRenderer() {
00650     SDL_GL_DeleteContext(_glContext);
00651     _glContext = nullptr;
00652 }
00653 #endif // SDL_VERSION_ATLEAST(2, 0, 0)
00654 
00655 #endif


Generated on Sat Feb 16 2019 05:01:00 for ResidualVM by doxygen 1.7.1
curved edge   curved edge