diff --git a/src/GuiComponent.cpp b/src/GuiComponent.cpp index 75f6d7e08..8ef8aa381 100644 --- a/src/GuiComponent.cpp +++ b/src/GuiComponent.cpp @@ -40,16 +40,7 @@ void GuiComponent::update(int deltaTime) { for(unsigned char i = 0; i < MAX_ANIMATIONS; i++) { - AnimationController* anim = mAnimationMap[i]; - if(anim) - { - bool done = anim->update(deltaTime); - if(done) - { - mAnimationMap[i] = NULL; - delete anim; - } - } + advanceAnimation(i, deltaTime); } for(unsigned int i = 0; i < getChildCount(); i++) @@ -257,6 +248,24 @@ bool GuiComponent::finishAnimation(unsigned char slot) } } +bool GuiComponent::advanceAnimation(unsigned char slot, unsigned int time) +{ + assert(slot < MAX_ANIMATIONS); + AnimationController* anim = mAnimationMap[slot]; + if(anim) + { + bool done = anim->update(time); + if(done) + { + mAnimationMap[slot] = NULL; + delete anim; + } + return true; + }else{ + return false; + } +} + void GuiComponent::stopAllAnimations() { for(unsigned char i = 0; i < MAX_ANIMATIONS; i++) diff --git a/src/GuiComponent.h b/src/GuiComponent.h index 39b01c282..4ccfc6d03 100644 --- a/src/GuiComponent.h +++ b/src/GuiComponent.h @@ -60,8 +60,9 @@ public: int getAnimationTime(unsigned char slot) const; void setAnimation(Animation* animation, int delay = 0, std::function finishedCallback = nullptr, bool reverse = false, unsigned char slot = 0); bool stopAnimation(unsigned char slot); - bool cancelAnimation(unsigned char slot); // like stopAnimation, but doesn't call finishedCallback - only removes the animation, leaving things in their current state - bool finishAnimation(unsigned char slot); // calls update(1.f) and finishedCallback, then deletes the animation - basically skips to the end + bool cancelAnimation(unsigned char slot); // Like stopAnimation, but doesn't call finishedCallback - only removes the animation, leaving things in their current state. Returns true if successful (an animation was in this slot). + bool finishAnimation(unsigned char slot); // Calls update(1.f) and finishedCallback, then deletes the animation - basically skips to the end. Returns true if successful (an animation was in this slot). + bool advanceAnimation(unsigned char slot, unsigned int time); // Returns true if successful (an animation was in this slot). void stopAllAnimations(); void cancelAllAnimations(); diff --git a/src/Window.cpp b/src/Window.cpp index 7a7b3be59..13f82568d 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -175,6 +175,8 @@ void Window::render() { Eigen::Affine3f transform = Eigen::Affine3f::Identity(); + mRenderedHelpPrompts = false; + // draw only bottom and top of GuiStack (if they are different) if(mGuiStack.size()) { @@ -199,7 +201,8 @@ void Window::render() mBackgroundOverlay->render(transform); }*/ - mHelp->render(transform); + if(!mRenderedHelpPrompts) + mHelp->render(transform); if(Settings::getInstance()->getBool("DrawFramerate") && mFrameDataText) { @@ -239,6 +242,12 @@ void Window::renderLoadingScreen() Renderer::swapBuffers(); } +void Window::renderHelpPromptsEarly() +{ + mHelp->render(Eigen::Affine3f::Identity()); + mRenderedHelpPrompts = true; +} + void Window::setHelpPrompts(const std::vector& prompts) { mHelp->clearPrompts(); diff --git a/src/Window.h b/src/Window.h index 5c87e9e75..752ee66fd 100644 --- a/src/Window.h +++ b/src/Window.h @@ -37,6 +37,7 @@ public: void renderLoadingScreen(); + void renderHelpPromptsEarly(); // used by ViewController to render HelpPrompts before a fade void setHelpPrompts(const std::vector& prompts); private: @@ -57,6 +58,7 @@ private: bool mNormalizeNextUpdate; bool mAllowSleep; + bool mRenderedHelpPrompts; }; #endif diff --git a/src/components/HelpComponent.cpp b/src/components/HelpComponent.cpp index 255f32f85..984652887 100644 --- a/src/components/HelpComponent.cpp +++ b/src/components/HelpComponent.cpp @@ -115,6 +115,16 @@ std::shared_ptr HelpComponent::getIconTexture(const char* name) return tex; } +void HelpComponent::setOpacity(unsigned char opacity) +{ + GuiComponent::setOpacity(opacity); + + for(unsigned int i = 0; i < mGrid->getChildCount(); i++) + { + mGrid->getChild(i)->setOpacity(opacity); + } +} + void HelpComponent::render(const Eigen::Affine3f& parentTrans) { Eigen::Affine3f trans = parentTrans * getTransform(); diff --git a/src/components/HelpComponent.h b/src/components/HelpComponent.h index 9cc76082f..7a3a6ef06 100644 --- a/src/components/HelpComponent.h +++ b/src/components/HelpComponent.h @@ -15,6 +15,7 @@ public: void setPrompts(const std::vector& prompts); void render(const Eigen::Affine3f& parent) override; + void setOpacity(unsigned char opacity) override; private: std::shared_ptr getIconTexture(const char* name); diff --git a/src/views/ViewController.cpp b/src/views/ViewController.cpp index ab456f714..6eb81900e 100644 --- a/src/views/ViewController.cpp +++ b/src/views/ViewController.cpp @@ -44,7 +44,6 @@ void ViewController::goToSystemView(SystemData* system) systemList->goToSystem(system, false); mCurrentView = systemList; - updateHelpPrompts(); playViewTransition(); } @@ -81,7 +80,6 @@ void ViewController::goToGameList(SystemData* system) mState.system = system; mCurrentView = getGameListView(system); - updateHelpPrompts(); playViewTransition(); } @@ -93,23 +91,36 @@ void ViewController::playViewTransition() if(Settings::getInstance()->getString("TransitionStyle") == "fade") { - // fade animation - auto fadeAnim = [this, target](float t) { - float fadeStart = lerp(0, 1, t / 0.3f); - float fadeEnd = lerp(1, 0, (t - 0.7f) / 0.3f); + // fade + // stop whatever's currently playing, leaving mFadeOpacity wherever it is + cancelAnimation(0); - if(t <= 0.3f) - { - mFadeOpacity = fadeStart; - }else{ - this->mCamera.translation() = -target; - mFadeOpacity = fadeEnd; - } + auto fadeFunc = [this](float t) { + mFadeOpacity = lerp(0, 1, t); }; - setAnimation(new LambdaAnimation(fadeAnim, 800)); + + const static int FADE_DURATION = 240; // fade in/out time + const static int FADE_WAIT = 320; // time to wait between in/out + setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), 0, [this, fadeFunc, target] { + this->mCamera.translation() = -target; + updateHelpPrompts(); + setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), FADE_WAIT, nullptr, true); + }); + + // fast-forward animation if we're partway faded + if(target == -mCamera.translation()) + { + // 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)); + }else{ + advanceAnimation(0, (int)(mFadeOpacity * FADE_DURATION)); + } }else{ // slide setAnimation(new MoveCameraAnimation(mCamera, target)); + updateHelpPrompts(); // update help prompts immediately } } @@ -267,6 +278,9 @@ void ViewController::render(const Eigen::Affine3f& parentTrans) it->second->render(trans); } + if(mWindow->peekGui() == this) + mWindow->renderHelpPromptsEarly(); + // fade out if(mFadeOpacity) {