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