Flutter Engine
The Flutter Engine
perlinnoise.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm/gm.h"
14#include "include/core/SkRect.h"
18#include "include/core/SkSize.h"
23
24#include <utility>
25
26namespace {
27
28enum class Type {
29 kFractalNoise,
30 kTurbulence,
31};
32
33sk_sp<SkShader> noise_shader(Type type,
34 float baseFrequencyX,
35 float baseFrequencyY,
36 int numOctaves,
37 float seed,
38 bool stitchTiles,
39 SkISize size) {
40 return (type == Type::kFractalNoise)
41 ? SkShaders::MakeFractalNoise(baseFrequencyX,
42 baseFrequencyY,
43 numOctaves,
44 seed,
45 stitchTiles ? &size : nullptr)
46 : SkShaders::MakeTurbulence(baseFrequencyX,
47 baseFrequencyY,
48 numOctaves,
49 seed,
50 stitchTiles ? &size : nullptr);
51}
52
53class PerlinNoiseGM : public skiagm::GM {
54 static constexpr SkISize kSize = {80, 80};
55
56 SkString getName() const override { return SkString("perlinnoise"); }
57
58 SkISize getISize() override { return {220, 620}; }
59
60 void drawRect(SkCanvas* canvas, SkPoint pt, const SkPaint& paint, const SkISize& size) {
61 canvas->save();
62 canvas->translate(pt.fX, pt.fY);
64 canvas->drawRect(r, paint);
65 canvas->restore();
66 }
67
68 void test(SkCanvas* canvas, SkPoint pt, Type type, bool stitch,
69 SkVector baseFrequency, int numOctaves, float seed, SkISize tileSize = {40, 40}) {
70 sk_sp<SkShader> shader = noise_shader(type,
71 baseFrequency.fX,
72 baseFrequency.fY,
73 numOctaves,
74 seed,
75 stitch,
76 tileSize);
78 paint.setShader(std::move(shader));
79 if (stitch) {
80 this->drawRect(canvas, pt, paint, tileSize);
81 pt.fX += tileSize.width();
82 this->drawRect(canvas, pt, paint, tileSize);
83 pt.fY += tileSize.height();
84 this->drawRect(canvas, pt, paint, tileSize);
85 pt.fX -= tileSize.width();
86 this->drawRect(canvas, pt, paint, tileSize);
87 } else {
88 this->drawRect(canvas, pt, paint, kSize);
89 }
90 }
91
92 void onDraw(SkCanvas* canvas) override {
93 this->test(canvas, SkPoint{ 0, 0}, Type::kFractalNoise, /*stitch=*/false,
94 SkVector{0.1f, 0.1f}, /*numOctaves=*/0, /*seed=*/0);
95 this->test(canvas, SkPoint{100, 0}, Type::kTurbulence, /*stitch=*/false,
96 SkVector{0.1f, 0.1f}, /*numOctaves=*/0, /*seed=*/0);
97
98 this->test(canvas, SkPoint{ 0, 100}, Type::kFractalNoise, /*stitch=*/false,
99 SkVector{0.1f, 0.1f}, /*numOctaves=*/2, /*seed=*/0);
100 this->test(canvas, SkPoint{100, 100}, Type::kFractalNoise, /*stitch=*/true,
101 SkVector{0.05f, 0.1f}, /*numOctaves=*/1, /*seed=*/0);
102
103 this->test(canvas, SkPoint{ 0, 200}, Type::kTurbulence, /*stitch=*/true,
104 SkVector{0.1f, 0.1f}, /*numOctaves=*/1, /*seed=*/0);
105 this->test(canvas, SkPoint{100, 200}, Type::kTurbulence, /*stitch=*/false,
106 SkVector{0.2f, 0.4f}, /*numOctaves=*/5, /*seed=*/0);
107
108 this->test(canvas, SkPoint{ 0, 300}, Type::kFractalNoise, /*stitch=*/false,
109 SkVector{0.1f, 0.1f}, /*numOctaves=*/3, /*seed=*/1);
110 this->test(canvas, SkPoint{100, 300}, Type::kFractalNoise, /*stitch=*/false,
111 SkVector{0.1f, 0.1f}, /*numOctaves=*/3, /*seed=*/4);
112
113 canvas->save();
114 canvas->scale(0.75f, 1.0f);
115
116 this->test(canvas, SkPoint{ 0, 400}, Type::kFractalNoise, /*stitch=*/false,
117 SkVector{0.1f, 0.1f}, /*numOctaves=*/2, /*seed=*/0);
118 this->test(canvas, SkPoint{100, 400}, Type::kFractalNoise, /*stitch=*/true,
119 SkVector{0.1f, 0.05f}, /*numOctaves=*/1, /*seed=*/0);
120
121 canvas->restore();
122
123 // Matches Chromium test case in svg/filters/feTurbulence-tiled.svg
124 this->test(canvas, SkPoint{ 0, 500}, Type::kTurbulence, /*stitch=*/true,
125 SkVector{0.03f, 0.03f}, /*numOctaves=*/1, /*seed=*/0, /*tileSize=*/{50, 50});
126
127 // Matches Chromium test case in css3/filters/effect-reference.html
128 this->test(canvas, SkPoint{120, 500}, Type::kTurbulence, /*stitch=*/false,
129 SkVector{0.05f, 0.05f}, /*numOctaves=*/2, /*seed=*/0);
130
131 }
132
133private:
134 using INHERITED = GM;
135};
136
137class PerlinNoiseLocalMatrixGM : public skiagm::GM {
138 static constexpr SkISize kSize = {80, 80};
139
140 SkString getName() const override { return SkString("perlinnoise_localmatrix"); }
141
142 SkISize getISize() override { return {640, 480}; }
143
144 void onDraw(SkCanvas* canvas) override {
145 canvas->translate(10, 10);
146
148 paint.setShader(noise_shader(Type::kFractalNoise, 0.1f, 0.1f, 2, 0, false, kSize));
149
150 const SkScalar w = SkIntToScalar(kSize.width());
151 const SkScalar h = SkIntToScalar(kSize.height());
152
153 SkRect r = SkRect::MakeWH(w, h);
154 canvas->drawRect(r, paint);
155
156 canvas->save();
157 canvas->translate(w * 5/4, 0);
158 canvas->drawRect(r, paint);
159 canvas->restore();
160
161 canvas->save();
162 canvas->translate(0, h + 10);
163 canvas->scale(2, 2);
164 canvas->drawRect(r, paint);
165 canvas->restore();
166
167 canvas->save();
168 canvas->translate(w + 100, h + 10);
169 canvas->scale(2, 2);
170 canvas->drawRect(r, paint);
171 canvas->restore();
172
173 // The next row should draw the same as the previous, even though we are using a local
174 // matrix instead of the canvas.
175
176 canvas->translate(0, h * 2 + 10);
177
178 SkMatrix lm;
179 lm.setScale(2, 2);
180 paint.setShader(paint.getShader()->makeWithLocalMatrix(lm));
181 r.fRight += r.width();
182 r.fBottom += r.height();
183
184 canvas->save();
185 canvas->translate(0, h + 10);
186 canvas->drawRect(r, paint);
187 canvas->restore();
188
189 canvas->save();
190 canvas->translate(w + 100, h + 10);
191 canvas->drawRect(r, paint);
192 canvas->restore();
193 }
194};
195
196// Demonstrate skbug.com/14166 (Perlin noise shader doesn't rotate correctly)
197class PerlinNoiseRotatedGM : public skiagm::GM {
198 static constexpr SkISize kCellSize = { 100, 100 };
199 static constexpr SkISize kRectSize = { 60, 60 };
200 static constexpr int kPad = 10;
201 static constexpr int kCellsX = 3;
202 static constexpr int kCellsY = 2;
203
204 SkString getName() const override { return SkString("perlinnoise_rotated"); }
205
206 SkISize getISize() override {
207 return {2 * kPad + kCellsX * kCellSize.width(), 2 * kPad + kCellsY * kCellSize.height()};
208 }
209
210 void onDraw(SkCanvas* canvas) override {
211 SkPaint outline;
212 outline.setColor(SK_ColorBLACK);
213 outline.setStrokeWidth(2.0f);
215 outline.setAntiAlias(true);
216
217 const SkRect kRectToDraw = SkRect::MakeWH(kRectSize.width(), kRectSize.height());
218 const SkRect kMarker = SkRect::MakeWH(5, 5);
219
220 float yOffset = kPad;
221 for (auto type : { Type::kFractalNoise, Type::kTurbulence }) {
222 float xOffset = kPad;
223
224 SkPaint p;
225 p.setShader(noise_shader(type, 0.05f, 0.05f, 1, 0, false, kRectSize));
226
227 for (float rotation : {0.0f, 10.0f, 80.0f}) {
228 int saveCount = canvas->save();
229 canvas->translate(xOffset, yOffset);
230
231 canvas->drawRect(SkRect::MakeWH(kCellSize.fWidth, kCellSize.fHeight), outline);
232
233 canvas->save();
234
235 canvas->translate(kCellSize.fWidth / 2.0f, kCellSize.fHeight / 2.0f);
236 canvas->rotate(rotation);
237 canvas->translate(-kRectSize.fWidth/2.0f, -kRectSize.fHeight/2.0f);
238
239 canvas->drawRect(kRectToDraw, p);
240
241 canvas->drawRect(kRectToDraw, outline);
242 canvas->drawRect(kMarker, outline);
243
244 canvas->restoreToCount(saveCount);
245
246 xOffset += kCellSize.width();
247 }
248
249 yOffset += kCellSize.height();
250 }
251 }
252};
253
254// Demonstrate skbug.com/14411 (Intel GPUs show artifacts when applying perlin noise to layers)
255class PerlinNoiseLayeredGM : public skiagm::GM {
256 SkString getName() const override { return SkString("perlinnoise_layered"); }
257
258 SkISize getISize() override { return {500, 500}; }
259
260 void onDraw(SkCanvas* canvas) override {
264
265 const SkPaint paint;
266 canvas->saveLayer(nullptr, &paint);
267 {
268 SkPaint p;
269 p.setImageFilter(perlin);
270 canvas->drawPaint(p);
271 }
272 canvas->restore();
273
274 canvas->saveLayer(nullptr, nullptr);
275 {
276 SkPaint p;
277 p.setImageFilter(perlin);
278 canvas->drawPaint(p);
279 }
280 canvas->restore();
281 }
282};
283
284} // anonymous namespace
285
286DEF_GM(return new PerlinNoiseGM;)
287DEF_GM(return new PerlinNoiseLocalMatrixGM;)
288DEF_GM(return new PerlinNoiseRotatedGM;)
289DEF_GM(return new PerlinNoiseLayeredGM;)
#define test(name)
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
#define SkIntToScalar(x)
Definition: SkScalar.h:57
constexpr int kPad
GLenum type
int saveLayer(const SkRect *bounds, const SkPaint *paint)
Definition: SkCanvas.cpp:496
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void drawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1668
void rotate(SkScalar degrees)
Definition: SkCanvas.cpp:1300
void restoreToCount(int saveCount)
Definition: SkCanvas.cpp:478
int save()
Definition: SkCanvas.cpp:447
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
static sk_sp< SkColorFilter > Matrix(const SkColorMatrix &)
static sk_sp< SkImageFilter > ColorFilter(sk_sp< SkColorFilter > cf, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Shader(sk_sp< SkShader > shader, const CropRect &cropRect={})
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:296
void setStyle(Style style)
Definition: SkPaint.cpp:105
void setColor(SkColor color)
Definition: SkPaint.cpp:119
void setAntiAlias(bool aa)
Definition: SkPaint.h:170
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
void setStrokeWidth(SkScalar width)
Definition: SkPaint.cpp:159
Definition: gm.h:110
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition: gm.cpp:81
virtual SkISize getISize()=0
virtual SkString getName() const =0
virtual DrawResult onDraw(SkCanvas *, SkString *errorMsg)
Definition: gm.cpp:139
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
const int kCellSize
#define DEF_GM(CODE)
Definition: gm.h:40
constexpr int kSize
SK_API sk_sp< SkShader > MakeTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, int numOctaves, SkScalar seed, const SkISize *tileSize=nullptr)
SK_API sk_sp< SkShader > MakeFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, int numOctaves, SkScalar seed, const SkISize *tileSize=nullptr)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SkScalar w
SkScalar h
Definition: SkSize.h:16
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165
SkScalar fBottom
larger y-axis bounds
Definition: extension.cpp:17
SkScalar fRight
larger x-axis bounds
Definition: extension.cpp:16
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609