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