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


Generated on Sat Dec 14 2019 05:00:27 for ResidualVM by doxygen 1.7.1
curved edge   curved edge