diff --git a/NEWS.md b/NEWS.md index ec8c034be..fc7ae3f0c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,7 +8,7 @@ First release, a major update to the application compared to the RetroPie versio Full navigation sound support has been implemented, and the metadata editor has seen a lot of updates including color coding of all changes done by the user and by the scraper. Favorite games can now also be sorted on top of the gamelists and game collections. -OpenGL GLSL shader support has been added (not for the OpenGL ES renderer though) which will open up many possibilities in the future. +OpenGL GLSL shader support has been added (not for the OpenGL ES renderer though) and there are multiple effects implemented such as scanlines for videos, blurred background when opening menus etc. A new default theme rbsimple-DE (based on Recalbox Multi) is bundled with the application and is part of the installation package/installer. However themes created for other EmulationStation ports should still work correctly. @@ -31,6 +31,7 @@ Many bugs have been fixed, and numerous features that were only partially implem * Updated the application to compile and work on Microsoft Windows, including full UTF-16 (Unicode) support * Updated the application to compile and work on Apple macOS * Added support for OpenGL GLSL shaders (OpenGL 2.1 renderer only, no support for OpenGL ES 1.0 renderer) +* Added multiple animations and shader effects, such as when opening menus, playing videos in the gamelists and via the screensaver etc. * Seamless (almost) launch of games without showing the desktop when starting and when returning from RetroArch and other emulators * Per-game launch command override, so that different cores or emulators can be used on a per-game basis (saved to gamelist.xml) * Core location can be defined relative to the emulator binary using the %EMUPATH% variable in es_systems.cfg (mostly useful for Windows) diff --git a/USERGUIDE.md b/USERGUIDE.md index c961c4f87..6a091c6e5 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -547,6 +547,14 @@ Defaults to Full which enables all functionality within the application. If set The order in which to sort your gamelists. This can be overriden per game system using the game options menu, but that override will only be persistent during the application session. +**Open menu effect** _(OpenGL renderer only)_ + +Animation to play when opening the main menu or the game options menu. Can be set to _scale-up_, _fade-in_ or _none_. + +**Render scanlines for gamelist videos** _(OpenGL renderer only)_ + +Whether to use a shader to render scanlines for videos in the gamelist view. + **Sort folders on top of gamelists** Whether to place all folders on top of the gamelists. If done so, the folders will not be part of the quick selector index, meaning they can no longer be quick-jumped to. Also, if this option is enabled, folders marked as favorites will not be sorted above non-favorite folders. @@ -591,22 +599,6 @@ This includes the ability to start the screensaver manually, but also to browse The screensaven style to use, which includes _Dim_, _Black_, _Slideshow_ and _Video_. -#### Video screensaver settings - -Options specific to the video screensaver. - -**Swap videos after (secs)** - -How long to play videos before change to the next game. - -**Stretch videos to screen resolution** - -This will fill the entire screen surface but will possibly break the aspect ratio of the video. - -**Play audio for screensaver video files** - -Muting or playing the audio. - #### Slideshow screensaver settings Options specific to the slideshow screensaver. @@ -619,6 +611,10 @@ How long to show images before change to the next game. This will fill the entire screen surface but will possibly break the aspect ratio of the image. +**Render scanlines** _(OpenGL renderer only)_ + +Whether to use a shader to render scanlines on top of the images. + **Background audio** Background audio to play when the screensaver is active. @@ -639,6 +635,30 @@ Whether to search the custom image directory recursively. The file extensions to consider for the custom images. +#### Video screensaver settings + +Options specific to the video screensaver. + +**Swap videos after (secs)** + +How long to play videos before change to the next game. + +**Stretch videos to screen resolution** + +This will fill the entire screen surface but will possibly break the aspect ratio of the video. + +**Play audio for screensaver video files** + +Muting or playing the audio. + +**Render scanlines** _(OpenGL renderer only)_ + +Whether to use a shader to render scanlines for the videos. + +**Render blur** _(OpenGL renderer only)_ + +Whether to use a shader to render a slight blur which somewhat simulates a well-used CRT monitor. + ### Sound settings diff --git a/es-app/src/SystemScreenSaver.cpp b/es-app/src/SystemScreenSaver.cpp index 82a3f4c9f..39ab7b930 100644 --- a/es-app/src/SystemScreenSaver.cpp +++ b/es-app/src/SystemScreenSaver.cpp @@ -251,10 +251,12 @@ void SystemScreenSaver::renderScreenSaver() } } else if (mState != STATE_INACTIVE) { + #if !defined(USE_OPENGL_21) Renderer::setMatrix(Transform4x4f::Identity()); unsigned char color = screensaver_behavior == "dim" ? 0x000000A0 : 0x000000FF; Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), color, color); + #endif } } diff --git a/es-app/src/SystemScreenSaver.h b/es-app/src/SystemScreenSaver.h index 65e7dbd4c..7c458b267 100644 --- a/es-app/src/SystemScreenSaver.h +++ b/es-app/src/SystemScreenSaver.h @@ -32,7 +32,8 @@ public: virtual FileData* getCurrentGame(); virtual void launchGame(); - inline virtual void resetCounts() { mVideosCounted = false; mImagesCounted = false; }; + virtual void resetCounts() { mVideosCounted = false; mImagesCounted = false; }; + virtual unsigned int getVideoCount() { return mVideoCount; }; private: unsigned long countGameListNodes(const char *nodeName); diff --git a/es-app/src/guis/GuiGeneralScreensaverOptions.cpp b/es-app/src/guis/GuiGeneralScreensaverOptions.cpp index 05711cc4b..6189449e7 100644 --- a/es-app/src/guis/GuiGeneralScreensaverOptions.cpp +++ b/es-app/src/guis/GuiGeneralScreensaverOptions.cpp @@ -66,14 +66,6 @@ GuiGeneralScreensaverOptions::GuiGeneralScreensaverOptions(Window* window, const ComponentListRow row; // Show filtered menu. - row.elements.clear(); - row.addElement(std::make_shared(mWindow, - "VIDEO SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); - row.addElement(makeArrow(mWindow), false); - row.makeAcceptInputHandler(std::bind( - &GuiGeneralScreensaverOptions::openVideoScreensaverOptions, this)); - addRow(row); - row.elements.clear(); row.addElement(std::make_shared(mWindow, "SLIDESHOW SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); @@ -81,6 +73,14 @@ GuiGeneralScreensaverOptions::GuiGeneralScreensaverOptions(Window* window, const row.makeAcceptInputHandler(std::bind( &GuiGeneralScreensaverOptions::openSlideshowScreensaverOptions, this)); addRow(row); + + row.elements.clear(); + row.addElement(std::make_shared(mWindow, + "VIDEO SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); + row.addElement(makeArrow(mWindow), false); + row.makeAcceptInputHandler(std::bind( + &GuiGeneralScreensaverOptions::openVideoScreensaverOptions, this)); + addRow(row); } GuiGeneralScreensaverOptions::~GuiGeneralScreensaverOptions() diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 9bc7ee9b9..b486d3ab8 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -387,6 +387,38 @@ void GuiMenu::openUISettings() } }); + #if defined(USE_OPENGL_21) + // Open menu effect. + auto open_menu_effect = std::make_shared> + (mWindow, getHelpStyle(), "OPEN MENU EFFECT", false); + std::vector menu_effects; + menu_effects.push_back("scale-up"); + menu_effects.push_back("fade-in"); + menu_effects.push_back("none"); + + for (auto it = menu_effects.cbegin(); it != menu_effects.cend(); it++) + open_menu_effect->add(*it, *it, Settings::getInstance()-> + getString("OpenMenuEffect") == *it); + s->addWithLabel("OPEN MENU EFFECT", open_menu_effect); + s->addSaveFunc([open_menu_effect] { + bool needReload = false; + if (Settings::getInstance()->getString("OpenMenuEffect") != + open_menu_effect->getSelected()) + needReload = true; + Settings::getInstance()->setString("OpenMenuEffect", open_menu_effect->getSelected()); + if (needReload) + ViewController::get()->reloadAll(); + }); + + // Render scanlines for videos in the gamelists using a shader. + auto render_video_scanlines = std::make_shared(mWindow); + render_video_scanlines->setState(Settings::getInstance()->getBool("GamelistVideoScanlines")); + s->addWithLabel("RENDER SCANLINES FOR GAMELIST VIDEOS", render_video_scanlines); + s->addSaveFunc([render_video_scanlines] { + Settings::getInstance()->setBool("GamelistVideoScanlines", + render_video_scanlines->getState()); }); + #endif + // Sort folders on top of the gamelists. auto folders_on_top = std::make_shared(mWindow); folders_on_top->setState(Settings::getInstance()->getBool("FoldersOnTop")); diff --git a/es-app/src/guis/GuiSlideshowScreensaverOptions.cpp b/es-app/src/guis/GuiSlideshowScreensaverOptions.cpp index 97e7ea740..4bc755b4e 100644 --- a/es-app/src/guis/GuiSlideshowScreensaverOptions.cpp +++ b/es-app/src/guis/GuiSlideshowScreensaverOptions.cpp @@ -38,6 +38,15 @@ GuiSlideshowScreensaverOptions::GuiSlideshowScreensaverOptions(Window* window, c Settings::getInstance()->setBool("ScreenSaverStretchImages", sss_stretch->getState()); }); + #if defined(USE_OPENGL_21) + // Render scanlines using a shader. + auto render_scanlines = std::make_shared(mWindow); + render_scanlines->setState(Settings::getInstance()->getBool("ScreenSaverImageScanlines")); + addWithLabel(row, "RENDER SCANLINES", render_scanlines); + addSaveFunc([render_scanlines] { Settings::getInstance()-> + setBool("ScreenSaverImageScanlines", render_scanlines->getState()); }); + #endif + // Background audio file. auto sss_bg_audio_file = std::make_shared(mWindow, "", Font::get(FONT_SIZE_SMALL), 0x777777FF); diff --git a/es-app/src/guis/GuiVideoScreensaverOptions.cpp b/es-app/src/guis/GuiVideoScreensaverOptions.cpp index c1c321524..73d65bf9d 100644 --- a/es-app/src/guis/GuiVideoScreensaverOptions.cpp +++ b/es-app/src/guis/GuiVideoScreensaverOptions.cpp @@ -87,6 +87,22 @@ GuiVideoScreensaverOptions::GuiVideoScreensaverOptions(Window* window, const cha addSaveFunc([ss_video_audio] { Settings::getInstance()-> setBool("ScreenSaverVideoAudio", ss_video_audio->getState()); }); + #if defined(USE_OPENGL_21) + // Render scanlines using a shader. + auto render_scanlines = std::make_shared(mWindow); + render_scanlines->setState(Settings::getInstance()->getBool("ScreenSaverVideoScanlines")); + addWithLabel("RENDER SCANLINES", render_scanlines); + addSaveFunc([render_scanlines] { Settings::getInstance()-> + setBool("ScreenSaverVideoScanlines", render_scanlines->getState()); }); + + // Render blur using a shader. + auto render_blur = std::make_shared(mWindow); + render_blur->setState(Settings::getInstance()->getBool("ScreenSaverVideoBlur")); + addWithLabel("RENDER BLUR", render_blur); + addSaveFunc([render_blur] { Settings::getInstance()-> + setBool("ScreenSaverVideoBlur", render_blur->getState()); }); + #endif + #if defined(_RPI_) // Define subtitle font. auto ss_omx_font_file = std::make_shared(mWindow, "", diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index 13a5ad6f9..ecbafc7e0 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -84,6 +84,8 @@ void Settings::setDefaults() mStringMap["ThemeSet"] = "rbsimple-DE"; mStringMap["UIMode"] = "full"; mStringMap["DefaultSortOrder"] = "filename, ascending"; + mStringMap["OpenMenuEffect"] = "scale-up"; + mBoolMap["GamelistVideoScanlines"] = true; mBoolMap["FoldersOnTop"] = true; mBoolMap["FavoritesFirst"] = true; mBoolMap["ForceDisableFilters"] = false; @@ -97,17 +99,10 @@ void Settings::setDefaults() mBoolMap["ScreenSaverControls"] = true; mStringMap["ScreenSaverBehavior"] = "dim"; - // UI settings -> screensaver settings -> video screensaver settings. - mIntMap["ScreenSaverSwapVideoTimeout"] = 25000; - mBoolMap["ScreenSaverStretchVideos"] = false; - #if defined(_RPI_) - mStringMap["ScreenSaverGameInfo"] = "never"; - #endif - mBoolMap["ScreenSaverVideoAudio"] = false; - // UI settings -> screensaver settings -> slideshow screensaver settings. mIntMap["ScreenSaverSwapImageTimeout"] = 10000; mBoolMap["ScreenSaverStretchImages"] = false; + mBoolMap["ScreenSaverImageScanlines"] = true; mStringMap["SlideshowScreenSaverBackgroundAudioFile"] = Utils::FileSystem::getHomePath() + "/.emulationstation/slideshow/audio/slideshow_bg.wav"; mBoolMap["SlideshowScreenSaverCustomImageSource"] = false; @@ -116,6 +111,16 @@ void Settings::setDefaults() mBoolMap["SlideshowScreenSaverRecurse"] = false; mStringMap["SlideshowScreenSaverImageFilter"] = ".png,.jpg"; + // UI settings -> screensaver settings -> video screensaver settings. + mIntMap["ScreenSaverSwapVideoTimeout"] = 25000; + mBoolMap["ScreenSaverStretchVideos"] = false; + #if defined(_RPI_) + mStringMap["ScreenSaverGameInfo"] = "never"; + #endif + mBoolMap["ScreenSaverVideoAudio"] = false; + mBoolMap["ScreenSaverVideoScanlines"] = true; + mBoolMap["ScreenSaverVideoBlur"] = false; + // Sound settings. // The ALSA Audio Card and Audio Device selection code is disabled at the moment. // As PulseAudio controls the sound devices for the desktop environment, it doesn't diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index e759687d1..6478f756e 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -9,7 +9,6 @@ #include "components/HelpComponent.h" #include "components/ImageComponent.h" #include "resources/Font.h" -#include "resources/TextureResource.h" #include "InputManager.h" #include "Log.h" #include "Scripting.h" @@ -28,7 +27,12 @@ Window::Window() mScreenSaver(nullptr), mRenderScreenSaver(false), mGameLaunchedState(false), - mInfoPopup(nullptr) + mInfoPopup(nullptr), + mCachedBackground(false), + mSaturationAmount(1.0), + mTopOpacity(0), + mTopScale(0.5), + mDimValue(1.0) { mHelp = new HelpComponent(this); mBackgroundOverlay = new ImageComponent(this); @@ -258,19 +262,67 @@ void Window::render() bottom->render(transform); if (bottom != top) { + #if defined(USE_OPENGL_21) + if (!mCachedBackground) { + // Generate a cache texture of the shaded background when opening the menu, which + // will remain valid until the menu is closed. This is way faster than having to + // render the shaders for every frame. + std::shared_ptr mPostprocessedBackground; + mPostprocessedBackground = TextureResource::get(""); + unsigned char* processedTexture = new unsigned char[Renderer::getScreenWidth() * + Renderer::getScreenHeight() * 4]; + + // Defocus the background using three passes of gaussian blur. + Renderer::shaderParameters blurParameters; + blurParameters.shaderPasses = 3; + Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL | + Renderer::SHADER_BLUR_VERTICAL, + blurParameters, processedTexture); + + mPostprocessedBackground->initFromPixels(processedTexture, + Renderer::getScreenWidth(), Renderer::getScreenHeight()); + + mBackgroundOverlay->setImage(mPostprocessedBackground); + + delete[] processedTexture; + mCachedBackground = true; + } + #endif mBackgroundOverlay->render(transform); + + #if defined(USE_OPENGL_21) + Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), + Renderer::getScreenHeight(), 0x00000070, 0x00000070); + + // Open menu effects (scale-up and fade-in). + if (Settings::getInstance()->getString("OpenMenuEffect") == "scale-up") { + if (mTopScale < 1.0) + mTopScale = Math::clamp(mTopScale+0.07, 0, 1.0); + Vector2f topCenter = top->getCenter(); + top->setOrigin({0.5, 0.5}); + top->setPosition({topCenter.x(), topCenter.y(), 0}); + top->setScale(mTopScale); + } + if (Settings::getInstance()->getString("OpenMenuEffect") == "fade-in") { + // Fade-in menu. + if (mTopOpacity < 255) + mTopOpacity = Math::clamp(mTopOpacity+15, 0, 255); + top->setOpacity(mTopOpacity); + } + #endif + top->render(transform); } + else { + mCachedBackground = false; + mTopOpacity = 0; + mTopScale = 0.5; + } } if (!mRenderedHelpPrompts) mHelp->render(transform); - if (Settings::getInstance()->getBool("DisplayGPUStatistics") && mFrameDataText) { - Renderer::setMatrix(Transform4x4f::Identity()); - mDefaultFonts.at(1)->renderTextCache(mFrameDataText.get()); - } - unsigned int screensaverTime = (unsigned int)Settings::getInstance()->getInt("ScreenSaverTime"); // If a game has been launched, reset the screensaver timer when it's been reached as we // don't want to start the screensaver in the background when running a game. @@ -289,7 +341,7 @@ void Window::render() mInfoPopup->render(transform); if (mTimeSinceLastInput >= screensaverTime && screensaverTime != 0) { - if (!isProcessing() && mAllowSleep && (!mScreenSaver || mScreenSaver->allowSleep())) { + if (!isProcessing() && mAllowSleep && (!mScreenSaver)) { // Go to sleep. if (mSleeping == false) { mSleeping = true; @@ -297,6 +349,55 @@ void Window::render() } } } + + #if defined(USE_OPENGL_21) + // Shaders for the screensavers. + if (mScreenSaver->isScreenSaverActive()) { + if (Settings::getInstance()->getString("ScreenSaverBehavior") == "video") { + if (mScreenSaver->getVideoCount() > 0) { + if (Settings::getInstance()->getBool("ScreenSaverVideoBlur")) + Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL); + if (Settings::getInstance()->getBool("ScreenSaverVideoScanlines")) + Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); + } + else { + // If there are no videos, render a black screen. + Renderer::shaderParameters blackParameters; + blackParameters.fragmentDimValue = mDimValue; + Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters); + if (mDimValue > 0.0) + mDimValue = Math::clamp(mDimValue-0.045, 0.0, 1.0); + } + } + else if (Settings::getInstance()->getString("ScreenSaverBehavior") == "slideshow") { + if (Settings::getInstance()->getBool("ScreenSaverImageScanlines")) + Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES); + } + else if (Settings::getInstance()->getString("ScreenSaverBehavior") == "dim") { + Renderer::shaderParameters dimParameters; + dimParameters.fragmentDimValue = mDimValue; + Renderer::shaderPostprocessing(Renderer::SHADER_DIM, dimParameters); + if (mDimValue > 0.4) + mDimValue = Math::clamp(mDimValue-0.021, 0.4, 1.0); + dimParameters.fragmentSaturation = mSaturationAmount; + Renderer::shaderPostprocessing(Renderer::SHADER_DESATURATE, dimParameters); + if (mSaturationAmount > 0.0) + mSaturationAmount = Math::clamp(mSaturationAmount-0.035, 0.0, 1.0); + } + else if (Settings::getInstance()->getString("ScreenSaverBehavior") == "black") { + Renderer::shaderParameters blackParameters; + blackParameters.fragmentDimValue = mDimValue; + Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters); + if (mDimValue > 0.0) + mDimValue = Math::clamp(mDimValue-0.045, 0.0, 1.0); + } + } + #endif + + if (Settings::getInstance()->getBool("DisplayGPUStatistics") && mFrameDataText) { + Renderer::setMatrix(Transform4x4f::Identity()); + mDefaultFonts.at(1)->renderTextCache(mFrameDataText.get()); + } } void Window::normalizeNextUpdate() @@ -473,6 +574,9 @@ bool Window::cancelScreenSaver() for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++) (*it)->onScreenSaverDeactivate(); + mSaturationAmount = 1.0; + mDimValue = 1.0; + return true; } diff --git a/es-core/src/Window.h b/es-core/src/Window.h index 2cbf953a3..d7166b7a3 100644 --- a/es-core/src/Window.h +++ b/es-core/src/Window.h @@ -8,6 +8,7 @@ #ifndef ES_CORE_WINDOW_H #define ES_CORE_WInDOW_H +#include "resources/TextureResource.h" #include "HelpPrompt.h" #include "InputConfig.h" #include "Settings.h" @@ -40,6 +41,7 @@ public: virtual FileData* getCurrentGame() = 0; virtual void launchGame() = 0; virtual void resetCounts() = 0; + virtual unsigned int getVideoCount() = 0; }; class InfoPopup @@ -116,6 +118,11 @@ private: bool mNormalizeNextUpdate; + float mSaturationAmount; + unsigned char mTopOpacity; + float mTopScale; + float mDimValue; + bool mCachedBackground; bool mAllowSleep; bool mSleeping; unsigned int mTimeSinceLastInput; diff --git a/es-core/src/animations/LambdaAnimation.h b/es-core/src/animations/LambdaAnimation.h index e3e971806..faa476522 100644 --- a/es-core/src/animations/LambdaAnimation.h +++ b/es-core/src/animations/LambdaAnimation.h @@ -10,6 +10,8 @@ #include "animations/Animation.h" +#include + // Useful for simple one-off animations, you can supply the animation's apply(t) // function directly in the constructor as a lambda. class LambdaAnimation : public Animation diff --git a/es-core/src/components/ImageComponent.cpp b/es-core/src/components/ImageComponent.cpp index 77dda1e99..7d5fa6583 100644 --- a/es-core/src/components/ImageComponent.cpp +++ b/es-core/src/components/ImageComponent.cpp @@ -345,10 +345,6 @@ void ImageComponent::updateColors() mVertices[1].col = mColorGradientHorizontal ? colorEnd : color; mVertices[2].col = mColorGradientHorizontal ? color : colorEnd; mVertices[3].col = colorEnd; - mVertices[0].saturation = mSaturation; - mVertices[1].saturation = mSaturation; - mVertices[2].saturation = mSaturation; - mVertices[3].saturation = mSaturation; } void ImageComponent::render(const Transform4x4f& parentTrans) @@ -372,7 +368,13 @@ void ImageComponent::render(const Transform4x4f& parentTrans) // texture is bound in this case but we want to handle a fade so it doesn't just // 'jump' in when it finally loads. fadeIn(mTexture->bind()); - Renderer::drawTriangleStrips(&mVertices[0], 4); + #if defined(USE_OPENGL_21) + if (mSaturation < 1.0) { + mVertices[0].shaders = Renderer::SHADER_DESATURATE; + mVertices[0].saturation = mSaturation; + } + #endif + Renderer::drawTriangleStrips(&mVertices[0], 4, trans); } else { LOG(LogError) << "Image texture is not initialized!"; diff --git a/es-core/src/components/VideoVlcComponent.cpp b/es-core/src/components/VideoVlcComponent.cpp index c76649c5d..265ea4812 100644 --- a/es-core/src/components/VideoVlcComponent.cpp +++ b/es-core/src/components/VideoVlcComponent.cpp @@ -171,8 +171,16 @@ void VideoVlcComponent::render(const Transform4x4f& parentTrans) mContext.surface->w, mContext.surface->h); mTexture->bind(); + #if defined(USE_OPENGL_21) + // Render scanlines if this option is enabled. However, if this is the video + // screensaver, then skip this as screensaver scanline rendering is handled from + // Window.cpp as a postprocessing step. + if (!mScreensaverMode && Settings::getInstance()->getBool("GamelistVideoScanlines")) + vertices[0].shaders = Renderer::SHADER_SCANLINES; + #endif + // Render it. - Renderer::drawTriangleStrips(&vertices[0], 4); + Renderer::drawTriangleStrips(&vertices[0], 4, trans); } else { VideoComponent::renderSnapshot(parentTrans);