blob: 0afe8eeb1d2e39316ce4969bc9e27ab27e631b4a [file] [log] [blame]
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "modules/skottie/src/SkottiePriv.h"
#include "modules/skottie/src/Animator.h"
#include "modules/skottie/src/Composition.h"
#include "modules/skottie/src/SkottieJson.h"
#include "modules/skottie/src/SkottieValue.h"
#include "modules/sksg/include/SkSGRenderNode.h"
#include "modules/sksg/include/SkSGScene.h"
#include "src/core/SkTLazy.h"
#include "src/utils/SkJSON.h"
namespace skottie {
namespace internal {
namespace {
// "Animates" time based on the layer's "tm" property.
class TimeRemapper final : public AnimatablePropertyContainer {
public:
TimeRemapper(const skjson::ObjectValue& jtm, const AnimationBuilder* abuilder, float scale)
: fScale(scale) {
this->bind(*abuilder, jtm, fT);
}
float t() const { return fT * fScale; }
private:
void onSync() override {
// nothing to sync - we just track t
}
const float fScale;
ScalarValue fT = 0;
};
// Applies a bias/scale/remap t-adjustment to child animators.
class CompTimeMapper final : public sksg::GroupAnimator {
public:
CompTimeMapper(sksg::AnimatorList&& layer_animators,
sk_sp<TimeRemapper> remapper,
float time_bias, float time_scale)
: INHERITED(std::move(layer_animators))
, fRemapper(std::move(remapper))
, fTimeBias(time_bias)
, fTimeScale(time_scale) {}
void onTick(float t) override {
if (fRemapper) {
// When time remapping is active, |t| is fully driven externally.
fRemapper->tick(t);
t = fRemapper->t();
} else {
t = (t + fTimeBias) * fTimeScale;
}
this->INHERITED::onTick(t);
}
private:
const sk_sp<TimeRemapper> fRemapper;
const float fTimeBias,
fTimeScale;
using INHERITED = sksg::GroupAnimator;
};
} // namespace
sk_sp<sksg::RenderNode> AnimationBuilder::attachPrecompLayer(const skjson::ObjectValue& jlayer,
LayerInfo* layer_info) const {
sk_sp<TimeRemapper> time_remapper;
if (const skjson::ObjectValue* jtm = jlayer["tm"]) {
time_remapper = sk_make_sp<TimeRemapper>(*jtm, this, fFrameRate);
}
const auto start_time = ParseDefault<float>(jlayer["st"], 0.0f),
stretch_time = ParseDefault<float>(jlayer["sr"], 1.0f);
const auto requires_time_mapping = !SkScalarNearlyEqual(start_time , 0) ||
!SkScalarNearlyEqual(stretch_time, 1) ||
time_remapper;
// Precomp layers are sized explicitly.
layer_info->fSize = SkSize::Make(ParseDefault<float>(jlayer["w"], 0.0f),
ParseDefault<float>(jlayer["h"], 0.0f));
SkTLazy<AutoScope> local_scope;
if (requires_time_mapping) {
local_scope.init(this);
}
auto precomp_layer = this->attachAssetRef(jlayer,
[this, layer_info] (const skjson::ObjectValue& jcomp) {
return CompositionBuilder(*this, layer_info->fSize, jcomp).build(*this);
});
if (requires_time_mapping) {
const auto t_bias = -start_time,
t_scale = sk_ieee_float_divide(1, stretch_time);
auto time_mapper = sk_make_sp<CompTimeMapper>(local_scope->release(),
std::move(time_remapper),
t_bias,
sk_float_isfinite(t_scale) ? t_scale : 0);
fCurrentAnimatorScope->push_back(std::move(time_mapper));
}
return precomp_layer;
}
} // namespace internal
} // namespace skottie