[skottie] Add support for ADBE Pro Levels2 effect
Similar to existing ADBE Easy Levels2, but provides separate mapping controls per channel. Change-Id: Ibc58c58e1e8cb8793d6eb819998c1804ccbbf859 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/268936 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
95a9e69c8c
commit
4a6a640299
@ -27,13 +27,14 @@ EffectBuilder::EffectBuilderT EffectBuilder::findBuilder(const skjson::ObjectVal
|
|||||||
EffectBuilderT fBuilder;
|
EffectBuilderT fBuilder;
|
||||||
} gBuilderInfo[] = {
|
} gBuilderInfo[] = {
|
||||||
{ "ADBE Drop Shadow" , &EffectBuilder::attachDropShadowEffect },
|
{ "ADBE Drop Shadow" , &EffectBuilder::attachDropShadowEffect },
|
||||||
{ "ADBE Easy Levels2" , &EffectBuilder::attachLevelsEffect },
|
{ "ADBE Easy Levels2" , &EffectBuilder::attachEasyLevelsEffect },
|
||||||
{ "ADBE Fill" , &EffectBuilder::attachFillEffect },
|
{ "ADBE Fill" , &EffectBuilder::attachFillEffect },
|
||||||
{ "ADBE Gaussian Blur 2", &EffectBuilder::attachGaussianBlurEffect },
|
{ "ADBE Gaussian Blur 2", &EffectBuilder::attachGaussianBlurEffect },
|
||||||
{ "ADBE Geometry2" , &EffectBuilder::attachTransformEffect },
|
{ "ADBE Geometry2" , &EffectBuilder::attachTransformEffect },
|
||||||
{ "ADBE HUE SATURATION" , &EffectBuilder::attachHueSaturationEffect },
|
{ "ADBE HUE SATURATION" , &EffectBuilder::attachHueSaturationEffect },
|
||||||
{ "ADBE Invert" , &EffectBuilder::attachInvertEffect },
|
{ "ADBE Invert" , &EffectBuilder::attachInvertEffect },
|
||||||
{ "ADBE Linear Wipe" , &EffectBuilder::attachLinearWipeEffect },
|
{ "ADBE Linear Wipe" , &EffectBuilder::attachLinearWipeEffect },
|
||||||
|
{ "ADBE Pro Levels2" , &EffectBuilder::attachProLevelsEffect },
|
||||||
{ "ADBE Radial Wipe" , &EffectBuilder::attachRadialWipeEffect },
|
{ "ADBE Radial Wipe" , &EffectBuilder::attachRadialWipeEffect },
|
||||||
{ "ADBE Ramp" , &EffectBuilder::attachGradientEffect },
|
{ "ADBE Ramp" , &EffectBuilder::attachGradientEffect },
|
||||||
{ "ADBE Shift Channels" , &EffectBuilder::attachShiftChannelsEffect },
|
{ "ADBE Shift Channels" , &EffectBuilder::attachShiftChannelsEffect },
|
||||||
|
@ -46,12 +46,14 @@ private:
|
|||||||
sk_sp<sksg::RenderNode>) const;
|
sk_sp<sksg::RenderNode>) const;
|
||||||
sk_sp<sksg::RenderNode> attachInvertEffect (const skjson::ArrayValue&,
|
sk_sp<sksg::RenderNode> attachInvertEffect (const skjson::ArrayValue&,
|
||||||
sk_sp<sksg::RenderNode>) const;
|
sk_sp<sksg::RenderNode>) const;
|
||||||
sk_sp<sksg::RenderNode> attachLevelsEffect (const skjson::ArrayValue&,
|
sk_sp<sksg::RenderNode> attachEasyLevelsEffect (const skjson::ArrayValue&,
|
||||||
sk_sp<sksg::RenderNode>) const;
|
sk_sp<sksg::RenderNode>) const;
|
||||||
sk_sp<sksg::RenderNode> attachLinearWipeEffect (const skjson::ArrayValue&,
|
sk_sp<sksg::RenderNode> attachLinearWipeEffect (const skjson::ArrayValue&,
|
||||||
sk_sp<sksg::RenderNode>) const;
|
sk_sp<sksg::RenderNode>) const;
|
||||||
sk_sp<sksg::RenderNode> attachMotionTileEffect (const skjson::ArrayValue&,
|
sk_sp<sksg::RenderNode> attachMotionTileEffect (const skjson::ArrayValue&,
|
||||||
sk_sp<sksg::RenderNode>) const;
|
sk_sp<sksg::RenderNode>) const;
|
||||||
|
sk_sp<sksg::RenderNode> attachProLevelsEffect (const skjson::ArrayValue&,
|
||||||
|
sk_sp<sksg::RenderNode>) const;
|
||||||
sk_sp<sksg::RenderNode> attachRadialWipeEffect (const skjson::ArrayValue&,
|
sk_sp<sksg::RenderNode> attachRadialWipeEffect (const skjson::ArrayValue&,
|
||||||
sk_sp<sksg::RenderNode>) const;
|
sk_sp<sksg::RenderNode>) const;
|
||||||
sk_sp<sksg::RenderNode> attachTintEffect (const skjson::ArrayValue&,
|
sk_sp<sksg::RenderNode> attachTintEffect (const skjson::ArrayValue&,
|
||||||
|
@ -8,105 +8,58 @@
|
|||||||
#include "modules/skottie/src/effects/Effects.h"
|
#include "modules/skottie/src/effects/Effects.h"
|
||||||
|
|
||||||
#include "include/effects/SkTableColorFilter.h"
|
#include "include/effects/SkTableColorFilter.h"
|
||||||
#include "modules/skottie/src/Animator.h"
|
#include "modules/skottie/src/Adapter.h"
|
||||||
#include "modules/skottie/src/SkottieValue.h"
|
#include "modules/skottie/src/SkottieValue.h"
|
||||||
#include "modules/sksg/include/SkSGColorFilter.h"
|
#include "modules/sksg/include/SkSGColorFilter.h"
|
||||||
#include "src/utils/SkJSON.h"
|
#include "src/utils/SkJSON.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace skottie {
|
namespace skottie {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// Levels color correction effect.
|
|
||||||
//
|
|
||||||
// Maps the selected channels from [inBlack...inWhite] to [outBlack, outWhite],
|
|
||||||
// based on a gamma exponent.
|
|
||||||
//
|
|
||||||
// For [i0..i1] -> [o0..o1]:
|
|
||||||
//
|
|
||||||
// c' = o0 + (o1 - o0) * ((c - i0) / (i1 - i0)) ^ G
|
|
||||||
//
|
|
||||||
// The output is optionally clipped to the output range.
|
|
||||||
//
|
|
||||||
// In/out intervals are clampped to [0..1]. Inversion is allowed.
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class LevelsEffectAdapter final : public AnimatablePropertyContainer {
|
struct ClipInfo {
|
||||||
public:
|
ScalarValue fClipBlack = 1, // 1: clip, 2/3: don't clip
|
||||||
static sk_sp<LevelsEffectAdapter> Make(const skjson::ArrayValue& jprops,
|
fClipWhite = 1; // ^
|
||||||
sk_sp<sksg::RenderNode> layer,
|
};
|
||||||
const AnimationBuilder* abuilder) {
|
|
||||||
return sk_sp<LevelsEffectAdapter>(new LevelsEffectAdapter(jprops,
|
|
||||||
std::move(layer),
|
|
||||||
abuilder));
|
|
||||||
}
|
|
||||||
|
|
||||||
sk_sp<sksg::RenderNode> node() const { return fEffect; }
|
struct ChannelMapper {
|
||||||
|
ScalarValue fInBlack = 0,
|
||||||
|
fInWhite = 1,
|
||||||
|
fOutBlack = 0,
|
||||||
|
fOutWhite = 1,
|
||||||
|
fGamma = 1;
|
||||||
|
|
||||||
private:
|
const uint8_t* build_lut(std::array<uint8_t, 256>& lut_storage,
|
||||||
LevelsEffectAdapter(const skjson::ArrayValue& jprops,
|
const ClipInfo& clip_info) const {
|
||||||
sk_sp<sksg::RenderNode> layer,
|
auto in_0 = fInBlack,
|
||||||
const AnimationBuilder* abuilder)
|
in_1 = fInWhite,
|
||||||
: fEffect(sksg::ExternalColorFilter::Make(std::move(layer))) {
|
out_0 = fOutBlack,
|
||||||
enum : size_t {
|
out_1 = fOutWhite,
|
||||||
kChannel_Index = 0,
|
|
||||||
// ??? = 1,
|
|
||||||
kInputBlack_Index = 2,
|
|
||||||
kInputWhite_Index = 3,
|
|
||||||
kGamma_Index = 4,
|
|
||||||
kOutputBlack_Index = 5,
|
|
||||||
kOutputWhite_Index = 6,
|
|
||||||
kClipToOutBlack_Index = 7,
|
|
||||||
kClipToOutWhite_Index = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
this->bind(*abuilder, EffectBuilder::GetPropValue(jprops, kChannel_Index), &fChannel );
|
|
||||||
this->bind(*abuilder, EffectBuilder::GetPropValue(jprops, kInputBlack_Index), &fInBlack );
|
|
||||||
this->bind(*abuilder, EffectBuilder::GetPropValue(jprops, kInputWhite_Index), &fInWhite );
|
|
||||||
this->bind(*abuilder, EffectBuilder::GetPropValue(jprops, kGamma_Index), &fGamma );
|
|
||||||
this->bind(*abuilder, EffectBuilder::GetPropValue(jprops, kOutputBlack_Index), &fOutBlack);
|
|
||||||
this->bind(*abuilder, EffectBuilder::GetPropValue(jprops, kOutputWhite_Index), &fOutWhite);
|
|
||||||
this->bind(*abuilder, EffectBuilder::GetPropValue(jprops, kClipToOutBlack_Index),
|
|
||||||
&fClipBlack);
|
|
||||||
this->bind(*abuilder, EffectBuilder::GetPropValue(jprops, kClipToOutWhite_Index),
|
|
||||||
&fClipWhite);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onSync() override {
|
|
||||||
enum LottieChannel {
|
|
||||||
kRGB_Channel = 1,
|
|
||||||
kR_Channel = 2,
|
|
||||||
kG_Channel = 3,
|
|
||||||
kB_Channel = 4,
|
|
||||||
kA_Channel = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto channel = SkScalarTruncToInt(fChannel);
|
|
||||||
if (channel < kRGB_Channel || channel > kA_Channel) {
|
|
||||||
fEffect->setColorFilter(nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto in_0 = SkTPin(fInBlack, 0.0f, 1.0f),
|
|
||||||
in_1 = SkTPin(fInWhite, 0.0f, 1.0f),
|
|
||||||
out_0 = SkTPin(fOutBlack, 0.0f, 1.0f),
|
|
||||||
out_1 = SkTPin(fOutWhite, 0.0f, 1.0f),
|
|
||||||
g = sk_ieee_float_divide(1, std::max(fGamma, 0.0f));
|
g = sk_ieee_float_divide(1, std::max(fGamma, 0.0f));
|
||||||
|
|
||||||
float clip[] = {0, 1};
|
float clip[] = {0, 1};
|
||||||
const auto kLottieDoClip = 1;
|
const auto kLottieDoClip = 1;
|
||||||
if (SkScalarTruncToInt(fClipBlack) == kLottieDoClip) {
|
if (SkScalarTruncToInt(clip_info.fClipBlack) == kLottieDoClip) {
|
||||||
const auto idx = fOutBlack <= fOutWhite ? 0 : 1;
|
const auto idx = fOutBlack <= fOutWhite ? 0 : 1;
|
||||||
clip[idx] = out_0;
|
clip[idx] = SkTPin(out_0, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
if (SkScalarTruncToInt(fClipWhite) == kLottieDoClip) {
|
if (SkScalarTruncToInt(clip_info.fClipWhite) == kLottieDoClip) {
|
||||||
const auto idx = fOutBlack <= fOutWhite ? 1 : 0;
|
const auto idx = fOutBlack <= fOutWhite ? 1 : 0;
|
||||||
clip[idx] = out_1;
|
clip[idx] = SkTPin(out_1, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
SkASSERT(clip[0] <= clip[1]);
|
SkASSERT(clip[0] <= clip[1]);
|
||||||
|
|
||||||
|
if (SkScalarNearlyEqual(in_0, out_0) &&
|
||||||
|
SkScalarNearlyEqual(in_1, out_1) &&
|
||||||
|
SkScalarNearlyEqual(g, 1)) {
|
||||||
|
// no-op
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto dIn = in_1 - in_0,
|
auto dIn = in_1 - in_0,
|
||||||
dOut = out_1 - out_0;
|
dOut = out_1 - out_0;
|
||||||
|
|
||||||
@ -126,48 +79,231 @@ private:
|
|||||||
SkASSERT(!SkScalarNearlyZero(dIn));
|
SkASSERT(!SkScalarNearlyZero(dIn));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t lut[256];
|
|
||||||
|
|
||||||
auto t = -in_0 / dIn,
|
auto t = -in_0 / dIn,
|
||||||
dT = 1 / 255.0f / dIn;
|
dT = 1 / 255.0f / dIn;
|
||||||
|
|
||||||
// TODO: is linear gamma common-enough to warrant a fast path?
|
|
||||||
for (size_t i = 0; i < 256; ++i) {
|
for (size_t i = 0; i < 256; ++i) {
|
||||||
const auto out = out_0 + dOut * std::pow(std::max(t, 0.0f), g);
|
const auto out = out_0 + dOut * std::pow(std::max(t, 0.0f), g);
|
||||||
SkASSERT(!SkScalarIsNaN(out));
|
SkASSERT(!SkScalarIsNaN(out));
|
||||||
|
|
||||||
lut[i] = static_cast<uint8_t>(std::round(SkTPin(out, clip[0], clip[1]) * 255));
|
lut_storage[i] = static_cast<uint8_t>(std::round(SkTPin(out, clip[0], clip[1]) * 255));
|
||||||
|
|
||||||
t += dT;
|
t += dT;
|
||||||
}
|
}
|
||||||
|
|
||||||
fEffect->setColorFilter(SkTableColorFilter::MakeARGB(
|
return lut_storage.data();
|
||||||
channel == kA_Channel ? lut : nullptr,
|
}
|
||||||
channel == kR_Channel || channel == kRGB_Channel ? lut : nullptr,
|
};
|
||||||
channel == kG_Channel || channel == kRGB_Channel ? lut : nullptr,
|
|
||||||
channel == kB_Channel || channel == kRGB_Channel ? lut : nullptr
|
// ADBE Easy Levels2 color correction effect.
|
||||||
|
//
|
||||||
|
// Maps the selected channel(s) from [inBlack...inWhite] to [outBlack, outWhite],
|
||||||
|
// based on a gamma exponent.
|
||||||
|
//
|
||||||
|
// For [i0..i1] -> [o0..o1]:
|
||||||
|
//
|
||||||
|
// c' = o0 + (o1 - o0) * ((c - i0) / (i1 - i0)) ^ G
|
||||||
|
//
|
||||||
|
// The output is optionally clipped to the output range.
|
||||||
|
//
|
||||||
|
// In/out intervals are clampped to [0..1]. Inversion is allowed.
|
||||||
|
|
||||||
|
class EasyLevelsEffectAdapter final : public DiscardableAdapterBase<EasyLevelsEffectAdapter,
|
||||||
|
sksg::ExternalColorFilter> {
|
||||||
|
public:
|
||||||
|
EasyLevelsEffectAdapter(const skjson::ArrayValue& jprops,
|
||||||
|
sk_sp<sksg::RenderNode> layer,
|
||||||
|
const AnimationBuilder* abuilder)
|
||||||
|
: INHERITED(sksg::ExternalColorFilter::Make(std::move(layer))) {
|
||||||
|
enum : size_t {
|
||||||
|
kChannel_Index = 0,
|
||||||
|
// kHist_Index = 1,
|
||||||
|
kInBlack_Index = 2,
|
||||||
|
kInWhite_Index = 3,
|
||||||
|
kGamma_Index = 4,
|
||||||
|
kOutBlack_Index = 5,
|
||||||
|
kOutWhite_Index = 6,
|
||||||
|
kClipToOutBlack_Index = 7,
|
||||||
|
kClipToOutWhite_Index = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
EffectBinder(jprops, *abuilder, this)
|
||||||
|
.bind( kChannel_Index, fChannel )
|
||||||
|
.bind( kInBlack_Index, fMapper.fInBlack )
|
||||||
|
.bind( kInWhite_Index, fMapper.fInWhite )
|
||||||
|
.bind( kGamma_Index, fMapper.fGamma )
|
||||||
|
.bind( kOutBlack_Index, fMapper.fOutBlack)
|
||||||
|
.bind( kOutWhite_Index, fMapper.fOutWhite)
|
||||||
|
.bind(kClipToOutBlack_Index, fClip.fClipBlack )
|
||||||
|
.bind(kClipToOutWhite_Index, fClip.fClipWhite );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onSync() override {
|
||||||
|
enum LottieChannel {
|
||||||
|
kRGB_Channel = 1,
|
||||||
|
kR_Channel = 2,
|
||||||
|
kG_Channel = 3,
|
||||||
|
kB_Channel = 4,
|
||||||
|
kA_Channel = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto channel = SkScalarTruncToInt(fChannel);
|
||||||
|
std::array<uint8_t, 256> lut;
|
||||||
|
if (channel < kRGB_Channel || channel > kA_Channel || !fMapper.build_lut(lut, fClip)) {
|
||||||
|
this->node()->setColorFilter(nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->node()->setColorFilter(SkTableColorFilter::MakeARGB(
|
||||||
|
channel == kA_Channel ? lut.data() : nullptr,
|
||||||
|
channel == kR_Channel || channel == kRGB_Channel ? lut.data() : nullptr,
|
||||||
|
channel == kG_Channel || channel == kRGB_Channel ? lut.data() : nullptr,
|
||||||
|
channel == kB_Channel || channel == kRGB_Channel ? lut.data() : nullptr
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
const sk_sp<sksg::ExternalColorFilter> fEffect;
|
ChannelMapper fMapper;
|
||||||
|
ClipInfo fClip;
|
||||||
|
ScalarValue fChannel = 1; // 1: RGB, 2: R, 3: G, 4: B, 5: A
|
||||||
|
|
||||||
ScalarValue fChannel = 1, // 1: RGB, 2: R, 3: G, 4: B, 5: A
|
using INHERITED = DiscardableAdapterBase<EasyLevelsEffectAdapter, sksg::ExternalColorFilter>;
|
||||||
fInBlack = 0,
|
};
|
||||||
fInWhite = 1,
|
|
||||||
fOutBlack = 0,
|
// ADBE Pro Levels2 color correction effect.
|
||||||
fOutWhite = 1,
|
//
|
||||||
fGamma = 1,
|
// Similar to ADBE Easy Levels2, but offers separate controls for each channel.
|
||||||
fClipBlack = 1, // 1: clip, 2,3: don't clip
|
|
||||||
fClipWhite = 1; // ^
|
class ProLevelsEffectAdapter final : public DiscardableAdapterBase<ProLevelsEffectAdapter,
|
||||||
|
sksg::ExternalColorFilter> {
|
||||||
|
public:
|
||||||
|
ProLevelsEffectAdapter(const skjson::ArrayValue& jprops,
|
||||||
|
sk_sp<sksg::RenderNode> layer,
|
||||||
|
const AnimationBuilder* abuilder)
|
||||||
|
: INHERITED(sksg::ExternalColorFilter::Make(std::move(layer))) {
|
||||||
|
enum : size_t {
|
||||||
|
// kHistChan_Index = 0,
|
||||||
|
// kHist_Index = 1,
|
||||||
|
// kRGBBegin_Index = 2,
|
||||||
|
kRGBInBlack_Index = 3,
|
||||||
|
kRGBInWhite_Index = 4,
|
||||||
|
kRGBGamma_Index = 5,
|
||||||
|
kRGBOutBlack_Index = 6,
|
||||||
|
kRGBOutWhite_Index = 7,
|
||||||
|
// kRGBEnd_Index = 8,
|
||||||
|
// kRBegin_Index = 9,
|
||||||
|
kRInBlack_Index = 10,
|
||||||
|
kRInWhite_Index = 11,
|
||||||
|
kRGamma_Index = 12,
|
||||||
|
kROutBlack_Index = 13,
|
||||||
|
kROutWhite_Index = 14,
|
||||||
|
// kREnd_Index = 15,
|
||||||
|
// kGBegin_Index = 16,
|
||||||
|
kGInBlack_Index = 17,
|
||||||
|
kGInWhite_Index = 18,
|
||||||
|
kGGamma_Index = 19,
|
||||||
|
kGOutBlack_Index = 20,
|
||||||
|
kGOutWhite_Index = 21,
|
||||||
|
// kGEnd_Index = 22,
|
||||||
|
// kBBegin_Index = 23,
|
||||||
|
kBInBlack_Index = 24,
|
||||||
|
kBInWhite_Index = 25,
|
||||||
|
kBGamma_Index = 26,
|
||||||
|
kBOutBlack_Index = 27,
|
||||||
|
kBOutWhite_Index = 28,
|
||||||
|
// kBEnd_Index = 29,
|
||||||
|
// kABegin_Index = 30,
|
||||||
|
kAInBlack_Index = 31,
|
||||||
|
kAInWhite_Index = 32,
|
||||||
|
kAGamma_Index = 33,
|
||||||
|
kAOutBlack_Index = 34,
|
||||||
|
kAOutWhite_Index = 35,
|
||||||
|
// kAEnd_Index = 36,
|
||||||
|
kClipToOutBlack_Index = 37,
|
||||||
|
kClipToOutWhite_Index = 38,
|
||||||
|
};
|
||||||
|
|
||||||
|
EffectBinder(jprops, *abuilder, this)
|
||||||
|
.bind( kRGBInBlack_Index, fRGBMapper.fInBlack )
|
||||||
|
.bind( kRGBInWhite_Index, fRGBMapper.fInWhite )
|
||||||
|
.bind( kRGBGamma_Index, fRGBMapper.fGamma )
|
||||||
|
.bind(kRGBOutBlack_Index, fRGBMapper.fOutBlack)
|
||||||
|
.bind(kRGBOutWhite_Index, fRGBMapper.fOutWhite)
|
||||||
|
|
||||||
|
.bind( kRInBlack_Index, fRMapper.fInBlack )
|
||||||
|
.bind( kRInWhite_Index, fRMapper.fInWhite )
|
||||||
|
.bind( kRGamma_Index, fRMapper.fGamma )
|
||||||
|
.bind(kROutBlack_Index, fRMapper.fOutBlack)
|
||||||
|
.bind(kROutWhite_Index, fRMapper.fOutWhite)
|
||||||
|
|
||||||
|
.bind( kGInBlack_Index, fGMapper.fInBlack )
|
||||||
|
.bind( kGInWhite_Index, fGMapper.fInWhite )
|
||||||
|
.bind( kGGamma_Index, fGMapper.fGamma )
|
||||||
|
.bind(kGOutBlack_Index, fGMapper.fOutBlack)
|
||||||
|
.bind(kGOutWhite_Index, fGMapper.fOutWhite)
|
||||||
|
|
||||||
|
.bind( kBInBlack_Index, fBMapper.fInBlack )
|
||||||
|
.bind( kBInWhite_Index, fBMapper.fInWhite )
|
||||||
|
.bind( kBGamma_Index, fBMapper.fGamma )
|
||||||
|
.bind(kBOutBlack_Index, fBMapper.fOutBlack)
|
||||||
|
.bind(kBOutWhite_Index, fBMapper.fOutWhite)
|
||||||
|
|
||||||
|
.bind( kAInBlack_Index, fAMapper.fInBlack )
|
||||||
|
.bind( kAInWhite_Index, fAMapper.fInWhite )
|
||||||
|
.bind( kAGamma_Index, fAMapper.fGamma )
|
||||||
|
.bind(kAOutBlack_Index, fAMapper.fOutBlack)
|
||||||
|
.bind(kAOutWhite_Index, fAMapper.fOutWhite);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onSync() override {
|
||||||
|
std::array<uint8_t, 256> a_lut_storage,
|
||||||
|
r_lut_storage,
|
||||||
|
g_lut_storage,
|
||||||
|
b_lut_storage;
|
||||||
|
|
||||||
|
auto cf = SkTableColorFilter::MakeARGB(fAMapper.build_lut(a_lut_storage, fClip),
|
||||||
|
fRMapper.build_lut(r_lut_storage, fClip),
|
||||||
|
fGMapper.build_lut(g_lut_storage, fClip),
|
||||||
|
fBMapper.build_lut(b_lut_storage, fClip));
|
||||||
|
|
||||||
|
// The RGB mapper composes outside individual channel mappers.
|
||||||
|
if (const auto* rgb_lut = fRGBMapper.build_lut(a_lut_storage, fClip)) {
|
||||||
|
cf = SkColorFilters::Compose(SkTableColorFilter::MakeARGB(nullptr,
|
||||||
|
rgb_lut,
|
||||||
|
rgb_lut,
|
||||||
|
rgb_lut),
|
||||||
|
std::move(cf));
|
||||||
|
}
|
||||||
|
|
||||||
|
this->node()->setColorFilter(std::move(cf));
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelMapper fRGBMapper,
|
||||||
|
fRMapper,
|
||||||
|
fGMapper,
|
||||||
|
fBMapper,
|
||||||
|
fAMapper;
|
||||||
|
|
||||||
|
ClipInfo fClip;
|
||||||
|
|
||||||
|
using INHERITED = DiscardableAdapterBase<ProLevelsEffectAdapter, sksg::ExternalColorFilter>;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous ns
|
} // anonymous ns
|
||||||
|
|
||||||
sk_sp<sksg::RenderNode> EffectBuilder::attachLevelsEffect(const skjson::ArrayValue& jprops,
|
sk_sp<sksg::RenderNode> EffectBuilder::attachEasyLevelsEffect(const skjson::ArrayValue& jprops,
|
||||||
sk_sp<sksg::RenderNode> layer) const {
|
sk_sp<sksg::RenderNode> layer) const {
|
||||||
return fBuilder->attachDiscardableAdapter<LevelsEffectAdapter>(jprops,
|
return fBuilder->attachDiscardableAdapter<EasyLevelsEffectAdapter>(jprops,
|
||||||
std::move(layer),
|
std::move(layer),
|
||||||
fBuilder);
|
fBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_sp<sksg::RenderNode> EffectBuilder::attachProLevelsEffect(const skjson::ArrayValue& jprops,
|
||||||
|
sk_sp<sksg::RenderNode> layer) const {
|
||||||
|
return fBuilder->attachDiscardableAdapter<ProLevelsEffectAdapter>(jprops,
|
||||||
|
std::move(layer),
|
||||||
|
fBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
1
resources/skottie/skottie-prolevels-effect.json
Normal file
1
resources/skottie/skottie-prolevels-effect.json
Normal file
File diff suppressed because one or more lines are too long
@ -452,6 +452,10 @@ sk_sp<SkColorFilter> SkTableColorFilter::MakeARGB(const uint8_t tableA[256],
|
|||||||
const uint8_t tableR[256],
|
const uint8_t tableR[256],
|
||||||
const uint8_t tableG[256],
|
const uint8_t tableG[256],
|
||||||
const uint8_t tableB[256]) {
|
const uint8_t tableB[256]) {
|
||||||
|
if (!tableA && !tableR && !tableG && !tableB) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return sk_make_sp<SkTable_ColorFilter>(tableA, tableR, tableG, tableB);
|
return sk_make_sp<SkTable_ColorFilter>(tableA, tableR, tableG, tableB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user