From 0a6e1f280fb2b6f65ccf0a57fa69e6da46ae77f0 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 15 Nov 2020 20:06:33 +0100 Subject: [PATCH] Improved transitions for SystemView. --- USERGUIDE.md | 4 - es-app/src/guis/GuiMenu.cpp | 15 ---- es-app/src/views/SystemView.cpp | 149 ++++++++++++++------------------ es-app/src/views/SystemView.h | 3 +- es-core/src/Settings.cpp | 1 - 5 files changed, 67 insertions(+), 105 deletions(-) diff --git a/USERGUIDE.md b/USERGUIDE.md index 6f3ab0b56..0e9a9d539 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -625,10 +625,6 @@ The order in which to sort your gamelists. This can be overriden per game system Animation to play when opening the main menu or the game options menu. Can be set to _scale-up_, _fade-in_ or _none_. -**Display carousel transitions** - -Whether to perform an animation when transitioning between systems in the system view. - **Render scanlines for gamelist videos** _(OpenGL renderer only)_ Whether to use a shader to render scanlines for videos in the gamelist view. The effect is usually pretty subtle as the video is normally renderered in a limited size in the GUI, and the scanlines are sized relative to the video window size. diff --git a/es-app/src/guis/GuiMenu.cpp b/es-app/src/guis/GuiMenu.cpp index 8753291f9..664973dd3 100644 --- a/es-app/src/guis/GuiMenu.cpp +++ b/es-app/src/guis/GuiMenu.cpp @@ -258,22 +258,7 @@ void GuiMenu::openUISettings() s->setNeedsSaving(); } }); - #endif - // Carousel transitions. - auto carousel_transitions = std::make_shared(mWindow); - carousel_transitions->setState(Settings::getInstance()->getBool("CarouselTransitions")); - s->addWithLabel("DISPLAY CAROUSEL TRANSITIONS", carousel_transitions); - s->addSaveFunc([carousel_transitions, s] { - if (carousel_transitions->getState() != - Settings::getInstance()->getBool("CarouselTransitions")) { - Settings::getInstance()->setBool("CarouselTransitions", - carousel_transitions->getState()); - s->setNeedsSaving(); - } - }); - - #if defined(USE_OPENGL_21) // Render scanlines for videos in the gamelists. auto gamelist_video_scanlines = std::make_shared(mWindow); gamelist_video_scanlines->setState(Settings::getInstance()->getBool("GamelistVideoScanlines")); diff --git a/es-app/src/views/SystemView.cpp b/es-app/src/views/SystemView.cpp index 6fa50b073..22df2da72 100644 --- a/es-app/src/views/SystemView.cpp +++ b/es-app/src/views/SystemView.cpp @@ -31,6 +31,7 @@ SystemView::SystemView( : IList (window, LIST_SCROLL_STYLE_SLOW, LIST_ALWAYS_LOOP), mPreviousScrollVelocity(0), + mUpdatedGameCount(false), mViewNeedsReload(true), mSystemInfo(window, "SYSTEM INFO", Font::get(FONT_SIZE_SMALL), 0x33333300, ALIGN_CENTER) { @@ -152,9 +153,31 @@ void SystemView::populate() } } +void SystemView::updateGameCount() +{ + std::pair gameCount = getSelected()->getDisplayedGameCount(); + std::stringstream ss; + + if (!getSelected()->isGameSystem()) + ss << "CONFIGURATION"; + else if (getSelected()->isCollection() && (getSelected()->getName() == "favorites")) + ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S"); + // The 'recent' gamelist has probably been trimmed after sorting, so we'll cap it at + // its maximum limit of 50 games. + else if (getSelected()->isCollection() && (getSelected()->getName() == "recent")) + ss << (gameCount.first > 50 ? 50 : gameCount.first) << " GAME" << + (gameCount.first == 1 ? " " : "S"); + else + ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S ") << "(" << + gameCount.second << " FAVORITE" << (gameCount.second == 1 ? ")" : "S)"); + + mSystemInfo.setText(ss.str()); +} + void SystemView::goToSystem(SystemData* system, bool animate) { setCursor(system); + updateGameCount(); if (!animate) finishAnimation(0); @@ -273,70 +296,31 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) mPreviousScrollVelocity = 1; } - // Animate mSystemInfo's opacity (fade out, wait, fade back in). - cancelAnimation(1); - cancelAnimation(2); - std::string transition_style = Settings::getInstance()->getString("TransitionStyle"); bool goFast = transition_style == "instant"; const float infoStartOpacity = mSystemInfo.getOpacity() / 255.f; - Animation* infoFadeOut = new LambdaAnimation( - [infoStartOpacity, this] (float t) { - mSystemInfo.setOpacity(static_cast( - Math::lerp(infoStartOpacity, 0.f, t) * 255)); - }, static_cast(infoStartOpacity * (goFast ? 10 : 150))); - // To prevent ugly jumps with two systems when quickly repeating the same direction. if (mPreviousScrollVelocity != 0 && posMax == 2 && mScrollVelocity == mPreviousScrollVelocity ) { if (fabs(endPos - startPos) < 0.5 || fabs(endPos - startPos) > 1.5) { (mScrollVelocity < 0) ? endPos -= 1 : endPos += 1; (mCursor == 0) ? mCursor = 1 : mCursor = 0; + updateGameCount(); return; } } - std::pair gameCount = getSelected()->getDisplayedGameCount(); - - // Also change the text after we've fully faded out. - setAnimation(infoFadeOut, 0, [this, gameCount] { - std::stringstream ss; - - if (!getSelected()->isGameSystem()) - ss << "CONFIGURATION"; - else if (getSelected()->isCollection() && (getSelected()->getName() == "favorites")) - ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S"); - // The 'recent' gamelist has probably been trimmed after sorting, so we'll cap it at - // its maximum limit of 50 games. - else if (getSelected()->isCollection() && (getSelected()->getName() == "recent")) - ss << (gameCount.first > 50 ? 50 : gameCount.first) << " GAME" << - (gameCount.first == 1 ? " " : "S"); - else - ss << gameCount.first << " GAME" << (gameCount.first == 1 ? " " : "S ") << "(" << - gameCount.second << " FAVORITE" << (gameCount.second == 1 ? ")" : "S)"); - - mSystemInfo.setText(ss.str()); - }, false, 1); - - Animation* infoFadeIn = new LambdaAnimation( - [this](float t) { - mSystemInfo.setOpacity(static_cast(Math::lerp(0.f, 1.f, t) * 255)); - }, goFast ? 10 : 300); - - // Wait 150ms to fade in. - setAnimation(infoFadeIn, goFast ? 0 : 500, nullptr, false, 2); - // No need to animate transition, we're not going anywhere (probably mEntries.size() == 1). if (endPos == mCamOffset && endPos == mExtrasCamOffset) return; Animation* anim; - bool carousel_transitions = Settings::getInstance()->getBool("CarouselTransitions"); + if (transition_style == "fade") { float startExtrasFade = mExtrasFadeOpacity; anim = new LambdaAnimation( - [this, startExtrasFade, startPos, endPos, posMax, carousel_transitions](float t) { + [this, startExtrasFade, startPos, endPos, posMax](float t) { t -= 1; float f = Math::lerp(startPos, endPos, t*t*t + 1); if (f < 0) @@ -344,7 +328,7 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) if (f >= posMax) f -= posMax; - this->mCamOffset = carousel_transitions ? f : endPos; + this->mCamOffset = f; t += 1; if (t < 0.3f) @@ -357,12 +341,15 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) if (t > 0.5f) this->mExtrasCamOffset = endPos; + // Update the game count when the entire animation has been completed. + if (mExtrasFadeOpacity == 1.0) + updateGameCount(); }, 500); } else if (transition_style == "slide") { - // Slide. + mUpdatedGameCount = false; anim = new LambdaAnimation( - [this, startPos, endPos, posMax, carousel_transitions](float t) { + [this, startPos, endPos, posMax](float t) { t -= 1; float f = Math::lerp(startPos, endPos, t*t*t + 1); if (f < 0) @@ -370,14 +357,30 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) if (f >= posMax) f -= posMax; - this->mCamOffset = carousel_transitions ? f : endPos; + this->mCamOffset = f; this->mExtrasCamOffset = f; + + // Hack to make the game count being updated in the middle of the animation. + bool update = false; + if (endPos == -1 && fabs(fabs(posMax) - fabs(mCamOffset)) > 0.5 && !mUpdatedGameCount) + update = true; + else if (endPos > posMax && fabs(endPos - posMax - fabs(mCamOffset)) < + 0.5 && !mUpdatedGameCount) + update = true; + else if (fabs(fabs(endPos) - fabs(mCamOffset)) < 0.5 && !mUpdatedGameCount) + update = true; + + if (update) { + mUpdatedGameCount = true; + updateGameCount(); + } }, 500); } else { // Instant. + updateGameCount(); anim = new LambdaAnimation( - [this, startPos, endPos, posMax, carousel_transitions ](float t) { + [this, startPos, endPos, posMax ](float t) { t -= 1; float f = Math::lerp(startPos, endPos, t*t*t + 1); if (f < 0) @@ -385,9 +388,9 @@ void SystemView::onCursorChanged(const CursorState& /*state*/) if (f >= posMax) f -= posMax; - this->mCamOffset = carousel_transitions ? f : endPos; + this->mCamOffset = f; this->mExtrasCamOffset = endPos; - }, carousel_transitions ? 500 : 1); + }, 500); } setAnimation(anim, 0, nullptr, false, 0); @@ -400,29 +403,16 @@ void SystemView::render(const Transform4x4f& parentTrans) Transform4x4f trans = getTransform() * parentTrans; - auto systemInfoZIndex = mSystemInfo.getZIndex(); - auto minMax = std::minmax(mCarousel.zIndex, systemInfoZIndex); + renderExtras(trans, INT16_MIN, INT16_MAX); - renderExtras(trans, INT16_MIN, minMax.first); - renderFade(trans); + // Fade the screen if we're using fade transitions and we're currently transitioning. + // This basically renders a black rectangle on top of the currently visible extras + // (and beneath the carousel and help prompts). + if (mExtrasFadeOpacity) + renderFade(trans); - if (mCarousel.zIndex > mSystemInfo.getZIndex()) { - renderInfoBar(trans); - } - else { - renderCarousel(trans); - } - - renderExtras(trans, minMax.first, minMax.second); - - if (mCarousel.zIndex > mSystemInfo.getZIndex()) { - renderCarousel(trans); - } - else { - renderInfoBar(trans); - } - - renderExtras(trans, minMax.second, INT16_MAX); + // Always render the carousel on top so that it's not faded. + renderCarousel(trans); } std::vector SystemView::getHelpPrompts() @@ -597,12 +587,6 @@ void SystemView::renderCarousel(const Transform4x4f& trans) Renderer::popClipRect(); } -void SystemView::renderInfoBar(const Transform4x4f& trans) -{ - Renderer::setMatrix(trans); - mSystemInfo.render(trans); -} - // Draw background extras. void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upper) { @@ -637,10 +621,10 @@ void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upp SystemViewData data = mEntries.at(index).data; for (unsigned int j = 0; j < data.backgroundExtras.size(); j++) { GuiComponent *extra = data.backgroundExtras[j]; - if (extra->getZIndex() >= lower && extra->getZIndex() < upper) { + if (extra->getZIndex() >= lower && extra->getZIndex() < upper) extra->render(extrasTrans); - } } + mSystemInfo.render(extrasTrans); Renderer::popClipRect(); } } @@ -649,12 +633,9 @@ void SystemView::renderExtras(const Transform4x4f& trans, float lower, float upp void SystemView::renderFade(const Transform4x4f& trans) { - // Fade extras if necessary. - if (mExtrasFadeOpacity) { - unsigned int fadeColor = 0x00000000 | static_cast(mExtrasFadeOpacity * 255); - Renderer::setMatrix(trans); - Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), fadeColor, fadeColor); - } + unsigned int fadeColor = 0x00000000 | static_cast(mExtrasFadeOpacity * 255); + Renderer::setMatrix(trans); + Renderer::drawRect(0.0f, 0.0f, mSize.x(), mSize.y(), fadeColor, fadeColor); } // Populate the system carousel with the legacy values. diff --git a/es-app/src/views/SystemView.h b/es-app/src/views/SystemView.h index 42c4708ca..d1006eeb5 100644 --- a/es-app/src/views/SystemView.h +++ b/es-app/src/views/SystemView.h @@ -76,13 +76,13 @@ protected: private: void populate(); + void updateGameCount(); void getViewElements(const std::shared_ptr& theme); void getDefaultElements(void); void getCarouselFromTheme(const ThemeData::ThemeElement* elem); void renderCarousel(const Transform4x4f& parentTrans); void renderExtras(const Transform4x4f& parentTrans, float lower, float upper); - void renderInfoBar(const Transform4x4f& trans); void renderFade(const Transform4x4f& trans); SystemViewCarousel mCarousel; @@ -94,6 +94,7 @@ private: float mExtrasFadeOpacity; int mPreviousScrollVelocity; + bool mUpdatedGameCount; bool mViewNeedsReload; bool mShowing; }; diff --git a/es-core/src/Settings.cpp b/es-core/src/Settings.cpp index 3522c8594..9fad5af29 100644 --- a/es-core/src/Settings.cpp +++ b/es-core/src/Settings.cpp @@ -110,7 +110,6 @@ void Settings::setDefaults() mStringMap["UIMode"] = "full"; mStringMap["DefaultSortOrder"] = "filename, ascending"; mStringMap["MenuOpeningEffect"] = "scale-up"; - mBoolMap["CarouselTransitions"] = true; mBoolMap["GamelistVideoScanlines"] = true; mBoolMap["FoldersOnTop"] = true; mBoolMap["FavoritesFirst"] = true;