ES-DE/es-app/src/SystemScreenSaver.cpp
Tomas Jakobsson 489d7de096 Eliminate drawRect that takes int's and make sure everything uses the float version properly, this way everything is rounded the same way
Only round the transforms when setting them on the GPU, to make sure everything is rounded the same, but only at the final moment
2019-08-31 17:58:36 +02:00

475 lines
13 KiB
C++

#include "SystemScreenSaver.h"
#ifdef _RPI_
#include "components/VideoPlayerComponent.h"
#endif
#include "components/VideoVlcComponent.h"
#include "utils/FileSystemUtil.h"
#include "views/gamelist/IGameListView.h"
#include "views/ViewController.h"
#include "FileData.h"
#include "FileFilterIndex.h"
#include "Log.h"
#include "PowerSaver.h"
#include "Sound.h"
#include "SystemData.h"
#include <unordered_map>
#include <time.h>
#define FADE_TIME 300
SystemScreenSaver::SystemScreenSaver(Window* window) :
mVideoScreensaver(NULL),
mImageScreensaver(NULL),
mWindow(window),
mVideosCounted(false),
mVideoCount(0),
mImagesCounted(false),
mImageCount(0),
mState(STATE_INACTIVE),
mOpacity(0.0f),
mTimer(0),
mSystemName(""),
mGameName(""),
mCurrentGame(NULL),
mStopBackgroundAudio(true)
{
mWindow->setScreenSaver(this);
std::string path = getTitleFolder();
if(!Utils::FileSystem::exists(path))
Utils::FileSystem::createDirectory(path);
srand((unsigned int)time(NULL));
mVideoChangeTime = 30000;
}
SystemScreenSaver::~SystemScreenSaver()
{
// Delete subtitle file, if existing
remove(getTitlePath().c_str());
mCurrentGame = NULL;
delete mVideoScreensaver;
delete mImageScreensaver;
}
bool SystemScreenSaver::allowSleep()
{
//return false;
return ((mVideoScreensaver == NULL) && (mImageScreensaver == NULL));
}
bool SystemScreenSaver::isScreenSaverActive()
{
return (mState != STATE_INACTIVE);
}
void SystemScreenSaver::startScreenSaver()
{
std::string screensaver_behavior = Settings::getInstance()->getString("ScreenSaverBehavior");
if (!mVideoScreensaver && (screensaver_behavior == "random video"))
{
// Configure to fade out the windows, Skip Fading if Instant mode
mState = PowerSaver::getMode() == PowerSaver::INSTANT
? STATE_SCREENSAVER_ACTIVE
: STATE_FADE_OUT_WINDOW;
mVideoChangeTime = Settings::getInstance()->getInt("ScreenSaverSwapVideoTimeout");
mOpacity = 0.0f;
// Load a random video
std::string path = "";
pickRandomVideo(path);
int retry = 200;
while(retry > 0 && ((path.empty() || !Utils::FileSystem::exists(path)) || mCurrentGame == NULL))
{
retry--;
pickRandomVideo(path);
}
if (!path.empty() && Utils::FileSystem::exists(path))
{
#ifdef _RPI_
// Create the correct type of video component
if (Settings::getInstance()->getBool("ScreenSaverOmxPlayer"))
mVideoScreensaver = new VideoPlayerComponent(mWindow, getTitlePath());
else
mVideoScreensaver = new VideoVlcComponent(mWindow, getTitlePath());
#else
mVideoScreensaver = new VideoVlcComponent(mWindow, getTitlePath());
#endif
mVideoScreensaver->topWindow(true);
mVideoScreensaver->setOrigin(0.5f, 0.5f);
mVideoScreensaver->setPosition(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f);
if (Settings::getInstance()->getBool("StretchVideoOnScreenSaver"))
{
mVideoScreensaver->setResize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
else
{
mVideoScreensaver->setMaxSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
mVideoScreensaver->setVideo(path);
mVideoScreensaver->setScreensaverMode(true);
mVideoScreensaver->onShow();
PowerSaver::runningScreenSaver(true);
mTimer = 0;
return;
}
}
else if (screensaver_behavior == "slideshow")
{
// Configure to fade out the windows, Skip Fading if Instant mode
mState = PowerSaver::getMode() == PowerSaver::INSTANT
? STATE_SCREENSAVER_ACTIVE
: STATE_FADE_OUT_WINDOW;
mVideoChangeTime = Settings::getInstance()->getInt("ScreenSaverSwapImageTimeout");
mOpacity = 0.0f;
// Load a random image
std::string path = "";
if (Settings::getInstance()->getBool("SlideshowScreenSaverCustomImageSource"))
{
pickRandomCustomImage(path);
// Custom images are not tied to the game list
mCurrentGame = NULL;
}
else
{
pickRandomGameListImage(path);
}
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, Renderer::getScreenHeight() / 2.0f);
if (Settings::getInstance()->getBool("SlideshowScreenSaverStretch"))
{
mImageScreensaver->setResize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
else
{
mImageScreensaver->setMaxSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
}
std::string bg_audio_file = Settings::getInstance()->getString("SlideshowScreenSaverBackgroundAudioFile");
if ((!mBackgroundAudio) && (bg_audio_file != ""))
{
if (Utils::FileSystem::exists(bg_audio_file))
{
// paused PS so that the background audio keeps playing
PowerSaver::pause();
mBackgroundAudio = Sound::get(bg_audio_file);
mBackgroundAudio->play();
}
}
PowerSaver::runningScreenSaver(true);
mTimer = 0;
return;
}
// No videos. Just use a standard screensaver
mState = STATE_SCREENSAVER_ACTIVE;
mCurrentGame = NULL;
}
void SystemScreenSaver::stopScreenSaver()
{
if ((mBackgroundAudio) && (mStopBackgroundAudio))
{
mBackgroundAudio->stop();
mBackgroundAudio.reset();
// if we were playing audio, we paused PS
PowerSaver::resume();
}
// so that we stop the background audio next time, unless we're restarting the screensaver
mStopBackgroundAudio = true;
delete mVideoScreensaver;
mVideoScreensaver = NULL;
delete mImageScreensaver;
mImageScreensaver = NULL;
// we need this to loop through different videos
mState = STATE_INACTIVE;
PowerSaver::runningScreenSaver(false);
}
void SystemScreenSaver::renderScreenSaver()
{
std::string screensaver_behavior = Settings::getInstance()->getString("ScreenSaverBehavior");
if (mVideoScreensaver && screensaver_behavior == "random video")
{
// Render black background
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
if ((int)mState >= STATE_FADE_IN_VIDEO)
{
Transform4x4f transform = Transform4x4f::Identity();
mVideoScreensaver->render(transform);
}
}
else if (mImageScreensaver && screensaver_behavior == "slideshow")
{
// Render black background
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
if ((int)mState >= STATE_FADE_IN_VIDEO)
{
if (mImageScreensaver->hasImage())
{
mImageScreensaver->setOpacity(255- (unsigned char) (mOpacity * 255));
Transform4x4f transform = Transform4x4f::Identity();
mImageScreensaver->render(transform);
}
}
// Check if we need to restart the background audio
if ((mBackgroundAudio) && (Settings::getInstance()->getString("SlideshowScreenSaverBackgroundAudioFile") != ""))
{
if (!mBackgroundAudio->isPlaying())
{
mBackgroundAudio->play();
}
}
}
else if (mState != STATE_INACTIVE)
{
Renderer::setMatrix(Transform4x4f::Identity());
unsigned char color = screensaver_behavior == "dim" ? 0x000000A0 : 0x000000FF;
Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), color, color);
}
}
unsigned long SystemScreenSaver::countGameListNodes(const char *nodeName)
{
unsigned long nodeCount = 0;
std::vector<SystemData*>::const_iterator it;
for (it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend(); ++it)
{
// We only want nodes from game systems that are not collections
if (!(*it)->isGameSystem() || (*it)->isCollection())
continue;
FileData* rootFileData = (*it)->getRootFolder();
FileType type = GAME;
std::vector<FileData*> allFiles = rootFileData->getFilesRecursive(type, true);
std::vector<FileData*>::const_iterator itf; // declare an iterator to a vector of strings
for(itf=allFiles.cbegin() ; itf < allFiles.cend(); itf++) {
if ((strcmp(nodeName, "video") == 0 && (*itf)->getVideoPath() != "") ||
(strcmp(nodeName, "image") == 0 && (*itf)->getImagePath() != ""))
{
nodeCount++;
}
}
}
return nodeCount;
}
void SystemScreenSaver::countVideos()
{
if (!mVideosCounted)
{
mVideoCount = countGameListNodes("video");
mVideosCounted = true;
}
}
void SystemScreenSaver::countImages()
{
if (!mImagesCounted)
{
mImageCount = countGameListNodes("image");
mImagesCounted = true;
}
}
void SystemScreenSaver::pickGameListNode(unsigned long index, const char *nodeName, std::string& path)
{
std::vector<SystemData*>::const_iterator it;
for (it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend(); ++it)
{
// We only want nodes from game systems that are not collections
if (!(*it)->isGameSystem() || (*it)->isCollection())
continue;
FileData* rootFileData = (*it)->getRootFolder();
FileType type = GAME;
std::vector<FileData*> allFiles = rootFileData->getFilesRecursive(type, true);
std::vector<FileData*>::const_iterator itf; // declare an iterator to a vector of strings
for(itf=allFiles.cbegin() ; itf < allFiles.cend(); itf++) {
if ((strcmp(nodeName, "video") == 0 && (*itf)->getVideoPath() != "") ||
(strcmp(nodeName, "image") == 0 && (*itf)->getImagePath() != ""))
{
if (index-- == 0)
{
// We have it
path = "";
if (strcmp(nodeName, "video") == 0)
path = (*itf)->getVideoPath();
else if (strcmp(nodeName, "image") == 0)
path = (*itf)->getImagePath();
mSystemName = (*it)->getFullName();
mGameName = (*itf)->getName();
mCurrentGame = (*itf);
// end of getting FileData
if (Settings::getInstance()->getString("ScreenSaverGameInfo") != "never")
writeSubtitle(mGameName.c_str(), mSystemName.c_str(),
(Settings::getInstance()->getString("ScreenSaverGameInfo") == "always"));
return;
}
}
}
}
}
void SystemScreenSaver::pickRandomVideo(std::string& path)
{
countVideos();
mCurrentGame = NULL;
if (mVideoCount > 0)
{
int video = (int)(((float)rand() / float(RAND_MAX)) * (float)mVideoCount);
pickGameListNode(video, "video", path);
}
}
void SystemScreenSaver::pickRandomGameListImage(std::string& path)
{
countImages();
mCurrentGame = NULL;
if (mImageCount > 0)
{
int image = (int)(((float)rand() / float(RAND_MAX)) * (float)mImageCount);
pickGameListNode(image, "image", path);
}
}
void SystemScreenSaver::pickRandomCustomImage(std::string& path)
{
std::string imageDir = Settings::getInstance()->getString("SlideshowScreenSaverImageDir");
if ((imageDir != "") && (Utils::FileSystem::exists(imageDir)))
{
std::string imageFilter = Settings::getInstance()->getString("SlideshowScreenSaverImageFilter");
std::vector<std::string> matchingFiles;
Utils::FileSystem::stringList dirContent = Utils::FileSystem::getDirContent(imageDir, Settings::getInstance()->getBool("SlideshowScreenSaverRecurse"));
for(Utils::FileSystem::stringList::const_iterator it = dirContent.cbegin(); it != dirContent.cend(); ++it)
{
if (Utils::FileSystem::isRegularFile(*it))
{
// If the image filter is empty, or the file extension is in the filter string,
// add it to the matching files list
if ((imageFilter.length() <= 0) ||
(imageFilter.find(Utils::FileSystem::getExtension(*it)) != std::string::npos))
{
matchingFiles.push_back(*it);
}
}
}
int fileCount = (int)matchingFiles.size();
if (fileCount > 0)
{
// get a random index in the range 0 to fileCount (exclusive)
int randomIndex = rand() % fileCount;
path = matchingFiles[randomIndex];
}
else
{
LOG(LogError) << "Slideshow Screensaver - No image files found\n";
}
}
else
{
LOG(LogError) << "Slideshow Screensaver - Image directory does not exist: " << imageDir << "\n";
}
}
void SystemScreenSaver::update(int deltaTime)
{
// Use this to update the fade value for the current fade stage
if (mState == STATE_FADE_OUT_WINDOW)
{
mOpacity += (float)deltaTime / FADE_TIME;
if (mOpacity >= 1.0f)
{
mOpacity = 1.0f;
// Update to the next state
mState = STATE_FADE_IN_VIDEO;
}
}
else if (mState == STATE_FADE_IN_VIDEO)
{
mOpacity -= (float)deltaTime / FADE_TIME;
if (mOpacity <= 0.0f)
{
mOpacity = 0.0f;
// Update to the next state
mState = STATE_SCREENSAVER_ACTIVE;
}
}
else if (mState == STATE_SCREENSAVER_ACTIVE)
{
// Update the timer that swaps the videos
mTimer += deltaTime;
if (mTimer > mVideoChangeTime)
{
nextVideo();
}
}
// If we have a loaded video then update it
if (mVideoScreensaver)
mVideoScreensaver->update(deltaTime);
if (mImageScreensaver)
mImageScreensaver->update(deltaTime);
}
void SystemScreenSaver::nextVideo() {
mStopBackgroundAudio = false;
stopScreenSaver();
startScreenSaver();
mState = STATE_SCREENSAVER_ACTIVE;
}
FileData* SystemScreenSaver::getCurrentGame()
{
return mCurrentGame;
}
void SystemScreenSaver::launchGame()
{
if (mCurrentGame != NULL)
{
// launching Game
ViewController::get()->goToGameList(mCurrentGame->getSystem());
IGameListView* view = ViewController::get()->getGameListView(mCurrentGame->getSystem()).get();
view->setCursor(mCurrentGame);
if (Settings::getInstance()->getBool("ScreenSaverControls"))
{
view->launch(mCurrentGame);
}
}
}