xref: /third_party/skia/gm/perlinnoise.cpp (revision cb93a386)
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"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
11#include "include/core/SkMatrix.h"
12#include "include/core/SkPaint.h"
13#include "include/core/SkRect.h"
14#include "include/core/SkRefCnt.h"
15#include "include/core/SkScalar.h"
16#include "include/core/SkShader.h"
17#include "include/core/SkSize.h"
18#include "include/core/SkString.h"
19#include "include/effects/SkPerlinNoiseShader.h"
20
21#include <utility>
22
23namespace {
24
25enum class Type {
26    kFractalNoise,
27    kTurbulence,
28};
29
30class PerlinNoiseGM : public skiagm::GM {
31    SkISize fSize = {80, 80};
32
33    void onOnceBeforeDraw() override { this->setBGColor(0xFF000000); }
34
35    SkString onShortName() override { return SkString("perlinnoise"); }
36
37    SkISize onISize() override { return {200, 500}; }
38
39    void drawRect(SkCanvas* canvas, int x, int y, const SkPaint& paint, const SkISize& size) {
40        canvas->save();
41        canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
42        SkRect r = SkRect::MakeWH(SkIntToScalar(size.width()),
43                                  SkIntToScalar(size.height()));
44        canvas->drawRect(r, paint);
45        canvas->restore();
46    }
47
48    void test(SkCanvas* canvas, int x, int y, Type type,
49              float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed,
50              bool stitchTiles) {
51        SkISize tileSize = SkISize::Make(fSize.width() / 2, fSize.height() / 2);
52        sk_sp<SkShader> shader;
53        switch (type) {
54            case Type::kFractalNoise:
55                shader = SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX,
56                                                               baseFrequencyY,
57                                                               numOctaves,
58                                                               seed,
59                                                               stitchTiles ? &tileSize : nullptr);
60                break;
61            case Type::kTurbulence:
62                shader = SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX,
63                                                             baseFrequencyY,
64                                                             numOctaves,
65                                                             seed,
66                                                             stitchTiles ? &tileSize : nullptr);
67                break;
68        }
69        SkPaint paint;
70        paint.setShader(std::move(shader));
71        if (stitchTiles) {
72            drawRect(canvas, x, y, paint, tileSize);
73            x += tileSize.width();
74            drawRect(canvas, x, y, paint, tileSize);
75            y += tileSize.width();
76            drawRect(canvas, x, y, paint, tileSize);
77            x -= tileSize.width();
78            drawRect(canvas, x, y, paint, tileSize);
79        } else {
80            drawRect(canvas, x, y, paint, fSize);
81        }
82    }
83
84    void onDraw(SkCanvas* canvas) override {
85        canvas->clear(SK_ColorBLACK);
86        test(canvas,   0,   0, Type::kFractalNoise,
87             0.1f, 0.1f, 0, 0, false);
88        test(canvas, 100,   0, Type::kTurbulence,
89             0.1f, 0.1f, 0, 0, false);
90
91        test(canvas,   0, 100, Type::kFractalNoise,
92             0.1f, 0.1f, 2, 0, false);
93        test(canvas, 100, 100, Type::kFractalNoise,
94             0.05f, 0.1f, 1, 0, true);
95
96        test(canvas,   0, 200, Type::kTurbulence,
97             0.1f, 0.1f, 1, 0, true);
98        test(canvas, 100, 200, Type::kTurbulence,
99             0.2f, 0.4f, 5, 0, false);
100
101        test(canvas,   0, 300, Type::kFractalNoise,
102             0.1f, 0.1f, 3, 1, false);
103        test(canvas, 100, 300, Type::kFractalNoise,
104             0.1f, 0.1f, 3, 4, false);
105
106        canvas->scale(0.75f, 1.0f);
107
108        test(canvas,   0, 400, Type::kFractalNoise,
109             0.1f, 0.1f, 2, 0, false);
110        test(canvas, 100, 400, Type::kFractalNoise,
111             0.1f, 0.05f, 1, 0, true);
112    }
113
114private:
115    using INHERITED = GM;
116};
117
118class PerlinNoiseGM2 : public skiagm::GM {
119    SkISize fSize = {80, 80};
120
121    SkString onShortName() override { return SkString("perlinnoise_localmatrix"); }
122
123    SkISize onISize() override { return {640, 480}; }
124
125    void install(SkPaint* paint, Type type,
126              float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed,
127              bool stitchTiles) {
128        sk_sp<SkShader> shader = (type == Type::kFractalNoise) ?
129            SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX, baseFrequencyY, numOctaves,
130                                                  seed, stitchTiles ? &fSize : nullptr) :
131            SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX, baseFrequencyY, numOctaves,
132                                                seed, stitchTiles ? &fSize : nullptr);
133        paint->setShader(std::move(shader));
134    }
135
136    void onDraw(SkCanvas* canvas) override {
137        canvas->translate(10, 10);
138
139        SkPaint paint;
140        this->install(&paint, Type::kFractalNoise, 0.1f, 0.1f, 2, 0, false);
141
142        const SkScalar w = SkIntToScalar(fSize.width());
143        const SkScalar h = SkIntToScalar(fSize.height());
144
145        SkRect r = SkRect::MakeWH(w, h);
146        canvas->drawRect(r, paint);
147
148        canvas->save();
149        canvas->translate(w * 5/4, 0);
150        canvas->drawRect(r, paint);
151        canvas->restore();
152
153        canvas->save();
154        canvas->translate(0, h + 10);
155        canvas->scale(2, 2);
156        canvas->drawRect(r, paint);
157        canvas->restore();
158
159        canvas->save();
160        canvas->translate(w + 100, h + 10);
161        canvas->scale(2, 2);
162        canvas->drawRect(r, paint);
163        canvas->restore();
164
165        // The next row should draw the same as the previous, even though we are using a local
166        // matrix instead of the canvas.
167
168        canvas->translate(0, h * 2 + 10);
169
170        SkMatrix lm;
171        lm.setScale(2, 2);
172        paint.setShader(paint.getShader()->makeWithLocalMatrix(lm));
173        r.fRight += r.width();
174        r.fBottom += r.height();
175
176        canvas->save();
177        canvas->translate(0, h + 10);
178        canvas->drawRect(r, paint);
179        canvas->restore();
180
181        canvas->save();
182        canvas->translate(w + 100, h + 10);
183        canvas->drawRect(r, paint);
184        canvas->restore();
185    }
186};
187
188} // namespace
189
190DEF_GM( return new PerlinNoiseGM; )
191DEF_GM( return new PerlinNoiseGM2; )
192