[skottie] Add transform tracking to SkottieSlide

Add UI options to select a named transform for tracking, and render a
decoration to highlight the transformed origin.

Change-Id: I2a51278150e7098034e1f6e00b268fce69558b44
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/531551
Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@google.com>
This commit is contained in:
Florin Malita 2022-04-20 11:04:21 -04:00 committed by SkCQ
parent 628d9278b6
commit ec8c595b9f
3 changed files with 143 additions and 11 deletions

View File

@ -257,8 +257,10 @@ generated_cc_atom(
"//include/core:SkCanvas_hdr",
"//include/core:SkFont_hdr",
"//include/core:SkTime_hdr",
"//include/private:SkNoncopyable_hdr",
"//include/private:SkTPin_hdr",
"//modules/audioplayer:SkAudioPlayer_hdr",
"//modules/skottie/include:SkottieProperty_hdr",
"//modules/skottie/include:Skottie_hdr",
"//modules/skottie/utils:SkottieUtils_hdr",
"//modules/skresources/include:SkResources_hdr",

View File

@ -12,15 +12,18 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkFont.h"
#include "include/core/SkTime.h"
#include "include/private/SkNoncopyable.h"
#include "include/private/SkTPin.h"
#include "modules/audioplayer/SkAudioPlayer.h"
#include "modules/skottie/include/Skottie.h"
#include "modules/skottie/include/SkottieProperty.h"
#include "modules/skottie/utils/SkottieUtils.h"
#include "modules/skresources/include/SkResources.h"
#include "src/utils/SkOSPath.h"
#include "tools/timer/TimeUtils.h"
#include <cmath>
#include <vector>
#include "imgui.h"
@ -74,8 +77,120 @@ private:
using INHERITED = skresources::ResourceProviderProxyBase;
};
class Decorator : public SkNoncopyable {
public:
virtual ~Decorator() = default;
virtual void render(SkCanvas*) = 0;
};
class SimpleMarker final : public Decorator {
public:
~SimpleMarker() override = default;
static std::unique_ptr<Decorator> Make() { return std::make_unique<SimpleMarker>(); }
void render(SkCanvas* canvas) override {
SkPaint p;
p.setAntiAlias(true);
p.setColor(SK_ColorGREEN);
canvas->drawCircle(0, 0, 5, p);
p.setColor(SK_ColorRED);
p.setStrokeWidth(1.5f);
canvas->drawLine(-10, 0, 10, 0, p);
canvas->drawLine(0, -10, 0, 10, p);
}
};
static const struct DecoratorRec {
const char* fName;
std::unique_ptr<Decorator>(*fFactory)();
} kDecorators[] = {
{ "Simple marker", SimpleMarker::Make }
};
} // namespace
class SkottieSlide::TransformTracker : public skottie::PropertyObserver {
public:
void renderUI() {
if (ImGui::Begin("Transform Tracker", nullptr)) {
if (ImGui::BeginCombo("Transform", fTransformSelect
? std::get<0>(*fTransformSelect).c_str()
: nullptr)) {
if (ImGui::Selectable("(none)", true)) {
fTransformSelect = nullptr;
}
for (const auto& entry : fTransforms) {
const auto* transform_name = std::get<0>(entry).c_str();
if (ImGui::Selectable(transform_name, false)) {
if (!fTransformSelect ||
transform_name != std::get<0>(*fTransformSelect).c_str()) {
fTransformSelect = &entry;
// Reset the decorator on transform change.
fDecorator = fDecoratorSelect->fFactory();
}
}
}
ImGui::EndCombo();
}
if (ImGui::BeginCombo("Decoration", fDecoratorSelect->fName)) {
for (const auto& dec : kDecorators) {
if (ImGui::Selectable(dec.fName, false)) {
if (dec.fName != fDecoratorSelect->fName) {
fDecoratorSelect = &dec;
fDecorator = fDecoratorSelect->fFactory();
}
}
}
ImGui::EndCombo();
}
}
ImGui::End();
}
void renderTracker(SkCanvas* canvas, const SkSize& win_size, const SkSize& anim_size) const {
if (!fTransformSelect) {
return;
}
const auto tprop = std::get<1>(*fTransformSelect)->get();
const auto m = SkMatrix::Translate(tprop.fPosition.fX, tprop.fPosition.fY)
* SkMatrix::RotateDeg(tprop.fRotation)
* SkMatrix::Scale (tprop.fScale.fX*0.01f, tprop.fScale.fY*0.01f)
* SkMatrix::Translate(tprop.fAnchorPoint.fX, tprop.fAnchorPoint.fY);
const auto viewer_matrix = SkMatrix::RectToRect(SkRect::MakeSize(anim_size),
SkRect::MakeSize(win_size),
SkMatrix::kCenter_ScaleToFit);
SkAutoCanvasRestore acr(canvas, true);
canvas->concat(viewer_matrix);
canvas->concat(m);
SkASSERT(fDecorator);
fDecorator->render(canvas);
}
private:
void onTransformProperty(const char name[],
const LazyHandle<skottie::TransformPropertyHandle>& lh) override {
fTransforms.push_back(std::make_tuple(SkString(name), lh()));
}
using TransformT = std::tuple<SkString, std::unique_ptr<skottie::TransformPropertyHandle>>;
std::vector<TransformT> fTransforms;
std::unique_ptr<Decorator> fDecorator;
const TransformT* fTransformSelect = nullptr;
const DecoratorRec* fDecoratorSelect = &kDecorators[0];
};
static void draw_stats_box(SkCanvas* canvas, const skottie::Animation::Builder::Stats& stats) {
static constexpr SkRect kR = { 10, 10, 280, 120 };
static constexpr SkScalar kTextSize = 20;
@ -168,10 +283,14 @@ void SkottieSlide::load(SkScalar w, SkScalar h) {
auto precomp_interceptor =
sk_make_sp<skottie_utils::ExternalAnimationPrecompInterceptor>(resource_provider,
kInterceptPrefix);
fTransformTracker = sk_make_sp<TransformTracker>();
fAnimation = builder
.setLogger(logger)
.setResourceProvider(std::move(resource_provider))
.setPrecompInterceptor(std::move(precomp_interceptor))
.setPropertyObserver(fTransformTracker)
.makeFromFile(fPath.c_str());
fAnimationStats = builder.getStats();
fWinSize = SkSize::Make(w, h);
@ -217,6 +336,8 @@ void SkottieSlide::draw(SkCanvas* canvas) {
fFrameTimes[frame_index] = static_cast<float>((SkTime::GetNSecs() - t0) * 1e-6);
}
fTransformTracker->renderTracker(canvas, fWinSize, fAnimation->size());
if (fShowAnimationStats) {
draw_stats_box(canvas, fAnimationStats);
}
@ -240,7 +361,9 @@ void SkottieSlide::draw(SkCanvas* canvas) {
if (fShowUI) {
this->renderUI();
}
if (fShowTrackerUI) {
fTransformTracker->renderUI();
}
}
}
@ -286,6 +409,9 @@ bool SkottieSlide::onChar(SkUnichar c) {
fPreferGlyphPaths = !fPreferGlyphPaths;
this->load(fWinSize.width(), fWinSize.height());
return true;
case 'T':
fShowTrackerUI = !fShowTrackerUI;
return true;
}
return INHERITED::onChar(c);

View File

@ -39,22 +39,26 @@ private:
SkRect UIArea() const;
void renderUI();
class TransformTracker;
const SkString fPath;
sk_sp<skottie::Animation> fAnimation;
skottie::Animation::Builder::Stats fAnimationStats;
sksg::InvalidationController fInvalController;
sk_sp<TransformTracker> fTransformTracker;
std::vector<float> fFrameTimes;
SkSize fWinSize = SkSize::MakeEmpty();
double fTimeBase = 0,
fFrameRate = 0;
const char* fFrameRateLabel = nullptr;
float fCurrentFrame = 0;
bool fShowAnimationInval = false,
fShowAnimationStats = false,
fShowUI = false,
fDraggingProgress = false,
fPreferGlyphPaths = false;
SkSize fWinSize = SkSize::MakeEmpty();
double fTimeBase = 0,
fFrameRate = 0;
const char* fFrameRateLabel = nullptr;
float fCurrentFrame = 0;
bool fShowAnimationInval = false,
fShowAnimationStats = false,
fShowUI = false,
fShowTrackerUI = false,
fDraggingProgress = false,
fPreferGlyphPaths = false;
using INHERITED = Slide;
};