1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2016 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h" 9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h" 10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageFilter.h" 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h" 19*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkImageFilters.h" 20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h" 21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h" 22*c8dee2aaSAndroid Build Coastguard Worker #include "tools/DecodeUtils.h" 23*c8dee2aaSAndroid Build Coastguard Worker #include "tools/timer/TimeUtils.h" 24*c8dee2aaSAndroid Build Coastguard Worker 25*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar kBlurMax = 7.0f; 26*c8dee2aaSAndroid Build Coastguard Worker static const int kNumNodes = 30; 27*c8dee2aaSAndroid Build Coastguard Worker static const int kWidth = 512; 28*c8dee2aaSAndroid Build Coastguard Worker static const int kHeight = 512; 29*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar kBlurAnimationDuration = 4.0f; // in secs 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker // This GM draws a lot of layers with animating BlurImageFilters 32*c8dee2aaSAndroid Build Coastguard Worker class AnimatedImageBlurs : public skiagm::GM { 33*c8dee2aaSAndroid Build Coastguard Worker public: AnimatedImageBlurs()34*c8dee2aaSAndroid Build Coastguard Worker AnimatedImageBlurs() : fLastTime(0.0f) { 35*c8dee2aaSAndroid Build Coastguard Worker this->setBGColor(0xFFCCCCCC); 36*c8dee2aaSAndroid Build Coastguard Worker } 37*c8dee2aaSAndroid Build Coastguard Worker 38*c8dee2aaSAndroid Build Coastguard Worker protected: runAsBench() const39*c8dee2aaSAndroid Build Coastguard Worker bool runAsBench() const override { return true; } 40*c8dee2aaSAndroid Build Coastguard Worker getName() const41*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("animated-image-blurs"); } 42*c8dee2aaSAndroid Build Coastguard Worker getISize()43*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(kWidth, kHeight); } 44*c8dee2aaSAndroid Build Coastguard Worker onOnceBeforeDraw()45*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override { 46*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kNumNodes; ++i) { 47*c8dee2aaSAndroid Build Coastguard Worker fNodes[i].init(&fRand); 48*c8dee2aaSAndroid Build Coastguard Worker } 49*c8dee2aaSAndroid Build Coastguard Worker } 50*c8dee2aaSAndroid Build Coastguard Worker onDraw(SkCanvas * canvas)51*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override { 52*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint; 53*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true); 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kNumNodes; ++i) { 56*c8dee2aaSAndroid Build Coastguard Worker SkPaint layerPaint; 57*c8dee2aaSAndroid Build Coastguard Worker layerPaint.setImageFilter(SkImageFilters::Blur(fNodes[i].sigma(), fNodes[i].sigma(), 58*c8dee2aaSAndroid Build Coastguard Worker nullptr)); 59*c8dee2aaSAndroid Build Coastguard Worker 60*c8dee2aaSAndroid Build Coastguard Worker canvas->saveLayer(nullptr, &layerPaint); 61*c8dee2aaSAndroid Build Coastguard Worker // The rect is outset to block the circle case 62*c8dee2aaSAndroid Build Coastguard Worker SkRect rect = SkRect::MakeLTRB(fNodes[i].pos().fX - fNodes[i].size()-0.5f, 63*c8dee2aaSAndroid Build Coastguard Worker fNodes[i].pos().fY - fNodes[i].size()-0.5f, 64*c8dee2aaSAndroid Build Coastguard Worker fNodes[i].pos().fX + fNodes[i].size()+0.5f, 65*c8dee2aaSAndroid Build Coastguard Worker fNodes[i].pos().fY + fNodes[i].size()+0.5f); 66*c8dee2aaSAndroid Build Coastguard Worker SkRRect rrect = SkRRect::MakeRectXY(rect, fNodes[i].size(), fNodes[i].size()); 67*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRRect(rrect, paint); 68*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 69*c8dee2aaSAndroid Build Coastguard Worker } 70*c8dee2aaSAndroid Build Coastguard Worker } 71*c8dee2aaSAndroid Build Coastguard Worker onAnimate(double nanos)72*c8dee2aaSAndroid Build Coastguard Worker bool onAnimate(double nanos) override { 73*c8dee2aaSAndroid Build Coastguard Worker if (0.0f != fLastTime) { 74*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < kNumNodes; ++i) { 75*c8dee2aaSAndroid Build Coastguard Worker fNodes[i].update(nanos, fLastTime); 76*c8dee2aaSAndroid Build Coastguard Worker } 77*c8dee2aaSAndroid Build Coastguard Worker } 78*c8dee2aaSAndroid Build Coastguard Worker 79*c8dee2aaSAndroid Build Coastguard Worker fLastTime = 1e-9 * nanos; 80*c8dee2aaSAndroid Build Coastguard Worker return true; 81*c8dee2aaSAndroid Build Coastguard Worker } 82*c8dee2aaSAndroid Build Coastguard Worker 83*c8dee2aaSAndroid Build Coastguard Worker private: 84*c8dee2aaSAndroid Build Coastguard Worker class Node { 85*c8dee2aaSAndroid Build Coastguard Worker public: Node()86*c8dee2aaSAndroid Build Coastguard Worker Node() 87*c8dee2aaSAndroid Build Coastguard Worker : fSize(0.0f) 88*c8dee2aaSAndroid Build Coastguard Worker , fPos { 0.0f, 0.0f } 89*c8dee2aaSAndroid Build Coastguard Worker , fDir { 1.0f, 0.0f } 90*c8dee2aaSAndroid Build Coastguard Worker , fBlurOffset(0.0f) 91*c8dee2aaSAndroid Build Coastguard Worker , fBlur(fBlurOffset) 92*c8dee2aaSAndroid Build Coastguard Worker , fSpeed(0.0f) { 93*c8dee2aaSAndroid Build Coastguard Worker } 94*c8dee2aaSAndroid Build Coastguard Worker init(SkRandom * rand)95*c8dee2aaSAndroid Build Coastguard Worker void init(SkRandom* rand) { 96*c8dee2aaSAndroid Build Coastguard Worker fSize = rand->nextRangeF(10.0f, 60.f); 97*c8dee2aaSAndroid Build Coastguard Worker fPos.fX = rand->nextRangeF(fSize, kWidth - fSize); 98*c8dee2aaSAndroid Build Coastguard Worker fPos.fY = rand->nextRangeF(fSize, kHeight - fSize); 99*c8dee2aaSAndroid Build Coastguard Worker fDir.fX = rand->nextRangeF(-1.0f, 1.0f); 100*c8dee2aaSAndroid Build Coastguard Worker fDir.fY = SkScalarSqrt(1.0f - fDir.fX * fDir.fX); 101*c8dee2aaSAndroid Build Coastguard Worker if (rand->nextBool()) { 102*c8dee2aaSAndroid Build Coastguard Worker fDir.fY = -fDir.fY; 103*c8dee2aaSAndroid Build Coastguard Worker } 104*c8dee2aaSAndroid Build Coastguard Worker fBlurOffset = rand->nextRangeF(0.0f, kBlurMax); 105*c8dee2aaSAndroid Build Coastguard Worker fBlur = fBlurOffset; 106*c8dee2aaSAndroid Build Coastguard Worker fSpeed = rand->nextRangeF(20.0f, 60.0f); 107*c8dee2aaSAndroid Build Coastguard Worker } 108*c8dee2aaSAndroid Build Coastguard Worker update(double nanos,SkScalar lastTime)109*c8dee2aaSAndroid Build Coastguard Worker void update(double nanos, SkScalar lastTime) { 110*c8dee2aaSAndroid Build Coastguard Worker SkScalar deltaTime = 1e-9 * nanos - lastTime; 111*c8dee2aaSAndroid Build Coastguard Worker 112*c8dee2aaSAndroid Build Coastguard Worker fPos.fX += deltaTime * fSpeed * fDir.fX; 113*c8dee2aaSAndroid Build Coastguard Worker fPos.fY += deltaTime * fSpeed * fDir.fY; 114*c8dee2aaSAndroid Build Coastguard Worker if (fPos.fX >= kWidth || fPos.fX < 0.0f) { 115*c8dee2aaSAndroid Build Coastguard Worker fPos.fX = SkTPin<SkScalar>(fPos.fX, 0.0f, kWidth); 116*c8dee2aaSAndroid Build Coastguard Worker fDir.fX = -fDir.fX; 117*c8dee2aaSAndroid Build Coastguard Worker } 118*c8dee2aaSAndroid Build Coastguard Worker if (fPos.fY >= kHeight || fPos.fY < 0.0f) { 119*c8dee2aaSAndroid Build Coastguard Worker fPos.fY = SkTPin<SkScalar>(fPos.fY, 0.0f, kHeight); 120*c8dee2aaSAndroid Build Coastguard Worker fDir.fY = -fDir.fY; 121*c8dee2aaSAndroid Build Coastguard Worker } 122*c8dee2aaSAndroid Build Coastguard Worker 123*c8dee2aaSAndroid Build Coastguard Worker fBlur = TimeUtils::PingPong(1e-9 * nanos, kBlurAnimationDuration, fBlurOffset, 0.0f, kBlurMax); 124*c8dee2aaSAndroid Build Coastguard Worker } 125*c8dee2aaSAndroid Build Coastguard Worker sigma() const126*c8dee2aaSAndroid Build Coastguard Worker SkScalar sigma() const { return fBlur; } pos() const127*c8dee2aaSAndroid Build Coastguard Worker const SkPoint& pos() const { return fPos; } size() const128*c8dee2aaSAndroid Build Coastguard Worker SkScalar size() const { return fSize; } 129*c8dee2aaSAndroid Build Coastguard Worker 130*c8dee2aaSAndroid Build Coastguard Worker private: 131*c8dee2aaSAndroid Build Coastguard Worker SkScalar fSize; 132*c8dee2aaSAndroid Build Coastguard Worker SkPoint fPos; 133*c8dee2aaSAndroid Build Coastguard Worker SkVector fDir; 134*c8dee2aaSAndroid Build Coastguard Worker SkScalar fBlurOffset; 135*c8dee2aaSAndroid Build Coastguard Worker SkScalar fBlur; 136*c8dee2aaSAndroid Build Coastguard Worker SkScalar fSpeed; 137*c8dee2aaSAndroid Build Coastguard Worker }; 138*c8dee2aaSAndroid Build Coastguard Worker 139*c8dee2aaSAndroid Build Coastguard Worker Node fNodes[kNumNodes]; 140*c8dee2aaSAndroid Build Coastguard Worker SkRandom fRand; 141*c8dee2aaSAndroid Build Coastguard Worker SkScalar fLastTime; 142*c8dee2aaSAndroid Build Coastguard Worker 143*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM; 144*c8dee2aaSAndroid Build Coastguard Worker }; 145*c8dee2aaSAndroid Build Coastguard Worker 146*c8dee2aaSAndroid Build Coastguard Worker // This GM draws an image with a tiled blur that animates from large to small sigmas 147*c8dee2aaSAndroid Build Coastguard Worker class AnimatedTiledImageBlur : public skiagm::GM { 148*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kMaxBlurSigma = 250.f; 149*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kAnimationDuration = 12.f; // seconds 150*c8dee2aaSAndroid Build Coastguard Worker public: AnimatedTiledImageBlur()151*c8dee2aaSAndroid Build Coastguard Worker AnimatedTiledImageBlur() : fBlurSigma(0.3f * kMaxBlurSigma) { 152*c8dee2aaSAndroid Build Coastguard Worker this->setBGColor(0xFFCCCCCC); 153*c8dee2aaSAndroid Build Coastguard Worker } 154*c8dee2aaSAndroid Build Coastguard Worker 155*c8dee2aaSAndroid Build Coastguard Worker protected: runAsBench() const156*c8dee2aaSAndroid Build Coastguard Worker bool runAsBench() const override { return true; } 157*c8dee2aaSAndroid Build Coastguard Worker getName() const158*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("animated-tiled-image-blur"); } 159*c8dee2aaSAndroid Build Coastguard Worker getISize()160*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(530, 530); } 161*c8dee2aaSAndroid Build Coastguard Worker onOnceBeforeDraw()162*c8dee2aaSAndroid Build Coastguard Worker void onOnceBeforeDraw() override { 163*c8dee2aaSAndroid Build Coastguard Worker fImage = ToolUtils::GetResourceAsImage("images/mandrill_512.png"); 164*c8dee2aaSAndroid Build Coastguard Worker } 165*c8dee2aaSAndroid Build Coastguard Worker onDraw(SkCanvas * canvas)166*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override { 167*c8dee2aaSAndroid Build Coastguard Worker auto drawBlurredImage = [&](float tx, float ty, SkTileMode tileMode) { 168*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint; 169*c8dee2aaSAndroid Build Coastguard Worker SkRect rect = SkRect::MakeIWH(250, 250); 170*c8dee2aaSAndroid Build Coastguard Worker canvas->save(); 171*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(tx, ty); 172*c8dee2aaSAndroid Build Coastguard Worker paint.setImageFilter(SkImageFilters::Blur(fBlurSigma, fBlurSigma, tileMode, 173*c8dee2aaSAndroid Build Coastguard Worker nullptr, rect)); 174*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImageRect(fImage, rect, SkFilterMode::kLinear, &paint); 175*c8dee2aaSAndroid Build Coastguard Worker canvas->restore(); 176*c8dee2aaSAndroid Build Coastguard Worker }; 177*c8dee2aaSAndroid Build Coastguard Worker 178*c8dee2aaSAndroid Build Coastguard Worker drawBlurredImage(10.f, 10.f, SkTileMode::kDecal); 179*c8dee2aaSAndroid Build Coastguard Worker drawBlurredImage(270.f, 10.f, SkTileMode::kClamp); 180*c8dee2aaSAndroid Build Coastguard Worker drawBlurredImage(10.f, 270.f, SkTileMode::kRepeat); 181*c8dee2aaSAndroid Build Coastguard Worker drawBlurredImage(270.f, 270.f, SkTileMode::kMirror); 182*c8dee2aaSAndroid Build Coastguard Worker } 183*c8dee2aaSAndroid Build Coastguard Worker onAnimate(double nanos)184*c8dee2aaSAndroid Build Coastguard Worker bool onAnimate(double nanos) override { 185*c8dee2aaSAndroid Build Coastguard Worker fBlurSigma = TimeUtils::PingPong(1e-9 * nanos, kAnimationDuration, 186*c8dee2aaSAndroid Build Coastguard Worker 0.f, 0.0f, kMaxBlurSigma); 187*c8dee2aaSAndroid Build Coastguard Worker return true; 188*c8dee2aaSAndroid Build Coastguard Worker } 189*c8dee2aaSAndroid Build Coastguard Worker 190*c8dee2aaSAndroid Build Coastguard Worker private: 191*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> fImage; 192*c8dee2aaSAndroid Build Coastguard Worker SkScalar fBlurSigma; 193*c8dee2aaSAndroid Build Coastguard Worker }; 194*c8dee2aaSAndroid Build Coastguard Worker 195*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////// 196*c8dee2aaSAndroid Build Coastguard Worker 197*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new AnimatedImageBlurs;) 198*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new AnimatedTiledImageBlur;) 199