| /* | |
| * Copyright 2019 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/private/SkAssert.h" | |
| #include "modules/skottie/src/SkottiePriv.h" | |
| #include "modules/skottie/src/SkottieValue.h" | |
| #include "modules/skottie/src/animator/Animator.h" | |
| #include "modules/skottie/src/effects/Effects.h" | |
| #include "modules/sksg/include/SkSGGradient.h" | |
| #include "modules/sksg/include/SkSGRenderEffect.h" | |
| #include "modules/sksg/include/SkSGRenderNode.h" | |
| #include <cstddef> | |
| #include <utility> | |
| namespace skjson { | |
| class ArrayValue; | |
| } | |
| namespace skottie { | |
| namespace internal { | |
| namespace { | |
| class GradientRampEffectAdapter final : public AnimatablePropertyContainer { | |
| public: | |
| static sk_sp<GradientRampEffectAdapter> Make(const skjson::ArrayValue& jprops, | |
| sk_sp<sksg::RenderNode> layer, | |
| const AnimationBuilder* abuilder) { | |
| return sk_sp<GradientRampEffectAdapter>(new GradientRampEffectAdapter(jprops, | |
| std::move(layer), | |
| abuilder)); | |
| } | |
| sk_sp<sksg::RenderNode> node() const { return fShaderEffect; } | |
| private: | |
| GradientRampEffectAdapter(const skjson::ArrayValue& jprops, | |
| sk_sp<sksg::RenderNode> layer, | |
| const AnimationBuilder* abuilder) | |
| : fShaderEffect(sksg::ShaderEffect::Make(std::move(layer))) { | |
| enum : size_t { | |
| kStartPoint_Index = 0, | |
| kStartColor_Index = 1, | |
| kEndPoint_Index = 2, | |
| kEndColor_Index = 3, | |
| kRampShape_Index = 4, | |
| kRampScatter_Index = 5, | |
| kBlendRatio_Index = 6, | |
| }; | |
| EffectBinder(jprops, *abuilder, this) | |
| .bind( kStartPoint_Index, fStartPoint) | |
| .bind( kStartColor_Index, fStartColor) | |
| .bind( kEndPoint_Index, fEndPoint ) | |
| .bind( kEndColor_Index, fEndColor ) | |
| .bind( kRampShape_Index, fShape ) | |
| .bind(kRampScatter_Index, fScatter ) | |
| .bind( kBlendRatio_Index, fBlend ); | |
| } | |
| enum class InstanceType { | |
| kNone, | |
| kLinear, | |
| kRadial, | |
| }; | |
| void onSync() override { | |
| // This adapter manages a SG fragment with the following structure: | |
| // | |
| // - ShaderEffect [fRoot] | |
| // \ GradientShader [fGradient] | |
| // \ child/wrapped fragment | |
| // | |
| // The gradient shader is updated based on the (animatable) instance type (linear/radial). | |
| auto update_gradient = [this] (InstanceType new_type) { | |
| if (new_type != fInstanceType) { | |
| fGradient = new_type == InstanceType::kLinear | |
| ? sk_sp<sksg::Gradient>(sksg::LinearGradient::Make()) | |
| : sk_sp<sksg::Gradient>(sksg::RadialGradient::Make()); | |
| fShaderEffect->setShader(fGradient); | |
| fInstanceType = new_type; | |
| } | |
| fGradient->setColorStops({{0, fStartColor}, | |
| {1, fEndColor}}); | |
| }; | |
| static constexpr int kLinearShapeValue = 1; | |
| const auto instance_type = (SkScalarRoundToInt(fShape) == kLinearShapeValue) | |
| ? InstanceType::kLinear | |
| : InstanceType::kRadial; | |
| // Sync the gradient shader instance if needed. | |
| update_gradient(instance_type); | |
| // Sync instance-dependent gradient params. | |
| const auto start_point = SkPoint{fStartPoint.x, fStartPoint.y}, | |
| end_point = SkPoint{ fEndPoint.x, fEndPoint.y}; | |
| if (instance_type == InstanceType::kLinear) { | |
| auto* lg = static_cast<sksg::LinearGradient*>(fGradient.get()); | |
| lg->setStartPoint(start_point); | |
| lg->setEndPoint(end_point); | |
| } else { | |
| SkASSERT(instance_type == InstanceType::kRadial); | |
| auto* rg = static_cast<sksg::RadialGradient*>(fGradient.get()); | |
| rg->setStartCenter(start_point); | |
| rg->setEndCenter(start_point); | |
| rg->setEndRadius(SkPoint::Distance(start_point, end_point)); | |
| } | |
| // TODO: blend, scatter | |
| } | |
| const sk_sp<sksg::ShaderEffect> fShaderEffect; | |
| sk_sp<sksg::Gradient> fGradient; | |
| InstanceType fInstanceType = InstanceType::kNone; | |
| ColorValue fStartColor, | |
| fEndColor; | |
| Vec2Value fStartPoint = {0,0}, | |
| fEndPoint = {0,0}; | |
| ScalarValue fBlend = 0, | |
| fScatter = 0, | |
| fShape = 0; // 1 -> linear, 7 -> radial (?!) | |
| }; | |
| } // namespace | |
| sk_sp<sksg::RenderNode> EffectBuilder::attachGradientEffect(const skjson::ArrayValue& jprops, | |
| sk_sp<sksg::RenderNode> layer) const { | |
| return fBuilder->attachDiscardableAdapter<GradientRampEffectAdapter>(jprops, | |
| std::move(layer), | |
| fBuilder); | |
| } | |
| } // namespace internal | |
| } // namespace skottie |