mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-29 19:55:37 +00:00
Added a startup progress bar to the splash screen.
This commit is contained in:
parent
d15927c156
commit
e44c18bc1b
|
@ -508,6 +508,15 @@ bool SystemData::loadConfig()
|
|||
return true;
|
||||
}
|
||||
|
||||
const bool splashScreen {Settings::getInstance()->getBool("SplashScreen")};
|
||||
float systemCount {0.0f};
|
||||
float loadedSystems {0.0f};
|
||||
|
||||
for (pugi::xml_node system {systemList.child("system")}; system;
|
||||
system = system.next_sibling("system")) {
|
||||
++systemCount;
|
||||
}
|
||||
|
||||
for (pugi::xml_node system {systemList.child("system")}; system;
|
||||
system = system.next_sibling("system")) {
|
||||
std::string name;
|
||||
|
@ -521,6 +530,13 @@ bool SystemData::loadConfig()
|
|||
sortName = system.child("systemsortname").text().get();
|
||||
path = system.child("path").text().get();
|
||||
|
||||
if (splashScreen) {
|
||||
++loadedSystems;
|
||||
const float progress {glm::mix(0.0f, 0.5f, loadedSystems / systemCount)};
|
||||
Window::getInstance()->renderSplashScreen(Window::SplashScreenState::SCANNING,
|
||||
progress);
|
||||
}
|
||||
|
||||
auto nameFindFunc = [&] {
|
||||
for (auto system : sSystemVector) {
|
||||
if (system->mName == name) {
|
||||
|
@ -581,7 +597,7 @@ bool SystemData::loadConfig()
|
|||
}
|
||||
|
||||
// Convert extensions list from a string into a vector of strings.
|
||||
std::vector<std::string> extensions = readList(system.child("extension").text().get());
|
||||
std::vector<std::string> extensions {readList(system.child("extension").text().get())};
|
||||
|
||||
// Load all launch command tags for the system and if there are multiple tags, then
|
||||
// the label attribute needs to be set on all entries as it's a requirement for the
|
||||
|
|
|
@ -531,16 +531,15 @@ int main(int argc, char* argv[])
|
|||
// This is a workaround to disable the incredibly annoying save state functionality in
|
||||
// macOS which forces a restore of the previous window state. The problem is that this
|
||||
// removes the splash screen on startup and it may have other adverse effects as well.
|
||||
std::string saveStateDir = Utils::FileSystem::expandHomePath(
|
||||
"~/Library/Saved Application State/org.es-de.EmulationStation.savedState");
|
||||
std::string saveStateDir {Utils::FileSystem::expandHomePath(
|
||||
"~/Library/Saved Application State/org.es-de.EmulationStation.savedState")};
|
||||
// Deletion of the state files should normally not be required as there shouldn't be any
|
||||
// files to begin with. But maybe the files can still be created for unknown reasons
|
||||
// as macOS really really loves to restore windows. Let's therefore include this deletion
|
||||
// step as an extra precaution.
|
||||
if (Utils::FileSystem::exists(saveStateDir)) {
|
||||
for (std::string stateFile : Utils::FileSystem::getDirContent(saveStateDir)) {
|
||||
for (std::string stateFile : Utils::FileSystem::getDirContent(saveStateDir))
|
||||
Utils::FileSystem::removeFile(stateFile);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Utils::FileSystem::createDirectory(saveStateDir);
|
||||
|
@ -683,8 +682,6 @@ int main(int argc, char* argv[])
|
|||
|
||||
window->pushGui(ViewController::getInstance());
|
||||
|
||||
bool splashScreen {Settings::getInstance()->getBool("SplashScreen")};
|
||||
|
||||
InputManager::getInstance().parseEvent(event);
|
||||
if (event.type == SDL_QUIT)
|
||||
return 1;
|
||||
|
@ -707,15 +704,18 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
#endif
|
||||
|
||||
if (splashScreen) {
|
||||
std::string progressText {"Loading system config..."};
|
||||
window->renderLoadingScreen(progressText);
|
||||
}
|
||||
|
||||
AudioManager::getInstance();
|
||||
MameNames::getInstance();
|
||||
ThemeData::populateThemeSets();
|
||||
// We need to temporarily disable VSync as the splash screen may otherwise slow down
|
||||
// application startup significantly due to excessive swapBuffers() calls.
|
||||
const bool splashScreen {Settings::getInstance()->getBool("SplashScreen")};
|
||||
const bool vSync {Settings::getInstance()->getBool("VSync")};
|
||||
if (splashScreen && vSync)
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
loadSystemsReturnCode loadSystemsStatus {loadSystemConfigFile()};
|
||||
if (splashScreen && vSync)
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
if (loadSystemsStatus) {
|
||||
// If there was an issue parsing the es_systems.xml file, display an error message.
|
||||
|
@ -752,9 +752,6 @@ int main(int argc, char* argv[])
|
|||
<< "\"";
|
||||
}
|
||||
|
||||
if (splashScreen)
|
||||
window->renderLoadingScreen("Done");
|
||||
|
||||
// Open the input configuration GUI if the flag to force this was passed from the command line.
|
||||
if (!loadSystemsStatus) {
|
||||
if (forceInputConfig) {
|
||||
|
|
|
@ -241,7 +241,7 @@ void ViewController::goToStart(bool playTransition)
|
|||
|
||||
void ViewController::ReloadAndGoToStart()
|
||||
{
|
||||
mWindow->renderLoadingScreen("Loading...");
|
||||
mWindow->renderSplashScreen(Window::SplashScreenState::RELOADING, 0.0f);
|
||||
reloadAll();
|
||||
if (mState.viewing == GAMELIST) {
|
||||
goToSystemView(SystemData::sSystemVector.front(), false);
|
||||
|
@ -1108,13 +1108,15 @@ void ViewController::preload()
|
|||
if (!SystemData::sSystemVector.empty())
|
||||
getSystemListView();
|
||||
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend();
|
||||
++it) {
|
||||
float loadedSystems {0.0f};
|
||||
|
||||
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
||||
it != SystemData::sSystemVector.cend(); ++it) {
|
||||
if (Settings::getInstance()->getBool("SplashScreen")) {
|
||||
mWindow->renderLoadingScreen(
|
||||
"Loading '" + (*it)->getFullName() + "' (" +
|
||||
std::to_string(std::distance(SystemData::sSystemVector.cbegin(), it) + 1) + "/" +
|
||||
std::to_string(systemCount) + ")");
|
||||
++loadedSystems;
|
||||
const float progress {
|
||||
glm::mix(0.5f, 1.0f, loadedSystems / static_cast<float>(systemCount))};
|
||||
mWindow->renderSplashScreen(Window::SplashScreenState::POPULATING, progress);
|
||||
}
|
||||
(*it)->getIndex()->resetFilters();
|
||||
getGamelistView(*it)->preloadGamelist();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// EmulationStation Desktop Edition
|
||||
// Window.cpp
|
||||
//
|
||||
// Window management, screensaver management, and help prompts.
|
||||
// Window management, screensaver management, help prompts and splash screen.
|
||||
// The input stack starts here as well, as this is the first instance called by InputManager.
|
||||
//
|
||||
|
||||
|
@ -25,6 +25,8 @@
|
|||
|
||||
Window::Window() noexcept
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mSplashTextPositions {0.0f, 0.0f, 0.0f, 0.0f}
|
||||
, mBackgroundOverlayOpacity {1.0f}
|
||||
, mScreensaver {nullptr}
|
||||
, mMediaViewer {nullptr}
|
||||
, mLaunchScreen {nullptr}
|
||||
|
@ -47,23 +49,19 @@ Window::Window() noexcept
|
|||
, mInvalidateCacheTimer {0}
|
||||
, mVideoPlayerCount {0}
|
||||
, mTopScale {0.5f}
|
||||
, mRenderedHelpPrompts {false}
|
||||
, mChangedThemeSet {false}
|
||||
{
|
||||
}
|
||||
|
||||
Window::~Window()
|
||||
{
|
||||
delete mBackgroundOverlay;
|
||||
delete mSplash;
|
||||
|
||||
// Delete all our GUIs.
|
||||
while (peekGui())
|
||||
delete peekGui();
|
||||
|
||||
if (mInfoPopup)
|
||||
delete mInfoPopup;
|
||||
|
||||
delete mHelp;
|
||||
}
|
||||
|
||||
Window* Window::getInstance()
|
||||
|
@ -112,10 +110,10 @@ bool Window::init()
|
|||
|
||||
ResourceManager::getInstance().reloadAll();
|
||||
|
||||
mHelp = new HelpComponent;
|
||||
mSplash = new ImageComponent;
|
||||
mHelp = std::make_unique<HelpComponent>();
|
||||
mSplash = std::make_unique<ImageComponent>(false, false);
|
||||
|
||||
mBackgroundOverlay = new ImageComponent;
|
||||
mBackgroundOverlay = std::make_unique<ImageComponent>(false, false);
|
||||
mBackgroundOverlayOpacity = 0.0f;
|
||||
|
||||
// Keep a reference to the default fonts, so they don't keep getting destroyed/recreated.
|
||||
|
@ -135,6 +133,49 @@ bool Window::init()
|
|||
mSplash->setPosition((mRenderer->getScreenWidth() - mSplash->getSize().x) / 2.0f,
|
||||
(mRenderer->getScreenHeight() - mSplash->getSize().y) / 2.0f * 0.6f);
|
||||
|
||||
mSplashTextScanning = std::unique_ptr<TextCache>(mDefaultFonts.at(1)->buildTextCache(
|
||||
"Scanning game files...", 0.0f, 0.0f, DEFAULT_TEXTCOLOR));
|
||||
mSplashTextPopulating = std::unique_ptr<TextCache>(mDefaultFonts.at(1)->buildTextCache(
|
||||
"Populating systems...", 0.0f, 0.0f, DEFAULT_TEXTCOLOR));
|
||||
mSplashTextReloading = std::unique_ptr<TextCache>(
|
||||
mDefaultFonts.at(1)->buildTextCache("Reloading...", 0.0f, 0.0f, DEFAULT_TEXTCOLOR));
|
||||
|
||||
mSplashTextPositions.x =
|
||||
(mRenderer->getScreenWidth() - mSplashTextScanning->metrics.size.x) / 2.0f;
|
||||
mSplashTextPositions.z =
|
||||
(mRenderer->getScreenWidth() - mSplashTextPopulating->metrics.size.x) / 2.0f;
|
||||
mSplashTextPositions.w =
|
||||
(mRenderer->getScreenWidth() - mSplashTextReloading->metrics.size.x) / 2.0f;
|
||||
mSplashTextPositions.y = mRenderer->getScreenHeight() * 0.745f;
|
||||
|
||||
ProgressBarRectangle progressBarRect;
|
||||
if (mRenderer->getScreenWidth() > mRenderer->getScreenHeight())
|
||||
progressBarRect.barWidth = mRenderer->getScreenHeight() * 0.53f;
|
||||
else
|
||||
progressBarRect.barWidth = mRenderer->getScreenWidth() * 0.53f;
|
||||
progressBarRect.barHeight = mDefaultFonts.at(1)->getLetterHeight() * 1.3f;
|
||||
progressBarRect.barPosX =
|
||||
(mRenderer->getScreenWidth() / 2.0f) - (progressBarRect.barWidth / 2.0f);
|
||||
progressBarRect.barPosY = mSplashTextPositions.y + (progressBarRect.barHeight * 1.65f);
|
||||
progressBarRect.color = DEFAULT_TEXTCOLOR;
|
||||
mProgressBarRectangles.emplace_back(progressBarRect);
|
||||
|
||||
const float borderThickness {std::ceil(2.0f * mRenderer->getScreenHeightModifier())};
|
||||
|
||||
progressBarRect.barWidth -= borderThickness * 2.0f;
|
||||
progressBarRect.barHeight -= borderThickness * 2.0f;
|
||||
progressBarRect.barPosX += borderThickness;
|
||||
progressBarRect.barPosY += borderThickness;
|
||||
progressBarRect.color = 0x000000FF;
|
||||
mProgressBarRectangles.emplace_back(progressBarRect);
|
||||
|
||||
progressBarRect.barWidth -= borderThickness * 2.0f;
|
||||
progressBarRect.barHeight -= borderThickness * 2.0f;
|
||||
progressBarRect.barPosX += borderThickness;
|
||||
progressBarRect.barPosY += borderThickness;
|
||||
progressBarRect.color = 0xA1001DFF;
|
||||
mProgressBarRectangles.emplace_back(progressBarRect);
|
||||
|
||||
mBackgroundOverlay->setImage(":/graphics/frame.png");
|
||||
mBackgroundOverlay->setResize(mRenderer->getScreenWidth(), mRenderer->getScreenHeight());
|
||||
|
||||
|
@ -605,23 +646,50 @@ void Window::render()
|
|||
}
|
||||
}
|
||||
|
||||
void Window::renderLoadingScreen(std::string text)
|
||||
void Window::renderSplashScreen(SplashScreenState state, float progress)
|
||||
{
|
||||
glm::mat4 trans {mRenderer->getIdentity()};
|
||||
mRenderer->setMatrix(trans);
|
||||
mRenderer->drawRect(0.0f, 0.0f, mRenderer->getScreenWidth(), mRenderer->getScreenHeight(),
|
||||
0x000000FF, 0x000000FF);
|
||||
mSplash->render(trans);
|
||||
|
||||
auto& font = mDefaultFonts.at(1);
|
||||
TextCache* cache {font->buildTextCache(text, 0.0f, 0.0f, 0x656565FF)};
|
||||
|
||||
float x {std::round((mRenderer->getScreenWidth() - cache->metrics.size.x) / 2.0f)};
|
||||
float y {std::round(mRenderer->getScreenHeight() * 0.835f)};
|
||||
trans = glm::translate(trans, glm::round(glm::vec3 {x, y, 0.0f}));
|
||||
mRenderer->setMatrix(trans);
|
||||
font->renderTextCache(cache);
|
||||
delete cache;
|
||||
|
||||
if (state != SplashScreenState::RELOADING) {
|
||||
// We need to render three rectangles: border, black center and actual progress bar.
|
||||
for (size_t i {0}; i < mProgressBarRectangles.size(); ++i) {
|
||||
const float rectWidth {i == mProgressBarRectangles.size() - 1 ? progress : 1.0f};
|
||||
mRenderer->drawRect(
|
||||
mProgressBarRectangles.at(i).barPosX, mProgressBarRectangles.at(i).barPosY,
|
||||
mProgressBarRectangles.at(i).barWidth * rectWidth,
|
||||
mProgressBarRectangles.at(i).barHeight, mProgressBarRectangles.at(i).color,
|
||||
mProgressBarRectangles.at(i).color);
|
||||
}
|
||||
}
|
||||
|
||||
float textPosX {0.0f};
|
||||
float textPosY {mSplashTextPositions.y};
|
||||
|
||||
if (state == SplashScreenState::SCANNING) {
|
||||
textPosX = mSplashTextPositions.x;
|
||||
}
|
||||
else if (state == SplashScreenState::POPULATING) {
|
||||
textPosX = mSplashTextPositions.z;
|
||||
}
|
||||
else if (state == SplashScreenState::RELOADING) {
|
||||
textPosX = mSplashTextPositions.w;
|
||||
textPosY += mDefaultFonts.at(1)->getLetterHeight();
|
||||
}
|
||||
|
||||
trans = glm::translate(trans, glm::round(glm::vec3 {textPosX, textPosY, 0.0f}));
|
||||
mRenderer->setMatrix(trans);
|
||||
|
||||
if (state == SplashScreenState::SCANNING)
|
||||
mDefaultFonts.at(1)->renderTextCache(mSplashTextScanning.get());
|
||||
else if (state == SplashScreenState::POPULATING)
|
||||
mDefaultFonts.at(1)->renderTextCache(mSplashTextPopulating.get());
|
||||
else if (state == SplashScreenState::RELOADING)
|
||||
mDefaultFonts.at(1)->renderTextCache(mSplashTextReloading.get());
|
||||
|
||||
mRenderer->swapBuffers();
|
||||
}
|
||||
|
@ -707,14 +775,6 @@ void Window::setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpSt
|
|||
mHelp->setPrompts(addPrompts);
|
||||
}
|
||||
|
||||
void Window::reloadHelpPrompts()
|
||||
{
|
||||
if (mHelp) {
|
||||
delete mHelp;
|
||||
mHelp = new HelpComponent;
|
||||
}
|
||||
}
|
||||
|
||||
void Window::stopInfoPopup()
|
||||
{
|
||||
if (mInfoPopup)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// EmulationStation Desktop Edition
|
||||
// Window.h
|
||||
//
|
||||
// Window management, screensaver management, and help prompts.
|
||||
// Window management, screensaver management, help prompts and splash screen.
|
||||
// The input stack starts here as well, as this is the first instance called by InputManager.
|
||||
//
|
||||
|
||||
|
@ -92,13 +92,18 @@ public:
|
|||
|
||||
void normalizeNextUpdate() { mNormalizeNextUpdate = true; }
|
||||
|
||||
void renderLoadingScreen(std::string text);
|
||||
enum class SplashScreenState {
|
||||
SCANNING,
|
||||
POPULATING,
|
||||
RELOADING
|
||||
};
|
||||
|
||||
void renderSplashScreen(SplashScreenState state, float progress);
|
||||
// The list scroll overlay is triggered from IList when the highest scrolling tier is reached.
|
||||
void renderListScrollOverlay(const float opacity, const std::string& text);
|
||||
|
||||
void renderHelpPromptsEarly(); // Used to render HelpPrompts before a fade.
|
||||
void setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpStyle& style);
|
||||
void reloadHelpPrompts();
|
||||
|
||||
// GuiInfoPopup notifications.
|
||||
void queueInfoPopup(const std::string& message, const int& duration)
|
||||
|
@ -150,10 +155,24 @@ private:
|
|||
// Returns true if at least one component on the stack is processing.
|
||||
bool isProcessing();
|
||||
|
||||
struct ProgressBarRectangle {
|
||||
float barWidth;
|
||||
float barHeight;
|
||||
float barPosX;
|
||||
float barPosY;
|
||||
unsigned int color;
|
||||
};
|
||||
|
||||
Renderer* mRenderer;
|
||||
HelpComponent* mHelp;
|
||||
ImageComponent* mBackgroundOverlay;
|
||||
ImageComponent* mSplash;
|
||||
std::unique_ptr<HelpComponent> mHelp;
|
||||
std::unique_ptr<ImageComponent> mBackgroundOverlay;
|
||||
std::unique_ptr<ImageComponent> mSplash;
|
||||
std::unique_ptr<TextCache> mSplashTextScanning;
|
||||
std::unique_ptr<TextCache> mSplashTextPopulating;
|
||||
std::unique_ptr<TextCache> mSplashTextReloading;
|
||||
glm::vec4 mSplashTextPositions;
|
||||
std::vector<ProgressBarRectangle> mProgressBarRectangles;
|
||||
|
||||
float mBackgroundOverlayOpacity;
|
||||
std::vector<GuiComponent*> mGuiStack;
|
||||
std::vector<std::shared_ptr<Font>> mDefaultFonts;
|
||||
|
|
|
@ -340,6 +340,7 @@ void RendererOpenGL::setSwapInterval()
|
|||
LOG(LogInfo) << "Enabling VSync...";
|
||||
}
|
||||
else {
|
||||
Settings::getInstance()->setBool("VSync", false);
|
||||
LOG(LogWarning) << "Could not enable VSync: " << SDL_GetError();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue