Home | History | Annotate | Download | only in samplecode
      1 /*
      2  * Copyright 2014 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 "SampleCode.h"
      9 #include "SkAnimTimer.h"
     10 #include "SkView.h"
     11 #include "SkCanvas.h"
     12 #include "SkDrawable.h"
     13 #include "SkInterpolator.h"
     14 #include "SkPictureRecorder.h"
     15 #include "SkRandom.h"
     16 
     17 const SkRect gUnitSquare = { -1, -1, 1, 1 };
     18 
     19 static void color_to_floats(SkColor c, SkScalar f[4]) {
     20     f[0] = SkIntToScalar(SkColorGetA(c));
     21     f[1] = SkIntToScalar(SkColorGetR(c));
     22     f[2] = SkIntToScalar(SkColorGetG(c));
     23     f[3] = SkIntToScalar(SkColorGetB(c));
     24 }
     25 
     26 static SkColor floats_to_color(const SkScalar f[4]) {
     27     return SkColorSetARGB(SkScalarRoundToInt(f[0]),
     28                           SkScalarRoundToInt(f[1]),
     29                           SkScalarRoundToInt(f[2]),
     30                           SkScalarRoundToInt(f[3]));
     31 }
     32 
     33 static bool oval_contains(const SkRect& r, SkScalar x, SkScalar y) {
     34     SkMatrix m;
     35     m.setRectToRect(r, gUnitSquare, SkMatrix::kFill_ScaleToFit);
     36     SkPoint pt;
     37     m.mapXY(x, y, &pt);
     38     return pt.lengthSqd() <= 1;
     39 }
     40 
     41 static SkColor rand_opaque_color(uint32_t seed) {
     42     SkRandom rand(seed);
     43     return rand.nextU() | (0xFF << 24);
     44 }
     45 
     46 class HTDrawable : public SkDrawable {
     47     SkRect          fR;
     48     SkColor         fColor;
     49     SkInterpolator* fInterp;
     50     SkMSec          fTime;
     51 
     52 public:
     53     HTDrawable(SkRandom& rand) {
     54         fR = SkRect::MakeXYWH(rand.nextRangeF(0, 640), rand.nextRangeF(0, 480),
     55                               rand.nextRangeF(20, 200), rand.nextRangeF(20, 200));
     56         fColor = rand_opaque_color(rand.nextU());
     57         fInterp = nullptr;
     58         fTime = 0;
     59     }
     60 
     61     void spawnAnimation(SkMSec now) {
     62         this->setTime(now);
     63 
     64         delete fInterp;
     65         fInterp = new SkInterpolator(5, 3);
     66         SkScalar values[5];
     67         color_to_floats(fColor, values); values[4] = 0;
     68         fInterp->setKeyFrame(0, now, values);
     69         values[0] = 0; values[4] = 180;
     70         fInterp->setKeyFrame(1, now + 1000, values);
     71         color_to_floats(rand_opaque_color(fColor), values); values[4] = 360;
     72         fInterp->setKeyFrame(2, now + 2000, values);
     73 
     74         fInterp->setMirror(true);
     75         fInterp->setRepeatCount(3);
     76 
     77         this->notifyDrawingChanged();
     78     }
     79 
     80     bool hitTest(SkScalar x, SkScalar y) {
     81         return oval_contains(fR, x, y);
     82     }
     83 
     84     void setTime(SkMSec time) { fTime = time; }
     85 
     86     void onDraw(SkCanvas* canvas) override {
     87         SkAutoCanvasRestore acr(canvas, false);
     88 
     89         SkPaint paint;
     90         paint.setAntiAlias(true);
     91 
     92         if (fInterp) {
     93             SkScalar values[5];
     94             SkInterpolator::Result res = fInterp->timeToValues(fTime, values);
     95             fColor = floats_to_color(values);
     96 
     97             canvas->save();
     98             canvas->translate(fR.centerX(), fR.centerY());
     99             canvas->rotate(values[4]);
    100             canvas->translate(-fR.centerX(), -fR.centerY());
    101 
    102             switch (res) {
    103                 case SkInterpolator::kFreezeEnd_Result:
    104                     delete fInterp;
    105                     fInterp = nullptr;
    106                     break;
    107                 default:
    108                     break;
    109             }
    110         }
    111         paint.setColor(fColor);
    112         canvas->drawRect(fR, paint);
    113     }
    114 
    115     SkRect onGetBounds() override { return fR; }
    116 };
    117 
    118 class HTView : public SampleView {
    119 public:
    120     enum {
    121         N = 50,
    122         W = 640,
    123         H = 480,
    124     };
    125 
    126     struct Rec {
    127         HTDrawable* fDrawable;
    128     };
    129     Rec fArray[N];
    130     SkAutoTUnref<SkDrawable> fRoot;
    131     SkMSec fTime;
    132 
    133     HTView() {
    134         SkRandom rand;
    135 
    136         SkPictureRecorder recorder;
    137         SkCanvas* canvas = recorder.beginRecording(SkRect::MakeWH(W, H));
    138         for (int i = 0; i < N; ++i) {
    139             fArray[i].fDrawable = new HTDrawable(rand);
    140             canvas->drawDrawable(fArray[i].fDrawable);
    141             fArray[i].fDrawable->unref();
    142         }
    143         fRoot.reset(recorder.endRecordingAsDrawable());
    144     }
    145 
    146 protected:
    147     bool onQuery(SkEvent* evt) override {
    148         if (SampleCode::TitleQ(*evt)) {
    149             SampleCode::TitleR(evt, "HT");
    150             return true;
    151         }
    152         return this->INHERITED::onQuery(evt);
    153     }
    154 
    155     void onDrawContent(SkCanvas* canvas) override {
    156         canvas->drawDrawable(fRoot);
    157     }
    158 
    159     bool onAnimate(const SkAnimTimer& timer) override {
    160         fTime = timer.msec();
    161         for (int i = 0; i < N; ++i) {
    162             fArray[i].fDrawable->setTime(fTime);
    163         }
    164         return true;
    165     }
    166 
    167     SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
    168         // search backwards to find the top-most
    169         for (int i = N - 1; i >= 0; --i) {
    170             if (fArray[i].fDrawable->hitTest(x, y)) {
    171                 fArray[i].fDrawable->spawnAnimation(fTime);
    172                 break;
    173             }
    174         }
    175         this->inval(nullptr);
    176         return nullptr;
    177     }
    178 
    179 private:
    180     typedef SampleView INHERITED;
    181 };
    182 
    183 //////////////////////////////////////////////////////////////////////////////
    184 
    185 static SkView* MyFactory() { return new HTView; }
    186 static SkViewRegister reg(MyFactory);
    187