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 15 static void rotateAbout(SkCanvas* canvas, SkScalar degrees, 16 SkScalar cx, SkScalar cy) { 17 canvas->translate(cx, cy); 18 canvas->rotate(degrees); 19 canvas->translate(-cx, -cy); 20 } 21 22 class RotateCirclesView : public SampleView { 23 public: 24 RotateCirclesView() { 25 this->setBGColor(SK_ColorLTGRAY); 26 27 fAngle = 0; 28 } 29 30 protected: 31 // overrides from SkEventSink 32 virtual bool onQuery(SkEvent* evt) { 33 if (SampleCode::TitleQ(*evt)) { 34 SampleCode::TitleR(evt, "RotateCircles"); 35 return true; 36 } 37 return this->INHERITED::onQuery(evt); 38 } 39 40 virtual void onDrawContent(SkCanvas* canvas) { 41 SkRandom rand; 42 SkPaint paint; 43 paint.setAntiAlias(true); 44 paint.setStrokeWidth(20); 45 46 SkScalar cx = 240; 47 SkScalar cy = 240; 48 SkScalar DX = 240 * 2; 49 SkColor color = 0; 50 51 float scale = 1; 52 float sign = 0.3f; 53 for (SkScalar rad = 200; rad >= 20; rad -= 15) { 54 sign = -sign; 55 scale += 0.2f; 56 57 paint.setColor(rand.nextU()); 58 paint.setAlpha(0xFF); 59 color = ~color; 60 61 paint.setStyle(SkPaint::kFill_Style); 62 63 canvas->save(); 64 rotateAbout(canvas, fAngle * scale * sign, cx, cy); 65 canvas->drawCircle(cx, cy, rad, paint); 66 canvas->restore(); 67 68 paint.setStyle(SkPaint::kStroke_Style); 69 paint.setStrokeWidth(rad*2); 70 71 canvas->save(); 72 rotateAbout(canvas, fAngle * scale * sign, cx + DX, cy); 73 canvas->drawCircle(cx + DX, cy, 10, paint); 74 canvas->restore(); 75 76 canvas->save(); 77 rotateAbout(canvas, fAngle * scale * sign, cx + DX, cy + DX); 78 canvas->drawCircle(cx + DX, cy + DX, 10, paint); 79 canvas->restore(); 80 81 } 82 83 fAngle = (fAngle + 1) % 360; 84 this->inval(NULL); 85 } 86 87 private: 88 int fAngle; 89 typedef SkView INHERITED; 90 }; 91 92 class TestCirclesView : public SampleView { 93 public: 94 TestCirclesView() { 95 } 96 97 protected: 98 virtual bool onQuery(SkEvent* evt) SK_OVERRIDE { 99 if (SampleCode::TitleQ(*evt)) { 100 SampleCode::TitleR(evt, "RotateCircles2"); 101 return true; 102 } 103 return this->INHERITED::onQuery(evt); 104 } 105 106 void draw_real_circle(SkCanvas* canvas, SkScalar radius) { 107 int w = SkScalarCeilToInt(radius * 2); 108 int h = w; 109 110 SkBitmap bm; 111 bm.allocN32Pixels(w, h); 112 bm.eraseColor(0); 113 114 SkAutoLockPixels alp(bm); 115 116 SkScalar cx = radius; 117 SkScalar cy = radius; 118 for (int y = 0; y < h; y += 1) { 119 for (int x = 0; x < w; x += 1) { 120 float d = sqrtf((x - cx)*(x - cx) + (y - cy)*(y - cy)); 121 if (d <= radius) { 122 *bm.getAddr32(x, y) = SkPackARGB32(0xFF, 0, 0, 0); 123 } 124 } 125 } 126 127 canvas->drawBitmap(bm, 0, 0, NULL); 128 } 129 130 virtual void onDrawContent(SkCanvas* canvas) { 131 SkScalar radius = 256; 132 canvas->translate(10, 10); 133 134 draw_real_circle(canvas, radius); 135 136 SkPaint paint; 137 paint.setAntiAlias(true); 138 139 paint.setColor(0x80FF0000); 140 canvas->drawCircle(radius, radius, radius, paint); 141 142 paint.setStyle(SkPaint::kStroke_Style); 143 paint.setStrokeWidth(radius); 144 paint.setColor(0x8000FF00); 145 canvas->drawCircle(radius, radius, radius/2, paint); 146 } 147 148 private: 149 typedef SkView INHERITED; 150 }; 151 152 static bool hittest(const SkPoint& target, SkScalar x, SkScalar y) { 153 const SkScalar TOL = 7; 154 return SkPoint::Distance(target, SkPoint::Make(x, y)) <= TOL; 155 } 156 157 static int getOnCurvePoints(const SkPath& path, SkPoint storage[]) { 158 SkPath::RawIter iter(path); 159 SkPoint pts[4]; 160 SkPath::Verb verb; 161 162 int count = 0; 163 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 164 switch (verb) { 165 case SkPath::kMove_Verb: 166 case SkPath::kLine_Verb: 167 case SkPath::kQuad_Verb: 168 case SkPath::kCubic_Verb: 169 storage[count++] = pts[0]; 170 break; 171 default: 172 break; 173 } 174 } 175 return count; 176 } 177 178 #include "SkPathMeasure.h" 179 180 class TestStrokeView : public SampleView { 181 enum { 182 SKELETON_COLOR = 0xFF0000FF, 183 WIREFRAME_COLOR = 0x80FF0000 184 }; 185 186 enum { 187 kCount = 9 188 }; 189 SkPoint fPts[kCount]; 190 SkScalar fWidth, fDWidth; 191 public: 192 TestStrokeView() { 193 this->setBGColor(SK_ColorLTGRAY); 194 195 fPts[0].set(50, 200); 196 fPts[1].set(50, 100); 197 fPts[2].set(150, 50); 198 fPts[3].set(300, 50); 199 200 fPts[4].set(350, 200); 201 fPts[5].set(350, 100); 202 fPts[6].set(450, 50); 203 204 fPts[7].set(200, 200); 205 fPts[8].set(400, 400); 206 207 fWidth = 50; 208 fDWidth = 0.25f; 209 } 210 211 protected: 212 virtual bool onQuery(SkEvent* evt) SK_OVERRIDE { 213 if (SampleCode::TitleQ(*evt)) { 214 SampleCode::TitleR(evt, "RotateCircles3"); 215 return true; 216 } 217 return this->INHERITED::onQuery(evt); 218 } 219 220 void draw_points(SkCanvas* canvas, const SkPath& path, SkColor color, 221 bool show_lines) { 222 SkPaint paint; 223 paint.setColor(color); 224 paint.setAlpha(0x80); 225 226 int n = path.countPoints(); 227 SkAutoSTArray<32, SkPoint> pts(n); 228 if (show_lines) { 229 path.getPoints(pts.get(), n); 230 canvas->drawPoints(SkCanvas::kPolygon_PointMode, n, pts.get(), paint); 231 } else { 232 n = getOnCurvePoints(path, pts.get()); 233 } 234 paint.setStrokeWidth(5); 235 canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts.get(), paint); 236 } 237 238 void draw_ribs(SkCanvas* canvas, const SkPath& path, SkScalar width, 239 SkColor color) { 240 const SkScalar radius = width / 2; 241 242 SkPathMeasure meas(path, false); 243 SkScalar total = meas.getLength(); 244 245 SkScalar delta = 8; 246 SkPaint paint; 247 paint.setColor(color); 248 249 SkPoint pos, tan; 250 for (SkScalar dist = 0; dist <= total; dist += delta) { 251 if (meas.getPosTan(dist, &pos, &tan)) { 252 tan.scale(radius); 253 tan.rotateCCW(); 254 canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(), 255 pos.x() - tan.x(), pos.y() - tan.y(), paint); 256 } 257 } 258 } 259 260 void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width) { 261 SkPaint paint; 262 paint.setAntiAlias(true); 263 paint.setStyle(SkPaint::kStroke_Style); 264 265 paint.setColor(SKELETON_COLOR); 266 canvas->drawPath(path, paint); 267 draw_points(canvas, path, SKELETON_COLOR, true); 268 269 draw_ribs(canvas, path, width, 0xFF00FF00); 270 271 SkPath fill; 272 273 SkPaint p; 274 p.setStyle(SkPaint::kStroke_Style); 275 p.setStrokeWidth(width); 276 p.getFillPath(path, &fill); 277 278 paint.setColor(WIREFRAME_COLOR); 279 canvas->drawPath(fill, paint); 280 draw_points(canvas, fill, WIREFRAME_COLOR, false); 281 } 282 283 virtual void onDrawContent(SkCanvas* canvas) { 284 SkPath path; 285 SkScalar width = fWidth; 286 287 path.moveTo(fPts[0]); 288 path.cubicTo(fPts[1], fPts[2], fPts[3]); 289 draw_stroke(canvas, path, width); 290 291 path.reset(); 292 path.moveTo(fPts[4]); 293 path.quadTo(fPts[5], fPts[6]); 294 draw_stroke(canvas, path, width); 295 296 SkScalar rad = 32; 297 SkRect r; 298 r.set(&fPts[7], 2); 299 path.reset(); 300 SkRRect rr; 301 rr.setRectXY(r, rad, rad); 302 path.addRRect(rr); 303 draw_stroke(canvas, path, width); 304 305 path.reset(); 306 SkRRect rr2; 307 rr.inset(width/2, width/2, &rr2); 308 path.addRRect(rr2, SkPath::kCCW_Direction); 309 rr.inset(-width/2, -width/2, &rr2); 310 path.addRRect(rr2, SkPath::kCW_Direction); 311 SkPaint paint; 312 paint.setAntiAlias(true); 313 paint.setColor(0x40FF8844); 314 canvas->drawPath(path, paint); 315 316 fWidth += fDWidth; 317 if (fDWidth > 0 && fWidth > 100) { 318 fDWidth = -fDWidth; 319 } else if (fDWidth < 0 && fWidth < 10) { 320 fDWidth = -fDWidth; 321 } 322 this->inval(NULL); 323 } 324 325 class MyClick : public Click { 326 public: 327 int fIndex; 328 MyClick(SkView* target, int index) : Click(target), fIndex(index) {} 329 }; 330 331 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, 332 unsigned modi) SK_OVERRIDE { 333 for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); ++i) { 334 if (hittest(fPts[i], x, y)) { 335 return new MyClick(this, (int)i); 336 } 337 } 338 return this->INHERITED::onFindClickHandler(x, y, modi); 339 } 340 341 virtual bool onClick(Click* click) { 342 int index = ((MyClick*)click)->fIndex; 343 fPts[index].offset(SkIntToScalar(click->fICurr.fX - click->fIPrev.fX), 344 SkIntToScalar(click->fICurr.fY - click->fIPrev.fY)); 345 this->inval(NULL); 346 return true; 347 } 348 349 private: 350 typedef SkView INHERITED; 351 }; 352 353 /////////////////////////////////////////////////////////////////////////////// 354 355 static SkView* F0() { return new RotateCirclesView; } 356 static SkViewRegister gR0(F0); 357 static SkView* F1() { return new TestCirclesView; } 358 static SkViewRegister gR1(F1); 359 static SkView* F2() { return new TestStrokeView; } 360 static SkViewRegister gR2(F2); 361