diff --git a/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp b/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp index 0067187a1b8f..a1b4d5b1865e 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp @@ -40,7 +40,6 @@ namespace rsx frame.back_color.g = 0.250980f; frame.back_color.b = 0.247059f; frame.back_color.a = 0.88f; - image.set_pos(78, 64); image.set_size(53, 53); @@ -54,9 +53,9 @@ namespace rsx sliding_animation.duration = 1.5f; sliding_animation.type = animation_type::ease_in_out_cubic; - sliding_animation.current = { -f32(frame.w), 0, 0 }; - sliding_animation.end = { 0, 0, 0}; - sliding_animation.active = true; + + // Make the fade animation a bit shorter to see the trophy better. + fade_animation.duration = 1.0f; } void trophy_notification::update() @@ -75,11 +74,14 @@ namespace rsx return; } - if (((t - creation_time) / 1000) > 5000) + const u64 time_since_creation = ((t - creation_time) / 1000); + u64 end_animation_begin = 5000; + + if (time_since_creation > end_animation_begin) { if (!sliding_animation.active) { - sliding_animation.end = { -f32(frame.w), 0, 0 }; + sliding_animation.end = { -f32(frame.x + frame.w), 0, 0 }; sliding_animation.on_finish = [this] { s_trophy_semaphore.release(); @@ -90,10 +92,32 @@ namespace rsx } } + // Match both animation ends based on their durations + if (sliding_animation.duration > fade_animation.duration) + { + end_animation_begin += static_cast((sliding_animation.duration - fade_animation.duration) * 1000); + } + + if (time_since_creation > end_animation_begin) + { + if (!fade_animation.active) + { + fade_animation.current = color4f(1.f); + fade_animation.end = color4f(0.f); + + fade_animation.active = true; + } + } + if (sliding_animation.active) { sliding_animation.update(rsx::get_current_renderer()->vblank_count); } + + if (fade_animation.active) + { + fade_animation.update(rsx::get_current_renderer()->vblank_count); + } } compiled_resource trophy_notification::get_compiled() @@ -108,6 +132,8 @@ namespace rsx result.add(text_view.get_compiled()); sliding_animation.apply(result); + fade_animation.apply(result); + return result; } @@ -140,7 +166,18 @@ namespace rsx u16 margin_sz = 9; frame.w = margin_sz * 3 + image.w + text_view.w; + sliding_animation.current = { -f32(frame.x + frame.w), 0, 0 }; + sliding_animation.end = { 0, 0, 0 }; + sliding_animation.active = true; + + fade_animation.current = color4f(0.f); + fade_animation.end = color4f(1.f); + fade_animation.active = true; + visible = true; + + Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/trophy.wav"); + return CELL_OK; } } // namespace overlays diff --git a/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.h b/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.h index ff17533b6035..e52c37d8d3b7 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.h @@ -19,6 +19,7 @@ namespace rsx std::unique_ptr icon_info; animation_translate sliding_animation; + animation_color_interpolate fade_animation; public: trophy_notification(); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 2ebfff999a63..f1fffd8155b1 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -80,6 +80,7 @@ struct EmuCallbacks std::function()> get_trophy_notification_dialog; std::function get_localized_string; std::function get_localized_u32string; + std::function play_sound; std::string(*resolve_path)(std::string_view) = nullptr; // Resolve path using Qt }; diff --git a/rpcs3/headless_application.cpp b/rpcs3/headless_application.cpp index 591f6ee270d9..41c2e35e025f 100644 --- a/rpcs3/headless_application.cpp +++ b/rpcs3/headless_application.cpp @@ -110,6 +110,8 @@ void headless_application::InitializeCallbacks() callbacks.get_localized_string = [](localized_string_id, const char*) -> std::string { return {}; }; callbacks.get_localized_u32string = [](localized_string_id, const char*) -> std::u32string { return {}; }; + callbacks.play_sound = [](const std::string&){}; + callbacks.resolve_path = [](std::string_view sv) { return QFileInfo(QString::fromUtf8(sv.data(), static_cast(sv.size()))).canonicalFilePath().toStdString(); diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 0b0bb54ef969..5e65b09e7d4a 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -412,6 +413,17 @@ void gui_application::InitializeCallbacks() return localized_emu::get_u32string(id, args); }; + callbacks.play_sound = [](const std::string& path) + { + Emu.CallAfter([path]() + { + if (fs::is_file(path)) + { + QSound::play(qstr(path)); + } + }); + }; + callbacks.resolve_path = [](std::string_view sv) { return QFileInfo(QString::fromUtf8(sv.data(), static_cast(sv.size()))).canonicalFilePath().toStdString(); diff --git a/rpcs3/rpcs3qt/trophy_notification_helper.cpp b/rpcs3/rpcs3qt/trophy_notification_helper.cpp index 7eaa431e8071..c81ee8d9c448 100644 --- a/rpcs3/rpcs3qt/trophy_notification_helper.cpp +++ b/rpcs3/rpcs3qt/trophy_notification_helper.cpp @@ -5,6 +5,8 @@ #include "../Emu/System.h" #include "../Emu/RSX/Overlays/overlay_trophy_notification.h" +#include "Utilities/File.h" + s32 trophy_notification_helper::ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector& trophy_icon_buffer) { if (auto manager = g_fxo->try_get()) @@ -26,6 +28,8 @@ s32 trophy_notification_helper::ShowTrophyNotification(const SceNpTrophyDetails& // Move notification to upper lefthand corner trophy_notification->move(m_game_window->mapToGlobal(QPoint(0, 0))); trophy_notification->show(); + + Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/trophy.wav"); }); return 0;