45class InvalidationController;
83static constexpr char gNoiseEffectSkSL[] =
84 "uniform float3x3 u_submatrix;"
86 "uniform float2 u_noise_planes;"
87 "uniform float u_noise_weight,"
92 "float hash(float3 v) {"
93 "v = fract(v*0.1031);"
94 "v += dot(v, v.zxy + 31.32);"
95 "return fract((v.x + v.y)*v.z);"
101 "float sample_noise(float2 xy) {"
104 "float n0 = hash(float3(xy, u_noise_planes.x)),"
105 "n1 = hash(float3(xy, u_noise_planes.y));"
110 "return mix(n0, n1, u_noise_weight);"
120 "float4 main(vec2 xy) {"
121 "float oct = u_octaves,"
128 "for (float i = 0; i < %u; ++i) {"
132 "float w = amp*min(oct,1.0);"
134 "n += w*fractal(filter(xy));"
137 "if (oct <= 1.0) { break; }"
140 "amp *= u_persistence;"
141 "xy = (u_submatrix*float3(xy,1)).xy;"
148 "return float4(n,n,n,1);"
151static constexpr char gFilterNearestSkSL[] =
152 "float filter(float2 xy) {"
153 "return sample_noise(xy);"
156static constexpr char gFilterLinearSkSL[] =
157 "float filter(float2 xy) {"
160 "float n00 = sample_noise(xy + float2(0,0)),"
161 "n10 = sample_noise(xy + float2(1,0)),"
162 "n01 = sample_noise(xy + float2(0,1)),"
163 "n11 = sample_noise(xy + float2(1,1));"
165 "float2 t = fract(xy);"
167 "return mix(mix(n00, n10, t.x), mix(n01, n11, t.x), t.y);"
170static constexpr char gFilterSoftLinearSkSL[] =
171 "float filter(float2 xy) {"
174 "float n00 = sample_noise(xy + float2(0,0)),"
175 "n10 = sample_noise(xy + float2(1,0)),"
176 "n01 = sample_noise(xy + float2(0,1)),"
177 "n11 = sample_noise(xy + float2(1,1));"
179 "float2 t = smoothstep(0, 1, fract(xy));"
181 "return mix(mix(n00, n10, t.x), mix(n01, n11, t.x), t.y);"
184static constexpr char gFractalBasicSkSL[] =
185 "float fractal(float n) {"
189static constexpr char gFractalTurbulentBasicSkSL[] =
190 "float fractal(float n) {"
191 "return 2*abs(0.5 - n);"
194static constexpr char gFractalTurbulentSmoothSkSL[] =
195 "float fractal(float n) {"
196 "n = 2*abs(0.5 - n);"
200static constexpr char gFractalTurbulentSharpSkSL[] =
201 "float fractal(float n) {"
202 "return sqrt(2*abs(0.5 - n));"
205enum class NoiseFilter {
212enum class NoiseFractal {
223 return std::move(
result.effect);
227 static constexpr char const* gFilters[] = {
230 gFilterSoftLinearSkSL
233 static constexpr char const* gFractals[] = {
235 gFractalTurbulentBasicSkSL,
236 gFractalTurbulentSmoothSkSL,
237 gFractalTurbulentSharpSkSL
240 SkASSERT(
static_cast<size_t>(filter) < std::size(gFilters));
241 SkASSERT(
static_cast<size_t>(fractal) < std::size(gFractals));
249 static constexpr BinInfo kLoopBins[] = {
258 auto bin_index = [](
float octaves) {
259 SkASSERT(octaves > kLoopBins[std::size(kLoopBins) - 1].threshold);
261 for (
size_t i = 0; i < std::size(kLoopBins); ++i) {
262 if (octaves > kLoopBins[i].threshold) {
270 [std::size(gFilters)]
271 [std::size(gFractals)];
273 const size_t bin = bin_index(octaves);
275 auto& effect = kEffectCache[bin]
276 [
static_cast<size_t>(filter)]
277 [
static_cast<size_t>(fractal)];
279 effect = make_noise_effect(kLoopBins[bin].loops,
280 gFilters[
static_cast<size_t>(filter)],
281 gFractals[
static_cast<size_t>(fractal)])
306 case NoiseFractal::kBasic:
307 return noise_effect(fOctaves, filter, NoiseFractal::kBasic);
308 case NoiseFractal::kTurbulentBasic:
309 return noise_effect(fOctaves, filter, NoiseFractal::kTurbulentBasic);
310 case NoiseFractal::kTurbulentSmooth:
311 return noise_effect(fOctaves, filter, NoiseFractal::kTurbulentSmooth);
312 case NoiseFractal::kTurbulentSharp:
313 return noise_effect(fOctaves, filter, NoiseFractal::kTurbulentSharp);
320 case NoiseFilter::kNearest :
return this->getEffect(NoiseFilter::kNearest);
321 case NoiseFilter::kLinear :
return this->getEffect(NoiseFilter::kLinear);
322 case NoiseFilter::kSoftLinear:
return this->getEffect(NoiseFilter::kSoftLinear);
330 builder.uniform(
"u_noise_planes") = fNoisePlanes;
331 builder.uniform(
"u_noise_weight") = fNoiseWeight;
332 builder.uniform(
"u_octaves" ) = fOctaves;
333 builder.uniform(
"u_persistence" ) = fPersistence;
334 builder.uniform(
"u_submatrix" ) = std::array<float,9>{
335 fSubMatrix.
rc(0,0), fSubMatrix.
rc(1,0), fSubMatrix.
rc(2,0),
336 fSubMatrix.
rc(0,1), fSubMatrix.
rc(1,1), fSubMatrix.
rc(2,1),
337 fSubMatrix.
rc(0,2), fSubMatrix.
rc(1,2), fSubMatrix.
rc(2,2),
340 return builder.makeShader(&fMatrix);
344 const auto& child = this->children()[0];
345 const auto bounds = child->revalidate(ic, ctm);
347 fEffectShader = this->buildEffectShader();
352 void onRender(
SkCanvas* canvas,
const RenderContext* ctx)
const override {
354 const auto local_ctx = ScopedRenderContext(canvas, ctx)
358 this->children()[0]->render(canvas, local_ctx);
367 const RenderNode* onNodeAt(
const SkPoint&)
const override {
return nullptr; }
373 NoiseFilter fFilter = NoiseFilter::kNearest;
374 NoiseFractal fFractal = NoiseFractal::kBasic;
375 SkV2 fNoisePlanes = {0,0};
376 float fNoiseWeight = 0,
383class FractalNoiseAdapter final :
public DiscardableAdapterBase<FractalNoiseAdapter,
387 const AnimationBuilder* abuilder,
391 EffectBinder(jprops, *abuilder,
this)
392 .bind( 0, fFractalType )
393 .bind( 1, fNoiseType )
395 .bind( 3, fContrast )
396 .bind( 4, fBrightness )
399 .bind( 7, fRotation )
400 .bind( 8, fUniformScaling )
402 .bind(10, fScaleWidth )
403 .bind(11, fScaleHeight )
407 .bind(15, fComplexity )
409 .bind(17, fSubInfluence )
410 .bind(18, fSubScale )
411 .bind(19, fSubRotation )
412 .bind(20, fSubOffset )
415 .bind(23, fEvolution )
417 .bind(25, fCycleEvolution )
418 .bind(26, fCycleRevolutions)
419 .bind(27, fRandomSeed )
421 .bind(29, fOpacity );
426 std::tuple<SkV2, float> noise()
const {
428 static constexpr auto kEvolutionScale = 0.25f;
442 rev_rad = std::max(fCycleRevolutions, 1.0f)*
SK_FloatPI*2,
443 cycle = fCycleEvolution
447 scale = fCycleEvolution
450 offset =
SkRandom(static_cast<uint32_t>(fRandomSeed)).nextRangeU(0, 100),
456 auto glsl_mod = [](
float x,
float y) {
457 return x -
y*std::floor(
x/
y);
460 const SkV2 noise_planes = {
461 glsl_mod(evo_ + 0, cycle) +
offset,
462 glsl_mod(evo_ + 1, cycle) +
offset,
465 return std::make_tuple(noise_planes, weight);
469 static constexpr float kGridSize = 64;
472 ?
SkV2{fScale, fScale}
473 :
SkV2{fScaleWidth, fScaleHeight};
483 const auto scale = 100 /
SkTPin(fSubScale, 10.0f, 10000.0f);
490 NoiseFilter noiseFilter()
const {
492 case 1:
return NoiseFilter::kNearest;
493 case 2:
return NoiseFilter::kLinear;
494 default:
return NoiseFilter::kSoftLinear;
499 NoiseFractal noiseFractal()
const {
501 case 1:
return NoiseFractal::kBasic;
502 case 3:
return NoiseFractal::kTurbulentSmooth;
503 case 4:
return NoiseFractal::kTurbulentBasic;
504 default:
return NoiseFractal::kTurbulentSharp;
509 void onSync()
override {
510 const auto& n = this->node();
512 const auto [noise_planes, noise_weight] = this->noise();
514 n->setOctaves(
SkTPin(fComplexity, 1.0f, 20.0f));
515 n->setPersistence(
SkTPin(fSubInfluence * 0.01f, 0.0f, 100.0f));
516 n->setNoisePlanes(noise_planes);
517 n->setNoiseWeight(noise_weight);
518 n->setNoiseFilter(this->noiseFilter());
519 n->setNoiseFractal(this->noiseFractal());
520 n->setMatrix(this->shaderMatrix());
521 n->setSubMatrix(this->subMatrix());
543 fCycleRevolutions = 0,
551 using INHERITED = DiscardableAdapterBase<FractalNoiseAdapter, FractalNoiseNode>;
558 auto fractal_noise = sk_make_sp<FractalNoiseNode>(std::move(layer));
561 std::move(fractal_noise));
constexpr float SK_FloatPI
#define INHERITED(method,...)
sk_sp< T > sk_ref_sp(T *obj)
#define SG_ATTRIBUTE(attr_name, attr_type, attr_container)
#define SkDegreesToRadians(degrees)
#define SkScalarRoundToInt(x)
#define SkScalarRoundToScalar(x)
SK_API SkString static SkString SkStringPrintf()
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
int saveLayer(const SkRect *bounds, const SkPaint *paint)
void drawPaint(const SkPaint &paint)
SkMatrix getTotalMatrix() const
static SkMatrix Scale(SkScalar sx, SkScalar sy)
static SkMatrix RotateDeg(SkScalar deg)
static SkMatrix Translate(SkScalar dx, SkScalar dy)
SkScalar rc(int r, int c) const
void setShader(sk_sp< SkShader > shader)
void setBlendMode(SkBlendMode mode)
static Result MakeForShader(SkString sksl, const Options &)
void attachDiscardableAdapter(sk_sp< T > adapter) const
Optional< SkRect > bounds
SIN Vec< N, float > floor(const Vec< N, float > &x)