Added a game info overlay to the screensaver.

Also refactored Window and SystemScreensaver and added a fade-in effect for the shaded background when opening menus.
This commit is contained in:
Leon Styhre 2020-11-12 00:46:59 +01:00
parent 08786f2027
commit 9bea6bb17e
11 changed files with 317 additions and 173 deletions

View file

@ -92,6 +92,13 @@ make
```
I have however not been able to test the CEC support and I'm not entirely sure how it's supposed to work.
To build ES with the GLES renderer, run the following:
```
cmake -DCMAKE_BUILD_TYPE=Debug -DGLES=on .
make
```
Note that the GLES renderer is quite limited as there is no shader support for it, so ES will definitely not look as pretty as when using the default OpenGL renderer.
Running multiple compile jobs in parallel is a good thing as it speeds up the build time a lot (scaling almost linearly). Here's an example telling make to run 6 parallel jobs:
```

View file

@ -27,6 +27,7 @@ Many bugs have been fixed, and numerous features that were only partially implem
* Files or folders can now be flagged for exclusion when scraping with the multi-scraper, and for folders it can be set to apply recursively
* Gamelist sorting is now working as expected and is persistent throughout the application session
* Overhaul of the game collection functionality including many bug fixes and optimizations
* Overhaul of the screensaver (the game info overlay now works correctly for instance)
* Added ability to delete custom collections from the GUI menu
* Game counting is now done during sorting instead of every time a system is selected. This should make the UI more responsive in case of large game libraries
* Added a system view counter for favorite games in addition to the total number of games

View file

@ -693,6 +693,10 @@ For how long to display images before changing to the next game. Allowed range i
This will fill the entire screen surface but will possibly break the aspect ratio of the image.
**Display game info overlay**
This will display an overlay in the bottom left corner, showing the game name and the game system name.
**Render scanlines** _(OpenGL renderer only)_
Whether to use a shader to render scanlines on top of the images.
@ -717,17 +721,17 @@ Options specific to the video screensaver.
For how long to play videos before changing to the next game. Allowed range is between 5 and 120 seconds.
**Show game info overlay**
**Play audio for screensaver videos**
This will display an overlay on top of the videos, showing the game name and game system name.
Muting or playing the audio.
**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**
**Display game info overlay**
Muting or playing the audio.
This will display an overlay in the bottom left corner, showing the game name and the game system name.
**Render scanlines** _(OpenGL renderer only)_

View file

@ -13,7 +13,9 @@
#include "components/VideoPlayerComponent.h"
#endif
#include "components/VideoVlcComponent.h"
#include "resources/Font.h"
#include "utils/FileSystemUtil.h"
#include "utils/StringUtil.h"
#include "views/gamelist/IGameListView.h"
#include "views/ViewController.h"
#include "FileData.h"
@ -33,19 +35,22 @@
SystemScreensaver::SystemScreensaver(
Window* window)
: mImageScreensaver(nullptr),
mVideoScreensaver(nullptr),
mWindow(window),
: mWindow(window),
mState(STATE_INACTIVE),
mOpacity(0.0f),
mTimer(0),
mSystemName(""),
mGameName(""),
mImageScreensaver(nullptr),
mVideoScreensaver(nullptr),
mCurrentGame(nullptr),
mHasMediaFiles(false)
mPreviousGame(nullptr),
mTimer(0),
mVideoChangeTime(30000),
mHasMediaFiles(false),
mOpacity(0.0f),
mDimValue(1.0),
mRectangleFadeIn(50),
mTextFadeIn(0),
mSaturationAmount(1.0)
{
mWindow->setScreensaver(this);
mVideoChangeTime = 30000;
}
SystemScreensaver::~SystemScreensaver()
@ -70,11 +75,18 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
std::string path = "";
std::string screensaverType = Settings::getInstance()->getString("ScreensaverType");
mHasMediaFiles = false;
mOpacity = 0.0f;
// Keep a reference to the default fonts, so they don't keep getting destroyed/recreated.
if (mGameOverlayFont.empty()) {
mGameOverlayFont.push_back(Font::get(FONT_SIZE_SMALL));
mGameOverlayFont.push_back(Font::get(FONT_SIZE_MEDIUM));
mGameOverlayFont.push_back(Font::get(FONT_SIZE_LARGE));
}
// Set mPreviousGame which will be used to avoid showing the same game again during
// the random selection.
if ((screensaverType == "video" || screensaverType == "slideshow") &&
mCurrentGame != nullptr)
if ((screensaverType == "slideshow" || screensaverType == "video") && mCurrentGame != nullptr)
mPreviousGame = mCurrentGame;
if (screensaverType == "slideshow") {
@ -87,7 +99,6 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
mState = STATE_FADE_OUT_WINDOW;
mVideoChangeTime = Settings::getInstance()->getInt("ScreensaverSwapImageTimeout");
mOpacity = 0.0f;
// Load a random image.
if (Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) {
@ -110,9 +121,12 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
mHasMediaFiles = true;
// Don't attempt to render the screensaver if there are no images available, but
// do flag it as running. This way Window::render() will fade to a black screen, i.e.
// it will activate the 'Black' screensaver type.
// do flag it as running. This way render() will fade to a black screen, i.e. it
// will activate the 'Black' screensaver type.
if (mImageFiles.size() > 0 || mImageCustomFiles.size() > 0) {
if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo"))
generateOverlayInfo();
if (!mImageScreensaver)
mImageScreensaver = new ImageComponent(mWindow, false, false);
@ -142,7 +156,6 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
mState = STATE_FADE_OUT_WINDOW;
mVideoChangeTime = Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout");
mOpacity = 0.0f;
// Load a random video.
if (generateMediaList)
@ -153,8 +166,11 @@ void SystemScreensaver::startScreensaver(bool generateMediaList)
mHasMediaFiles = true;
if (!path.empty() && Utils::FileSystem::exists(path)) {
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo"))
generateOverlayInfo();
#if defined(_RPI_)
// Create the correct type of video component
// Create the correct type of video component.
if (Settings::getInstance()->getBool("ScreensaverOmxPlayer"))
mVideoScreensaver = new VideoPlayerComponent(mWindow);
else
@ -197,6 +213,14 @@ void SystemScreensaver::stopScreensaver()
mState = STATE_INACTIVE;
PowerSaver::runningScreensaver(false);
mDimValue = 1.0;
mRectangleFadeIn = 50;
mTextFadeIn = 0;
mSaturationAmount = 1.0;
if (mGameOverlay)
mGameOverlay.release();
}
void SystemScreensaver::nextGame() {
@ -221,7 +245,7 @@ void SystemScreensaver::renderScreensaver()
{
std::string screensaverType = Settings::getInstance()->getString("ScreensaverType");
if (mVideoScreensaver && screensaverType == "video") {
// Render black background.
// Render a black background below the video.
Renderer::setMatrix(Transform4x4f::Identity());
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
@ -233,12 +257,12 @@ void SystemScreensaver::renderScreensaver()
}
}
else if (mImageScreensaver && screensaverType == "slideshow") {
// Render a black background.
// Render a black background below the image.
Renderer::setMatrix(Transform4x4f::Identity());
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
// Only render the video if the state requires it.
// Only render the image if the state requires it.
if (static_cast<int>(mState) >= STATE_FADE_IN_VIDEO) {
if (mImageScreensaver->hasImage()) {
mImageScreensaver->setOpacity(255 - static_cast<unsigned char>(mOpacity * 255));
@ -248,14 +272,117 @@ void SystemScreensaver::renderScreensaver()
}
}
}
#if !defined(USE_OPENGL_21)
else if (mState != STATE_INACTIVE) {
if (isScreensaverActive()) {
Renderer::setMatrix(Transform4x4f::Identity());
unsigned char color = screensaverType == "dim" ? 0x000000A0 : 0x000000FF;
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), color, color);
if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") {
if (mHasMediaFiles) {
#if defined(USE_OPENGL_21)
if (Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"))
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
#endif
if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo") &&
mGameOverlay) {
if (mGameOverlayRectangleCoords.size() == 4) {
Renderer::drawRect(mGameOverlayRectangleCoords[0],
mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[2],
mGameOverlayRectangleCoords[3], 0x00000000 | mRectangleFadeIn,
0x00000000 | mRectangleFadeIn );
}
if (mRectangleFadeIn < 180)
mRectangleFadeIn = Math::clamp(mRectangleFadeIn + 4, 0, 255);
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
mGameOverlayFont.at(0)->renderTextCache(mGameOverlay.get());
if (mTextFadeIn < 255)
mTextFadeIn = Math::clamp(mTextFadeIn + 8, 0, 255);
}
}
else {
// If there are no images, fade in a black screen.
#if defined(USE_OPENGL_21)
Renderer::shaderParameters blackParameters;
blackParameters.fragmentDimValue = mDimValue;
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters);
#else
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF, mDimValue);
#endif
if (mDimValue > 0.0)
mDimValue = Math::clamp(mDimValue-0.045, 0.0, 1.0);
}
}
if (Settings::getInstance()->getString("ScreensaverType") == "video") {
if (mHasMediaFiles) {
#if defined(USE_OPENGL_21)
if (Settings::getInstance()->getBool("ScreensaverVideoBlur"))
Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL);
if (Settings::getInstance()->getBool("ScreensaverVideoScanlines"))
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
#endif
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo") && mGameOverlay) {
if (mGameOverlayRectangleCoords.size() == 4) {
#if defined(USE_OPENGL_21)
Renderer::shaderPostprocessing(Renderer::SHADER_OPACITY);
#endif
Renderer::drawRect(mGameOverlayRectangleCoords[0],
mGameOverlayRectangleCoords[1], mGameOverlayRectangleCoords[2],
mGameOverlayRectangleCoords[3], 0x00000000 | mRectangleFadeIn,
0x00000000 | mRectangleFadeIn );
}
if (mRectangleFadeIn < 180)
mRectangleFadeIn = Math::clamp(mRectangleFadeIn + 4, 0, 255);
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
mGameOverlayFont.at(0)->renderTextCache(mGameOverlay.get());
if (mTextFadeIn < 255)
mTextFadeIn = Math::clamp(mTextFadeIn + 8, 0, 255);
}
}
else {
// If there are no videos, fade in a black screen.
#if defined(USE_OPENGL_21)
Renderer::shaderParameters blackParameters;
blackParameters.fragmentDimValue = mDimValue;
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters);
#else
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF, mDimValue);
#endif
if (mDimValue > 0.0)
mDimValue = Math::clamp(mDimValue-0.045, 0.0, 1.0);
}
}
else if (Settings::getInstance()->getString("ScreensaverType") == "dim") {
#if defined(USE_OPENGL_21)
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
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x000000A0, 0x000000A0);
#endif
}
else if (Settings::getInstance()->getString("ScreensaverType") == "black") {
#if defined(USE_OPENGL_21)
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
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x000000FF, 0x000000FF);
#endif
}
}
#endif
}
void SystemScreensaver::update(int deltaTime)
@ -438,3 +565,41 @@ void SystemScreensaver::pickRandomCustomImage(std::string& path)
mGameName = "";
mSystemName = "";
}
void SystemScreensaver::generateOverlayInfo()
{
if (mGameName == "" || mSystemName == "")
return;
float posX = static_cast<float>(Renderer::getWindowWidth()) * 0.03;
float posY = static_cast<float>(Renderer::getWindowHeight()) * 0.87;
const std::string gameName = Utils::String::toUpper(mGameName);
const std::string systemName = Utils::String::toUpper(mSystemName);
const std::string overlayText = gameName + "\n" + systemName;
mGameOverlay = std::unique_ptr<TextCache>(mGameOverlayFont.at(0)->
buildTextCache(overlayText, posX, posY, 0xFFFFFFFF));
float textSizeX;
float textSizeY = mGameOverlayFont[0].get()->sizeText(overlayText).y();
// There is a weird issue with sizeText() where the X size value is returned
// as too large if there are two rows in a string and the second row is longer
// than the first row. Possibly it's the newline character that is somehow
// injected in the size calculation. Regardless, this workaround is working
// fine for the time being.
if (mGameOverlayFont[0].get()->sizeText(gameName).x() >
mGameOverlayFont[0].get()->sizeText(systemName).x())
textSizeX = mGameOverlayFont[0].get()->sizeText(gameName).x();
else
textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x();
float marginX = Renderer::getWindowWidth() * 0.01;
mGameOverlayRectangleCoords.clear();
mGameOverlayRectangleCoords.push_back(posX - marginX);
mGameOverlayRectangleCoords.push_back(posY);
mGameOverlayRectangleCoords.push_back(textSizeX + marginX * 2);
mGameOverlayRectangleCoords.push_back(textSizeY);
}

View file

@ -13,7 +13,6 @@
#include "Window.h"
class ImageComponent;
class Sound;
class VideoComponent;
// Screensaver implementation.
@ -34,7 +33,6 @@ public:
virtual void renderScreensaver();
virtual void update(int deltaTime);
virtual bool getHasMediaFiles() { return mHasMediaFiles; };
virtual FileData* getCurrentGame() { return mCurrentGame; };
private:
@ -44,6 +42,7 @@ private:
void pickRandomImage(std::string& path);
void pickRandomVideo(std::string& path);
void pickRandomCustomImage(std::string& path);
void generateOverlayInfo();
enum STATE {
STATE_INACTIVE,
@ -52,22 +51,33 @@ private:
STATE_SCREENSAVER_ACTIVE
};
Window* mWindow;
STATE mState;
std::vector<FileData*> mImageFiles;
std::vector<FileData*> mVideoFiles;
std::vector<std::string> mImageCustomFiles;
bool mHasMediaFiles;
VideoComponent* mVideoScreensaver;
ImageComponent* mImageScreensaver;
Window* mWindow;
STATE mState;
float mOpacity;
int mTimer;
VideoComponent* mVideoScreensaver;
FileData* mCurrentGame;
FileData* mPreviousGame;
std::string mPreviousCustomImage;
std::string mGameName;
std::string mSystemName;
int mTimer;
int mVideoChangeTime;
bool mHasMediaFiles;
float mOpacity;
float mDimValue;
unsigned char mRectangleFadeIn;
unsigned char mTextFadeIn;
float mSaturationAmount;
std::unique_ptr<TextCache> mGameOverlay;
std::vector<std::shared_ptr<Font>> mGameOverlayFont;
std::vector<float> mGameOverlayRectangleCoords;
};
#endif // ES_APP_SYSTEM_SCREEN_SAVER_H

View file

@ -131,17 +131,31 @@ void GuiScreensaverOptions::openSlideshowScreensaverOptions()
}
});
// Show game info overlay for slideshow screensaver.
auto screensaver_slideshow_game_info = std::make_shared<SwitchComponent>(mWindow);
screensaver_slideshow_game_info->
setState(Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo"));
s->addWithLabel("DISPLAY GAME INFO OVERLAY", screensaver_slideshow_game_info);
s->addSaveFunc([screensaver_slideshow_game_info, s] {
if (screensaver_slideshow_game_info->getState() !=
Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo")) {
Settings::getInstance()->setBool("ScreensaverSlideshowGameInfo",
screensaver_slideshow_game_info->getState());
s->setNeedsSaving();
}
});
#if defined(USE_OPENGL_21)
// Render scanlines using a shader.
auto screensaver_image_scanlines = std::make_shared<SwitchComponent>(mWindow);
screensaver_image_scanlines->
setState(Settings::getInstance()->getBool("ScreensaverImageScanlines"));
s->addWithLabel("RENDER SCANLINES", screensaver_image_scanlines);
s->addSaveFunc([screensaver_image_scanlines, s] {
if (screensaver_image_scanlines->getState() !=
Settings::getInstance()->getBool("ScreensaverImageScanlines")) {
Settings::getInstance()->
setBool("ScreensaverImageScanlines", screensaver_image_scanlines->getState());
auto screensaver_slideshow_scanlines = std::make_shared<SwitchComponent>(mWindow);
screensaver_slideshow_scanlines->
setState(Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"));
s->addWithLabel("RENDER SCANLINES", screensaver_slideshow_scanlines);
s->addSaveFunc([screensaver_slideshow_scanlines, s] {
if (screensaver_slideshow_scanlines->getState() !=
Settings::getInstance()->getBool("ScreensaverSlideshowScanlines")) {
Settings::getInstance()->setBool("ScreensaverSlideshowScanlines",
screensaver_slideshow_scanlines->getState());
s->setNeedsSaving();
}
});
@ -215,22 +229,15 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
}
});
// Show game info overlay.
auto screensaver_video_game_info = std::make_shared<OptionListComponent<std::string>>
(mWindow,getHelpStyle(), "SHOW GAME INFO OVERLAY", false);
std::vector<std::string> info_type;
info_type.push_back("always");
info_type.push_back("start & end");
info_type.push_back("never");
for (auto it = info_type.cbegin(); it != info_type.cend(); it++)
screensaver_video_game_info->add(*it, *it,
Settings::getInstance()->getString("ScreensaverVideoGameInfo") == *it);
s->addWithLabel("SHOW GAME INFO OVERLAY", screensaver_video_game_info);
s->addSaveFunc([screensaver_video_game_info, s] {
if (screensaver_video_game_info->getSelected() !=
Settings::getInstance()->getString("ScreensaverVideoGameInfo")) {
Settings::getInstance()->setString("ScreensaverVideoGameInfo",
screensaver_video_game_info->getSelected());
// PLay audio for screensaver videos.
auto screensaver_video_audio = std::make_shared<SwitchComponent>(mWindow);
screensaver_video_audio->setState(Settings::getInstance()->getBool("ScreensaverVideoAudio"));
s->addWithLabel("PLAY AUDIO FOR SCREENSAVER VIDEOS", screensaver_video_audio);
s->addSaveFunc([screensaver_video_audio, s] {
if (screensaver_video_audio->getState() !=
Settings::getInstance()->getBool("ScreensaverVideoAudio")) {
Settings::getInstance()->setBool("ScreensaverVideoAudio",
screensaver_video_audio->getState());
s->setNeedsSaving();
}
});
@ -249,7 +256,22 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
}
});
// Show game info overlay for video screensaver.
auto screensaver_video_game_info = std::make_shared<SwitchComponent>(mWindow);
screensaver_video_game_info->
setState(Settings::getInstance()->getBool("ScreensaverVideoGameInfo"));
s->addWithLabel("DISPLAY GAME INFO OVERLAY", screensaver_video_game_info);
s->addSaveFunc([screensaver_video_game_info, s] {
if (screensaver_video_game_info->getState() !=
Settings::getInstance()->getBool("ScreensaverVideoGameInfo")) {
Settings::getInstance()->setBool("ScreensaverVideoGameInfo",
screensaver_video_game_info->getState());
s->setNeedsSaving();
}
});
#if defined(_RPI_)
// Use OMX player for screensaver.
auto screensaver_omx_player = std::make_shared<SwitchComponent>(mWindow);
screensaver_omx_player->setState(Settings::getInstance()->getBool("ScreensaverOmxPlayer"));
s->addWithLabel("USE OMX PLAYER FOR SCREENSAVER", screensaver_omx_player);
@ -263,42 +285,6 @@ void GuiScreensaverOptions::openVideoScreensaverOptions()
});
#endif
// ComponentListRow row;
// Set subtitle position.
// auto ss_omx_subs_align = std::make_shared<OptionListComponent<std::string>>
// (mWindow, getHelpStyle(), "GAME INFO ALIGNMENT", false);
// std::vector<std::string> align_mode;
// align_mode.push_back("left");
// align_mode.push_back("center");
// for (auto it = align_mode.cbegin(); it != align_mode.cend(); it++)
// ss_omx_subs_align->add(*it, *it, Settings::getInstance()->
// getString("SubtitleAlignment") == *it);
// addWithLabel("GAME INFO ALIGNMENT", ss_omx_subs_align);
// addSaveFunc([ss_omx_subs_align, this] { Settings::getInstance()->
// setString("SubtitleAlignment", ss_omx_subs_align->getSelected()); });
// Set font size.
// auto ss_omx_font_size = std::make_shared<SliderComponent>(mWindow, 1.f, 64.f, 1.f, "h");
// ss_omx_font_size->setValue((float)(Settings::getInstance()->getInt("SubtitleSize")));
// addWithLabel("GAME INFO FONT SIZE", ss_omx_font_size);
// addSaveFunc([ss_omx_font_size] {
// int subSize = (int)Math::round(ss_omx_font_size->getValue());
// Settings::getInstance()->setInt("SubtitleSize", subSize);
// });
auto screensaver_video_audio = std::make_shared<SwitchComponent>(mWindow);
screensaver_video_audio->setState(Settings::getInstance()->getBool("ScreensaverVideoAudio"));
s->addWithLabel("PLAY AUDIO FOR SCREENSAVER VIDEOS", screensaver_video_audio);
s->addSaveFunc([screensaver_video_audio, s] {
if (screensaver_video_audio->getState() !=
Settings::getInstance()->getBool("ScreensaverVideoAudio")) {
Settings::getInstance()->setBool("ScreensaverVideoAudio",
screensaver_video_audio->getState());
s->setNeedsSaving();
}
});
#if defined(USE_OPENGL_21)
// Render scanlines using a shader.
auto screensaver_video_scanlines = std::make_shared<SwitchComponent>(mWindow);

View file

@ -130,7 +130,8 @@ void Settings::setDefaults()
// UI settings -> screensaver settings -> slideshow screensaver settings.
mIntMap["ScreensaverSwapImageTimeout"] = 8000;
mBoolMap["ScreensaverStretchImages"] = false;
mBoolMap["ScreensaverImageScanlines"] = true;
mBoolMap["ScreensaverSlideshowGameInfo"] = true;
mBoolMap["ScreensaverSlideshowScanlines"] = true;
mBoolMap["ScreensaverSlideshowCustomImages"] = false;
mBoolMap["ScreensaverSlideshowRecurse"] = false;
mStringMap["ScreensaverSlideshowImageDir"] =
@ -138,9 +139,9 @@ void Settings::setDefaults()
// UI settings -> screensaver settings -> video screensaver settings.
mIntMap["ScreensaverSwapVideoTimeout"] = 25000;
mBoolMap["ScreensaverStretchVideos"] = false;
mStringMap["ScreensaverVideoGameInfo"] = "always";
mBoolMap["ScreensaverVideoAudio"] = false;
mBoolMap["ScreensaverStretchVideos"] = false;
mBoolMap["ScreensaverVideoGameInfo"] = true;
mBoolMap["ScreensaverVideoScanlines"] = true;
mBoolMap["ScreensaverVideoBlur"] = false;

View file

@ -3,7 +3,7 @@
// EmulationStation Desktop Edition
// Window.cpp
//
// Window management, screensaver and help prompts.
// Window management, screensaver management, and help prompts.
// The input stack starts here as well, as this is the first instance called by InputManager.
//
@ -33,10 +33,9 @@ Window::Window()
mGameLaunchedState(false),
mAllowTextScrolling(true),
mCachedBackground(false),
mSaturationAmount(1.0),
mInvalidatedCachedBackground(false),
mTopOpacity(0),
mTopScale(0.5),
mDimValue(1.0)
mTopScale(0.5)
{
mHelp = new HelpComponent(this);
mBackgroundOverlay = new ImageComponent(this);
@ -266,7 +265,8 @@ void Window::update(int deltaTime)
textureVramUsageMiB << " MiB\nMax Texture VRAM: " <<
textureTotalUsageMiB << " MiB";
mFrameDataText = std::unique_ptr<TextCache>
(mDefaultFonts.at(1)->buildTextCache(ss.str(), 30.f, 30.f, 0xFF00FFFF));
(mDefaultFonts.at(1)->buildTextCache(ss.str(), Renderer::getScreenWidth() *
0.02 , Renderer::getScreenHeight() * 0.02, 0xFF00FFFF));
}
mFrameTimeElapsed = 0;
@ -322,17 +322,43 @@ void Window::render()
Renderer::getScreenWidth(), Renderer::getScreenHeight());
mBackgroundOverlay->setImage(mPostprocessedBackground);
mBackgroundOverlay->render(transform);
// Dim the background. We need to do this as a separate step as combining
// it with the blurring leads to very strange and severe artifacts.
// This is for sure a bug that needs to be resolved at some later date.
Renderer::shaderParameters blackParameters;
blackParameters.fragmentDimValue = 0.6;
Renderer::shaderPostprocessing(Renderer::SHADER_DIM,
blackParameters, processedTexture);
mPostprocessedBackground->initFromPixels(processedTexture,
Renderer::getScreenWidth(), Renderer::getScreenHeight());
mBackgroundOverlay->setImage(mPostprocessedBackground);
// The following is done to avoid fading in if the cached image was
// invalidated (rather than the menu being opened).
if (mInvalidatedCachedBackground) {
mBackgroundOverlayOpacity = 255;
mInvalidatedCachedBackground = false;
}
else {
mBackgroundOverlayOpacity = 25;
}
delete[] processedTexture;
mCachedBackground = true;
}
// Fade in the cached background.
mBackgroundOverlay->setOpacity(mBackgroundOverlayOpacity);
if (mBackgroundOverlayOpacity < 255)
mBackgroundOverlayOpacity = Math::clamp(mBackgroundOverlayOpacity + 30, 0, 255);
#endif
mBackgroundOverlay->render(transform);
#if defined(USE_OPENGL_21)
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(),
Renderer::getScreenHeight(), 0x00000070, 0x00000070);
// Menu opening effects (scale-up and fade-in).
if (Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up") {
if (mTopScale < 1.0)
@ -394,60 +420,6 @@ void Window::render()
}
}
#if defined(USE_OPENGL_21)
// Shaders for the screensavers.
if (mScreensaver->isScreensaverActive()) {
if (Settings::getInstance()->getString("ScreensaverType") == "video") {
if (mScreensaver->getHasMediaFiles()) {
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, fade in 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("ScreensaverType") == "slideshow") {
if (mScreensaver->getHasMediaFiles()) {
if (Settings::getInstance()->getBool("ScreensaverImageScanlines"))
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
}
else {
// If there are no images, fade in 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("ScreensaverType") == "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("ScreensaverType") == "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());
@ -632,9 +604,6 @@ bool Window::cancelScreensaver()
(*it)->onPauseVideo();
}
mSaturationAmount = 1.0;
mDimValue = 1.0;
return true;
}

View file

@ -3,7 +3,7 @@
// EmulationStation Desktop Edition
// Window.h
//
// Window management, screensaver and help prompts.
// Window management, screensaver management, and help prompts.
// The input stack starts here as well, as this is the first instance called by InputManager.
//
@ -42,7 +42,6 @@ public:
virtual bool isScreensaverActive() = 0;
virtual FileData* getCurrentGame() = 0;
virtual void launchGame() = 0;
virtual bool getHasMediaFiles() = 0;
};
class InfoPopup
@ -96,7 +95,8 @@ public:
void setAllowTextScrolling(bool setting) { mAllowTextScrolling = setting; };
bool getAllowTextScrolling() { return mAllowTextScrolling; };
void invalidateCachedBackground() { mCachedBackground = false; };
void invalidateCachedBackground()
{ mCachedBackground = false; mInvalidatedCachedBackground = true;};
private:
void onSleep();
@ -107,6 +107,7 @@ private:
HelpComponent* mHelp;
ImageComponent* mBackgroundOverlay;
unsigned char mBackgroundOverlayOpacity;
Screensaver* mScreensaver;
InfoPopup* mInfoPopup;
std::vector<GuiComponent*> mGuiStack;
@ -125,11 +126,10 @@ private:
bool mGameLaunchedState;
bool mAllowTextScrolling;
bool mCachedBackground;
bool mInvalidatedCachedBackground;
float mSaturationAmount;
unsigned char mTopOpacity;
float mTopScale;
float mDimValue;
bool mRenderedHelpPrompts;
};

View file

@ -370,8 +370,7 @@ namespace Renderer
else {
bindTexture(0);
}
drawTriangleStrips(vertices, 4, _trans,
_srcBlendFactor, _dstBlendFactor);
drawTriangleStrips(vertices, 4, _trans, _srcBlendFactor, _dstBlendFactor);
}
unsigned int rgbaToABGR(const unsigned int _color)

View file

@ -266,6 +266,7 @@ namespace Renderer
GL_CHECK_ERROR(glBlendFunc(convertBlendFactor(_srcBlendFactor),
convertBlendFactor(_dstBlendFactor)));
#if defined(USE_OPENGL_21)
if (_vertices[0].shaders == 0) {
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices));
}
@ -348,6 +349,7 @@ namespace Renderer
}
}
}
#endif
}
void setProjection(const Transform4x4f& _projection)