From fe2ee9ecf5709d49279265f0e5d3b2d0a5688265 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Fri, 11 Dec 2015 19:23:41 +0100 Subject: OPENGL: Refactor screen refresh handling. Subclasses of OpenGLGraphicsManager are now supposed to supply a refreshScreen function which handles actual screen updating (for example, buffer swapping). --- backends/graphics/opengl/opengl-graphics.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'backends/graphics/opengl/opengl-graphics.cpp') diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index 5821856c30..301813c23f 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -431,6 +431,8 @@ void OpenGLGraphicsManager::updateScreen() { GLCALL(glColor4f(1.0f, 1.0f, 1.0f, 1.0f)); } #endif + + refreshScreen(); } Graphics::Surface *OpenGLGraphicsManager::lockScreen() { -- cgit v1.2.3 From f65a8b26898db3bd870010fc3a0b0b71e50e16b7 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Fri, 11 Dec 2015 19:54:47 +0100 Subject: OPENGL: Only redraw screen when actual changes happened. --- backends/graphics/opengl/opengl-graphics.cpp | 35 ++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'backends/graphics/opengl/opengl-graphics.cpp') diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index 301813c23f..05e24675fd 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -51,7 +51,8 @@ OpenGLGraphicsManager::OpenGLGraphicsManager() _overlayVisible(false), _cursor(nullptr), _cursorX(0), _cursorY(0), _cursorDisplayX(0),_cursorDisplayY(0), _cursorHotspotX(0), _cursorHotspotY(0), _cursorHotspotXScaled(0), _cursorHotspotYScaled(0), _cursorWidthScaled(0), _cursorHeightScaled(0), - _cursorKeyColor(0), _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false) + _cursorKeyColor(0), _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false), + _forceRedraw(false) #ifdef USE_OSD , _osdAlpha(0), _osdFadeStartTime(0), _osd(nullptr) #endif @@ -343,7 +344,10 @@ void OpenGLGraphicsManager::fillScreen(uint32 col) { } void OpenGLGraphicsManager::setShakePos(int shakeOffset) { - _gameScreenShakeOffset = shakeOffset; + if (_gameScreenShakeOffset != shakeOffset) { + _gameScreenShakeOffset = shakeOffset; + _forceRedraw = true; + } } void OpenGLGraphicsManager::updateScreen() { @@ -351,6 +355,16 @@ void OpenGLGraphicsManager::updateScreen() { return; } + // We only update the screen when there actually have been any changes. + if ( !_forceRedraw + && !_gameScreen->isDirty() + && !(_overlayVisible && _overlay->isDirty()) + && !(_cursorVisible && _cursor && _cursor->isDirty()) + && _osdAlpha == 0) { + return; + } + _forceRedraw = false; + // Clear the screen buffer. GLCALL(glClear(GL_COLOR_BUFFER_BIT)); @@ -467,6 +481,7 @@ int16 OpenGLGraphicsManager::getOverlayHeight() { void OpenGLGraphicsManager::showOverlay() { _overlayVisible = true; + _forceRedraw = true; // Update cursor position. setMousePosition(_cursorX, _cursorY); @@ -474,6 +489,7 @@ void OpenGLGraphicsManager::showOverlay() { void OpenGLGraphicsManager::hideOverlay() { _overlayVisible = false; + _forceRedraw = true; // Update cursor position. setMousePosition(_cursorX, _cursorY); @@ -505,6 +521,12 @@ void OpenGLGraphicsManager::grabOverlay(void *buf, int pitch) { } bool OpenGLGraphicsManager::showMouse(bool visible) { + // In case the mouse cursor visibility changed we need to redraw the whole + // screen even when nothing else changed. + if (_cursorVisible != visible) { + _forceRedraw = true; + } + bool last = _cursorVisible; _cursorVisible = visible; return last; @@ -940,6 +962,12 @@ void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) { } void OpenGLGraphicsManager::setMousePosition(int x, int y) { + // Whenever the mouse position changed we force a screen redraw to reflect + // changes properly. + if (_cursorX != x || _cursorY != y) { + _forceRedraw = true; + } + _cursorX = x; _cursorY = y; @@ -1100,6 +1128,9 @@ void OpenGLGraphicsManager::recalculateDisplayArea() { // Update the cursor position to adjust for new display area. setMousePosition(_cursorX, _cursorY); + + // Force a redraw to assure screen is properly redrawn. + _forceRedraw = true; } void OpenGLGraphicsManager::updateCursorPalette() { -- cgit v1.2.3 From 693834e8c6e9bf01925dc1731dad44d15f880be9 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Fri, 11 Dec 2015 21:22:42 +0100 Subject: OPENGL: Implement black borders using scissor test. --- backends/graphics/opengl/opengl-graphics.cpp | 90 +++++++++++++--------------- 1 file changed, 42 insertions(+), 48 deletions(-) (limited to 'backends/graphics/opengl/opengl-graphics.cpp') diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index 05e24675fd..df74e110bb 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -52,7 +52,7 @@ OpenGLGraphicsManager::OpenGLGraphicsManager() _cursorX(0), _cursorY(0), _cursorDisplayX(0),_cursorDisplayY(0), _cursorHotspotX(0), _cursorHotspotY(0), _cursorHotspotXScaled(0), _cursorHotspotYScaled(0), _cursorWidthScaled(0), _cursorHeightScaled(0), _cursorKeyColor(0), _cursorVisible(false), _cursorDontScale(false), _cursorPaletteEnabled(false), - _forceRedraw(false) + _forceRedraw(false), _scissorOverride(3) #ifdef USE_OSD , _osdAlpha(0), _osdFadeStartTime(0), _osd(nullptr) #endif @@ -366,7 +366,19 @@ void OpenGLGraphicsManager::updateScreen() { _forceRedraw = false; // Clear the screen buffer. - GLCALL(glClear(GL_COLOR_BUFFER_BIT)); + if (_scissorOverride) { + // In certain cases we need to assure that the whole screen area is + // cleared. For example, when switching from overlay visible to + // invisible, we need to assure that all contents are cleared to + // properly remove all overlay contents. + GLCALL(glDisable(GL_SCISSOR_TEST)); + GLCALL(glClear(GL_COLOR_BUFFER_BIT)); + GLCALL(glEnable(GL_SCISSOR_TEST)); + + --_scissorOverride; + } else { + GLCALL(glClear(GL_COLOR_BUFFER_BIT)); + } const GLfloat shakeOffset = _gameScreenShakeOffset * (GLfloat)_displayHeight / _gameScreen->getHeight(); @@ -389,37 +401,8 @@ void OpenGLGraphicsManager::updateScreen() { _cursorWidthScaled, _cursorHeightScaled); } - // Fourth step: Draw black borders around the game screen when no overlay - // is visible. This makes sure that the mouse cursor etc. is only drawn - // in the actual game screen area in this case. - if (!_overlayVisible) { - GLCALL(glColor4f(0.0f, 0.0f, 0.0f, 1.0f)); - - GLCALL(glDisable(GL_TEXTURE_2D)); - GLCALL(glDisableClientState(GL_TEXTURE_COORD_ARRAY)); - - // Top border. - drawRect(0, 0, _outputScreenWidth, _displayY); - - // Left border. - drawRect(0, 0, _displayX, _outputScreenHeight); - - // Bottom border. - const int y = _displayY + _displayHeight; - drawRect(0, y, _outputScreenWidth, _outputScreenHeight - y); - - // Right border. - const int x = _displayX + _displayWidth; - drawRect(x, 0, _outputScreenWidth - x, _outputScreenHeight); - - GLCALL(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); - GLCALL(glEnable(GL_TEXTURE_2D)); - - GLCALL(glColor4f(1.0f, 1.0f, 1.0f, 1.0f)); - } - #ifdef USE_OSD - // Fifth step: Draw the OSD. + // Fourth step: Draw the OSD. if (_osdAlpha > 0) { Common::StackLock lock(_osdMutex); @@ -483,6 +466,9 @@ void OpenGLGraphicsManager::showOverlay() { _overlayVisible = true; _forceRedraw = true; + // Allow drawing inside full screen area. + GLCALL(glDisable(GL_SCISSOR_TEST)); + // Update cursor position. setMousePosition(_cursorX, _cursorY); } @@ -491,6 +477,10 @@ void OpenGLGraphicsManager::hideOverlay() { _overlayVisible = false; _forceRedraw = true; + // Limit drawing to screen area. + GLCALL(glEnable(GL_SCISSOR_TEST)); + _scissorOverride = 3; + // Update cursor position. setMousePosition(_cursorX, _cursorY); } @@ -875,6 +865,16 @@ void OpenGLGraphicsManager::notifyContextCreate(const Graphics::PixelFormat &def GLCALL(glEnable(GL_TEXTURE_2D)); + // Setup scissor state accordingly. + if (_overlayVisible) { + GLCALL(glDisable(GL_SCISSOR_TEST)); + } else { + GLCALL(glEnable(GL_SCISSOR_TEST)); + } + // Clear the whole screen for the first three frames to assure any + // leftovers are cleared. + _scissorOverride = 3; + // We use a "pack" alignment (when reading from textures) to 4 here, // since the only place where we really use it is the BMP screenshot // code and that requires the same alignment too. @@ -1126,6 +1126,16 @@ void OpenGLGraphicsManager::recalculateDisplayArea() { _displayX = (_outputScreenWidth - _displayWidth ) / 2; _displayY = (_outputScreenHeight - _displayHeight) / 2; + // Setup drawing limitation for game graphics. + // This invovles some trickery because OpenGL's viewport coordinate system + // is upside down compared to ours. + GLCALL(glScissor(_displayX, + _outputScreenHeight - _displayHeight - _displayY, + _displayWidth, + _displayHeight)); + // Clear the whole screen for the first three frames to remove leftovers. + _scissorOverride = 3; + // Update the cursor position to adjust for new display area. setMousePosition(_cursorX, _cursorY); @@ -1248,20 +1258,4 @@ void OpenGLGraphicsManager::saveScreenshot(const Common::String &filename) const delete[] pixels; } -void OpenGLGraphicsManager::drawRect(GLfloat x, GLfloat y, GLfloat w, GLfloat h) { - if (w < 0 || h < 0) { - return; - } - - const GLfloat vertices[4*2] = { - x, y, - x + w, y, - x, y + h, - x + w, y + h - }; - GLCALL(glVertexPointer(2, GL_FLOAT, 0, vertices)); - - GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); -} - } // End of namespace OpenGL -- cgit v1.2.3 From 942d0fdad46d2105f1606ddea8cd9146acec70d8 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 13 Dec 2015 19:05:18 +0100 Subject: OPENGL: Limit scissor override to invisible overlay. This fixes some corner cases which caused black bars to appear for a few screen updates when the overlay is visible. --- backends/graphics/opengl/opengl-graphics.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'backends/graphics/opengl/opengl-graphics.cpp') diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index df74e110bb..c80f57a40e 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -366,7 +366,7 @@ void OpenGLGraphicsManager::updateScreen() { _forceRedraw = false; // Clear the screen buffer. - if (_scissorOverride) { + if (_scissorOverride && !_overlayVisible) { // In certain cases we need to assure that the whole screen area is // cleared. For example, when switching from overlay visible to // invisible, we need to assure that all contents are cleared to -- cgit v1.2.3 From 64f9c902ddf0c8294fd9e5f66cf96661eb12040b Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 14 Dec 2015 20:09:29 +0100 Subject: OPENGL: Smooth mouse experience when black bars are visible. This gets rid of the feeling of the mouse sticking to black borders by using the full output resolution as area for tracking game mouse movement. The same behavior is present in plain SDL output with SDL2. --- backends/graphics/opengl/opengl-graphics.cpp | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'backends/graphics/opengl/opengl-graphics.cpp') diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index c80f57a40e..ac6d41d47d 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -551,11 +551,8 @@ void OpenGLGraphicsManager::warpMouse(int x, int y) { return; } - x = (x * _displayWidth) / _gameScreen->getWidth(); - y = (y * _displayHeight) / _gameScreen->getHeight(); - - x += _displayX; - y += _displayY; + x = (x * _outputScreenWidth) / _gameScreen->getWidth(); + y = (y * _outputScreenHeight) / _gameScreen->getHeight(); } setMousePosition(x, y); @@ -946,18 +943,11 @@ void OpenGLGraphicsManager::adjustMousePosition(int16 &x, int16 &y) { y = (y * _overlay->getHeight()) / _outputScreenHeight; } } else if (_gameScreen) { - x -= _displayX; - y -= _displayY; - const int16 width = _gameScreen->getWidth(); const int16 height = _gameScreen->getHeight(); - x = (x * width) / (int)_displayWidth; - y = (y * height) / (int)_displayHeight; - - // Make sure we only supply valid coordinates. - x = CLIP(x, 0, width - 1); - y = CLIP(y, 0, height - 1); + x = (x * width) / (int)_outputScreenWidth; + y = (y * height) / (int)_outputScreenHeight; } } @@ -975,8 +965,8 @@ void OpenGLGraphicsManager::setMousePosition(int x, int y) { _cursorDisplayX = x; _cursorDisplayY = y; } else { - _cursorDisplayX = CLIP(x, _displayX, _displayX + _displayWidth - 1); - _cursorDisplayY = CLIP(y, _displayY, _displayY + _displayHeight - 1); + _cursorDisplayX = _displayX + (x * _displayWidth) / _outputScreenWidth; + _cursorDisplayY = _displayY + (y * _displayHeight) / _outputScreenHeight; } } -- cgit v1.2.3