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 "Sample.h"
9 #include "SkAnimTimer.h"
10 #include "SkCanvas.h"
11 #include "SkDrawable.h"
12 #include "SkInterpolator.h"
13 #include "SkPictureRecorder.h"
14 #include "SkPointPriv.h"
15 #include "SkRandom.h"
16
17 const SkRect gUnitSquare = { -1, -1, 1, 1 };
18
color_to_floats(SkColor c,SkScalar f[4])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
floats_to_color(const SkScalar f[4])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
oval_contains(const SkRect & r,SkScalar x,SkScalar y)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 SkPointPriv::LengthSqd(pt) <= 1;
39 }
40
rand_opaque_color(uint32_t seed)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:
HTDrawable(SkRandom & rand)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
spawnAnimation(SkMSec now)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
hitTest(SkScalar x,SkScalar y)80 bool hitTest(SkScalar x, SkScalar y) {
81 return oval_contains(fR, x, y);
82 }
83
setTime(SkMSec time)84 void setTime(SkMSec time) { fTime = time; }
85
onDraw(SkCanvas * canvas)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->rotate(values[4], fR.centerX(), fR.centerY());
99
100 switch (res) {
101 case SkInterpolator::kFreezeEnd_Result:
102 delete fInterp;
103 fInterp = nullptr;
104 break;
105 default:
106 break;
107 }
108 }
109 paint.setColor(fColor);
110 canvas->drawRect(fR, paint);
111 }
112
onGetBounds()113 SkRect onGetBounds() override { return fR; }
114 };
115
116 class HTView : public Sample {
117 public:
118 enum {
119 N = 50,
120 W = 640,
121 H = 480,
122 };
123
124 struct Rec {
125 HTDrawable* fDrawable;
126 };
127 Rec fArray[N];
128 sk_sp<SkDrawable> fRoot;
129 SkMSec fTime;
130
HTView()131 HTView() {
132 SkRandom rand;
133
134 SkPictureRecorder recorder;
135 SkCanvas* canvas = recorder.beginRecording(SkRect::MakeWH(W, H));
136 for (int i = 0; i < N; ++i) {
137 fArray[i].fDrawable = new HTDrawable(rand);
138 canvas->drawDrawable(fArray[i].fDrawable);
139 fArray[i].fDrawable->unref();
140 }
141 fRoot = recorder.finishRecordingAsDrawable();
142 }
143
144 protected:
onQuery(Sample::Event * evt)145 bool onQuery(Sample::Event* evt) override {
146 if (Sample::TitleQ(*evt)) {
147 Sample::TitleR(evt, "HT");
148 return true;
149 }
150 return this->INHERITED::onQuery(evt);
151 }
152
onDrawContent(SkCanvas * canvas)153 void onDrawContent(SkCanvas* canvas) override {
154 canvas->drawDrawable(fRoot.get());
155 }
156
onAnimate(const SkAnimTimer & timer)157 bool onAnimate(const SkAnimTimer& timer) override {
158 fTime = timer.msec();
159 for (int i = 0; i < N; ++i) {
160 fArray[i].fDrawable->setTime(fTime);
161 }
162 return true;
163 }
164
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)165 Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
166 // search backwards to find the top-most
167 for (int i = N - 1; i >= 0; --i) {
168 if (fArray[i].fDrawable->hitTest(x, y)) {
169 fArray[i].fDrawable->spawnAnimation(fTime);
170 break;
171 }
172 }
173 return nullptr;
174 }
175
176 private:
177 typedef Sample INHERITED;
178 };
179
180 //////////////////////////////////////////////////////////////////////////////
181
182 DEF_SAMPLE( return new HTView(); )
183