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.h" 9 #include "SkAnimTimer.h" 10 #include "SkBlurImageFilter.h" 11 #include "SkRandom.h" 12 #include "SkRRect.h" 13 14 static const SkScalar kBlurMax = 7.0f; 15 static const int kNumNodes = 30; 16 static const int kWidth = 512; 17 static const int kHeight = 512; 18 static const SkScalar kBlurAnimationDuration = 4.0f; // in secs 19 20 // This GM draws a lot of layers with animating BlurImageFilters 21 class AnimatedImageBlurs : public skiagm::GM { 22 public: 23 AnimatedImageBlurs() : fLastTime(0.0f) { 24 this->setBGColor(0xFFCCCCCC); 25 } 26 27 protected: 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 73 private: 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 139 DEF_GM(return new AnimatedImageBlurs;) 140