Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: Add BG animation for recent games #14347

Merged
merged 3 commits into from
Apr 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ enum ChatPositions {
CENTER_RIGHT = 7,
};

enum class BackgroundAnimation {
OFF = 0,
FLOATING_SYMBOLS = 1,
};

namespace http {
class Download;
class Downloader;
Expand Down
6 changes: 6 additions & 0 deletions Core/ConfigValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,9 @@ enum class UnthrottleMode {
SKIP_DRAW = 1,
SKIP_FLIP = 2,
};

enum class BackgroundAnimation {
OFF = 0,
FLOATING_SYMBOLS = 1,
RECENT_GAMES = 2,
};
8 changes: 8 additions & 0 deletions UI/GameInfoCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ class GameInfo {
std::string GetTitle();
void SetTitle(const std::string &newTitle);

GameInfoTex *GetBGPic() {
if (pic0.texture)
return &pic0;
if (pic1.texture)
return &pic1;
return nullptr;
}

// Hold this when reading or writing from the GameInfo.
// Don't need to hold it when just passing around the pointer,
// and obviously also not when creating it and holding the only pointer
Expand Down
2 changes: 1 addition & 1 deletion UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ void GameSettingsScreen::CreateViews() {
if (backgroundChoice_ != nullptr) {
backgroundChoice_->OnClick.Handle(this, &GameSettingsScreen::OnChangeBackground);
}
static const char *backgroundAnimations[] = { "No animation", "Floating Symbols" };
static const char *backgroundAnimations[] = { "No animation", "Floating symbols", "Recent games" };
systemSettings->Add(new PopupMultiChoice(&g_Config.iBackgroundAnimation, sy->T("UI background animation"), backgroundAnimations, 0, ARRAY_SIZE(backgroundAnimations), sy->GetName(), screenManager()));

systemSettings->Add(new ItemHeader(sy->T("Help the PPSSPP team")));
Expand Down
8 changes: 2 additions & 6 deletions UI/MainScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,12 +1309,8 @@ bool MainScreen::DrawBackgroundFor(UIContext &dc, const std::string &gamePath, f
return false;
}

Draw::Texture *texture = nullptr;
if (ginfo->pic1.texture) {
texture = ginfo->pic1.texture->GetTexture();
} else if (ginfo->pic0.texture) {
texture = ginfo->pic0.texture->GetTexture();
}
auto pic = ginfo->GetBGPic();
Draw::Texture *texture = pic ? pic->texture->GetTexture() : nullptr;

uint32_t color = whiteAlpha(ease(progress)) & 0xFFc0c0c0;
if (texture) {
Expand Down
131 changes: 108 additions & 23 deletions UI/MiscScreens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,29 +85,118 @@ class FloatingSymbolsAnimation : public Animation {
void Draw(UIContext &dc, double t, float alpha) override {
float xres = dc.GetBounds().w;
float yres = dc.GetBounds().h;
if (xbase[0] == 0.0f || last_xres != xres || last_yres != yres) {
GMRng rng;
for (int i = 0; i < 100; i++) {
xbase[i] = rng.F() * xres;
ybase[i] = rng.F() * yres;
}
last_xres = xres;
last_yres = yres;
if (last_xres != xres || last_yres != yres) {
Regenerate(xres, yres);
}

for (int i = 0; i < 100; i++) {
for (int i = 0; i < COUNT; i++) {
float x = xbase[i] + dc.GetBounds().x;
float y = ybase[i] + dc.GetBounds().y + 40 * cosf(i * 7.2f + t * 1.3f);
float angle = (float)sin(i + t);
int n = i & 3;
ui_draw2d.DrawImageRotated(symbols[n], x, y, 1.0f, angle, colorAlpha(colors[n], alpha * 0.1f));
}
}

private:
float xbase[100] = { 0 };
float ybase[100] = { 0 };
static constexpr int COUNT = 100;

float xbase[COUNT]{};
float ybase[COUNT]{};
float last_xres = 0;
float last_yres = 0;

void Regenerate(int xres, int yres) {
GMRng rng;
for (int i = 0; i < COUNT; i++) {
xbase[i] = rng.F() * xres;
ybase[i] = rng.F() * yres;
}

last_xres = xres;
last_yres = yres;
}
};

class RecentGamesAnimation : public Animation {
public:
~RecentGamesAnimation() override {}
void Draw(UIContext &dc, double t, float alpha) override {
if (lastIndex_ == nextIndex_) {
CheckNext(dc, t);
} else if (t > nextT_) {
lastIndex_ = nextIndex_;
}

if (!g_Config.recentIsos.empty()) {
std::shared_ptr<GameInfo> lastInfo = GetInfo(dc, lastIndex_);
std::shared_ptr<GameInfo> nextInfo = GetInfo(dc, nextIndex_);
dc.Flush();

float lastAmount = Clamp((float)(nextT_ - t) * 1.0f / TRANSITION, 0.0f, 1.0f);
DrawTex(dc, lastInfo, lastAmount * alpha * 0.2f);

float nextAmount = lastAmount <= 0.0f ? 1.0f : 1.0f - lastAmount;
DrawTex(dc, nextInfo, nextAmount * alpha * 0.2f);

dc.RebindTexture();
}
}

private:
void CheckNext(UIContext &dc, double t) {
if (g_Config.recentIsos.empty()) {
return;
}

for (int index = lastIndex_ + 1; index != lastIndex_; ++index) {
if (index < 0 || index >= (int)g_Config.recentIsos.size()) {
if (lastIndex_ == -1)
break;
index = 0;
}

std::shared_ptr<GameInfo> ginfo = GetInfo(dc, index);
if (ginfo && ginfo->pending) {
// Wait for it to load. It might be the next one.
break;
}
if (ginfo && (ginfo->pic1.texture || ginfo->pic0.texture)) {
nextIndex_ = index;
nextT_ = t + INTERVAL;
break;
}

// Otherwise, keep going. This skips games with no BG.
}
}

std::shared_ptr<GameInfo> GetInfo(UIContext &dc, int index) {
if (index < 0) {
return nullptr;
}
return g_gameInfoCache->GetInfo(dc.GetDrawContext(), g_Config.recentIsos[index], GAMEINFO_WANTBG);
}

void DrawTex(UIContext &dc, std::shared_ptr<GameInfo> &ginfo, float amount) {
if (!ginfo || amount <= 0.0f)
return;
GameInfoTex *pic = ginfo->GetBGPic();
if (!pic)
return;

dc.GetDrawContext()->BindTexture(0, pic->texture->GetTexture());
uint32_t color = whiteAlpha(amount) & 0xFFc0c0c0;
dc.Draw()->DrawTexRect(dc.GetBounds(), 0, 0, 1, 1, color);
dc.Flush();
}

static constexpr double INTERVAL = 8.0;
static constexpr float TRANSITION = 3.0f;

int lastIndex_ = -1;
int nextIndex_ = -1;
double nextT_ = -INTERVAL;
};

// TODO: Add more styles. Remember to add to the enum in Config.cpp and the selector in GameSettings too.
Expand Down Expand Up @@ -137,6 +226,9 @@ void DrawBackground(UIContext &dc, float alpha) {
case BackgroundAnimation::FLOATING_SYMBOLS:
g_Animation.reset(new FloatingSymbolsAnimation());
break;
case BackgroundAnimation::RECENT_GAMES:
g_Animation.reset(new RecentGamesAnimation());
break;
default:
g_Animation.reset(nullptr);
}
Expand Down Expand Up @@ -177,19 +269,12 @@ void DrawGameBackground(UIContext &dc, const std::string &gamePath) {
ginfo = g_gameInfoCache->GetInfo(dc.GetDrawContext(), gamePath, GAMEINFO_WANTBG);
dc.Flush();

bool hasPic = false;
double loadTime;
if (ginfo && ginfo->pic1.texture) {
dc.GetDrawContext()->BindTexture(0, ginfo->pic1.texture->GetTexture());
loadTime = ginfo->pic1.timeLoaded;
hasPic = true;
} else if (ginfo && ginfo->pic0.texture) {
dc.GetDrawContext()->BindTexture(0, ginfo->pic0.texture->GetTexture());
loadTime = ginfo->pic0.timeLoaded;
hasPic = true;
GameInfoTex *pic = ginfo ? ginfo->GetBGPic() : nullptr;
if (pic) {
dc.GetDrawContext()->BindTexture(0, pic->texture->GetTexture());
}
if (hasPic) {
uint32_t color = whiteAlpha(ease((time_now_d() - loadTime) * 3)) & 0xFFc0c0c0;
if (pic) {
uint32_t color = whiteAlpha(ease((time_now_d() - pic->timeLoaded) * 3)) & 0xFFc0c0c0;
dc.Draw()->DrawTexRect(dc.GetBounds(), 0,0,1,1, color);
dc.Flush();
dc.RebindTexture();
Expand Down
8 changes: 3 additions & 5 deletions UI/TextureUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,9 @@ void GameIconView::Draw(UIContext &dc) {

// Fade icon with the backgrounds.
double loadTime = info->icon.timeLoaded;
if (info->pic1.texture) {
loadTime = std::max(loadTime, info->pic1.timeLoaded);
}
if (info->pic0.texture) {
loadTime = std::max(loadTime, info->pic0.timeLoaded);
auto pic = info->GetBGPic();
if (pic) {
loadTime = std::max(loadTime, pic->timeLoaded);
}
uint32_t color = whiteAlpha(ease((time_now_d() - loadTime) * 3));

Expand Down