diff options
-rw-r--r-- | backends/graphics/opengl/gltexture.cpp | 57 | ||||
-rw-r--r-- | backends/graphics/opengl/gltexture.h | 37 | ||||
-rw-r--r-- | backends/graphics/opengl/opengl-graphics.cpp | 347 | ||||
-rw-r--r-- | backends/graphics/opengl/opengl-graphics.h | 38 | ||||
-rw-r--r-- | backends/graphics/openglsdl/openglsdl-graphics.cpp | 29 | ||||
-rw-r--r-- | backends/graphics/openglsdl/openglsdl-graphics.h | 3 |
6 files changed, 377 insertions, 134 deletions
diff --git a/backends/graphics/opengl/gltexture.cpp b/backends/graphics/opengl/gltexture.cpp index 98291edfac..188386d0ab 100644 --- a/backends/graphics/opengl/gltexture.cpp +++ b/backends/graphics/opengl/gltexture.cpp @@ -56,18 +56,22 @@ static GLuint nextHigher2(GLuint v) { void GLTexture::initGLExtensions() { static bool inited = false; + // Return if extensions already checked if (inited) return; + // Get a string with all extensions const char* ext_string = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); CHECK_GL_ERROR(); Common::StringTokenizer tokenizer(ext_string, " "); + // Iterate all string tokens while (!tokenizer.empty()) { Common::String token = tokenizer.nextToken(); if (token == "GL_ARB_texture_non_power_of_two") npot_supported = true; } + inited = true; } @@ -83,31 +87,21 @@ GLTexture::GLTexture(byte bpp, GLenum format, GLenum type) _refresh(false), _filter(GL_NEAREST) { - // Generates the texture ID for GL + // Generate the texture ID glGenTextures(1, &_textureName); CHECK_GL_ERROR(); - - // This all gets reset later in allocBuffer: - _surface.w = 0; - _surface.h = 0; - _surface.pitch = 0; - _surface.pixels = NULL; - _surface.bytesPerPixel = 0; } GLTexture::~GLTexture() { + // Delete the texture glDeleteTextures(1, &_textureName); CHECK_GL_ERROR(); } void GLTexture::refresh() { - // Generates the texture ID for GL + // Generate the texture ID glGenTextures(1, &_textureName); CHECK_GL_ERROR(); _refresh = true; } -void GLTexture::refreshBuffer() { - updateBuffer(_surface.pixels, _surface.pitch, 0, 0, _surface.w, _surface.h); -} - void GLTexture::allocBuffer(GLuint w, GLuint h) { _realWidth = w; _realHeight = h; @@ -124,62 +118,47 @@ void GLTexture::allocBuffer(GLuint w, GLuint h) { _textureHeight = nextHigher2(h); } - // Allocate room for the texture now, but pixel data gets uploaded - // later (perhaps with multiple TexSubImage2D operations). + // Select this OpenGL texture glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR(); + + // Set the texture parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _filter); CHECK_GL_ERROR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _filter); CHECK_GL_ERROR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); CHECK_GL_ERROR(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); CHECK_GL_ERROR(); + + // Allocate room for the texture glTexImage2D(GL_TEXTURE_2D, 0, _glFormat, _textureWidth, _textureHeight, 0, _glFormat, _glType, NULL); CHECK_GL_ERROR(); - if (_surface.w != _textureWidth || _surface.h != _textureHeight) - _surface.create(_textureWidth, _textureHeight, _bytesPerPixel); - else if (_refresh) - refreshBuffer(); - _refresh = false; } void GLTexture::updateBuffer(const void *buf, int pitch, GLuint x, GLuint y, GLuint w, GLuint h) { + // Select this OpenGL texture glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR(); + // Check if the buffer has its data contiguously if (static_cast<int>(w) * _bytesPerPixel == pitch) { glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, _glFormat, _glType, buf); CHECK_GL_ERROR(); - if (buf != _surface.pixels) - memcpy(_surface.getBasePtr(x, y), buf, h * pitch); } else { + // Update the texture row by row const byte *src = static_cast<const byte *>(buf); do { glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, 1, _glFormat, _glType, src); CHECK_GL_ERROR(); - if (buf != _surface.pixels) - memcpy(_surface.getBasePtr(x, y), src, w * _bytesPerPixel); ++y; src += pitch; } while (--h); } } -void GLTexture::fillBuffer(uint32 x) { - if (_bytesPerPixel == 1) - memset(_surface.pixels, x, _surface.w * _surface.h); - else { - for (int i = 0; i < _surface.w * _surface.h; i++) { - memcpy(_surface.pixels, &x, _bytesPerPixel); - } - } - - glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR(); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _surface.w, _surface.h, - _glFormat, _glType, _surface.pixels); CHECK_GL_ERROR(); -} - void GLTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { + // Select this OpenGL texture glBindTexture(GL_TEXTURE_2D, _textureName); CHECK_GL_ERROR(); + // Calculate the texture rect that will be drawn const GLfloat texWidth = (GLfloat)_realWidth / _textureWidth;//xdiv(_surface.w, _textureWidth); const GLfloat texHeight = (GLfloat)_realHeight / _textureHeight;//xdiv(_surface.h, _textureHeight); const GLfloat texcoords[] = { @@ -190,6 +169,7 @@ void GLTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { }; glTexCoordPointer(2, GL_FLOAT, 0, texcoords); CHECK_GL_ERROR(); + // Calculate the screen rect where the texture will be drawn const GLshort vertices[] = { x, y, x + w, y, @@ -198,6 +178,7 @@ void GLTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { }; glVertexPointer(2, GL_SHORT, 0, vertices); CHECK_GL_ERROR(); + // Draw the texture to the screen buffer glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CHECK_GL_ERROR(); } diff --git a/backends/graphics/opengl/gltexture.h b/backends/graphics/opengl/gltexture.h index abdb7eceaa..73771fda91 100644 --- a/backends/graphics/opengl/gltexture.h +++ b/backends/graphics/opengl/gltexture.h @@ -53,28 +53,50 @@ */ class GLTexture { public: + /** + * Initialize OpenGL Extensions + */ static void initGLExtensions(); GLTexture(byte bpp, GLenum format, GLenum type); virtual ~GLTexture(); + /** + * Refresh the texture after a context change. The + * process will be completed on next allocBuffer call. + */ virtual void refresh(); - virtual void refreshBuffer(); + /** + * Allocates memory needed for the given size. + */ virtual void allocBuffer(GLuint width, GLuint height); - virtual void fillBuffer(uint32 x); + + /** + * Updates the texture pixels. + */ virtual void updateBuffer(const void *buf, int pitch, GLuint x, GLuint y, GLuint w, GLuint h); - virtual void drawTexture() { drawTexture(0, 0, _realWidth, _realHeight); } + /** + * Draws the texture to the screen buffer. + */ virtual void drawTexture(GLshort x, GLshort y, GLshort w, GLshort h); - Graphics::Surface *getSurface() { return &_surface; } - + /** + * Get the texture width. + */ GLuint getWidth() const { return _realWidth; } + + /** + * Get the texture height. + */ GLuint getHeight() const { return _realHeight; } - GLuint getTextureName() const { return _textureName; } + /** + * Set the texture filter. + * GL_NEAREST or GL_LINEAR should be passed. + */ void setFilter(GLint filter) { _filter = filter; } protected: @@ -82,12 +104,11 @@ protected: const GLenum _glFormat; const GLenum _glType; - Graphics::Surface _surface; GLuint _realWidth; GLuint _realHeight; GLuint _textureName; GLuint _textureWidth; GLuint _textureHeight; - bool _refresh; GLint _filter; + bool _refresh; }; diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index 5bb496d1ba..6ba4fed474 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -33,20 +33,20 @@ OpenGLGraphicsManager::OpenGLGraphicsManager() : _gameTexture(0), _overlayTexture(0), _cursorTexture(0), - _screenChangeCount(0), + _screenChangeCount(0), _screenNeedsRedraw(false), _currentShakePos(0), _newShakePos(0), - _overlayVisible(false), + _overlayVisible(false), _overlayNeedsRedraw(false), _transactionMode(kTransactionNone), _cursorNeedsRedraw(false), _cursorPaletteDisabled(true), - _cursorVisible(false), _cursorData(0), _cursorKeyColor(0), + _cursorVisible(false), _cursorKeyColor(0), _cursorTargetScale(1) { memset(&_oldVideoMode, 0, sizeof(_oldVideoMode)); memset(&_videoMode, 0, sizeof(_videoMode)); memset(&_transactionDetails, 0, sizeof(_transactionDetails)); - _videoMode.mode = OpenGL::GFX_NORMAL; - _videoMode.scaleFactor = 1; + _videoMode.mode = OpenGL::GFX_DOUBLESIZE; + _videoMode.scaleFactor = 2; _videoMode.fullscreen = false; _videoMode.antialiasing = false; @@ -64,8 +64,6 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() { free(_gamePalette); free(_cursorPalette); - if (_cursorData != NULL) - free(_cursorData); if (_gameTexture != NULL) delete _gameTexture; @@ -80,11 +78,19 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() { // bool OpenGLGraphicsManager::hasFeature(OSystem::Feature f) { - return (f == OSystem::kFeatureCursorHasPalette); + return + (f == OSystem::kFeatureAspectRatioCorrection) || + (f == OSystem::kFeatureCursorHasPalette); } void OpenGLGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { - + switch (f) { + case OSystem::kFeatureAspectRatioCorrection: + setAspectRatioCorrection(enable ? -1 : 0); + break; + default: + break; + } } bool OpenGLGraphicsManager::getFeatureState(OSystem::Feature f) { @@ -225,10 +231,10 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() { errors |= OSystem::kTransactionFullscreenFailed; _videoMode.fullscreen = _oldVideoMode.fullscreen; - /*} else if (_videoMode.aspectRatioCorrection != _oldVideoMode.aspectRatioCorrection) { + } else if (_videoMode.aspectRatioCorrection != _oldVideoMode.aspectRatioCorrection) { errors |= OSystem::kTransactionAspectRatioFailed; - _videoMode.aspectRatioCorrection = _oldVideoMode.aspectRatioCorrection;*/ + _videoMode.aspectRatioCorrection = _oldVideoMode.aspectRatioCorrection; } else if (_videoMode.mode != _oldVideoMode.mode) { errors |= OSystem::kTransactionModeSwitchFailed; @@ -251,7 +257,7 @@ OSystem::TransactionError OpenGLGraphicsManager::endGFXTransaction() { } if (_videoMode.fullscreen == _oldVideoMode.fullscreen && - //_videoMode.aspectRatioCorrection == _oldVideoMode.aspectRatioCorrection && + _videoMode.aspectRatioCorrection == _oldVideoMode.aspectRatioCorrection && _videoMode.mode == _oldVideoMode.mode && _videoMode.screenWidth == _oldVideoMode.screenWidth && _videoMode.screenHeight == _oldVideoMode.screenHeight) { @@ -310,6 +316,8 @@ void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) // Save the screen palette memcpy(_gamePalette + start * 4, colors, num * 4); + _screenNeedsRedraw = true; + if (_cursorPaletteDisabled) _cursorNeedsRedraw = true; } @@ -326,45 +334,65 @@ void OpenGLGraphicsManager::grabPalette(byte *colors, uint start, uint num) { } void OpenGLGraphicsManager::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { - if (_screenFormat == Graphics::PixelFormat::createFormatCLUT8()) { - // Create a temporary RGBA888 surface - byte *surface = new byte[w * h * 3]; - - // Convert the paletted buffer to RGBA888 - const byte *src = buf; - byte *dst = surface; - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - dst[0] = _gamePalette[src[j] * 4]; - dst[1] = _gamePalette[src[j] * 4 + 1]; - dst[2] = _gamePalette[src[j] * 4 + 2]; - dst += 3; - } - src += pitch; - } - - // Update the texture - _gameTexture->updateBuffer(surface, w * 3, x, y, w, h); + assert(x >= 0 && x < _screenData.w); + assert(y >= 0 && y < _screenData.h); + assert(h > 0 && y + h <= _screenData.h); + assert(w > 0 && x + w <= _screenData.w); + + // Copy buffer data to game screen internal buffer + const byte *src = buf; + byte *dst = (byte *)_screenData.pixels + y * _screenData.pitch; + for (int i = 0; i < h; i++) { + memcpy(dst + x * _screenData.bytesPerPixel, src, w * _screenData.bytesPerPixel); + src += pitch; + dst += _screenData.pitch; + } - // Free the temp surface - delete[] surface; - } else - _gameTexture->updateBuffer(buf, pitch, x, y, w, h); + if (!_screenNeedsRedraw) { + const Common::Rect dirtyRect(x, y, x + w, y + h); + _screenDirtyRect.extend(dirtyRect); + } } Graphics::Surface *OpenGLGraphicsManager::lockScreen() { - return _gameTexture->getSurface(); + return &_screenData; } void OpenGLGraphicsManager::unlockScreen() { - _gameTexture->refreshBuffer(); + _screenNeedsRedraw = true; } void OpenGLGraphicsManager::fillScreen(uint32 col) { if (_gameTexture == NULL) return; - _gameTexture->fillBuffer(col); + if (_screenFormat.bytesPerPixel == 1) { + memset(_screenData.pixels, col, _screenData.h * _screenData.pitch); + } else if (_screenFormat.bytesPerPixel == 2) { + uint16 *pixels = (uint16 *)_screenData.pixels; + uint16 col16 = (uint16)col; + for (int i = 0; i < _screenData.w * _screenData.h; i++) { + pixels[i] = col16; + } + } else if (_screenFormat.bytesPerPixel == 3) { + uint8 *pixels = (uint8 *)_screenData.pixels; + byte r = (col >> 16) & 0xFF; + byte g = (col >> 8) & 0xFF; + byte b = col & 0xFF; + for (int i = 0; i < _screenData.w * _screenData.h; i++) { + pixels[0] = r; + pixels[1] = g; + pixels[2] = b; + pixels += 3; + } + } else if (_screenFormat.bytesPerPixel == 4) { + uint32 *pixels = (uint32 *)_screenData.pixels; + for (int i = 0; i < _screenData.w * _screenData.h; i++) { + pixels[i] = col; + } + } + + _screenNeedsRedraw = true; } void OpenGLGraphicsManager::updateScreen() { @@ -392,13 +420,23 @@ void OpenGLGraphicsManager::clearFocusRectangle() { void OpenGLGraphicsManager::showOverlay() { assert (_transactionMode == kTransactionNone); + if (_overlayVisible) + return; + _overlayVisible = true; + + clearOverlay(); } void OpenGLGraphicsManager::hideOverlay() { assert (_transactionMode == kTransactionNone); + if (!_overlayVisible) + return; + _overlayVisible = false; + + clearOverlay(); } Graphics::PixelFormat OpenGLGraphicsManager::getOverlayFormat() const { @@ -406,21 +444,18 @@ Graphics::PixelFormat OpenGLGraphicsManager::getOverlayFormat() const { } void OpenGLGraphicsManager::clearOverlay() { - _overlayTexture->fillBuffer(0); + memset(_overlayData.pixels, 0, _overlayData.h * _overlayData.pitch); + _overlayNeedsRedraw = true; } void OpenGLGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) { - const Graphics::Surface *surface = _overlayTexture->getSurface(); - assert(surface->bytesPerPixel == sizeof(buf[0])); - uint w = _overlayTexture->getWidth(); - uint h = _overlayTexture->getHeight(); - const byte *src = (byte *)surface->pixels; - do { - //memset(buf, 0, w * sizeof(buf[0])); - memcpy(buf, src, w * sizeof(buf[0])); + assert(_overlayData.bytesPerPixel == sizeof(buf[0])); + const byte *src = (byte *)_overlayData.pixels; + for (int i = 0; i < _overlayData.h; i++) { + memcpy(buf, src, _overlayData.pitch); buf += pitch; - src += surface->pitch; - } while (--h); + src += _overlayData.pitch; + } } void OpenGLGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { @@ -429,7 +464,40 @@ void OpenGLGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch if (_overlayTexture == NULL) return; - _overlayTexture->updateBuffer(buf, pitch * sizeof(buf[0]), x, y, w, h); + // Clip the coordinates + if (x < 0) { + w += x; + buf -= x; + x = 0; + } + + if (y < 0) { + h += y; buf -= y * pitch; + y = 0; + } + + if (w > _overlayData.w - x) + w = _overlayData.w - x; + + if (h > _overlayData.h - y) + h = _overlayData.h - y; + + if (w <= 0 || h <= 0) + return; + + // Copy buffer data to internal overlay surface + const byte *src = (byte *)buf; + byte *dst = (byte *)_overlayData.pixels + y * _overlayData.pitch; + for (int i = 0; i < h; i++) { + memcpy(dst + x * _overlayData.bytesPerPixel, src, w * _overlayData.bytesPerPixel); + src += pitch * sizeof(buf[0]); + dst += _overlayData.pitch; + } + + if (!_overlayNeedsRedraw) { + const Common::Rect dirtyRect(x, y, x + w, y + h); + _overlayDirtyRect.extend(dirtyRect); + } } int16 OpenGLGraphicsManager::getOverlayHeight() { @@ -474,9 +542,8 @@ void OpenGLGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int #endif // Save cursor data - free(_cursorData); - _cursorData = (byte *)malloc(w * h * _cursorFormat.bytesPerPixel); - memcpy(_cursorData, buf, w * h * _cursorFormat.bytesPerPixel); + _cursorData.create(w, h, _cursorFormat.bytesPerPixel); + memcpy(_cursorData.pixels, buf, h * _cursorData.pitch); // Set cursor info _cursorState.w = w; @@ -503,10 +570,106 @@ void OpenGLGraphicsManager::disableCursorPalette(bool disable) { _cursorNeedsRedraw = true; } +// +// Misc +// + +void OpenGLGraphicsManager::displayMessageOnOSD(const char *msg) { + +} + +// +// Intern +// + +void OpenGLGraphicsManager::refreshGameScreen() { + if (_screenNeedsRedraw) + _screenDirtyRect = Common::Rect(0, 0, _screenData.w, _screenData.h); + + int x = _screenDirtyRect.left; + int y = _screenDirtyRect.top; + int w = _screenDirtyRect.width(); + int h = _screenDirtyRect.height(); + + if (_screenData.bytesPerPixel == 1) { + // Create a temporary RGB888 surface + byte *surface = new byte[w * h * 3]; + + // Convert the paletted buffer to RGB888 + const byte *src = (byte *)_screenData.pixels + y * _screenData.pitch; + src += x * _screenData.bytesPerPixel; + byte *dst = surface; + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + dst[0] = _gamePalette[src[j] * 4]; + dst[1] = _gamePalette[src[j] * 4 + 1]; + dst[2] = _gamePalette[src[j] * 4 + 2]; + dst += 3; + } + src += _screenData.pitch; + } + + // Update the texture + _gameTexture->updateBuffer(surface, w * 3, x, y, w, h); + + // Free the temp surface + delete[] surface; + } else { + // Update the texture + _gameTexture->updateBuffer((byte *)_screenData.pixels + y * _screenData.pitch + + x * _screenData.bytesPerPixel, _screenData.pitch, x, y, w, h); + } + + _screenNeedsRedraw = false; + _screenDirtyRect = Common::Rect(); +} + +void OpenGLGraphicsManager::refreshOverlay() { + if (_overlayNeedsRedraw) + _overlayDirtyRect = Common::Rect(0, 0, _overlayData.w, _overlayData.h); + + int x = _overlayDirtyRect.left; + int y = _overlayDirtyRect.top; + int w = _overlayDirtyRect.width(); + int h = _overlayDirtyRect.height(); + + if (_overlayData.bytesPerPixel == 1) { + // Create a temporary RGB888 surface + byte *surface = new byte[w * h * 3]; + + // Convert the paletted buffer to RGB888 + const byte *src = (byte *)_overlayData.pixels + y * _overlayData.pitch; + src += x * _overlayData.bytesPerPixel; + byte *dst = surface; + for (int i = 0; i < h; i++) { + for (int j = 0; j < w; j++) { + dst[0] = _gamePalette[src[j] * 4]; + dst[1] = _gamePalette[src[j] * 4 + 1]; + dst[2] = _gamePalette[src[j] * 4 + 2]; + dst += 3; + } + src += _screenData.pitch; + } + + // Update the texture + _overlayTexture->updateBuffer(surface, w * 3, x, y, w, h); + + // Free the temp surface + delete[] surface; + } else { + // Update the texture + _overlayTexture->updateBuffer((byte *)_overlayData.pixels + y * _overlayData.pitch + + x * _overlayData.bytesPerPixel, _overlayData.pitch, x, y, w, h); + } + + _overlayNeedsRedraw = false; + _overlayDirtyRect = Common::Rect(); +} + void OpenGLGraphicsManager::refreshCursor() { _cursorNeedsRedraw = false; - if (_cursorFormat == Graphics::PixelFormat::createFormatCLUT8()) { + if (_cursorFormat.bytesPerPixel == 1) { // Create a temporary RGBA8888 surface byte *surface = new byte[_cursorState.w * _cursorState.h * 4]; memset(surface, 0, _cursorState.w * _cursorState.h * 4); @@ -519,13 +682,14 @@ void OpenGLGraphicsManager::refreshCursor() { palette = _cursorPalette; // Convert the paletted cursor to RGBA8888 + const byte *src = (byte *)_cursorData.pixels; byte *dst = surface; for (int i = 0; i < _cursorState.w * _cursorState.h; i++) { // Check for keycolor - if (_cursorData[i] != _cursorKeyColor) { - dst[0] = palette[_cursorData[i] * 4]; - dst[1] = palette[_cursorData[i] * 4 + 1]; - dst[2] = palette[_cursorData[i] * 4 + 2]; + if (src[i] != _cursorKeyColor) { + dst[0] = palette[src[i] * 4]; + dst[1] = palette[src[i] * 4 + 1]; + dst[2] = palette[src[i] * 4 + 2]; dst[3] = 255; } dst += 4; @@ -542,18 +706,6 @@ void OpenGLGraphicsManager::refreshCursor() { } } -// -// Misc -// - -void OpenGLGraphicsManager::displayMessageOnOSD(const char *msg) { - -} - -// -// Intern -// - void OpenGLGraphicsManager::getGLPixelFormat(Graphics::PixelFormat pixelFormat, byte &bpp, GLenum &glFormat, GLenum &gltype) { if (pixelFormat == Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) { // RGBA8888 bpp = 4; @@ -575,13 +727,14 @@ void OpenGLGraphicsManager::getGLPixelFormat(Graphics::PixelFormat pixelFormat, bpp = 2; glFormat = GL_RGBA; gltype = GL_UNSIGNED_SHORT_4_4_4_4; - } else if (pixelFormat == Graphics::PixelFormat::createFormatCLUT8()) { // CLUT8 - // If uses a palette, create as RGBA888, then convert + } else if (pixelFormat.bytesPerPixel == 1) { // CLUT8 + // If uses a palette, create texture as RGB888. The pixel data will be converted + // later. bpp = 3; glFormat = GL_RGB; gltype = GL_UNSIGNED_BYTE; } else { - error("Not supported format"); + error("Pixel format not supported"); } } @@ -590,16 +743,29 @@ void OpenGLGraphicsManager::internUpdateScreen() { glClear(GL_COLOR_BUFFER_BIT); CHECK_GL_ERROR(); // Draw the game screen + if (_screenNeedsRedraw || !_screenDirtyRect.isEmpty()) + // Refresh texture if dirty + refreshGameScreen(); + _gameTexture->drawTexture(0, 0, _videoMode.hardwareWidth, _videoMode.hardwareHeight); // Draw the overlay - if (_overlayVisible) + if (_overlayVisible) { + + // Refresh texture if dirty + if (_overlayNeedsRedraw || !_overlayDirtyRect.isEmpty()) + refreshOverlay(); + _overlayTexture->drawTexture(0, 0, _videoMode.hardwareWidth, _videoMode.hardwareHeight); + } // Draw the cursor if (_cursorVisible) { + + // Refresh texture if dirty if (_cursorNeedsRedraw) refreshCursor(); + _cursorTexture->drawTexture(_cursorState.x - _cursorState.hotX, _cursorState.y - _cursorState.hotY, _cursorState.w, _cursorState.h); } @@ -640,6 +806,11 @@ void OpenGLGraphicsManager::initGL() { } void OpenGLGraphicsManager::loadTextures() { +#ifdef USE_RGB_COLOR + if (_transactionDetails.formatChanged && _gameTexture) + delete _gameTexture; +#endif + if (!_gameTexture) { byte bpp; GLenum format; @@ -679,6 +850,21 @@ void OpenGLGraphicsManager::loadTextures() { _gameTexture->allocBuffer(_videoMode.screenWidth, _videoMode.screenHeight); _overlayTexture->allocBuffer(_videoMode.overlayWidth, _videoMode.overlayHeight); _cursorTexture->allocBuffer(_cursorState.w, _cursorState.h); + + if (_transactionDetails.formatChanged || + _oldVideoMode.screenWidth != _videoMode.screenWidth || + _oldVideoMode.screenHeight != _videoMode.screenHeight) + _screenData.create(_videoMode.screenWidth, _videoMode.screenHeight, + _screenFormat.bytesPerPixel); + + if (_oldVideoMode.overlayWidth != _videoMode.overlayWidth || + _oldVideoMode.overlayHeight != _videoMode.overlayHeight) + _overlayData.create(_videoMode.overlayWidth, _videoMode.overlayHeight, + _overlayFormat.bytesPerPixel); + + _screenNeedsRedraw = true; + _overlayNeedsRedraw = true; + _cursorNeedsRedraw = true; } bool OpenGLGraphicsManager::loadGFXMode() { @@ -705,6 +891,19 @@ void OpenGLGraphicsManager::setScale(int newScale) { _transactionDetails.sizeChanged = true; } +void OpenGLGraphicsManager::setAspectRatioCorrection(int ratio) { + if (_oldVideoMode.setup && _oldVideoMode.aspectRatioCorrection == ratio) + return; + + if (_transactionMode == kTransactionActive) { + if (ratio == -1) + _videoMode.aspectRatioCorrection = (_videoMode.aspectRatioCorrection + 1) % 4; + else + _videoMode.aspectRatioCorrection = ratio; + _transactionDetails.needHotswap = true; + } +} + void OpenGLGraphicsManager::adjustMouseEvent(const Common::Event &event) { if (!event.synthetic) { Common::Event newEvent(event); diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h index e366216a8c..a372cb9d0d 100644 --- a/backends/graphics/opengl/opengl-graphics.h +++ b/backends/graphics/opengl/opengl-graphics.h @@ -126,12 +126,18 @@ protected: TransactionDetails _transactionDetails; int _transactionMode; + enum { + kAspectRatioNone, + kAspectRatioConserve, + kAspectRatio4_3, + kAspectRatio16_10 + }; + struct VideoState { bool setup; bool fullscreen; - //bool aspectRatioCorrection; - //AspectRatio desiredAspectRatio; + int aspectRatioCorrection; int mode; int scaleFactor; @@ -153,19 +159,24 @@ protected: virtual void unloadGFXMode(); virtual void setScale(int newScale); + virtual void setAspectRatioCorrection(int mode); // // Game screen // GLTexture* _gameTexture; - Graphics::Surface _lockedScreen; + Graphics::Surface _screenData; int _screenChangeCount; + bool _screenNeedsRedraw; + Common::Rect _screenDirtyRect; #ifdef USE_RGB_COLOR Graphics::PixelFormat _screenFormat; #endif byte *_gamePalette; + virtual void refreshGameScreen(); + // Shake mode int _currentShakePos; int _newShakePos; @@ -174,8 +185,13 @@ protected: // Overlay // GLTexture* _overlayTexture; - bool _overlayVisible; + Graphics::Surface _overlayData; Graphics::PixelFormat _overlayFormat; + bool _overlayVisible; + bool _overlayNeedsRedraw; + Common::Rect _overlayDirtyRect; + + virtual void refreshOverlay(); // // Mouse @@ -191,21 +207,22 @@ protected: // The size and hotspot of the pre-scaled cursor image, in real // coordinates. - int16 rW, rH; - int16 rHotX, rHotY; + //int16 rW, rH; + //int16 rHotX, rHotY; // The size and hotspot of the pre-scaled cursor image, in game // coordinates. - int16 vW, vH; - int16 vHotX, vHotY; + //int16 vW, vH; + //int16 vHotX, vHotY; - MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0), + MousePos() : x(0), y(0), w(0), h(0), hotX(0), hotY(0)/*, rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0), - vHotX(0), vHotY(0) + vHotX(0), vHotY(0)*/ { } }; GLTexture* _cursorTexture; + Graphics::Surface _cursorData; #ifdef USE_RGB_COLOR Graphics::PixelFormat _cursorFormat; #endif @@ -213,7 +230,6 @@ protected: bool _cursorPaletteDisabled; MousePos _cursorState; bool _cursorVisible; - byte *_cursorData; uint32 _cursorKeyColor; int _cursorTargetScale; bool _cursorNeedsRedraw; diff --git a/backends/graphics/openglsdl/openglsdl-graphics.cpp b/backends/graphics/openglsdl/openglsdl-graphics.cpp index aa0a9aa717..6f2ba0df9c 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.cpp +++ b/backends/graphics/openglsdl/openglsdl-graphics.cpp @@ -44,6 +44,28 @@ OpenGLSdlGraphicsManager::~OpenGLSdlGraphicsManager() { } + +bool OpenGLSdlGraphicsManager::hasFeature(OSystem::Feature f) { + return + (f == OSystem::kFeatureFullscreenMode) || + (f == OSystem::kFeatureIconifyWindow) || + OpenGLGraphicsManager::hasFeature(f); +} + +void OpenGLSdlGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { + switch (f) { + case OSystem::kFeatureFullscreenMode: + setFullscreenMode(enable); + break; + case OSystem::kFeatureIconifyWindow: + if (enable) + SDL_WM_IconifyWindow(); + break; + default: + OpenGLGraphicsManager::setFeatureState(f, enable); + } +} + #ifdef USE_RGB_COLOR const Graphics::PixelFormat RGBList[] = { @@ -202,9 +224,9 @@ void OpenGLSdlGraphicsManager::internUpdateScreen() { bool OpenGLSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) { // Ctrl-Alt-a toggles aspect ratio correction - /*if (key == 'a') { + if (key == 'a') { beginGFXTransaction(); - setFeatureState(OSystem::kFeatureAspectRatioCorrection, !_videoMode.aspectRatioCorrection); + setAspectRatioCorrection(-1); endGFXTransaction(); #ifdef USE_OSD char buffer[128]; @@ -222,7 +244,7 @@ bool OpenGLSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) { #endif internUpdateScreen(); return true; - }*/ + } // Ctrl-Alt-f toggles antialiasing if (key == 'f') { @@ -329,6 +351,7 @@ bool OpenGLSdlGraphicsManager::notifyEvent(const Common::Event &event) { _videoMode.hardwareHeight = event.mouse.y; _screenResized = true; _transactionDetails.sizeChanged = true; + _transactionDetails.newContext = true; endGFXTransaction(); return true; diff --git a/backends/graphics/openglsdl/openglsdl-graphics.h b/backends/graphics/openglsdl/openglsdl-graphics.h index b0bf12cd4d..f11782131c 100644 --- a/backends/graphics/openglsdl/openglsdl-graphics.h +++ b/backends/graphics/openglsdl/openglsdl-graphics.h @@ -42,6 +42,9 @@ public: OpenGLSdlGraphicsManager(); virtual ~OpenGLSdlGraphicsManager(); + virtual bool hasFeature(OSystem::Feature f); + virtual void setFeatureState(OSystem::Feature f, bool enable); + #ifdef USE_RGB_COLOR virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const; #endif |