[skottie] Add SkottieSlide frame rate UI option

Also store fTimeBase as a double/ns, since uint/ms doesn't have enough
precision when setting progress manually.

Change-Id: Ic01a55cea5897dd8b43d2d54f4a98e08e7406af8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/259172
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
Florin Malita 2019-12-11 08:55:46 -05:00 committed by Skia Commit-Bot
parent b692ce4c63
commit 1bb3a6dae5
2 changed files with 45 additions and 13 deletions

View File

@ -145,7 +145,7 @@ void SkottieSlide::draw(SkCanvas* canvas) {
fAnimation->render(canvas, &dstR); fAnimation->render(canvas, &dstR);
// TODO: this does not capture GPU flush time! // TODO: this does not capture GPU flush time!
const auto frame_index = SkToSizeT(SkScalarRoundToInt(fCurrentFrame)); const auto frame_index = static_cast<size_t>(fCurrentFrame);
fFrameTimes[frame_index] = static_cast<float>((SkTime::GetNSecs() - t0) * 1e-6); fFrameTimes[frame_index] = static_cast<float>((SkTime::GetNSecs() - t0) * 1e-6);
} }
@ -178,23 +178,30 @@ void SkottieSlide::draw(SkCanvas* canvas) {
} }
bool SkottieSlide::animate(double nanos) { bool SkottieSlide::animate(double nanos) {
SkMSec msec = TimeUtils::NanosToMSec(nanos); if (!fTimeBase) {
if (fTimeBase == 0) {
// Reset the animation time. // Reset the animation time.
fTimeBase = msec; fTimeBase = nanos;
} }
if (fAnimation) { if (fAnimation) {
fInvalController.reset(); fInvalController.reset();
const auto frame_count = fAnimation->duration() * fAnimation->fps();
if (!fDraggingProgress) { if (!fDraggingProgress) {
// Clock-driven progress: update current frame. // Clock-driven progress: update current frame.
const double t_sec = (msec - fTimeBase) / 1000.0; const double t_sec = (nanos - fTimeBase) * 1e-9;
fCurrentFrame = std::fmod(t_sec, fAnimation->duration()) * fAnimation->fps(); fCurrentFrame = std::fmod(t_sec * fAnimation->fps(), frame_count);
} else { } else {
// Slider-driven progress: update the time origin. // Slider-driven progress: update the time origin.
fTimeBase = TimeUtils::NanosToMSec(nanos) fTimeBase = nanos - fCurrentFrame / fAnimation->fps() * 1e9;
- static_cast<SkMSec>(fCurrentFrame / fAnimation->fps() * 1000); }
// Sanitize and rate-lock the current frame.
fCurrentFrame = SkTPin<float>(fCurrentFrame, 0.0f, frame_count - 1);
if (fFrameRate > 0) {
const auto fps_scale = fFrameRate / fAnimation->fps();
fCurrentFrame = std::trunc(fCurrentFrame * fps_scale) / fps_scale;
} }
fAnimation->seekFrame(fCurrentFrame); fAnimation->seekFrame(fCurrentFrame);
@ -230,14 +237,26 @@ bool SkottieSlide::onMouse(SkScalar x, SkScalar y, skui::InputState state, skui:
} }
SkRect SkottieSlide::UIArea() const { SkRect SkottieSlide::UIArea() const {
static constexpr float kUIHeight = 150.0f; static constexpr float kUIHeight = 120.0f;
return SkRect::MakeXYWH(0, fWinSize.height() - kUIHeight, fWinSize.width(), kUIHeight); return SkRect::MakeXYWH(0, fWinSize.height() - kUIHeight, fWinSize.width(), kUIHeight);
} }
void SkottieSlide::renderUI() { void SkottieSlide::renderUI() {
static constexpr auto kUI_opacity = 0.35f, static constexpr auto kUI_opacity = 0.35f,
kUI_hist_height = 50.0f; kUI_hist_height = 50.0f,
kUI_fps_width = 100.0f;
auto add_frame_rate_option = [this](const char* label, double rate) {
const auto is_selected = (fFrameRate == rate);
if (ImGui::Selectable(label, is_selected)) {
fFrameRate = rate;
fFrameRateLabel = label;
}
if (is_selected) {
ImGui::SetItemDefaultFocus();
}
};
ImGui::SetNextWindowBgAlpha(kUI_opacity); ImGui::SetNextWindowBgAlpha(kUI_opacity);
if (ImGui::Begin("Skottie Controls", nullptr, ImGuiWindowFlags_NoDecoration | if (ImGui::Begin("Skottie Controls", nullptr, ImGuiWindowFlags_NoDecoration |
@ -251,12 +270,23 @@ void SkottieSlide::renderUI() {
ImGui::SetWindowSize(ImVec2(ui_area.width(), ui_area.height())); ImGui::SetWindowSize(ImVec2(ui_area.width(), ui_area.height()));
ImGui::PushItemWidth(-1); ImGui::PushItemWidth(-1);
ImGui::PlotHistogram("", fFrameTimes.data(), fFrameTimes.size(), ImGui::PlotHistogram("", fFrameTimes.data(), fFrameTimes.size(),
0, nullptr, FLT_MAX, FLT_MAX, ImVec2(0, kUI_hist_height)); 0, nullptr, FLT_MAX, FLT_MAX, ImVec2(0, kUI_hist_height));
ImGui::SliderFloat("", &fCurrentFrame, 0, fAnimation->duration() * fAnimation->fps() - 1); ImGui::SliderFloat("", &fCurrentFrame, 0, fAnimation->duration() * fAnimation->fps() - 1);
fDraggingProgress = ImGui::IsItemActive(); fDraggingProgress = ImGui::IsItemActive();
ImGui::PopItemWidth();
ImGui::PushItemWidth(kUI_fps_width);
if (ImGui::BeginCombo("FPS", fFrameRateLabel)) {
add_frame_rate_option("", 0.0);
add_frame_rate_option("Native", fAnimation->fps());
add_frame_rate_option( "1", 1.0);
add_frame_rate_option("15", 15.0);
add_frame_rate_option("24", 24.0);
add_frame_rate_option("30", 30.0);
add_frame_rate_option("60", 60.0);
ImGui::EndCombo();
}
ImGui::PopItemWidth(); ImGui::PopItemWidth();
} }
ImGui::End(); ImGui::End();

View File

@ -46,7 +46,9 @@ private:
sksg::InvalidationController fInvalController; sksg::InvalidationController fInvalController;
std::vector<float> fFrameTimes; std::vector<float> fFrameTimes;
SkSize fWinSize = SkSize::MakeEmpty(); SkSize fWinSize = SkSize::MakeEmpty();
SkMSec fTimeBase = 0; double fTimeBase = 0,
fFrameRate = 0;
const char* fFrameRateLabel = nullptr;
float fCurrentFrame = 0; float fCurrentFrame = 0;
bool fShowAnimationInval = false, bool fShowAnimationInval = false,
fShowAnimationStats = false, fShowAnimationStats = false,