[skottie] Cleanup: relocate Animator base class out of SkSG

Decouple animator semantics from the scene graph.

No functional changes, just shuffling code around.

TBR=
Change-Id: I9a4592c424d2f8eb45b1b5f3e1f4b885cfaff9f6
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/279421
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
Florin Malita 2020-03-26 15:58:56 -04:00 committed by Skia Commit-Bot
parent 2a8a3ff04e
commit bb7d95f0f0
17 changed files with 133 additions and 121 deletions

View File

@ -16,6 +16,7 @@
#include "modules/skresources/include/SkResources.h"
#include <memory>
#include <vector>
class SkCanvas;
struct SkRect;
@ -32,6 +33,8 @@ class Scene;
namespace skottie {
namespace internal { class Animator; }
using ImageAsset = skresources::ImageAsset;
using ResourceProvider = skresources::ResourceProvider;
@ -61,7 +64,6 @@ public:
class SK_API Animation : public SkNVRefCnt<Animation> {
public:
class Builder final {
public:
enum Flags : uint32_t {
@ -214,17 +216,20 @@ private:
kRequiresTopLevelIsolation = 1 << 0, // Needs to draw into a layer due to layer blending.
};
Animation(std::unique_ptr<sksg::Scene>, SkString ver, const SkSize& size,
Animation(std::unique_ptr<sksg::Scene>,
std::vector<sk_sp<internal::Animator>>&&,
SkString ver, const SkSize& size,
double inPoint, double outPoint, double duration, double fps, uint32_t flags);
std::unique_ptr<sksg::Scene> fScene;
const SkString fVersion;
const SkSize fSize;
const double fInPoint,
fOutPoint,
fDuration,
fFPS;
const uint32_t fFlags;
const std::unique_ptr<sksg::Scene> fScene;
const std::vector<sk_sp<internal::Animator>> fAnimators;
const SkString fVersion;
const SkSize fSize;
const double fInPoint,
fOutPoint,
fDuration,
fFPS;
const uint32_t fFlags;
typedef SkNVRefCnt<Animation> INHERITED;
};

View File

@ -46,7 +46,7 @@ sk_sp<sksg::RenderNode> AnimationBuilder::attachNestedAnimation(const char* name
const sk_sp<Animation> fAnimation;
};
class SkottieAnimatorAdapter final : public sksg::Animator {
class SkottieAnimatorAdapter final : public Animator {
public:
SkottieAnimatorAdapter(sk_sp<Animation> animation, float time_scale)
: fAnimation(std::move(animation))

View File

@ -211,9 +211,9 @@ sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
return sksg::MaskEffect::Make(std::move(childNode), std::move(maskNode));
}
class LayerController final : public sksg::Animator {
class LayerController final : public Animator {
public:
LayerController(sksg::AnimatorList&& layer_animators,
LayerController(AnimatorScope&& layer_animators,
sk_sp<sksg::RenderNode> layer,
size_t tanim_count, float in, float out)
: fLayerAnimators(std::move(layer_animators))
@ -242,14 +242,14 @@ protected:
}
private:
const sksg::AnimatorList fLayerAnimators;
const AnimatorScope fLayerAnimators;
const sk_sp<sksg::RenderNode> fLayerNode;
const size_t fTransformAnimatorsCount;
const float fIn,
fOut;
};
class MotionBlurController final : public sksg::Animator {
class MotionBlurController final : public Animator {
public:
explicit MotionBlurController(sk_sp<MotionBlurEffect> mbe)
: fMotionBlurEffect(std::move(mbe)) {}
@ -468,11 +468,11 @@ sk_sp<sksg::RenderNode> LayerBuilder::buildRenderTree(const AnimationBuilder& ab
const auto has_animators = !abuilder.fCurrentAnimatorScope->empty();
sk_sp<sksg::Animator> controller = sk_make_sp<LayerController>(ascope.release(),
layer,
fTransformAnimatorCount,
layer_info.fInPoint,
layer_info.fOutPoint);
sk_sp<Animator> controller = sk_make_sp<LayerController>(ascope.release(),
layer,
fTransformAnimatorCount,
layer_info.fInPoint,
layer_info.fOutPoint);
// Optional motion blur.
if (layer && has_animators && this->hasMotionBlur(cbuilder)) {

View File

@ -173,7 +173,7 @@ AnimationBuilder::AnimationBuilder(sk_sp<ResourceProvider> rp, sk_sp<SkFontMgr>
, fFlags(flags)
, fHasNontrivialBlending(false) {}
std::unique_ptr<sksg::Scene> AnimationBuilder::parse(const skjson::ObjectValue& jroot) {
AnimationBuilder::AnimationInfo AnimationBuilder::parse(const skjson::ObjectValue& jroot) {
this->dispatchMarkers(jroot["markers"]);
this->parseAssets(jroot["assets"]);
@ -185,7 +185,7 @@ std::unique_ptr<sksg::Scene> AnimationBuilder::parse(const skjson::ObjectValue&
auto animators = ascope.release();
fStats->fAnimatorCount = animators.size();
return sksg::Scene::Make(std::move(root), std::move(animators));
return { sksg::Scene::Make(std::move(root)), std::move(animators) };
}
void AnimationBuilder::parseAssets(const skjson::ArrayValue* jassets) {
@ -399,13 +399,13 @@ sk_sp<Animation> Animation::Builder::make(const char* data, size_t data_len) {
std::move(fLogger),
std::move(fMarkerObserver),
&fStats, size, duration, fps, fFlags);
auto scene = builder.parse(json);
auto ainfo = builder.parse(json);
const auto t2 = std::chrono::steady_clock::now();
fStats.fSceneParseTimeMS = std::chrono::duration<float, std::milli>{t2-t1}.count();
fStats.fTotalLoadTimeMS = std::chrono::duration<float, std::milli>{t2-t0}.count();
if (!scene && fLogger) {
if (!ainfo.fScene && fLogger) {
fLogger->log(Logger::Level::kError, "Could not parse animation.\n");
}
@ -414,7 +414,8 @@ sk_sp<Animation> Animation::Builder::make(const char* data, size_t data_len) {
flags |= Animation::Flags::kRequiresTopLevelIsolation;
}
return sk_sp<Animation>(new Animation(std::move(scene),
return sk_sp<Animation>(new Animation(std::move(ainfo.fScene),
std::move(ainfo.fAnimators),
std::move(version),
size,
inPoint,
@ -431,9 +432,12 @@ sk_sp<Animation> Animation::Builder::makeFromFile(const char path[]) {
: nullptr;
}
Animation::Animation(std::unique_ptr<sksg::Scene> scene, SkString version, const SkSize& size,
Animation::Animation(std::unique_ptr<sksg::Scene> scene,
std::vector<sk_sp<internal::Animator>>&& animators,
SkString version, const SkSize& size,
double inPoint, double outPoint, double duration, double fps, uint32_t flags)
: fScene(std::move(scene))
, fAnimators(std::move(animators))
, fVersion(std::move(version))
, fSize(size)
, fInPoint(inPoint)
@ -480,9 +484,14 @@ void Animation::seekFrame(double t, sksg::InvalidationController* ic) {
return;
// Per AE/Lottie semantics out_point is exclusive.
const auto kLastValidFrame = std::nextafterf(fOutPoint, fInPoint);
const auto kLastValidFrame = std::nextafterf(fOutPoint, fInPoint),
comp_time = SkTPin<float>(fInPoint + t, fInPoint, kLastValidFrame);
fScene->animate(SkTPin<float>(fInPoint + t, fInPoint, kLastValidFrame), ic);
for (const auto& anim : fAnimators) {
anim->tick(comp_time);
}
fScene->revalidate(ic);
}
void Animation::seekFrameTime(double t, sksg::InvalidationController* ic) {

View File

@ -15,10 +15,12 @@
#include "include/core/SkTypeface.h"
#include "include/private/SkTHash.h"
#include "modules/skottie/include/SkottieProperty.h"
#include "modules/skottie/src/animator/Animator.h"
#include "modules/sksg/include/SkSGScene.h"
#include "src/utils/SkUTF.h"
#include <functional>
#include <vector>
class SkFontMgr;
@ -45,7 +47,7 @@ class TextAdapter;
class TransformAdapter2D;
class TransformAdapter3D;
using AnimatorScope = sksg::AnimatorList;
using AnimatorScope = std::vector<sk_sp<Animator>>;
class AnimationBuilder final : public SkNoncopyable {
public:
@ -54,7 +56,12 @@ public:
Animation::Builder::Stats*, const SkSize& comp_size,
float duration, float framerate, uint32_t flags);
std::unique_ptr<sksg::Scene> parse(const skjson::ObjectValue&);
struct AnimationInfo {
std::unique_ptr<sksg::Scene> fScene;
AnimatorScope fAnimators;
};
AnimationInfo parse(const skjson::ObjectValue&);
struct FontInfo {
SkString fFamily,

View File

@ -8,7 +8,9 @@
#ifndef SkottieAnimator_DEFINED
#define SkottieAnimator_DEFINED
#include "modules/sksg/include/SkSGScene.h"
#include "include/core/SkRefCnt.h"
#include <vector>
namespace skjson {
@ -22,7 +24,23 @@ namespace internal {
class AnimationBuilder;
class KeyframeAnimatorBuilder;
class AnimatablePropertyContainer : public sksg::Animator {
class Animator : public SkRefCnt {
public:
virtual ~Animator() = default;
void tick(float t) { this->onTick(t); }
protected:
Animator() = default;
virtual void onTick(float t) = 0;
private:
Animator(const Animator&) = delete;
Animator& operator=(const Animator&) = delete;
};
class AnimatablePropertyContainer : public Animator {
public:
// This is the workhorse for property binding: depending on whether the property is animated,
// it will either apply immediately or instantiate and attach a keyframe animator, scoped to
@ -52,7 +70,7 @@ private:
KeyframeAnimatorBuilder&,
void*);
sksg::AnimatorList fAnimators;
std::vector<sk_sp<Animator>> fAnimators;
};
} // namespace internal

View File

@ -11,6 +11,7 @@
#include "include/core/SkCubicMap.h"
#include "include/core/SkPoint.h"
#include "include/private/SkNoncopyable.h"
#include "modules/skottie/src/animator/Animator.h"
#include "modules/sksg/include/SkSGScene.h"
#include <vector>
@ -53,7 +54,7 @@ struct Keyframe {
static constexpr uint32_t kCubicIndexOffset = 2;
};
class KeyframeAnimatorBase : public sksg::Animator {
class KeyframeAnimatorBase : public Animator {
public:
virtual ~KeyframeAnimatorBase() override;

View File

@ -11,6 +11,7 @@
#include "include/core/SkMath.h"
#include "include/core/SkPixmap.h"
#include "include/private/SkVx.h"
#include "modules/skottie/src/animator/Animator.h"
#include "src/core/SkMathPriv.h"
namespace skottie {
@ -33,7 +34,7 @@ private:
const sk_sp<RenderNode>& fChild;
};
sk_sp<MotionBlurEffect> MotionBlurEffect::Make(sk_sp<sksg::Animator> animator,
sk_sp<MotionBlurEffect> MotionBlurEffect::Make(sk_sp<Animator> animator,
sk_sp<sksg::RenderNode> child,
size_t samples_per_frame,
float shutter_angle, float shutter_phase) {
@ -53,7 +54,7 @@ sk_sp<MotionBlurEffect> MotionBlurEffect::Make(sk_sp<sksg::Animator> animator,
phase, dt));
}
MotionBlurEffect::MotionBlurEffect(sk_sp<sksg::Animator> animator,
MotionBlurEffect::MotionBlurEffect(sk_sp<Animator> animator,
sk_sp<sksg::RenderNode> child,
size_t samples, float phase, float dt)
: INHERITED({std::move(child)})

View File

@ -14,9 +14,11 @@
namespace skottie {
namespace internal {
class Animator;
class MotionBlurEffect final : public sksg::CustomRenderNode {
public:
static sk_sp<MotionBlurEffect> Make(sk_sp<sksg::Animator> animator,
static sk_sp<MotionBlurEffect> Make(sk_sp<Animator> animator,
sk_sp<sksg::RenderNode> child,
size_t samples_per_frame,
float shutter_angle, float shutter_phase);
@ -36,14 +38,14 @@ private:
SkRect seekToSample(size_t sample_idx, const SkMatrix& ctm) const;
MotionBlurEffect(sk_sp<sksg::Animator> animator,
MotionBlurEffect(sk_sp<Animator> animator,
sk_sp<sksg::RenderNode> child,
size_t sample_count, float phase, float dt);
const sk_sp<sksg::Animator> fAnimator;
const size_t fSampleCount;
const float fPhase,
fDT;
const sk_sp<Animator> fAnimator;
const size_t fSampleCount;
const float fPhase,
fDT;
float fT = 0;
size_t fVisibleSampleCount = 0;

View File

@ -24,7 +24,7 @@ SkMatrix image_matrix(const sk_sp<SkImage>& image, const SkISize& dest_size) {
: SkMatrix::I();
}
class ImageAnimator final : public sksg::Animator {
class ImageAnimator final : public Animator {
public:
ImageAnimator(sk_sp<ImageAsset> asset,
sk_sp<sksg::Image> image_node,

View File

@ -42,12 +42,12 @@ private:
};
// Applies a bias/scale/remap t-adjustment to child animators.
class CompTimeMapper final : public sksg::GroupAnimator {
class CompTimeMapper final : public Animator {
public:
CompTimeMapper(sksg::AnimatorList&& layer_animators,
CompTimeMapper(AnimatorScope&& layer_animators,
sk_sp<TimeRemapper> remapper,
float time_bias, float time_scale)
: INHERITED(std::move(layer_animators))
: fAnimators(std::move(layer_animators))
, fRemapper(std::move(remapper))
, fTimeBias(time_bias)
, fTimeScale(time_scale) {}
@ -61,15 +61,16 @@ public:
t = (t + fTimeBias) * fTimeScale;
}
this->INHERITED::onTick(t);
for (const auto& anim : fAnimators) {
anim->tick(t);
}
}
private:
const AnimatorScope fAnimators;
const sk_sp<TimeRemapper> fRemapper;
const float fTimeBias,
fTimeScale;
using INHERITED = sksg::GroupAnimator;
};
} // namespace

View File

@ -23,59 +23,24 @@ class InvalidationController;
class RenderNode;
/**
* Base class for animators.
*
*/
class Animator : public SkRefCnt {
public:
virtual ~Animator();
Animator(const Animator&) = delete;
Animator& operator=(const Animator&) = delete;
void tick(float t) { this->onTick(t); }
protected:
Animator();
virtual void onTick(float t) = 0;
};
using AnimatorList = std::vector<sk_sp<Animator>>;
class GroupAnimator : public Animator {
protected:
explicit GroupAnimator(AnimatorList&&);
void onTick(float t) override;
private:
const AnimatorList fAnimators;
using INHERITED = Animator;
};
/**
* Holds a scene root and a list of animators.
*
* Provides high-level mehods for driving rendering and animations.
* Holds a scene root. Provides high-level methods for rendering.
*
*/
class Scene final {
public:
static std::unique_ptr<Scene> Make(sk_sp<RenderNode> root, AnimatorList&& animators);
static std::unique_ptr<Scene> Make(sk_sp<RenderNode> root);
~Scene();
Scene(const Scene&) = delete;
Scene& operator=(const Scene&) = delete;
void render(SkCanvas*) const;
void animate(float t, InvalidationController* = nullptr);
void revalidate(InvalidationController* = nullptr);
const RenderNode* nodeAt(const SkPoint&) const;
private:
Scene(sk_sp<RenderNode> root, AnimatorList&& animators);
explicit Scene(sk_sp<RenderNode> root);
const sk_sp<RenderNode> fRoot;
const AnimatorList fAnimators;
};
} // namespace sksg

View File

@ -146,7 +146,7 @@ protected:
SkRect::MakeIWH(this->width(), this->height()),
SkMatrix::kFill_ScaleToFit));
auto root = sksg::TransformEffect::Make(std::move(group), fContentMatrix);
fScene = sksg::Scene::Make(std::move(root), sksg::AnimatorList());
fScene = sksg::Scene::Make(std::move(root));
// Off we go.
this->updatePaddleStrategy();
@ -184,7 +184,6 @@ protected:
void onDrawContent(SkCanvas* canvas) override {
sksg::InvalidationController ic;
fScene->animate(0, &ic);
fScene->render(canvas);
if (fShowInval) {

View File

@ -15,25 +15,11 @@
namespace sksg {
Animator::Animator() = default;
Animator::~Animator() = default;
GroupAnimator::GroupAnimator(AnimatorList&& animators)
: fAnimators(std::move(animators)) {}
void GroupAnimator::onTick(float t) {
for (const auto& a : fAnimators) {
a->tick(t);
}
std::unique_ptr<Scene> Scene::Make(sk_sp<RenderNode> root) {
return root ? std::unique_ptr<Scene>(new Scene(std::move(root))) : nullptr;
}
std::unique_ptr<Scene> Scene::Make(sk_sp<RenderNode> root, AnimatorList&& anims) {
return root ? std::unique_ptr<Scene>(new Scene(std::move(root), std::move(anims))) : nullptr;
}
Scene::Scene(sk_sp<RenderNode> root, AnimatorList&& animators)
: fRoot(std::move(root))
, fAnimators(std::move(animators)) {}
Scene::Scene(sk_sp<RenderNode> root) : fRoot(std::move(root)) {}
Scene::~Scene() = default;
@ -41,14 +27,11 @@ void Scene::render(SkCanvas* canvas) const {
// Ensure the SG is revalidated.
// Note: this is a no-op if the scene has already been revalidated - e.g. in animate().
fRoot->revalidate(nullptr, SkMatrix::I());
fRoot->render(canvas);
}
void Scene::animate(float t, InvalidationController* ic) {
for (const auto& anim : fAnimators) {
anim->tick(t);
}
void Scene::revalidate(InvalidationController* ic) {
fRoot->revalidate(ic, SkMatrix::I());
}

View File

@ -52,7 +52,7 @@ public:
SampleSG() {
fGroup = sksg::Group::Make();
fScene = sksg::Scene::Make(fGroup, sksg::AnimatorList());
fScene = sksg::Scene::Make(fGroup);
auto r = sksg::Rect::Make({20, 20, 400, 300});
auto p = sksg::Color::Make(SK_ColorRED);

View File

@ -24,6 +24,20 @@
#include <cmath>
#include <utility>
class SlideDir::Animator : public SkRefCnt {
public:
virtual ~Animator() = default;
Animator(const Animator&) = delete;
Animator& operator=(const Animator&) = delete;
void tick(float t) { this->onTick(t); }
protected:
Animator() = default;
virtual void onTick(float t) = 0;
};
namespace {
static constexpr float kAspectRatio = 1.5f;
@ -46,9 +60,9 @@ public:
SkASSERT(fSlide);
}
sk_sp<sksg::Animator> makeForwardingAnimator() {
sk_sp<SlideDir::Animator> makeForwardingAnimator() {
// Trivial sksg::Animator -> skottie::Animation tick adapter
class ForwardingAnimator final : public sksg::Animator {
class ForwardingAnimator final : public SlideDir::Animator {
public:
explicit ForwardingAnimator(sk_sp<SlideAdapter> adapter)
: fAdapter(std::move(adapter)) {}
@ -108,7 +122,7 @@ struct SlideDir::Rec {
SkRect fRect;
};
class SlideDir::FocusController final : public sksg::Animator {
class SlideDir::FocusController final : public Animator {
public:
FocusController(const SlideDir* dir, const SkRect& focusRect)
: fDir(dir)
@ -247,7 +261,7 @@ private:
fTimeBase = 0;
State fState = State::kIdle;
using INHERITED = sksg::Animator;
using INHERITED = Animator;
};
SlideDir::SlideDir(const SkString& name, SkTArray<sk_sp<Slide>>&& slides, int columns)
@ -292,7 +306,6 @@ void SlideDir::load(SkScalar winWidth, SkScalar winHeight) {
const auto cellWidth = winWidth / fColumns;
fCellSize = SkSize::Make(cellWidth, cellWidth / kAspectRatio);
sksg::AnimatorList sceneAnimators;
fRoot = sksg::Group::Make();
for (int i = 0; i < fSlides.count(); ++i) {
@ -318,13 +331,13 @@ void SlideDir::load(SkScalar winWidth, SkScalar winHeight) {
slideMatrix->getMatrix()));
auto slideRoot = sksg::TransformEffect::Make(std::move(slideGrp), slideMatrix);
sceneAnimators.push_back(adapter->makeForwardingAnimator());
fSceneAnimators.push_back(adapter->makeForwardingAnimator());
fRoot->addChild(slideRoot);
fRecs.push_back({ slide, slideRoot, slideMatrix, slideRect });
}
fScene = sksg::Scene::Make(fRoot, std::move(sceneAnimators));
fScene = sksg::Scene::Make(fRoot);
const auto focusRect = SkRect::MakeSize(fWinSize).makeInset(kFocusInset.width(),
kFocusInset.height());
@ -360,7 +373,9 @@ bool SlideDir::animate(double nanos) {
}
const auto t = msec - fTimeBase;
fScene->animate(t);
for (const auto& anim : fSceneAnimators) {
anim->tick(t);
}
fFocusController->tick(t);
return true;

View File

@ -12,6 +12,9 @@
#include "include/private/SkTArray.h"
#include <memory>
#include <vector>
class SkString;
namespace sksg {
@ -26,6 +29,8 @@ public:
SlideDir(const SkString& name, SkTArray<sk_sp<Slide>>&&,
int columns = kDefaultColumnCount);
class Animator;
protected:
void load(SkScalar winWidth, SkScalar winHeight) override;
void unload() override;
@ -52,6 +57,7 @@ private:
SkTArray<Rec, true> fRecs;
std::unique_ptr<sksg::Scene> fScene;
std::vector<sk_sp<Animator>> fSceneAnimators;
sk_sp<sksg::Group> fRoot;
SkSize fWinSize = SkSize::MakeEmpty();