blob: 2165128a89b7a47697425dafa52dc0432877c2c6 [file] [log] [blame]
/*
* Copyright 2019 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/effects/Effects.h"
#include "modules/skottie/src/SkottieAdapter.h"
#include "modules/skottie/src/SkottieValue.h"
#include "modules/sksg/include/SkSGGradient.h"
#include "modules/sksg/include/SkSGRenderEffect.h"
#include "src/utils/SkJSON.h"
namespace skottie {
namespace internal {
namespace {
class GradientRampEffectAdapter final : public SkNVRefCnt<GradientRampEffectAdapter> {
public:
explicit GradientRampEffectAdapter(sk_sp<sksg::RenderNode> child)
: fRoot(sksg::ShaderEffect::Make(std::move(child))) {}
ADAPTER_PROPERTY(StartPoint, SkPoint , SkPoint::Make(0, 0))
ADAPTER_PROPERTY(EndPoint , SkPoint , SkPoint::Make(0, 0))
ADAPTER_PROPERTY(StartColor, SkColor , SK_ColorBLACK)
ADAPTER_PROPERTY(EndColor , SkColor , SK_ColorBLACK)
ADAPTER_PROPERTY(Blend , SkScalar, 0)
ADAPTER_PROPERTY(Scatter , SkScalar, 0)
// Really an enum: 1 -> linear, 7 -> radial (?!)
ADAPTER_PROPERTY(Shape , SkScalar, 0)
const sk_sp<sksg::ShaderEffect>& root() const { return fRoot; }
private:
enum class InstanceType {
kNone,
kLinear,
kRadial,
};
void apply() {
// 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());
fRoot->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.
if (instance_type == InstanceType::kLinear) {
auto* lg = static_cast<sksg::LinearGradient*>(fGradient.get());
lg->setStartPoint(fStartPoint);
lg->setEndPoint(fEndPoint);
} else {
SkASSERT(instance_type == InstanceType::kRadial);
auto* rg = static_cast<sksg::RadialGradient*>(fGradient.get());
rg->setStartCenter(fStartPoint);
rg->setEndCenter(fStartPoint);
rg->setEndRadius(SkPoint::Distance(fStartPoint, fEndPoint));
}
// TODO: blend, scatter
}
sk_sp<sksg::ShaderEffect> fRoot;
sk_sp<sksg::Gradient> fGradient;
InstanceType fInstanceType = InstanceType::kNone;
};
} // anonymous ns
sk_sp<sksg::RenderNode> EffectBuilder::attachGradientEffect(const skjson::ArrayValue& jprops,
sk_sp<sksg::RenderNode> layer) const {
enum : size_t {
kStartPoint_Index = 0,
kStartColor_Index = 1,
kEndPoint_Index = 2,
kEndColor_Index = 3,
kRampShape_Index = 4,
kRampScatter_Index = 5,
kBlendRatio_Index = 6,
};
auto adapter = sk_make_sp<GradientRampEffectAdapter>(std::move(layer));
fBuilder->bindProperty<VectorValue>(GetPropValue(jprops, kStartPoint_Index),
[adapter](const VectorValue& p0) {
adapter->setStartPoint(ValueTraits<VectorValue>::As<SkPoint>(p0));
});
fBuilder->bindProperty<VectorValue>(GetPropValue(jprops, kEndPoint_Index),
[adapter](const VectorValue& p1) {
adapter->setEndPoint(ValueTraits<VectorValue>::As<SkPoint>(p1));
});
fBuilder->bindProperty<VectorValue>(GetPropValue(jprops, kStartColor_Index),
[adapter](const VectorValue& c0) {
adapter->setStartColor(ValueTraits<VectorValue>::As<SkColor>(c0));
});
fBuilder->bindProperty<VectorValue>(GetPropValue(jprops, kEndColor_Index),
[adapter](const VectorValue& c1) {
adapter->setEndColor(ValueTraits<VectorValue>::As<SkColor>(c1));
});
fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kRampShape_Index),
[adapter](const ScalarValue& shape) {
adapter->setShape(shape);
});
fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kBlendRatio_Index),
[adapter](const ScalarValue& blend) {
adapter->setBlend(blend);
});
fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kRampScatter_Index),
[adapter](const ScalarValue& scatter) {
adapter->setScatter(scatter);
});
return adapter->root();
}
} // namespace internal
} // namespace skottie