diff options
Diffstat (limited to 'experimental/skottie/SkottieAdapter.cpp')
-rw-r--r-- | experimental/skottie/SkottieAdapter.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/experimental/skottie/SkottieAdapter.cpp b/experimental/skottie/SkottieAdapter.cpp new file mode 100644 index 0000000000..5186e2c2f8 --- /dev/null +++ b/experimental/skottie/SkottieAdapter.cpp @@ -0,0 +1,164 @@ +/* + * 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 "SkottieAdapter.h" + +#include "SkMatrix.h" +#include "SkottieValue.h" +#include "SkPath.h" +#include "SkRRect.h" +#include "SkSGGradient.h" +#include "SkSGPath.h" +#include "SkSGRect.h" +#include "SkSGTransform.h" +#include "SkSGTrimEffect.h" + +#include <cmath> + +namespace skottie { + +RRectAdapter::RRectAdapter(sk_sp<sksg::RRect> wrapped_node) + : fRRectNode(std::move(wrapped_node)) {} + +void RRectAdapter::apply() { + // BM "position" == "center position" + auto rr = SkRRect::MakeRectXY(SkRect::MakeXYWH(fPosition.x() - fSize.width() / 2, + fPosition.y() - fSize.height() / 2, + fSize.width(), fSize.height()), + fRadius.width(), + fRadius.height()); + fRRectNode->setRRect(rr); +} + +TransformAdapter::TransformAdapter(sk_sp<sksg::Matrix> matrix) + : fMatrixNode(std::move(matrix)) {} + +void TransformAdapter::apply() { + SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y()); + + t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based + t.postRotate(fRotation); + t.postTranslate(fPosition.x(), fPosition.y()); + // TODO: skew + + fMatrixNode->setMatrix(t); +} + +PolyStarAdapter::PolyStarAdapter(sk_sp<sksg::Path> wrapped_node, Type t) + : fPathNode(std::move(wrapped_node)) + , fType(t) {} + +void PolyStarAdapter::apply() { + const auto count = SkScalarTruncToInt(fPointCount); + const auto arc = SK_ScalarPI * 2 / count; + + const auto pt_on_circle = [](const SkPoint& c, SkScalar r, SkScalar a) { + return SkPoint::Make(c.x() + r * std::cos(a), + c.y() + r * std::sin(a)); + }; + + // TODO: inner/outer "roundness"? + + SkPath poly; + + auto angle = SkDegreesToRadians(fRotation); + poly.moveTo(pt_on_circle(fPosition, fOuterRadius, angle)); + + for (int i = 0; i < count; ++i) { + if (fType == Type::kStar) { + poly.lineTo(pt_on_circle(fPosition, fInnerRadius, angle + arc * 0.5f)); + } + angle += arc; + poly.lineTo(pt_on_circle(fPosition, fOuterRadius, angle)); + } + + poly.close(); + fPathNode->setPath(poly); +} + +GradientAdapter::GradientAdapter(sk_sp<sksg::Gradient> grad, size_t stopCount) + : fGradient(std::move(grad)) + , fStopCount(stopCount) {} + +void GradientAdapter::apply() { + this->onApply(); + + // |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ] + + if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) { + SkDebugf("!! Invalid gradient stop array size: %zu", fColorStops.size()); + return; + } + + std::vector<sksg::Gradient::ColorStop> stops; + + // TODO: merge/lerp opacity stops + const auto csEnd = fColorStops.cbegin() + fStopCount * 4; + for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) { + const auto pos = cs[0]; + const VectorValue rgb({ cs[1], cs[2], cs[3] }); + + stops.push_back({ pos, ValueTraits<VectorValue>::As<SkColor>(rgb) }); + } + + fGradient->setColorStops(std::move(stops)); +} + +LinearGradientAdapter::LinearGradientAdapter(sk_sp<sksg::LinearGradient> grad, size_t stopCount) + : INHERITED(std::move(grad), stopCount) {} + +void LinearGradientAdapter::onApply() { + auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get()); + grad->setStartPoint(this->startPoint()); + grad->setEndPoint(this->endPoint()); +} + +RadialGradientAdapter::RadialGradientAdapter(sk_sp<sksg::RadialGradient> grad, size_t stopCount) + : INHERITED(std::move(grad), stopCount) {} + +void RadialGradientAdapter::onApply() { + auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get()); + grad->setStartCenter(this->startPoint()); + grad->setEndCenter(this->startPoint()); + grad->setStartRadius(0); + grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint())); +} + +TrimEffectAdapter::TrimEffectAdapter(sk_sp<sksg::TrimEffect> trimEffect) + : fTrimEffect(std::move(trimEffect)) { + SkASSERT(fTrimEffect); +} + +void TrimEffectAdapter::apply() { + // BM semantics: start/end are percentages, offset is "degrees" (?!). + const auto start = fStart / 100, + end = fEnd / 100, + offset = fOffset / 360; + + auto startT = SkTMin(start, end) + offset, + stopT = SkTMax(start, end) + offset; + auto mode = SkTrimPathEffect::Mode::kNormal; + + if (stopT - startT < 1) { + startT -= SkScalarFloorToScalar(startT); + stopT -= SkScalarFloorToScalar(stopT); + + if (startT > stopT) { + SkTSwap(startT, stopT); + mode = SkTrimPathEffect::Mode::kInverted; + } + } else { + startT = 0; + stopT = 1; + } + + fTrimEffect->setStart(startT); + fTrimEffect->setStop(stopT); + fTrimEffect->setMode(mode); +} + +} // namespace skottie |