Home | History | Annotate | Download | only in gm
      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