45class InvalidationController;
64static constexpr char gDisplacementSkSL[] =
65 "uniform shader child;"
66 "uniform shader displ;"
68 "uniform half4x4 selector_matrix;"
69 "uniform half4 selector_offset;"
71 "half4 main(float2 xy) {"
72 "half4 d = displ.eval(xy);"
74 "d = selector_matrix*unpremul(d) + selector_offset;"
76 "return child.eval(xy + d.xy*d.zw);"
85 printf(
"!!! %s\n", err.c_str());
94 ~DisplacementNode()
override {
95 this->unobserveInval(fDisplSource);
101 const SkSize& displ_size) {
102 if (!child || !displ) {
107 std::move(displ), displ_size));
110 enum class Pos :
unsigned {
118 enum class Selector :
unsigned {
145 , fDisplSource(std::move(displ))
146 , fDisplSize(displ_size)
147 , fChildSize(child_size)
149 this->observeInval(fDisplSource);
152 struct SelectorCoeffs {
157 static SelectorCoeffs Coeffs(Selector sel) {
160 static constexpr SelectorCoeffs gCoeffs[] = {
171 { 0,0,0,0,.5f, 0,1 },
175 const auto i =
static_cast<size_t>(sel);
181 static bool IsConst(Selector
s) {
182 return s == Selector::kFull
183 ||
s == Selector::kHalf
184 ||
s == Selector::kOff;
190 if ((IsConst(fXSelector) && IsConst(fYSelector)) ||
201 const auto bounds = node->revalidate(ic, ctm);
208 const auto child_content = get_content_picture(this->children()[0], ic, ctm),
209 displ_content = get_content_picture(fDisplSource, ic, ctm);
210 if (!child_content || !displ_content) {
215 auto child_shader = child_content->makeShader(fChildTileMode,
222 const auto displ_mode = this->displacementTileMode();
223 const auto displ_matrix = this->displacementMatrix();
224 auto displ_shader = displ_content->makeShader(displ_mode,
231 builder.child(
"child") = std::move(child_shader);
232 builder.child(
"displ") = std::move(displ_shader);
234 const auto xc = Coeffs(fXSelector),
235 yc = Coeffs(fYSelector);
237 const auto s = fScale * 2;
239 const float selector_m[] = {
240 xc.dr*
s.
x, yc.dr*
s.
y, 0, 0,
241 xc.dg*
s.
x, yc.dg*
s.
y, 0, 0,
242 xc.db*
s.
x, yc.db*
s.
y, 0, 0,
243 xc.da*
s.
x, yc.da*
s.
y, xc.c_scale, yc.c_scale,
250 const float selector_o[] = {
251 (xc.d_offset - .5f) *
s.
x,
252 (yc.d_offset - .5f) *
s.
y,
257 builder.uniform(
"selector_matrix") = selector_m;
258 builder.uniform(
"selector_offset") = selector_o;
265 fEffectShader = this->buildEffectShader(ic, ctm);
267 auto bounds = this->children()[0]->revalidate(ic, ctm);
270 bounds.outset(std::abs(fScale.
x), std::abs(fScale.
y));
276 void onRender(
SkCanvas* canvas,
const RenderContext* ctx)
const override {
277 if (!fEffectShader) {
279 this->children()[0]->render(canvas, ctx);
283 auto local_ctx = ScopedRenderContext(canvas, ctx).setIsolation(this->
bounds(),
293 return fPos == Pos::kTile
298 SkMatrix displacementMatrix()
const {
311 const RenderNode* onNodeAt(
const SkPoint&)
const override {
return nullptr; }
320 SkV2 fScale = { 0, 0 };
322 Pos fPos = Pos::kCenter;
323 Selector fXSelector = Selector::kR,
324 fYSelector = Selector::kR;
325 bool fExpandBounds =
false;
330class DisplacementMapAdapter final :
public DiscardableAdapterBase<DisplacementMapAdapter,
334 const AnimationBuilder* abuilder,
337 EffectBinder(jprops, *abuilder,
this)
338 .bind(kUseForHorizontal_Index, fHorizontalSelector)
339 .bind(kMaxHorizontal_Index , fMaxHorizontal )
340 .bind(kUseForVertical_Index , fVerticalSelector )
341 .bind(kMaxVertical_Index , fMaxVertical )
342 .bind(kMapBehavior_Index , fMapBehavior )
343 .bind(kEdgeBehavior_Index , fEdgeBehavior )
344 .bind(kExpandOutput_Index , fExpandOutput );
347 static std::tuple<sk_sp<sksg::RenderNode>,
SkSize> GetDisplacementSource(
349 const EffectBuilder* ebuilder) {
352 auto* map_builder = ebuilder->getLayerBuilder(
ParseDefault((*jv)[
"k"], -1));
354 return std::make_tuple(map_builder->contentTree(), map_builder->size());
358 return std::make_tuple<sk_sp<sksg::RenderNode>,
SkSize>(
nullptr, {0,0});
364 kUseForHorizontal_Index = 1,
365 kMaxHorizontal_Index = 2,
366 kUseForVertical_Index = 3,
367 kMaxVertical_Index = 4,
368 kMapBehavior_Index = 5,
369 kEdgeBehavior_Index = 6,
370 kExpandOutput_Index = 7,
373 template <
typename E>
376 const auto uv = std::min(
static_cast<unsigned>(v) - 1,
377 static_cast<unsigned>(E::kLast));
379 return static_cast<E>(uv);
382 void onSync()
override {
387 this->node()->setScale({fMaxHorizontal, fMaxVertical});
391 this->node()->setPos(ToEnum<DisplacementNode::Pos>(fMapBehavior));
392 this->node()->setXSelector(ToEnum<DisplacementNode::Selector>(fHorizontalSelector));
393 this->node()->setYSelector(ToEnum<DisplacementNode::Selector>(fVerticalSelector));
394 this->node()->setExpandBounds(fExpandOutput != 0);
398 fVerticalSelector = 0,
405 using INHERITED = DiscardableAdapterBase<DisplacementMapAdapter, DisplacementNode>;
412 auto [ displ, displ_size ] = DisplacementMapAdapter::GetDisplacementSource(jprops,
this);
414 auto displ_node = DisplacementNode::Make(layer, fLayerSize, std::move(displ), displ_size);
422 std::move(displ_node));
@ kSaturation
saturation of source with hue and luminosity of destination
@ kHue
hue of source with saturation and luminosity of destination
@ kFull
modifies glyph outlines for maximum constrast
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
static constexpr uint16_t kHalf
#define INHERITED(method,...)
sk_sp< T > sk_ref_sp(T *obj)
#define SG_ATTRIBUTE(attr_name, attr_type, attr_container)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
void drawRect(const SkRect &rect, const SkPaint &paint)
SkMatrix getTotalMatrix() const
static SkMatrix Scale(SkScalar sx, SkScalar sy)
static SkMatrix Translate(SkScalar dx, SkScalar dy)
static const SkMatrix & I()
void setShader(sk_sp< SkShader > shader)
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
static Result MakeForShader(SkString sksl, const Options &)
void attachDiscardableAdapter(sk_sp< T > adapter) const
static const skjson::Value & GetPropValue(const skjson::ArrayValue &jprops, size_t prop_index)
Optional< SkRect > bounds
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
T ParseDefault(const skjson::Value &v, const T &defaultValue)
static constexpr SkRect MakeSize(const SkSize &size)
sk_sp< SkRuntimeEffect > effect