OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2012 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 "SkView.h" | |
10 #include "SkCanvas.h" | |
11 #include "SkRandom.h" | |
12 #include "SkRRect.h" | |
13 #include "SkColorPriv.h" | |
14 #include "SkStrokerPriv.h" | |
15 | |
16 static void rotateAbout(SkCanvas* canvas, SkScalar degrees, | |
17 SkScalar cx, SkScalar cy) { | |
18 canvas->translate(cx, cy); | |
19 canvas->rotate(degrees); | |
20 canvas->translate(-cx, -cy); | |
21 } | |
22 | |
23 class RotateCirclesView : public SampleView { | |
24 public: | |
25 RotateCirclesView() { | |
26 this->setBGColor(SK_ColorLTGRAY); | |
27 | |
28 fAngle = 0; | |
29 } | |
30 | |
31 protected: | |
32 // overrides from SkEventSink | |
33 virtual bool onQuery(SkEvent* evt) { | |
34 if (SampleCode::TitleQ(*evt)) { | |
35 SampleCode::TitleR(evt, "RotateCircles"); | |
36 return true; | |
37 } | |
38 return this->INHERITED::onQuery(evt); | |
39 } | |
40 | |
41 virtual void onDrawContent(SkCanvas* canvas) { | |
42 SkRandom rand; | |
43 SkPaint paint; | |
44 paint.setAntiAlias(true); | |
45 paint.setStrokeWidth(20); | |
46 | |
47 SkScalar cx = 240; | |
48 SkScalar cy = 240; | |
49 SkScalar DX = 240 * 2; | |
50 SkColor color = 0; | |
51 | |
52 float scale = 1; | |
53 float sign = 0.3f; | |
54 for (SkScalar rad = 200; rad >= 20; rad -= 15) { | |
55 sign = -sign; | |
56 scale += 0.2f; | |
57 | |
58 paint.setColor(rand.nextU()); | |
59 paint.setAlpha(0xFF); | |
60 color = ~color; | |
61 | |
62 paint.setStyle(SkPaint::kFill_Style); | |
63 | |
64 canvas->save(); | |
65 rotateAbout(canvas, fAngle * scale * sign, cx, cy); | |
66 canvas->drawCircle(cx, cy, rad, paint); | |
67 canvas->restore(); | |
68 | |
69 paint.setStyle(SkPaint::kStroke_Style); | |
70 paint.setStrokeWidth(rad*2); | |
71 | |
72 canvas->save(); | |
73 rotateAbout(canvas, fAngle * scale * sign, cx + DX, cy); | |
74 canvas->drawCircle(cx + DX, cy, 10, paint); | |
75 canvas->restore(); | |
76 | |
77 canvas->save(); | |
78 rotateAbout(canvas, fAngle * scale * sign, cx + DX, cy + DX); | |
79 canvas->drawCircle(cx + DX, cy + DX, 10, paint); | |
80 canvas->restore(); | |
81 | |
82 } | |
83 | |
84 fAngle = (fAngle + 1) % 360; | |
85 this->inval(NULL); | |
86 } | |
87 | |
88 private: | |
89 int fAngle; | |
90 typedef SkView INHERITED; | |
91 }; | |
92 | |
93 class TestCirclesView : public SampleView { | |
94 public: | |
95 TestCirclesView() { | |
96 } | |
97 | |
98 protected: | |
99 bool onQuery(SkEvent* evt) SK_OVERRIDE { | |
100 if (SampleCode::TitleQ(*evt)) { | |
101 SampleCode::TitleR(evt, "RotateCircles2"); | |
102 return true; | |
103 } | |
104 return this->INHERITED::onQuery(evt); | |
105 } | |
106 | |
107 void draw_real_circle(SkCanvas* canvas, SkScalar radius) { | |
108 int w = SkScalarCeilToInt(radius * 2); | |
109 int h = w; | |
110 | |
111 SkBitmap bm; | |
112 bm.allocN32Pixels(w, h); | |
113 bm.eraseColor(0); | |
114 | |
115 SkAutoLockPixels alp(bm); | |
116 | |
117 SkScalar cx = radius; | |
118 SkScalar cy = radius; | |
119 for (int y = 0; y < h; y += 1) { | |
120 for (int x = 0; x < w; x += 1) { | |
121 float d = sqrtf((x - cx)*(x - cx) + (y - cy)*(y - cy)); | |
122 if (d <= radius) { | |
123 *bm.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0, 0); | |
124 } | |
125 } | |
126 } | |
127 | |
128 canvas->drawBitmap(bm, 0, 0, NULL); | |
129 } | |
130 | |
131 void onDrawContent(SkCanvas* canvas) SK_OVERRIDE { | |
132 SkScalar radius = 256; | |
133 canvas->translate(10, 10); | |
134 | |
135 draw_real_circle(canvas, radius); | |
136 | |
137 SkPaint paint; | |
138 paint.setAntiAlias(true); | |
139 | |
140 paint.setColor(0x80FF0000); | |
141 canvas->drawCircle(radius, radius, radius, paint); | |
142 | |
143 paint.setStyle(SkPaint::kStroke_Style); | |
144 paint.setStrokeWidth(radius); | |
145 paint.setColor(0x8000FF00); | |
146 canvas->drawCircle(radius, radius, radius/2, paint); | |
147 } | |
148 | |
149 private: | |
150 typedef SkView INHERITED; | |
151 }; | |
152 | |
153 static bool hittest(const SkPoint& target, SkScalar x, SkScalar y) { | |
154 const SkScalar TOL = 7; | |
155 return SkPoint::Distance(target, SkPoint::Make(x, y)) <= TOL; | |
156 } | |
157 | |
158 static int getOnCurvePoints(const SkPath& path, SkPoint storage[]) { | |
159 SkPath::RawIter iter(path); | |
160 SkPoint pts[4]; | |
161 SkPath::Verb verb; | |
162 | |
163 int count = 0; | |
164 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | |
165 switch (verb) { | |
166 case SkPath::kMove_Verb: | |
167 case SkPath::kLine_Verb: | |
168 case SkPath::kQuad_Verb: | |
169 case SkPath::kCubic_Verb: | |
170 storage[count++] = pts[0]; | |
171 break; | |
172 default: | |
173 break; | |
174 } | |
175 } | |
176 return count; | |
177 } | |
178 | |
179 #include "SkPathMeasure.h" | |
180 | |
181 struct StrokeTypeButton { | |
182 SkRect fBounds; | |
183 char fLabel; | |
184 bool fEnabled; | |
185 }; | |
186 | |
187 class TestStrokeView : public SampleView { | |
188 enum { | |
189 SKELETON_COLOR = 0xFF0000FF, | |
190 WIREFRAME_COLOR = 0x80FF0000 | |
191 }; | |
192 | |
193 enum { | |
194 kCount = 9 | |
195 }; | |
196 SkPoint fPts[kCount]; | |
197 SkRect fErrorControl; | |
198 SkRect fWidthControl; | |
199 StrokeTypeButton fCubicButton; | |
200 StrokeTypeButton fQuadButton; | |
201 StrokeTypeButton fRRectButton; | |
202 SkScalar fWidth, fDWidth; | |
203 bool fAnimate; | |
204 #if QUAD_STROKE_APPROXIMATION && defined(SK_DEBUG) | |
205 #define kStrokerErrorMin 0.001f | |
206 #define kStrokerErrorMax 5 | |
207 #endif | |
208 #define kWidthMin 1 | |
209 #define kWidthMax 100 | |
210 public: | |
211 TestStrokeView() { | |
212 this->setBGColor(SK_ColorLTGRAY); | |
213 | |
214 fPts[0].set(50, 200); | |
215 fPts[1].set(50, 100); | |
216 fPts[2].set(150, 50); | |
217 fPts[3].set(300, 50); | |
218 | |
219 fPts[4].set(350, 200); | |
220 fPts[5].set(350, 100); | |
221 fPts[6].set(450, 50); | |
222 | |
223 fPts[7].set(200, 200); | |
224 fPts[8].set(400, 400); | |
225 | |
226 fWidth = 50; | |
227 fDWidth = 0.25f; | |
228 | |
229 fCubicButton.fLabel = 'C'; | |
230 fCubicButton.fEnabled = true; | |
231 fQuadButton.fLabel = 'Q'; | |
232 fQuadButton.fEnabled = true; | |
233 fRRectButton.fLabel = 'R'; | |
234 fRRectButton.fEnabled = true; | |
235 fAnimate = true; | |
236 } | |
237 | |
238 protected: | |
239 bool onQuery(SkEvent* evt) SK_OVERRIDE { | |
240 if (SampleCode::TitleQ(*evt)) { | |
241 SampleCode::TitleR(evt, "RotateCircles3"); | |
242 return true; | |
243 } | |
244 return this->INHERITED::onQuery(evt); | |
245 } | |
246 | |
247 void onSizeChange() SK_OVERRIDE { | |
248 fErrorControl.setXYWH(this->width() - 100, 30, 30, 400); | |
249 fWidthControl.setXYWH(this->width() - 50, 30, 30, 400); | |
250 fCubicButton.fBounds.setXYWH(this->width() - 50, 450, 30, 30); | |
251 fQuadButton.fBounds.setXYWH(this->width() - 50, 500, 30, 30); | |
252 fRRectButton.fBounds.setXYWH(this->width() - 50, 550, 30, 30); | |
253 this->INHERITED::onSizeChange(); | |
254 } | |
255 | |
256 void draw_points(SkCanvas* canvas, const SkPath& path, SkColor color, | |
257 bool show_lines) { | |
258 SkPaint paint; | |
259 paint.setColor(color); | |
260 paint.setAlpha(0x80); | |
261 paint.setAntiAlias(true); | |
262 int n = path.countPoints(); | |
263 SkAutoSTArray<32, SkPoint> pts(n); | |
264 if (show_lines) { | |
265 path.getPoints(pts.get(), n); | |
266 canvas->drawPoints(SkCanvas::kPolygon_PointMode, n, pts.get(), paint
); | |
267 } else { | |
268 n = getOnCurvePoints(path, pts.get()); | |
269 } | |
270 paint.setStrokeWidth(5); | |
271 canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts.get(), paint); | |
272 } | |
273 | |
274 void draw_ribs(SkCanvas* canvas, const SkPath& path, SkScalar width, | |
275 SkColor color) { | |
276 const SkScalar radius = width / 2; | |
277 | |
278 SkPathMeasure meas(path, false); | |
279 SkScalar total = meas.getLength(); | |
280 | |
281 SkScalar delta = 8; | |
282 SkPaint paint; | |
283 paint.setColor(color); | |
284 | |
285 SkPoint pos, tan; | |
286 for (SkScalar dist = 0; dist <= total; dist += delta) { | |
287 if (meas.getPosTan(dist, &pos, &tan)) { | |
288 tan.scale(radius); | |
289 tan.rotateCCW(); | |
290 canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(), | |
291 pos.x() - tan.x(), pos.y() - tan.y(), paint); | |
292 } | |
293 } | |
294 } | |
295 | |
296 void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width) { | |
297 SkPaint paint; | |
298 paint.setAntiAlias(true); | |
299 paint.setStyle(SkPaint::kStroke_Style); | |
300 | |
301 paint.setColor(SKELETON_COLOR); | |
302 canvas->drawPath(path, paint); | |
303 draw_points(canvas, path, SKELETON_COLOR, true); | |
304 | |
305 draw_ribs(canvas, path, width, 0xFF00FF00); | |
306 | |
307 SkPath fill; | |
308 | |
309 SkPaint p; | |
310 p.setStyle(SkPaint::kStroke_Style); | |
311 p.setStrokeWidth(width); | |
312 p.getFillPath(path, &fill); | |
313 | |
314 paint.setColor(WIREFRAME_COLOR); | |
315 canvas->drawPath(fill, paint); | |
316 draw_points(canvas, fill, WIREFRAME_COLOR, false); | |
317 } | |
318 | |
319 void draw_button(SkCanvas* canvas, const StrokeTypeButton& button) { | |
320 SkPaint paint; | |
321 paint.setAntiAlias(true); | |
322 paint.setStyle(SkPaint::kStroke_Style); | |
323 paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000); | |
324 canvas->drawRect(button.fBounds, paint); | |
325 paint.setTextSize(25.0f); | |
326 paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000); | |
327 paint.setTextAlign(SkPaint::kCenter_Align); | |
328 paint.setStyle(SkPaint::kFill_Style); | |
329 canvas->drawText(&button.fLabel, 1, button.fBounds.centerX(), button.fBo
unds.fBottom - 5, | |
330 paint); | |
331 } | |
332 | |
333 void draw_control(SkCanvas* canvas, const SkRect& bounds, SkScalar value, | |
334 SkScalar min, SkScalar max, const char* name) { | |
335 SkPaint paint; | |
336 paint.setAntiAlias(true); | |
337 paint.setStyle(SkPaint::kStroke_Style); | |
338 canvas->drawRect(bounds, paint); | |
339 SkScalar scale = max - min; | |
340 SkScalar yPos = bounds.fTop + (value - min) * bounds.height() / scale; | |
341 paint.setColor(0xFFFF0000); | |
342 canvas->drawLine(bounds.fLeft - 5, yPos, bounds.fRight + 5, yPos, paint)
; | |
343 SkString label; | |
344 label.printf("%0.3g", value); | |
345 paint.setColor(0xFF000000); | |
346 paint.setTextSize(11.0f); | |
347 paint.setStyle(SkPaint::kFill_Style); | |
348 canvas->drawText(label.c_str(), label.size(), bounds.fLeft + 5, yPos - 5
, paint); | |
349 paint.setTextSize(13.0f); | |
350 canvas->drawText(name, strlen(name), bounds.fLeft, bounds.bottom() + 11,
paint); | |
351 } | |
352 | |
353 void onDrawContent(SkCanvas* canvas) SK_OVERRIDE { | |
354 SkPath path; | |
355 SkScalar width = fWidth; | |
356 | |
357 if (fCubicButton.fEnabled) { | |
358 path.moveTo(fPts[0]); | |
359 path.cubicTo(fPts[1], fPts[2], fPts[3]); | |
360 draw_stroke(canvas, path, width); | |
361 } | |
362 | |
363 if (fQuadButton.fEnabled) { | |
364 path.reset(); | |
365 path.moveTo(fPts[4]); | |
366 path.quadTo(fPts[5], fPts[6]); | |
367 draw_stroke(canvas, path, width); | |
368 } | |
369 | |
370 if (fRRectButton.fEnabled) { | |
371 SkScalar rad = 32; | |
372 SkRect r; | |
373 r.set(&fPts[7], 2); | |
374 path.reset(); | |
375 SkRRect rr; | |
376 rr.setRectXY(r, rad, rad); | |
377 path.addRRect(rr); | |
378 draw_stroke(canvas, path, width); | |
379 | |
380 path.reset(); | |
381 SkRRect rr2; | |
382 rr.inset(width/2, width/2, &rr2); | |
383 path.addRRect(rr2, SkPath::kCCW_Direction); | |
384 rr.inset(-width/2, -width/2, &rr2); | |
385 path.addRRect(rr2, SkPath::kCW_Direction); | |
386 SkPaint paint; | |
387 paint.setAntiAlias(true); | |
388 paint.setColor(0x40FF8844); | |
389 canvas->drawPath(path, paint); | |
390 } | |
391 | |
392 if (fAnimate) { | |
393 fWidth += fDWidth; | |
394 if (fDWidth > 0 && fWidth > kWidthMax) { | |
395 fDWidth = -fDWidth; | |
396 } else if (fDWidth < 0 && fWidth < kWidthMin) { | |
397 fDWidth = -fDWidth; | |
398 } | |
399 } | |
400 #if QUAD_STROKE_APPROXIMATION && defined(SK_DEBUG) | |
401 draw_control(canvas, fErrorControl, gDebugStrokerError, kStrokerErrorMin
, kStrokerErrorMax, | |
402 "error"); | |
403 #endif | |
404 draw_control(canvas, fWidthControl, fWidth, kWidthMin, kWidthMax, "width
"); | |
405 draw_button(canvas, fQuadButton); | |
406 draw_button(canvas, fCubicButton); | |
407 draw_button(canvas, fRRectButton); | |
408 this->inval(NULL); | |
409 } | |
410 | |
411 class MyClick : public Click { | |
412 public: | |
413 int fIndex; | |
414 MyClick(SkView* target, int index) : Click(target), fIndex(index) {} | |
415 }; | |
416 | |
417 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, | |
418 unsigned modi) SK_OVERRIDE { | |
419 for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); ++i) { | |
420 if (hittest(fPts[i], x, y)) { | |
421 return new MyClick(this, (int)i); | |
422 } | |
423 } | |
424 const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1); | |
425 #if QUAD_STROKE_APPROXIMATION && defined(SK_DEBUG) | |
426 if (fErrorControl.contains(rectPt)) { | |
427 return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 1); | |
428 } | |
429 #endif | |
430 if (fWidthControl.contains(rectPt)) { | |
431 return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 3); | |
432 } | |
433 if (fCubicButton.fBounds.contains(rectPt)) { | |
434 fCubicButton.fEnabled ^= true; | |
435 return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 4); | |
436 } | |
437 if (fQuadButton.fBounds.contains(rectPt)) { | |
438 fQuadButton.fEnabled ^= true; | |
439 return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 5); | |
440 } | |
441 if (fRRectButton.fBounds.contains(rectPt)) { | |
442 fRRectButton.fEnabled ^= true; | |
443 return new MyClick(this, (int) SK_ARRAY_COUNT(fPts) + 6); | |
444 } | |
445 return this->INHERITED::onFindClickHandler(x, y, modi); | |
446 } | |
447 | |
448 static SkScalar MapScreenYtoValue(int y, const SkRect& control, SkScalar min
, | |
449 SkScalar max) { | |
450 return (SkIntToScalar(y) - control.fTop) / control.height() * (max - min
) + min; | |
451 } | |
452 | |
453 bool onClick(Click* click) SK_OVERRIDE { | |
454 int index = ((MyClick*)click)->fIndex; | |
455 if (index < (int) SK_ARRAY_COUNT(fPts)) { | |
456 fPts[index].offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX
), | |
457 SkIntToScalar(click->fICurr.fY - click->fIPrev.fY
)); | |
458 this->inval(NULL); | |
459 } | |
460 #if QUAD_STROKE_APPROXIMATION && defined(SK_DEBUG) | |
461 else if (index == (int) SK_ARRAY_COUNT(fPts) + 1) { | |
462 gDebugStrokerError = MapScreenYtoValue(click->fICurr.fY, fErrorContr
ol, | |
463 kStrokerErrorMin, kStrokerErrorMax); | |
464 gDebugStrokerErrorSet = true; | |
465 } | |
466 #endif | |
467 else if (index == (int) SK_ARRAY_COUNT(fPts) + 3) { | |
468 fWidth = MapScreenYtoValue(click->fICurr.fY, fWidthControl, kWidthMi
n, kWidthMax); | |
469 fAnimate = fWidth <= kWidthMin; | |
470 } | |
471 return true; | |
472 } | |
473 | |
474 private: | |
475 typedef SkView INHERITED; | |
476 }; | |
477 | |
478 /////////////////////////////////////////////////////////////////////////////// | |
479 | |
480 static SkView* F0() { return new RotateCirclesView; } | |
481 static SkViewRegister gR0(F0); | |
482 static SkView* F1() { return new TestCirclesView; } | |
483 static SkViewRegister gR1(F1); | |
484 static SkView* F2() { return new TestStrokeView; } | |
485 static SkViewRegister gR2(F2); | |
OLD | NEW |