blob: bc2dc153a05d674b5e1b28045bdf1b8a91db22c1 [file] [log] [blame]
/*
* Copyright 2020 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/Adapter.h"
#include "modules/skottie/src/SkottieJson.h"
#include "modules/skottie/src/SkottiePriv.h"
#include "modules/skottie/src/SkottieValue.h"
#include "modules/skottie/src/layers/shapelayer/ShapeLayer.h"
#include "modules/sksg/include/SkSGGeometryEffect.h"
#include "modules/sksg/include/SkSGMerge.h"
#include <vector>
namespace skottie {
namespace internal {
namespace {
class TrimEffectAdapter final : public DiscardableAdapterBase<TrimEffectAdapter, sksg::TrimEffect> {
public:
TrimEffectAdapter(const skjson::ObjectValue& jtrim,
const AnimationBuilder& abuilder,
sk_sp<sksg::GeometryNode> child)
: INHERITED(sksg::TrimEffect::Make(std::move(child))) {
this->bind(abuilder, jtrim["s"], &fStart);
this->bind(abuilder, jtrim["e"], &fEnd);
this->bind(abuilder, jtrim["o"], &fOffset);
}
private:
void onSync() override {
// BM semantics: start/end are percentages, offset is "degrees" (?!).
const auto start = fStart / 100,
end = fEnd / 100,
offset = fOffset / 360;
auto startT = std::min(start, end) + offset,
stopT = std::max(start, end) + offset;
auto mode = SkTrimPathEffect::Mode::kNormal;
if (stopT - startT < 1) {
startT -= SkScalarFloorToScalar(startT);
stopT -= SkScalarFloorToScalar(stopT);
if (startT > stopT) {
using std::swap;
swap(startT, stopT);
mode = SkTrimPathEffect::Mode::kInverted;
}
} else {
startT = 0;
stopT = 1;
}
this->node()->setStart(startT);
this->node()->setStop(stopT);
this->node()->setMode(mode);
}
ScalarValue fStart = 0,
fEnd = 100,
fOffset = 0;
using INHERITED = DiscardableAdapterBase<TrimEffectAdapter, sksg::TrimEffect>;
};
} // namespace
std::vector<sk_sp<sksg::GeometryNode>> ShapeBuilder::AttachTrimGeometryEffect(
const skjson::ObjectValue& jtrim,
const AnimationBuilder* abuilder,
std::vector<sk_sp<sksg::GeometryNode>>&& geos) {
enum class Mode {
kParallel, // "m": 1 (Trim Multiple Shapes: Simultaneously)
kSerial, // "m": 2 (Trim Multiple Shapes: Individually)
} gModes[] = { Mode::kParallel, Mode::kSerial};
const auto mode = gModes[std::min<size_t>(ParseDefault<size_t>(jtrim["m"], 1) - 1,
SK_ARRAY_COUNT(gModes) - 1)];
std::vector<sk_sp<sksg::GeometryNode>> inputs;
if (mode == Mode::kSerial) {
inputs.push_back(ShapeBuilder::MergeGeometry(std::move(geos), sksg::Merge::Mode::kMerge));
} else {
inputs = std::move(geos);
}
std::vector<sk_sp<sksg::GeometryNode>> trimmed;
trimmed.reserve(inputs.size());
for (const auto& i : inputs) {
trimmed.push_back(
abuilder->attachDiscardableAdapter<TrimEffectAdapter>(jtrim, *abuilder, i));
}
return trimmed;
}
} // namespace internal
} // namespace skottie