diff options
Diffstat (limited to 'backends/graphics')
-rw-r--r-- | backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp | 25 | ||||
-rw-r--r-- | backends/graphics/gph/gph-graphics.cpp | 27 | ||||
-rw-r--r-- | backends/graphics/graphics.h | 4 | ||||
-rw-r--r-- | backends/graphics/linuxmotosdl/linuxmotosdl-graphics.cpp | 25 | ||||
-rw-r--r-- | backends/graphics/opengl/opengl-graphics.cpp | 34 | ||||
-rw-r--r-- | backends/graphics/opengl/opengl-graphics.h | 3 | ||||
-rw-r--r-- | backends/graphics/surfacesdl/surfacesdl-graphics.cpp | 254 | ||||
-rw-r--r-- | backends/graphics/surfacesdl/surfacesdl-graphics.h | 20 |
8 files changed, 319 insertions, 73 deletions
diff --git a/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp b/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp index 7a248f1859..0938be2d4e 100644 --- a/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp +++ b/backends/graphics/dinguxsdl/dinguxsdl-graphics.cpp @@ -259,21 +259,33 @@ void DINGUXSdlGraphicsManager::internUpdateScreen() { #ifdef USE_OSD // OSD visible (i.e. non-transparent)? - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + if (_osdMessageAlpha != SDL_ALPHA_TRANSPARENT) { // Updated alpha value - const int diff = SDL_GetTicks() - _osdFadeStartTime; + const int diff = SDL_GetTicks() - _osdMessageFadeStartTime; if (diff > 0) { if (diff >= kOSDFadeOutDuration) { // Back to full transparency - _osdAlpha = SDL_ALPHA_TRANSPARENT; + _osdMessageAlpha = SDL_ALPHA_TRANSPARENT; } else { // Do a linear fade out... const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; - _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + _osdMessageAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; } - SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); _forceFull = true; } + + if (_osdMessageAlpha == SDL_ALPHA_TRANSPARENT) { + removeOSDMessage(); + } else { + if (_osdMessageSurface && _osdSurface) { + SDL_Rect dstRect; + dstRect.x = (_osdSurface->w - _osdMessageSurface->w) / 2; + dstRect.y = (_osdSurface->h - _osdMessageSurface->h) / 2; + dstRect.w = _osdMessageSurface->w; + dstRect.h = _osdMessageSurface->h; + blitOSDMessage(dstRect); + } + } } #endif @@ -405,9 +417,8 @@ void DINGUXSdlGraphicsManager::internUpdateScreen() { drawMouse(); #ifdef USE_OSD - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + if (_osdMessageAlpha != SDL_ALPHA_TRANSPARENT) SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); - } #endif // Finally, blit all our changes to the screen SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); diff --git a/backends/graphics/gph/gph-graphics.cpp b/backends/graphics/gph/gph-graphics.cpp index 65cb3d1d65..bd0f246286 100644 --- a/backends/graphics/gph/gph-graphics.cpp +++ b/backends/graphics/gph/gph-graphics.cpp @@ -279,21 +279,33 @@ void GPHGraphicsManager::internUpdateScreen() { #ifdef USE_OSD // OSD visible (i.e. non-transparent)? - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + if (_osdMessageAlpha != SDL_ALPHA_TRANSPARENT) { // Updated alpha value - const int diff = SDL_GetTicks() - _osdFadeStartTime; + const int diff = SDL_GetTicks() - _osdMessageFadeStartTime; if (diff > 0) { if (diff >= kOSDFadeOutDuration) { // Back to full transparency - _osdAlpha = SDL_ALPHA_TRANSPARENT; + _osdMessageAlpha = SDL_ALPHA_TRANSPARENT; } else { // Do a linear fade out... const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; - _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + _osdMessageAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; } - SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); _forceFull = true; } + + if (_osdMessageAlpha == SDL_ALPHA_TRANSPARENT) { + removeOSDMessage(); + } else { + if (_osdMessageSurface && _osdSurface) { + SDL_Rect dstRect; + dstRect.x = (_osdSurface->w - _osdMessageSurface->w) / 2; + dstRect.y = (_osdSurface->h - _osdMessageSurface->h) / 2; + dstRect.w = _osdMessageSurface->w; + dstRect.h = _osdMessageSurface->h; + blitOSDMessage(dstRect); + } + } } #endif @@ -428,9 +440,8 @@ void GPHGraphicsManager::internUpdateScreen() { drawMouse(); #ifdef USE_OSD - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + if (_osdMessageAlpha != SDL_ALPHA_TRANSPARENT) SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); - } #endif // Finally, blit all our changes to the screen SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); @@ -459,7 +470,7 @@ void GPHGraphicsManager::hideOverlay() { bool GPHGraphicsManager::loadGFXMode() { - // We don't offer anything other than fullscreen on GPH devices so let’s not even pretend. + // We don't offer anything other than fullscreen on GPH devices so let's not even pretend. _videoMode.fullscreen = true; // Set the hardware stats to match the LCD. diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h index 3671b9f0b9..921dfca61c 100644 --- a/backends/graphics/graphics.h +++ b/backends/graphics/graphics.h @@ -84,6 +84,10 @@ public: virtual void setCursorPalette(const byte *colors, uint start, uint num) = 0; virtual void displayMessageOnOSD(const char *msg) {} + virtual void copyRectToOSD(const void *buf, int pitch, int x, int y, int w, int h) {} + virtual void clearOSD() {} + virtual Graphics::PixelFormat getOSDFormat() { return Graphics::PixelFormat(); } + // Graphics::PaletteManager interface //virtual void setPalette(const byte *colors, uint start, uint num) = 0; diff --git a/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.cpp b/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.cpp index 52e5b42e8b..a69cba24ee 100644 --- a/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.cpp +++ b/backends/graphics/linuxmotosdl/linuxmotosdl-graphics.cpp @@ -292,21 +292,33 @@ void LinuxmotoSdlGraphicsManager::internUpdateScreen() { #ifdef USE_OSD // OSD visible (i.e. non-transparent)? - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + if (_osdMessageAlpha != SDL_ALPHA_TRANSPARENT) { // Updated alpha value - const int diff = SDL_GetTicks() - _osdFadeStartTime; + const int diff = SDL_GetTicks() - _osdMessageFadeStartTime; if (diff > 0) { if (diff >= kOSDFadeOutDuration) { // Back to full transparency - _osdAlpha = SDL_ALPHA_TRANSPARENT; + _osdMessageAlpha = SDL_ALPHA_TRANSPARENT; } else { // Do a linear fade out... const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; - _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + _osdMessageAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; } - SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); _forceFull = true; } + + if (_osdMessageAlpha == SDL_ALPHA_TRANSPARENT) { + removeOSDMessage(); + } else { + if (_osdMessageSurface && _osdSurface) { + SDL_Rect dstRect; + dstRect.x = (_osdSurface->w - _osdMessageSurface->w) / 2; + dstRect.y = (_osdSurface->h - _osdMessageSurface->h) / 2; + dstRect.w = _osdMessageSurface->w; + dstRect.h = _osdMessageSurface->h; + blitOSDMessage(dstRect); + } + } } #endif @@ -439,9 +451,8 @@ void LinuxmotoSdlGraphicsManager::internUpdateScreen() { drawMouse(); #ifdef USE_OSD - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + if (_osdMessageAlpha != SDL_ALPHA_TRANSPARENT) SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); - } #endif // Finally, blit all our changes to the screen SDL_UpdateRects(_hwscreen, _numDirtyRects, _dirtyRectList); diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp index 4d6a00a3b3..8861d364e6 100644 --- a/backends/graphics/opengl/opengl-graphics.cpp +++ b/backends/graphics/opengl/opengl-graphics.cpp @@ -367,7 +367,10 @@ void OpenGLGraphicsManager::updateScreen() { && !_gameScreen->isDirty() && !(_overlayVisible && _overlay->isDirty()) && !(_cursorVisible && _cursor && _cursor->isDirty()) - && _osdAlpha == 0) { +#ifdef USE_OSD + && _osdAlpha == 0 +#endif + ) { return; } _forceRedraw = false; @@ -378,7 +381,9 @@ void OpenGLGraphicsManager::updateScreen() { _cursor->updateGLTexture(); } _overlay->updateGLTexture(); +#ifdef USE_OSD _osd->updateGLTexture(); +#endif // Clear the screen buffer. if (_scissorOverride && !_overlayVisible) { @@ -751,6 +756,33 @@ void OpenGLGraphicsManager::displayMessageOnOSD(const char *msg) { #endif } +void OpenGLGraphicsManager::copyRectToOSD(const void *buf, int pitch, int x, int y, int w, int h) { +#ifdef USE_OSD + _osd->copyRectToTexture(x, y, w, h, buf, pitch); +#endif +} + +void OpenGLGraphicsManager::clearOSD() { +#ifdef USE_OSD + // HACK: Actually no client code should use graphics functions from + // another thread. But the MT-32 emulator still does, thus we need to + // make sure this doesn't happen while a updateScreen call is done. + Common::StackLock lock(_osdMutex); + + Graphics::Surface *dst = _osd->getSurface(); + _osd->fill(0); + _osd->flagDirty(); + + // Init the OSD display parameters. + _osdAlpha = kOSDInitialAlpha; + _osdFadeStartTime = g_system->getMillis() + kOSDFadeOutDelay; +#endif +} + +Graphics::PixelFormat OpenGLGraphicsManager::getOSDFormat() { + return _defaultFormatAlpha; +} + void OpenGLGraphicsManager::setPalette(const byte *colors, uint start, uint num) { assert(_gameScreen->hasPalette()); diff --git a/backends/graphics/opengl/opengl-graphics.h b/backends/graphics/opengl/opengl-graphics.h index 35435c156e..55d2c5c826 100644 --- a/backends/graphics/opengl/opengl-graphics.h +++ b/backends/graphics/opengl/opengl-graphics.h @@ -115,6 +115,9 @@ public: virtual void setCursorPalette(const byte *colors, uint start, uint num); virtual void displayMessageOnOSD(const char *msg); + virtual void copyRectToOSD(const void *buf, int pitch, int x, int y, int w, int h); + virtual void clearOSD(); + virtual Graphics::PixelFormat getOSDFormat(); // PaletteManager interface virtual void setPalette(const byte *colors, uint start, uint num); diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index 5b591e77ff..f4a466d740 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -121,7 +121,7 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou : SdlGraphicsManager(sdlEventSource, window), #ifdef USE_OSD - _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0), + _osdSurface(0), _osdMessageSurface(nullptr), _osdMessageAlpha(SDL_ALPHA_TRANSPARENT), _osdMessageFadeStartTime(0), #endif _hwscreen(0), #if SDL_VERSION_ATLEAST(2, 0, 0) @@ -883,13 +883,16 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() { _osdSurface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _hwscreen->w, _hwscreen->h, - 16, - _hwscreen->format->Rmask, - _hwscreen->format->Gmask, - _hwscreen->format->Bmask, - _hwscreen->format->Amask); + 32, + 0xFF000000, + 0x00FF0000, + 0x0000FF00, + 0x000000FF + ); if (_osdSurface == NULL) error("allocating _osdSurface failed"); + + _osdFormat = getSurfaceFormat(_osdSurface); SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey); #endif @@ -946,6 +949,11 @@ void SurfaceSdlGraphicsManager::unloadGFXMode() { SDL_FreeSurface(_osdSurface); _osdSurface = NULL; } + + if (_osdMessageSurface) { + SDL_FreeSurface(_osdMessageSurface); + _osdMessageSurface = NULL; + } #endif DestroyScalers(); @@ -1059,21 +1067,33 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() { #ifdef USE_OSD // OSD visible (i.e. non-transparent)? - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + if (_osdMessageAlpha != SDL_ALPHA_TRANSPARENT) { // Updated alpha value - const int diff = SDL_GetTicks() - _osdFadeStartTime; + const int diff = SDL_GetTicks() - _osdMessageFadeStartTime; if (diff > 0) { if (diff >= kOSDFadeOutDuration) { // Back to full transparency - _osdAlpha = SDL_ALPHA_TRANSPARENT; + _osdMessageAlpha = SDL_ALPHA_TRANSPARENT; } else { // Do a linear fade out... const int startAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; - _osdAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; + _osdMessageAlpha = startAlpha + diff * (SDL_ALPHA_TRANSPARENT - startAlpha) / kOSDFadeOutDuration; } - SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); _forceFull = true; } + + if (_osdMessageAlpha == SDL_ALPHA_TRANSPARENT) { + removeOSDMessage(); + } else { + if (_osdMessageSurface && _osdSurface) { + SDL_Rect dstRect; + dstRect.x = (_osdSurface->w - _osdMessageSurface->w) / 2; + dstRect.y = (_osdSurface->h - _osdMessageSurface->h) / 2; + dstRect.w = _osdMessageSurface->w; + dstRect.h = _osdMessageSurface->h; + blitOSDMessage(dstRect); + } + } } #endif @@ -1179,9 +1199,8 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() { drawMouse(); #ifdef USE_OSD - if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + if (_osdMessageAlpha != SDL_ALPHA_TRANSPARENT) SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); - } #endif #ifdef USE_SDL_DEBUG_FOCUSRECT @@ -2121,26 +2140,11 @@ void SurfaceSdlGraphicsManager::displayMessageOnOSD(const char *msg) { Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends - uint i; - - // Lock the OSD surface for drawing - if (SDL_LockSurface(_osdSurface)) - error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); - - Graphics::Surface dst; - dst.init(_osdSurface->w, _osdSurface->h, _osdSurface->pitch, _osdSurface->pixels, - Graphics::PixelFormat(_osdSurface->format->BytesPerPixel, - 8 - _osdSurface->format->Rloss, 8 - _osdSurface->format->Gloss, - 8 - _osdSurface->format->Bloss, 8 - _osdSurface->format->Aloss, - _osdSurface->format->Rshift, _osdSurface->format->Gshift, - _osdSurface->format->Bshift, _osdSurface->format->Ashift)); + removeOSDMessage(); // The font we are going to use: const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kLocalizedFont); - // Clear everything with the "transparent" color, i.e. the colorkey - SDL_FillRect(_osdSurface, 0, kOSDColorKey); - // Split the message into separate lines. Common::Array<Common::String> lines; const char *ptr; @@ -2159,44 +2163,184 @@ void SurfaceSdlGraphicsManager::displayMessageOnOSD(const char *msg) { const int lineHeight = font->getFontHeight() + 2 * lineSpacing; int width = 0; int height = lineHeight * lines.size() + 2 * vOffset; + uint i; for (i = 0; i < lines.size(); i++) { width = MAX(width, font->getStringWidth(lines[i]) + 14); } // Clip the rect - if (width > dst.w) - width = dst.w; - if (height > dst.h) - height = dst.h; + if (width > _osdSurface->w) + width = _osdSurface->w; + if (height > _osdSurface->h) + height = _osdSurface->h; + + _osdMessageSurface = SDL_CreateRGBSurface( + SDL_SWSURFACE | SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, + width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF + ); + + // Lock the surface + if (SDL_LockSurface(_osdMessageSurface)) + error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); // Draw a dark gray rect // TODO: Rounded corners ? Border? - SDL_Rect osdRect; - osdRect.x = (dst.w - width) / 2; - osdRect.y = (dst.h - height) / 2; - osdRect.w = width; - osdRect.h = height; - SDL_FillRect(_osdSurface, &osdRect, SDL_MapRGB(_osdSurface->format, 64, 64, 64)); + SDL_FillRect(_osdMessageSurface, nullptr, SDL_MapRGB(_osdMessageSurface->format, 64, 64, 64)); + + Graphics::Surface dst; + dst.init(_osdMessageSurface->w, _osdMessageSurface->h, _osdMessageSurface->pitch, _osdMessageSurface->pixels, + Graphics::PixelFormat(_osdMessageSurface->format->BytesPerPixel, + 8 - _osdMessageSurface->format->Rloss, 8 - _osdMessageSurface->format->Gloss, + 8 - _osdMessageSurface->format->Bloss, 8 - _osdMessageSurface->format->Aloss, + _osdMessageSurface->format->Rshift, _osdMessageSurface->format->Gshift, + _osdMessageSurface->format->Bshift, _osdMessageSurface->format->Ashift)); // Render the message, centered, and in white for (i = 0; i < lines.size(); i++) { font->drawString(&dst, lines[i], - osdRect.x, osdRect.y + i * lineHeight + vOffset + lineSpacing, osdRect.w, - SDL_MapRGB(_osdSurface->format, 255, 255, 255), - Graphics::kTextAlignCenter); + 0, 0 + i * lineHeight + vOffset + lineSpacing, width, + SDL_MapRGB(_osdMessageSurface->format, 255, 255, 255), + Graphics::kTextAlignCenter); } + // Finished drawing, so unlock the OSD message surface + SDL_UnlockSurface(_osdMessageSurface); + + // Init the OSD display parameters, and the fade out + _osdMessageAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; + _osdMessageFadeStartTime = SDL_GetTicks() + kOSDFadeOutDelay; + + // Ensure a full redraw takes place next time the screen is updated + _forceFull = true; +} + +void SurfaceSdlGraphicsManager::copyRectToOSD(const void *buf, int pitch, int x, int y, int w, int h) { + assert(_transactionMode == kTransactionNone); + assert(buf); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + // Lock the OSD surface for drawing + if (SDL_LockSurface(_osdSurface)) + error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); + + // Mark that area as "dirty" + addDirtyRect(x, y, w, h, true); + +#ifdef USE_RGB_COLOR + byte *dst = (byte *)_osdSurface->pixels + y * _osdSurface->pitch + x * _osdSurface->format->BytesPerPixel; + if (_videoMode.screenWidth == w && pitch == _osdSurface->pitch) { + memcpy(dst, buf, h*pitch); + } else { + const byte *src = (const byte *)buf; + do { + memcpy(dst, src, w * _osdSurface->format->BytesPerPixel); + src += pitch; + dst += _osdSurface->pitch; + } while (--h); + } +#else + byte *dst = (byte *)_osdSurface->pixels + y * _osdSurface->pitch + x; + if (_osdSurface->pitch == pitch && pitch == w) { + memcpy(dst, buf, h*w); + } else { + const byte *src = (const byte *)buf; + do { + memcpy(dst, src, w); + src += pitch; + dst += _osdSurface->pitch; + } while (--h); + } +#endif + // Finished drawing, so unlock the OSD surface again SDL_UnlockSurface(_osdSurface); +} - // Init the OSD display parameters, and the fade out - _osdAlpha = SDL_ALPHA_TRANSPARENT + kOSDInitialAlpha * (SDL_ALPHA_OPAQUE - SDL_ALPHA_TRANSPARENT) / 100; - _osdFadeStartTime = SDL_GetTicks() + kOSDFadeOutDelay; - SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); +void SurfaceSdlGraphicsManager::clearOSD() { + assert(_transactionMode == kTransactionNone); + + Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends + + // Lock the OSD surface for drawing + if (SDL_LockSurface(_osdSurface)) + error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); + + // Clear everything with the "transparent" color, i.e. the colorkey + SDL_FillRect(_osdSurface, 0, kOSDColorKey); + + // Finished drawing, so unlock the OSD surface again + SDL_UnlockSurface(_osdSurface); + + // Remove OSD message as well + removeOSDMessage(); // Ensure a full redraw takes place next time the screen is updated _forceFull = true; } + +void SurfaceSdlGraphicsManager::removeOSDMessage() { + // Lock the OSD surface for drawing + if (SDL_LockSurface(_osdSurface)) + error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); + + //remove previous message + if (_osdMessageSurface) { + SDL_Rect osdRect; + osdRect.x = (_osdSurface->w - _osdMessageSurface->w) / 2; + osdRect.y = (_osdSurface->h - _osdMessageSurface->h) / 2; + osdRect.w = _osdMessageSurface->w; + osdRect.h = _osdMessageSurface->h; + SDL_FillRect(_osdSurface, &osdRect, kOSDColorKey); + SDL_FreeSurface(_osdMessageSurface); + } + + _osdMessageSurface = NULL; + _osdMessageAlpha = SDL_ALPHA_TRANSPARENT; + + // Finished drawing, so unlock the OSD surface again + SDL_UnlockSurface(_osdSurface); +} + +void SurfaceSdlGraphicsManager::blitOSDMessage(SDL_Rect dstRect) { + SDL_Surface *src = _osdMessageSurface; + SDL_Surface *dst = _osdSurface; + Graphics::PixelFormat srcFormat = getSurfaceFormat(src); + Graphics::PixelFormat dstFormat = _osdFormat; + for (int y = 0; y < dstRect.h; y++) { + const byte *srcRow = (const byte *)((const byte *)(src->pixels) + y * src->pitch); //src (x, y) == (0, 0) + byte *dstRow = (byte *)((byte *)(dst->pixels) + (dstRect.y + y) * dst->pitch + dstRect.x * dstFormat.bytesPerPixel); + + for (int x = 0; x < dstRect.w; x++) { + uint32 srcColor; + if (dst->format->BytesPerPixel == 2) + srcColor = READ_UINT16(srcRow); + else if (dst->format->BytesPerPixel == 3) + srcColor = READ_UINT24(srcRow); + else + srcColor = READ_UINT32(srcRow); + + srcRow += srcFormat.bytesPerPixel; + + // Convert that color to the new format + byte r, g, b, a; + srcFormat.colorToARGB(srcColor, a, r, g, b); + a = _osdMessageAlpha; //this is the important line, because apart from that this is plain surface copying + uint32 color = dstFormat.ARGBToColor(a, r, g, b); + + if (dstFormat.bytesPerPixel == 2) + *((uint16 *)dstRow) = color; + else + *((uint32 *)dstRow) = color; + + dstRow += dstFormat.bytesPerPixel; + } + } +} + +Graphics::PixelFormat SurfaceSdlGraphicsManager::getOSDFormat() { + return _osdFormat; +} #endif bool SurfaceSdlGraphicsManager::handleScalerHotkeys(Common::KeyCode key) { @@ -2492,4 +2636,22 @@ void SurfaceSdlGraphicsManager::SDL_UpdateRects(SDL_Surface *screen, int numrect } #endif // SDL_VERSION_ATLEAST(2, 0, 0) +Graphics::PixelFormat SurfaceSdlGraphicsManager::getSurfaceFormat(SDL_Surface *surface) { + Graphics::PixelFormat format; + if (surface) { + format.bytesPerPixel = surface->format->BytesPerPixel; + + format.rLoss = surface->format->Rloss; + format.gLoss = surface->format->Gloss; + format.bLoss = surface->format->Bloss; + format.aLoss = surface->format->Aloss; + + format.rShift = surface->format->Rshift; + format.gShift = surface->format->Gshift; + format.bShift = surface->format->Bshift; + format.aShift = surface->format->Ashift; + } + return format; +} + #endif diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index 25d6ff041c..d8f826aca0 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -145,6 +145,9 @@ public: #ifdef USE_OSD virtual void displayMessageOnOSD(const char *msg); + virtual void copyRectToOSD(const void *buf, int pitch, int x, int y, int w, int h); + virtual void clearOSD(); + virtual Graphics::PixelFormat getOSDFormat(); #endif // Override from Common::EventObserver @@ -160,12 +163,14 @@ public: protected: #ifdef USE_OSD - /** Surface containing the OSD message */ + /** Surface containing the OSD */ SDL_Surface *_osdSurface; - /** Transparency level of the OSD */ - uint8 _osdAlpha; + /** Surface containing the OSD message */ + SDL_Surface *_osdMessageSurface; + /** Transparency level of the OSD message */ + uint8 _osdMessageAlpha; /** When to start the fade out */ - uint32 _osdFadeStartTime; + uint32 _osdMessageFadeStartTime; /** Enum with OSD options */ enum { kOSDFadeOutDelay = 2 * 1000, /** < Delay before the OSD is faded out (in milliseconds) */ @@ -173,6 +178,11 @@ protected: kOSDColorKey = 1, /** < Transparent color key */ kOSDInitialAlpha = 80 /** < Initial alpha level, in percent */ }; + /** OSD pixel format */ + Graphics::PixelFormat _osdFormat; + + void removeOSDMessage(); + void blitOSDMessage(SDL_Rect dstRect); #endif /** Hardware screen */ @@ -358,6 +368,8 @@ protected: Common::Rect _focusRect; #endif + static Graphics::PixelFormat getSurfaceFormat(SDL_Surface *surface); + virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false); virtual void drawMouse(); |