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_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();
}
}

View file

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