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