xref: /aosp_15_r20/external/skia/gm/animatedimageblurs.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2016 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/SkImageFilter.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPoint.h"
13 #include "include/core/SkRRect.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkSize.h"
17 #include "include/core/SkString.h"
18 #include "include/core/SkTypes.h"
19 #include "include/effects/SkImageFilters.h"
20 #include "include/private/base/SkTPin.h"
21 #include "src/base/SkRandom.h"
22 #include "tools/DecodeUtils.h"
23 #include "tools/timer/TimeUtils.h"
24 
25 static const SkScalar kBlurMax = 7.0f;
26 static const int kNumNodes = 30;
27 static const int kWidth = 512;
28 static const int kHeight = 512;
29 static const SkScalar kBlurAnimationDuration = 4.0f; // in secs
30 
31 // This GM draws a lot of layers with animating BlurImageFilters
32 class AnimatedImageBlurs : public skiagm::GM {
33 public:
AnimatedImageBlurs()34     AnimatedImageBlurs() : fLastTime(0.0f) {
35         this->setBGColor(0xFFCCCCCC);
36     }
37 
38 protected:
runAsBench() const39     bool runAsBench() const override { return true; }
40 
getName() const41     SkString getName() const override { return SkString("animated-image-blurs"); }
42 
getISize()43     SkISize getISize() override { return SkISize::Make(kWidth, kHeight); }
44 
onOnceBeforeDraw()45     void onOnceBeforeDraw() override {
46         for (int i = 0; i < kNumNodes; ++i) {
47             fNodes[i].init(&fRand);
48         }
49     }
50 
onDraw(SkCanvas * canvas)51     void onDraw(SkCanvas* canvas) override {
52         SkPaint paint;
53         paint.setAntiAlias(true);
54 
55         for (int i = 0; i < kNumNodes; ++i) {
56             SkPaint layerPaint;
57             layerPaint.setImageFilter(SkImageFilters::Blur(fNodes[i].sigma(), fNodes[i].sigma(),
58                                                            nullptr));
59 
60             canvas->saveLayer(nullptr, &layerPaint);
61                 // The rect is outset to block the circle case
62                 SkRect rect = SkRect::MakeLTRB(fNodes[i].pos().fX - fNodes[i].size()-0.5f,
63                                                fNodes[i].pos().fY - fNodes[i].size()-0.5f,
64                                                fNodes[i].pos().fX + fNodes[i].size()+0.5f,
65                                                fNodes[i].pos().fY + fNodes[i].size()+0.5f);
66                 SkRRect rrect = SkRRect::MakeRectXY(rect, fNodes[i].size(), fNodes[i].size());
67                 canvas->drawRRect(rrect, paint);
68             canvas->restore();
69         }
70     }
71 
onAnimate(double nanos)72     bool onAnimate(double nanos) override {
73         if (0.0f != fLastTime) {
74             for (int i = 0; i < kNumNodes; ++i) {
75                 fNodes[i].update(nanos, fLastTime);
76             }
77         }
78 
79         fLastTime = 1e-9 * nanos;
80         return true;
81     }
82 
83 private:
84     class Node {
85     public:
Node()86         Node()
87             : fSize(0.0f)
88             , fPos { 0.0f, 0.0f }
89             , fDir { 1.0f, 0.0f }
90             , fBlurOffset(0.0f)
91             , fBlur(fBlurOffset)
92             , fSpeed(0.0f) {
93         }
94 
init(SkRandom * rand)95         void init(SkRandom* rand) {
96             fSize = rand->nextRangeF(10.0f, 60.f);
97             fPos.fX = rand->nextRangeF(fSize, kWidth - fSize);
98             fPos.fY = rand->nextRangeF(fSize, kHeight - fSize);
99             fDir.fX = rand->nextRangeF(-1.0f, 1.0f);
100             fDir.fY = SkScalarSqrt(1.0f - fDir.fX * fDir.fX);
101             if (rand->nextBool()) {
102                 fDir.fY = -fDir.fY;
103             }
104             fBlurOffset = rand->nextRangeF(0.0f, kBlurMax);
105             fBlur = fBlurOffset;
106             fSpeed = rand->nextRangeF(20.0f, 60.0f);
107         }
108 
update(double nanos,SkScalar lastTime)109         void update(double nanos, SkScalar lastTime) {
110             SkScalar deltaTime = 1e-9 * nanos - lastTime;
111 
112             fPos.fX += deltaTime * fSpeed * fDir.fX;
113             fPos.fY += deltaTime * fSpeed * fDir.fY;
114             if (fPos.fX >= kWidth || fPos.fX < 0.0f) {
115                 fPos.fX = SkTPin<SkScalar>(fPos.fX, 0.0f, kWidth);
116                 fDir.fX = -fDir.fX;
117             }
118             if (fPos.fY >= kHeight || fPos.fY < 0.0f) {
119                 fPos.fY = SkTPin<SkScalar>(fPos.fY, 0.0f, kHeight);
120                 fDir.fY = -fDir.fY;
121             }
122 
123             fBlur = TimeUtils::PingPong(1e-9 * nanos, kBlurAnimationDuration, fBlurOffset, 0.0f, kBlurMax);
124         }
125 
sigma() const126         SkScalar sigma() const { return fBlur; }
pos() const127         const SkPoint& pos() const { return fPos; }
size() const128         SkScalar size() const { return fSize; }
129 
130     private:
131         SkScalar fSize;
132         SkPoint  fPos;
133         SkVector fDir;
134         SkScalar fBlurOffset;
135         SkScalar fBlur;
136         SkScalar fSpeed;
137     };
138 
139     Node     fNodes[kNumNodes];
140     SkRandom fRand;
141     SkScalar fLastTime;
142 
143     using INHERITED = GM;
144 };
145 
146 // This GM draws an image with a tiled blur that animates from large to small sigmas
147 class AnimatedTiledImageBlur : public skiagm::GM {
148 static constexpr float kMaxBlurSigma = 250.f;
149 static constexpr float kAnimationDuration = 12.f; // seconds
150 public:
AnimatedTiledImageBlur()151     AnimatedTiledImageBlur() : fBlurSigma(0.3f * kMaxBlurSigma) {
152         this->setBGColor(0xFFCCCCCC);
153     }
154 
155 protected:
runAsBench() const156     bool runAsBench() const override { return true; }
157 
getName() const158     SkString getName() const override { return SkString("animated-tiled-image-blur"); }
159 
getISize()160     SkISize getISize() override { return SkISize::Make(530, 530); }
161 
onOnceBeforeDraw()162     void onOnceBeforeDraw() override {
163         fImage = ToolUtils::GetResourceAsImage("images/mandrill_512.png");
164     }
165 
onDraw(SkCanvas * canvas)166     void onDraw(SkCanvas* canvas) override {
167         auto drawBlurredImage = [&](float tx, float ty, SkTileMode tileMode) {
168             SkPaint paint;
169             SkRect rect = SkRect::MakeIWH(250, 250);
170             canvas->save();
171             canvas->translate(tx, ty);
172             paint.setImageFilter(SkImageFilters::Blur(fBlurSigma, fBlurSigma, tileMode,
173                                                       nullptr, rect));
174             canvas->drawImageRect(fImage, rect, SkFilterMode::kLinear, &paint);
175             canvas->restore();
176         };
177 
178         drawBlurredImage(10.f,  10.f,  SkTileMode::kDecal);
179         drawBlurredImage(270.f, 10.f,  SkTileMode::kClamp);
180         drawBlurredImage(10.f,  270.f, SkTileMode::kRepeat);
181         drawBlurredImage(270.f, 270.f, SkTileMode::kMirror);
182     }
183 
onAnimate(double nanos)184     bool onAnimate(double nanos) override {
185         fBlurSigma = TimeUtils::PingPong(1e-9 * nanos, kAnimationDuration,
186                                          0.f, 0.0f, kMaxBlurSigma);
187         return true;
188     }
189 
190 private:
191     sk_sp<SkImage> fImage;
192     SkScalar fBlurSigma;
193 };
194 
195 //////////////////////////////////////////////////////////////////////////////
196 
197 DEF_GM(return new AnimatedImageBlurs;)
198 DEF_GM(return new AnimatedTiledImageBlur;)
199