achievements_overlay: implemented queue and hermite interpolation

This commit is contained in:
Hyper 2024-11-30 21:57:40 +00:00
parent 82f3c4ee1a
commit e1fff00bab
3 changed files with 63 additions and 38 deletions

View file

@ -14,53 +14,53 @@ constexpr double OVERLAY_CONTAINER_COMMON_MOTION_END = 11;
constexpr double OVERLAY_CONTAINER_INTRO_FADE_START = 5; constexpr double OVERLAY_CONTAINER_INTRO_FADE_START = 5;
constexpr double OVERLAY_CONTAINER_INTRO_FADE_END = 9; constexpr double OVERLAY_CONTAINER_INTRO_FADE_END = 9;
constexpr double OVERLAY_CONTAINER_OUTRO_FADE_START = 0; constexpr double OVERLAY_CONTAINER_OUTRO_FADE_START = 0;
constexpr double OVERLAY_CONTAINER_OUTRO_FADE_END = 5; constexpr double OVERLAY_CONTAINER_OUTRO_FADE_END = 4;
constexpr double OVERLAY_DURATION = 5; constexpr double OVERLAY_DURATION = 3;
static bool m_isClosing = false; static bool g_isClosing = false;
static double m_appearTime = 0; static double g_appearTime = 0;
static Achievement m_achievement; static Achievement g_achievement;
static ImFont* m_fntSeurat; static ImFont* g_fntSeurat;
static bool DrawContainer(ImVec2 min, ImVec2 max, float cornerRadius = 25) static bool DrawContainer(ImVec2 min, ImVec2 max, float cornerRadius = 25)
{ {
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
// Expand/retract animation. // Expand/retract animation.
auto containerMotion = ComputeMotion(m_appearTime, OVERLAY_CONTAINER_COMMON_MOTION_START, OVERLAY_CONTAINER_COMMON_MOTION_END); auto containerMotion = ComputeMotion(g_appearTime, OVERLAY_CONTAINER_COMMON_MOTION_START, OVERLAY_CONTAINER_COMMON_MOTION_END);
auto centreX = (min.x + max.x) / 2; auto centreX = (min.x + max.x) / 2;
auto centreY = (min.y + max.y) / 2; auto centreY = (min.y + max.y) / 2;
if (m_isClosing) if (g_isClosing)
{ {
min.x = CubicEase(min.x, centreX, containerMotion); min.x = Hermite(min.x, centreX, containerMotion);
max.x = CubicEase(max.x, centreX, containerMotion); max.x = Hermite(max.x, centreX, containerMotion);
min.y = CubicEase(min.y, centreY, containerMotion); min.y = Hermite(min.y, centreY, containerMotion);
max.y = CubicEase(max.y, centreY, containerMotion); max.y = Hermite(max.y, centreY, containerMotion);
} }
else else
{ {
min.x = CubicEase(centreX, min.x, containerMotion); min.x = Hermite(centreX, min.x, containerMotion);
max.x = CubicEase(centreX, max.x, containerMotion); max.x = Hermite(centreX, max.x, containerMotion);
min.y = CubicEase(centreY, min.y, containerMotion); min.y = Hermite(centreY, min.y, containerMotion);
max.y = CubicEase(centreY, max.y, containerMotion); max.y = Hermite(centreY, max.y, containerMotion);
} }
auto vertices = GetPauseContainerVertices(min, max, cornerRadius); auto vertices = GetPauseContainerVertices(min, max, cornerRadius);
// Transparency fade animation. // Transparency fade animation.
auto colourMotion = m_isClosing auto colourMotion = g_isClosing
? ComputeMotion(m_appearTime, OVERLAY_CONTAINER_OUTRO_FADE_START, OVERLAY_CONTAINER_OUTRO_FADE_END) ? ComputeMotion(g_appearTime, OVERLAY_CONTAINER_OUTRO_FADE_START, OVERLAY_CONTAINER_OUTRO_FADE_END)
: ComputeMotion(m_appearTime, OVERLAY_CONTAINER_INTRO_FADE_START, OVERLAY_CONTAINER_INTRO_FADE_END); : ComputeMotion(g_appearTime, OVERLAY_CONTAINER_INTRO_FADE_START, OVERLAY_CONTAINER_INTRO_FADE_END);
auto alpha = m_isClosing auto alpha = g_isClosing
? CubicEase(1, 0, colourMotion) ? Hermite(1, 0, colourMotion)
: CubicEase(0, 1, colourMotion); : Hermite(0, 1, colourMotion);
auto colShadow = IM_COL32(0, 0, 0, 156 * alpha); auto colShadow = IM_COL32(0, 0, 0, 156 * alpha);
auto colGradientTop = IM_COL32(197, 194, 197, 200 * alpha); auto colGradientTop = IM_COL32(197, 194, 197, 200 * alpha);
@ -114,7 +114,7 @@ void AchievementOverlay::Init()
constexpr float FONT_SCALE = 2.0f; constexpr float FONT_SCALE = 2.0f;
m_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 24.0f * FONT_SCALE); g_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 24.0f * FONT_SCALE);
} }
void AchievementOverlay::Draw() void AchievementOverlay::Draw()
@ -122,19 +122,19 @@ void AchievementOverlay::Draw()
if (!s_isVisible) if (!s_isVisible)
return; return;
if (ImGui::GetTime() - m_appearTime >= OVERLAY_DURATION) if (ImGui::GetTime() - g_appearTime >= OVERLAY_DURATION)
AchievementOverlay::Close(); AchievementOverlay::Close();
auto drawList = ImGui::GetForegroundDrawList(); auto drawList = ImGui::GetForegroundDrawList();
auto& res = ImGui::GetIO().DisplaySize; auto& res = ImGui::GetIO().DisplaySize;
auto strAchievementUnlocked = Localise("Achievements_Unlock").c_str(); auto strAchievementUnlocked = Localise("Achievements_Unlock").c_str();
auto strAchievementName = m_achievement.Name.c_str(); auto strAchievementName = g_achievement.Name.c_str();
// Calculate text sizes. // Calculate text sizes.
auto fontSize = Scale(24); auto fontSize = Scale(24);
auto headerSize = m_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementUnlocked); auto headerSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementUnlocked);
auto bodySize = m_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementName); auto bodySize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementName);
auto maxSize = std::max(headerSize.x, bodySize.x); auto maxSize = std::max(headerSize.x, bodySize.x);
// Calculate image margins. // Calculate image margins.
@ -153,10 +153,16 @@ void AchievementOverlay::Draw()
if (DrawContainer(min, max)) if (DrawContainer(min, max))
{ {
if (g_isClosing)
{
s_isVisible = false;
return;
}
// Draw achievement icon. // Draw achievement icon.
drawList->AddImage drawList->AddImage
( (
g_xdbfTextureCache[m_achievement.ID], // user_texture_id g_xdbfTextureCache[g_achievement.ID], // user_texture_id
{ /* X */ min.x + imageMarginX, /* Y */ min.y + imageMarginY }, // p_min { /* X */ min.x + imageMarginX, /* Y */ min.y + imageMarginY }, // p_min
{ /* X */ min.x + imageMarginX + imageSize, /* Y */ min.y + imageMarginY + imageSize }, // p_max { /* X */ min.x + imageMarginX + imageSize, /* Y */ min.y + imageMarginY + imageSize }, // p_max
{ 0, 0 }, // uv_min { 0, 0 }, // uv_min
@ -167,7 +173,7 @@ void AchievementOverlay::Draw()
// Draw header text. // Draw header text.
DrawTextWithShadow DrawTextWithShadow
( (
m_fntSeurat, // font g_fntSeurat, // font
fontSize, // fontSize fontSize, // fontSize
{ /* X */ min.x + textMarginX + (maxSize - headerSize.x) / 2, /* Y */ min.y + textMarginY }, // pos { /* X */ min.x + textMarginX + (maxSize - headerSize.x) / 2, /* Y */ min.y + textMarginY }, // pos
IM_COL32(252, 243, 5, 255), // colour IM_COL32(252, 243, 5, 255), // colour
@ -180,7 +186,7 @@ void AchievementOverlay::Draw()
// Draw achievement name. // Draw achievement name.
DrawTextWithShadow DrawTextWithShadow
( (
m_fntSeurat, // font g_fntSeurat, // font
fontSize, // fontSize fontSize, // fontSize
{ /* X */ min.x + textMarginX + (maxSize - bodySize.x) / 2, /* Y */ min.y + textMarginY + bodySize.y + Scale(6) }, // pos { /* X */ min.x + textMarginX + (maxSize - bodySize.x) / 2, /* Y */ min.y + textMarginY + bodySize.y + Scale(6) }, // pos
IM_COL32(255, 255, 255, 255), // colour IM_COL32(255, 255, 255, 255), // colour
@ -197,22 +203,32 @@ void AchievementOverlay::Draw()
void AchievementOverlay::Open(int id) void AchievementOverlay::Open(int id)
{ {
if (s_isVisible)
{
s_queue.emplace(id);
return;
}
s_isVisible = true; s_isVisible = true;
m_isClosing = false; g_isClosing = false;
m_appearTime = ImGui::GetTime(); g_appearTime = ImGui::GetTime();
m_achievement = g_xdbfWrapper.GetAchievement((EXDBFLanguage)Config::Language.Value, id); g_achievement = g_xdbfWrapper.GetAchievement((EXDBFLanguage)Config::Language.Value, id);
Game_PlaySound("obj_navi_appear"); Game_PlaySound("obj_navi_appear");
} }
void AchievementOverlay::Close() void AchievementOverlay::Close()
{ {
if (!m_isClosing) if (!g_isClosing)
{ {
m_appearTime = ImGui::GetTime(); g_appearTime = ImGui::GetTime();
m_isClosing = true; g_isClosing = true;
} }
if (ImGui::GetTime() - m_appearTime >= OVERLAY_CONTAINER_COMMON_MOTION_END) if (s_queue.size())
{
s_isVisible = false; s_isVisible = false;
AchievementOverlay::Open(s_queue.front());
s_queue.pop();
}
} }

View file

@ -1,10 +1,14 @@
#pragma once #pragma once
#include <queue>
class AchievementOverlay class AchievementOverlay
{ {
public: public:
inline static bool s_isVisible = false; inline static bool s_isVisible = false;
inline static std::queue<uint16_t> s_queue{};
static void Init(); static void Init();
static void Draw(); static void Draw();
static void Open(int id); static void Open(int id);

View file

@ -176,11 +176,16 @@ static float Lerp(float a, float b, float t)
return a + (b - a) * t; return a + (b - a) * t;
} }
static float CubicEase(float a, float b, float t) static float Cubic(float a, float b, float t)
{ {
return a + (b - a) * (t * t * t); return a + (b - a) * (t * t * t);
} }
static float Hermite(float a, float b, float t)
{
return a + (b - a) * (t * t * (3 - 2 * t));
}
static ImVec2 Lerp(const ImVec2& a, const ImVec2& b, float t) static ImVec2 Lerp(const ImVec2& a, const ImVec2& b, float t)
{ {
return { a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t }; return { a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t };