ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

sdl-graphics.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "backends/graphics/sdl/sdl-graphics.h"
00024 #include "backends/platform/sdl/sdl-sys.h"
00025 #include "backends/platform/sdl/sdl.h"
00026 #include "backends/events/sdl/resvm-sdl-events.h"
00027 #include "backends/keymapper/action.h"
00028 #include "backends/keymapper/keymap.h"
00029 #include "common/config-manager.h"
00030 #include "common/fs.h"
00031 #include "common/textconsole.h"
00032 #include "common/translation.h"
00033 //#include "graphics/scaler/aspect.h" // ResidualVM
00034 #if 0 // ResidualVM
00035 #ifdef USE_OSD
00036 #include "common/translation.h"
00037 #endif
00038 #endif // ResidualVM
00039 
00040 SdlGraphicsManager::SdlGraphicsManager(SdlEventSource *source, SdlWindow *window)
00041     : _eventSource(source), _window(window)// ResidualVM not used: , _hwScreen(nullptr) {
00042 #if 0 // ResidualVM
00043 #if SDL_VERSION_ATLEAST(2, 0, 0)
00044     , _allowWindowSizeReset(false), _hintedWidth(0), _hintedHeight(0), _lastFlags(0)
00045 #endif
00046 #endif // ResidualVM
00047 {
00048     // ResidualVM - not used:
00049     //SDL_GetMouseState(&_cursorX, &_cursorY);
00050 }
00051 
00052 void SdlGraphicsManager::activateManager() {
00053     _eventSource->setGraphicsManager(this);
00054 
00055     // Register the graphics manager as a event observer
00056     g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
00057 }
00058 
00059 void SdlGraphicsManager::deactivateManager() {
00060     // Unregister the event observer
00061     if (g_system->getEventManager()->getEventDispatcher()) {
00062         g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
00063     }
00064 
00065     _eventSource->setGraphicsManager(0);
00066 }
00067 
00068 SdlGraphicsManager::State SdlGraphicsManager::getState() const {
00069     State state;
00070 
00071     state.screenWidth   = getWidth();
00072     state.screenHeight  = getHeight();
00073     state.aspectRatio   = getFeatureState(OSystem::kFeatureAspectRatioCorrection);
00074     state.fullscreen    = getFeatureState(OSystem::kFeatureFullscreenMode);
00075     state.cursorPalette = getFeatureState(OSystem::kFeatureCursorPalette);
00076 #ifdef USE_RGB_COLOR
00077     state.pixelFormat   = getScreenFormat();
00078 #endif
00079     return state;
00080 }
00081 
00082 bool SdlGraphicsManager::setState(const State &state) {
00083     beginGFXTransaction();
00084 #ifdef USE_RGB_COLOR
00085         initSize(state.screenWidth, state.screenHeight, &state.pixelFormat);
00086 #else
00087         initSize(state.screenWidth, state.screenHeight, nullptr);
00088 #endif
00089         setFeatureState(OSystem::kFeatureAspectRatioCorrection, state.aspectRatio);
00090         setFeatureState(OSystem::kFeatureFullscreenMode, state.fullscreen);
00091         setFeatureState(OSystem::kFeatureCursorPalette, state.cursorPalette);
00092 
00093     if (endGFXTransaction() != OSystem::kTransactionSuccess) {
00094         return false;
00095     } else {
00096         return true;
00097     }
00098 }
00099 
00100 #if 0 // ResidualVM
00101 bool SdlGraphicsManager::defaultGraphicsModeConfig() const {
00102     const Common::ConfigManager::Domain *transientDomain = ConfMan.getDomain(Common::ConfigManager::kTransientDomain);
00103     if (transientDomain && transientDomain->contains("gfx_mode")) {
00104         const Common::String &mode = transientDomain->getVal("gfx_mode");
00105         if (!mode.equalsIgnoreCase("normal") && !mode.equalsIgnoreCase("default")) {
00106             return false;
00107         }
00108     }
00109 
00110     const Common::ConfigManager::Domain *gameDomain = ConfMan.getActiveDomain();
00111     if (gameDomain && gameDomain->contains("gfx_mode")) {
00112         const Common::String &mode = gameDomain->getVal("gfx_mode");
00113         if (!mode.equalsIgnoreCase("normal") && !mode.equalsIgnoreCase("default")) {
00114             return false;
00115         }
00116     }
00117 
00118     return true;
00119 }
00120 
00121 int SdlGraphicsManager::getGraphicsModeIdByName(const Common::String &name) const {
00122     if (name == "normal" || name == "default") {
00123         return getDefaultGraphicsMode();
00124     }
00125 
00126     const OSystem::GraphicsMode *mode = getSupportedGraphicsModes();
00127     while (mode && mode->name != nullptr) {
00128         if (name.equalsIgnoreCase(mode->name)) {
00129             return mode->id;
00130         }
00131         ++mode;
00132     }
00133     return -1;
00134 }
00135 
00136 void SdlGraphicsManager::initSizeHint(const Graphics::ModeList &modes) {
00137 #if SDL_VERSION_ATLEAST(2, 0, 0)
00138     const bool useDefault = defaultGraphicsModeConfig();
00139 
00140     int scale = getGraphicsModeScale(getGraphicsModeIdByName(ConfMan.get("gfx_mode")));
00141     if (scale == -1) {
00142         warning("Unknown scaler; defaulting to 1");
00143         scale = 1;
00144     }
00145 
00146     int16 bestWidth = 0, bestHeight = 0;
00147     const Graphics::ModeList::const_iterator end = modes.end();
00148     for (Graphics::ModeList::const_iterator it = modes.begin(); it != end; ++it) {
00149         int16 width = it->width, height = it->height;
00150 
00151         // TODO: Normalize AR correction by passing a PAR in the mode list
00152         // instead of checking the dimensions here like this, since not all
00153         // 320x200/640x400 uses are with non-square pixels (e.g. DreamWeb).
00154         if (ConfMan.getBool("aspect_ratio")) {
00155             if ((width == 320 && height == 200) || (width == 640 && height == 400)) {
00156                 height = real2Aspect(height);
00157             }
00158         }
00159 
00160         if (!useDefault || width <= 320) {
00161             width *= scale;
00162             height *= scale;
00163         }
00164 
00165         if (bestWidth < width) {
00166             bestWidth = width;
00167         }
00168 
00169         if (bestHeight < height) {
00170             bestHeight = height;
00171         }
00172     }
00173 
00174     _hintedWidth = bestWidth;
00175     _hintedHeight = bestHeight;
00176 #endif
00177 }
00178 
00179 bool SdlGraphicsManager::showMouse(bool visible) {
00180     if (visible == _cursorVisible) {
00181         return visible;
00182     }
00183 
00184     int showCursor = SDL_DISABLE;
00185     if (visible) {
00186         // _cursorX and _cursorY are currently always clipped to the active
00187         // area, so we need to ask SDL where the system's mouse cursor is
00188         // instead
00189         int x, y;
00190         SDL_GetMouseState(&x, &y);
00191         if (!_activeArea.drawRect.contains(Common::Point(x, y))) {
00192             showCursor = SDL_ENABLE;
00193         }
00194     }
00195     SDL_ShowCursor(showCursor);
00196 
00197     return WindowedGraphicsManager::showMouse(visible);
00198 }
00199 
00200 bool SdlGraphicsManager::notifyMousePosition(Common::Point &mouse) {
00201     int showCursor = SDL_DISABLE;
00202     bool valid = true;
00203     if (_activeArea.drawRect.contains(mouse)) {
00204         _cursorLastInActiveArea = true;
00205     } else {
00206         mouse.x = CLIP<int>(mouse.x, _activeArea.drawRect.left, _activeArea.drawRect.right - 1);
00207         mouse.y = CLIP<int>(mouse.y, _activeArea.drawRect.top, _activeArea.drawRect.bottom - 1);
00208 
00209         if (_window->mouseIsGrabbed() ||
00210             // Keep the mouse inside the game area during dragging to prevent an
00211             // event mismatch where the mouseup event gets lost because it is
00212             // performed outside of the game area
00213             (_cursorLastInActiveArea && SDL_GetMouseState(nullptr, nullptr) != 0)) {
00214             setSystemMousePosition(mouse.x, mouse.y);
00215         } else {
00216             // Allow the in-game mouse to get a final movement event to the edge
00217             // of the window if the mouse was moved out of the game area
00218             if (_cursorLastInActiveArea) {
00219                 _cursorLastInActiveArea = false;
00220             } else if (_cursorVisible) {
00221                 // Keep sending events to the game if the cursor is invisible,
00222                 // since otherwise if a game lets you skip a cutscene by
00223                 // clicking and the user moved the mouse outside the active
00224                 // area, the clicks wouldn't do anything, which would be
00225                 // confusing
00226                 valid = false;
00227             }
00228 
00229             if (_cursorVisible) {
00230                 showCursor = SDL_ENABLE;
00231             }
00232         }
00233     }
00234 
00235     SDL_ShowCursor(showCursor);
00236     if (valid) {
00237         setMousePosition(mouse.x, mouse.y);
00238         mouse = convertWindowToVirtual(mouse.x, mouse.y);
00239     }
00240     return valid;
00241 }
00242 
00243 void SdlGraphicsManager::setSystemMousePosition(const int x, const int y) {
00244     assert(_window);
00245     if (!_window->warpMouseInWindow(x, y)) {
00246         const Common::Point mouse = convertWindowToVirtual(x, y);
00247         _eventSource->fakeWarpMouse(mouse.x, mouse.y);
00248     }
00249 }
00250 
00251 void SdlGraphicsManager::handleResizeImpl(const int width, const int height, const int xdpi, const int ydpi) {
00252     _forceRedraw = true;
00253 }
00254 
00255 #if SDL_VERSION_ATLEAST(2, 0, 0)
00256 bool SdlGraphicsManager::createOrUpdateWindow(int width, int height, const Uint32 flags) {
00257     if (!_window) {
00258         return false;
00259     }
00260 
00261     // We only update the actual window when flags change (which usually means
00262     // fullscreen mode is entered/exited), when updates are forced so that we
00263     // do not reset the window size whenever a game makes a call to change the
00264     // size or pixel format of the internal game surface (since a user may have
00265     // resized the game window), or when the launcher is visible (since a user
00266     // may change the scaler, which should reset the window size)
00267     if (!_window->getSDLWindow() || _lastFlags != flags || _overlayVisible || _allowWindowSizeReset) {
00268         const bool fullscreen = (flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0;
00269         if (!fullscreen) {
00270             if (_hintedWidth) {
00271                 width = _hintedWidth;
00272             }
00273             if (_hintedHeight) {
00274                 height = _hintedHeight;
00275             }
00276         }
00277 
00278         if (!_window->createOrUpdateWindow(width, height, flags)) {
00279             return false;
00280         }
00281 
00282         _lastFlags = flags;
00283         _allowWindowSizeReset = false;
00284     }
00285 
00286     return true;
00287 }
00288 #endif
00289 
00290 void SdlGraphicsManager::saveScreenshot() {
00291     Common::String filename;
00292 
00293     Common::String screenshotsPath;
00294     OSystem_SDL *sdl_g_system = dynamic_cast<OSystem_SDL*>(g_system);
00295     if (sdl_g_system)
00296         screenshotsPath = sdl_g_system->getScreenshotsPath();
00297 
00298     // Use the name of the running target as a base for screenshot file names
00299     Common::String currentTarget = ConfMan.getActiveDomainName();
00300 
00301 #ifdef USE_PNG
00302     const char *extension = "png";
00303 #else
00304     const char *extension = "bmp";
00305 #endif
00306 
00307     for (int n = 0;; n++) {
00308         filename = Common::String::format("scummvm%s%s-%05d.%s", currentTarget.empty() ? "" : "-",
00309                                           currentTarget.c_str(), n, extension);
00310 
00311         Common::FSNode file = Common::FSNode(screenshotsPath + filename);
00312         if (!file.exists()) {
00313             break;
00314         }
00315     }
00316 
00317     if (saveScreenshot(screenshotsPath + filename)) {
00318         if (screenshotsPath.empty())
00319             debug("Saved screenshot '%s' in current directory", filename.c_str());
00320         else
00321             debug("Saved screenshot '%s' in directory '%s'", filename.c_str(), screenshotsPath.c_str());
00322     } else {
00323         if (screenshotsPath.empty())
00324             warning("Could not save screenshot in current directory");
00325         else
00326             warning("Could not save screenshot in directory '%s'", screenshotsPath.c_str());
00327     }
00328 }
00329 
00330 bool SdlGraphicsManager::notifyEvent(const Common::Event &event) {
00331     if (event.type != Common::EVENT_CUSTOM_BACKEND_ACTION_START) {
00332         return false;
00333     }
00334 
00335     switch ((CustomEventAction) event.customType) {
00336     case kActionToggleMouseCapture:
00337         getWindow()->toggleMouseGrab();
00338         return true;
00339 
00340     case kActionToggleFullscreen:
00341         toggleFullScreen();
00342         return true;
00343 
00344     case kActionSaveScreenshot:
00345         saveScreenshot();
00346         return true;
00347 
00348     default:
00349         return false;
00350     }
00351 }
00352 
00353 void SdlGraphicsManager::toggleFullScreen() {
00354     if (!g_system->hasFeature(OSystem::kFeatureFullscreenMode))
00355         return;
00356 
00357     beginGFXTransaction();
00358     setFeatureState(OSystem::kFeatureFullscreenMode, !getFeatureState(OSystem::kFeatureFullscreenMode));
00359     endGFXTransaction();
00360 #ifdef USE_OSD
00361     if (getFeatureState(OSystem::kFeatureFullscreenMode))
00362         displayMessageOnOSD(_("Fullscreen mode"));
00363     else
00364         displayMessageOnOSD(_("Windowed mode"));
00365 #endif
00366 }
00367 #endif // ResidualVM
00368 Common::Keymap *SdlGraphicsManager::getKeymap() {
00369     using namespace Common;
00370 
00371     Keymap *keymap = new Keymap(Keymap::kKeymapTypeGlobal, "sdl-graphics", _("Graphics"));
00372     Action *act;
00373 
00374     if (g_system->hasFeature(OSystem::kFeatureFullscreenMode)) {
00375         act = new Action("FULS", _("Toggle fullscreen"));
00376         act->addDefaultInputMapping("A+RETURN");
00377         act->addDefaultInputMapping("A+KP_ENTER");
00378         act->setCustomBackendActionEvent(kActionToggleFullscreen);
00379         keymap->addAction(act);
00380     }
00381 
00382     act = new Action("CAPT", _("Toggle mouse capture"));
00383     act->addDefaultInputMapping("C+m");
00384     act->setCustomBackendActionEvent(kActionToggleMouseCapture);
00385     keymap->addAction(act);
00386 
00387     act = new Action("SCRS", _("Save screenshot"));
00388     act->addDefaultInputMapping("A+s");
00389     act->setCustomBackendActionEvent(kActionSaveScreenshot);
00390     keymap->addAction(act);
00391 
00392     if (hasFeature(OSystem::kFeatureAspectRatioCorrection)) {
00393         act = new Action("ASPT", _("Toggle aspect ratio correction"));
00394         act->addDefaultInputMapping("C+A+a");
00395         act->setCustomBackendActionEvent(kActionToggleAspectRatioCorrection);
00396         keymap->addAction(act);
00397     }
00398 #if 0 // ResidualVM: not used
00399     if (hasFeature(OSystem::kFeatureFilteringMode)) {
00400         act = new Action("FILT", _("Toggle linear filtered scaling"));
00401         act->addDefaultInputMapping("C+A+f");
00402         act->setCustomBackendActionEvent(kActionToggleFilteredScaling);
00403         keymap->addAction(act);
00404     }
00405 
00406     if (hasFeature(OSystem::kFeatureStretchMode)) {
00407         act = new Action("STCH", _("Cycle through stretch modes"));
00408         act->addDefaultInputMapping("C+A+s");
00409         act->setCustomBackendActionEvent(kActionCycleStretchMode);
00410         keymap->addAction(act);
00411     }
00412 
00413     act = new Action("SCL+", _("Increase the scale factor"));
00414     act->addDefaultInputMapping("C+A+PLUS");
00415     act->addDefaultInputMapping("C+A+KP_PLUS");
00416     act->setCustomBackendActionEvent(kActionIncreaseScaleFactor);
00417     keymap->addAction(act);
00418 
00419     act = new Action("SCL-", _("Decrease the scale factor"));
00420     act->addDefaultInputMapping("C+A+MINUS");
00421     act->addDefaultInputMapping("C+A+KP_MINUS");
00422     act->setCustomBackendActionEvent(kActionDecreaseScaleFactor);
00423     keymap->addAction(act);
00424 
00425 #ifdef USE_SCALERS
00426     struct ActionEntry {
00427         const char *id;
00428         const char *description;
00429     };
00430     static const ActionEntry filters[] = {
00431             { "FLT1", _s("Switch to nearest neighbour scaling") },
00432             { "FLT2", _s("Switch to AdvMame 2x/3x scaling")     },
00433 #ifdef USE_HQ_SCALERS
00434             { "FLT3", _s("Switch to HQ 2x/3x scaling")          },
00435 #endif
00436             { "FLT4", _s("Switch to 2xSai scaling")             },
00437             { "FLT5", _s("Switch to Super2xSai scaling")        },
00438             { "FLT6", _s("Switch to SuperEagle scaling")        },
00439             { "FLT7", _s("Switch to TV 2x scaling")             },
00440             { "FLT8", _s("Switch to DotMatrix scaling")         }
00441     };
00442 
00443     for (uint i = 0; i < ARRAYSIZE(filters); i++) {
00444         act = new Action(filters[i].id, filters[i].description);
00445         act->addDefaultInputMapping(String::format("C+A+%d", i + 1));
00446         act->addDefaultInputMapping(String::format("C+A+KP%d", i + 1));
00447         act->setCustomBackendActionEvent(kActionSetScaleFilter1 + i);
00448         keymap->addAction(act);
00449     }
00450 #endif
00451 #endif // ResidualVM
00452     return keymap;
00453 }


Generated on Sat Aug 8 2020 05:01:04 for ResidualVM by doxygen 1.7.1
curved edge   curved edge