diff --git a/rpcs3/Emu/RSX/Overlays/overlay_animation.cpp b/rpcs3/Emu/RSX/Overlays/overlay_animation.cpp index 1f0ff7a237..c98cb43ee7 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_animation.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_animation.cpp @@ -10,7 +10,17 @@ namespace rsx void animation_base::begin_animation(u64 frame) { frame_start = frame; - frame_end = u64(frame + duration * g_cfg.video.vblank_rate); + frame_end = frame + get_duration_in_frames(); + } + + u64 animation_base::get_duration_in_frames() const + { + return u64(duration * g_cfg.video.vblank_rate); + } + + u64 animation_base::get_remaining_frames(u64 frame) const + { + return frame >= frame_end ? 0 : (frame_end - frame); } f32 animation_base::get_progress_ratio(u64 frame) const @@ -39,11 +49,16 @@ namespace rsx return t; } - void animation_translate::reset(u64 frame) + void animation_translate::reset(u64 start_frame) { active = false; current = start; - frame_start = 0; + frame_start = start_frame; + + if (frame_start > 0) + { + frame_end = frame_start + get_duration_in_frames(); + } } void animation_translate::apply(compiled_resource& resource) @@ -101,11 +116,16 @@ namespace rsx } } - void animation_color_interpolate::reset(u64 frame) + void animation_color_interpolate::reset(u64 start_frame) { active = false; current = start; - frame_start = 0; + frame_start = start_frame; + + if (frame_start > 0) + { + frame_end = frame_start + get_duration_in_frames(); + } } void animation_color_interpolate::apply(compiled_resource& data) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_animation.h b/rpcs3/Emu/RSX/Overlays/overlay_animation.h index d62e880ccf..40bd581b76 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_animation.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_animation.h @@ -42,8 +42,11 @@ namespace rsx std::function on_finish; + u64 get_duration_in_frames() const; + u64 get_remaining_frames(u64 frame) const; + virtual void apply(compiled_resource&) = 0; - virtual void reset(u64 frame) = 0; + virtual void reset(u64 start_frame) = 0; virtual void update(u64 frame) = 0; }; @@ -58,7 +61,7 @@ namespace rsx vector3f end{}; void apply(compiled_resource& data) override; - void reset(u64 frame) override; + void reset(u64 start_frame = 0) override; void update(u64 frame) override; void finish(); }; @@ -73,7 +76,7 @@ namespace rsx color4f end{}; void apply(compiled_resource& data) override; - void reset(u64 frame) override; + void reset(u64 start_frame = 0) override; void update(u64 frame) override; void finish(); }; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp index 65f464c626..05d2daa2b6 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp @@ -123,10 +123,13 @@ namespace rsx if (m_fade_in_animation.active) { + // We are fading in. m_fade_in_animation.update(rsx::get_current_renderer()->vblank_count); } else if (time + u64(m_fade_out_animation.duration * 1'000'000) > get_expiration()) { + // We are fading out. + // Only activate the animation if the message hasn't expired yet (prevents glitches afterwards). if (time <= get_expiration()) { @@ -137,7 +140,19 @@ namespace rsx } else if (m_fade_out_animation.active) { - m_fade_out_animation.reset(rsx::get_current_renderer()->vblank_count); + // We are fading out, but the expiration was extended. + + // Reset the fade in animation to the state of the fade out animation to prevent opacity pop. + const usz current_frame = rsx::get_current_renderer()->vblank_count; + const f32 fade_out_progress = static_cast(m_fade_out_animation.get_remaining_frames(current_frame)) / static_cast(m_fade_out_animation.get_duration_in_frames()); + const u64 fade_in_frames_done = u64(fade_out_progress * m_fade_in_animation.get_duration_in_frames()); + + m_fade_in_animation.reset(current_frame - fade_in_frames_done); + m_fade_in_animation.active = true; + m_fade_in_animation.update(current_frame); + + // Reset the fade out animation. + m_fade_out_animation.reset(); } m_processed = true;