From d2ef3ad20c80c2f939418a1d917191e9715f46f3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 13 Mar 2004 14:19:15 +0000 Subject: Added an OSD (On Screen Display) to the SDL backend svn-id: r13248 --- backends/sdl/graphics.cpp | 273 ++++++++++++++++++++++++++++++---------------- backends/sdl/sdl-common.h | 26 ++++- backends/sdl/sdl.cpp | 23 +++- 3 files changed, 222 insertions(+), 100 deletions(-) (limited to 'backends/sdl') diff --git a/backends/sdl/graphics.cpp b/backends/sdl/graphics.cpp index 307caa724a..0c9e603220 100644 --- a/backends/sdl/graphics.cpp +++ b/backends/sdl/graphics.cpp @@ -23,6 +23,7 @@ #include "backends/sdl/sdl-common.h" #include "common/scaler.h" #include "common/util.h" +#include "gui/font.h" static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { {"1x", "Normal (no scaling)", GFX_NORMAL}, @@ -107,19 +108,41 @@ bool OSystem_SDL::setGraphicsMode(int mode) { } _mode = mode; - + _scaler_proc = newScalerProc; if (newScaleFactor != _scaleFactor) { + _scaleFactor = newScaleFactor; hotswap_gfx_mode(); - } else { - _scaler_proc = newScalerProc; - _forceFull = true; + } - // Blit everything to the screen - internUpdateScreen(); - - // Make sure that an EVENT_SCREEN_CHANGED gets sent later - _modeChanged = true; + if (!_screen) + return true; + +#ifdef USE_OSD + if (_osdSurface) { + const char *newScalerName = 0; + const GraphicsMode *g = s_supportedGraphicsModes; + while (g->name) { + if (g->id == mode) { + newScalerName = g->description; + break; + } + g++; + } + if (newScalerName) { + char buffer[128]; + sprintf(buffer, "Active graphics filter: %s", newScalerName); + displayMessageOnOSD(buffer); + } } +#endif + + + // Blit everything to the screen + _forceFull = true; + internUpdateScreen(); + + // Make sure that an EVENT_SCREEN_CHANGED gets sent later + _modeChanged = true; return true; } @@ -153,69 +176,13 @@ void OSystem_SDL::load_gfx_mode() { _mode_flags |= DF_UPDATE_EXPAND_1_PIXEL; _tmpscreen = NULL; - _tmpScreenWidth = (_screenWidth + 3); - switch(_mode) { - case GFX_NORMAL: - _scaleFactor = 1; - _scaler_proc = Normal1x; - break; - case GFX_DOUBLESIZE: - _scaleFactor = 2; - _scaler_proc = Normal2x; - break; - case GFX_TRIPLESIZE: - _scaleFactor = 3; - _scaler_proc = Normal3x; - break; - - case GFX_2XSAI: - _scaleFactor = 2; - _scaler_proc = _2xSaI; - break; - case GFX_SUPER2XSAI: - _scaleFactor = 2; - _scaler_proc = Super2xSaI; - break; - case GFX_SUPEREAGLE: - _scaleFactor = 2; - _scaler_proc = SuperEagle; - break; - case GFX_ADVMAME2X: - _scaleFactor = 2; - _scaler_proc = AdvMame2x; - break; - case GFX_ADVMAME3X: - _scaleFactor = 3; - _scaler_proc = AdvMame3x; - break; - case GFX_HQ2X: - _scaleFactor = 2; - _scaler_proc = HQ2x; - break; - case GFX_HQ3X: - _scaleFactor = 3; - _scaler_proc = HQ3x; - break; - case GFX_TV2X: - _scaleFactor = 2; - _scaler_proc = TV2x; - break; - case GFX_DOTMATRIX: - _scaleFactor = 2; - _scaler_proc = DotMatrix; - break; - - default: - error("unknown gfx mode %d", _mode); - } - // // Create the surface that contains the 8 bit game data // _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth, _screenHeight, 8, 0, 0, 0, 0); if (_screen == NULL) - error("_screen failed"); + error("allocating _screen failed"); // // Create the surface that contains the scaled graphics in 16 bit mode @@ -256,16 +223,31 @@ void OSystem_SDL::load_gfx_mode() { InitScalers(565); // Need some extra bytes around when using 2xSaI - uint16 *tmp_screen = (uint16 *)calloc(_tmpScreenWidth * (_screenHeight + 3), sizeof(uint16)); - _tmpscreen = SDL_CreateRGBSurfaceFrom(tmp_screen, - _tmpScreenWidth, _screenHeight + 3, 16, _tmpScreenWidth * 2, + _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, + _screenWidth + 3, + _screenHeight + 3, + 16, _hwscreen->format->Rmask, _hwscreen->format->Gmask, _hwscreen->format->Bmask, _hwscreen->format->Amask); if (_tmpscreen == NULL) - error("_tmpscreen failed"); + error("allocating _tmpscreen failed"); + +#ifdef USE_OSD + _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); + if (_osdSurface == NULL) + error("allocating _osdSurface failed"); + SDL_SetColorKey(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, kOSDColorKey); +#endif // keyboard cursor control, some other better place for it? km.x_max = _screenWidth * _scaleFactor - 1; @@ -286,10 +268,16 @@ void OSystem_SDL::unload_gfx_mode() { } if (_tmpscreen) { - free(_tmpscreen->pixels); SDL_FreeSurface(_tmpscreen); _tmpscreen = NULL; } + +#ifdef USE_OSD + if (_osdSurface) { + SDL_FreeSurface(_osdSurface); + _osdSurface = NULL; + } +#endif } void OSystem_SDL::hotswap_gfx_mode() { @@ -304,6 +292,11 @@ void OSystem_SDL::hotswap_gfx_mode() { // Release the HW screen surface SDL_FreeSurface(_hwscreen); +#ifdef USE_OSD + // Release the OSD surface + SDL_FreeSurface(_osdSurface); +#endif + // Setup the new GFX mode load_gfx_mode(); @@ -316,7 +309,6 @@ void OSystem_SDL::hotswap_gfx_mode() { // Free the old surfaces SDL_FreeSurface(old_screen); - free(old_tmpscreen->pixels); SDL_FreeSurface(old_tmpscreen); // Blit everything to the screen @@ -364,6 +356,26 @@ void OSystem_SDL::internUpdateScreen() { _forceFull = true; } +#ifdef USE_OSD + // OSD visible (i.e. non-transparent)? + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + // Updated alpha value + const int diff = SDL_GetTicks() - _osdFadeStartTime; + if (diff > 0) { + if (diff >= kOSDFadeOutDuration) { + // Back to full transparency + _osdAlpha = 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; + } + SDL_SetAlpha(_osdSurface, SDL_RLEACCEL | SDL_SRCCOLORKEY | SDL_SRCALPHA, _osdAlpha); + _forceFull = true; + } + } +#endif + // Force a full redraw if requested if (_forceFull) { _num_dirty_rects = 1; @@ -453,6 +465,12 @@ void OSystem_SDL::internUpdateScreen() { _dirty_rect_list[0].h = effectiveScreenHeight(); } +#ifdef USE_OSD + if (_osdAlpha != SDL_ALPHA_TRANSPARENT) { + SDL_BlitSurface(_osdSurface, 0, _hwscreen, 0); + } +#endif + // Finally, blit all our changes to the screen SDL_UpdateRects(_hwscreen, _num_dirty_rects, _dirty_rect_list); } @@ -488,11 +506,21 @@ void OSystem_SDL::setFullscreenMode(bool enable) { if (!SDL_WM_ToggleFullScreen(_hwscreen)) { // if ToggleFullScreen fails, achieve the same effect with hotswap gfx mode hotswap_gfx_mode(); - } else { - // Make sure that an EVENT_SCREEN_CHANGED gets sent later - _modeChanged = true; } #endif + +#ifdef USE_OSD + if (_full_screen) + displayMessageOnOSD("Fullscreen mode"); + else + displayMessageOnOSD("Windowed mode"); +#endif + + // Blit everything to the screen + internUpdateScreen(); + + // Make sure that an EVENT_SCREEN_CHANGED gets sent later + _modeChanged = true; } } @@ -830,7 +858,7 @@ void OSystem_SDL::clear_overlay() { _forceFull = true; } -void OSystem_SDL::grab_overlay(int16 *buf, int pitch) { +void OSystem_SDL::grab_overlay(OverlayColor *buf, int pitch) { if (!_overlayVisible) return; @@ -843,18 +871,18 @@ void OSystem_SDL::grab_overlay(int16 *buf, int pitch) { if (SDL_LockSurface(_tmpscreen) == -1) error("SDL_LockSurface failed: %s", SDL_GetError()); - int16 *src = (int16 *)_tmpscreen->pixels + _tmpScreenWidth + 1; + byte *src = (byte *)_tmpscreen->pixels + _tmpscreen->pitch + 2; // Offset by one row, one column int h = _screenHeight; do { memcpy(buf, src, _screenWidth*2); - src += _tmpScreenWidth; + src += _tmpscreen->pitch; buf += pitch; } while (--h); SDL_UnlockSurface(_tmpscreen); } -void OSystem_SDL::copy_rect_overlay(const int16 *buf, int pitch, int x, int y, int w, int h) { +void OSystem_SDL::copy_rect_overlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { if (!_overlayVisible) return; @@ -894,21 +922,21 @@ void OSystem_SDL::copy_rect_overlay(const int16 *buf, int pitch, int x, int y, i if (SDL_LockSurface(_tmpscreen) == -1) error("SDL_LockSurface failed: %s", SDL_GetError()); - int16 *dst = (int16 *)_tmpscreen->pixels + (y + 1) * _tmpScreenWidth + (x + 1); + byte *dst = (byte *)_tmpscreen->pixels + (y + 1) * _tmpscreen->pitch + (x + 1) * 2; do { memcpy(dst, buf, w * 2); - dst += _tmpScreenWidth; + dst += _tmpscreen->pitch; buf += pitch; } while (--h); SDL_UnlockSurface(_tmpscreen); } -int16 OSystem_SDL::RGBToColor(uint8 r, uint8 g, uint8 b) { +OverlayColor OSystem_SDL::RGBToColor(uint8 r, uint8 g, uint8 b) { return SDL_MapRGB(_tmpscreen->format, r, g, b); } -void OSystem_SDL::colorToRGB(int16 color, uint8 &r, uint8 &g, uint8 &b) { +void OSystem_SDL::colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b) { SDL_GetRGB(color, _tmpscreen->format, &r, &g, &b); } @@ -1040,22 +1068,22 @@ void OSystem_SDL::draw_mouse() { } else { uint16 *bak = (uint16 *)_mouseBackup; // Surface used to backup the area obscured by the mouse - uint16 *dst; // Surface we are drawing into + byte *dst; // Surface we are drawing into - dst = (uint16 *)_tmpscreen->pixels + (y + 1) * _tmpScreenWidth + (x + 1); + dst = (byte *)_tmpscreen->pixels + (y + 1) * _tmpscreen->pitch + (x + 1) * 2; while (h > 0) { int width = w; while (width > 0) { - *bak++ = *dst; + *bak++ = *(uint16 *)dst; color = *src++; if (color != 0xFF) // 0xFF = transparent, don't draw - *dst = RGBToColor(_currentPalette[color].r, _currentPalette[color].g, _currentPalette[color].b); - dst++; + *(uint16 *)dst = RGBToColor(_currentPalette[color].r, _currentPalette[color].g, _currentPalette[color].b); + dst += 2; width--; } src += _mouseCurState.w - w; bak += MAX_MOUSE_W - w; - dst += _tmpScreenWidth - w; + dst += _tmpscreen->pitch - w * 2; h--; } } @@ -1113,13 +1141,14 @@ void OSystem_SDL::undraw_mouse() { } else { - uint16 *dst, *bak = (uint16 *)_mouseBackup; + byte *dst; + uint16 *bak = (uint16 *)_mouseBackup; // No need to do clipping here, since draw_mouse() did that already - dst = (uint16 *)_tmpscreen->pixels + (old_mouse_y + 1) * _tmpScreenWidth + (old_mouse_x + 1); - for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += _tmpScreenWidth) { + dst = (byte *)_tmpscreen->pixels + (old_mouse_y + 1) * _tmpscreen->pitch + (old_mouse_x + 1) * 2; + for (y = 0; y < old_mouse_h; ++y, bak += MAX_MOUSE_W, dst += _tmpscreen->pitch) { for (x = 0; x < old_mouse_w; ++x) { - dst[x] = bak[x]; + *((uint16 *)dst + x) = bak[x]; } } } @@ -1128,3 +1157,61 @@ void OSystem_SDL::undraw_mouse() { SDL_UnlockSurface(_overlayVisible ? _tmpscreen : _screen); } + + +#pragma mark - +#pragma mark --- Mouse --- +#pragma mark - + +#ifdef USE_OSD +void OSystem_SDL::displayMessageOnOSD(const char *msg) { + +// printf("displayMessageOnOSD(%s)\n", msg); + if (SDL_LockSurface(_osdSurface)) + error("displayMessageOnOSD: SDL_LockSurface failed: %s", SDL_GetError()); + + GUI::Surface dst; + dst.pixels = _osdSurface->pixels; + dst.w = _osdSurface->w; + dst.h = _osdSurface->h; + dst.pitch = _osdSurface->pitch; + dst.bytesPerPixel = _osdSurface->format->BytesPerPixel; + + // Clear everything with the "transparent" color, i.e. the colorkey + SDL_FillRect(_osdSurface, 0, kOSDColorKey); + + // Determine a rect which would contain the message string (clipped to the + // screen dimensions). + const int vOffset = 10; + int width = GUI::g_sysfont.getStringWidth(msg) + 16; + int height = GUI::g_sysfont.getFontHeight() + 2 * vOffset; + if (width > dst.w) + width = dst.w; + if (height > dst.h) + height = dst.h; + + // 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)); + + // Render the message, centered, and in white + GUI::g_sysfont.drawString(&dst, msg, osdRect.x, osdRect.y + vOffset, osdRect.w, + SDL_MapRGB(_osdSurface->format, 255, 255, 255), + GUI::kTextAlignCenter); + + 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); + + // Ensure a full redraw takes place next time the screen is updated + _forceFull = true; +} +#endif diff --git a/backends/sdl/sdl-common.h b/backends/sdl/sdl-common.h index de97a27e8d..c82ddb17c2 100644 --- a/backends/sdl/sdl-common.h +++ b/backends/sdl/sdl-common.h @@ -31,6 +31,9 @@ #include +// Uncomment this to enable the 'on screen display' code. +#define USE_OSD 1 + class OSystem_SDL : public OSystem { public: OSystem_SDL(); @@ -111,14 +114,14 @@ public: virtual void show_overlay(); virtual void hide_overlay(); virtual void clear_overlay(); - virtual void grab_overlay(int16 *buf, int pitch); - virtual void copy_rect_overlay(const int16 *buf, int pitch, int x, int y, int w, int h); + virtual void grab_overlay(OverlayColor *buf, int pitch); + virtual void copy_rect_overlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); virtual int16 get_height(); virtual int16 get_width(); // Methods that convert RGB to/from colors suitable for the overlay. - virtual int16 RGBToColor(uint8 r, uint8 g, uint8 b); - virtual void colorToRGB(int16 color, uint8 &r, uint8 &g, uint8 &b); + virtual OverlayColor RGBToColor(uint8 r, uint8 g, uint8 b); + virtual void colorToRGB(OverlayColor color, uint8 &r, uint8 &g, uint8 &b); virtual const GraphicsMode *getSupportedGraphicsModes() const; @@ -136,6 +139,20 @@ public: protected: void init_intern(); +#ifdef USE_OSD + SDL_Surface *_osdSurface; + Uint8 _osdAlpha; // Transparency level of the OSD + uint32 _osdFadeStartTime; // When to start the fade out + enum { + kOSDFadeOutDelay = 2 * 1000, // Delay before the OSD is faded out (in milliseconds) + kOSDFadeOutDuration = 500, // Duration of the OSD fade out (in milliseconds) + kOSDColorKey = 1, + kOSDInitialAlpha = 80 // Initial alpha level, in percent + }; + + void displayMessageOnOSD(const char *msg); +#endif + // hardware screen SDL_Surface *_hwscreen; @@ -145,7 +162,6 @@ protected: // temporary screen (for scalers/overlay) SDL_Surface *_tmpscreen; - int _tmpScreenWidth; bool _overlayVisible; // CD Audio diff --git a/backends/sdl/sdl.cpp b/backends/sdl/sdl.cpp index 3a32642aae..e87c661c1b 100644 --- a/backends/sdl/sdl.cpp +++ b/backends/sdl/sdl.cpp @@ -56,6 +56,8 @@ void OSystem_SDL::init_intern() { cksum_valid = false; _mode = GFX_DOUBLESIZE; + _scaleFactor = 2; + _scaler_proc = Normal2x; _full_screen = ConfMan.getBool("fullscreen"); _adjustAspectRatio = ConfMan.getBool("aspect_ratio"); _mode_flags = 0; @@ -74,8 +76,12 @@ void OSystem_SDL::init_intern() { } OSystem_SDL::OSystem_SDL() - : _hwscreen(0), _screen(0), _screenWidth(0), _screenHeight(0), - _tmpscreen(0), _tmpScreenWidth(0), _overlayVisible(false), + : +#ifdef USE_OSD + _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0), +#endif + _hwscreen(0), _screen(0), _screenWidth(0), _screenHeight(0), + _tmpscreen(0), _overlayVisible(false), _cdrom(0), _scaler_proc(0), _modeChanged(false), _dirty_checksums(0), _mouseVisible(false), _mouseDrawn(false), _mouseData(0), _mouseHotspotX(0), _mouseHotspotY(0), @@ -143,6 +149,19 @@ void OSystem_SDL::setFeatureState(Feature f, bool enable) { //assert(_hwscreen != 0); _adjustAspectRatio ^= true; hotswap_gfx_mode(); + +#ifdef USE_OSD + if (_adjustAspectRatio) + displayMessageOnOSD("Enabled aspect ratio correction"); + else + displayMessageOnOSD("Disabled aspect ratio correction"); +#endif + + // Blit everything to the screen + internUpdateScreen(); + + // Make sure that an EVENT_SCREEN_CHANGED gets sent later + _modeChanged = true; } break; case kFeatureAutoComputeDirtyRects: -- cgit v1.2.3