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