diff --git a/NEWS.md b/NEWS.md index 75726d916..c1fafff4e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -56,6 +56,7 @@ Many bugs have been fixed, and numerous features that were only partially implem * Refactoring, cleanup and documentation of the source code, removal of deprecated files etc. * All required fonts bundled with the application, no dependencies on the OS to provide them any longer * Made pugixml an external dependency instead of bundling it +* Decreased CPU usage dramatically by only rendering the currently visible view (previously every view were always rendered) * Updated the CMake/CPack install and package build script to work as expected (it can now generate .deb, .rpm, .dmg and NSIS installation packages) * Added support for Clang/LLVM, made the application build with no errors or warnings using this compiler (Unix and macOS only) * License files included for all the libraries and resources that are bundled with the application @@ -79,6 +80,7 @@ Many bugs have been fixed, and numerous features that were only partially implem * The random game selection traversed folders, i.e. a game could be selected inside a subdirectory and vice versa * Deleting a game from the metadata editor did not delete the game media files or the entry in the gamelist.xml file * SystemView didn't properly loop the systems if only two systems were available +* When changing to the video view style from inside a gamelist, the view was not initialized * Hidden files still showed up if they had a gamelist.xml entry * Fixed an annoying gamelist issue that caused the game images and data to be updated and rendered up to six times every time the list was scrolled * VRAM statistics overlay was somewhat broken and incorrectly displayed numbers in megabytes instead of mebibytes diff --git a/es-app/src/animations/MoveCameraAnimation.h b/es-app/src/animations/MoveCameraAnimation.h index d4729ff4f..8c308f5bd 100644 --- a/es-app/src/animations/MoveCameraAnimation.h +++ b/es-app/src/animations/MoveCameraAnimation.h @@ -1,11 +1,11 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // MoveCameraAnimation.h // -// Animation to play when moving the camera, used by the slide transition style -// (when moving between gamelists using quick system select). +// Animation to play when moving the camera, used by the slide transition style. // -#pragma once #ifndef ES_APP_ANIMATIONS_MOVE_CAMERA_ANIMATION_H #define ES_APP_ANIMATIONS_MOVE_CAMERA_ANIMATION_H diff --git a/es-app/src/guis/GuiGamelistOptions.cpp b/es-app/src/guis/GuiGamelistOptions.cpp index 257406d8f..7a6b887a1 100644 --- a/es-app/src/guis/GuiGamelistOptions.cpp +++ b/es-app/src/guis/GuiGamelistOptions.cpp @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // GuiGamelistOptions.cpp // // Gamelist options menu for the 'Jump to...' quick selector, @@ -19,8 +21,8 @@ #include "FileFilterIndex.h" #include "FileSorts.h" #include "GuiMetaDataEd.h" -#include "SystemData.h" #include "Sound.h" +#include "SystemData.h" GuiGamelistOptions::GuiGamelistOptions( Window* window, @@ -177,6 +179,11 @@ GuiGamelistOptions::GuiGamelistOptions( GuiGamelistOptions::~GuiGamelistOptions() { + // This is required for the situation where scrolling started just before the menu + // was openened. Without this, the scrolling would run until manually stopped after + // the menu has been closed. + ViewController::get()->stopScrolling(); + if (mCancelled) return; diff --git a/es-app/src/guis/GuiGamelistOptions.h b/es-app/src/guis/GuiGamelistOptions.h index b8558e107..5f38c0d78 100644 --- a/es-app/src/guis/GuiGamelistOptions.h +++ b/es-app/src/guis/GuiGamelistOptions.h @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // GuiGamelistOptions.h // // Gamelist options menu for the 'Jump to...' quick selector, @@ -8,15 +10,14 @@ // metadata edit interface is covered by GuiMetaDataEd. // -#pragma once #ifndef ES_APP_GUIS_GUI_GAME_LIST_OPTIONS_H #define ES_APP_GUIS_GUI_GAME_LIST_OPTIONS_H #include "components/MenuComponent.h" #include "components/OptionListComponent.h" +#include "utils/StringUtil.h" #include "FileData.h" #include "GuiComponent.h" -#include "utils/StringUtil.h" class IGameListView; class SystemData; diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 6105decdc..d9a9e12e5 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // GuiMenu.cpp // // Main menu. @@ -17,9 +19,9 @@ #include "guis/GuiMsgBox.h" #include "guis/GuiScraperMenu.h" #include "guis/GuiSettings.h" +#include "views/gamelist/IGameListView.h" #include "views/UIModeController.h" #include "views/ViewController.h" -#include "views/gamelist/IGameListView.h" #include "CollectionSystemManager.h" #include "EmulationStation.h" #include "FileSorts.h" @@ -63,6 +65,14 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), Renderer::getScreenHeight() * 0.15f); } +GuiMenu::~GuiMenu() +{ + // This is required for the situation where scrolling started just before the menu + // was openened. Without this, the scrolling would run until manually stopped after + // the menu has been closed. + ViewController::get()->stopScrolling(); +} + void GuiMenu::openScraperSettings() { // Open the scrape menu. diff --git a/es-app/src/guis/GuiMenu.h b/es-app/src/guis/GuiMenu.h index f6ce43c9a..4c193e826 100644 --- a/es-app/src/guis/GuiMenu.h +++ b/es-app/src/guis/GuiMenu.h @@ -1,11 +1,12 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // GuiMenu.h // // Main menu. // Some submenus are covered in separate source files. // -#pragma once #ifndef ES_APP_GUIS_GUI_MENU_H #define ES_APP_GUIS_GUI_MENU_H @@ -16,6 +17,7 @@ class GuiMenu : public GuiComponent { public: GuiMenu(Window* window); + ~GuiMenu(); bool input(InputConfig* config, Input input) override; void onSizeChanged() override; diff --git a/es-app/src/views/SystemView.cpp b/es-app/src/views/SystemView.cpp index 602939bdc..ac1a148ad 100644 --- a/es-app/src/views/SystemView.cpp +++ b/es-app/src/views/SystemView.cpp @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // SystemView.cpp // // Main system view. @@ -177,10 +179,12 @@ bool SystemView::input(InputConfig* config, Input input) case VERTICAL: case VERTICAL_WHEEL: if (config->isMappedLike("up", input)) { + ViewController::get()->resetMovingCamera(); listInput(-1); return true; } if (config->isMappedLike("down", input)) { + ViewController::get()->resetMovingCamera(); listInput(1); return true; } @@ -189,10 +193,12 @@ bool SystemView::input(InputConfig* config, Input input) case HORIZONTAL_WHEEL: default: if (config->isMappedLike("left", input)) { + ViewController::get()->resetMovingCamera(); listInput(-1); return true; } if (config->isMappedLike("right", input)) { + ViewController::get()->resetMovingCamera(); listInput(1); return true; } diff --git a/es-app/src/views/SystemView.h b/es-app/src/views/SystemView.h index e0387de94..2e2069fc8 100644 --- a/es-app/src/views/SystemView.h +++ b/es-app/src/views/SystemView.h @@ -1,10 +1,11 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // SystemView.h // // Main system view. // -#pragma once #ifndef ES_APP_VIEWS_SYSTEM_VIEW_H #define ES_APP_VIEWS_SYSTEM_VIEW_H diff --git a/es-app/src/views/ViewController.cpp b/es-app/src/views/ViewController.cpp index 7cab16e0e..5069d0f71 100644 --- a/es-app/src/views/ViewController.cpp +++ b/es-app/src/views/ViewController.cpp @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // ViewController.cpp // // Handles overall system navigation including animations and transitions. @@ -11,14 +13,13 @@ #include "animations/Animation.h" #include "animations/LambdaAnimation.h" -#include "animations/LaunchAnimation.h" #include "animations/MoveCameraAnimation.h" #include "guis/GuiInfoPopup.h" #include "guis/GuiMenu.h" #include "guis/GuiMsgBox.h" #include "views/gamelist/DetailedGameListView.h" -#include "views/gamelist/IGameListView.h" #include "views/gamelist/GridGameListView.h" +#include "views/gamelist/IGameListView.h" #include "views/gamelist/VideoGameListView.h" #include "views/SystemView.h" #include "views/UIModeController.h" @@ -111,28 +112,59 @@ void ViewController::ReloadAndGoToStart() ViewController::get()->goToStart(); } +bool ViewController::isCameraMoving() +{ + if (mCurrentView) { + if (mCamera.r3().x() != -mCurrentView->getPosition().x() || + mCamera.r3().y() != -mCurrentView->getPosition().y()) + return true; + } + return false; +} + +void ViewController::resetMovingCamera() +{ + if (isCameraMoving()) { + mCamera.r3().x() = -mCurrentView->getPosition().x(); + mCamera.r3().y() = -mCurrentView->getPosition().y(); + stopAllAnimations(); + } +} + +void ViewController::stopScrolling() +{ + mSystemListView->stopScrolling(); + mCurrentView->stopListScrolling(); + + if (mSystemListView->isAnimationPlaying(0)) + mSystemListView->finishAnimation(0); +} + int ViewController::getSystemId(SystemData* system) { std::vector& sysVec = SystemData::sSystemVector; - return (int)(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin()); + return static_cast(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin()); } void ViewController::goToSystemView(SystemData* system) { - // Tell any current view it's about to be hidden. - if (mCurrentView) + // Tell any current view it's about to be hidden and stop its rendering. + if (mCurrentView) { mCurrentView->onHide(); + mCurrentView->setRenderView(false); + } mState.viewing = SYSTEM_SELECT; mState.system = system; auto systemList = getSystemListView(); - systemList->setPosition(getSystemId(system) * (float)Renderer::getScreenWidth(), + systemList->setPosition(getSystemId(system) * static_cast(Renderer::getScreenWidth()), systemList->getPosition().y()); systemList->goToSystem(system, false); mCurrentView = systemList; mCurrentView->onShow(); + mCurrentView->setRenderView(true); PowerSaver::setState(true); playViewTransition(); @@ -158,13 +190,29 @@ void ViewController::goToPrevGameList() void ViewController::goToGameList(SystemData* system) { + // Stop any scrolling, animations and camera movements. + if (mSystemListView) { + mSystemListView->stopScrolling(); + if (mSystemListView->isAnimationPlaying(0)) + mSystemListView->finishAnimation(0); + } + resetMovingCamera(); + + // Disable rendering of the system view. + if (getSystemListView()->getRenderView()) + getSystemListView()->setRenderView(false); + + // If switching between gamelists, disable rendering of the current view. + if (mCurrentView) + mCurrentView->setRenderView(false); + if (mState.viewing == SYSTEM_SELECT) { // Move system list. auto sysList = getSystemListView(); float offX = sysList->getPosition().x(); int sysId = getSystemId(system); - sysList->setPosition(sysId * (float)Renderer::getScreenWidth(), + sysList->setPosition(sysId * static_cast(Renderer::getScreenWidth()), sysList->getPosition().y()); offX = sysList->getPosition().x() - offX; mCamera.translation().x() -= offX; @@ -178,8 +226,10 @@ void ViewController::goToGameList(SystemData* system) mCurrentView = getGameListView(system); - if (mCurrentView) + if (mCurrentView) { mCurrentView->onShow(); + mCurrentView->setRenderView(true); + } playViewTransition(); } @@ -218,10 +268,10 @@ void ViewController::playViewTransition() // Not changing screens, so cancel the first half entirely. advanceAnimation(0, FADE_DURATION); advanceAnimation(0, FADE_WAIT); - advanceAnimation(0, FADE_DURATION - (int)(mFadeOpacity * FADE_DURATION)); + advanceAnimation(0, FADE_DURATION - static_cast(mFadeOpacity * FADE_DURATION)); } else { - advanceAnimation(0, (int)(mFadeOpacity * FADE_DURATION)); + advanceAnimation(0, static_cast(mFadeOpacity * FADE_DURATION)); } } else if (transition_style == "slide") { @@ -247,90 +297,43 @@ void ViewController::onFileChanged(FileData* file, FileChangeType change) void ViewController::launch(FileData* game, Vector3f center) { if (game->getType() != GAME) { - LOG(LogError) << "tried to launch something that isn't a game"; + LOG(LogError) << "tried to launch something that isn't a game."; return; } - // Hide the current view. + // If the video view style is used, pause the video currently playing or block the + // video from starting to play if the static image is still shown. if (mCurrentView) - mCurrentView->onHide(); + mCurrentView->onPauseVideo(); - Transform4x4f origCamera = mCamera; - origCamera.translation() = -mCurrentView->getPosition(); - - center += mCurrentView->getPosition(); stopAnimation(1); // Make sure the fade in isn't still playing. mWindow->stopInfoPopup(); // Make sure we disable any existing info popup. mLockInput = true; - // TEMPORARY - Until a proper game launch screen is implemented, at least this - // will let the user know that something is actually happening (in addition - // to the launch sound, if navigation sounds are enabled). + // Until a proper game launch screen is implemented, at least this will let the + // user know that something is actually happening (in addition to the launch sound, + // if navigation sounds are enabled). GuiInfoPopup* s = new GuiInfoPopup(mWindow, "LAUNCHING GAME '" + Utils::String::toUpper(game->metadata.get("name") + "'"), 10000); mWindow->setInfoPopup(s); - std::string transition_style = Settings::getInstance()->getString("TransitionStyle"); - NavigationSounds::getInstance()->playThemeNavigationSound(LAUNCHSOUND); - // Let launch sound play to the end before launching game. - while (NavigationSounds::getInstance()->isPlayingThemeNavigationSound(LAUNCHSOUND)); - // TEMPORARY - disabled the launch animations as they don't work properly and more - // work is needed to fix them. This has been done in LaunchAnimation.h instead of here, - // as not calling the animation leads to input not being properly consumed. This also - // needs to be fixed later on. - setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 1500), 0, - [this, origCamera, center, game] { + // This is just a dummy animation in order for the launch notification popup to be + // displayed briefly, and for the navigation sound playing to be able to complete. + // During this time period, all user input is blocked. + setAnimation(new LambdaAnimation([](float t){}, 1700), 0, [this, game] { + while (NavigationSounds::getInstance()->isPlayingThemeNavigationSound(LAUNCHSOUND)); game->launchGame(mWindow); - mCamera = origCamera; - setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 600), 0, [this] { - mLockInput = false; }, true); - this->onFileChanged(game, FILE_METADATA_CHANGED); + onFileChanged(game, FILE_METADATA_CHANGED); if (mCurrentView) mCurrentView->onShow(); + // This is a workaround so that any key or button presses used for exiting the emulator + // are not captured upon returning to ES. + setAnimation(new LambdaAnimation([](float t){}, 1), 0, [this] { + mLockInput = false; + }); }); - - // if (transition_style == "fade") { - // // Fade out, launch game, fade back in. - // auto fadeFunc = [this](float t) { - // mFadeOpacity = Math::lerp(0.0f, 1.0f, t); - // }; - // setAnimation(new LambdaAnimation(fadeFunc, 800), 0, [this, game, fadeFunc] { - // game->launchGame(mWindow); - // setAnimation(new LambdaAnimation(fadeFunc, 800), 0, [this] { - // mLockInput = false; }, true); - // this->onFileChanged(game, FILE_METADATA_CHANGED); - // if (mCurrentView) - // mCurrentView->onShow(); - // }); - // } - // else if (transition_style == "slide") { - // // Move camera to zoom in on center + fade out, launch game, come back in. - // setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 1500), 0, - // [this, origCamera, center, game] { - // game->launchGame(mWindow); - // mCamera = origCamera; - // setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 600), 0, [this] { - // mLockInput = false; }, true); - // this->onFileChanged(game, FILE_METADATA_CHANGED); - // if (mCurrentView) - // mCurrentView->onShow(); - // }); - // } - // // Instant - // else { - // setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 10), 0, - // [this, origCamera, center, game] { - // game->launchGame(mWindow); - // mCamera = origCamera; - // setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 10), 0, - // [this] { mLockInput = false; }, true); - // this->onFileChanged(game, FILE_METADATA_CHANGED); - // if (mCurrentView) - // mCurrentView->onShow(); - // }); - // } } void ViewController::removeGameListView(SystemData* system) @@ -344,46 +347,46 @@ void ViewController::removeGameListView(SystemData* system) std::shared_ptr ViewController::getGameListView(SystemData* system) { - // If we already made one, return that one. + // If we have already created an entry for this system, then return that one. auto exists = mGameListViews.find(system); if (exists != mGameListViews.cend()) return exists->second; system->getIndex()->setUIModeFilters(); - // If we didn't, make it, remember it, and return it. + // If there's no entry, then create it and return it. std::shared_ptr view; bool themeHasVideoView = system->getTheme()->hasView("video"); - // Decide type. - GameListViewType selectedViewType = AUTOMATIC; + // Decide which view style to use. + GameListViewType selectedViewStyle = AUTOMATIC; std::string viewPreference = Settings::getInstance()->getString("GamelistViewStyle"); if (viewPreference.compare("basic") == 0) - selectedViewType = BASIC; + selectedViewStyle = BASIC; if (viewPreference.compare("detailed") == 0) - selectedViewType = DETAILED; + selectedViewStyle = DETAILED; if (viewPreference.compare("grid") == 0) - selectedViewType = GRID; + selectedViewStyle = GRID; if (viewPreference.compare("video") == 0) - selectedViewType = VIDEO; + selectedViewStyle = VIDEO; - if (selectedViewType == AUTOMATIC) { + if (selectedViewStyle == AUTOMATIC) { std::vector files = system->getRootFolder()->getFilesRecursive(GAME | FOLDER); for (auto it = files.cbegin(); it != files.cend(); it++) { if (themeHasVideoView && !(*it)->getVideoPath().empty()) { - selectedViewType = VIDEO; + selectedViewStyle = VIDEO; break; } else if (!(*it)->getImagePath().empty()) { - selectedViewType = DETAILED; + selectedViewStyle = DETAILED; // Don't break out in case any subsequent files have videos. } } } // Create the view. - switch (selectedViewType) + switch (selectedViewStyle) { case VIDEO: view = std::shared_ptr( @@ -407,9 +410,10 @@ std::shared_ptr ViewController::getGameListView(SystemData* syste view->setTheme(system->getTheme()); std::vector& sysVec = SystemData::sSystemVector; - int id = (int)(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin()); - view->setPosition(id * (float)Renderer::getScreenWidth(), - (float)Renderer::getScreenHeight() * 2); + int id = static_cast( + std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin()); + view->setPosition(id * static_cast(Renderer::getScreenWidth()), + static_cast(Renderer::getScreenHeight() * 2)); addChild(view.get()); @@ -419,13 +423,13 @@ std::shared_ptr ViewController::getGameListView(SystemData* syste std::shared_ptr ViewController::getSystemListView() { - // If we already made one, return that one. + // If we have already created a system view entry, then return it. if (mSystemListView) return mSystemListView; mSystemListView = std::shared_ptr(new SystemView(mWindow)); addChild(mSystemListView.get()); - mSystemListView->setPosition(0, (float)Renderer::getScreenHeight()); + mSystemListView->setPosition(0, static_cast(Renderer::getScreenHeight())); return mSystemListView; } @@ -447,7 +451,7 @@ bool ViewController::input(InputConfig* config, Input input) } #endif - // Open menu. + // Open the main menu. if (!(UIModeController::getInstance()->isUIModeKid() && !Settings::getInstance()->getBool("ShowKidStartMenu")) && config->isMappedTo("start", input) && input.value != 0) { @@ -461,8 +465,9 @@ bool ViewController::input(InputConfig* config, Input input) mSystemListView->finishAnimation(0); // Stop the gamelist scrolling as well as it would otherwise // also continue to run after closing the menu. - if (mCurrentView->isListScrolling()) - mCurrentView->stopListScrolling(); + mCurrentView->stopListScrolling(); + // Finally, if the camera is currently moving, reset its position. + resetMovingCamera(); mWindow->pushGui(new GuiMenu(mWindow)); return true; @@ -494,25 +499,32 @@ void ViewController::render(const Transform4x4f& parentTrans) // Camera position, position + size. Vector3f viewStart = transInverse.translation(); - Vector3f viewEnd = transInverse * Vector3f((float)Renderer::getScreenWidth(), - (float)Renderer::getScreenHeight(), 0); + Vector3f viewEnd = transInverse * Vector3f(static_cast(Renderer::getScreenWidth()), + static_cast(Renderer::getScreenHeight(), 0)); // Keep track of UI mode changes. UIModeController::getInstance()->monitorUIMode(); - // Draw system view. - getSystemListView()->render(trans); + // Draw the system view if it's flagged to be rendered. + // If the camera is moving, we're transitioning and in that case render it regardless + // of whether it's flagged for rendering or not. (Otherwise there will be a black portion + // shown on the screen during the animation). + if (getSystemListView()->getRenderView() || isCameraMoving()) + getSystemListView()->render(trans); - // Draw gamelists. + // Draw the gamelists. for (auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++) { - // Clipping. - Vector3f guiStart = it->second->getPosition(); - Vector3f guiEnd = it->second->getPosition() + Vector3f(it->second->getSize().x(), - it->second->getSize().y(), 0); + // Same thing as for the system view, limit the rendering only to what needs to be drawn. + if (it->second->getRenderView() || isCameraMoving()) { + // Clipping. + Vector3f guiStart = it->second->getPosition(); + Vector3f guiEnd = it->second->getPosition() + Vector3f(it->second->getSize().x(), + it->second->getSize().y(), 0); - if (guiEnd.x() >= viewStart.x() && guiEnd.y() >= viewStart.y() && - guiStart.x() <= viewEnd.x() && guiStart.y() <= viewEnd.y()) - it->second->render(trans); + if (guiEnd.x() >= viewStart.x() && guiEnd.y() >= viewStart.y() && + guiStart.x() <= viewEnd.x() && guiStart.y() <= viewEnd.y()) + it->second->render(trans); + } } if (mWindow->peekGui() == this) @@ -520,7 +532,7 @@ void ViewController::render(const Transform4x4f& parentTrans) // Fade out. if (mFadeOpacity) { - unsigned int fadeColor = 0x00000000 | (unsigned char)(mFadeOpacity * 255); + unsigned int fadeColor = 0x00000000 | static_cast(mFadeOpacity * 255); Renderer::setMatrix(parentTrans); Renderer::drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(), fadeColor, fadeColor); @@ -529,23 +541,21 @@ void ViewController::render(const Transform4x4f& parentTrans) void ViewController::preload() { - uint32_t i = 0; - for (auto it = SystemData::sSystemVector.cbegin(); - it != SystemData::sSystemVector.cend(); it++) { - if (Settings::getInstance()->getBool("SplashScreen") && - Settings::getInstance()->getBool("SplashScreenProgress")) { - i++; - char buffer[100]; - sprintf (buffer, "Loading '%s' (%d/%d)", - (*it)->getFullName().c_str(), i, (int)SystemData::sSystemVector.size()); - mWindow->renderLoadingScreen(std::string(buffer)); - } + unsigned int systemCount = SystemData::sSystemVector.size(); + for (auto it = SystemData::sSystemVector.cbegin(); + it != SystemData::sSystemVector.cend(); it ++) { + if (Settings::getInstance()->getBool("SplashScreen") && + Settings::getInstance()->getBool("SplashScreenProgress")) { + mWindow->renderLoadingScreen("Loading '" + (*it)->getFullName() + "' (" + + std::to_string(std::distance(SystemData::sSystemVector.cbegin(), it)+1) + + "/" + std::to_string(systemCount) + ")"); + } (*it)->getIndex()->resetFilters(); getGameListView(*it); } // Load navigation sounds, but only if at least one system exists. - if (SystemData::sSystemVector.size() > 0) + if (systemCount > 0) NavigationSounds::getInstance()->loadThemeNavigationSounds( SystemData::sSystemVector.front()->getTheme()); } @@ -587,8 +597,10 @@ void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme) #endif // Redisplay the current view. - if (mCurrentView) + if (mCurrentView) { mCurrentView->onShow(); + mCurrentView->setRenderView(true); + } } void ViewController::reloadAll() @@ -630,6 +642,8 @@ void ViewController::reloadAll() NavigationSounds::getInstance()->loadThemeNavigationSounds( SystemData::sSystemVector.front()->getTheme()); + mCurrentView->onShow(); + mCurrentView->setRenderView(true); updateHelpPrompts(); } diff --git a/es-app/src/views/ViewController.h b/es-app/src/views/ViewController.h index 1eda75ac2..cf5f99103 100644 --- a/es-app/src/views/ViewController.h +++ b/es-app/src/views/ViewController.h @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // ViewController.h // // Handles overall system navigation including animations and transitions. @@ -7,13 +9,13 @@ // Initiates the launching of games, calling FileData to do the actual launch. // -#pragma once #ifndef ES_APP_VIEWS_VIEW_CONTROLLER_H #define ES_APP_VIEWS_VIEW_CONTROLLER_H #include "renderers/Renderer.h" #include "FileData.h" #include "GuiComponent.h" + #include class IGameListView; @@ -51,10 +53,13 @@ public: void goToStart(); void ReloadAndGoToStart(); + // Functions to make the GUI behave properly. + bool isCameraMoving(); + void resetMovingCamera(); + void stopScrolling(); + void onFileChanged(FileData* file, FileChangeType change); - // Plays a nice launch effect and launches the game at the end of it. - // Once the game terminates, plays a return effect. void launch(FileData* game, Vector3f centerCameraOn = Vector3f(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f, 0)); diff --git a/es-app/src/views/gamelist/IGameListView.cpp b/es-app/src/views/gamelist/IGameListView.cpp index f29f9bc60..711705b39 100644 --- a/es-app/src/views/gamelist/IGameListView.cpp +++ b/es-app/src/views/gamelist/IGameListView.cpp @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // IGameListView.cpp // // Interface that defines the minimum for a GameListView. @@ -17,8 +19,8 @@ bool IGameListView::input(InputConfig* config, Input input) // Select button opens GuiGamelistOptions. if (!UIModeController::getInstance()->isUIModeKid() && config->isMappedTo("select", input) && input.value) { - if (isListScrolling()) - stopListScrolling(); + ViewController::get()->resetMovingCamera(); + stopListScrolling(); mWindow->pushGui(new GuiGamelistOptions(mWindow, this->mRoot->getSystem())); return true; } @@ -56,10 +58,10 @@ void IGameListView::render(const Transform4x4f& parentTrans) float scaleX = trans.r0().x(); float scaleY = trans.r1().y(); - Vector2i pos((int)Math::round(trans.translation()[0]), - (int)Math::round(trans.translation()[1])); - Vector2i size((int)Math::round(mSize.x() * scaleX), - (int)Math::round(mSize.y() * scaleY)); + Vector2i pos(static_cast(Math::round(trans.translation()[0])), + static_cast(Math::round(trans.translation()[1]))); + Vector2i size(static_cast(Math::round(mSize.x() * scaleX)), + static_cast(Math::round(mSize.y() * scaleY))); Renderer::pushClipRect(pos, size); renderChildren(trans); diff --git a/es-app/src/views/gamelist/IGameListView.h b/es-app/src/views/gamelist/IGameListView.h index c1698e598..99c6eda1b 100644 --- a/es-app/src/views/gamelist/IGameListView.h +++ b/es-app/src/views/gamelist/IGameListView.h @@ -1,10 +1,11 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // IGameListView.h // // Interface that defines the minimum for a GameListView. // -#pragma once #ifndef ES_APP_VIEWS_GAME_LIST_IGAME_LIST_VIEW_H #define ES_APP_VIEWS_GAME_LIST_IGAME_LIST_VIEW_H @@ -24,15 +25,15 @@ public: FileData* root) : GuiComponent(window), mRoot(root) - { setSize((float)Renderer::getScreenWidth(), - (float)Renderer::getScreenHeight()); } + { setSize(static_cast(Renderer::getScreenWidth()), + static_cast(Renderer::getScreenHeight())); } virtual ~IGameListView() {} // Called when a new file is added, a file is removed, a file's metadata changes, // or a file's children are sorted. - // NOTE: FILE_SORTED is only reported for the topmost FileData, where the sort started. - // Since sorts are recursive, that FileData's children probably changed too. + // Note: FILE_SORTED is only reported for the topmost FileData, where the sort started. + // Since sorts are recursive, FileData's children probably changed too. virtual void onFileChanged(FileData* file, FileChangeType change) = 0; // Called whenever the theme changes. diff --git a/es-app/src/views/gamelist/ISimpleGameListView.cpp b/es-app/src/views/gamelist/ISimpleGameListView.cpp index ce838b2f7..b08dd07ee 100644 --- a/es-app/src/views/gamelist/ISimpleGameListView.cpp +++ b/es-app/src/views/gamelist/ISimpleGameListView.cpp @@ -1,7 +1,9 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // ISimpleGameListView.cpp // -// Interface that defines a simple GameListView. +// Interface that defines a simple gamelist view. // #include "views/gamelist/ISimpleGameListView.h" @@ -101,13 +103,14 @@ bool ISimpleGameListView::input(InputConfig* config, Input input) if (config->isMappedTo("a", input)) { FileData* cursor = getCursor(); if (cursor->getType() == GAME) { - if (isListScrolling()) - stopListScrolling(); + ViewController::get()->resetMovingCamera(); + stopListScrolling(); launch(cursor); } else { // It's a folder. if (cursor->getChildren().size() > 0) { + ViewController::get()->resetMovingCamera(); NavigationSounds::getInstance()->playThemeNavigationSound(SELECTSOUND); mCursorStack.push(cursor); populateList(cursor->getChildrenListToDisplay()); @@ -119,6 +122,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input) return true; } else if (config->isMappedTo("b", input)) { + ViewController::get()->resetMovingCamera(); if (mCursorStack.size()) { NavigationSounds::getInstance()->playThemeNavigationSound(BACKSOUND); populateList(mCursorStack.top()->getParent()->getChildren()); @@ -128,8 +132,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input) else { NavigationSounds::getInstance()->playThemeNavigationSound(BACKSOUND); onFocusLost(); - if (isListScrolling()) - stopListScrolling(); + stopListScrolling(); SystemData* systemToView = getCursor()->getSystem(); if (systemToView->isCollection()) systemToView = CollectionSystemManager::get()->getSystemToView(systemToView); @@ -142,8 +145,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input) else if (config->isMappedLike(getQuickSystemSelectRightButton(), input)) { if (Settings::getInstance()->getBool("QuickSystemSelect")) { onFocusLost(); - if (isListScrolling()) - stopListScrolling(); + stopListScrolling(); ViewController::get()->goToNextGameList(); return true; } @@ -151,16 +153,14 @@ bool ISimpleGameListView::input(InputConfig* config, Input input) else if (config->isMappedLike(getQuickSystemSelectLeftButton(), input)) { if (Settings::getInstance()->getBool("QuickSystemSelect")) { onFocusLost(); - if (isListScrolling()) - stopListScrolling(); + stopListScrolling(); ViewController::get()->goToPrevGameList(); return true; } } else if (config->isMappedTo("x", input)) { if (mRoot->getSystem()->isGameSystem() && getCursor()->getType() != PLACEHOLDER) { - if (isListScrolling()) - stopListScrolling(); + stopListScrolling(); // Go to random system game. NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND); FileData* randomGame = getCursor()->getSystem()->getRandomGame(getCursor()); @@ -182,7 +182,6 @@ bool ISimpleGameListView::input(InputConfig* config, Input input) if (mRoot->getSystem()->isGameSystem()) { if (getCursor()->getType() == GAME || getCursor()->getType() == FOLDER) NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND); - // Marking folders as favorites is only cosmetic as they're not sorted // differently and they're not part of any collections. So it makes more // sense to do it here than to add the function to CollectionSystemManager. diff --git a/es-app/src/views/gamelist/ISimpleGameListView.h b/es-app/src/views/gamelist/ISimpleGameListView.h index d64a54090..14632a76a 100644 --- a/es-app/src/views/gamelist/ISimpleGameListView.h +++ b/es-app/src/views/gamelist/ISimpleGameListView.h @@ -1,16 +1,18 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // ISimpleGameListView.h // -// Interface that defines a simple GameListView. +// Interface that defines a simple gamelist view. // -#pragma once #ifndef ES_APP_VIEWS_GAME_LIST_ISIMPLE_GAME_LIST_VIEW_H #define ES_APP_VIEWS_GAME_LIST_ISIMPLE_GAME_LIST_VIEW_H #include "components/ImageComponent.h" #include "components/TextComponent.h" #include "views/gamelist/IGameListView.h" + #include class ISimpleGameListView : public IGameListView @@ -21,8 +23,8 @@ public: // Called when a new file is added, a file is removed, a file's metadata changes, // or a file's children are sorted. - // NOTE: FILE_SORTED is only reported for the topmost FileData, where the sort started. - // Since sorts are recursive, that FileData's children probably changed too. + // Note: FILE_SORTED is only reported for the topmost FileData, where the sort started. + // Since sorts are recursive, FileData's children probably changed too. virtual void onFileChanged(FileData* file, FileChangeType change) override; // Called whenever the theme changes. diff --git a/es-core/src/GuiComponent.cpp b/es-core/src/GuiComponent.cpp index 4507e4156..d0d8e39e8 100644 --- a/es-core/src/GuiComponent.cpp +++ b/es-core/src/GuiComponent.cpp @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // GuiComponent.cpp // // Basic GUI component handling such as placement, rotation, Z-order, rendering and animation. @@ -12,6 +14,7 @@ #include "Log.h" #include "ThemeData.h" #include "Window.h" + #include GuiComponent::GuiComponent(Window* window) @@ -26,7 +29,8 @@ GuiComponent::GuiComponent(Window* window) mTransform(Transform4x4f::Identity()), mIsProcessing(false), mVisible(true), - mEnabled(true) + mEnabled(true), + mRenderView(false) { for (unsigned char i = 0; i < MAX_ANIMATIONS; i++) mAnimationMap[i] = nullptr; @@ -230,7 +234,7 @@ void GuiComponent::sortChildren() unsigned int GuiComponent::getChildCount() const { - return (int)mChildren.size(); + return static_cast(mChildren.size()); } GuiComponent* GuiComponent::getChild(unsigned int i) const @@ -437,7 +441,8 @@ void GuiComponent::applyTheme(const std::shared_ptr& theme, const std::string& view, const std::string& element, unsigned int properties) { Vector2f scale = getParent() ? getParent()->getSize() - : Vector2f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); + : Vector2f(static_cast(Renderer::getScreenWidth()), + static_cast(Renderer::getScreenHeight())); const ThemeData::ThemeElement* elem = theme->getElement(view, element, ""); if (!elem) @@ -511,6 +516,12 @@ void GuiComponent::onHide() getChild(i)->onHide(); } +void GuiComponent::onPauseVideo() +{ + for (unsigned int i = 0; i < getChildCount(); i++) + getChild(i)->onPauseVideo(); +} + void GuiComponent::onScreenSaverActivate() { for (unsigned int i = 0; i < getChildCount(); i++) diff --git a/es-core/src/GuiComponent.h b/es-core/src/GuiComponent.h index 26c2e891e..3382f3125 100644 --- a/es-core/src/GuiComponent.h +++ b/es-core/src/GuiComponent.h @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // GuiComponent.h // // Basic GUI component handling such as placement, rotation, Z-order, rendering and animation. @@ -91,7 +93,8 @@ public: float getRotation() const; void setRotation(float rotation); - inline void setRotationDegrees(float rotation) { setRotation((float)ES_DEG_TO_RAD(rotation)); } + inline void setRotationDegrees(float rotation) { + setRotation(static_cast(ES_DEG_TO_RAD(rotation))); } float getScale() const; void setScale(float scale); @@ -163,6 +166,9 @@ public: virtual void onShow(); virtual void onHide(); + virtual void onPauseVideo(); + virtual void setRenderView(bool status) { mRenderView = status; } + virtual bool getRenderView() { return mRenderView; }; virtual void onScreenSaverActivate(); virtual void onScreenSaverDeactivate(); @@ -221,6 +227,7 @@ protected: bool mIsProcessing; bool mVisible; bool mEnabled; + bool mRenderView; private: // Don't access this directly! Use getTransform()! diff --git a/es-core/src/components/VideoComponent.cpp b/es-core/src/components/VideoComponent.cpp index 51888068a..97fc743b8 100644 --- a/es-core/src/components/VideoComponent.cpp +++ b/es-core/src/components/VideoComponent.cpp @@ -1,4 +1,6 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // VideoComponent.cpp // // Base class for playing videos. @@ -67,10 +69,11 @@ VideoComponent::VideoComponent( mIsPlaying(false), mPause(false), mShowing(false), - mScreensaverActive(false), - mGameLaunched(false), mDisable(false), + mScreensaverActive(false), mScreensaverMode(false), + mGameLaunched(false), + mBlockPlayer(false), mTargetIsMax(false), mTargetSize(0, 0) { @@ -236,6 +239,9 @@ std::vector VideoComponent::getHelpPrompts() void VideoComponent::handleStartDelay() { + if (mBlockPlayer) + return; + // Only play if any delay has timed out. if (mStartDelayed) { // If the setting to override the theme-supplied video delay setting has been enabled, @@ -284,6 +290,11 @@ void VideoComponent::startVideoWithDelay() void VideoComponent::update(int deltaTime) { + if (mBlockPlayer) { + setImage(mStaticImagePath); + return; + } + manageState(); // If the video start is delayed and there is less than the fade time, then set @@ -340,6 +351,8 @@ void VideoComponent::manageState() void VideoComponent::onShow() { + mBlockPlayer = false; + mPause = false; mShowing = true; manageState(); } @@ -350,6 +363,13 @@ void VideoComponent::onHide() manageState(); } +void VideoComponent::onPauseVideo() +{ + mBlockPlayer = true; + mPause = true; + manageState(); +} + void VideoComponent::onScreenSaverActivate() { mScreensaverActive = true; diff --git a/es-core/src/components/VideoComponent.h b/es-core/src/components/VideoComponent.h index 15d404c6d..57a1d0335 100644 --- a/es-core/src/components/VideoComponent.h +++ b/es-core/src/components/VideoComponent.h @@ -1,10 +1,11 @@ +// SPDX-License-Identifier: MIT // +// EmulationStation Desktop Edition // VideoComponent.h // // Base class for playing videos. // -#pragma once #ifndef ES_CORE_COMPONENTS_VIDEO_COMPONENT_H #define ES_CORE_COMPONENTS_VIDEO_COMPONENT_H @@ -46,6 +47,7 @@ public: virtual void onShow() override; virtual void onHide() override; + virtual void onPauseVideo() override; virtual void onScreenSaverActivate() override; virtual void onScreenSaverDeactivate() override; virtual void onGameLaunchedActivate() override; @@ -110,8 +112,8 @@ protected: std::string mVideoPath; std::string mPlayingVideoPath; - bool mStartDelayed; unsigned mStartTime; + bool mStartDelayed; bool mIsPlaying; bool mPause; bool mShowing; @@ -119,6 +121,7 @@ protected: bool mScreensaverActive; bool mScreensaverMode; bool mGameLaunched; + bool mBlockPlayer; bool mTargetIsMax; Configuration mConfig;