2020-09-18 16:40:22 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-23 18:07:00 +00:00
|
|
|
//
|
2020-09-18 16:40:22 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-11-10 21:33:57 +00:00
|
|
|
// SystemScreensaver.cpp
|
2020-06-23 18:07:00 +00:00
|
|
|
//
|
2020-11-10 21:18:20 +00:00
|
|
|
// Screensaver, supporting the following types:
|
2020-07-27 14:53:54 +00:00
|
|
|
// Dim, black, slideshow, video.
|
2020-06-23 18:07:00 +00:00
|
|
|
//
|
|
|
|
|
2020-11-10 21:33:57 +00:00
|
|
|
#include "SystemScreensaver.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2021-06-22 22:24:15 +00:00
|
|
|
#include "components/VideoFFmpegComponent.h"
|
2020-08-23 15:04:30 +00:00
|
|
|
#if defined(_RPI_)
|
2020-11-12 16:40:06 +00:00
|
|
|
#include "components/VideoOmxComponent.h"
|
2016-12-14 08:30:54 +00:00
|
|
|
#endif
|
2021-06-22 22:24:15 +00:00
|
|
|
#if defined(BUILD_VLC_PLAYER)
|
2016-12-14 08:30:54 +00:00
|
|
|
#include "components/VideoVlcComponent.h"
|
2021-06-22 22:24:15 +00:00
|
|
|
#endif
|
2021-05-11 15:30:37 +00:00
|
|
|
#include "AudioManager.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "FileData.h"
|
|
|
|
#include "Log.h"
|
2016-12-14 08:30:54 +00:00
|
|
|
#include "SystemData.h"
|
2021-07-07 18:03:42 +00:00
|
|
|
#include "resources/Font.h"
|
|
|
|
#include "utils/FileSystemUtil.h"
|
|
|
|
#include "utils/StringUtil.h"
|
|
|
|
#include "views/ViewController.h"
|
|
|
|
#include "views/gamelist/IGameListView.h"
|
2020-07-03 18:23:51 +00:00
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
#include <random>
|
2018-01-29 22:50:10 +00:00
|
|
|
#include <time.h>
|
2020-09-21 17:17:34 +00:00
|
|
|
#include <unordered_map>
|
2020-07-03 18:23:51 +00:00
|
|
|
|
2020-08-23 15:04:30 +00:00
|
|
|
#if defined(_WIN64)
|
2020-07-03 18:23:51 +00:00
|
|
|
#include <cstring>
|
|
|
|
#endif
|
|
|
|
|
2020-06-23 18:07:00 +00:00
|
|
|
#define FADE_TIME 300
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
SystemScreensaver::SystemScreensaver(Window* window)
|
|
|
|
: mWindow(window)
|
|
|
|
, mState(STATE_INACTIVE)
|
|
|
|
, mImageScreensaver(nullptr)
|
|
|
|
, mVideoScreensaver(nullptr)
|
|
|
|
, mCurrentGame(nullptr)
|
|
|
|
, mPreviousGame(nullptr)
|
|
|
|
, mTimer(0)
|
|
|
|
, mMediaSwapTime(0)
|
|
|
|
, mTriggerNextGame(false)
|
|
|
|
, mHasMediaFiles(false)
|
|
|
|
, mFallbackScreensaver(false)
|
|
|
|
, mOpacity(0.0f)
|
|
|
|
, mDimValue(1.0)
|
|
|
|
, mRectangleFadeIn(50)
|
|
|
|
, mTextFadeIn(0)
|
|
|
|
, mSaturationAmount(1.0)
|
2016-12-14 08:30:54 +00:00
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
mWindow->setScreensaver(this);
|
2016-12-14 08:30:54 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
SystemScreensaver::~SystemScreensaver()
|
2016-12-14 08:30:54 +00:00
|
|
|
{
|
2020-06-23 18:07:00 +00:00
|
|
|
mCurrentGame = nullptr;
|
|
|
|
delete mVideoScreensaver;
|
|
|
|
delete mImageScreensaver;
|
2016-12-14 08:30:54 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::startScreensaver(bool generateMediaList)
|
2016-12-14 08:30:54 +00:00
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
std::string path = "";
|
|
|
|
std::string screensaverType = Settings::getInstance()->getString("ScreensaverType");
|
|
|
|
mHasMediaFiles = false;
|
2021-03-18 19:07:07 +00:00
|
|
|
mFallbackScreensaver = false;
|
2020-11-11 23:46:59 +00:00
|
|
|
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));
|
|
|
|
}
|
2020-07-28 09:10:14 +00:00
|
|
|
|
|
|
|
// Set mPreviousGame which will be used to avoid showing the same game again during
|
|
|
|
// the random selection.
|
2020-11-11 23:46:59 +00:00
|
|
|
if ((screensaverType == "slideshow" || screensaverType == "video") && mCurrentGame != nullptr)
|
2020-07-28 09:10:14 +00:00
|
|
|
mPreviousGame = mCurrentGame;
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
if (screensaverType == "slideshow") {
|
|
|
|
if (generateMediaList) {
|
|
|
|
mImageFiles.clear();
|
|
|
|
mImageCustomFiles.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
// This creates a fade transition between the images.
|
|
|
|
mState = STATE_FADE_OUT_WINDOW;
|
|
|
|
|
2020-11-12 16:13:24 +00:00
|
|
|
mMediaSwapTime = Settings::getInstance()->getInt("ScreensaverSwapImageTimeout");
|
2020-11-10 21:18:20 +00:00
|
|
|
|
|
|
|
// Load a random image.
|
|
|
|
if (Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages")) {
|
|
|
|
if (generateMediaList)
|
|
|
|
generateCustomImageList();
|
|
|
|
pickRandomCustomImage(path);
|
|
|
|
|
|
|
|
if (mImageCustomFiles.size() > 0)
|
|
|
|
mHasMediaFiles = true;
|
|
|
|
// Custom images are not tied to the game list.
|
|
|
|
mCurrentGame = nullptr;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (generateMediaList)
|
|
|
|
generateImageList();
|
|
|
|
pickRandomImage(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mImageFiles.size() > 0)
|
|
|
|
mHasMediaFiles = true;
|
|
|
|
|
|
|
|
// Don't attempt to render the screensaver if there are no images available, but
|
2020-11-11 23:46:59 +00:00
|
|
|
// do flag it as running. This way render() will fade to a black screen, i.e. it
|
|
|
|
// will activate the 'Black' screensaver type.
|
2020-11-10 21:18:20 +00:00
|
|
|
if (mImageFiles.size() > 0 || mImageCustomFiles.size() > 0) {
|
2020-11-11 23:46:59 +00:00
|
|
|
if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo"))
|
|
|
|
generateOverlayInfo();
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
if (!mImageScreensaver)
|
|
|
|
mImageScreensaver = new ImageComponent(mWindow, false, false);
|
|
|
|
|
|
|
|
mTimer = 0;
|
|
|
|
|
|
|
|
mImageScreensaver->setImage(path);
|
|
|
|
mImageScreensaver->setOrigin(0.5f, 0.5f);
|
|
|
|
mImageScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
|
2021-07-07 18:03:42 +00:00
|
|
|
Renderer::getScreenHeight() / 2.0f);
|
2020-11-10 21:18:20 +00:00
|
|
|
|
|
|
|
if (Settings::getInstance()->getBool("ScreensaverStretchImages"))
|
|
|
|
mImageScreensaver->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()));
|
2020-11-10 21:18:20 +00:00
|
|
|
else
|
|
|
|
mImageScreensaver->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()));
|
2020-11-10 21:18:20 +00:00
|
|
|
}
|
|
|
|
mTimer = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (!mVideoScreensaver && (screensaverType == "video")) {
|
|
|
|
if (generateMediaList)
|
|
|
|
mVideoFiles.clear();
|
|
|
|
|
|
|
|
// This creates a fade transition between the videos.
|
|
|
|
mState = STATE_FADE_OUT_WINDOW;
|
|
|
|
|
2020-11-12 16:13:24 +00:00
|
|
|
mMediaSwapTime = Settings::getInstance()->getInt("ScreensaverSwapVideoTimeout");
|
2020-06-23 18:07:00 +00:00
|
|
|
|
|
|
|
// Load a random video.
|
2020-11-10 21:18:20 +00:00
|
|
|
if (generateMediaList)
|
|
|
|
generateVideoList();
|
2020-06-23 18:07:00 +00:00
|
|
|
pickRandomVideo(path);
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
if (mVideoFiles.size() > 0)
|
|
|
|
mHasMediaFiles = true;
|
2020-06-23 18:07:00 +00:00
|
|
|
|
|
|
|
if (!path.empty() && Utils::FileSystem::exists(path)) {
|
2020-11-11 23:46:59 +00:00
|
|
|
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo"))
|
|
|
|
generateOverlayInfo();
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
#if defined(_RPI_)
|
2020-11-11 23:46:59 +00:00
|
|
|
// Create the correct type of video component.
|
2020-11-05 17:18:11 +00:00
|
|
|
if (Settings::getInstance()->getBool("ScreensaverOmxPlayer"))
|
2020-11-12 16:40:06 +00:00
|
|
|
mVideoScreensaver = new VideoOmxComponent(mWindow);
|
2021-05-09 20:56:41 +00:00
|
|
|
else if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
2020-10-17 14:06:01 +00:00
|
|
|
mVideoScreensaver = new VideoVlcComponent(mWindow);
|
2021-06-22 22:24:15 +00:00
|
|
|
else
|
|
|
|
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
2021-07-07 18:03:42 +00:00
|
|
|
#elif defined(BUILD_VLC_PLAYER)
|
2021-05-09 20:56:41 +00:00
|
|
|
if (Settings::getInstance()->getString("VideoPlayer") == "vlc")
|
|
|
|
mVideoScreensaver = new VideoVlcComponent(mWindow);
|
|
|
|
else
|
|
|
|
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
2021-07-07 18:03:42 +00:00
|
|
|
#else
|
2021-06-22 22:24:15 +00:00
|
|
|
mVideoScreensaver = new VideoFFmpegComponent(mWindow);
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
2020-06-23 18:07:00 +00:00
|
|
|
|
|
|
|
mVideoScreensaver->topWindow(true);
|
|
|
|
mVideoScreensaver->setOrigin(0.5f, 0.5f);
|
|
|
|
mVideoScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f,
|
2021-07-07 18:03:42 +00:00
|
|
|
Renderer::getScreenHeight() / 2.0f);
|
2020-06-23 18:07:00 +00:00
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
if (Settings::getInstance()->getBool("ScreensaverStretchVideos"))
|
2020-09-18 16:40:22 +00:00
|
|
|
mVideoScreensaver->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()));
|
2020-06-23 18:07:00 +00:00
|
|
|
else
|
2020-09-18 16:40:22 +00:00
|
|
|
mVideoScreensaver->setMaxSize(static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()));
|
2020-06-23 18:07:00 +00:00
|
|
|
|
|
|
|
mVideoScreensaver->setVideo(path);
|
|
|
|
mVideoScreensaver->setScreensaverMode(true);
|
|
|
|
mVideoScreensaver->onShow();
|
|
|
|
mTimer = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-11-10 21:18:20 +00:00
|
|
|
// No videos or images, just use a standard screensaver.
|
2020-06-23 18:07:00 +00:00
|
|
|
mState = STATE_SCREENSAVER_ACTIVE;
|
|
|
|
mCurrentGame = nullptr;
|
2016-12-14 08:30:54 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::stopScreensaver()
|
2016-12-14 08:30:54 +00:00
|
|
|
{
|
2020-06-23 18:07:00 +00:00
|
|
|
delete mVideoScreensaver;
|
|
|
|
mVideoScreensaver = nullptr;
|
|
|
|
delete mImageScreensaver;
|
|
|
|
mImageScreensaver = nullptr;
|
|
|
|
|
|
|
|
mState = STATE_INACTIVE;
|
2020-11-11 23:46:59 +00:00
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
mDimValue = 1.0f;
|
2020-11-11 23:46:59 +00:00
|
|
|
mRectangleFadeIn = 50;
|
|
|
|
mTextFadeIn = 0;
|
2021-07-07 18:03:42 +00:00
|
|
|
mSaturationAmount = 1.0f;
|
2020-11-11 23:46:59 +00:00
|
|
|
|
|
|
|
if (mGameOverlay)
|
2021-02-28 17:58:52 +00:00
|
|
|
mGameOverlay.reset();
|
2020-11-10 21:18:20 +00:00
|
|
|
}
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
void SystemScreensaver::nextGame()
|
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
stopScreensaver();
|
|
|
|
startScreensaver(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SystemScreensaver::launchGame()
|
|
|
|
{
|
|
|
|
if (mCurrentGame != nullptr) {
|
|
|
|
// Launching game
|
2020-11-17 16:30:23 +00:00
|
|
|
ViewController::get()->triggerGameLaunch(mCurrentGame);
|
2020-11-10 21:18:20 +00:00
|
|
|
ViewController::get()->goToGameList(mCurrentGame->getSystem());
|
2021-07-07 18:03:42 +00:00
|
|
|
IGameListView* view =
|
|
|
|
ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
|
2020-11-10 21:18:20 +00:00
|
|
|
view->setCursor(mCurrentGame);
|
2020-11-16 16:44:33 +00:00
|
|
|
ViewController::get()->cancelViewTransitions();
|
2020-11-10 21:18:20 +00:00
|
|
|
}
|
2016-12-14 08:30:54 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 16:13:24 +00:00
|
|
|
void SystemScreensaver::goToGame()
|
|
|
|
{
|
|
|
|
if (mCurrentGame != nullptr) {
|
|
|
|
// Go to the game in the gamelist view, but don't launch it.
|
|
|
|
ViewController::get()->goToGameList(mCurrentGame->getSystem());
|
2021-07-07 18:03:42 +00:00
|
|
|
IGameListView* view =
|
|
|
|
ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
|
2020-11-12 16:13:24 +00:00
|
|
|
view->setCursor(mCurrentGame);
|
2020-11-16 16:44:33 +00:00
|
|
|
ViewController::get()->cancelViewTransitions();
|
2020-11-12 16:13:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::renderScreensaver()
|
2016-12-14 08:30:54 +00:00
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
std::string screensaverType = Settings::getInstance()->getString("ScreensaverType");
|
2021-03-18 19:07:07 +00:00
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
if (mVideoScreensaver && screensaverType == "video") {
|
2020-11-11 23:46:59 +00:00
|
|
|
// Render a black background below the video.
|
2020-06-23 18:07:00 +00:00
|
|
|
Renderer::setMatrix(Transform4x4f::Identity());
|
2020-12-29 10:06:01 +00:00
|
|
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
2020-06-23 18:07:00 +00:00
|
|
|
|
|
|
|
// Only render the video if the state requires it.
|
2020-09-18 16:40:22 +00:00
|
|
|
if (static_cast<int>(mState) >= STATE_FADE_IN_VIDEO) {
|
2020-06-23 18:07:00 +00:00
|
|
|
Transform4x4f transform = Transform4x4f::Identity();
|
|
|
|
mVideoScreensaver->render(transform);
|
|
|
|
}
|
|
|
|
}
|
2020-11-10 21:18:20 +00:00
|
|
|
else if (mImageScreensaver && screensaverType == "slideshow") {
|
2020-11-11 23:46:59 +00:00
|
|
|
// Render a black background below the image.
|
2020-06-23 18:07:00 +00:00
|
|
|
Renderer::setMatrix(Transform4x4f::Identity());
|
2020-12-29 10:06:01 +00:00
|
|
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
2020-06-23 18:07:00 +00:00
|
|
|
|
2020-11-11 23:46:59 +00:00
|
|
|
// Only render the image if the state requires it.
|
2020-11-10 21:18:20 +00:00
|
|
|
if (static_cast<int>(mState) >= STATE_FADE_IN_VIDEO) {
|
2020-06-23 18:07:00 +00:00
|
|
|
if (mImageScreensaver->hasImage()) {
|
2020-09-18 16:40:22 +00:00
|
|
|
mImageScreensaver->setOpacity(255 - static_cast<unsigned char>(mOpacity * 255));
|
2020-06-23 18:07:00 +00:00
|
|
|
|
|
|
|
Transform4x4f transform = Transform4x4f::Identity();
|
|
|
|
mImageScreensaver->render(transform);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-11 23:46:59 +00:00
|
|
|
|
|
|
|
if (isScreensaverActive()) {
|
2020-06-23 18:07:00 +00:00
|
|
|
Renderer::setMatrix(Transform4x4f::Identity());
|
2020-11-11 23:46:59 +00:00
|
|
|
if (Settings::getInstance()->getString("ScreensaverType") == "slideshow") {
|
|
|
|
if (mHasMediaFiles) {
|
2021-07-07 18:03:42 +00:00
|
|
|
#if defined(USE_OPENGL_21)
|
2020-11-11 23:46:59 +00:00
|
|
|
if (Settings::getInstance()->getBool("ScreensaverSlideshowScanlines"))
|
|
|
|
Renderer::shaderPostprocessing(Renderer::SHADER_SCANLINES);
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
2020-11-11 23:46:59 +00:00
|
|
|
if (Settings::getInstance()->getBool("ScreensaverSlideshowGameInfo") &&
|
2021-07-07 18:03:42 +00:00
|
|
|
mGameOverlay) {
|
2020-11-11 23:46:59 +00:00
|
|
|
if (mGameOverlayRectangleCoords.size() == 4) {
|
2021-07-07 18:03:42 +00:00
|
|
|
Renderer::drawRect(
|
|
|
|
mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1],
|
|
|
|
mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3],
|
|
|
|
0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn);
|
2020-11-11 23:46:59 +00:00
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
mRectangleFadeIn =
|
|
|
|
Math::clamp(mRectangleFadeIn + 6 + mRectangleFadeIn / 20, 0, 170);
|
2020-11-11 23:46:59 +00:00
|
|
|
|
|
|
|
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
|
2020-11-12 23:02:09 +00:00
|
|
|
if (mTextFadeIn > 50)
|
|
|
|
mGameOverlayFont.at(0)->renderTextCache(mGameOverlay.get());
|
2020-11-11 23:46:59 +00:00
|
|
|
if (mTextFadeIn < 255)
|
2020-11-12 23:02:09 +00:00
|
|
|
mTextFadeIn = Math::clamp(mTextFadeIn + 2 + mTextFadeIn / 6, 0, 255);
|
2020-11-11 23:46:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2021-03-18 19:07:07 +00:00
|
|
|
mFallbackScreensaver = true;
|
2020-11-11 23:46:59 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-18 19:07:07 +00:00
|
|
|
else if (Settings::getInstance()->getString("ScreensaverType") == "video") {
|
2020-11-11 23:46:59 +00:00
|
|
|
if (mHasMediaFiles) {
|
2021-07-07 18:03:42 +00:00
|
|
|
#if defined(USE_OPENGL_21)
|
2021-03-17 19:32:18 +00:00
|
|
|
Renderer::shaderParameters videoParameters;
|
|
|
|
unsigned int shaders = 0;
|
2020-11-11 23:46:59 +00:00
|
|
|
if (Settings::getInstance()->getBool("ScreensaverVideoScanlines"))
|
2021-03-17 19:32:18 +00:00
|
|
|
shaders = Renderer::SHADER_SCANLINES;
|
|
|
|
if (Settings::getInstance()->getBool("ScreensaverVideoBlur")) {
|
|
|
|
shaders |= Renderer::SHADER_BLUR_HORIZONTAL;
|
|
|
|
float heightModifier = Renderer::getScreenHeightModifier();
|
2021-07-07 18:03:42 +00:00
|
|
|
// clang-format off
|
2021-03-17 19:32:18 +00:00
|
|
|
if (heightModifier < 1)
|
|
|
|
videoParameters.blurPasses = 2; // Below 1080
|
|
|
|
else if (heightModifier >= 4)
|
|
|
|
videoParameters.blurPasses = 12; // 8K
|
|
|
|
else if (heightModifier >= 2.9)
|
|
|
|
videoParameters.blurPasses = 10; // 6K
|
|
|
|
else if (heightModifier >= 2.6)
|
|
|
|
videoParameters.blurPasses = 8; // 5K
|
|
|
|
else if (heightModifier >= 2)
|
|
|
|
videoParameters.blurPasses = 5; // 4K
|
|
|
|
else if (heightModifier >= 1.3)
|
|
|
|
videoParameters.blurPasses = 3; // 1440
|
|
|
|
else if (heightModifier >= 1)
|
|
|
|
videoParameters.blurPasses = 2; // 1080
|
2021-07-07 18:03:42 +00:00
|
|
|
// clang-format on
|
2021-03-17 19:32:18 +00:00
|
|
|
}
|
|
|
|
Renderer::shaderPostprocessing(shaders, videoParameters);
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
2020-11-11 23:46:59 +00:00
|
|
|
if (Settings::getInstance()->getBool("ScreensaverVideoGameInfo") && mGameOverlay) {
|
|
|
|
if (mGameOverlayRectangleCoords.size() == 4) {
|
2021-07-07 18:03:42 +00:00
|
|
|
#if defined(USE_OPENGL_21)
|
2020-11-11 23:46:59 +00:00
|
|
|
Renderer::shaderPostprocessing(Renderer::SHADER_OPACITY);
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
|
|
|
Renderer::drawRect(
|
|
|
|
mGameOverlayRectangleCoords[0], mGameOverlayRectangleCoords[1],
|
|
|
|
mGameOverlayRectangleCoords[2], mGameOverlayRectangleCoords[3],
|
|
|
|
0x00000000 | mRectangleFadeIn, 0x00000000 | mRectangleFadeIn);
|
2020-11-11 23:46:59 +00:00
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
mRectangleFadeIn =
|
|
|
|
Math::clamp(mRectangleFadeIn + 6 + mRectangleFadeIn / 20, 0, 170);
|
2020-11-11 23:46:59 +00:00
|
|
|
|
|
|
|
mGameOverlay.get()->setColor(0xFFFFFF00 | mTextFadeIn);
|
2020-11-12 23:02:09 +00:00
|
|
|
if (mTextFadeIn > 50)
|
|
|
|
mGameOverlayFont.at(0)->renderTextCache(mGameOverlay.get());
|
2020-11-11 23:46:59 +00:00
|
|
|
if (mTextFadeIn < 255)
|
2020-11-12 23:02:09 +00:00
|
|
|
mTextFadeIn = Math::clamp(mTextFadeIn + 2 + mTextFadeIn / 6, 0, 255);
|
2020-11-11 23:46:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2021-03-18 19:07:07 +00:00
|
|
|
mFallbackScreensaver = true;
|
2020-11-11 23:46:59 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-18 19:07:07 +00:00
|
|
|
if (mFallbackScreensaver ||
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getString("ScreensaverType") == "dim") {
|
|
|
|
#if defined(USE_OPENGL_21)
|
2020-11-11 23:46:59 +00:00
|
|
|
Renderer::shaderParameters dimParameters;
|
|
|
|
dimParameters.fragmentDimValue = mDimValue;
|
|
|
|
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, dimParameters);
|
|
|
|
if (mDimValue > 0.4)
|
2020-12-29 10:06:01 +00:00
|
|
|
mDimValue = Math::clamp(mDimValue - 0.021f, 0.4f, 1.0f);
|
2020-11-11 23:46:59 +00:00
|
|
|
dimParameters.fragmentSaturation = mSaturationAmount;
|
|
|
|
Renderer::shaderPostprocessing(Renderer::SHADER_DESATURATE, dimParameters);
|
|
|
|
if (mSaturationAmount > 0.0)
|
2020-12-29 10:06:01 +00:00
|
|
|
mSaturationAmount = Math::clamp(mSaturationAmount - 0.035f, 0.0f, 1.0f);
|
2021-07-07 18:03:42 +00:00
|
|
|
#else
|
|
|
|
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
|
|
|
|
0x000000A0, 0x000000A0);
|
|
|
|
#endif
|
2020-11-11 23:46:59 +00:00
|
|
|
}
|
2021-05-16 16:02:07 +00:00
|
|
|
else if (Settings::getInstance()->getString("ScreensaverType") == "black") {
|
2021-07-07 18:03:42 +00:00
|
|
|
#if defined(USE_OPENGL_21)
|
2021-05-16 16:02:07 +00:00
|
|
|
Renderer::shaderParameters blackParameters;
|
|
|
|
blackParameters.fragmentDimValue = mDimValue;
|
|
|
|
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, blackParameters);
|
|
|
|
if (mDimValue > 0.0)
|
|
|
|
mDimValue = Math::clamp(mDimValue - 0.045f, 0.0f, 1.0f);
|
2021-07-07 18:03:42 +00:00
|
|
|
#else
|
|
|
|
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
|
|
|
|
0x000000FF, 0x000000FF);
|
|
|
|
#endif
|
2021-05-16 16:02:07 +00:00
|
|
|
}
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
2016-12-14 08:30:54 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::update(int deltaTime)
|
2016-12-14 08:30:54 +00:00
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
// Use this to update the fade value for the current fade stage.
|
|
|
|
if (mState == STATE_FADE_OUT_WINDOW) {
|
|
|
|
mOpacity += static_cast<float>(deltaTime) / FADE_TIME;
|
|
|
|
if (mOpacity >= 1.0f) {
|
|
|
|
mOpacity = 1.0f;
|
2020-06-23 18:07:00 +00:00
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
// Update to the next state.
|
|
|
|
mState = STATE_FADE_IN_VIDEO;
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-10 21:18:20 +00:00
|
|
|
else if (mState == STATE_FADE_IN_VIDEO) {
|
|
|
|
mOpacity -= static_cast<float>(deltaTime) / FADE_TIME;
|
|
|
|
if (mOpacity <= 0.0f) {
|
|
|
|
mOpacity = 0.0f;
|
|
|
|
// Update to the next state.
|
|
|
|
mState = STATE_SCREENSAVER_ACTIVE;
|
|
|
|
}
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
2020-11-10 21:18:20 +00:00
|
|
|
else if (mState == STATE_SCREENSAVER_ACTIVE) {
|
2020-11-12 16:13:24 +00:00
|
|
|
// Update the timer that swaps the media, unless the swap time is set to 0 (only
|
|
|
|
// applicable for the video screensaver). This means that videos play to the end,
|
2021-06-22 22:24:15 +00:00
|
|
|
// at which point the video player will trigger a skip to the next game.
|
2020-11-12 16:13:24 +00:00
|
|
|
if (mMediaSwapTime != 0) {
|
|
|
|
mTimer += deltaTime;
|
|
|
|
if (mTimer > mMediaSwapTime)
|
|
|
|
nextGame();
|
|
|
|
}
|
|
|
|
if (mTriggerNextGame) {
|
|
|
|
mTriggerNextGame = false;
|
2020-11-10 21:18:20 +00:00
|
|
|
nextGame();
|
2020-11-12 16:13:24 +00:00
|
|
|
}
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
2020-11-10 21:18:20 +00:00
|
|
|
|
2020-11-12 16:13:24 +00:00
|
|
|
// If we have a loaded a video or image, then update it.
|
2020-11-10 21:18:20 +00:00
|
|
|
if (mVideoScreensaver)
|
|
|
|
mVideoScreensaver->update(deltaTime);
|
|
|
|
if (mImageScreensaver)
|
|
|
|
mImageScreensaver->update(deltaTime);
|
2017-09-09 03:45:50 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::generateImageList()
|
2017-09-09 03:45:50 +00:00
|
|
|
{
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
|
|
|
it != SystemData::sSystemVector.cend(); it++) {
|
2020-06-23 18:07:00 +00:00
|
|
|
// We only want nodes from game systems that are not collections.
|
|
|
|
if (!(*it)->isGameSystem() || (*it)->isCollection())
|
|
|
|
continue;
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
std::vector<FileData*> allFiles = (*it)->getRootFolder()->getFilesRecursive(GAME, true);
|
|
|
|
for (auto it = allFiles.begin(); it != allFiles.end(); it++) {
|
|
|
|
std::string imagePath = (*it)->getImagePath();
|
|
|
|
if (imagePath != "")
|
|
|
|
mImageFiles.push_back((*it));
|
2020-07-28 09:10:14 +00:00
|
|
|
}
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
2017-09-09 03:45:50 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::generateVideoList()
|
2017-09-09 03:45:50 +00:00
|
|
|
{
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
|
|
|
it != SystemData::sSystemVector.cend(); it++) {
|
2020-11-10 21:18:20 +00:00
|
|
|
// We only want nodes from game systems that are not collections.
|
|
|
|
if (!(*it)->isGameSystem() || (*it)->isCollection())
|
|
|
|
continue;
|
2020-07-28 09:10:14 +00:00
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
std::vector<FileData*> allFiles = (*it)->getRootFolder()->getFilesRecursive(GAME, true);
|
|
|
|
for (auto it = allFiles.begin(); it != allFiles.end(); it++) {
|
|
|
|
std::string videoPath = (*it)->getVideoPath();
|
|
|
|
if (videoPath != "")
|
|
|
|
mVideoFiles.push_back((*it));
|
2020-07-28 09:10:14 +00:00
|
|
|
}
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
2017-09-09 03:45:50 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::generateCustomImageList()
|
2017-09-09 03:45:50 +00:00
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
std::string imageDir = Utils::FileSystem::expandHomePath(
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getString("ScreensaverSlideshowImageDir"));
|
2020-06-23 18:07:00 +00:00
|
|
|
|
2021-06-30 15:11:25 +00:00
|
|
|
// This makes it possible to set the custom image directory relative to the ES-DE binary
|
|
|
|
// directory or the ROM directory.
|
|
|
|
imageDir = Utils::String::replace(imageDir, "%ESPATH%", Utils::FileSystem::getExePath());
|
|
|
|
imageDir = Utils::String::replace(imageDir, "%ROMPATH%", FileData::getROMDirectory());
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
if (imageDir != "" && Utils::FileSystem::isDirectory(imageDir)) {
|
2020-11-05 17:18:11 +00:00
|
|
|
std::string imageFilter = ".jpg, .JPG, .png, .PNG";
|
2020-06-23 18:07:00 +00:00
|
|
|
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(
|
2021-07-07 18:03:42 +00:00
|
|
|
imageDir, Settings::getInstance()->getBool("ScreensaverSlideshowRecurse"));
|
2020-06-23 18:07:00 +00:00
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
for (auto it = dirContent.begin(); it != dirContent.end(); it++) {
|
2020-06-23 18:07:00 +00:00
|
|
|
if (Utils::FileSystem::isRegularFile(*it)) {
|
2020-11-10 21:18:20 +00:00
|
|
|
if (imageFilter.find(Utils::FileSystem::getExtension(*it)) != std::string::npos)
|
|
|
|
mImageCustomFiles.push_back(*it);
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2021-07-07 18:03:42 +00:00
|
|
|
LOG(LogWarning) << "Custom screensaver image directory '" << imageDir << "' does not exist";
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
2017-09-09 03:45:50 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::pickRandomImage(std::string& path)
|
2016-12-14 08:30:54 +00:00
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
mCurrentGame = nullptr;
|
2020-06-23 18:07:00 +00:00
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
if (mImageFiles.size() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (mImageFiles.size() == 1) {
|
|
|
|
mPreviousGame = nullptr;
|
|
|
|
mCurrentGame = mImageFiles.front();
|
|
|
|
path = mImageFiles.front()->getImagePath();
|
2021-01-11 19:12:45 +00:00
|
|
|
mGameName = mImageFiles.front()->getName();
|
|
|
|
mSystemName = mImageFiles.front()->getSystem()->getFullName();
|
|
|
|
mCurrentGame = mImageFiles.front();
|
2020-11-10 21:18:20 +00:00
|
|
|
return;
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
unsigned int index;
|
|
|
|
do {
|
|
|
|
// Get a random number in range.
|
|
|
|
std::random_device randDev;
|
|
|
|
// Mersenne Twister pseudorandom number generator.
|
2021-07-07 18:03:42 +00:00
|
|
|
std::mt19937 engine { randDev() };
|
|
|
|
std::uniform_int_distribution<int> uniform_dist(0,
|
|
|
|
static_cast<int>(mImageFiles.size()) - 1);
|
2020-11-10 21:18:20 +00:00
|
|
|
index = uniform_dist(engine);
|
2021-07-07 18:03:42 +00:00
|
|
|
} while (mPreviousGame && mImageFiles.at(index) == mPreviousGame);
|
2017-06-01 20:08:44 +00:00
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
path = mImageFiles.at(index)->getImagePath();
|
|
|
|
mGameName = mImageFiles.at(index)->getName();
|
|
|
|
mSystemName = mImageFiles.at(index)->getSystem()->getFullName();
|
|
|
|
mCurrentGame = mImageFiles.at(index);
|
2017-06-01 20:08:44 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::pickRandomVideo(std::string& path)
|
2017-06-01 20:08:44 +00:00
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
mCurrentGame = nullptr;
|
|
|
|
|
|
|
|
if (mVideoFiles.size() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (mVideoFiles.size() == 1) {
|
|
|
|
mPreviousGame = nullptr;
|
|
|
|
mCurrentGame = mVideoFiles.front();
|
|
|
|
path = mVideoFiles.front()->getVideoPath();
|
2021-01-11 19:12:45 +00:00
|
|
|
mGameName = mVideoFiles.front()->getName();
|
|
|
|
mSystemName = mVideoFiles.front()->getSystem()->getFullName();
|
|
|
|
mCurrentGame = mVideoFiles.front();
|
2020-11-10 21:18:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int index;
|
|
|
|
do {
|
|
|
|
// Get a random number in range.
|
|
|
|
std::random_device randDev;
|
|
|
|
// Mersenne Twister pseudorandom number generator.
|
2021-07-07 18:03:42 +00:00
|
|
|
std::mt19937 engine { randDev() };
|
|
|
|
std::uniform_int_distribution<int> uniform_dist(0,
|
|
|
|
static_cast<int>(mVideoFiles.size()) - 1);
|
2020-11-10 21:18:20 +00:00
|
|
|
index = uniform_dist(engine);
|
2021-07-07 18:03:42 +00:00
|
|
|
} while (mPreviousGame && mVideoFiles.at(index) == mPreviousGame);
|
2020-11-10 21:18:20 +00:00
|
|
|
|
|
|
|
path = mVideoFiles.at(index)->getVideoPath();
|
|
|
|
mGameName = mVideoFiles.at(index)->getName();
|
|
|
|
mSystemName = mVideoFiles.at(index)->getSystem()->getFullName();
|
|
|
|
mCurrentGame = mVideoFiles.at(index);
|
2017-06-01 20:08:44 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void SystemScreensaver::pickRandomCustomImage(std::string& path)
|
2017-06-01 20:08:44 +00:00
|
|
|
{
|
2020-11-10 21:18:20 +00:00
|
|
|
if (mImageCustomFiles.size() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (mVideoFiles.size() == 1) {
|
|
|
|
mPreviousCustomImage = mImageCustomFiles.front();
|
|
|
|
path = mImageCustomFiles.front();
|
|
|
|
return;
|
2020-06-23 18:07:00 +00:00
|
|
|
}
|
2020-11-10 21:18:20 +00:00
|
|
|
|
|
|
|
unsigned int index;
|
|
|
|
do {
|
|
|
|
// Get a random number in range.
|
|
|
|
std::random_device randDev;
|
|
|
|
// Mersenne Twister pseudorandom number generator.
|
2021-07-07 18:03:42 +00:00
|
|
|
std::mt19937 engine { randDev() };
|
|
|
|
std::uniform_int_distribution<int> uniform_dist(
|
|
|
|
0, static_cast<int>(mImageCustomFiles.size()) - 1);
|
2020-11-10 21:18:20 +00:00
|
|
|
index = uniform_dist(engine);
|
2021-07-07 18:03:42 +00:00
|
|
|
} while (mPreviousCustomImage != "" && mImageCustomFiles.at(index) == mPreviousCustomImage);
|
2020-11-10 21:18:20 +00:00
|
|
|
|
|
|
|
path = mImageCustomFiles.at(index);
|
|
|
|
mPreviousCustomImage = path;
|
|
|
|
mGameName = "";
|
|
|
|
mSystemName = "";
|
2017-08-02 19:56:33 +00:00
|
|
|
}
|
2020-11-11 23:46:59 +00:00
|
|
|
|
|
|
|
void SystemScreensaver::generateOverlayInfo()
|
|
|
|
{
|
|
|
|
if (mGameName == "" || mSystemName == "")
|
|
|
|
return;
|
|
|
|
|
2020-12-29 10:06:01 +00:00
|
|
|
float posX = static_cast<float>(Renderer::getWindowWidth()) * 0.023f;
|
|
|
|
float posY = static_cast<float>(Renderer::getWindowHeight()) * 0.02f;
|
2020-11-12 16:13:24 +00:00
|
|
|
|
|
|
|
std::string favoriteChar;
|
2021-03-01 18:40:23 +00:00
|
|
|
if (mCurrentGame && mCurrentGame->getFavorite())
|
2020-12-16 20:19:48 +00:00
|
|
|
favoriteChar = " " + ViewController::FAVORITE_CHAR;
|
2020-11-11 23:46:59 +00:00
|
|
|
|
2020-11-12 16:13:24 +00:00
|
|
|
const std::string gameName = Utils::String::toUpper(mGameName) + favoriteChar;
|
2020-11-11 23:46:59 +00:00
|
|
|
const std::string systemName = Utils::String::toUpper(mSystemName);
|
|
|
|
const std::string overlayText = gameName + "\n" + systemName;
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
mGameOverlay = std::unique_ptr<TextCache>(
|
|
|
|
mGameOverlayFont.at(0)->buildTextCache(overlayText, posX, posY, 0xFFFFFFFF));
|
2020-11-11 23:46:59 +00:00
|
|
|
|
|
|
|
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() >
|
2021-07-07 18:03:42 +00:00
|
|
|
mGameOverlayFont[0].get()->sizeText(systemName).x())
|
2020-11-11 23:46:59 +00:00
|
|
|
textSizeX = mGameOverlayFont[0].get()->sizeText(gameName).x();
|
|
|
|
else
|
|
|
|
textSizeX = mGameOverlayFont[0].get()->sizeText(systemName).x();
|
|
|
|
|
2020-12-29 10:06:01 +00:00
|
|
|
float marginX = Renderer::getWindowWidth() * 0.01f;
|
2020-11-11 23:46:59 +00:00
|
|
|
|
|
|
|
mGameOverlayRectangleCoords.clear();
|
|
|
|
mGameOverlayRectangleCoords.push_back(posX - marginX);
|
|
|
|
mGameOverlayRectangleCoords.push_back(posY);
|
2021-05-12 21:03:29 +00:00
|
|
|
mGameOverlayRectangleCoords.push_back(textSizeX + marginX * 2.0f);
|
2020-11-11 23:46:59 +00:00
|
|
|
mGameOverlayRectangleCoords.push_back(textSizeY);
|
|
|
|
}
|