1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2021 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkM44.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/Adapter.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottiePriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottieValue.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/effects/Effects.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGNode.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGRenderNode.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
31*c8dee2aaSAndroid Build Coastguard Worker #include <array>
32*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
33*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
34*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
35*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
36*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
37*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker struct SkPoint;
40*c8dee2aaSAndroid Build Coastguard Worker
41*c8dee2aaSAndroid Build Coastguard Worker namespace skjson {
42*c8dee2aaSAndroid Build Coastguard Worker class ArrayValue;
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker namespace sksg {
45*c8dee2aaSAndroid Build Coastguard Worker class InvalidationController;
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker
48*c8dee2aaSAndroid Build Coastguard Worker namespace skottie::internal {
49*c8dee2aaSAndroid Build Coastguard Worker namespace {
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker // An implementation of the ADBE Fractal Noise effect:
52*c8dee2aaSAndroid Build Coastguard Worker //
53*c8dee2aaSAndroid Build Coastguard Worker // - multiple noise sublayers (octaves) are combined using a weighted average
54*c8dee2aaSAndroid Build Coastguard Worker // - each layer is subject to a (cumulative) transform, filter and post-sampling options
55*c8dee2aaSAndroid Build Coastguard Worker //
56*c8dee2aaSAndroid Build Coastguard Worker // Parameters:
57*c8dee2aaSAndroid Build Coastguard Worker //
58*c8dee2aaSAndroid Build Coastguard Worker // * Noise Type -- controls noise layer post-sampling filtering
59*c8dee2aaSAndroid Build Coastguard Worker // (Block, Linear, Soft Linear, Spline)
60*c8dee2aaSAndroid Build Coastguard Worker // * Fractal Type -- determines a noise layer post-filtering transformation
61*c8dee2aaSAndroid Build Coastguard Worker // (Basic, Turbulent Smooth, Turbulent Basic, etc)
62*c8dee2aaSAndroid Build Coastguard Worker // * Transform -- offset/scale/rotate the noise effect (local matrix)
63*c8dee2aaSAndroid Build Coastguard Worker //
64*c8dee2aaSAndroid Build Coastguard Worker // * Complexity -- number of sublayers;
65*c8dee2aaSAndroid Build Coastguard Worker // can be fractional, where the fractional part modulates the last layer
66*c8dee2aaSAndroid Build Coastguard Worker // * Evolution -- controls noise topology in a gradual manner (can be animated for smooth
67*c8dee2aaSAndroid Build Coastguard Worker // noise transitions)
68*c8dee2aaSAndroid Build Coastguard Worker // * Sub Influence -- relative amplitude weight for sublayers (cumulative)
69*c8dee2aaSAndroid Build Coastguard Worker //
70*c8dee2aaSAndroid Build Coastguard Worker // * Sub Scaling/Rotation/Offset -- relative scale for sublayers (cumulative)
71*c8dee2aaSAndroid Build Coastguard Worker //
72*c8dee2aaSAndroid Build Coastguard Worker // * Invert -- invert noise values
73*c8dee2aaSAndroid Build Coastguard Worker //
74*c8dee2aaSAndroid Build Coastguard Worker // * Contrast -- apply a contrast to the noise result
75*c8dee2aaSAndroid Build Coastguard Worker //
76*c8dee2aaSAndroid Build Coastguard Worker // * Brightness -- apply a brightness effect to the noise result
77*c8dee2aaSAndroid Build Coastguard Worker //
78*c8dee2aaSAndroid Build Coastguard Worker //
79*c8dee2aaSAndroid Build Coastguard Worker // TODO:
80*c8dee2aaSAndroid Build Coastguard Worker // - Invert
81*c8dee2aaSAndroid Build Coastguard Worker // - Contrast/Brightness
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gNoiseEffectSkSL[] =
84*c8dee2aaSAndroid Build Coastguard Worker "uniform float3x3 u_submatrix;" // sublayer transform
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker "uniform float2 u_noise_planes;" // noise planes computed based on evolution params
87*c8dee2aaSAndroid Build Coastguard Worker "uniform float u_noise_weight," // noise planes lerp weight
88*c8dee2aaSAndroid Build Coastguard Worker "u_octaves," // number of octaves (can be fractional)
89*c8dee2aaSAndroid Build Coastguard Worker "u_persistence;" // relative octave weight
90*c8dee2aaSAndroid Build Coastguard Worker
91*c8dee2aaSAndroid Build Coastguard Worker // Hash based on hash13 (https://www.shadertoy.com/view/4djSRW).
92*c8dee2aaSAndroid Build Coastguard Worker "float hash(float3 v) {"
93*c8dee2aaSAndroid Build Coastguard Worker "v = fract(v*0.1031);"
94*c8dee2aaSAndroid Build Coastguard Worker "v += dot(v, v.zxy + 31.32);"
95*c8dee2aaSAndroid Build Coastguard Worker "return fract((v.x + v.y)*v.z);"
96*c8dee2aaSAndroid Build Coastguard Worker "}"
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker // The general idea is to compute a coherent hash for two planes in discretized (x,y,e) space,
99*c8dee2aaSAndroid Build Coastguard Worker // and interpolate between them. This yields gradual changes when animating |e| - which is the
100*c8dee2aaSAndroid Build Coastguard Worker // desired outcome.
101*c8dee2aaSAndroid Build Coastguard Worker "float sample_noise(float2 xy) {"
102*c8dee2aaSAndroid Build Coastguard Worker "xy = floor(xy);"
103*c8dee2aaSAndroid Build Coastguard Worker
104*c8dee2aaSAndroid Build Coastguard Worker "float n0 = hash(float3(xy, u_noise_planes.x)),"
105*c8dee2aaSAndroid Build Coastguard Worker "n1 = hash(float3(xy, u_noise_planes.y));"
106*c8dee2aaSAndroid Build Coastguard Worker
107*c8dee2aaSAndroid Build Coastguard Worker // Note: Ideally we would use 4 samples (-1, 0, 1, 2) and cubic interpolation for
108*c8dee2aaSAndroid Build Coastguard Worker // better results -- but that's significantly more expensive than lerp.
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker "return mix(n0, n1, u_noise_weight);"
111*c8dee2aaSAndroid Build Coastguard Worker "}"
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker // filter() placeholder
114*c8dee2aaSAndroid Build Coastguard Worker "%s"
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard Worker // fractal() placeholder
117*c8dee2aaSAndroid Build Coastguard Worker "%s"
118*c8dee2aaSAndroid Build Coastguard Worker
119*c8dee2aaSAndroid Build Coastguard Worker // Generate ceil(u_octaves) noise layers and combine based on persistentce and sublayer xform.
120*c8dee2aaSAndroid Build Coastguard Worker "float4 main(vec2 xy) {"
121*c8dee2aaSAndroid Build Coastguard Worker "float oct = u_octaves," // initial octave count (this is the effective loop counter)
122*c8dee2aaSAndroid Build Coastguard Worker "amp = 1," // initial layer amplitude
123*c8dee2aaSAndroid Build Coastguard Worker "wacc = 0," // weight accumulator
124*c8dee2aaSAndroid Build Coastguard Worker "n = 0;" // noise accumulator
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker // Constant loop counter chosen to be >= ceil(u_octaves).
127*c8dee2aaSAndroid Build Coastguard Worker // The logical counter is actually 'oct'.
128*c8dee2aaSAndroid Build Coastguard Worker "for (float i = 0; i < %u; ++i) {"
129*c8dee2aaSAndroid Build Coastguard Worker // effective layer weight
130*c8dee2aaSAndroid Build Coastguard Worker // -- for full octaves: layer amplitude
131*c8dee2aaSAndroid Build Coastguard Worker // -- for fractional octave: layer amplitude modulated by fractional part
132*c8dee2aaSAndroid Build Coastguard Worker "float w = amp*min(oct,1.0);"
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker "n += w*fractal(filter(xy));"
135*c8dee2aaSAndroid Build Coastguard Worker "wacc += w;"
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker "if (oct <= 1.0) { break; }"
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker "oct -= 1.0;"
140*c8dee2aaSAndroid Build Coastguard Worker "amp *= u_persistence;"
141*c8dee2aaSAndroid Build Coastguard Worker "xy = (u_submatrix*float3(xy,1)).xy;"
142*c8dee2aaSAndroid Build Coastguard Worker "}"
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard Worker "n /= wacc;"
145*c8dee2aaSAndroid Build Coastguard Worker
146*c8dee2aaSAndroid Build Coastguard Worker // TODO: fractal functions
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Worker "return float4(n,n,n,1);"
149*c8dee2aaSAndroid Build Coastguard Worker "}";
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gFilterNearestSkSL[] =
152*c8dee2aaSAndroid Build Coastguard Worker "float filter(float2 xy) {"
153*c8dee2aaSAndroid Build Coastguard Worker "return sample_noise(xy);"
154*c8dee2aaSAndroid Build Coastguard Worker "}";
155*c8dee2aaSAndroid Build Coastguard Worker
156*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gFilterLinearSkSL[] =
157*c8dee2aaSAndroid Build Coastguard Worker "float filter(float2 xy) {"
158*c8dee2aaSAndroid Build Coastguard Worker "xy -= 0.5;"
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker "float n00 = sample_noise(xy + float2(0,0)),"
161*c8dee2aaSAndroid Build Coastguard Worker "n10 = sample_noise(xy + float2(1,0)),"
162*c8dee2aaSAndroid Build Coastguard Worker "n01 = sample_noise(xy + float2(0,1)),"
163*c8dee2aaSAndroid Build Coastguard Worker "n11 = sample_noise(xy + float2(1,1));"
164*c8dee2aaSAndroid Build Coastguard Worker
165*c8dee2aaSAndroid Build Coastguard Worker "float2 t = fract(xy);"
166*c8dee2aaSAndroid Build Coastguard Worker
167*c8dee2aaSAndroid Build Coastguard Worker "return mix(mix(n00, n10, t.x), mix(n01, n11, t.x), t.y);"
168*c8dee2aaSAndroid Build Coastguard Worker "}";
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gFilterSoftLinearSkSL[] =
171*c8dee2aaSAndroid Build Coastguard Worker "float filter(float2 xy) {"
172*c8dee2aaSAndroid Build Coastguard Worker "xy -= 0.5;"
173*c8dee2aaSAndroid Build Coastguard Worker
174*c8dee2aaSAndroid Build Coastguard Worker "float n00 = sample_noise(xy + float2(0,0)),"
175*c8dee2aaSAndroid Build Coastguard Worker "n10 = sample_noise(xy + float2(1,0)),"
176*c8dee2aaSAndroid Build Coastguard Worker "n01 = sample_noise(xy + float2(0,1)),"
177*c8dee2aaSAndroid Build Coastguard Worker "n11 = sample_noise(xy + float2(1,1));"
178*c8dee2aaSAndroid Build Coastguard Worker
179*c8dee2aaSAndroid Build Coastguard Worker "float2 t = smoothstep(0, 1, fract(xy));"
180*c8dee2aaSAndroid Build Coastguard Worker
181*c8dee2aaSAndroid Build Coastguard Worker "return mix(mix(n00, n10, t.x), mix(n01, n11, t.x), t.y);"
182*c8dee2aaSAndroid Build Coastguard Worker "}";
183*c8dee2aaSAndroid Build Coastguard Worker
184*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gFractalBasicSkSL[] =
185*c8dee2aaSAndroid Build Coastguard Worker "float fractal(float n) {"
186*c8dee2aaSAndroid Build Coastguard Worker "return n;"
187*c8dee2aaSAndroid Build Coastguard Worker "}";
188*c8dee2aaSAndroid Build Coastguard Worker
189*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gFractalTurbulentBasicSkSL[] =
190*c8dee2aaSAndroid Build Coastguard Worker "float fractal(float n) {"
191*c8dee2aaSAndroid Build Coastguard Worker "return 2*abs(0.5 - n);"
192*c8dee2aaSAndroid Build Coastguard Worker "}";
193*c8dee2aaSAndroid Build Coastguard Worker
194*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gFractalTurbulentSmoothSkSL[] =
195*c8dee2aaSAndroid Build Coastguard Worker "float fractal(float n) {"
196*c8dee2aaSAndroid Build Coastguard Worker "n = 2*abs(0.5 - n);"
197*c8dee2aaSAndroid Build Coastguard Worker "return n*n;"
198*c8dee2aaSAndroid Build Coastguard Worker "}";
199*c8dee2aaSAndroid Build Coastguard Worker
200*c8dee2aaSAndroid Build Coastguard Worker static constexpr char gFractalTurbulentSharpSkSL[] =
201*c8dee2aaSAndroid Build Coastguard Worker "float fractal(float n) {"
202*c8dee2aaSAndroid Build Coastguard Worker "return sqrt(2*abs(0.5 - n));"
203*c8dee2aaSAndroid Build Coastguard Worker "}";
204*c8dee2aaSAndroid Build Coastguard Worker
205*c8dee2aaSAndroid Build Coastguard Worker enum class NoiseFilter {
206*c8dee2aaSAndroid Build Coastguard Worker kNearest,
207*c8dee2aaSAndroid Build Coastguard Worker kLinear,
208*c8dee2aaSAndroid Build Coastguard Worker kSoftLinear,
209*c8dee2aaSAndroid Build Coastguard Worker // TODO: kSpline?
210*c8dee2aaSAndroid Build Coastguard Worker };
211*c8dee2aaSAndroid Build Coastguard Worker
212*c8dee2aaSAndroid Build Coastguard Worker enum class NoiseFractal {
213*c8dee2aaSAndroid Build Coastguard Worker kBasic,
214*c8dee2aaSAndroid Build Coastguard Worker kTurbulentBasic,
215*c8dee2aaSAndroid Build Coastguard Worker kTurbulentSmooth,
216*c8dee2aaSAndroid Build Coastguard Worker kTurbulentSharp,
217*c8dee2aaSAndroid Build Coastguard Worker };
218*c8dee2aaSAndroid Build Coastguard Worker
make_noise_effect(unsigned loops,const char * filter,const char * fractal)219*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> make_noise_effect(unsigned loops, const char* filter, const char* fractal) {
220*c8dee2aaSAndroid Build Coastguard Worker auto result = SkRuntimeEffect::MakeForShader(
221*c8dee2aaSAndroid Build Coastguard Worker SkStringPrintf(gNoiseEffectSkSL, filter, fractal, loops), {});
222*c8dee2aaSAndroid Build Coastguard Worker
223*c8dee2aaSAndroid Build Coastguard Worker return std::move(result.effect);
224*c8dee2aaSAndroid Build Coastguard Worker }
225*c8dee2aaSAndroid Build Coastguard Worker
noise_effect(float octaves,NoiseFilter filter,NoiseFractal fractal)226*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> noise_effect(float octaves, NoiseFilter filter, NoiseFractal fractal) {
227*c8dee2aaSAndroid Build Coastguard Worker static constexpr char const* gFilters[] = {
228*c8dee2aaSAndroid Build Coastguard Worker gFilterNearestSkSL,
229*c8dee2aaSAndroid Build Coastguard Worker gFilterLinearSkSL,
230*c8dee2aaSAndroid Build Coastguard Worker gFilterSoftLinearSkSL
231*c8dee2aaSAndroid Build Coastguard Worker };
232*c8dee2aaSAndroid Build Coastguard Worker
233*c8dee2aaSAndroid Build Coastguard Worker static constexpr char const* gFractals[] = {
234*c8dee2aaSAndroid Build Coastguard Worker gFractalBasicSkSL,
235*c8dee2aaSAndroid Build Coastguard Worker gFractalTurbulentBasicSkSL,
236*c8dee2aaSAndroid Build Coastguard Worker gFractalTurbulentSmoothSkSL,
237*c8dee2aaSAndroid Build Coastguard Worker gFractalTurbulentSharpSkSL
238*c8dee2aaSAndroid Build Coastguard Worker };
239*c8dee2aaSAndroid Build Coastguard Worker
240*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(static_cast<size_t>(filter) < std::size(gFilters));
241*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(static_cast<size_t>(fractal) < std::size(gFractals));
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker // Bin the loop counter based on the number of octaves (range: [1..20]).
244*c8dee2aaSAndroid Build Coastguard Worker // Low complexities are common, so we maximize resolution for the low end.
245*c8dee2aaSAndroid Build Coastguard Worker struct BinInfo {
246*c8dee2aaSAndroid Build Coastguard Worker float threshold;
247*c8dee2aaSAndroid Build Coastguard Worker unsigned loops;
248*c8dee2aaSAndroid Build Coastguard Worker };
249*c8dee2aaSAndroid Build Coastguard Worker static constexpr BinInfo kLoopBins[] = {
250*c8dee2aaSAndroid Build Coastguard Worker { 8, 20 },
251*c8dee2aaSAndroid Build Coastguard Worker { 4, 8 },
252*c8dee2aaSAndroid Build Coastguard Worker { 3, 4 },
253*c8dee2aaSAndroid Build Coastguard Worker { 2, 3 },
254*c8dee2aaSAndroid Build Coastguard Worker { 1, 2 },
255*c8dee2aaSAndroid Build Coastguard Worker { 0, 1 }
256*c8dee2aaSAndroid Build Coastguard Worker };
257*c8dee2aaSAndroid Build Coastguard Worker
258*c8dee2aaSAndroid Build Coastguard Worker auto bin_index = [](float octaves) {
259*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(octaves > kLoopBins[std::size(kLoopBins) - 1].threshold);
260*c8dee2aaSAndroid Build Coastguard Worker
261*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kLoopBins); ++i) {
262*c8dee2aaSAndroid Build Coastguard Worker if (octaves > kLoopBins[i].threshold) {
263*c8dee2aaSAndroid Build Coastguard Worker return i;
264*c8dee2aaSAndroid Build Coastguard Worker }
265*c8dee2aaSAndroid Build Coastguard Worker }
266*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
267*c8dee2aaSAndroid Build Coastguard Worker };
268*c8dee2aaSAndroid Build Coastguard Worker
269*c8dee2aaSAndroid Build Coastguard Worker static SkRuntimeEffect* kEffectCache[std::size(kLoopBins)]
270*c8dee2aaSAndroid Build Coastguard Worker [std::size(gFilters)]
271*c8dee2aaSAndroid Build Coastguard Worker [std::size(gFractals)];
272*c8dee2aaSAndroid Build Coastguard Worker
273*c8dee2aaSAndroid Build Coastguard Worker const size_t bin = bin_index(octaves);
274*c8dee2aaSAndroid Build Coastguard Worker
275*c8dee2aaSAndroid Build Coastguard Worker auto& effect = kEffectCache[bin]
276*c8dee2aaSAndroid Build Coastguard Worker [static_cast<size_t>(filter)]
277*c8dee2aaSAndroid Build Coastguard Worker [static_cast<size_t>(fractal)];
278*c8dee2aaSAndroid Build Coastguard Worker if (!effect) {
279*c8dee2aaSAndroid Build Coastguard Worker effect = make_noise_effect(kLoopBins[bin].loops,
280*c8dee2aaSAndroid Build Coastguard Worker gFilters[static_cast<size_t>(filter)],
281*c8dee2aaSAndroid Build Coastguard Worker gFractals[static_cast<size_t>(fractal)])
282*c8dee2aaSAndroid Build Coastguard Worker .release();
283*c8dee2aaSAndroid Build Coastguard Worker }
284*c8dee2aaSAndroid Build Coastguard Worker
285*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(effect);
286*c8dee2aaSAndroid Build Coastguard Worker return sk_ref_sp(effect);
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker
289*c8dee2aaSAndroid Build Coastguard Worker class FractalNoiseNode final : public sksg::CustomRenderNode {
290*c8dee2aaSAndroid Build Coastguard Worker public:
FractalNoiseNode(sk_sp<RenderNode> child)291*c8dee2aaSAndroid Build Coastguard Worker explicit FractalNoiseNode(sk_sp<RenderNode> child) : INHERITED({std::move(child)}) {}
292*c8dee2aaSAndroid Build Coastguard Worker
293*c8dee2aaSAndroid Build Coastguard Worker SG_ATTRIBUTE(Matrix , SkMatrix , fMatrix )
294*c8dee2aaSAndroid Build Coastguard Worker SG_ATTRIBUTE(SubMatrix , SkMatrix , fSubMatrix )
295*c8dee2aaSAndroid Build Coastguard Worker
296*c8dee2aaSAndroid Build Coastguard Worker SG_ATTRIBUTE(NoiseFilter , NoiseFilter , fFilter )
297*c8dee2aaSAndroid Build Coastguard Worker SG_ATTRIBUTE(NoiseFractal , NoiseFractal, fFractal )
298*c8dee2aaSAndroid Build Coastguard Worker SG_ATTRIBUTE(NoisePlanes , SkV2 , fNoisePlanes )
299*c8dee2aaSAndroid Build Coastguard Worker SG_ATTRIBUTE(NoiseWeight , float , fNoiseWeight )
300*c8dee2aaSAndroid Build Coastguard Worker SG_ATTRIBUTE(Octaves , float , fOctaves )
301*c8dee2aaSAndroid Build Coastguard Worker SG_ATTRIBUTE(Persistence , float , fPersistence )
302*c8dee2aaSAndroid Build Coastguard Worker
303*c8dee2aaSAndroid Build Coastguard Worker private:
getEffect(NoiseFilter filter) const304*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> getEffect(NoiseFilter filter) const {
305*c8dee2aaSAndroid Build Coastguard Worker switch (fFractal) {
306*c8dee2aaSAndroid Build Coastguard Worker case NoiseFractal::kBasic:
307*c8dee2aaSAndroid Build Coastguard Worker return noise_effect(fOctaves, filter, NoiseFractal::kBasic);
308*c8dee2aaSAndroid Build Coastguard Worker case NoiseFractal::kTurbulentBasic:
309*c8dee2aaSAndroid Build Coastguard Worker return noise_effect(fOctaves, filter, NoiseFractal::kTurbulentBasic);
310*c8dee2aaSAndroid Build Coastguard Worker case NoiseFractal::kTurbulentSmooth:
311*c8dee2aaSAndroid Build Coastguard Worker return noise_effect(fOctaves, filter, NoiseFractal::kTurbulentSmooth);
312*c8dee2aaSAndroid Build Coastguard Worker case NoiseFractal::kTurbulentSharp:
313*c8dee2aaSAndroid Build Coastguard Worker return noise_effect(fOctaves, filter, NoiseFractal::kTurbulentSharp);
314*c8dee2aaSAndroid Build Coastguard Worker }
315*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
316*c8dee2aaSAndroid Build Coastguard Worker }
317*c8dee2aaSAndroid Build Coastguard Worker
getEffect() const318*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkRuntimeEffect> getEffect() const {
319*c8dee2aaSAndroid Build Coastguard Worker switch (fFilter) {
320*c8dee2aaSAndroid Build Coastguard Worker case NoiseFilter::kNearest : return this->getEffect(NoiseFilter::kNearest);
321*c8dee2aaSAndroid Build Coastguard Worker case NoiseFilter::kLinear : return this->getEffect(NoiseFilter::kLinear);
322*c8dee2aaSAndroid Build Coastguard Worker case NoiseFilter::kSoftLinear: return this->getEffect(NoiseFilter::kSoftLinear);
323*c8dee2aaSAndroid Build Coastguard Worker }
324*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
325*c8dee2aaSAndroid Build Coastguard Worker }
326*c8dee2aaSAndroid Build Coastguard Worker
buildEffectShader() const327*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> buildEffectShader() const {
328*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeShaderBuilder builder(this->getEffect());
329*c8dee2aaSAndroid Build Coastguard Worker
330*c8dee2aaSAndroid Build Coastguard Worker builder.uniform("u_noise_planes") = fNoisePlanes;
331*c8dee2aaSAndroid Build Coastguard Worker builder.uniform("u_noise_weight") = fNoiseWeight;
332*c8dee2aaSAndroid Build Coastguard Worker builder.uniform("u_octaves" ) = fOctaves;
333*c8dee2aaSAndroid Build Coastguard Worker builder.uniform("u_persistence" ) = fPersistence;
334*c8dee2aaSAndroid Build Coastguard Worker builder.uniform("u_submatrix" ) = std::array<float,9>{
335*c8dee2aaSAndroid Build Coastguard Worker fSubMatrix.rc(0,0), fSubMatrix.rc(1,0), fSubMatrix.rc(2,0),
336*c8dee2aaSAndroid Build Coastguard Worker fSubMatrix.rc(0,1), fSubMatrix.rc(1,1), fSubMatrix.rc(2,1),
337*c8dee2aaSAndroid Build Coastguard Worker fSubMatrix.rc(0,2), fSubMatrix.rc(1,2), fSubMatrix.rc(2,2),
338*c8dee2aaSAndroid Build Coastguard Worker };
339*c8dee2aaSAndroid Build Coastguard Worker
340*c8dee2aaSAndroid Build Coastguard Worker return builder.makeShader(&fMatrix);
341*c8dee2aaSAndroid Build Coastguard Worker }
342*c8dee2aaSAndroid Build Coastguard Worker
onRevalidate(sksg::InvalidationController * ic,const SkMatrix & ctm)343*c8dee2aaSAndroid Build Coastguard Worker SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
344*c8dee2aaSAndroid Build Coastguard Worker const auto& child = this->children()[0];
345*c8dee2aaSAndroid Build Coastguard Worker const auto bounds = child->revalidate(ic, ctm);
346*c8dee2aaSAndroid Build Coastguard Worker
347*c8dee2aaSAndroid Build Coastguard Worker fEffectShader = this->buildEffectShader();
348*c8dee2aaSAndroid Build Coastguard Worker
349*c8dee2aaSAndroid Build Coastguard Worker return bounds;
350*c8dee2aaSAndroid Build Coastguard Worker }
351*c8dee2aaSAndroid Build Coastguard Worker
onRender(SkCanvas * canvas,const RenderContext * ctx) const352*c8dee2aaSAndroid Build Coastguard Worker void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
353*c8dee2aaSAndroid Build Coastguard Worker const auto& bounds = this->bounds();
354*c8dee2aaSAndroid Build Coastguard Worker const auto local_ctx = ScopedRenderContext(canvas, ctx)
355*c8dee2aaSAndroid Build Coastguard Worker .setIsolation(bounds, canvas->getTotalMatrix(), true);
356*c8dee2aaSAndroid Build Coastguard Worker
357*c8dee2aaSAndroid Build Coastguard Worker canvas->saveLayer(&bounds, nullptr);
358*c8dee2aaSAndroid Build Coastguard Worker this->children()[0]->render(canvas, local_ctx);
359*c8dee2aaSAndroid Build Coastguard Worker
360*c8dee2aaSAndroid Build Coastguard Worker SkPaint effect_paint;
361*c8dee2aaSAndroid Build Coastguard Worker effect_paint.setShader(fEffectShader);
362*c8dee2aaSAndroid Build Coastguard Worker effect_paint.setBlendMode(SkBlendMode::kSrcIn);
363*c8dee2aaSAndroid Build Coastguard Worker
364*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPaint(effect_paint);
365*c8dee2aaSAndroid Build Coastguard Worker }
366*c8dee2aaSAndroid Build Coastguard Worker
onNodeAt(const SkPoint &) const367*c8dee2aaSAndroid Build Coastguard Worker const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing
368*c8dee2aaSAndroid Build Coastguard Worker
369*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> fEffectShader;
370*c8dee2aaSAndroid Build Coastguard Worker
371*c8dee2aaSAndroid Build Coastguard Worker SkMatrix fMatrix,
372*c8dee2aaSAndroid Build Coastguard Worker fSubMatrix;
373*c8dee2aaSAndroid Build Coastguard Worker NoiseFilter fFilter = NoiseFilter::kNearest;
374*c8dee2aaSAndroid Build Coastguard Worker NoiseFractal fFractal = NoiseFractal::kBasic;
375*c8dee2aaSAndroid Build Coastguard Worker SkV2 fNoisePlanes = {0,0};
376*c8dee2aaSAndroid Build Coastguard Worker float fNoiseWeight = 0,
377*c8dee2aaSAndroid Build Coastguard Worker fOctaves = 1,
378*c8dee2aaSAndroid Build Coastguard Worker fPersistence = 1;
379*c8dee2aaSAndroid Build Coastguard Worker
380*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = sksg::CustomRenderNode;
381*c8dee2aaSAndroid Build Coastguard Worker };
382*c8dee2aaSAndroid Build Coastguard Worker
383*c8dee2aaSAndroid Build Coastguard Worker class FractalNoiseAdapter final : public DiscardableAdapterBase<FractalNoiseAdapter,
384*c8dee2aaSAndroid Build Coastguard Worker FractalNoiseNode> {
385*c8dee2aaSAndroid Build Coastguard Worker public:
FractalNoiseAdapter(const skjson::ArrayValue & jprops,const AnimationBuilder * abuilder,sk_sp<FractalNoiseNode> node)386*c8dee2aaSAndroid Build Coastguard Worker FractalNoiseAdapter(const skjson::ArrayValue& jprops,
387*c8dee2aaSAndroid Build Coastguard Worker const AnimationBuilder* abuilder,
388*c8dee2aaSAndroid Build Coastguard Worker sk_sp<FractalNoiseNode> node)
389*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(std::move(node))
390*c8dee2aaSAndroid Build Coastguard Worker {
391*c8dee2aaSAndroid Build Coastguard Worker EffectBinder(jprops, *abuilder, this)
392*c8dee2aaSAndroid Build Coastguard Worker .bind( 0, fFractalType )
393*c8dee2aaSAndroid Build Coastguard Worker .bind( 1, fNoiseType )
394*c8dee2aaSAndroid Build Coastguard Worker .bind( 2, fInvert )
395*c8dee2aaSAndroid Build Coastguard Worker .bind( 3, fContrast )
396*c8dee2aaSAndroid Build Coastguard Worker .bind( 4, fBrightness )
397*c8dee2aaSAndroid Build Coastguard Worker // 5 -- overflow
398*c8dee2aaSAndroid Build Coastguard Worker // 6 -- transform begin-group
399*c8dee2aaSAndroid Build Coastguard Worker .bind( 7, fRotation )
400*c8dee2aaSAndroid Build Coastguard Worker .bind( 8, fUniformScaling )
401*c8dee2aaSAndroid Build Coastguard Worker .bind( 9, fScale )
402*c8dee2aaSAndroid Build Coastguard Worker .bind(10, fScaleWidth )
403*c8dee2aaSAndroid Build Coastguard Worker .bind(11, fScaleHeight )
404*c8dee2aaSAndroid Build Coastguard Worker .bind(12, fOffset )
405*c8dee2aaSAndroid Build Coastguard Worker // 13 -- TODO: perspective offset
406*c8dee2aaSAndroid Build Coastguard Worker // 14 -- transform end-group
407*c8dee2aaSAndroid Build Coastguard Worker .bind(15, fComplexity )
408*c8dee2aaSAndroid Build Coastguard Worker // 16 -- sub settings begin-group
409*c8dee2aaSAndroid Build Coastguard Worker .bind(17, fSubInfluence )
410*c8dee2aaSAndroid Build Coastguard Worker .bind(18, fSubScale )
411*c8dee2aaSAndroid Build Coastguard Worker .bind(19, fSubRotation )
412*c8dee2aaSAndroid Build Coastguard Worker .bind(20, fSubOffset )
413*c8dee2aaSAndroid Build Coastguard Worker // 21 -- center subscale
414*c8dee2aaSAndroid Build Coastguard Worker // 22 -- sub settings end-group
415*c8dee2aaSAndroid Build Coastguard Worker .bind(23, fEvolution )
416*c8dee2aaSAndroid Build Coastguard Worker // 24 -- evolution options begin-group
417*c8dee2aaSAndroid Build Coastguard Worker .bind(25, fCycleEvolution )
418*c8dee2aaSAndroid Build Coastguard Worker .bind(26, fCycleRevolutions)
419*c8dee2aaSAndroid Build Coastguard Worker .bind(27, fRandomSeed )
420*c8dee2aaSAndroid Build Coastguard Worker // 28 -- evolution options end-group
421*c8dee2aaSAndroid Build Coastguard Worker .bind(29, fOpacity );
422*c8dee2aaSAndroid Build Coastguard Worker // 30 -- TODO: blending mode
423*c8dee2aaSAndroid Build Coastguard Worker }
424*c8dee2aaSAndroid Build Coastguard Worker
425*c8dee2aaSAndroid Build Coastguard Worker private:
noise() const426*c8dee2aaSAndroid Build Coastguard Worker std::tuple<SkV2, float> noise() const {
427*c8dee2aaSAndroid Build Coastguard Worker // Constant chosen to visually match AE's evolution rate.
428*c8dee2aaSAndroid Build Coastguard Worker static constexpr auto kEvolutionScale = 0.25f;
429*c8dee2aaSAndroid Build Coastguard Worker
430*c8dee2aaSAndroid Build Coastguard Worker // Evolution inputs:
431*c8dee2aaSAndroid Build Coastguard Worker //
432*c8dee2aaSAndroid Build Coastguard Worker // * evolution - main evolution control (degrees)
433*c8dee2aaSAndroid Build Coastguard Worker // * cycle evolution - flag controlling whether evolution cycles
434*c8dee2aaSAndroid Build Coastguard Worker // * cycle revolutions - number of revolutions after which evolution cycles (period)
435*c8dee2aaSAndroid Build Coastguard Worker // * random seed - determines an arbitrary starting plane (evolution offset)
436*c8dee2aaSAndroid Build Coastguard Worker //
437*c8dee2aaSAndroid Build Coastguard Worker // The shader uses evolution floor/ceil to select two noise planes, and the fractional part
438*c8dee2aaSAndroid Build Coastguard Worker // to interpolate between the two -> in order to wrap around smoothly, the cycle/period
439*c8dee2aaSAndroid Build Coastguard Worker // must be integral.
440*c8dee2aaSAndroid Build Coastguard Worker const float
441*c8dee2aaSAndroid Build Coastguard Worker evo_rad = SkDegreesToRadians(fEvolution),
442*c8dee2aaSAndroid Build Coastguard Worker rev_rad = std::max(fCycleRevolutions, 1.0f)*SK_FloatPI*2,
443*c8dee2aaSAndroid Build Coastguard Worker cycle = fCycleEvolution
444*c8dee2aaSAndroid Build Coastguard Worker ? SkScalarRoundToScalar(rev_rad*kEvolutionScale)
445*c8dee2aaSAndroid Build Coastguard Worker : SK_ScalarMax,
446*c8dee2aaSAndroid Build Coastguard Worker // Adjust scale when cycling to ensure an integral period (post scaling).
447*c8dee2aaSAndroid Build Coastguard Worker scale = fCycleEvolution
448*c8dee2aaSAndroid Build Coastguard Worker ? cycle/rev_rad
449*c8dee2aaSAndroid Build Coastguard Worker : kEvolutionScale,
450*c8dee2aaSAndroid Build Coastguard Worker offset = SkRandom(static_cast<uint32_t>(fRandomSeed)).nextRangeU(0, 100),
451*c8dee2aaSAndroid Build Coastguard Worker evo = evo_rad*scale,
452*c8dee2aaSAndroid Build Coastguard Worker evo_ = std::floor(evo),
453*c8dee2aaSAndroid Build Coastguard Worker weight = evo - evo_;
454*c8dee2aaSAndroid Build Coastguard Worker
455*c8dee2aaSAndroid Build Coastguard Worker // We want the GLSL mod() flavor.
456*c8dee2aaSAndroid Build Coastguard Worker auto glsl_mod = [](float x, float y) {
457*c8dee2aaSAndroid Build Coastguard Worker return x - y*std::floor(x/y);
458*c8dee2aaSAndroid Build Coastguard Worker };
459*c8dee2aaSAndroid Build Coastguard Worker
460*c8dee2aaSAndroid Build Coastguard Worker const SkV2 noise_planes = {
461*c8dee2aaSAndroid Build Coastguard Worker glsl_mod(evo_ + 0, cycle) + offset,
462*c8dee2aaSAndroid Build Coastguard Worker glsl_mod(evo_ + 1, cycle) + offset,
463*c8dee2aaSAndroid Build Coastguard Worker };
464*c8dee2aaSAndroid Build Coastguard Worker
465*c8dee2aaSAndroid Build Coastguard Worker return std::make_tuple(noise_planes, weight);
466*c8dee2aaSAndroid Build Coastguard Worker }
467*c8dee2aaSAndroid Build Coastguard Worker
shaderMatrix() const468*c8dee2aaSAndroid Build Coastguard Worker SkMatrix shaderMatrix() const {
469*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kGridSize = 64;
470*c8dee2aaSAndroid Build Coastguard Worker
471*c8dee2aaSAndroid Build Coastguard Worker const auto scale = (SkScalarRoundToInt(fUniformScaling) == 1)
472*c8dee2aaSAndroid Build Coastguard Worker ? SkV2{fScale, fScale}
473*c8dee2aaSAndroid Build Coastguard Worker : SkV2{fScaleWidth, fScaleHeight};
474*c8dee2aaSAndroid Build Coastguard Worker
475*c8dee2aaSAndroid Build Coastguard Worker return SkMatrix::Translate(fOffset.x, fOffset.y)
476*c8dee2aaSAndroid Build Coastguard Worker * SkMatrix::Scale(SkTPin(scale.x, 1.0f, 10000.0f) * 0.01f,
477*c8dee2aaSAndroid Build Coastguard Worker SkTPin(scale.y, 1.0f, 10000.0f) * 0.01f)
478*c8dee2aaSAndroid Build Coastguard Worker * SkMatrix::RotateDeg(fRotation)
479*c8dee2aaSAndroid Build Coastguard Worker * SkMatrix::Scale(kGridSize, kGridSize);
480*c8dee2aaSAndroid Build Coastguard Worker }
481*c8dee2aaSAndroid Build Coastguard Worker
subMatrix() const482*c8dee2aaSAndroid Build Coastguard Worker SkMatrix subMatrix() const {
483*c8dee2aaSAndroid Build Coastguard Worker const auto scale = 100 / SkTPin(fSubScale, 10.0f, 10000.0f);
484*c8dee2aaSAndroid Build Coastguard Worker
485*c8dee2aaSAndroid Build Coastguard Worker return SkMatrix::Translate(-fSubOffset.x * 0.01f, -fSubOffset.y * 0.01f)
486*c8dee2aaSAndroid Build Coastguard Worker * SkMatrix::RotateDeg(-fSubRotation)
487*c8dee2aaSAndroid Build Coastguard Worker * SkMatrix::Scale(scale, scale);
488*c8dee2aaSAndroid Build Coastguard Worker }
489*c8dee2aaSAndroid Build Coastguard Worker
noiseFilter() const490*c8dee2aaSAndroid Build Coastguard Worker NoiseFilter noiseFilter() const {
491*c8dee2aaSAndroid Build Coastguard Worker switch (SkScalarRoundToInt(fNoiseType)) {
492*c8dee2aaSAndroid Build Coastguard Worker case 1: return NoiseFilter::kNearest;
493*c8dee2aaSAndroid Build Coastguard Worker case 2: return NoiseFilter::kLinear;
494*c8dee2aaSAndroid Build Coastguard Worker default: return NoiseFilter::kSoftLinear;
495*c8dee2aaSAndroid Build Coastguard Worker }
496*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
497*c8dee2aaSAndroid Build Coastguard Worker }
498*c8dee2aaSAndroid Build Coastguard Worker
noiseFractal() const499*c8dee2aaSAndroid Build Coastguard Worker NoiseFractal noiseFractal() const {
500*c8dee2aaSAndroid Build Coastguard Worker switch (SkScalarRoundToInt(fFractalType)) {
501*c8dee2aaSAndroid Build Coastguard Worker case 1: return NoiseFractal::kBasic;
502*c8dee2aaSAndroid Build Coastguard Worker case 3: return NoiseFractal::kTurbulentSmooth;
503*c8dee2aaSAndroid Build Coastguard Worker case 4: return NoiseFractal::kTurbulentBasic;
504*c8dee2aaSAndroid Build Coastguard Worker default: return NoiseFractal::kTurbulentSharp;
505*c8dee2aaSAndroid Build Coastguard Worker }
506*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
507*c8dee2aaSAndroid Build Coastguard Worker }
508*c8dee2aaSAndroid Build Coastguard Worker
onSync()509*c8dee2aaSAndroid Build Coastguard Worker void onSync() override {
510*c8dee2aaSAndroid Build Coastguard Worker const auto& n = this->node();
511*c8dee2aaSAndroid Build Coastguard Worker
512*c8dee2aaSAndroid Build Coastguard Worker const auto [noise_planes, noise_weight] = this->noise();
513*c8dee2aaSAndroid Build Coastguard Worker
514*c8dee2aaSAndroid Build Coastguard Worker n->setOctaves(SkTPin(fComplexity, 1.0f, 20.0f));
515*c8dee2aaSAndroid Build Coastguard Worker n->setPersistence(SkTPin(fSubInfluence * 0.01f, 0.0f, 100.0f));
516*c8dee2aaSAndroid Build Coastguard Worker n->setNoisePlanes(noise_planes);
517*c8dee2aaSAndroid Build Coastguard Worker n->setNoiseWeight(noise_weight);
518*c8dee2aaSAndroid Build Coastguard Worker n->setNoiseFilter(this->noiseFilter());
519*c8dee2aaSAndroid Build Coastguard Worker n->setNoiseFractal(this->noiseFractal());
520*c8dee2aaSAndroid Build Coastguard Worker n->setMatrix(this->shaderMatrix());
521*c8dee2aaSAndroid Build Coastguard Worker n->setSubMatrix(this->subMatrix());
522*c8dee2aaSAndroid Build Coastguard Worker }
523*c8dee2aaSAndroid Build Coastguard Worker
524*c8dee2aaSAndroid Build Coastguard Worker Vec2Value fOffset = {0,0},
525*c8dee2aaSAndroid Build Coastguard Worker fSubOffset = {0,0};
526*c8dee2aaSAndroid Build Coastguard Worker
527*c8dee2aaSAndroid Build Coastguard Worker ScalarValue fFractalType = 0,
528*c8dee2aaSAndroid Build Coastguard Worker fNoiseType = 0,
529*c8dee2aaSAndroid Build Coastguard Worker
530*c8dee2aaSAndroid Build Coastguard Worker fRotation = 0,
531*c8dee2aaSAndroid Build Coastguard Worker fUniformScaling = 0,
532*c8dee2aaSAndroid Build Coastguard Worker fScale = 100, // used when uniform scaling is selected
533*c8dee2aaSAndroid Build Coastguard Worker fScaleWidth = 100, // used when uniform scaling is not selected
534*c8dee2aaSAndroid Build Coastguard Worker fScaleHeight = 100, // ^
535*c8dee2aaSAndroid Build Coastguard Worker
536*c8dee2aaSAndroid Build Coastguard Worker fComplexity = 1,
537*c8dee2aaSAndroid Build Coastguard Worker fSubInfluence = 100,
538*c8dee2aaSAndroid Build Coastguard Worker fSubScale = 50,
539*c8dee2aaSAndroid Build Coastguard Worker fSubRotation = 0,
540*c8dee2aaSAndroid Build Coastguard Worker
541*c8dee2aaSAndroid Build Coastguard Worker fEvolution = 0,
542*c8dee2aaSAndroid Build Coastguard Worker fCycleEvolution = 0,
543*c8dee2aaSAndroid Build Coastguard Worker fCycleRevolutions = 0,
544*c8dee2aaSAndroid Build Coastguard Worker fRandomSeed = 0,
545*c8dee2aaSAndroid Build Coastguard Worker
546*c8dee2aaSAndroid Build Coastguard Worker fOpacity = 100, // TODO
547*c8dee2aaSAndroid Build Coastguard Worker fInvert = 0, // TODO
548*c8dee2aaSAndroid Build Coastguard Worker fContrast = 100, // TODO
549*c8dee2aaSAndroid Build Coastguard Worker fBrightness = 0; // TODO
550*c8dee2aaSAndroid Build Coastguard Worker
551*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = DiscardableAdapterBase<FractalNoiseAdapter, FractalNoiseNode>;
552*c8dee2aaSAndroid Build Coastguard Worker };
553*c8dee2aaSAndroid Build Coastguard Worker
554*c8dee2aaSAndroid Build Coastguard Worker } // namespace
555*c8dee2aaSAndroid Build Coastguard Worker
attachFractalNoiseEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const556*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> EffectBuilder::attachFractalNoiseEffect(
557*c8dee2aaSAndroid Build Coastguard Worker const skjson::ArrayValue& jprops, sk_sp<sksg::RenderNode> layer) const {
558*c8dee2aaSAndroid Build Coastguard Worker auto fractal_noise = sk_make_sp<FractalNoiseNode>(std::move(layer));
559*c8dee2aaSAndroid Build Coastguard Worker
560*c8dee2aaSAndroid Build Coastguard Worker return fBuilder->attachDiscardableAdapter<FractalNoiseAdapter>(jprops, fBuilder,
561*c8dee2aaSAndroid Build Coastguard Worker std::move(fractal_noise));
562*c8dee2aaSAndroid Build Coastguard Worker }
563*c8dee2aaSAndroid Build Coastguard Worker
564*c8dee2aaSAndroid Build Coastguard Worker } // namespace skottie::internal
565