From e1fff00bab1b9fdb585fde41cca1b2cdcb563529 Mon Sep 17 00:00:00 2001 From: Hyper <34012267+hyperbx@users.noreply.github.com> Date: Sat, 30 Nov 2024 21:57:40 +0000 Subject: [PATCH] achievements_overlay: implemented queue and hermite interpolation --- UnleashedRecomp/ui/achievement_overlay.cpp | 90 +++++++++++++--------- UnleashedRecomp/ui/achievement_overlay.h | 4 + UnleashedRecomp/ui/imgui_utils.h | 7 +- 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/UnleashedRecomp/ui/achievement_overlay.cpp b/UnleashedRecomp/ui/achievement_overlay.cpp index df9d22e0..e6e4eee4 100644 --- a/UnleashedRecomp/ui/achievement_overlay.cpp +++ b/UnleashedRecomp/ui/achievement_overlay.cpp @@ -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_END = 9; 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) { auto drawList = ImGui::GetForegroundDrawList(); // 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 centreY = (min.y + max.y) / 2; - if (m_isClosing) + if (g_isClosing) { - min.x = CubicEase(min.x, centreX, containerMotion); - max.x = CubicEase(max.x, centreX, containerMotion); - min.y = CubicEase(min.y, centreY, containerMotion); - max.y = CubicEase(max.y, centreY, containerMotion); + min.x = Hermite(min.x, centreX, containerMotion); + max.x = Hermite(max.x, centreX, containerMotion); + min.y = Hermite(min.y, centreY, containerMotion); + max.y = Hermite(max.y, centreY, containerMotion); } else { - min.x = CubicEase(centreX, min.x, containerMotion); - max.x = CubicEase(centreX, max.x, containerMotion); - min.y = CubicEase(centreY, min.y, containerMotion); - max.y = CubicEase(centreY, max.y, containerMotion); + min.x = Hermite(centreX, min.x, containerMotion); + max.x = Hermite(centreX, max.x, containerMotion); + min.y = Hermite(centreY, min.y, containerMotion); + max.y = Hermite(centreY, max.y, containerMotion); } auto vertices = GetPauseContainerVertices(min, max, cornerRadius); // Transparency fade animation. - auto colourMotion = m_isClosing - ? ComputeMotion(m_appearTime, OVERLAY_CONTAINER_OUTRO_FADE_START, OVERLAY_CONTAINER_OUTRO_FADE_END) - : ComputeMotion(m_appearTime, OVERLAY_CONTAINER_INTRO_FADE_START, OVERLAY_CONTAINER_INTRO_FADE_END); + auto colourMotion = g_isClosing + ? ComputeMotion(g_appearTime, OVERLAY_CONTAINER_OUTRO_FADE_START, OVERLAY_CONTAINER_OUTRO_FADE_END) + : ComputeMotion(g_appearTime, OVERLAY_CONTAINER_INTRO_FADE_START, OVERLAY_CONTAINER_INTRO_FADE_END); - auto alpha = m_isClosing - ? CubicEase(1, 0, colourMotion) - : CubicEase(0, 1, colourMotion); + auto alpha = g_isClosing + ? Hermite(1, 0, colourMotion) + : Hermite(0, 1, colourMotion); auto colShadow = IM_COL32(0, 0, 0, 156 * alpha); auto colGradientTop = IM_COL32(197, 194, 197, 200 * alpha); @@ -114,7 +114,7 @@ void AchievementOverlay::Init() 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() @@ -122,19 +122,19 @@ void AchievementOverlay::Draw() if (!s_isVisible) return; - if (ImGui::GetTime() - m_appearTime >= OVERLAY_DURATION) + if (ImGui::GetTime() - g_appearTime >= OVERLAY_DURATION) AchievementOverlay::Close(); auto drawList = ImGui::GetForegroundDrawList(); auto& res = ImGui::GetIO().DisplaySize; auto strAchievementUnlocked = Localise("Achievements_Unlock").c_str(); - auto strAchievementName = m_achievement.Name.c_str(); + auto strAchievementName = g_achievement.Name.c_str(); // Calculate text sizes. auto fontSize = Scale(24); - auto headerSize = m_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementUnlocked); - auto bodySize = m_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementName); + auto headerSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementUnlocked); + auto bodySize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementName); auto maxSize = std::max(headerSize.x, bodySize.x); // Calculate image margins. @@ -153,10 +153,16 @@ void AchievementOverlay::Draw() if (DrawContainer(min, max)) { + if (g_isClosing) + { + s_isVisible = false; + return; + } + // Draw achievement icon. 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 + imageSize, /* Y */ min.y + imageMarginY + imageSize }, // p_max { 0, 0 }, // uv_min @@ -167,7 +173,7 @@ void AchievementOverlay::Draw() // Draw header text. DrawTextWithShadow ( - m_fntSeurat, // font + g_fntSeurat, // font fontSize, // fontSize { /* X */ min.x + textMarginX + (maxSize - headerSize.x) / 2, /* Y */ min.y + textMarginY }, // pos IM_COL32(252, 243, 5, 255), // colour @@ -180,7 +186,7 @@ void AchievementOverlay::Draw() // Draw achievement name. DrawTextWithShadow ( - m_fntSeurat, // font + g_fntSeurat, // font fontSize, // fontSize { /* X */ min.x + textMarginX + (maxSize - bodySize.x) / 2, /* Y */ min.y + textMarginY + bodySize.y + Scale(6) }, // pos IM_COL32(255, 255, 255, 255), // colour @@ -197,22 +203,32 @@ void AchievementOverlay::Draw() void AchievementOverlay::Open(int id) { + if (s_isVisible) + { + s_queue.emplace(id); + return; + } + s_isVisible = true; - m_isClosing = false; - m_appearTime = ImGui::GetTime(); - m_achievement = g_xdbfWrapper.GetAchievement((EXDBFLanguage)Config::Language.Value, id); + g_isClosing = false; + g_appearTime = ImGui::GetTime(); + g_achievement = g_xdbfWrapper.GetAchievement((EXDBFLanguage)Config::Language.Value, id); Game_PlaySound("obj_navi_appear"); } void AchievementOverlay::Close() { - if (!m_isClosing) + if (!g_isClosing) { - m_appearTime = ImGui::GetTime(); - m_isClosing = true; + g_appearTime = ImGui::GetTime(); + g_isClosing = true; } - if (ImGui::GetTime() - m_appearTime >= OVERLAY_CONTAINER_COMMON_MOTION_END) + if (s_queue.size()) + { s_isVisible = false; + AchievementOverlay::Open(s_queue.front()); + s_queue.pop(); + } } diff --git a/UnleashedRecomp/ui/achievement_overlay.h b/UnleashedRecomp/ui/achievement_overlay.h index 697c0bcb..5312605f 100644 --- a/UnleashedRecomp/ui/achievement_overlay.h +++ b/UnleashedRecomp/ui/achievement_overlay.h @@ -1,10 +1,14 @@ #pragma once +#include + class AchievementOverlay { public: inline static bool s_isVisible = false; + inline static std::queue s_queue{}; + static void Init(); static void Draw(); static void Open(int id); diff --git a/UnleashedRecomp/ui/imgui_utils.h b/UnleashedRecomp/ui/imgui_utils.h index 4e96f902..b3a1bd92 100644 --- a/UnleashedRecomp/ui/imgui_utils.h +++ b/UnleashedRecomp/ui/imgui_utils.h @@ -176,11 +176,16 @@ static float Lerp(float a, float b, float 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); } +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) { return { a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t };