1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef BACKENDS_GRAPHICS_SURFACESDL_GRAPHICS_H 24 #define BACKENDS_GRAPHICS_SURFACESDL_GRAPHICS_H 25 26 #include "backends/graphics/graphics.h" 27 #include "backends/graphics/sdl/sdl-graphics.h" 28 #include "graphics/pixelformat.h" 29 #include "graphics/scaler.h" 30 #include "common/events.h" 31 #include "common/system.h" 32 33 #include "backends/events/sdl/sdl-events.h" 34 35 #include "backends/platform/sdl/sdl-sys.h" 36 37 #ifndef RELEASE_BUILD 38 // Define this to allow for focus rectangle debugging 39 #define USE_SDL_DEBUG_FOCUSRECT 40 #endif 41 42 enum { 43 GFX_NORMAL = 0, 44 GFX_DOUBLESIZE = 1, 45 GFX_TRIPLESIZE = 2, 46 GFX_2XSAI = 3, 47 GFX_SUPER2XSAI = 4, 48 GFX_SUPEREAGLE = 5, 49 GFX_ADVMAME2X = 6, 50 GFX_ADVMAME3X = 7, 51 GFX_HQ2X = 8, 52 GFX_HQ3X = 9, 53 GFX_TV2X = 10, 54 GFX_DOTMATRIX = 11 55 }; 56 57 58 class AspectRatio { 59 int _kw, _kh; 60 public: AspectRatio()61 AspectRatio() { _kw = _kh = 0; } 62 AspectRatio(int w, int h); 63 isAuto()64 bool isAuto() const { return (_kw | _kh) == 0; } 65 kw()66 int kw() const { return _kw; } kh()67 int kh() const { return _kh; } 68 }; 69 70 /** 71 * SDL graphics manager 72 */ 73 class SurfaceSdlGraphicsManager : public SdlGraphicsManager { 74 public: 75 SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSource, SdlWindow *window); 76 virtual ~SurfaceSdlGraphicsManager(); 77 78 virtual void activateManager() override; 79 virtual void deactivateManager() override; 80 81 virtual bool hasFeature(OSystem::Feature f) const override; 82 virtual void setFeatureState(OSystem::Feature f, bool enable) override; 83 virtual bool getFeatureState(OSystem::Feature f) const override; 84 85 virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override; 86 virtual int getDefaultGraphicsMode() const override; 87 virtual bool setGraphicsMode(int mode) override; 88 virtual int getGraphicsMode() const override; 89 virtual void resetGraphicsScale() override; 90 #ifdef USE_RGB_COLOR getScreenFormat()91 virtual Graphics::PixelFormat getScreenFormat() const override { return _screenFormat; } 92 virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const override; 93 #endif 94 virtual const OSystem::GraphicsMode *getSupportedShaders() const override; 95 virtual int getShader() const override; 96 virtual bool setShader(int id) override; 97 #if SDL_VERSION_ATLEAST(2, 0, 0) 98 virtual const OSystem::GraphicsMode *getSupportedStretchModes() const override; 99 virtual int getDefaultStretchMode() const override; 100 virtual bool setStretchMode(int mode) override; 101 virtual int getStretchMode() const override; 102 #endif 103 virtual void initSize(uint w, uint h, const Graphics::PixelFormat *format = NULL) override; getScreenChangeID()104 virtual int getScreenChangeID() const override { return _screenChangeCount; } 105 106 virtual void beginGFXTransaction() override; 107 virtual OSystem::TransactionError endGFXTransaction() override; 108 109 virtual int16 getHeight() const override; 110 virtual int16 getWidth() const override; 111 112 protected: 113 // PaletteManager API 114 virtual void setPalette(const byte *colors, uint start, uint num) override; 115 virtual void grabPalette(byte *colors, uint start, uint num) const override; 116 117 /** 118 * Convert from the SDL pixel format to Graphics::PixelFormat 119 * @param in The SDL pixel format to convert 120 * @param out A pixel format to be written to 121 */ 122 Graphics::PixelFormat convertSDLPixelFormat(SDL_PixelFormat *in) const; 123 public: 124 virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) override; 125 virtual Graphics::Surface *lockScreen() override; 126 virtual void unlockScreen() override; 127 virtual void fillScreen(uint32 col) override; 128 virtual void updateScreen() override; 129 virtual void setFocusRectangle(const Common::Rect& rect) override; 130 virtual void clearFocusRectangle() override; 131 getOverlayFormat()132 virtual Graphics::PixelFormat getOverlayFormat() const override { return _overlayFormat; } 133 virtual void clearOverlay() override; 134 virtual void grabOverlay(void *buf, int pitch) const override; 135 virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override; getOverlayHeight()136 virtual int16 getOverlayHeight() const override { return _videoMode.overlayHeight; } getOverlayWidth()137 virtual int16 getOverlayWidth() const override { return _videoMode.overlayWidth; } 138 139 virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) override; 140 virtual void setCursorPalette(const byte *colors, uint start, uint num) override; 141 142 #ifdef USE_OSD 143 virtual void displayMessageOnOSD(const char *msg) override; 144 virtual void displayActivityIconOnOSD(const Graphics::Surface *icon) override; 145 #endif 146 147 // Override from Common::EventObserver 148 virtual bool notifyEvent(const Common::Event &event) override; 149 150 // SdlGraphicsManager interface 151 virtual void notifyVideoExpose() override; 152 virtual void notifyResize(const int width, const int height) override; 153 154 protected: 155 #ifdef USE_OSD 156 /** Surface containing the OSD message */ 157 SDL_Surface *_osdMessageSurface; 158 /** Transparency level of the OSD message */ 159 uint8 _osdMessageAlpha; 160 /** When to start the fade out */ 161 uint32 _osdMessageFadeStartTime; 162 /** Enum with OSD options */ 163 enum { 164 kOSDFadeOutDelay = 2 * 1000, /** < Delay before the OSD is faded out (in milliseconds) */ 165 kOSDFadeOutDuration = 500, /** < Duration of the OSD fade out (in milliseconds) */ 166 kOSDInitialAlpha = 80 /** < Initial alpha level, in percent */ 167 }; 168 /** Screen rectangle where the OSD message is drawn */ 169 SDL_Rect getOSDMessageRect() const; 170 /** Clear the currently displayed OSD message if any */ 171 void removeOSDMessage(); 172 /** Surface containing the OSD background activity icon */ 173 SDL_Surface *_osdIconSurface; 174 /** Screen rectangle where the OSD background activity icon is drawn */ 175 SDL_Rect getOSDIconRect() const; 176 177 void updateOSD(); 178 void drawOSD(); 179 #endif 180 gameNeedsAspectRatioCorrection()181 virtual bool gameNeedsAspectRatioCorrection() const override { 182 return _videoMode.aspectRatioCorrection; 183 } getGameRenderScale()184 virtual int getGameRenderScale() const override { 185 return _videoMode.scaleFactor; 186 } 187 188 virtual void handleResizeImpl(const int width, const int height, const int xdpi, const int ydpi) override; 189 190 virtual int getGraphicsModeScale(int mode) const override; 191 virtual ScalerProc *getGraphicsScalerProc(int mode) const; 192 193 #if SDL_VERSION_ATLEAST(2, 0, 0) 194 /* SDL2 features a different API for 2D graphics. We create a wrapper 195 * around this API to keep the code paths as close as possible. */ 196 SDL_Renderer *_renderer; 197 SDL_Texture *_screenTexture; 198 void deinitializeRenderer(); 199 void recreateScreenTexture(); 200 201 virtual SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); 202 virtual void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects); 203 #endif 204 205 /** Unseen game screen */ 206 SDL_Surface *_screen; 207 Graphics::PixelFormat _screenFormat; 208 Graphics::PixelFormat _cursorFormat; 209 #ifdef USE_RGB_COLOR 210 Common::List<Graphics::PixelFormat> _supportedFormats; 211 212 /** 213 * Update the list of supported pixel formats. 214 * This method is invoked by loadGFXMode(). 215 */ 216 void detectSupportedFormats(); 217 #endif 218 219 /** Temporary screen (for scalers) */ 220 SDL_Surface *_tmpscreen; 221 /** Temporary screen (for scalers) */ 222 SDL_Surface *_tmpscreen2; 223 224 SDL_Surface *_overlayscreen; 225 Graphics::PixelFormat _overlayFormat; 226 227 enum { 228 kTransactionNone = 0, 229 kTransactionActive = 1, 230 kTransactionRollback = 2 231 }; 232 233 struct TransactionDetails { 234 bool sizeChanged; 235 bool needHotswap; 236 bool needUpdatescreen; 237 #if SDL_VERSION_ATLEAST(2, 0, 0) 238 bool needTextureUpdate; 239 bool needDisplayResize; 240 #endif 241 #ifdef USE_RGB_COLOR 242 bool formatChanged; 243 #endif 244 TransactionDetailsTransactionDetails245 TransactionDetails() { 246 sizeChanged = false; 247 needHotswap = false; 248 needUpdatescreen = false; 249 250 #if SDL_VERSION_ATLEAST(2, 0, 0) 251 needTextureUpdate = false; 252 needDisplayResize = false; 253 #endif 254 #ifdef USE_RGB_COLOR 255 formatChanged = false; 256 #endif 257 } 258 }; 259 TransactionDetails _transactionDetails; 260 261 struct VideoState { 262 bool setup; 263 264 bool fullscreen; 265 bool aspectRatioCorrection; 266 AspectRatio desiredAspectRatio; 267 bool filtering; 268 269 #if SDL_VERSION_ATLEAST(2, 0, 0) 270 int stretchMode; 271 #endif 272 273 int mode; 274 int scaleFactor; 275 276 int screenWidth, screenHeight; 277 int overlayWidth, overlayHeight; 278 int hardwareWidth, hardwareHeight; 279 #ifdef USE_RGB_COLOR 280 Graphics::PixelFormat format; 281 #endif 282 VideoStateVideoState283 VideoState() { 284 setup = false; 285 fullscreen = false; 286 aspectRatioCorrection = false; 287 // desiredAspectRatio set to (0, 0) by AspectRatio constructor 288 filtering = false; 289 290 #if SDL_VERSION_ATLEAST(2, 0, 0) 291 stretchMode = 0; 292 #endif 293 294 mode = 0; 295 scaleFactor = 0; 296 297 screenWidth = 0; 298 screenHeight = 0; 299 overlayWidth = 0; 300 overlayHeight = 0; 301 hardwareWidth = 0; 302 hardwareHeight = 0; 303 #ifdef USE_RGB_COLOR 304 // format set to 0 values by Graphics::PixelFormat constructor 305 #endif 306 } 307 }; 308 VideoState _videoMode, _oldVideoMode; 309 310 #if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0) 311 /** 312 * Original BPP to restore the video mode on unload. 313 * 314 * This is required to make listing video modes for the OpenGL output work 315 * on Windows 8+. On these systems OpenGL modes are only available for 316 * 32bit formats. However, we setup a 16bit format and thus mode listings 317 * for OpenGL will return an empty list afterwards. 318 * 319 * In theory we might require this behavior on non-Win32 platforms too. 320 * However, SDL sometimes gives us invalid pixel formats for X11 outputs 321 * causing crashes when trying to setup the original pixel format. 322 * See bug #7038 "IRIX: X BadMatch when trying to start any 640x480 game". 323 */ 324 uint8 _originalBitsPerPixel; 325 #endif 326 327 ScalerProc *_scalerProc; 328 int _scalerType; 329 int _transactionMode; 330 331 // Indicates whether it is needed to free _hwSurface in destructor 332 bool _displayDisabled; 333 334 bool _screenIsLocked; 335 Graphics::Surface _framebuffer; 336 337 int _screenChangeCount; 338 339 int _currentShader; 340 int _numShaders; 341 342 enum { 343 NUM_DIRTY_RECT = 100, 344 MAX_SCALING = 3 345 }; 346 347 // Dirty rect management 348 SDL_Rect _dirtyRectList[NUM_DIRTY_RECT]; 349 int _numDirtyRects; 350 351 struct MousePos { 352 // The size and hotspot of the original cursor image. 353 int16 w, h; 354 int16 hotX, hotY; 355 356 // The size and hotspot of the pre-scaled cursor image, in real 357 // coordinates. 358 int16 rW, rH; 359 int16 rHotX, rHotY; 360 361 // The size and hotspot of the pre-scaled cursor image, in game 362 // coordinates. 363 int16 vW, vH; 364 int16 vHotX, vHotY; 365 MousePosMousePos366 MousePos() : w(0), h(0), hotX(0), hotY(0), 367 rW(0), rH(0), rHotX(0), rHotY(0), vW(0), vH(0), 368 vHotX(0), vHotY(0) 369 { } 370 }; 371 372 byte *_mouseData; 373 SDL_Rect _mouseBackup; 374 MousePos _mouseCurState; 375 #ifdef USE_RGB_COLOR 376 uint32 _mouseKeyColor; 377 #else 378 byte _mouseKeyColor; 379 #endif 380 bool _cursorDontScale; 381 bool _cursorPaletteDisabled; 382 SDL_Surface *_mouseOrigSurface; 383 SDL_Surface *_mouseSurface; 384 enum { 385 kMouseColorKey = 1 386 }; 387 388 // Shake mode 389 // This is always set to 0 when building with SDL2. 390 int _currentShakeXOffset; 391 int _currentShakeYOffset; 392 393 // Palette data 394 SDL_Color *_currentPalette; 395 uint _paletteDirtyStart, _paletteDirtyEnd; 396 397 // Cursor palette data 398 SDL_Color *_cursorPalette; 399 400 /** 401 * Mutex which prevents multiple threads from interfering with each other 402 * when accessing the screen. 403 */ 404 OSystem::MutexRef _graphicsMutex; 405 406 #ifdef USE_SDL_DEBUG_FOCUSRECT 407 bool _enableFocusRectDebugCode; 408 bool _enableFocusRect; 409 Common::Rect _focusRect; 410 #endif 411 412 virtual void addDirtyRect(int x, int y, int w, int h, bool realCoordinates = false); 413 414 virtual void drawMouse(); 415 virtual void undrawMouse(); 416 virtual void blitCursor(); 417 418 virtual void internUpdateScreen(); 419 virtual void updateShader(); 420 421 virtual bool loadGFXMode(); 422 virtual void unloadGFXMode(); 423 virtual bool hotswapGFXMode(); 424 425 virtual void setAspectRatioCorrection(bool enable); 426 void setFilteringMode(bool enable); 427 428 virtual bool saveScreenshot(const Common::String &filename) const; 429 virtual void setGraphicsModeIntern(); 430 431 private: 432 void setFullscreenMode(bool enable); 433 bool handleScalerHotkeys(Common::KeyCode key); 434 bool isScalerHotkey(const Common::Event &event); 435 436 /** 437 * Converts the given point from the overlay's coordinate space to the 438 * game's coordinate space. 439 */ convertOverlayToGame(const int x,const int y)440 Common::Point convertOverlayToGame(const int x, const int y) const { 441 if (getOverlayWidth() == 0 || getOverlayHeight() == 0) { 442 error("convertOverlayToGame called without a valid overlay"); 443 } 444 445 return Common::Point(x * getWidth() / getOverlayWidth(), 446 y * getHeight() / getOverlayHeight()); 447 } 448 449 /** 450 * Converts the given point from the game's coordinate space to the 451 * overlay's coordinate space. 452 */ convertGameToOverlay(const int x,const int y)453 Common::Point convertGameToOverlay(const int x, const int y) const { 454 if (getWidth() == 0 || getHeight() == 0) { 455 error("convertGameToOverlay called without a valid overlay"); 456 } 457 458 return Common::Point(x * getOverlayWidth() / getWidth(), 459 y * getOverlayHeight() / getHeight()); 460 } 461 }; 462 463 #endif 464