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