From 5bace118a74e74dbb2b5d1ed9a7e73d5ed6a5b34 Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Mon, 6 Jan 2020 19:56:46 +0200 Subject: [PATCH] overlays: Redesign animation system (add easing functions, fix bugs) Instead of speed, direction and distance, the user now specifies start/end offsets and how much time the transition should take. Fixes: - Stuttering caused from framerate estimation. - An edge case where animations would go over their supposed limit. Adds: - The ability to specify arbitrary easing functions for the animations - Implemented quadratic ease in and ease out and cubic ease in/out. - Usage of cubic ease in/out in the trophy notification --- rpcs3/Emu/RSX/Overlays/overlay_animation.cpp | 66 +++++++++++-------- rpcs3/Emu/RSX/Overlays/overlay_animation.h | 36 ++++++---- .../Overlays/overlay_trophy_notification.cpp | 14 ++-- 3 files changed, 68 insertions(+), 48 deletions(-) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_animation.cpp b/rpcs3/Emu/RSX/Overlays/overlay_animation.cpp index 80f25ad398..ec429dad6a 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_animation.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_animation.cpp @@ -1,19 +1,22 @@ -#include "stdafx.h" +#include "stdafx.h" +#pragma optimize("", off) #include "overlay_animation.h" #include "overlay_controls.h" +#include + namespace rsx { namespace overlays { void animation_translate::apply(compiled_resource& resource) { - if (progress == vector3i(0, 0, 0)) + if (!active) { return; } - const vertex delta = { static_cast(progress.x), static_cast(progress.y), static_cast(progress.z), 0.f }; + const vertex delta = { current.x, current.y, current.z, 0.f }; for (auto& cmd : resource.draw_commands) { for (auto& v : cmd.verts) @@ -23,49 +26,54 @@ namespace rsx } } - void animation_translate::update(u64 t) + void animation_translate::update(u64 frame) { if (!active) { return; } - if (time == 0) + if (frame_start == 0) { - time = t; + start = current; + frame_start = frame; + frame_end = u64(frame + duration * g_cfg.video.vblank_rate); + return; } - const u64 delta = (t - time); - const u64 frames = delta / 16667; - - if (frames) + if (frame >= frame_end) { - const int mag = frames * speed; - const vector3i new_progress = progress + direction * mag; - const auto d = new_progress.distance(progress_limit); - - if (distance >= 0) - { - if (d > distance) - { - // Exit condition - finish(); - return; - } - } - - progress = new_progress; - distance = d; - time = t; + // Exit condition + finish(); + return; } + + f32 t = f32(frame - frame_start) / (frame_end - frame_start); + + switch (type) { + case animation_type::linear: + break; + case animation_type::ease_in_quad: + t = t * t; + break; + case animation_type::ease_out_quad: + t = t * (2.0 - t); + break; + case animation_type::ease_in_out_cubic: + t = t > 0.5 ? 4.0 * std::pow((t - 1.0), 3.0) + 1.0 : 4.0 * std::pow(t, 3.0); + break; + } + + current = (1.f - t) * start + t * end; } void animation_translate::finish() { active = false; - distance = -1; - time = 0; + frame_start = 0; + frame_end = 0; + current = end; // Snap current to limit in case we went over if (on_finish) { diff --git a/rpcs3/Emu/RSX/Overlays/overlay_animation.h b/rpcs3/Emu/RSX/Overlays/overlay_animation.h index 5170fb5e89..d3d842e03e 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_animation.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_animation.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Utilities/types.h" #include "Utilities/geometry.h" #include "overlay_utils.h" @@ -9,28 +9,40 @@ namespace rsx { struct compiled_resource; + enum class animation_type + { + linear, + ease_in_quad, + ease_out_quad, + ease_in_out_cubic, + }; + struct animation_base { bool active = false; + animation_type type { animation_type::linear }; + + std::function on_finish; virtual void apply(compiled_resource&) = 0; - virtual void update(u64 t) = 0; + virtual void update(u64 frame) = 0; }; struct animation_translate : animation_base { - vector3i direction{}; - vector3i progress{}; - vector3i progress_limit{}; - - std::function on_finish; - - int speed = 0; - int distance = -1; - u64 time = 0; + private: + vector3f start{}; // Set `current` instead of this + // NOTE: Necessary because update() is called after rendering, + // resulting in one frame of incorrect translation + u64 frame_start = 0; + u64 frame_end = 0; + public: + vector3f current{}; + vector3f end{}; + f32 duration{}; // in seconds void apply(compiled_resource& data) override; - void update(u64 t) override; + void update(u64 frame) override; void finish(); }; } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp b/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp index fa9e265516..a3348e498b 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "overlays.h" +#include "Emu/RSX/RSXThread.h" namespace rsx { @@ -46,10 +47,10 @@ namespace rsx text_view.align_text(overlay_element::text_align::center); text_view.back_color.a = 0.f; - sliding_animation.direction = { 1, 0, 0 }; - sliding_animation.speed = 10; - sliding_animation.progress = { -int(frame.w), 0, 0 }; - sliding_animation.progress_limit = { 0, 0, 0}; + sliding_animation.duration = 1.5; + 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; } @@ -73,8 +74,7 @@ namespace rsx { if (!sliding_animation.active) { - sliding_animation.direction.x = -1; - sliding_animation.progress_limit = { -int(frame.w), 0, 0 }; + sliding_animation.end = { -f32(frame.w), 0, 0 }; sliding_animation.on_finish = [this] { s_trophy_semaphore.release(); @@ -87,7 +87,7 @@ namespace rsx if (sliding_animation.active) { - sliding_animation.update(t); + sliding_animation.update(rsx::get_current_renderer()->vblank_count); } }