diff --git a/src/Sound.cpp b/src/Sound.cpp index 000d7dc65..d3fad30e0 100644 --- a/src/Sound.cpp +++ b/src/Sound.cpp @@ -136,4 +136,11 @@ void Sound::setPosition(Uint32 newPosition) Uint32 Sound::getLength() const { return mSampleLength; -} \ No newline at end of file +} + +Uint32 Sound::getLengthMS() const +{ + //44100 samples per second, 2 channels (stereo) + //I have no idea why the *0.75 is necessary, but otherwise it's inaccurate + return (Uint32)((mSampleLength / 44100.0f / 2.0f * 0.75f) * 1000); +} diff --git a/src/Sound.h b/src/Sound.h index d4858c11b..51cac2f9f 100644 --- a/src/Sound.h +++ b/src/Sound.h @@ -31,6 +31,7 @@ public: Uint32 getPosition() const; void setPosition(Uint32 newPosition); Uint32 getLength() const; + Uint32 getLengthMS() const; }; #endif diff --git a/src/Window.cpp b/src/Window.cpp index 9c0af7905..8c4ce6dfb 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -7,9 +7,11 @@ #include "Settings.h" #include -Window::Window() : mNormalizeNextUpdate(false), mFrameTimeElapsed(0), mFrameCountElapsed(0), mAverageDeltaTime(10) +Window::Window() : mNormalizeNextUpdate(false), mFrameTimeElapsed(0), mFrameCountElapsed(0), mAverageDeltaTime(10), + mZoomFactor(1.0f), mCenterPoint(0, 0), mMatrix(Eigen::Affine3f::Identity()), mFadePercent(0.0f) { mInputManager = new InputManager(this); + setCenterPoint(Eigen::Vector2f(Renderer::getScreenWidth() / 2, Renderer::getScreenHeight() / 2)); } Window::~Window() @@ -127,13 +129,13 @@ void Window::render() if(mGuiStack.size() == 0) std::cout << "guistack empty\n"; - Eigen::Affine3f trans(Eigen::Affine3f::Identity()); - for(unsigned int i = 0; i < mGuiStack.size(); i++) { - mGuiStack.at(i)->render(trans); + mGuiStack.at(i)->render(mMatrix); } + postProcess(); + if(Settings::getInstance()->getBool("DRAWFRAMERATE")) { Renderer::setMatrix(Eigen::Affine3f::Identity()); @@ -155,3 +157,39 @@ ResourceManager* Window::getResourceManager() { return &mResourceManager; } + +void Window::setZoomFactor(const float& zoom) +{ + mZoomFactor = zoom; + updateMatrix(); +} + +void Window::setCenterPoint(const Eigen::Vector2f& point) +{ + mCenterPoint = point; + updateMatrix(); +} + +void Window::updateMatrix() +{ + const float sw = Renderer::getScreenWidth() / mZoomFactor; + const float sh = Renderer::getScreenHeight() / mZoomFactor; + + mMatrix = Eigen::Affine3f::Identity(); + mMatrix = mMatrix.scale(Eigen::Vector3f(mZoomFactor, mZoomFactor, 1)); + mMatrix = mMatrix.translate(Eigen::Vector3f(sw / 2 - mCenterPoint.x(), sh / 2 - mCenterPoint.y(), 0)); +} + +void Window::setFadePercent(const float& perc) +{ + mFadePercent = perc; +} + +void Window::postProcess() +{ + if(mFadePercent > 0.0f) + { + Renderer::setMatrix(Eigen::Affine3f::Identity()); + Renderer::drawRect(0, 0, Renderer::getScreenWidth(), Renderer::getScreenHeight(), 0x00000000 | ((unsigned char)(mFadePercent * 255))); + } +} diff --git a/src/Window.h b/src/Window.h index d4698e13a..9cb694d85 100644 --- a/src/Window.h +++ b/src/Window.h @@ -29,6 +29,11 @@ public: void normalizeNextUpdate(); + void setZoomFactor(const float& zoom); + void setCenterPoint(const Eigen::Vector2f& point); + + void setFadePercent(const float& perc); + private: InputManager* mInputManager; ResourceManager mResourceManager; @@ -42,6 +47,15 @@ private: std::string mFrameDataString; bool mNormalizeNextUpdate; + + float mZoomFactor; + Eigen::Vector2f mCenterPoint; + + void updateMatrix(); + Eigen::Affine3f mMatrix; + + void postProcess(); + float mFadePercent; }; #endif diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 1eade1e9b..6b39bb67a 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -10,7 +10,6 @@ std::vector GuiGameList::sortStates; - Eigen::Vector3f GuiGameList::getImagePos() { return Eigen::Vector3f(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX"), Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY"), 0.0f); @@ -32,7 +31,9 @@ GuiGameList::GuiGameList(Window* window) : GuiComponent(window), mDescContainer(window), mTransitionImage(window, 0.0f, 0.0f, "", (float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), true), mHeaderText(mWindow), - sortStateIndex(Settings::getInstance()->getInt("GameListSortIndex")) + sortStateIndex(Settings::getInstance()->getInt("GameListSortIndex")), + mLockInput(false), + mEffectFunc(NULL), mEffectTime(0), mGameLaunchEffectLength(700) { //first object initializes the vector if (sortStates.empty()) { @@ -116,7 +117,10 @@ void GuiGameList::render(const Eigen::Affine3f& parentTrans) } bool GuiGameList::input(InputConfig* config, Input input) -{ +{ + if(mLockInput) + return false; + mList.input(config, input); if(config->isMappedTo("a", input) && mFolder->getFileCount() > 0 && input.value != 0) @@ -135,10 +139,14 @@ bool GuiGameList::input(InputConfig* config, Input input) }else{ mList.stopScrolling(); - //wait for the sound to finish or we'll never hear it... - while(mTheme->getSound("menuSelect")->isPlaying()); + mEffectFunc = &GuiGameList::updateGameLaunchEffect; + mEffectTime = 0; + mGameLaunchEffectLength = (int)mTheme->getSound("menuSelect")->getLengthMS(); + if(mGameLaunchEffectLength < 800) + mGameLaunchEffectLength = 800; + + mLockInput = true; - mSystem->launchGame(mWindow, (GameData*)file); return true; } } @@ -390,6 +398,13 @@ void GuiGameList::update(int deltaTime) { mTransitionAnimation.update(deltaTime); mImageAnimation.update(deltaTime); + + if(mEffectFunc != NULL) + { + mEffectTime += deltaTime; + (this->*mEffectFunc)(mEffectTime); + } + GuiComponent::update(deltaTime); } @@ -406,3 +421,64 @@ void GuiGameList::doTransition(int dir) mTransitionAnimation.move(Renderer::getScreenWidth() * dir, 0, 50); } + +float lerpFloat(const float& start, const float& end, float t) +{ + if(t <= 0) + return start; + if(t >= 1) + return end; + + return (start * (1 - t) + end * t); +} + +Eigen::Vector2f lerpVector2f(const Eigen::Vector2f& start, const Eigen::Vector2f& end, float t) +{ + if(t <= 0) + return start; + if(t >= 1) + return end; + + return (start * (1 - t) + end * t); +} + +void GuiGameList::updateGameLaunchEffect(int t) +{ + const int endTime = mGameLaunchEffectLength; + + const int zoomTime = endTime; + const int centerTime = endTime - 100; + + const int fadeDelay = endTime - 500; + const int fadeTime = endTime - fadeDelay; + + Eigen::Vector2f imageCenter(mScreenshot.getCenter()); + if(!isDetailed()) + { + imageCenter << mList.getPosition().x() + mList.getSize().x() / 2, mList.getPosition().y() + mList.getSize().y() / 2; + } + + const Eigen::Vector2f centerStart(Renderer::getScreenWidth() / 2, Renderer::getScreenHeight() / 2); + + mWindow->setCenterPoint(lerpVector2f(centerStart, imageCenter, (float)t / endTime)); + mWindow->setZoomFactor(lerpFloat(1.0f, 2.0f, (float)t / endTime)); + mWindow->setFadePercent(lerpFloat(0.0f, 1.0f, (float)(t - fadeDelay) / fadeTime)); + + if(t > endTime) + { + //effect done + mSystem->launchGame(mWindow, (GameData*)mList.getSelectedObject()); + mEffectFunc = &GuiGameList::updateGameReturnEffect; + mEffectTime = 0; + mGameLaunchEffectLength = 700; + mLockInput = false; + } +} + +void GuiGameList::updateGameReturnEffect(int t) +{ + updateGameLaunchEffect(mGameLaunchEffectLength - t); + + if(t >= mGameLaunchEffectLength) + mEffectFunc = NULL; +} diff --git a/src/components/GuiGameList.h b/src/components/GuiGameList.h index d6a3143ec..dda1e8088 100644 --- a/src/components/GuiGameList.h +++ b/src/components/GuiGameList.h @@ -69,6 +69,15 @@ private: AnimationComponent mTransitionAnimation; Eigen::Vector3f getImagePos(); + + bool mLockInput; + + void (GuiGameList::*mEffectFunc)(int); + int mEffectTime; + int mGameLaunchEffectLength; + + void updateGameLaunchEffect(int t); + void updateGameReturnEffect(int t); }; #endif diff --git a/src/components/ImageComponent.cpp b/src/components/ImageComponent.cpp index 60f4b9e95..e7f990882 100644 --- a/src/components/ImageComponent.cpp +++ b/src/components/ImageComponent.cpp @@ -14,6 +14,12 @@ Eigen::Vector2i ImageComponent::getTextureSize() const return Eigen::Vector2i(0, 0); } +Eigen::Vector2f ImageComponent::getCenter() const +{ + return Eigen::Vector2f(mPosition.x() - (getSize().x() * mOrigin.x()) + getSize().x() / 2, + mPosition.y() - (getSize().y() * mOrigin.y()) + getSize().y() / 2); +} + ImageComponent::ImageComponent(Window* window, float offsetX, float offsetY, std::string path, float targetWidth, float targetHeight, bool allowUpscale) : GuiComponent(window), mTiled(false), mAllowUpscale(allowUpscale), mFlipX(false), mFlipY(false), mOrigin(0.5, 0.5), mTargetSize(targetWidth, targetHeight) { diff --git a/src/components/ImageComponent.h b/src/components/ImageComponent.h index 8f4d6a482..c0df6bea1 100644 --- a/src/components/ImageComponent.h +++ b/src/components/ImageComponent.h @@ -30,6 +30,8 @@ public: //You can get the rendered size of the ImageComponent with getSize(). Eigen::Vector2i getTextureSize() const; + Eigen::Vector2f getCenter() const; + bool hasImage(); void render(const Eigen::Affine3f& parentTrans) override; diff --git a/src/components/TextListComponent.h b/src/components/TextListComponent.h index acfd1da75..7de53ce8d 100644 --- a/src/components/TextListComponent.h +++ b/src/components/TextListComponent.h @@ -149,7 +149,12 @@ void TextListComponent::render(const Eigen::Affine3f& parentTrans) if(listCutoff > (int)mRowVector.size()) listCutoff = mRowVector.size(); - Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), Eigen::Vector2i((int)getSize().x(), (int)getSize().y())); + Eigen::Vector3f dim(getSize().x(), getSize().y(), 0); + dim = trans * dim - trans.translation(); + Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), Eigen::Vector2i((int)dim.x(), (int)dim.y())); + + //Renderer::pushClipRect(pos, dim); + //Renderer::pushClipRect(Eigen::Vector2i((int)trans.translation().x(), (int)trans.translation().y()), Eigen::Vector2i((int)getSize().x() * trans., (int)getSize().y() * trans.scale().y())); //Renderer::pushClipRect(getGlobalOffset(), getSize()); for(int i = startEntry; i < listCutoff; i++)