• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/utils/SkRandom.h"
21 #include "tools/timer/TimeUtils.h"
22 
23 static const SkScalar kBlurMax = 7.0f;
24 static const int kNumNodes = 30;
25 static const int kWidth = 512;
26 static const int kHeight = 512;
27 static const SkScalar kBlurAnimationDuration = 4.0f; // in secs
28 
29 // This GM draws a lot of layers with animating BlurImageFilters
30 class AnimatedImageBlurs : public skiagm::GM {
31 public:
AnimatedImageBlurs()32     AnimatedImageBlurs() : fLastTime(0.0f) {
33         this->setBGColor(0xFFCCCCCC);
34     }
35 
36 protected:
runAsBench() const37     bool runAsBench() const override { return true; }
38 
onShortName()39     SkString onShortName() override { return SkString("animated-image-blurs"); }
40 
onISize()41     SkISize onISize() override { return SkISize::Make(kWidth, kHeight); }
42 
onOnceBeforeDraw()43     void onOnceBeforeDraw() override {
44         for (int i = 0; i < kNumNodes; ++i) {
45             fNodes[i].init(&fRand);
46         }
47     }
48 
onDraw(SkCanvas * canvas)49     void onDraw(SkCanvas* canvas) override {
50         SkPaint paint;
51         paint.setAntiAlias(true);
52 
53         for (int i = 0; i < kNumNodes; ++i) {
54             SkPaint layerPaint;
55             layerPaint.setImageFilter(SkImageFilters::Blur(fNodes[i].sigma(), fNodes[i].sigma(),
56                                                            nullptr));
57 
58             canvas->saveLayer(nullptr, &layerPaint);
59                 // The rect is outset to block the circle case
60                 SkRect rect = SkRect::MakeLTRB(fNodes[i].pos().fX - fNodes[i].size()-0.5f,
61                                                fNodes[i].pos().fY - fNodes[i].size()-0.5f,
62                                                fNodes[i].pos().fX + fNodes[i].size()+0.5f,
63                                                fNodes[i].pos().fY + fNodes[i].size()+0.5f);
64                 SkRRect rrect = SkRRect::MakeRectXY(rect, fNodes[i].size(), fNodes[i].size());
65                 canvas->drawRRect(rrect, paint);
66             canvas->restore();
67         }
68     }
69 
onAnimate(double nanos)70     bool onAnimate(double nanos) override {
71         if (0.0f != fLastTime) {
72             for (int i = 0; i < kNumNodes; ++i) {
73                 fNodes[i].update(nanos, fLastTime);
74             }
75         }
76 
77         fLastTime = 1e-9 * nanos;
78         return true;
79     }
80 
81 private:
82     class Node {
83     public:
Node()84         Node()
85             : fSize(0.0f)
86             , fPos { 0.0f, 0.0f }
87             , fDir { 1.0f, 0.0f }
88             , fBlurOffset(0.0f)
89             , fBlur(fBlurOffset)
90             , fSpeed(0.0f) {
91         }
92 
init(SkRandom * rand)93         void init(SkRandom* rand) {
94             fSize = rand->nextRangeF(10.0f, 60.f);
95             fPos.fX = rand->nextRangeF(fSize, kWidth - fSize);
96             fPos.fY = rand->nextRangeF(fSize, kHeight - fSize);
97             fDir.fX = rand->nextRangeF(-1.0f, 1.0f);
98             fDir.fY = SkScalarSqrt(1.0f - fDir.fX * fDir.fX);
99             if (rand->nextBool()) {
100                 fDir.fY = -fDir.fY;
101             }
102             fBlurOffset = rand->nextRangeF(0.0f, kBlurMax);
103             fBlur = fBlurOffset;
104             fSpeed = rand->nextRangeF(20.0f, 60.0f);
105         }
106 
update(double nanos,SkScalar lastTime)107         void update(double nanos, SkScalar lastTime) {
108             SkScalar deltaTime = 1e-9 * nanos - lastTime;
109 
110             fPos.fX += deltaTime * fSpeed * fDir.fX;
111             fPos.fY += deltaTime * fSpeed * fDir.fY;
112             if (fPos.fX >= kWidth || fPos.fX < 0.0f) {
113                 fPos.fX = SkTPin<SkScalar>(fPos.fX, 0.0f, kWidth);
114                 fDir.fX = -fDir.fX;
115             }
116             if (fPos.fY >= kHeight || fPos.fY < 0.0f) {
117                 fPos.fY = SkTPin<SkScalar>(fPos.fY, 0.0f, kHeight);
118                 fDir.fY = -fDir.fY;
119             }
120 
121             fBlur = TimeUtils::PingPong(1e-9 * nanos, kBlurAnimationDuration, fBlurOffset, 0.0f, kBlurMax);
122         }
123 
sigma() const124         SkScalar sigma() const { return fBlur; }
pos() const125         const SkPoint& pos() const { return fPos; }
size() const126         SkScalar size() const { return fSize; }
127 
128     private:
129         SkScalar fSize;
130         SkPoint  fPos;
131         SkVector fDir;
132         SkScalar fBlurOffset;
133         SkScalar fBlur;
134         SkScalar fSpeed;
135     };
136 
137     Node     fNodes[kNumNodes];
138     SkRandom fRand;
139     SkScalar fLastTime;
140 
141     typedef GM INHERITED;
142 };
143 
144 //////////////////////////////////////////////////////////////////////////////
145 
146 DEF_GM(return new AnimatedImageBlurs;)
147