From 49df804d1bdcc3b6c26166c0c6141f6a894f8562 Mon Sep 17 00:00:00 2001 From: KamFretoZ <14798312+kamfretoz@users.noreply.github.com> Date: Fri, 12 Jan 2024 22:04:55 +0700 Subject: [PATCH] FSUI: Add Recording Indicator and Time --- 3rdparty/include/IconsFontAwesome5.h | 1 + bin/resources/fonts/fa-solid-900.ttf | Bin 207040 -> 207104 bytes pcsx2/GS/GSCapture.cpp | 11 ++++++ pcsx2/GS/GSCapture.h | 2 ++ pcsx2/ImGui/ImGuiManager.cpp | 2 +- pcsx2/ImGui/ImGuiOverlays.cpp | 48 ++++++++++++++++++++++----- 6 files changed, 55 insertions(+), 9 deletions(-) diff --git a/3rdparty/include/IconsFontAwesome5.h b/3rdparty/include/IconsFontAwesome5.h index 67cddab501a82..1a78a9a130315 100644 --- a/3rdparty/include/IconsFontAwesome5.h +++ b/3rdparty/include/IconsFontAwesome5.h @@ -706,6 +706,7 @@ #define ICON_FA_RANDOM "\xef\x81\xb4" // U+f074 #define ICON_FA_RECEIPT "\xef\x95\x83" // U+f543 #define ICON_FA_RECORD_VINYL "\xef\xa3\x99" // U+f8d9 +#define ICON_FA_RECORDING "\xef\xa3\x9a" // U+f8da #define ICON_FA_RECYCLE "\xef\x86\xb8" // U+f1b8 #define ICON_FA_REDO "\xef\x80\x9e" // U+f01e #define ICON_FA_REDO_ALT "\xef\x8b\xb9" // U+f2f9 diff --git a/bin/resources/fonts/fa-solid-900.ttf b/bin/resources/fonts/fa-solid-900.ttf index f40fa9fc9a8f7f18ba5f6c89cf692d38b5171d53..c5a68d3dc3a28bdf244acf20978d2bc36393e64e 100644 GIT binary patch delta 553 zcmX?bk*DDjPdx)80|NsuLjwadLx7uGi0`~Y#+eMv8c%?tGVU&}ZhQv3kAeI-K)#26 zu)dLTdsqSk17ie`pOBoJSnye%J%E8hu!Dg?KrB76xZwYPph?UcQ-Jau={c2Y9vif? z85j&p7?=)}WTYmhC_F5l4V1eB#AX>8sr890&TJk)14V!WDjB&Y6;~seS%CZ<3=I4i za`KZCSv53m7#I{60QpyP6DtZ>!Wa{P@)kh#3VDgSsmdGl&u{aUftv}a4QRW{lSLr<;U%UMHzqNfvws1pWd5?* zj?r0wnSnuca)Y2aFAvZspwN+FVB!5Rd5Pd<##@^!gyt{;oyYZMvV_PfCazVRpNOpB zVqyNs{AqKK{A)(W&yyd@8*g5%xSOAC{}zy+H)j}bGMjuT^ZRDO%n|{{2bW?ap{4h$F*Gb1q(HYL%nLtR~m;z2~$_HQ4U zzOypFV33>~C@jLn{AD}accy3TOe{~fzxl_Ms;OC;m+5BV;>ezySd>_nmn|}dYb*hZ%DB6@x^WqCeg*OqfP5$a zV0|Ow_AnruF#^a>NX|_x_~rUzB?E(C3j>3IP}mbW;;e_ z0p$je6wntCECUW920jj;2q>&%7+84UOkN>)nepc48lgFiEZh=YpC`+RoB|rX`Gv>| zuFX^AUo$d(n*31Sc=Kk(-TXk0Z!R(1WXAFT|NnDLj*Oc(>t!ShGTz@jsq(NN^H-+U z=7}K_`1}7q0PN3?{{R30 diff --git a/pcsx2/GS/GSCapture.cpp b/pcsx2/GS/GSCapture.cpp index 73c4e9cc34945..8a6995dedbe67 100644 --- a/pcsx2/GS/GSCapture.cpp +++ b/pcsx2/GS/GSCapture.cpp @@ -19,6 +19,7 @@ #include "common/SmallString.h" #include "common/StringUtil.h" #include "common/Threading.h" +#include "common/Timer.h" #include #include @@ -160,6 +161,7 @@ namespace GSCapture static std::mutex s_lock; static GSVector2i s_size{}; static std::string s_filename; + static Common::Timer s_capture_start_time; static std::atomic_bool s_capturing{false}; static std::atomic_bool s_encoding_error{false}; @@ -806,6 +808,9 @@ bool GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float lock.unlock(); Host::OnCaptureStarted(s_filename); + + s_capture_start_time.Reset(); + return true; } @@ -1339,6 +1344,12 @@ bool GSCapture::IsCapturingAudio() return (s_audio_stream != nullptr); } +TinyString GSCapture::GetElapsedTime() +{ + const u32 seconds = static_cast(s_capture_start_time.GetTimeSeconds()); + return TinyString::from_fmt("{:02d}:{:02d}:{:02d}", seconds / 3600, (seconds % 3600) / 60, seconds % 60); +} + const Threading::ThreadHandle& GSCapture::GetEncoderThreadHandle() { return s_encoder_thread; diff --git a/pcsx2/GS/GSCapture.h b/pcsx2/GS/GSCapture.h index 3c7d420fca7f0..05b0a7605d77c 100644 --- a/pcsx2/GS/GSCapture.h +++ b/pcsx2/GS/GSCapture.h @@ -6,6 +6,7 @@ #include #include +#include "common/SmallString.h" #include "GSVector.h" namespace Threading @@ -26,6 +27,7 @@ namespace GSCapture bool IsCapturing(); bool IsCapturingVideo(); bool IsCapturingAudio(); + TinyString GetElapsedTime(); const Threading::ThreadHandle& GetEncoderThreadHandle(); GSVector2i GetSize(); std::string GetNextCaptureFileName(); diff --git a/pcsx2/ImGui/ImGuiManager.cpp b/pcsx2/ImGui/ImGuiManager.cpp index ad7cfa8870d5e..dda32b156cfa6 100644 --- a/pcsx2/ImGui/ImGuiManager.cpp +++ b/pcsx2/ImGui/ImGuiManager.cpp @@ -482,7 +482,7 @@ ImFont* ImGuiManager::AddFixedFont(float size) bool ImGuiManager::AddIconFonts(float size) { // clang-format off - static constexpr ImWchar range_fa[] = { 0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf01c,0xf01c,0xf021,0xf021,0xf023,0xf023,0xf025,0xf025,0xf027,0xf028,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03d,0xf04a,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf059,0xf059,0xf05e,0xf05e,0xf063,0xf063,0xf065,0xf065,0xf067,0xf067,0xf06a,0xf06a,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf085,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c9,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f1,0xf0f1,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf110,0xf110,0xf119,0xf119,0xf11b,0xf11c,0xf121,0xf121,0xf133,0xf133,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1c9,0xf1c9,0xf1dd,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf242,0xf242,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2d0,0xf2d0,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf2f5,0xf2f5,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf466,0xf466,0xf500,0xf500,0xf517,0xf517,0xf51f,0xf51f,0xf543,0xf543,0xf545,0xf545,0xf547,0xf548,0xf552,0xf552,0xf56d,0xf56d,0xf5a2,0xf5a2,0xf5e7,0xf5e7,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf756,0xf756,0xf7c2,0xf7c2,0xf807,0xf807,0xf815,0xf815,0xf818,0xf818,0xf84c,0xf84c,0xf8cc,0xf8cc,0xf8d9,0xf8d9,0x0,0x0 }; + static constexpr ImWchar range_fa[] = { 0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf01c,0xf01c,0xf021,0xf021,0xf023,0xf023,0xf025,0xf025,0xf027,0xf028,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03d,0xf04a,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf059,0xf059,0xf05e,0xf05e,0xf063,0xf063,0xf065,0xf065,0xf067,0xf067,0xf06a,0xf06a,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf085,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c9,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f1,0xf0f1,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf110,0xf110,0xf119,0xf119,0xf11b,0xf11c,0xf121,0xf121,0xf133,0xf133,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1c9,0xf1c9,0xf1dd,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf242,0xf242,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2d0,0xf2d0,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf2f5,0xf2f5,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf466,0xf466,0xf500,0xf500,0xf517,0xf517,0xf51f,0xf51f,0xf543,0xf543,0xf545,0xf545,0xf547,0xf548,0xf552,0xf552,0xf56d,0xf56d,0xf5a2,0xf5a2,0xf5e7,0xf5e7,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf756,0xf756,0xf7c2,0xf7c2,0xf807,0xf807,0xf815,0xf815,0xf818,0xf818,0xf84c,0xf84c,0xf8cc,0xf8cc,0xf8da,0xf8da,0x0,0x0 }; static constexpr ImWchar range_pf[] = { 0x2198,0x2199,0x219e,0x21a1,0x21b0,0x21b3,0x21ba,0x21c3,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21f3,0x21f3,0x21f7,0x21f8,0x21fa,0x21fb,0x227a,0x227d,0x22bf,0x22c8,0x23b2,0x23b4,0x23f4,0x23f7,0x2427,0x243a,0x243c,0x243c,0x2443,0x2443,0x2460,0x246b,0x24f5,0x24fd,0x24ff,0x24ff,0x278a,0x278e,0xe001,0xe001,0xff21,0xff3a,0x0,0x0 }; // clang-format on diff --git a/pcsx2/ImGui/ImGuiOverlays.cpp b/pcsx2/ImGui/ImGuiOverlays.cpp index 58a1c681c687b..ce50c56802044 100644 --- a/pcsx2/ImGui/ImGuiOverlays.cpp +++ b/pcsx2/ImGui/ImGuiOverlays.cpp @@ -51,6 +51,7 @@ namespace ImGuiManager static void DrawSettingsOverlay(); static void DrawInputsOverlay(); static void DrawInputRecordingOverlay(float& position_y); + static void DrawVideoCaptureOverlay(float& position_y); } // namespace ImGuiManager static std::tuple GetMinMax(std::span values) @@ -629,24 +630,54 @@ void ImGuiManager::DrawInputRecordingOverlay(float& position_y) dl->AddText(font, font->FontSize, ImVec2(GetWindowWidth() - margin - text_size.x, position_y), color, (text)); \ position_y += text_size.y + spacing; \ } while (0) - // TODO - icon list that would be nice to add - // - 'video' when screen capturing - if (g_InputRecording.isActive()) + if (g_InputRecording.isActive() && !FullscreenUI::HasActiveWindow()) { // Status Indicators if (g_InputRecording.getControls().isRecording()) { - DRAW_LINE(standard_font, fmt::format("{} Recording", ICON_FA_RECORD_VINYL).c_str(), IM_COL32(255, 0, 0, 255)); + DRAW_LINE(standard_font, TinyString::from_fmt("{} Recording Input", ICON_FA_RECORDING).c_str(), IM_COL32(255, 0, 0, 255)); } else { - DRAW_LINE(standard_font, fmt::format("{} Replaying", ICON_FA_PLAY).c_str(), IM_COL32(97, 240, 84, 255)); + DRAW_LINE(standard_font, TinyString::from_fmt("{} Replaying", ICON_FA_PLAY).c_str(), IM_COL32(97, 240, 84, 255)); } // Input Recording Metadata - DRAW_LINE(fixed_font, fmt::format("Input Recording Active: {}", g_InputRecording.getData().getFilename()).c_str(), IM_COL32(117, 255, 241, 255)); - DRAW_LINE(fixed_font, fmt::format("Frame: {}/{} ({})", g_InputRecording.getFrameCounter() + 1, g_InputRecording.getData().getTotalFrames(), g_FrameCount).c_str(), IM_COL32(117, 255, 241, 255)); - DRAW_LINE(fixed_font, fmt::format("Undo Count: {}", g_InputRecording.getData().getUndoCount()).c_str(), IM_COL32(117, 255, 241, 255)); + DRAW_LINE(fixed_font, TinyString::from_fmt("Input Recording Active: {}", g_InputRecording.getData().getFilename()).c_str(), IM_COL32(117, 255, 241, 255)); + DRAW_LINE(fixed_font, TinyString::from_fmt("Frame: {}/{} ({})", g_InputRecording.getFrameCounter() + 1, g_InputRecording.getData().getTotalFrames(), g_FrameCount).c_str(), IM_COL32(117, 255, 241, 255)); + DRAW_LINE(fixed_font, TinyString::from_fmt("Undo Count: {}", g_InputRecording.getData().getUndoCount()).c_str(), IM_COL32(117, 255, 241, 255)); + } + +#undef DRAW_LINE +} + +void ImGuiManager::DrawVideoCaptureOverlay(float& position_y) +{ + const float scale = ImGuiManager::GetGlobalScale(); + const float shadow_offset = std::ceil(1.0f * scale); + const float margin = std::ceil(10.0f * scale); + const float spacing = std::ceil(5.0f * scale); + position_y += margin; + + ImFont* const standard_font = ImGuiManager::GetStandardFont(); + + ImDrawList* dl = ImGui::GetBackgroundDrawList(); + ImVec2 text_size; + +#define DRAW_LINE(font, text, color) \ + do \ + { \ + text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits::max(), -1.0f, (text), nullptr, nullptr); \ + dl->AddText(font, font->FontSize, \ + ImVec2(GetWindowWidth() - margin - text_size.x + shadow_offset, position_y + shadow_offset), \ + IM_COL32(0, 0, 0, 100), (text)); \ + dl->AddText(font, font->FontSize, ImVec2(GetWindowWidth() - margin - text_size.x, position_y), color, (text)); \ + position_y += text_size.y + spacing; \ + } while (0) + + if (GSCapture::IsCapturing() && !FullscreenUI::HasActiveWindow()) + { + DRAW_LINE(standard_font, TinyString::from_fmt("{} {}", ICON_FA_RECORDING, GSCapture::GetElapsedTime()).c_str(), IM_COL32(255, 0, 0, 255)); } #undef DRAW_LINE @@ -1041,6 +1072,7 @@ void SaveStateSelectorUI::ShowSlotOSDMessage() void ImGuiManager::RenderOverlays() { float position_y = 0; + DrawVideoCaptureOverlay(position_y); DrawInputRecordingOverlay(position_y); DrawPerformanceOverlay(position_y); DrawSettingsOverlay();