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