mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-05-08 02:01:37 +00:00
Clean-up, improved animation and layouts
This commit is contained in:
parent
8c3b50738d
commit
faf3b52331
14 changed files with 619 additions and 498 deletions
|
|
@ -77,7 +77,6 @@ set(SWA_PATCHES_CXX_SOURCES
|
||||||
set(SWA_UI_CXX_SOURCES
|
set(SWA_UI_CXX_SOURCES
|
||||||
"ui/achievement_menu.cpp"
|
"ui/achievement_menu.cpp"
|
||||||
"ui/achievement_overlay.cpp"
|
"ui/achievement_overlay.cpp"
|
||||||
"ui/imgui_view.cpp"
|
|
||||||
"ui/options_menu.cpp"
|
"ui/options_menu.cpp"
|
||||||
"ui/sdl_listener.cpp"
|
"ui/sdl_listener.cpp"
|
||||||
"ui/window.cpp"
|
"ui/window.cpp"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <xdbf_wrapper.h>
|
|
||||||
|
|
||||||
extern double g_deltaTime;
|
extern double g_deltaTime;
|
||||||
extern XDBFWrapper g_xdbf;
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,12 @@
|
||||||
#include <cpu/code_cache.h>
|
#include <cpu/code_cache.h>
|
||||||
#include <cpu/guest_code.h>
|
#include <cpu/guest_code.h>
|
||||||
#include <kernel/memory.h>
|
#include <kernel/memory.h>
|
||||||
|
#include <kernel/xdbf.h>
|
||||||
#include <xxHashMap.h>
|
#include <xxHashMap.h>
|
||||||
#include <shader/shader_cache.h>
|
#include <shader/shader_cache.h>
|
||||||
#include <ui/imgui_view.h>
|
#include <ui/achievement_menu.h>
|
||||||
|
#include <ui/achievement_overlay.h>
|
||||||
|
#include <ui/options_menu.h>
|
||||||
|
|
||||||
#include "imgui_snapshot.h"
|
#include "imgui_snapshot.h"
|
||||||
#include "imgui_common.h"
|
#include "imgui_common.h"
|
||||||
|
|
@ -1011,8 +1014,9 @@ static void CreateImGuiBackend()
|
||||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
|
io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
|
||||||
|
|
||||||
for (auto& view : GetImGuiViews())
|
AchievementMenu::Init();
|
||||||
view->Init();
|
AchievementOverlay::Init();
|
||||||
|
OptionsMenu::Init();
|
||||||
|
|
||||||
ImGui_ImplSDL2_InitForOther(Window::s_pWindow);
|
ImGui_ImplSDL2_InitForOther(Window::s_pWindow);
|
||||||
|
|
||||||
|
|
@ -1310,6 +1314,18 @@ static void CreateHostDevice()
|
||||||
desc.renderTargetBlend[0] = RenderBlendDesc::Copy();
|
desc.renderTargetBlend[0] = RenderBlendDesc::Copy();
|
||||||
desc.renderTargetCount = 1;
|
desc.renderTargetCount = 1;
|
||||||
g_gammaCorrectionPipeline = g_device->createGraphicsPipeline(desc);
|
g_gammaCorrectionPipeline = g_device->createGraphicsPipeline(desc);
|
||||||
|
|
||||||
|
g_xdbfTextureCache = std::unordered_map<uint16_t, GuestTexture*>();
|
||||||
|
|
||||||
|
for (auto& achievement : g_xdbfWrapper.GetAchievements(XDBF_LANGUAGE_ENGLISH))
|
||||||
|
{
|
||||||
|
// huh?
|
||||||
|
if (!achievement.pImageBuffer || !achievement.ImageBufferSize)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_xdbfTextureCache[achievement.ID] =
|
||||||
|
LoadTexture((uint8_t*)achievement.pImageBuffer, achievement.ImageBufferSize).release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WaitForGPU()
|
static void WaitForGPU()
|
||||||
|
|
@ -1653,8 +1669,9 @@ static void DrawImGui()
|
||||||
ImGui_ImplSDL2_NewFrame();
|
ImGui_ImplSDL2_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
for (auto& view : GetImGuiViews())
|
AchievementMenu::Draw();
|
||||||
view->Draw();
|
OptionsMenu::Draw();
|
||||||
|
AchievementOverlay::Draw();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
|
||||||
|
|
|
||||||
7
UnleashedRecomp/kernel/xdbf.h
Normal file
7
UnleashedRecomp/kernel/xdbf.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gpu/video.h>
|
||||||
|
#include <xdbf_wrapper.h>
|
||||||
|
|
||||||
|
extern XDBFWrapper g_xdbfWrapper;
|
||||||
|
extern std::unordered_map<uint16_t, GuestTexture*> g_xdbfTextureCache;
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
#include <user/achievement_data.h>
|
#include <user/achievement_data.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
#include <user/paths.h>
|
#include <user/paths.h>
|
||||||
#include <xdbf_wrapper.h>
|
#include <kernel/xdbf.h>
|
||||||
|
|
||||||
#define GAME_XEX_PATH "game:\\default.xex"
|
#define GAME_XEX_PATH "game:\\default.xex"
|
||||||
|
|
||||||
|
|
@ -24,7 +24,8 @@ const size_t XMAIOEnd = XMAIOBegin + 0x0000FFFF;
|
||||||
Memory g_memory{ reinterpret_cast<void*>(0x100000000), 0x100000000 };
|
Memory g_memory{ reinterpret_cast<void*>(0x100000000), 0x100000000 };
|
||||||
Heap g_userHeap;
|
Heap g_userHeap;
|
||||||
CodeCache g_codeCache;
|
CodeCache g_codeCache;
|
||||||
XDBFWrapper g_xdbf;
|
XDBFWrapper g_xdbfWrapper;
|
||||||
|
std::unordered_map<uint16_t, GuestTexture*> g_xdbfTextureCache;
|
||||||
|
|
||||||
// Name inspired from nt's entry point
|
// Name inspired from nt's entry point
|
||||||
void KiSystemStartup()
|
void KiSystemStartup()
|
||||||
|
|
@ -124,7 +125,7 @@ uint32_t LdrLoadModule(const char* path)
|
||||||
|
|
||||||
auto res = Xex2FindOptionalHeader<XEX_RESOURCE_INFO>(xex, XEX_HEADER_RESOURCE_INFO);
|
auto res = Xex2FindOptionalHeader<XEX_RESOURCE_INFO>(xex, XEX_HEADER_RESOURCE_INFO);
|
||||||
|
|
||||||
g_xdbf = XDBFWrapper((uint8_t*)g_memory.Translate(res->Offset.get()), res->SizeOfData);
|
g_xdbfWrapper = XDBFWrapper((uint8_t*)g_memory.Translate(res->Offset.get()), res->SizeOfData);
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,136 +1,115 @@
|
||||||
#include "achievement_menu.h"
|
#include "achievement_menu.h"
|
||||||
#include "imgui_utils.h"
|
#include "imgui_utils.h"
|
||||||
#include <xdbf_wrapper.h>
|
|
||||||
#include <api/SWA.h>
|
#include <api/SWA.h>
|
||||||
#include <gpu/video.h>
|
#include <gpu/video.h>
|
||||||
|
#include <kernel/xdbf.h>
|
||||||
#include <locale/locale.h>
|
#include <locale/locale.h>
|
||||||
#include <user/achievement_data.h>
|
#include <user/achievement_data.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
#include <app.h>
|
#include <app.h>
|
||||||
#include <exports.h>
|
#include <exports.h>
|
||||||
|
|
||||||
AchievementMenu m_achievementMenu;
|
static std::vector<Achievement> m_achievements;
|
||||||
|
|
||||||
static std::vector<Achievement> g_achievements;
|
static ImFont* m_fntSeurat;
|
||||||
static std::unordered_map<uint16_t, GuestTexture*> g_achievementTextures;
|
static ImFont* m_fntNewRodin;
|
||||||
|
|
||||||
static ImFont* g_fntSeurat;
|
static int m_firstVisibleRowIndex;
|
||||||
static ImFont* g_fntNewRodin;
|
static int m_prevSelectedRowIndex;
|
||||||
|
static int m_selectedRowIndex;
|
||||||
|
static double m_rowSelectionTime;
|
||||||
|
|
||||||
static int g_firstVisibleRowIndex;
|
static bool m_upWasHeld;
|
||||||
static int g_prevSelectedRowIndex;
|
static bool m_downWasHeld;
|
||||||
static int g_selectedRowIndex;
|
|
||||||
static double g_rowSelectionTime;
|
|
||||||
|
|
||||||
static bool g_upWasHeld;
|
|
||||||
static bool g_downWasHeld;
|
|
||||||
|
|
||||||
static void ResetSelection()
|
static void ResetSelection()
|
||||||
{
|
{
|
||||||
g_firstVisibleRowIndex = 0;
|
m_firstVisibleRowIndex = 0;
|
||||||
g_selectedRowIndex = 0;
|
m_selectedRowIndex = 0;
|
||||||
g_prevSelectedRowIndex = 0;
|
m_prevSelectedRowIndex = 0;
|
||||||
g_rowSelectionTime = ImGui::GetTime();
|
m_rowSelectionTime = ImGui::GetTime();
|
||||||
g_upWasHeld = false;
|
m_upWasHeld = false;
|
||||||
g_downWasHeld = false;
|
m_downWasHeld = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementMenu::Init()
|
static void DrawContainer(ImVec2 min, ImVec2 max, ImU32 gradientTop, ImU32 gradientBottom, float cornerRadius = 25)
|
||||||
{
|
|
||||||
auto& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
constexpr float FONT_SCALE = 2.0f;
|
|
||||||
|
|
||||||
g_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 24.0f * FONT_SCALE);
|
|
||||||
g_fntNewRodin = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-UB.otf", 20.0f * FONT_SCALE);
|
|
||||||
|
|
||||||
g_achievements = g_xdbf.GetAchievements((EXDBFLanguage)Config::Language.Value);
|
|
||||||
|
|
||||||
for (auto& achievement : g_achievements)
|
|
||||||
{
|
|
||||||
auto texture = LoadTexture((uint8_t*)achievement.pImageBuffer, achievement.ImageBufferSize);
|
|
||||||
g_achievementTextures[achievement.ID] = texture.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DrawContainer(ImVec2 min, ImVec2 max, ImU32 gradientTop, ImU32 gradientBottom, float cornerRadius = 25.0f)
|
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
auto vertices = GetPauseContainerVertices(min, max, cornerRadius);
|
||||||
ImVec2 v1 = { min.x, min.y + cornerRadius };
|
|
||||||
ImVec2 v2 = { min.x + cornerRadius, min.y };
|
|
||||||
ImVec2 v3 = { max.x, min.y };
|
|
||||||
ImVec2 v4 = { max.x, min.y + cornerRadius };
|
|
||||||
ImVec2 v5 = { max.x, max.y - cornerRadius };
|
|
||||||
ImVec2 v6 = { max.x - cornerRadius, max.y };
|
|
||||||
ImVec2 v7 = { min.x, max.y };
|
|
||||||
ImVec2 v8 = { min.x, max.y - cornerRadius };
|
|
||||||
ImVec2 vertices[] = { v1, v2, v3, v4, v5, v6, v7, v8 };
|
|
||||||
|
|
||||||
// TODO: add a drop shadow.
|
// TODO: add a drop shadow.
|
||||||
|
|
||||||
SetGradient(min, max, gradientTop, gradientBottom);
|
SetGradient(min, max, gradientTop, gradientBottom);
|
||||||
drawList->AddConvexPolyFilled(vertices, IM_ARRAYSIZE(vertices), IM_COL32(255, 255, 255, 255));
|
drawList->AddConvexPolyFilled(vertices.data(), vertices.size(), IM_COL32(255, 255, 255, 255));
|
||||||
ResetGradient();
|
ResetGradient();
|
||||||
|
|
||||||
drawList->AddPolyline(vertices, IM_ARRAYSIZE(vertices), IM_COL32(247, 247, 247, 255), true, Scale(2.5f));
|
drawList->AddPolyline(vertices.data(), vertices.size(), IM_COL32(247, 247, 247, 255), true, Scale(2.5f));
|
||||||
|
|
||||||
for (int i = 0; i < IM_ARRAYSIZE(vertices); i++)
|
for (int i = 0; i < vertices.size(); i++)
|
||||||
{
|
{
|
||||||
vertices[i].x -= 0.4f;
|
vertices[i].x -= Scale(0.4f);
|
||||||
vertices[i].y -= 0.2f;
|
vertices[i].y -= Scale(0.2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto colLineTop = IM_COL32(165, 170, 165, 230);
|
auto colLineTop = IM_COL32(165, 170, 165, 230);
|
||||||
auto colLineBottom = IM_COL32(190, 190, 190, 230);
|
auto colLineBottom = IM_COL32(190, 190, 190, 230);
|
||||||
auto lineThickness = Scale(1.0f);
|
auto lineThickness = Scale(1);
|
||||||
|
|
||||||
// Top left corner bottom to top left corner top.
|
// Top left corner bottom to top left corner top.
|
||||||
drawList->AddLine(vertices[0], vertices[1], colLineTop, lineThickness * 0.5f);
|
drawList->AddLine(vertices[0], vertices[1], colLineTop, lineThickness * Scale(0.5f));
|
||||||
|
|
||||||
// Top left corner bottom to bottom left.
|
// Top left corner bottom to bottom left.
|
||||||
drawList->AddRectFilledMultiColor({ vertices[0].x - 0.2f, vertices[0].y }, { vertices[6].x + lineThickness - 0.2f, vertices[6].y }, colLineTop, colLineTop, colLineBottom, colLineBottom);
|
drawList->AddRectFilledMultiColor
|
||||||
|
(
|
||||||
|
{ /* X */ vertices[0].x - Scale(0.2f), /* Y */ vertices[0].y },
|
||||||
|
{ /* X */ vertices[6].x + lineThickness - Scale(0.2f), /* Y */ vertices[6].y },
|
||||||
|
colLineTop,
|
||||||
|
colLineTop,
|
||||||
|
colLineBottom,
|
||||||
|
colLineBottom
|
||||||
|
);
|
||||||
|
|
||||||
// Top left corner top to top right.
|
// Top left corner top to top right.
|
||||||
drawList->AddLine(vertices[1], vertices[2], colLineTop, lineThickness);
|
drawList->AddLine(vertices[1], vertices[2], colLineTop, lineThickness);
|
||||||
|
|
||||||
drawList->PushClipRect({ min.x, min.y + 20.0f }, { max.x, max.y - 5.0f });
|
drawList->PushClipRect({ min.x, min.y + Scale(20) }, { max.x, max.y - Scale(5) });
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawSelectionContainer(ImVec2 min, ImVec2 max)
|
static void DrawSelectionContainer(ImVec2 min, ImVec2 max)
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
auto vertices = GetPauseContainerVertices(min, max, 10);
|
||||||
auto cornerRadius = Scale(10.0f);
|
|
||||||
ImVec2 v1 = { min.x, min.y + cornerRadius };
|
|
||||||
ImVec2 v2 = { min.x + cornerRadius, min.y };
|
|
||||||
ImVec2 v3 = { max.x, min.y };
|
|
||||||
ImVec2 v4 = { max.x, min.y + cornerRadius };
|
|
||||||
ImVec2 v5 = { max.x, max.y - cornerRadius };
|
|
||||||
ImVec2 v6 = { max.x - cornerRadius, max.y };
|
|
||||||
ImVec2 v7 = { min.x, max.y };
|
|
||||||
ImVec2 v8 = { min.x, max.y - cornerRadius };
|
|
||||||
ImVec2 vertices[] = { v1, v2, v3, v4, v5, v6, v7, v8 };
|
|
||||||
|
|
||||||
SetGradient(min, max, IM_COL32(255, 246, 0, 129), IM_COL32(255, 194, 0, 118));
|
SetGradient(min, max, IM_COL32(255, 246, 0, 129), IM_COL32(255, 194, 0, 118));
|
||||||
drawList->AddConvexPolyFilled(vertices, IM_ARRAYSIZE(vertices), IM_COL32(255, 255, 255, 255));
|
drawList->AddConvexPolyFilled(vertices.data(), vertices.size(), IM_COL32(255, 255, 255, 255));
|
||||||
ResetGradient();
|
ResetGradient();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawHeaderContainer(const char* text)
|
static void DrawHeaderContainer(const char* text)
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
auto fontSize = Scale(26);
|
||||||
|
auto textSize = m_fntNewRodin->CalcTextSizeA(fontSize, FLT_MAX, 0, text);
|
||||||
|
auto cornerRadius = 23;
|
||||||
|
auto textMarginX = Scale(16) + (Scale(cornerRadius) / 2);
|
||||||
|
|
||||||
ImVec2 min = { Scale(256.0f), Scale(138.0f) };
|
ImVec2 min = { Scale(256), Scale(138) };
|
||||||
ImVec2 max = { Scale(556.0f), Scale(185.0f) };
|
ImVec2 max = { min.x + textMarginX * 2 + textSize.x, Scale(185) };
|
||||||
|
|
||||||
DrawContainer(min, max, IM_COL32(140, 142, 140, 201), IM_COL32(66, 65, 66, 234), Scale(23.0f));
|
DrawContainer(min, max, IM_COL32(140, 142, 140, 201), IM_COL32(66, 65, 66, 234), cornerRadius);
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
|
|
||||||
auto textSize = g_fntNewRodin->CalcTextSizeA(Scale(26.0f), FLT_MAX, 0.0f, text);
|
|
||||||
|
|
||||||
// TODO: skew this text and apply bevel.
|
// TODO: skew this text and apply bevel.
|
||||||
DrawTextWithOutline<int>(g_fntNewRodin, Scale(26.0f), { min.x + Scale(20.0f), min.y + textSize.y / 2.0f - 3.0f }, IM_COL32(255, 255, 255, 255), text, Scale(3), IM_COL32(0, 0, 0, 255));
|
DrawTextWithOutline<int>
|
||||||
|
(
|
||||||
|
m_fntNewRodin,
|
||||||
|
fontSize,
|
||||||
|
{ /* X */ min.x + textMarginX, /* Y */ min.y + textSize.y / Scale(2) + Scale(2.5f) /* 2.5 = container outline thickness */ },
|
||||||
|
IM_COL32(255, 255, 255, 255),
|
||||||
|
text,
|
||||||
|
3,
|
||||||
|
IM_COL32(0, 0, 0, 255)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievement, bool isUnlocked)
|
static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievement, bool isUnlocked)
|
||||||
|
|
@ -140,51 +119,99 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen
|
||||||
auto clipRectMin = drawList->GetClipRectMin();
|
auto clipRectMin = drawList->GetClipRectMin();
|
||||||
auto clipRectMax = drawList->GetClipRectMax();
|
auto clipRectMax = drawList->GetClipRectMax();
|
||||||
|
|
||||||
auto itemWidth = Scale(708.0f);
|
auto itemWidth = Scale(708);
|
||||||
auto itemHeight = Scale(94.0f);
|
auto itemHeight = Scale(94);
|
||||||
auto itemMarginX = Scale(13.0f);
|
auto itemMarginX = Scale(13);
|
||||||
auto imageMarginX = Scale(25.0f);
|
auto imageMarginX = Scale(25);
|
||||||
auto imageMarginY = Scale(18.0f);
|
auto imageMarginY = Scale(18);
|
||||||
auto imageSize = Scale(60.0f);
|
auto imageSize = Scale(60);
|
||||||
|
|
||||||
ImVec2 min = { itemMarginX + clipRectMin.x, clipRectMin.y + itemHeight * rowIndex + yOffset };
|
ImVec2 min = { itemMarginX + clipRectMin.x, clipRectMin.y + itemHeight * rowIndex + yOffset };
|
||||||
ImVec2 max = { itemMarginX + min.x + itemWidth, min.y + itemHeight };
|
ImVec2 max = { itemMarginX + min.x + itemWidth, min.y + itemHeight };
|
||||||
|
|
||||||
auto icon = g_achievementTextures[achievement.ID];
|
auto icon = g_xdbfTextureCache[achievement.ID];
|
||||||
auto isSelected = rowIndex == g_selectedRowIndex;
|
auto isSelected = rowIndex == m_selectedRowIndex;
|
||||||
|
|
||||||
if (isSelected)
|
if (isSelected)
|
||||||
DrawSelectionContainer(min, max);
|
DrawSelectionContainer(min, max);
|
||||||
|
|
||||||
auto alpha = isUnlocked ? 255 : 127;
|
|
||||||
auto desc = isUnlocked ? achievement.UnlockedDesc.c_str() : achievement.LockedDesc.c_str();
|
auto desc = isUnlocked ? achievement.UnlockedDesc.c_str() : achievement.LockedDesc.c_str();
|
||||||
auto fontSize = Scale(24.0f);
|
auto fontSize = Scale(24);
|
||||||
auto textSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, desc);
|
auto textSize = m_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, desc);
|
||||||
auto textX = min.x + imageMarginX + imageSize + itemMarginX * 2.0f;
|
auto textX = min.x + imageMarginX + imageSize + itemMarginX * 2;
|
||||||
auto textMarqueeX = min.x + imageMarginX + imageSize;
|
auto textMarqueeX = min.x + imageMarginX + imageSize;
|
||||||
auto titleTextY = Scale(20.0f);
|
auto titleTextY = Scale(20);
|
||||||
auto descTextY = Scale(52.0f);
|
auto descTextY = Scale(52);
|
||||||
auto cmnShadowOffset = Scale(2.0f);
|
|
||||||
auto cmnShadowScale = Scale(0.4f);
|
|
||||||
|
|
||||||
// Draw achievement icon.
|
// Draw achievement icon.
|
||||||
// TODO: make image greyscale if locked.
|
// TODO: make icon greyscale if locked?
|
||||||
drawList->AddImage(icon, { min.x + imageMarginX, min.y + imageMarginY }, { min.x + imageMarginX + imageSize, min.y + imageMarginY + imageSize }, { 0, 0 }, { 1, 1 }, IM_COL32(255, 255, 255, alpha));
|
drawList->AddImage
|
||||||
|
(
|
||||||
|
icon,
|
||||||
|
{ /* X */ min.x + imageMarginX, /* Y */ min.y + imageMarginY },
|
||||||
|
{ /* X */ min.x + imageMarginX + imageSize, /* Y */ min.y + imageMarginY + imageSize },
|
||||||
|
{ /* U */ 0, /* V */ 0 },
|
||||||
|
{ /* U */ 1, /* V */ 1 },
|
||||||
|
IM_COL32(255, 255, 255, 255 * (isUnlocked ? 1 : 0.5f))
|
||||||
|
);
|
||||||
|
|
||||||
drawList->PushClipRect(min, max, true);
|
drawList->PushClipRect(min, max, true);
|
||||||
|
|
||||||
|
auto colLockedText = IM_COL32(60, 60, 60, 29);
|
||||||
|
|
||||||
|
auto colTextShadow = isUnlocked
|
||||||
|
? IM_COL32(0, 0, 0, 255)
|
||||||
|
: IM_COL32(60, 60, 60, 28);
|
||||||
|
|
||||||
|
auto shadowOffset = isUnlocked ? 2 : 1;
|
||||||
|
|
||||||
// Draw achievement name.
|
// Draw achievement name.
|
||||||
DrawTextWithShadow(g_fntSeurat, fontSize, { textX, min.y + titleTextY }, IM_COL32(252, 243, 5, alpha), achievement.Name.c_str(), cmnShadowOffset, cmnShadowScale, IM_COL32(0, 0, 0, alpha));
|
DrawTextWithShadow
|
||||||
|
(
|
||||||
|
m_fntSeurat,
|
||||||
|
fontSize,
|
||||||
|
{ textX, min.y + titleTextY },
|
||||||
|
isUnlocked ? IM_COL32(252, 243, 5, 255) : colLockedText,
|
||||||
|
achievement.Name.c_str(),
|
||||||
|
shadowOffset,
|
||||||
|
0.4f,
|
||||||
|
colTextShadow
|
||||||
|
);
|
||||||
|
|
||||||
if (isSelected && textX + textSize.x >= max.x)
|
if (isSelected && textX + textSize.x >= max.x)
|
||||||
{
|
{
|
||||||
// Draw achievement description with marquee.
|
// Draw achievement description with marquee.
|
||||||
DrawTextWithMarqueeShadow(g_fntSeurat, fontSize, { textX, min.y + descTextY }, { textMarqueeX, min.y }, max, IM_COL32(255, 255, 255, alpha), desc, g_rowSelectionTime, 0.9, 250.0, cmnShadowOffset, cmnShadowScale);
|
DrawTextWithMarqueeShadow
|
||||||
|
(
|
||||||
|
m_fntSeurat,
|
||||||
|
fontSize,
|
||||||
|
{ textX, min.y + descTextY },
|
||||||
|
{ textMarqueeX, min.y },
|
||||||
|
max,
|
||||||
|
isUnlocked ? IM_COL32(255, 255, 255, 255) : colLockedText,
|
||||||
|
desc,
|
||||||
|
m_rowSelectionTime,
|
||||||
|
0.9,
|
||||||
|
250.0,
|
||||||
|
shadowOffset,
|
||||||
|
0.4f,
|
||||||
|
colTextShadow
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Draw achievement description.
|
// Draw achievement description.
|
||||||
DrawTextWithShadow(g_fntSeurat, fontSize, { textX, min.y + descTextY }, IM_COL32(255, 255, 255, alpha), desc, cmnShadowOffset, cmnShadowScale, IM_COL32(0, 0, 0, alpha));
|
DrawTextWithShadow
|
||||||
|
(
|
||||||
|
m_fntSeurat,
|
||||||
|
fontSize,
|
||||||
|
{ textX, min.y + descTextY },
|
||||||
|
isUnlocked ? IM_COL32(255, 255, 255, 255) : colLockedText,
|
||||||
|
desc,
|
||||||
|
shadowOffset,
|
||||||
|
0.4f,
|
||||||
|
colTextShadow
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
|
|
@ -194,39 +221,39 @@ static void DrawContentContainer()
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
ImVec2 min = { Scale(256.0f), Scale(192.0f) };
|
ImVec2 min = { Scale(256), Scale(192) };
|
||||||
ImVec2 max = { Scale(1026.0f), Scale(601.0f) };
|
ImVec2 max = { Scale(1026), Scale(601) };
|
||||||
|
|
||||||
DrawContainer(min, max, IM_COL32(197, 194, 197, 200), IM_COL32(115, 113, 115, 236), Scale(25.0f));
|
DrawContainer(min, max, IM_COL32(197, 194, 197, 200), IM_COL32(115, 113, 115, 236));
|
||||||
|
|
||||||
auto clipRectMin = drawList->GetClipRectMin();
|
auto clipRectMin = drawList->GetClipRectMin();
|
||||||
auto clipRectMax = drawList->GetClipRectMax();
|
auto clipRectMax = drawList->GetClipRectMax();
|
||||||
|
|
||||||
auto itemHeight = Scale(94.0f);
|
auto itemHeight = Scale(94);
|
||||||
auto yOffset = -g_firstVisibleRowIndex * itemHeight + Scale(2.0f);
|
auto yOffset = -m_firstVisibleRowIndex * itemHeight + Scale(2);
|
||||||
auto rowCount = 0;
|
auto rowCount = 0;
|
||||||
|
|
||||||
// Draw separators.
|
// Draw separators.
|
||||||
for (int i = 1; i <= 3; i++)
|
for (int i = 1; i <= 3; i++)
|
||||||
{
|
{
|
||||||
auto lineMarginLeft = Scale(31.0f);
|
auto lineMarginLeft = Scale(31);
|
||||||
auto lineMarginRight = Scale(46.0f);
|
auto lineMarginRight = Scale(46);
|
||||||
auto lineMarginY = Scale(2.0f);
|
auto lineMarginY = Scale(2);
|
||||||
|
|
||||||
ImVec2 lineMin = { clipRectMin.x + lineMarginLeft, clipRectMin.y + itemHeight * i + lineMarginY };
|
ImVec2 lineMin = { clipRectMin.x + lineMarginLeft, clipRectMin.y + itemHeight * i + lineMarginY };
|
||||||
ImVec2 lineMax = { clipRectMax.x - lineMarginRight, clipRectMin.y + itemHeight * i + lineMarginY };
|
ImVec2 lineMax = { clipRectMax.x - lineMarginRight, clipRectMin.y + itemHeight * i + lineMarginY };
|
||||||
|
|
||||||
drawList->AddLine(lineMin, lineMax, IM_COL32(163, 163, 163, 255));
|
drawList->AddLine(lineMin, lineMax, IM_COL32(163, 163, 163, 255));
|
||||||
drawList->AddLine({ lineMin.x, lineMin.y + Scale(1.0f) }, { lineMax.x, lineMax.y + Scale(1.0f) }, IM_COL32(143, 148, 143, 255));
|
drawList->AddLine({ lineMin.x, lineMin.y + Scale(1) }, { lineMax.x, lineMax.y + Scale(1) }, IM_COL32(143, 148, 143, 255));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto achievement : g_achievements)
|
for (auto achievement : m_achievements)
|
||||||
{
|
{
|
||||||
if (AchievementData::IsUnlocked(achievement.ID))
|
if (AchievementData::IsUnlocked(achievement.ID))
|
||||||
DrawAchievement(rowCount++, yOffset, achievement, true);
|
DrawAchievement(rowCount++, yOffset, achievement, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto achievement : g_achievements)
|
for (auto achievement : m_achievements)
|
||||||
{
|
{
|
||||||
if (!AchievementData::IsUnlocked(achievement.ID))
|
if (!AchievementData::IsUnlocked(achievement.ID))
|
||||||
DrawAchievement(rowCount++, yOffset, achievement, false);
|
DrawAchievement(rowCount++, yOffset, achievement, false);
|
||||||
|
|
@ -240,52 +267,52 @@ static void DrawContentContainer()
|
||||||
bool downIsHeld = inputState->GetPadState().IsDown(SWA::eKeyState_DpadDown) ||
|
bool downIsHeld = inputState->GetPadState().IsDown(SWA::eKeyState_DpadDown) ||
|
||||||
inputState->GetPadState().LeftStickVertical < -0.5f;
|
inputState->GetPadState().LeftStickVertical < -0.5f;
|
||||||
|
|
||||||
bool scrollUp = !g_upWasHeld && upIsHeld;
|
bool scrollUp = !m_upWasHeld && upIsHeld;
|
||||||
bool scrollDown = !g_downWasHeld && downIsHeld;
|
bool scrollDown = !m_downWasHeld && downIsHeld;
|
||||||
|
|
||||||
int prevSelectedRowIndex = g_selectedRowIndex;
|
int prevSelectedRowIndex = m_selectedRowIndex;
|
||||||
|
|
||||||
if (scrollUp)
|
if (scrollUp)
|
||||||
{
|
{
|
||||||
--g_selectedRowIndex;
|
--m_selectedRowIndex;
|
||||||
if (g_selectedRowIndex < 0)
|
if (m_selectedRowIndex < 0)
|
||||||
g_selectedRowIndex = rowCount - 1;
|
m_selectedRowIndex = rowCount - 1;
|
||||||
}
|
}
|
||||||
else if (scrollDown)
|
else if (scrollDown)
|
||||||
{
|
{
|
||||||
++g_selectedRowIndex;
|
++m_selectedRowIndex;
|
||||||
if (g_selectedRowIndex >= rowCount)
|
if (m_selectedRowIndex >= rowCount)
|
||||||
g_selectedRowIndex = 0;
|
m_selectedRowIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrollUp || scrollDown)
|
if (scrollUp || scrollDown)
|
||||||
{
|
{
|
||||||
g_rowSelectionTime = ImGui::GetTime();
|
m_rowSelectionTime = ImGui::GetTime();
|
||||||
g_prevSelectedRowIndex = prevSelectedRowIndex;
|
m_prevSelectedRowIndex = prevSelectedRowIndex;
|
||||||
Game_PlaySound("sys_actstg_pausecursor");
|
Game_PlaySound("sys_actstg_pausecursor");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_upWasHeld = upIsHeld;
|
m_upWasHeld = upIsHeld;
|
||||||
g_downWasHeld = downIsHeld;
|
m_downWasHeld = downIsHeld;
|
||||||
|
|
||||||
int visibleRowCount = int(floor((clipRectMax.y - clipRectMin.y) / itemHeight));
|
int visibleRowCount = int(floor((clipRectMax.y - clipRectMin.y) / itemHeight));
|
||||||
|
|
||||||
bool disableMoveAnimation = false;
|
bool disableMoveAnimation = false;
|
||||||
|
|
||||||
if (g_firstVisibleRowIndex > g_selectedRowIndex)
|
if (m_firstVisibleRowIndex > m_selectedRowIndex)
|
||||||
{
|
{
|
||||||
g_firstVisibleRowIndex = g_selectedRowIndex;
|
m_firstVisibleRowIndex = m_selectedRowIndex;
|
||||||
disableMoveAnimation = true;
|
disableMoveAnimation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_firstVisibleRowIndex + visibleRowCount - 1 < g_selectedRowIndex)
|
if (m_firstVisibleRowIndex + visibleRowCount - 1 < m_selectedRowIndex)
|
||||||
{
|
{
|
||||||
g_firstVisibleRowIndex = std::max(0, g_selectedRowIndex - visibleRowCount + 1);
|
m_firstVisibleRowIndex = std::max(0, m_selectedRowIndex - visibleRowCount + 1);
|
||||||
disableMoveAnimation = true;
|
disableMoveAnimation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disableMoveAnimation)
|
if (disableMoveAnimation)
|
||||||
g_prevSelectedRowIndex = g_selectedRowIndex;
|
m_prevSelectedRowIndex = m_selectedRowIndex;
|
||||||
|
|
||||||
// Pop clip rect from DrawContentContainer
|
// Pop clip rect from DrawContentContainer
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
|
|
@ -296,7 +323,7 @@ static void DrawContentContainer()
|
||||||
float cornerRadius = Scale(25.0f);
|
float cornerRadius = Scale(25.0f);
|
||||||
float totalHeight = (clipRectMax.y - clipRectMin.y - cornerRadius) - Scale(3.0f);
|
float totalHeight = (clipRectMax.y - clipRectMin.y - cornerRadius) - Scale(3.0f);
|
||||||
float heightRatio = float(visibleRowCount) / float(rowCount);
|
float heightRatio = float(visibleRowCount) / float(rowCount);
|
||||||
float offsetRatio = float(g_firstVisibleRowIndex) / float(rowCount);
|
float offsetRatio = float(m_firstVisibleRowIndex) / float(rowCount);
|
||||||
float offsetX = clipRectMax.x - Scale(31.0f);
|
float offsetX = clipRectMax.x - Scale(31.0f);
|
||||||
float offsetY = offsetRatio * totalHeight + clipRectMin.y + Scale(4.0f);
|
float offsetY = offsetRatio * totalHeight + clipRectMin.y + Scale(4.0f);
|
||||||
float lineThickness = Scale(1.0f);
|
float lineThickness = Scale(1.0f);
|
||||||
|
|
@ -306,8 +333,8 @@ static void DrawContentContainer()
|
||||||
// Outline
|
// Outline
|
||||||
drawList->AddRect
|
drawList->AddRect
|
||||||
(
|
(
|
||||||
{ offsetX - lineThickness, clipRectMin.y - lineThickness },
|
{ /* X */ offsetX - lineThickness, /* Y */ clipRectMin.y - lineThickness },
|
||||||
{ clipRectMax.x - outerMarginX + lineThickness, max.y - cornerRadius + lineThickness },
|
{ /* X */ clipRectMax.x - outerMarginX + lineThickness, /* Y */ max.y - cornerRadius + lineThickness },
|
||||||
IM_COL32(255, 255, 255, 155),
|
IM_COL32(255, 255, 255, 155),
|
||||||
Scale(0.5f)
|
Scale(0.5f)
|
||||||
);
|
);
|
||||||
|
|
@ -315,8 +342,8 @@ static void DrawContentContainer()
|
||||||
// Background
|
// Background
|
||||||
drawList->AddRectFilledMultiColor
|
drawList->AddRectFilledMultiColor
|
||||||
(
|
(
|
||||||
{ offsetX, clipRectMin.y },
|
{ /* X */ offsetX, /* Y */ clipRectMin.y },
|
||||||
{ clipRectMax.x - outerMarginX, max.y - cornerRadius },
|
{ /* X */ clipRectMax.x - outerMarginX, /* Y */ max.y - cornerRadius },
|
||||||
IM_COL32(82, 85, 82, 186),
|
IM_COL32(82, 85, 82, 186),
|
||||||
IM_COL32(82, 85, 82, 186),
|
IM_COL32(82, 85, 82, 186),
|
||||||
IM_COL32(74, 73, 74, 185),
|
IM_COL32(74, 73, 74, 185),
|
||||||
|
|
@ -326,8 +353,8 @@ static void DrawContentContainer()
|
||||||
// Scroll Bar Outline
|
// Scroll Bar Outline
|
||||||
drawList->AddRectFilledMultiColor
|
drawList->AddRectFilledMultiColor
|
||||||
(
|
(
|
||||||
{ offsetX + innerMarginX, offsetY - lineThickness },
|
{ /* X */ offsetX + innerMarginX, /* Y */ offsetY - lineThickness },
|
||||||
{ clipRectMax.x - outerMarginX - innerMarginX, offsetY + lineThickness + totalHeight * heightRatio},
|
{ /* X */ clipRectMax.x - outerMarginX - innerMarginX, /* Y */ offsetY + lineThickness + totalHeight * heightRatio },
|
||||||
IM_COL32(185, 185, 185, 255),
|
IM_COL32(185, 185, 185, 255),
|
||||||
IM_COL32(185, 185, 185, 255),
|
IM_COL32(185, 185, 185, 255),
|
||||||
IM_COL32(172, 172, 172, 255),
|
IM_COL32(172, 172, 172, 255),
|
||||||
|
|
@ -337,13 +364,25 @@ static void DrawContentContainer()
|
||||||
// Scroll Bar
|
// Scroll Bar
|
||||||
drawList->AddRectFilled
|
drawList->AddRectFilled
|
||||||
(
|
(
|
||||||
{ offsetX + innerMarginX + lineThickness, offsetY },
|
{ /* X */ offsetX + innerMarginX + lineThickness, /* Y */ offsetY },
|
||||||
{ clipRectMax.x - outerMarginX - innerMarginX - lineThickness, offsetY + totalHeight * heightRatio },
|
{ /* X */ clipRectMax.x - outerMarginX - innerMarginX - lineThickness, /* Y */ offsetY + totalHeight * heightRatio },
|
||||||
IM_COL32(255, 255, 255, 255)
|
IM_COL32(255, 255, 255, 255)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AchievementMenu::Init()
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
constexpr float FONT_SCALE = 2.0f;
|
||||||
|
|
||||||
|
m_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 24.0f * FONT_SCALE);
|
||||||
|
m_fntNewRodin = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-UB.otf", 20.0f * FONT_SCALE);
|
||||||
|
|
||||||
|
m_achievements = g_xdbfWrapper.GetAchievements((EXDBFLanguage)Config::Language.Value);
|
||||||
|
}
|
||||||
|
|
||||||
void AchievementMenu::Draw()
|
void AchievementMenu::Draw()
|
||||||
{
|
{
|
||||||
if (!s_isVisible)
|
if (!s_isVisible)
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "imgui_view.h"
|
class AchievementMenu
|
||||||
|
|
||||||
class AchievementMenu : ImGuiView
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline static bool s_isVisible = false;
|
inline static bool s_isVisible = false;
|
||||||
|
|
||||||
void Init() override;
|
static void Init();
|
||||||
void Draw() override;
|
static void Draw();
|
||||||
static void Open();
|
static void Open();
|
||||||
static void Close();
|
static void Close();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,42 @@
|
||||||
#include "achievement_overlay.h"
|
#include "achievement_overlay.h"
|
||||||
#include "imgui_utils.h"
|
#include "imgui_utils.h"
|
||||||
|
|
||||||
#include <user/config.h>
|
|
||||||
#include <user/achievement_data.h>
|
|
||||||
#include <gpu/video.h>
|
#include <gpu/video.h>
|
||||||
#include <kernel/memory.h>
|
#include <kernel/memory.h>
|
||||||
|
#include <kernel/xdbf.h>
|
||||||
#include <locale/locale.h>
|
#include <locale/locale.h>
|
||||||
|
#include <user/config.h>
|
||||||
|
#include <user/achievement_data.h>
|
||||||
#include <app.h>
|
#include <app.h>
|
||||||
#include <exports.h>
|
#include <exports.h>
|
||||||
|
|
||||||
AchievementOverlay m_achievementOverlay;
|
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_START = 0;
|
||||||
|
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_MOTION_START = 0.0;
|
constexpr double OVERLAY_DURATION = 5;
|
||||||
constexpr double OVERLAY_CONTAINER_MOTION_END = 8.0;
|
|
||||||
constexpr double OVERLAY_CONTAINER_FADE_IN_START = 5.0;
|
|
||||||
constexpr double OVERLAY_CONTAINER_FADE_OUT_START = 4.0;
|
|
||||||
constexpr double OVERLAY_ELEMENTS_FADE_START = 10.0;
|
|
||||||
constexpr double OVERLAY_ELEMENTS_FADE_END = 12.0;
|
|
||||||
constexpr double OVERLAY_DURATION = 5.0;
|
|
||||||
|
|
||||||
static bool g_isClosing = false;
|
static bool m_isClosing = false;
|
||||||
|
|
||||||
static double g_appearTime = 0.0;
|
static double m_appearTime = 0;
|
||||||
|
|
||||||
static Achievement g_achievement;
|
static Achievement m_achievement;
|
||||||
static std::unique_ptr<GuestTexture> g_upAchievementIcon;
|
|
||||||
|
|
||||||
static ImFont* g_fntSeurat;
|
static ImFont* m_fntSeurat;
|
||||||
|
|
||||||
void AchievementOverlay::Init()
|
static bool DrawContainer(ImVec2 min, ImVec2 max, float cornerRadius = 25)
|
||||||
{
|
|
||||||
auto& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
constexpr float FONT_SCALE = 2.0f;
|
|
||||||
|
|
||||||
g_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 26.0f * FONT_SCALE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static double ComputeMotion(double frameOffset, double frames)
|
|
||||||
{
|
|
||||||
double t = std::clamp((ImGui::GetTime() - g_appearTime - frameOffset / 60.0) / frames * 60.0, 0.0, 1.0);
|
|
||||||
return sqrt(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DrawContainer(ImVec2 min, ImVec2 max, float cornerRadius = 25.0f)
|
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
auto containerMotion = ComputeMotion(OVERLAY_CONTAINER_MOTION_START, OVERLAY_CONTAINER_MOTION_END);
|
// Expand/retract animation.
|
||||||
auto centreX = (min.x + max.x) / 2.0f;
|
auto containerMotion = ComputeMotion(m_appearTime, OVERLAY_CONTAINER_COMMON_MOTION_START, OVERLAY_CONTAINER_COMMON_MOTION_END);
|
||||||
auto centreY = (min.y + max.y) / 2.0f;
|
|
||||||
|
|
||||||
if (g_isClosing)
|
auto centreX = (min.x + max.x) / 2;
|
||||||
|
auto centreY = (min.y + max.y) / 2;
|
||||||
|
|
||||||
|
if (m_isClosing)
|
||||||
{
|
{
|
||||||
min.x = CubicEase(min.x, centreX, containerMotion);
|
min.x = CubicEase(min.x, centreX, containerMotion);
|
||||||
max.x = CubicEase(max.x, centreX, containerMotion);
|
max.x = CubicEase(max.x, centreX, containerMotion);
|
||||||
|
|
@ -66,40 +51,47 @@ static void DrawContainer(ImVec2 min, ImVec2 max, float cornerRadius = 25.0f)
|
||||||
max.y = CubicEase(centreY, max.y, containerMotion);
|
max.y = CubicEase(centreY, max.y, containerMotion);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImVec2 v1 = { min.x, min.y + cornerRadius };
|
auto vertices = GetPauseContainerVertices(min, max, cornerRadius);
|
||||||
ImVec2 v2 = { min.x + cornerRadius, min.y };
|
|
||||||
ImVec2 v3 = { max.x, min.y };
|
|
||||||
ImVec2 v4 = { max.x, min.y + cornerRadius };
|
|
||||||
ImVec2 v5 = { max.x, max.y - cornerRadius };
|
|
||||||
ImVec2 v6 = { max.x - cornerRadius, max.y };
|
|
||||||
ImVec2 v7 = { min.x, max.y };
|
|
||||||
ImVec2 v8 = { min.x, max.y - cornerRadius };
|
|
||||||
ImVec2 vertices[] = { v1, v2, v3, v4, v5, v6, v7, v8 };
|
|
||||||
|
|
||||||
auto colourMotion = ComputeMotion(g_isClosing ? OVERLAY_CONTAINER_MOTION_START : OVERLAY_CONTAINER_FADE_IN_START,
|
// Transparency fade animation.
|
||||||
g_isClosing ? OVERLAY_CONTAINER_FADE_OUT_START : OVERLAY_CONTAINER_MOTION_END);
|
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 colShadow = IM_COL32(0, 0, 0, (int)CubicEase(g_isClosing ? 156 : 0, g_isClosing ? 0 : 156, colourMotion));
|
auto alpha = m_isClosing
|
||||||
auto colGradientTop = IM_COL32(197, 194, 197, (int)CubicEase(g_isClosing ? 200 : 0, g_isClosing ? 0 : 200, colourMotion));
|
? CubicEase(1, 0, colourMotion)
|
||||||
auto colGradientBottom = IM_COL32(115, 113, 115, (int)CubicEase(g_isClosing ? 236 : 0, g_isClosing ? 0 : 236, colourMotion));
|
: CubicEase(0, 1, colourMotion);
|
||||||
|
|
||||||
|
auto colShadow = IM_COL32(0, 0, 0, 156 * alpha);
|
||||||
|
auto colGradientTop = IM_COL32(197, 194, 197, 200 * alpha);
|
||||||
|
auto colGradientBottom = IM_COL32(115, 113, 115, 236 * alpha);
|
||||||
|
|
||||||
// TODO: add a drop shadow.
|
// TODO: add a drop shadow.
|
||||||
|
|
||||||
|
// Draw vertices with gradient.
|
||||||
SetGradient(min, max, colGradientTop, colGradientBottom);
|
SetGradient(min, max, colGradientTop, colGradientBottom);
|
||||||
drawList->AddConvexPolyFilled(vertices, IM_ARRAYSIZE(vertices), IM_COL32(255, 255, 255, 255));
|
drawList->AddConvexPolyFilled(vertices.data(), vertices.size(), IM_COL32(255, 255, 255, 255 * alpha));
|
||||||
ResetGradient();
|
ResetGradient();
|
||||||
|
|
||||||
drawList->AddPolyline(vertices, IM_ARRAYSIZE(vertices), IM_COL32(247, 247, 247, (int)CubicEase(g_isClosing ? 255 : 0, g_isClosing ? 0 : 255, colourMotion)), true, Scale(2.5f));
|
// Draw outline.
|
||||||
|
drawList->AddPolyline
|
||||||
|
(
|
||||||
|
vertices.data(),
|
||||||
|
vertices.size(),
|
||||||
|
IM_COL32(247, 247, 247, 255 * alpha),
|
||||||
|
true,
|
||||||
|
Scale(2.5f)
|
||||||
|
);
|
||||||
|
|
||||||
for (int i = 0; i < IM_ARRAYSIZE(vertices); i++)
|
// Offset vertices to draw 3D effect lines.
|
||||||
|
for (int i = 0; i < vertices.size(); i++)
|
||||||
{
|
{
|
||||||
vertices[i].x -= 0.4f;
|
vertices[i].x -= Scale(0.4f);
|
||||||
vertices[i].y -= 0.2f;
|
vertices[i].y -= Scale(0.2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lineAlpha = (int)CubicEase(g_isClosing ? 230 : 0, g_isClosing ? 0 : 230, colourMotion);
|
auto colLineTop = IM_COL32(165, 170, 165, 230 * alpha);
|
||||||
auto colLineTop = IM_COL32(165, 170, 165, lineAlpha);
|
auto colLineBottom = IM_COL32(190, 190, 190, 230 * alpha);
|
||||||
auto colLineBottom = IM_COL32(190, 190, 190, lineAlpha);
|
|
||||||
auto lineThickness = Scale(1.0f);
|
auto lineThickness = Scale(1.0f);
|
||||||
|
|
||||||
// Top left corner bottom to top left corner top.
|
// Top left corner bottom to top left corner top.
|
||||||
|
|
@ -112,6 +104,17 @@ static void DrawContainer(ImVec2 min, ImVec2 max, float cornerRadius = 25.0f)
|
||||||
drawList->AddLine(vertices[1], vertices[2], colLineTop, lineThickness);
|
drawList->AddLine(vertices[1], vertices[2], colLineTop, lineThickness);
|
||||||
|
|
||||||
drawList->PushClipRect(min, max);
|
drawList->PushClipRect(min, max);
|
||||||
|
|
||||||
|
return containerMotion >= 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AchievementOverlay::Init()
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
constexpr float FONT_SCALE = 2.0f;
|
||||||
|
|
||||||
|
m_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 24.0f * FONT_SCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementOverlay::Draw()
|
void AchievementOverlay::Draw()
|
||||||
|
|
@ -119,69 +122,97 @@ void AchievementOverlay::Draw()
|
||||||
if (!s_isVisible)
|
if (!s_isVisible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ImGui::GetTime() - g_appearTime >= OVERLAY_DURATION)
|
if (ImGui::GetTime() - m_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 = g_achievement.Name.c_str();
|
auto strAchievementName = m_achievement.Name.c_str();
|
||||||
|
|
||||||
auto fontSize = 30.0f;
|
// Calculate text sizes.
|
||||||
auto headerTextSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, strAchievementUnlocked);
|
auto fontSize = Scale(24);
|
||||||
auto bodyTextSize = g_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, strAchievementName);
|
auto headerSize = m_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementUnlocked);
|
||||||
auto longestTextSize = std::max(headerTextSize.x, bodyTextSize.x);
|
auto bodySize = m_fntSeurat->CalcTextSizeA(fontSize, FLT_MAX, 0, strAchievementName);
|
||||||
|
auto maxSize = std::max(headerSize.x, bodySize.x);
|
||||||
|
|
||||||
constexpr auto imageX = 25.0f;
|
// Calculate image margins.
|
||||||
constexpr auto imageY = 20.0f;
|
auto imageMarginX = Scale(20);
|
||||||
constexpr auto imageSize = 90.0f;
|
auto imageMarginY = Scale(20);
|
||||||
constexpr auto textX = 140.0f;
|
auto imageSize = Scale(60);
|
||||||
|
|
||||||
auto width = textX + longestTextSize + 30.0f;
|
// Calculate text margins.
|
||||||
|
auto textMarginX = imageMarginX * 2 + imageSize;
|
||||||
|
auto textMarginY = imageMarginY + Scale(2);
|
||||||
|
|
||||||
ImVec2 min = { (res.x / 2.0f) - (width / 2.0f), 50.0f };
|
auto containerWidth = imageMarginX + textMarginX + maxSize;
|
||||||
ImVec2 max = { min.x + width, min.y + 125.0f };
|
|
||||||
|
|
||||||
DrawContainer(min, max);
|
ImVec2 min = { (res.x / 2) - (containerWidth / 2), Scale(50) };
|
||||||
|
ImVec2 max = { min.x + containerWidth, min.y + Scale(100) };
|
||||||
|
|
||||||
auto colourMotion = ComputeMotion(g_isClosing ? OVERLAY_CONTAINER_MOTION_START : OVERLAY_ELEMENTS_FADE_START,
|
if (DrawContainer(min, max))
|
||||||
g_isClosing ? OVERLAY_CONTAINER_FADE_OUT_START : OVERLAY_ELEMENTS_FADE_END);
|
{
|
||||||
|
// Draw achievement icon.
|
||||||
|
drawList->AddImage
|
||||||
|
(
|
||||||
|
g_xdbfTextureCache[m_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
|
||||||
|
{ 1, 1 }, // uv_max
|
||||||
|
IM_COL32(255, 255, 255, 255) // col
|
||||||
|
);
|
||||||
|
|
||||||
auto alpha = (int)CubicEase(g_isClosing ? 255 : 0, g_isClosing ? 0 : 255, colourMotion);
|
// Draw header text.
|
||||||
|
DrawTextWithShadow
|
||||||
|
(
|
||||||
|
m_fntSeurat, // font
|
||||||
|
fontSize, // fontSize
|
||||||
|
{ /* X */ min.x + textMarginX + (maxSize - headerSize.x) / 2, /* Y */ min.y + textMarginY }, // pos
|
||||||
|
IM_COL32(252, 243, 5, 255), // colour
|
||||||
|
strAchievementUnlocked, // text
|
||||||
|
2, // offset
|
||||||
|
0.4f, // radius
|
||||||
|
IM_COL32(0, 0, 0, 255) // shadowColour
|
||||||
|
);
|
||||||
|
|
||||||
drawList->AddImage(g_upAchievementIcon.get(), { min.x + imageX, min.y + imageY }, { min.x + imageX + imageSize, min.y + imageY + imageSize }, { 0, 0 }, { 1, 1 }, IM_COL32(255, 255, 255, alpha));
|
// Draw achievement name.
|
||||||
|
DrawTextWithShadow
|
||||||
|
(
|
||||||
|
m_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
|
||||||
|
strAchievementName, // text
|
||||||
|
2, // offset
|
||||||
|
0.4f, // radius
|
||||||
|
IM_COL32(0, 0, 0, 255) // shadowColour
|
||||||
|
);
|
||||||
|
|
||||||
auto cmnShadowOffset = Scale(2.0f);
|
// Pop clip rect from DrawContainer.
|
||||||
auto cmnShadowScale = Scale(0.4f);
|
|
||||||
|
|
||||||
DrawTextWithShadow(g_fntSeurat, fontSize, { min.x + textX + (longestTextSize - headerTextSize.x) / 2.0f, min.y + 30.0f}, IM_COL32(252, 243, 5, alpha), strAchievementUnlocked, cmnShadowOffset, cmnShadowScale, IM_COL32(0, 0, 0, alpha));
|
|
||||||
DrawTextWithShadow(g_fntSeurat, fontSize, { min.x + textX + (longestTextSize - bodyTextSize.x) / 2.0f, min.y + 68.0f}, IM_COL32(255, 255, 255, alpha), strAchievementName, cmnShadowOffset, cmnShadowScale, IM_COL32(0, 0, 0, alpha));
|
|
||||||
|
|
||||||
// Pop clip rect from DrawContainer
|
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AchievementOverlay::Open(int id)
|
void AchievementOverlay::Open(int id)
|
||||||
{
|
{
|
||||||
s_isVisible = true;
|
s_isVisible = true;
|
||||||
g_isClosing = false;
|
m_isClosing = false;
|
||||||
g_appearTime = ImGui::GetTime();
|
m_appearTime = ImGui::GetTime();
|
||||||
|
m_achievement = g_xdbfWrapper.GetAchievement((EXDBFLanguage)Config::Language.Value, id);
|
||||||
g_achievement = g_xdbf.GetAchievement((EXDBFLanguage)Config::Language.Value, id);
|
|
||||||
g_upAchievementIcon = LoadTexture((uint8_t*)g_achievement.pImageBuffer, g_achievement.ImageBufferSize);
|
|
||||||
|
|
||||||
Game_PlaySound("obj_navi_appear");
|
Game_PlaySound("obj_navi_appear");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementOverlay::Close()
|
void AchievementOverlay::Close()
|
||||||
{
|
{
|
||||||
if (!g_isClosing)
|
if (!m_isClosing)
|
||||||
{
|
{
|
||||||
g_appearTime = ImGui::GetTime();
|
m_appearTime = ImGui::GetTime();
|
||||||
g_isClosing = true;
|
m_isClosing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::GetTime() - g_appearTime >= OVERLAY_ELEMENTS_FADE_END)
|
if (ImGui::GetTime() - m_appearTime >= OVERLAY_CONTAINER_COMMON_MOTION_END)
|
||||||
s_isVisible = false;
|
s_isVisible = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "imgui_view.h"
|
class AchievementOverlay
|
||||||
|
|
||||||
class AchievementOverlay : ImGuiView
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline static bool s_isVisible = false;
|
inline static bool s_isVisible = false;
|
||||||
|
|
||||||
void Init() override;
|
static void Init();
|
||||||
void Draw() override;
|
static void Draw();
|
||||||
static void Open(int id);
|
static void Open(int id);
|
||||||
static void Close();
|
static void Close();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <gpu/imgui_common.h>
|
#include <gpu/imgui_common.h>
|
||||||
|
#include <app.h>
|
||||||
|
|
||||||
static std::vector<std::unique_ptr<ImGuiCallbackData>> g_callbackData;
|
static std::vector<std::unique_ptr<ImGuiCallbackData>> g_callbackData;
|
||||||
static uint32_t g_callbackDataIndex = 0;
|
static uint32_t g_callbackDataIndex = 0;
|
||||||
|
|
@ -66,11 +67,33 @@ static float ScaleY(float y)
|
||||||
return y * io.DisplaySize.y / 720.0f;
|
return y * io.DisplaySize.y / 720.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double ComputeMotion(double duration, double offset, double total)
|
||||||
|
{
|
||||||
|
return sqrt(std::clamp((ImGui::GetTime() - duration - offset / 60.0) / total * 60.0, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<ImVec2> GetPauseContainerVertices(ImVec2 min, ImVec2 max, float cornerRadius = 25)
|
||||||
|
{
|
||||||
|
cornerRadius = Scale(cornerRadius);
|
||||||
|
|
||||||
|
return
|
||||||
|
{
|
||||||
|
{ min.x, min.y + cornerRadius },
|
||||||
|
{ min.x + cornerRadius, min.y },
|
||||||
|
{ max.x, min.y },
|
||||||
|
{ max.x, min.y + cornerRadius },
|
||||||
|
{ max.x, max.y - cornerRadius },
|
||||||
|
{ max.x - cornerRadius, max.y },
|
||||||
|
{ min.x, max.y },
|
||||||
|
{ min.x, max.y - cornerRadius }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 color, const char* text, double time, double delay, double speed)
|
static void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 color, const char* text, double time, double delay, double speed)
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
auto rectWidth = max.x - min.x;
|
auto rectWidth = max.x - min.x;
|
||||||
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, text);
|
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, text);
|
||||||
auto textX = pos.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth);
|
auto textX = pos.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth);
|
||||||
|
|
||||||
drawList->PushClipRect(min, max, true);
|
drawList->PushClipRect(min, max, true);
|
||||||
|
|
@ -89,6 +112,8 @@ static void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
|
outlineSize = Scale(outlineSize);
|
||||||
|
|
||||||
if constexpr (std::is_same_v<float, T> || std::is_same_v<double, T>)
|
if constexpr (std::is_same_v<float, T> || std::is_same_v<double, T>)
|
||||||
{
|
{
|
||||||
// TODO: This is still very inefficient!
|
// TODO: This is still very inefficient!
|
||||||
|
|
@ -120,7 +145,11 @@ static void DrawTextWithShadow(const ImFont* font, float fontSize, const ImVec2&
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
|
offset = Scale(offset);
|
||||||
|
radius = Scale(radius);
|
||||||
|
|
||||||
DrawTextWithOutline<float>(font, fontSize, { pos.x + offset, pos.y + offset }, shadowColour, text, radius, shadowColour);
|
DrawTextWithOutline<float>(font, fontSize, { pos.x + offset, pos.y + offset }, shadowColour, text, radius, shadowColour);
|
||||||
|
|
||||||
drawList->AddText(font, fontSize, pos, colour, text);
|
drawList->AddText(font, fontSize, pos, colour, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,7 +157,7 @@ static void DrawTextWithMarqueeShadow(const ImFont* font, float fontSize, const
|
||||||
{
|
{
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
auto rectWidth = max.x - min.x;
|
auto rectWidth = max.x - min.x;
|
||||||
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, text);
|
auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, text);
|
||||||
auto textX = pos.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth);
|
auto textX = pos.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth);
|
||||||
|
|
||||||
drawList->PushClipRect(min, max, true);
|
drawList->PushClipRect(min, max, true);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
#include "imgui_view.h"
|
|
||||||
|
|
||||||
std::vector<IImGuiView*>& GetImGuiViews()
|
|
||||||
{
|
|
||||||
static std::vector<IImGuiView*> g_imGuiViews;
|
|
||||||
return g_imGuiViews;
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class IImGuiView
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~IImGuiView() = default;
|
|
||||||
virtual void Init() = 0;
|
|
||||||
virtual void Draw() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<IImGuiView*>& GetImGuiViews();
|
|
||||||
|
|
||||||
class ImGuiView : public IImGuiView
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ImGuiView()
|
|
||||||
{
|
|
||||||
GetImGuiViews().emplace_back(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init() override {}
|
|
||||||
void Draw() override {}
|
|
||||||
};
|
|
||||||
|
|
@ -12,34 +12,59 @@
|
||||||
|
|
||||||
#include <patches/audio_patches.h>
|
#include <patches/audio_patches.h>
|
||||||
|
|
||||||
OptionsMenu m_optionsMenu;
|
static constexpr double CONTAINER_LINE_ANIMATION_DURATION = 8.0;
|
||||||
|
|
||||||
|
static constexpr double CONTAINER_OUTER_TIME = CONTAINER_LINE_ANIMATION_DURATION + 8.0; // 8 frame delay
|
||||||
|
static constexpr double CONTAINER_OUTER_DURATION = 8.0;
|
||||||
|
|
||||||
|
static constexpr double CONTAINER_INNER_TIME = CONTAINER_OUTER_TIME + CONTAINER_OUTER_DURATION + 8.0; // 8 frame delay
|
||||||
|
static constexpr double CONTAINER_INNER_DURATION = 8.0;
|
||||||
|
|
||||||
|
static constexpr double CONTAINER_BACKGROUND_TIME = CONTAINER_INNER_TIME + CONTAINER_INNER_DURATION + 8.0; // 8 frame delay
|
||||||
|
static constexpr double CONTAINER_BACKGROUND_DURATION = 12.0;
|
||||||
|
|
||||||
|
static constexpr double CONTAINER_FULL_DURATION = CONTAINER_BACKGROUND_TIME + CONTAINER_BACKGROUND_DURATION;
|
||||||
|
|
||||||
|
static constexpr double CONTAINER_CATEGORY_TIME = (CONTAINER_INNER_TIME + CONTAINER_BACKGROUND_TIME) / 2.0;
|
||||||
|
static constexpr double CONTAINER_CATEGORY_DURATION = 12.0;
|
||||||
|
|
||||||
constexpr float COMMON_PADDING_POS_Y = 118.0f;
|
constexpr float COMMON_PADDING_POS_Y = 118.0f;
|
||||||
constexpr float COMMON_PADDING_POS_X = 30.0f;
|
constexpr float COMMON_PADDING_POS_X = 30.0f;
|
||||||
constexpr float INFO_CONTAINER_POS_X = 870.0f;
|
constexpr float INFO_CONTAINER_POS_X = 870.0f;
|
||||||
|
|
||||||
static ImFont* g_seuratFont;
|
static constexpr int32_t m_categoryCount = 4;
|
||||||
static ImFont* g_dfsogeistdFont;
|
static int32_t m_categoryIndex;
|
||||||
static ImFont* g_newRodinFont;
|
static ImVec2 m_categoryAnimMin;
|
||||||
|
static ImVec2 m_categoryAnimMax;
|
||||||
|
|
||||||
static const IConfigDef* g_selectedItem;
|
static int32_t m_firstVisibleRowIndex;
|
||||||
|
static int32_t m_prevSelectedRowIndex;
|
||||||
|
static int32_t m_selectedRowIndex;
|
||||||
|
static double m_rowSelectionTime;
|
||||||
|
|
||||||
static std::string* g_inaccessibleReason;
|
static bool m_leftWasHeld;
|
||||||
|
static bool m_upWasHeld;
|
||||||
|
static bool m_rightWasHeld;
|
||||||
|
static bool m_downWasHeld;
|
||||||
|
|
||||||
static bool g_isEnterKeyBuffered = false;
|
static bool m_lockedOnOption;
|
||||||
|
static double m_lastTappedTime;
|
||||||
|
static double m_lastIncrementTime;
|
||||||
|
static double m_lastIncrementSoundTime;
|
||||||
|
|
||||||
static double g_appearTime = 0.0;
|
static constexpr size_t GRID_SIZE = 9;
|
||||||
|
|
||||||
void OptionsMenu::Init()
|
static ImFont* m_seuratFont;
|
||||||
{
|
static ImFont* m_dfsogeistdFont;
|
||||||
auto& io = ImGui::GetIO();
|
static ImFont* m_newRodinFont;
|
||||||
|
|
||||||
constexpr float FONT_SCALE = 2.0f;
|
static const IConfigDef* m_selectedItem;
|
||||||
|
|
||||||
g_seuratFont = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 26.0f * FONT_SCALE);
|
static std::string* m_inaccessibleReason;
|
||||||
g_dfsogeistdFont = io.Fonts->AddFontFromFileTTF("DFSoGeiStd-W7.otf", 48.0f * FONT_SCALE);
|
|
||||||
g_newRodinFont = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-DB.otf", 20.0f * FONT_SCALE);
|
static bool m_isEnterKeyBuffered = false;
|
||||||
}
|
|
||||||
|
static double m_appearTime = 0.0;
|
||||||
|
|
||||||
static void DrawScanlineBars()
|
static void DrawScanlineBars()
|
||||||
{
|
{
|
||||||
|
|
@ -57,95 +82,85 @@ static void DrawScanlineBars()
|
||||||
if (OptionsMenu::s_pauseMenuType != SWA::eMenuType_WorldMap)
|
if (OptionsMenu::s_pauseMenuType != SWA::eMenuType_WorldMap)
|
||||||
{
|
{
|
||||||
// Top bar fade
|
// Top bar fade
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor
|
||||||
|
(
|
||||||
{ 0.0f, 0.0f },
|
{ 0.0f, 0.0f },
|
||||||
{ res.x, height },
|
{ res.x, height },
|
||||||
FADE_COLOR0,
|
FADE_COLOR0,
|
||||||
FADE_COLOR0,
|
FADE_COLOR0,
|
||||||
FADE_COLOR1,
|
FADE_COLOR1,
|
||||||
FADE_COLOR1);
|
FADE_COLOR1
|
||||||
|
);
|
||||||
|
|
||||||
// Bottom bar fade
|
// Bottom bar fade
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor
|
||||||
|
(
|
||||||
{ res.x, res.y },
|
{ res.x, res.y },
|
||||||
{ 0.0f, res.y - height },
|
{ 0.0f, res.y - height },
|
||||||
FADE_COLOR0,
|
FADE_COLOR0,
|
||||||
FADE_COLOR0,
|
FADE_COLOR0,
|
||||||
FADE_COLOR1,
|
FADE_COLOR1,
|
||||||
FADE_COLOR1);
|
FADE_COLOR1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_SCANLINE);
|
SetShaderModifier(IMGUI_SHADER_MODIFIER_SCANLINE);
|
||||||
|
|
||||||
// Top bar
|
// Top bar
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor
|
||||||
|
(
|
||||||
{ 0.0f, 0.0f },
|
{ 0.0f, 0.0f },
|
||||||
{ res.x, height },
|
{ res.x, height },
|
||||||
COLOR0,
|
COLOR0,
|
||||||
COLOR0,
|
COLOR0,
|
||||||
COLOR1,
|
COLOR1,
|
||||||
COLOR1);
|
COLOR1
|
||||||
|
);
|
||||||
|
|
||||||
// Bottom bar
|
// Bottom bar
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor
|
||||||
|
(
|
||||||
{ res.x, res.y },
|
{ res.x, res.y },
|
||||||
{ 0.0f, res.y - height },
|
{ 0.0f, res.y - height },
|
||||||
COLOR0,
|
COLOR0,
|
||||||
COLOR0,
|
COLOR0,
|
||||||
COLOR1,
|
COLOR1,
|
||||||
COLOR1);
|
COLOR1
|
||||||
|
);
|
||||||
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
||||||
|
|
||||||
// Options text
|
// Options text
|
||||||
// TODO: localise this.
|
// TODO: localise this.
|
||||||
DrawTextWithOutline<int>(g_dfsogeistdFont, Scale(48.0f), { Scale(122.0f), Scale(56.0f) }, IM_COL32(255, 195, 0, 255), "OPTIONS", Scale(4), IM_COL32_BLACK);
|
DrawTextWithOutline<int>(m_dfsogeistdFont, Scale(48.0f), { Scale(122.0f), Scale(56.0f) }, IM_COL32(255, 195, 0, 255), "OPTIONS", 4, IM_COL32_BLACK);
|
||||||
|
|
||||||
// Top bar line
|
// Top bar line
|
||||||
drawList->AddLine(
|
drawList->AddLine
|
||||||
|
(
|
||||||
{ 0.0f, height },
|
{ 0.0f, height },
|
||||||
{ res.x, height },
|
{ res.x, height },
|
||||||
OUTLINE_COLOR,
|
OUTLINE_COLOR,
|
||||||
Scale(1));
|
Scale(1)
|
||||||
|
);
|
||||||
|
|
||||||
// Bottom bar line
|
// Bottom bar line
|
||||||
drawList->AddLine(
|
drawList->AddLine
|
||||||
|
(
|
||||||
{ 0.0f, res.y - height },
|
{ 0.0f, res.y - height },
|
||||||
{ res.x, res.y - height },
|
{ res.x, res.y - height },
|
||||||
OUTLINE_COLOR,
|
OUTLINE_COLOR,
|
||||||
Scale(1));
|
Scale(1)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr size_t GRID_SIZE = 9;
|
|
||||||
|
|
||||||
static float AlignToNextGrid(float value)
|
static float AlignToNextGrid(float value)
|
||||||
{
|
{
|
||||||
return floor(value / GRID_SIZE) * GRID_SIZE;
|
return floor(value / GRID_SIZE) * GRID_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double ComputeMotion(double frameOffset, double frames)
|
|
||||||
{
|
|
||||||
double t = std::clamp((ImGui::GetTime() - g_appearTime - frameOffset / 60.0) / frames * 60.0, 0.0, 1.0);
|
|
||||||
return sqrt(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// all in 60 FPS
|
|
||||||
static constexpr double CONTAINER_LINE_ANIMATION_DURATION = 8.0;
|
|
||||||
|
|
||||||
static constexpr double CONTAINER_OUTER_TIME = CONTAINER_LINE_ANIMATION_DURATION + 8.0; // 8 frame delay
|
|
||||||
static constexpr double CONTAINER_OUTER_DURATION = 8.0;
|
|
||||||
|
|
||||||
static constexpr double CONTAINER_INNER_TIME = CONTAINER_OUTER_TIME + CONTAINER_OUTER_DURATION + 8.0; // 8 frame delay
|
|
||||||
static constexpr double CONTAINER_INNER_DURATION = 8.0;
|
|
||||||
|
|
||||||
static constexpr double CONTAINER_BACKGROUND_TIME = CONTAINER_INNER_TIME + CONTAINER_INNER_DURATION + 8.0; // 8 frame delay
|
|
||||||
static constexpr double CONTAINER_BACKGROUND_DURATION = 12.0;
|
|
||||||
|
|
||||||
static constexpr double CONTAINER_FULL_DURATION = CONTAINER_BACKGROUND_TIME + CONTAINER_BACKGROUND_DURATION;
|
|
||||||
|
|
||||||
static void DrawContainer(ImVec2 min, ImVec2 max)
|
static void DrawContainer(ImVec2 min, ImVec2 max)
|
||||||
{
|
{
|
||||||
double containerHeight = ComputeMotion(0.0, CONTAINER_LINE_ANIMATION_DURATION);
|
double containerHeight = ComputeMotion(m_appearTime, 0.0, CONTAINER_LINE_ANIMATION_DURATION);
|
||||||
|
|
||||||
float center = (min.y + max.y) / 2.0f;
|
float center = (min.y + max.y) / 2.0f;
|
||||||
min.y = Lerp(center, min.y, containerHeight);
|
min.y = Lerp(center, min.y, containerHeight);
|
||||||
|
|
@ -154,9 +169,9 @@ static void DrawContainer(ImVec2 min, ImVec2 max)
|
||||||
auto& res = ImGui::GetIO().DisplaySize;
|
auto& res = ImGui::GetIO().DisplaySize;
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
double outerAlpha = ComputeMotion(CONTAINER_OUTER_TIME, CONTAINER_OUTER_DURATION);
|
double outerAlpha = ComputeMotion(m_appearTime, CONTAINER_OUTER_TIME, CONTAINER_OUTER_DURATION);
|
||||||
double innerAlpha = ComputeMotion(CONTAINER_INNER_TIME, CONTAINER_INNER_DURATION);
|
double innerAlpha = ComputeMotion(m_appearTime, CONTAINER_INNER_TIME, CONTAINER_INNER_DURATION);
|
||||||
double backgroundAlpha = ComputeMotion(CONTAINER_BACKGROUND_TIME, CONTAINER_BACKGROUND_DURATION);
|
double backgroundAlpha = ComputeMotion(m_appearTime, CONTAINER_BACKGROUND_TIME, CONTAINER_BACKGROUND_DURATION);
|
||||||
|
|
||||||
const uint32_t lineColor = IM_COL32(0, 89, 0, 255 * containerHeight);
|
const uint32_t lineColor = IM_COL32(0, 89, 0, 255 * containerHeight);
|
||||||
const uint32_t outerColor = IM_COL32(0, 49, 0, 255 * outerAlpha);
|
const uint32_t outerColor = IM_COL32(0, 49, 0, 255 * outerAlpha);
|
||||||
|
|
@ -194,11 +209,6 @@ static void DrawContainer(ImVec2 min, ImVec2 max)
|
||||||
drawList->PushClipRect({ min.x + gridSize * 2.0f, min.y + gridSize * 2.0f }, { max.x - gridSize * 2.0f + 1.0f, max.y - gridSize * 2.0f + 1.0f });
|
drawList->PushClipRect({ min.x + gridSize * 2.0f, min.y + gridSize * 2.0f }, { max.x - gridSize * 2.0f + 1.0f, max.y - gridSize * 2.0f + 1.0f });
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr int32_t g_categoryCount = 4;
|
|
||||||
static int32_t g_categoryIndex;
|
|
||||||
static ImVec2 g_categoryAnimMin;
|
|
||||||
static ImVec2 g_categoryAnimMax;
|
|
||||||
|
|
||||||
static std::string& GetCategory(int index)
|
static std::string& GetCategory(int index)
|
||||||
{
|
{
|
||||||
// TODO: Don't use raw numbers here!
|
// TODO: Don't use raw numbers here!
|
||||||
|
|
@ -213,61 +223,44 @@ static std::string& GetCategory(int index)
|
||||||
return g_localeMissing;
|
return g_localeMissing;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t g_firstVisibleRowIndex;
|
|
||||||
static int32_t g_prevSelectedRowIndex;
|
|
||||||
static int32_t g_selectedRowIndex;
|
|
||||||
static double g_rowSelectionTime;
|
|
||||||
|
|
||||||
static bool g_leftWasHeld;
|
|
||||||
static bool g_upWasHeld;
|
|
||||||
static bool g_rightWasHeld;
|
|
||||||
static bool g_downWasHeld;
|
|
||||||
|
|
||||||
static bool g_lockedOnOption;
|
|
||||||
static double g_lastTappedTime;
|
|
||||||
static double g_lastIncrementTime;
|
|
||||||
static double g_lastIncrementSoundTime;
|
|
||||||
|
|
||||||
static void ResetSelection()
|
static void ResetSelection()
|
||||||
{
|
{
|
||||||
g_firstVisibleRowIndex = 0;
|
m_firstVisibleRowIndex = 0;
|
||||||
g_selectedRowIndex = 0;
|
m_selectedRowIndex = 0;
|
||||||
g_prevSelectedRowIndex = 0;
|
m_prevSelectedRowIndex = 0;
|
||||||
g_rowSelectionTime = ImGui::GetTime();
|
m_rowSelectionTime = ImGui::GetTime();
|
||||||
g_leftWasHeld = false;
|
m_leftWasHeld = false;
|
||||||
g_upWasHeld = false;
|
m_upWasHeld = false;
|
||||||
g_rightWasHeld = false;
|
m_rightWasHeld = false;
|
||||||
g_downWasHeld = false;
|
m_downWasHeld = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr double CONTAINER_CATEGORY_TIME = (CONTAINER_INNER_TIME + CONTAINER_BACKGROUND_TIME) / 2.0;
|
|
||||||
static constexpr double CONTAINER_CATEGORY_DURATION = 12.0;
|
|
||||||
|
|
||||||
static bool DrawCategories()
|
static bool DrawCategories()
|
||||||
{
|
{
|
||||||
double motion = ComputeMotion(CONTAINER_CATEGORY_TIME, CONTAINER_CATEGORY_DURATION);
|
double motion = ComputeMotion(m_appearTime, CONTAINER_CATEGORY_TIME, CONTAINER_CATEGORY_DURATION);
|
||||||
|
|
||||||
if (motion == 0.0)
|
if (motion == 0.0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto inputState = SWA::CInputState::GetInstance();
|
auto inputState = SWA::CInputState::GetInstance();
|
||||||
|
|
||||||
bool moveLeft = !g_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_LeftBumper) ||
|
bool moveLeft = !m_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_LeftBumper) ||
|
||||||
inputState->GetPadState().IsTapped(SWA::eKeyState_LeftTrigger));
|
inputState->GetPadState().IsTapped(SWA::eKeyState_LeftTrigger));
|
||||||
|
|
||||||
bool moveRight = !g_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper) ||
|
bool moveRight = !m_lockedOnOption && (inputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper) ||
|
||||||
inputState->GetPadState().IsTapped(SWA::eKeyState_RightTrigger));
|
inputState->GetPadState().IsTapped(SWA::eKeyState_RightTrigger));
|
||||||
|
|
||||||
if (moveLeft)
|
if (moveLeft)
|
||||||
{
|
{
|
||||||
--g_categoryIndex;
|
--m_categoryIndex;
|
||||||
if (g_categoryIndex < 0)
|
if (m_categoryIndex < 0)
|
||||||
g_categoryIndex = g_categoryCount - 1;
|
m_categoryIndex = m_categoryCount - 1;
|
||||||
}
|
}
|
||||||
else if (moveRight)
|
else if (moveRight)
|
||||||
{
|
{
|
||||||
++g_categoryIndex;
|
++m_categoryIndex;
|
||||||
if (g_categoryIndex >= g_categoryCount)
|
if (m_categoryIndex >= m_categoryCount)
|
||||||
g_categoryIndex = 0;
|
m_categoryIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moveLeft || moveRight)
|
if (moveLeft || moveRight)
|
||||||
|
|
@ -285,22 +278,22 @@ static bool DrawCategories()
|
||||||
float tabPadding = gridSize;
|
float tabPadding = gridSize;
|
||||||
|
|
||||||
float size = Scale(32.0f);
|
float size = Scale(32.0f);
|
||||||
ImVec2 textSizes[g_categoryCount];
|
ImVec2 textSizes[m_categoryCount];
|
||||||
float tabWidthSum = 0.0f;
|
float tabWidthSum = 0.0f;
|
||||||
for (size_t i = 0; i < g_categoryCount; i++)
|
for (size_t i = 0; i < m_categoryCount; i++)
|
||||||
{
|
{
|
||||||
textSizes[i] = g_dfsogeistdFont->CalcTextSizeA(size, FLT_MAX, 0.0f, GetCategory(i).c_str());
|
textSizes[i] = m_dfsogeistdFont->CalcTextSizeA(size, FLT_MAX, 0.0f, GetCategory(i).c_str());
|
||||||
tabWidthSum += textSizes[i].x + textPadding * 2.0f;
|
tabWidthSum += textSizes[i].x + textPadding * 2.0f;
|
||||||
}
|
}
|
||||||
tabWidthSum += (g_categoryCount - 1) * tabPadding;
|
tabWidthSum += (m_categoryCount - 1) * tabPadding;
|
||||||
|
|
||||||
float tabHeight = gridSize * 4.0f;
|
float tabHeight = gridSize * 4.0f;
|
||||||
float xOffset = ((clipRectMax.x - clipRectMin.x) - tabWidthSum) / 2.0f;
|
float xOffset = ((clipRectMax.x - clipRectMin.x) - tabWidthSum) / 2.0f;
|
||||||
xOffset -= (1.0 - motion) * gridSize * 4.0;
|
xOffset -= (1.0 - motion) * gridSize * 4.0;
|
||||||
|
|
||||||
ImVec2 minVec[g_categoryCount];
|
ImVec2 minVec[m_categoryCount];
|
||||||
|
|
||||||
for (size_t i = 0; i < g_categoryCount; i++)
|
for (size_t i = 0; i < m_categoryCount; i++)
|
||||||
{
|
{
|
||||||
ImVec2 min = { clipRectMin.x + xOffset, clipRectMin.y };
|
ImVec2 min = { clipRectMin.x + xOffset, clipRectMin.y };
|
||||||
|
|
||||||
|
|
@ -308,58 +301,64 @@ static bool DrawCategories()
|
||||||
ImVec2 max = { clipRectMin.x + xOffset, clipRectMin.y + tabHeight };
|
ImVec2 max = { clipRectMin.x + xOffset, clipRectMin.y + tabHeight };
|
||||||
xOffset += tabPadding;
|
xOffset += tabPadding;
|
||||||
|
|
||||||
if (g_categoryIndex == i)
|
if (m_categoryIndex == i)
|
||||||
{
|
{
|
||||||
// Animation interrupted by entering/exiting or resizing the options menu
|
// Animation interrupted by entering/exiting or resizing the options menu
|
||||||
if (motion < 1.0 || abs(g_categoryAnimMin.y - min.y) > 0.01f || abs(g_categoryAnimMax.y - max.y) > 0.01f)
|
if (motion < 1.0 || abs(m_categoryAnimMin.y - min.y) > 0.01f || abs(m_categoryAnimMax.y - max.y) > 0.01f)
|
||||||
{
|
{
|
||||||
g_categoryAnimMin = min;
|
m_categoryAnimMin = min;
|
||||||
g_categoryAnimMax = max;
|
m_categoryAnimMax = max;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float animWidth = g_categoryAnimMax.x - g_categoryAnimMin.x;
|
float animWidth = m_categoryAnimMax.x - m_categoryAnimMin.x;
|
||||||
float width = max.x - min.x;
|
float width = max.x - min.x;
|
||||||
float height = max.y - min.y;
|
float height = max.y - min.y;
|
||||||
|
|
||||||
animWidth = Lerp(animWidth, width, 1.0f - exp(-64.0f * ImGui::GetIO().DeltaTime));
|
animWidth = Lerp(animWidth, width, 1.0f - exp(-64.0f * ImGui::GetIO().DeltaTime));
|
||||||
|
|
||||||
auto center = Lerp(min, max, 0.5f);
|
auto center = Lerp(min, max, 0.5f);
|
||||||
auto animCenter = Lerp(g_categoryAnimMin, g_categoryAnimMax, 0.5f);
|
auto animCenter = Lerp(m_categoryAnimMin, m_categoryAnimMax, 0.5f);
|
||||||
auto animatedCenter = Lerp(animCenter, center, 1.0f - exp(-16.0f * ImGui::GetIO().DeltaTime));
|
auto animatedCenter = Lerp(animCenter, center, 1.0f - exp(-16.0f * ImGui::GetIO().DeltaTime));
|
||||||
|
|
||||||
float widthHalfExtent = width / 2.0f;
|
float widthHalfExtent = width / 2.0f;
|
||||||
float heightHalfExtent = height / 2.0f;
|
float heightHalfExtent = height / 2.0f;
|
||||||
|
|
||||||
g_categoryAnimMin = { animatedCenter.x - widthHalfExtent, animatedCenter.y - heightHalfExtent };
|
m_categoryAnimMin = { animatedCenter.x - widthHalfExtent, animatedCenter.y - heightHalfExtent };
|
||||||
g_categoryAnimMax = { animatedCenter.x + widthHalfExtent, animatedCenter.y + heightHalfExtent };
|
m_categoryAnimMax = { animatedCenter.x + widthHalfExtent, animatedCenter.y + heightHalfExtent };
|
||||||
}
|
}
|
||||||
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_SCANLINE_BUTTON);
|
SetShaderModifier(IMGUI_SHADER_MODIFIER_SCANLINE_BUTTON);
|
||||||
|
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor
|
||||||
g_categoryAnimMin,
|
(
|
||||||
g_categoryAnimMax,
|
m_categoryAnimMin,
|
||||||
|
m_categoryAnimMax,
|
||||||
IM_COL32(0, 130, 0, 223 * motion),
|
IM_COL32(0, 130, 0, 223 * motion),
|
||||||
IM_COL32(0, 130, 0, 178 * motion),
|
IM_COL32(0, 130, 0, 178 * motion),
|
||||||
IM_COL32(0, 130, 0, 223 * motion),
|
IM_COL32(0, 130, 0, 223 * motion),
|
||||||
IM_COL32(0, 130, 0, 178 * motion));
|
IM_COL32(0, 130, 0, 178 * motion)
|
||||||
|
);
|
||||||
|
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor
|
||||||
g_categoryAnimMin,
|
(
|
||||||
g_categoryAnimMax,
|
m_categoryAnimMin,
|
||||||
|
m_categoryAnimMax,
|
||||||
IM_COL32(0, 0, 0, 13 * motion),
|
IM_COL32(0, 0, 0, 13 * motion),
|
||||||
IM_COL32(0, 0, 0, 0),
|
IM_COL32(0, 0, 0, 0),
|
||||||
IM_COL32(0, 0, 0, 55 * motion),
|
IM_COL32(0, 0, 0, 55 * motion),
|
||||||
IM_COL32(0, 0, 0, 6));
|
IM_COL32(0, 0, 0, 6)
|
||||||
|
);
|
||||||
|
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor
|
||||||
g_categoryAnimMin,
|
(
|
||||||
g_categoryAnimMax,
|
m_categoryAnimMin,
|
||||||
|
m_categoryAnimMax,
|
||||||
IM_COL32(0, 130, 0, 13 * motion),
|
IM_COL32(0, 130, 0, 13 * motion),
|
||||||
IM_COL32(0, 130, 0, 111 * motion),
|
IM_COL32(0, 130, 0, 111 * motion),
|
||||||
IM_COL32(0, 130, 0, 0),
|
IM_COL32(0, 130, 0, 0),
|
||||||
IM_COL32(0, 130, 0, 55 * motion));
|
IM_COL32(0, 130, 0, 55 * motion)
|
||||||
|
);
|
||||||
|
|
||||||
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
SetShaderModifier(IMGUI_SHADER_MODIFIER_NONE);
|
||||||
}
|
}
|
||||||
|
|
@ -370,30 +369,34 @@ static bool DrawCategories()
|
||||||
minVec[i] = min;
|
minVec[i] = min;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < g_categoryCount; i++)
|
for (size_t i = 0; i < m_categoryCount; i++)
|
||||||
{
|
{
|
||||||
auto& min = minVec[i];
|
auto& min = minVec[i];
|
||||||
uint8_t alpha = (i == g_categoryIndex ? 235 : 128) * motion;
|
uint8_t alpha = (i == m_categoryIndex ? 235 : 128) * motion;
|
||||||
|
|
||||||
SetGradient(
|
SetGradient
|
||||||
|
(
|
||||||
min,
|
min,
|
||||||
{ min.x + textSizes[i].x, min.y + textSizes[i].y },
|
{ min.x + textSizes[i].x, min.y + textSizes[i].y },
|
||||||
IM_COL32(128, 255, 0, alpha),
|
IM_COL32(128, 255, 0, alpha),
|
||||||
IM_COL32(255, 192, 0, alpha));
|
IM_COL32(255, 192, 0, alpha)
|
||||||
|
);
|
||||||
|
|
||||||
DrawTextWithOutline<int>(
|
DrawTextWithOutline<int>
|
||||||
g_dfsogeistdFont,
|
(
|
||||||
|
m_dfsogeistdFont,
|
||||||
size,
|
size,
|
||||||
min,
|
min,
|
||||||
IM_COL32_WHITE,
|
IM_COL32_WHITE,
|
||||||
GetCategory(i).c_str(),
|
GetCategory(i).c_str(),
|
||||||
Scale(3),
|
3,
|
||||||
IM_COL32_BLACK);
|
IM_COL32_BLACK
|
||||||
|
);
|
||||||
|
|
||||||
ResetGradient();
|
ResetGradient();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ImGui::GetTime() - g_appearTime) >= (CONTAINER_FULL_DURATION / 60.0))
|
if ((ImGui::GetTime() - m_appearTime) >= (CONTAINER_FULL_DURATION / 60.0))
|
||||||
{
|
{
|
||||||
drawList->PushClipRect({ clipRectMin.x, clipRectMin.y + gridSize * 6.0f }, { clipRectMax.x - gridSize, clipRectMax.y - gridSize });
|
drawList->PushClipRect({ clipRectMin.x, clipRectMin.y + gridSize * 6.0f }, { clipRectMax.x - gridSize, clipRectMax.y - gridSize });
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -427,18 +430,18 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
|
|
||||||
auto configName = config->GetNameLocalised();
|
auto configName = config->GetNameLocalised();
|
||||||
auto size = Scale(26.0f);
|
auto size = Scale(26.0f);
|
||||||
auto textSize = g_seuratFont->CalcTextSizeA(size, FLT_MAX, 0.0f, configName.c_str());
|
auto textSize = m_seuratFont->CalcTextSizeA(size, FLT_MAX, 0.0f, configName.c_str());
|
||||||
|
|
||||||
ImVec2 textPos = { min.x + gridSize, min.y + (optionHeight - textSize.y) / 2.0f };
|
ImVec2 textPos = { min.x + gridSize, min.y + (optionHeight - textSize.y) / 2.0f };
|
||||||
ImVec4 textClipRect = { min.x, min.y, max.x, max.y };
|
ImVec4 textClipRect = { min.x, min.y, max.x, max.y };
|
||||||
|
|
||||||
bool lockedOnOption = false;
|
bool lockedOnOption = false;
|
||||||
if (g_selectedRowIndex == rowIndex)
|
if (m_selectedRowIndex == rowIndex)
|
||||||
{
|
{
|
||||||
g_selectedItem = config;
|
m_selectedItem = config;
|
||||||
g_inaccessibleReason = isAccessible ? nullptr : inaccessibleReason;
|
m_inaccessibleReason = isAccessible ? nullptr : inaccessibleReason;
|
||||||
|
|
||||||
if (!g_isEnterKeyBuffered)
|
if (!m_isEnterKeyBuffered)
|
||||||
{
|
{
|
||||||
if (isAccessible)
|
if (isAccessible)
|
||||||
{
|
{
|
||||||
|
|
@ -462,12 +465,12 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
|
|
||||||
if (padState.IsTapped(SWA::eKeyState_A))
|
if (padState.IsTapped(SWA::eKeyState_A))
|
||||||
{
|
{
|
||||||
g_lockedOnOption ^= true;
|
m_lockedOnOption ^= true;
|
||||||
|
|
||||||
if (g_lockedOnOption)
|
if (m_lockedOnOption)
|
||||||
{
|
{
|
||||||
g_leftWasHeld = false;
|
m_leftWasHeld = false;
|
||||||
g_rightWasHeld = false;
|
m_rightWasHeld = false;
|
||||||
// remember value
|
// remember value
|
||||||
s_oldValue = config->Value;
|
s_oldValue = config->Value;
|
||||||
|
|
||||||
|
|
@ -486,12 +489,12 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
{
|
{
|
||||||
// released lock, restore old value
|
// released lock, restore old value
|
||||||
config->Value = s_oldValue;
|
config->Value = s_oldValue;
|
||||||
g_lockedOnOption = false;
|
m_lockedOnOption = false;
|
||||||
|
|
||||||
Game_PlaySound("sys_worldmap_cansel");
|
Game_PlaySound("sys_worldmap_cansel");
|
||||||
}
|
}
|
||||||
|
|
||||||
lockedOnOption = g_lockedOnOption;
|
lockedOnOption = m_lockedOnOption;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -502,14 +505,14 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fadedOut = (g_lockedOnOption && g_selectedItem != config) || !isAccessible;
|
auto fadedOut = (m_lockedOnOption && m_selectedItem != config) || !isAccessible;
|
||||||
auto alpha = fadedOut ? 0.5f : 1.0f;
|
auto alpha = fadedOut ? 0.5f : 1.0f;
|
||||||
auto textColour = IM_COL32(255, 255, 255, 255 * alpha);
|
auto textColour = IM_COL32(255, 255, 255, 255 * alpha);
|
||||||
|
|
||||||
if (g_selectedItem == config)
|
if (m_selectedItem == config)
|
||||||
{
|
{
|
||||||
float prevItemOffset = (g_prevSelectedRowIndex - g_selectedRowIndex) * (optionHeight + optionPadding);
|
float prevItemOffset = (m_prevSelectedRowIndex - m_selectedRowIndex) * (optionHeight + optionPadding);
|
||||||
double animRatio = std::clamp((ImGui::GetTime() - g_rowSelectionTime) * 60.0 / 8.0, 0.0, 1.0);
|
double animRatio = std::clamp((ImGui::GetTime() - m_rowSelectionTime) * 60.0 / 8.0, 0.0, 1.0);
|
||||||
prevItemOffset *= pow(1.0 - animRatio, 3.0);
|
prevItemOffset *= pow(1.0 - animRatio, 3.0);
|
||||||
|
|
||||||
auto c0 = IM_COL32(0xE2, 0x71, 0x22, isAccessible ? 0x80 : 0x30);
|
auto c0 = IM_COL32(0xE2, 0x71, 0x22, isAccessible ? 0x80 : 0x30);
|
||||||
|
|
@ -517,11 +520,11 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
|
|
||||||
drawList->AddRectFilledMultiColor({ min.x, min.y + prevItemOffset }, { max.x, max.y + prevItemOffset }, c0, c0, c1, c1);
|
drawList->AddRectFilledMultiColor({ min.x, min.y + prevItemOffset }, { max.x, max.y + prevItemOffset }, c0, c0, c1, c1);
|
||||||
|
|
||||||
DrawTextWithMarquee(g_seuratFont, size, textPos, min, max, textColour, configName.c_str(), g_rowSelectionTime, 0.9, 250.0);
|
DrawTextWithMarquee(m_seuratFont, size, textPos, min, max, textColour, configName.c_str(), m_rowSelectionTime, 0.9, 250.0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
drawList->AddText(g_seuratFont, size, textPos, textColour, configName.c_str(), 0, 0.0f, &textClipRect);
|
drawList->AddText(m_seuratFont, size, textPos, textColour, configName.c_str(), 0, 0.0f, &textClipRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right side
|
// Right side
|
||||||
|
|
@ -543,13 +546,15 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
float xPadding = Scale(6.0f);
|
float xPadding = Scale(6.0f);
|
||||||
float yPadding = Scale(3.0f);
|
float yPadding = Scale(3.0f);
|
||||||
|
|
||||||
drawList->AddRectFilledMultiColor(
|
drawList->AddRectFilledMultiColor
|
||||||
|
(
|
||||||
{ min.x + xPadding, min.y + yPadding },
|
{ min.x + xPadding, min.y + yPadding },
|
||||||
{ max.x - xPadding, max.y - yPadding },
|
{ max.x - xPadding, max.y - yPadding },
|
||||||
innerColor0,
|
innerColor0,
|
||||||
innerColor0,
|
innerColor0,
|
||||||
innerColor1,
|
innerColor1,
|
||||||
innerColor1);
|
innerColor1
|
||||||
|
);
|
||||||
|
|
||||||
// The actual slider
|
// The actual slider
|
||||||
const uint32_t sliderColor0 = IM_COL32(57, 241, 0, 255 * alpha);
|
const uint32_t sliderColor0 = IM_COL32(57, 241, 0, 255 * alpha);
|
||||||
|
|
@ -580,34 +585,38 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
constexpr uint32_t COLOR = IM_COL32(0, 97, 0, 255);
|
constexpr uint32_t COLOR = IM_COL32(0, 97, 0, 255);
|
||||||
|
|
||||||
// Left
|
// Left
|
||||||
drawList->AddTriangleFilled(
|
drawList->AddTriangleFilled
|
||||||
|
(
|
||||||
{ min.x - trianglePadding, min.y },
|
{ min.x - trianglePadding, min.y },
|
||||||
{ min.x - trianglePadding, max.y },
|
{ min.x - trianglePadding, max.y },
|
||||||
{ min.x - trianglePadding - triangleWidth, (min.y + max.y) / 2.0f },
|
{ min.x - trianglePadding - triangleWidth, (min.y + max.y) / 2.0f },
|
||||||
COLOR);
|
COLOR
|
||||||
|
);
|
||||||
|
|
||||||
// Right
|
// Right
|
||||||
drawList->AddTriangleFilled(
|
drawList->AddTriangleFilled
|
||||||
|
(
|
||||||
{ max.x + trianglePadding, max.y },
|
{ max.x + trianglePadding, max.y },
|
||||||
{ max.x + trianglePadding, min.y },
|
{ max.x + trianglePadding, min.y },
|
||||||
{ max.x + trianglePadding + triangleWidth, (min.y + max.y) / 2.0f },
|
{ max.x + trianglePadding + triangleWidth, (min.y + max.y) / 2.0f },
|
||||||
COLOR);
|
COLOR
|
||||||
|
);
|
||||||
|
|
||||||
bool leftIsHeld = padState.IsDown(SWA::eKeyState_DpadLeft) || padState.LeftStickHorizontal < -0.5f;
|
bool leftIsHeld = padState.IsDown(SWA::eKeyState_DpadLeft) || padState.LeftStickHorizontal < -0.5f;
|
||||||
bool rightIsHeld = padState.IsDown(SWA::eKeyState_DpadRight) || padState.LeftStickHorizontal > 0.5f;
|
bool rightIsHeld = padState.IsDown(SWA::eKeyState_DpadRight) || padState.LeftStickHorizontal > 0.5f;
|
||||||
|
|
||||||
bool leftTapped = !g_leftWasHeld && leftIsHeld;
|
bool leftTapped = !m_leftWasHeld && leftIsHeld;
|
||||||
bool rightTapped = !g_rightWasHeld && rightIsHeld;
|
bool rightTapped = !m_rightWasHeld && rightIsHeld;
|
||||||
|
|
||||||
double time = ImGui::GetTime();
|
double time = ImGui::GetTime();
|
||||||
|
|
||||||
if (leftTapped || rightTapped)
|
if (leftTapped || rightTapped)
|
||||||
g_lastTappedTime = time;
|
m_lastTappedTime = time;
|
||||||
|
|
||||||
bool decrement = leftTapped;
|
bool decrement = leftTapped;
|
||||||
bool increment = rightTapped;
|
bool increment = rightTapped;
|
||||||
|
|
||||||
bool fastIncrement = (time - g_lastTappedTime) > 0.5;
|
bool fastIncrement = (time - m_lastTappedTime) > 0.5;
|
||||||
constexpr double INCREMENT_TIME = 1.0 / 120.0;
|
constexpr double INCREMENT_TIME = 1.0 / 120.0;
|
||||||
|
|
||||||
constexpr double INCREMENT_SOUND_TIME = 1.0 / 7.5;
|
constexpr double INCREMENT_SOUND_TIME = 1.0 / 7.5;
|
||||||
|
|
@ -615,12 +624,12 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
|
|
||||||
if (fastIncrement)
|
if (fastIncrement)
|
||||||
{
|
{
|
||||||
isPlayIncrementSound = (time - g_lastIncrementSoundTime) > INCREMENT_SOUND_TIME;
|
isPlayIncrementSound = (time - m_lastIncrementSoundTime) > INCREMENT_SOUND_TIME;
|
||||||
|
|
||||||
if ((time - g_lastIncrementTime) < INCREMENT_TIME)
|
if ((time - m_lastIncrementTime) < INCREMENT_TIME)
|
||||||
fastIncrement = false;
|
fastIncrement = false;
|
||||||
else
|
else
|
||||||
g_lastIncrementTime = time;
|
m_lastIncrementTime = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fastIncrement)
|
if (fastIncrement)
|
||||||
|
|
@ -629,8 +638,8 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
increment = rightIsHeld;
|
increment = rightIsHeld;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_leftWasHeld = leftIsHeld;
|
m_leftWasHeld = leftIsHeld;
|
||||||
g_rightWasHeld = rightIsHeld;
|
m_rightWasHeld = rightIsHeld;
|
||||||
|
|
||||||
if constexpr (std::is_enum_v<T>)
|
if constexpr (std::is_enum_v<T>)
|
||||||
{
|
{
|
||||||
|
|
@ -678,13 +687,14 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
}
|
}
|
||||||
|
|
||||||
deltaTime -= INCREMENT_TIME;
|
deltaTime -= INCREMENT_TIME;
|
||||||
} while (fastIncrement && deltaTime > 0.0f);
|
}
|
||||||
|
while (fastIncrement && deltaTime > 0.0f);
|
||||||
|
|
||||||
bool isConfigValueInBounds = config->Value >= valueMin && config->Value <= valueMax;
|
bool isConfigValueInBounds = config->Value >= valueMin && config->Value <= valueMax;
|
||||||
|
|
||||||
if ((increment || decrement) && isConfigValueInBounds && isPlayIncrementSound)
|
if ((increment || decrement) && isConfigValueInBounds && isPlayIncrementSound)
|
||||||
{
|
{
|
||||||
g_lastIncrementSoundTime = time;
|
m_lastIncrementSoundTime = time;
|
||||||
Game_PlaySound("sys_actstg_twn_speechbutton");
|
Game_PlaySound("sys_actstg_twn_speechbutton");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -697,33 +707,42 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
||||||
|
|
||||||
std::string valueText;
|
std::string valueText;
|
||||||
if constexpr (std::is_same_v<T, float>)
|
if constexpr (std::is_same_v<T, float>)
|
||||||
|
{
|
||||||
valueText = std::format("{}%", int32_t(round(config->Value * 100.0f)));
|
valueText = std::format("{}%", int32_t(round(config->Value * 100.0f)));
|
||||||
|
}
|
||||||
else if constexpr (std::is_same_v<T, int32_t>)
|
else if constexpr (std::is_same_v<T, int32_t>)
|
||||||
|
{
|
||||||
valueText = config->Value >= valueMax ? Localise("Options_Value_Max") : std::format("{}", config->Value);
|
valueText = config->Value >= valueMax ? Localise("Options_Value_Max") : std::format("{}", config->Value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
valueText = config->GetValueLocalised();
|
valueText = config->GetValueLocalised();
|
||||||
|
}
|
||||||
|
|
||||||
size = Scale(20.0f);
|
size = Scale(20.0f);
|
||||||
textSize = g_newRodinFont->CalcTextSizeA(size, FLT_MAX, 0.0f, valueText.data());
|
textSize = m_newRodinFont->CalcTextSizeA(size, FLT_MAX, 0.0f, valueText.data());
|
||||||
|
|
||||||
min.x += ((max.x - min.x) - textSize.x) / 2.0f;
|
min.x += ((max.x - min.x) - textSize.x) / 2.0f;
|
||||||
min.y += ((max.y - min.y) - textSize.y) / 2.0f;
|
min.y += ((max.y - min.y) - textSize.y) / 2.0f;
|
||||||
|
|
||||||
SetGradient(
|
SetGradient
|
||||||
|
(
|
||||||
min,
|
min,
|
||||||
{ min.x + textSize.x, min.y + textSize.y },
|
{ min.x + textSize.x, min.y + textSize.y },
|
||||||
IM_COL32(192, 255, 0, 255),
|
IM_COL32(192, 255, 0, 255),
|
||||||
IM_COL32(128, 170, 0, 255)
|
IM_COL32(128, 170, 0, 255)
|
||||||
);
|
);
|
||||||
|
|
||||||
DrawTextWithOutline<int>(
|
DrawTextWithOutline<int>
|
||||||
g_newRodinFont,
|
(
|
||||||
|
m_newRodinFont,
|
||||||
size,
|
size,
|
||||||
min,
|
min,
|
||||||
IM_COL32(255, 255, 255, 255 * alpha),
|
IM_COL32(255, 255, 255, 255 * alpha),
|
||||||
valueText.data(),
|
valueText.data(),
|
||||||
Scale(2),
|
2,
|
||||||
IM_COL32(0, 0, 0, 255 * alpha));
|
IM_COL32(0, 0, 0, 255 * alpha)
|
||||||
|
);
|
||||||
|
|
||||||
ResetGradient();
|
ResetGradient();
|
||||||
}
|
}
|
||||||
|
|
@ -734,11 +753,11 @@ static void DrawConfigOptions()
|
||||||
auto clipRectMin = drawList->GetClipRectMin();
|
auto clipRectMin = drawList->GetClipRectMin();
|
||||||
auto clipRectMax = drawList->GetClipRectMax();
|
auto clipRectMax = drawList->GetClipRectMax();
|
||||||
|
|
||||||
g_selectedItem = nullptr;
|
m_selectedItem = nullptr;
|
||||||
|
|
||||||
float gridSize = Scale(GRID_SIZE);
|
float gridSize = Scale(GRID_SIZE);
|
||||||
float optionHeightWithPadding = gridSize * 6.0f;
|
float optionHeightWithPadding = gridSize * 6.0f;
|
||||||
float yOffset = -g_firstVisibleRowIndex * optionHeightWithPadding;
|
float yOffset = -m_firstVisibleRowIndex * optionHeightWithPadding;
|
||||||
|
|
||||||
int32_t rowCount = 0;
|
int32_t rowCount = 0;
|
||||||
|
|
||||||
|
|
@ -746,7 +765,7 @@ static void DrawConfigOptions()
|
||||||
auto cmnReason = &Localise("Options_Desc_NotAvailable");
|
auto cmnReason = &Localise("Options_Desc_NotAvailable");
|
||||||
|
|
||||||
// TODO: Don't use raw numbers here!
|
// TODO: Don't use raw numbers here!
|
||||||
switch (g_categoryIndex)
|
switch (m_categoryIndex)
|
||||||
{
|
{
|
||||||
case 0: // SYSTEM
|
case 0: // SYSTEM
|
||||||
DrawConfigOption(rowCount++, yOffset, &Config::Language, !OptionsMenu::s_isPause, cmnReason);
|
DrawConfigOption(rowCount++, yOffset, &Config::Language, !OptionsMenu::s_isPause, cmnReason);
|
||||||
|
|
@ -794,58 +813,58 @@ static void DrawConfigOptions()
|
||||||
|
|
||||||
auto inputState = SWA::CInputState::GetInstance();
|
auto inputState = SWA::CInputState::GetInstance();
|
||||||
|
|
||||||
bool upIsHeld = !g_lockedOnOption && (inputState->GetPadState().IsDown(SWA::eKeyState_DpadUp) ||
|
bool upIsHeld = !m_lockedOnOption && (inputState->GetPadState().IsDown(SWA::eKeyState_DpadUp) ||
|
||||||
inputState->GetPadState().LeftStickVertical > 0.5f);
|
inputState->GetPadState().LeftStickVertical > 0.5f);
|
||||||
|
|
||||||
bool downIsHeld = !g_lockedOnOption && (inputState->GetPadState().IsDown(SWA::eKeyState_DpadDown) ||
|
bool downIsHeld = !m_lockedOnOption && (inputState->GetPadState().IsDown(SWA::eKeyState_DpadDown) ||
|
||||||
inputState->GetPadState().LeftStickVertical < -0.5f);
|
inputState->GetPadState().LeftStickVertical < -0.5f);
|
||||||
|
|
||||||
bool scrollUp = !g_upWasHeld && upIsHeld;
|
bool scrollUp = !m_upWasHeld && upIsHeld;
|
||||||
bool scrollDown = !g_downWasHeld && downIsHeld;
|
bool scrollDown = !m_downWasHeld && downIsHeld;
|
||||||
|
|
||||||
int32_t prevSelectedRowIndex = g_selectedRowIndex;
|
int32_t prevSelectedRowIndex = m_selectedRowIndex;
|
||||||
|
|
||||||
if (scrollUp)
|
if (scrollUp)
|
||||||
{
|
{
|
||||||
--g_selectedRowIndex;
|
--m_selectedRowIndex;
|
||||||
if (g_selectedRowIndex < 0)
|
if (m_selectedRowIndex < 0)
|
||||||
g_selectedRowIndex = rowCount - 1;
|
m_selectedRowIndex = rowCount - 1;
|
||||||
}
|
}
|
||||||
else if (scrollDown)
|
else if (scrollDown)
|
||||||
{
|
{
|
||||||
++g_selectedRowIndex;
|
++m_selectedRowIndex;
|
||||||
if (g_selectedRowIndex >= rowCount)
|
if (m_selectedRowIndex >= rowCount)
|
||||||
g_selectedRowIndex = 0;
|
m_selectedRowIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrollUp || scrollDown)
|
if (scrollUp || scrollDown)
|
||||||
{
|
{
|
||||||
g_rowSelectionTime = ImGui::GetTime();
|
m_rowSelectionTime = ImGui::GetTime();
|
||||||
g_prevSelectedRowIndex = prevSelectedRowIndex;
|
m_prevSelectedRowIndex = prevSelectedRowIndex;
|
||||||
Game_PlaySound("sys_worldmap_cursor");
|
Game_PlaySound("sys_worldmap_cursor");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_upWasHeld = upIsHeld;
|
m_upWasHeld = upIsHeld;
|
||||||
g_downWasHeld = downIsHeld;
|
m_downWasHeld = downIsHeld;
|
||||||
|
|
||||||
int32_t visibleRowCount = int32_t(floor((clipRectMax.y - clipRectMin.y) / optionHeightWithPadding));
|
int32_t visibleRowCount = int32_t(floor((clipRectMax.y - clipRectMin.y) / optionHeightWithPadding));
|
||||||
|
|
||||||
bool disableMoveAnimation = false;
|
bool disableMoveAnimation = false;
|
||||||
|
|
||||||
if (g_firstVisibleRowIndex > g_selectedRowIndex)
|
if (m_firstVisibleRowIndex > m_selectedRowIndex)
|
||||||
{
|
{
|
||||||
g_firstVisibleRowIndex = g_selectedRowIndex;
|
m_firstVisibleRowIndex = m_selectedRowIndex;
|
||||||
disableMoveAnimation = true;
|
disableMoveAnimation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_firstVisibleRowIndex + visibleRowCount - 1 < g_selectedRowIndex)
|
if (m_firstVisibleRowIndex + visibleRowCount - 1 < m_selectedRowIndex)
|
||||||
{
|
{
|
||||||
g_firstVisibleRowIndex = std::max(0, g_selectedRowIndex - visibleRowCount + 1);
|
m_firstVisibleRowIndex = std::max(0, m_selectedRowIndex - visibleRowCount + 1);
|
||||||
disableMoveAnimation = true;
|
disableMoveAnimation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disableMoveAnimation)
|
if (disableMoveAnimation)
|
||||||
g_prevSelectedRowIndex = g_selectedRowIndex;
|
m_prevSelectedRowIndex = m_selectedRowIndex;
|
||||||
|
|
||||||
// Pop clip rect from DrawCategories
|
// Pop clip rect from DrawCategories
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
|
|
@ -855,10 +874,11 @@ static void DrawConfigOptions()
|
||||||
{
|
{
|
||||||
float totalHeight = (clipRectMax.y - clipRectMin.y);
|
float totalHeight = (clipRectMax.y - clipRectMin.y);
|
||||||
float heightRatio = float(visibleRowCount) / float(rowCount);
|
float heightRatio = float(visibleRowCount) / float(rowCount);
|
||||||
float offsetRatio = float(g_firstVisibleRowIndex) / float(rowCount);
|
float offsetRatio = float(m_firstVisibleRowIndex) / float(rowCount);
|
||||||
float minY = offsetRatio * totalHeight + clipRectMin.y;
|
float minY = offsetRatio * totalHeight + clipRectMin.y;
|
||||||
|
|
||||||
drawList->AddRectFilled(
|
drawList->AddRectFilled
|
||||||
|
(
|
||||||
{ clipRectMax.x, minY },
|
{ clipRectMax.x, minY },
|
||||||
{ clipRectMax.x + gridSize, minY + totalHeight * heightRatio },
|
{ clipRectMax.x + gridSize, minY + totalHeight * heightRatio },
|
||||||
IM_COL32(0, 128, 0, 255)
|
IM_COL32(0, 128, 0, 255)
|
||||||
|
|
@ -876,9 +896,13 @@ static void DrawSettingsPanel()
|
||||||
DrawContainer(settingsMin, settingsMax);
|
DrawContainer(settingsMin, settingsMax);
|
||||||
|
|
||||||
if (DrawCategories())
|
if (DrawCategories())
|
||||||
|
{
|
||||||
DrawConfigOptions();
|
DrawConfigOptions();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
ResetSelection();
|
ResetSelection();
|
||||||
|
}
|
||||||
|
|
||||||
// Pop clip rect from DrawContainer
|
// Pop clip rect from DrawContainer
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
|
|
@ -901,21 +925,21 @@ static void DrawInfoPanel()
|
||||||
// Thumbnail box
|
// Thumbnail box
|
||||||
drawList->AddRectFilled(clipRectMin, thumbnailMax, IM_COL32(0, 0, 0, 255));
|
drawList->AddRectFilled(clipRectMin, thumbnailMax, IM_COL32(0, 0, 0, 255));
|
||||||
|
|
||||||
if (g_selectedItem)
|
if (m_selectedItem)
|
||||||
{
|
{
|
||||||
auto desc = g_selectedItem->GetDescription();
|
auto desc = m_selectedItem->GetDescription();
|
||||||
|
|
||||||
if (g_inaccessibleReason)
|
if (m_inaccessibleReason)
|
||||||
{
|
{
|
||||||
desc = *g_inaccessibleReason;
|
desc = *m_inaccessibleReason;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Specialised description for resolution scale
|
// Specialised description for resolution scale
|
||||||
if (g_selectedItem->GetName() == "ResolutionScale")
|
if (m_selectedItem->GetName() == "ResolutionScale")
|
||||||
{
|
{
|
||||||
char buf[100];
|
char buf[100];
|
||||||
auto resScale = round(*(float*)g_selectedItem->GetValue() * 1000) / 1000;
|
auto resScale = round(*(float*)m_selectedItem->GetValue() * 1000) / 1000;
|
||||||
|
|
||||||
std::snprintf(buf, sizeof(buf), desc.c_str(),
|
std::snprintf(buf, sizeof(buf), desc.c_str(),
|
||||||
(int)((float)Window::s_width * resScale),
|
(int)((float)Window::s_width * resScale),
|
||||||
|
|
@ -924,13 +948,14 @@ static void DrawInfoPanel()
|
||||||
desc = buf;
|
desc = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
desc += "\n\n" + g_selectedItem->GetValueDescription();
|
desc += "\n\n" + m_selectedItem->GetValueDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size = Scale(26.0f);
|
auto size = Scale(26.0f);
|
||||||
|
|
||||||
drawList->AddText(
|
drawList->AddText
|
||||||
g_seuratFont,
|
(
|
||||||
|
m_seuratFont,
|
||||||
size,
|
size,
|
||||||
{ clipRectMin.x, thumbnailMax.y + size - 5.0f },
|
{ clipRectMin.x, thumbnailMax.y + size - 5.0f },
|
||||||
IM_COL32_WHITE,
|
IM_COL32_WHITE,
|
||||||
|
|
@ -944,6 +969,17 @@ static void DrawInfoPanel()
|
||||||
drawList->PopClipRect();
|
drawList->PopClipRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OptionsMenu::Init()
|
||||||
|
{
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
constexpr float FONT_SCALE = 2.0f;
|
||||||
|
|
||||||
|
m_seuratFont = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 26.0f * FONT_SCALE);
|
||||||
|
m_dfsogeistdFont = io.Fonts->AddFontFromFileTTF("DFSoGeiStd-W7.otf", 48.0f * FONT_SCALE);
|
||||||
|
m_newRodinFont = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-DB.otf", 20.0f * FONT_SCALE);
|
||||||
|
}
|
||||||
|
|
||||||
void OptionsMenu::Draw()
|
void OptionsMenu::Draw()
|
||||||
{
|
{
|
||||||
auto pInputState = SWA::CInputState::GetInstance();
|
auto pInputState = SWA::CInputState::GetInstance();
|
||||||
|
|
@ -953,7 +989,7 @@ void OptionsMenu::Draw()
|
||||||
|
|
||||||
// We've entered the menu now, no need to check this.
|
// We've entered the menu now, no need to check this.
|
||||||
if (pInputState->GetPadState().IsReleased(SWA::eKeyState_A))
|
if (pInputState->GetPadState().IsReleased(SWA::eKeyState_A))
|
||||||
g_isEnterKeyBuffered = false;
|
m_isEnterKeyBuffered = false;
|
||||||
|
|
||||||
g_callbackDataIndex = 0;
|
g_callbackDataIndex = 0;
|
||||||
|
|
||||||
|
|
@ -975,16 +1011,16 @@ void OptionsMenu::Open(bool isPause, SWA::EMenuType pauseMenuType)
|
||||||
|
|
||||||
s_pauseMenuType = pauseMenuType;
|
s_pauseMenuType = pauseMenuType;
|
||||||
|
|
||||||
g_appearTime = ImGui::GetTime();
|
m_appearTime = ImGui::GetTime();
|
||||||
g_categoryIndex = 0;
|
m_categoryIndex = 0;
|
||||||
g_categoryAnimMin = { 0.0f, 0.0f };
|
m_categoryAnimMin = { 0.0f, 0.0f };
|
||||||
g_categoryAnimMax = { 0.0f, 0.0f };
|
m_categoryAnimMax = { 0.0f, 0.0f };
|
||||||
g_selectedItem = nullptr;
|
m_selectedItem = nullptr;
|
||||||
|
|
||||||
/* Store button state so we can track it later
|
/* Store button state so we can track it later
|
||||||
and prevent the first item being selected. */
|
and prevent the first item being selected. */
|
||||||
if (SWA::CInputState::GetInstance()->GetPadState().IsDown(SWA::eKeyState_A))
|
if (SWA::CInputState::GetInstance()->GetPadState().IsDown(SWA::eKeyState_A))
|
||||||
g_isEnterKeyBuffered = true;
|
m_isEnterKeyBuffered = true;
|
||||||
|
|
||||||
ResetSelection();
|
ResetSelection();
|
||||||
|
|
||||||
|
|
@ -1006,5 +1042,5 @@ void OptionsMenu::Close()
|
||||||
|
|
||||||
bool OptionsMenu::CanClose()
|
bool OptionsMenu::CanClose()
|
||||||
{
|
{
|
||||||
return !g_lockedOnOption;
|
return !m_lockedOnOption;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "imgui_view.h"
|
|
||||||
#include <api/SWA.h>
|
#include <api/SWA.h>
|
||||||
|
|
||||||
struct OptionsMenu : ImGuiView
|
struct OptionsMenu
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline static bool s_isVisible = false;
|
inline static bool s_isVisible = false;
|
||||||
|
|
@ -11,8 +10,8 @@ public:
|
||||||
|
|
||||||
inline static SWA::EMenuType s_pauseMenuType;
|
inline static SWA::EMenuType s_pauseMenuType;
|
||||||
|
|
||||||
void Init() override;
|
static void Init();
|
||||||
void Draw() override;
|
static void Draw();
|
||||||
static void Open(bool isPause = false, SWA::EMenuType pauseMenuType = SWA::eMenuType_WorldMap);
|
static void Open(bool isPause = false, SWA::EMenuType pauseMenuType = SWA::eMenuType_WorldMap);
|
||||||
static void Close();
|
static void Close();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue