• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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 "gm.h"
9 #include "sk_tool_utils.h"
10 #include "SkDashPathEffect.h"
11 #include "SkGradientShader.h"
12 #include "SkMaskFilter.h"
13 #include "SkPaint.h"
14 #include "SkPath.h"
15 #include "SkPoint3.h"
16 
17 constexpr int kNumColumns = 6;
18 constexpr int kNumRows = 8;
19 constexpr int kRadius = 40;  // radius of the snowflake
20 constexpr int kPad = 5;      // padding on both sides of the snowflake
21 constexpr int kNumSpokes = 6;
22 constexpr SkScalar kStrokeWidth = 5.0f;
23 
draw_fins(SkCanvas * canvas,const SkPoint & offset,float angle,const SkPaint & paint)24 static void draw_fins(SkCanvas* canvas, const SkPoint& offset, float angle, const SkPaint& paint) {
25     SkScalar cos, sin;
26 
27     // first fin
28     sin = SkScalarSinCos(angle + (SK_ScalarPI/4), &cos);
29     sin *= kRadius / 2.0f;
30     cos *= kRadius / 2.0f;
31 
32     SkPath p;
33     p.moveTo(offset.fX, offset.fY);
34     p.lineTo(offset.fX + cos, offset.fY + sin);
35     canvas->drawPath(p, paint);
36 
37     // second fin
38     sin = SkScalarSinCos(angle - (SK_ScalarPI/4), &cos);
39     sin *= kRadius / 2.0f;
40     cos *= kRadius / 2.0f;
41 
42     p.reset();
43     p.moveTo(offset.fX, offset.fY);
44     p.lineTo(offset.fX + cos, offset.fY + sin);
45     canvas->drawPath(p, paint);
46 }
47 
48 // draw a snowflake centered at the origin
draw_snowflake(SkCanvas * canvas,const SkPaint & paint)49 static void draw_snowflake(SkCanvas* canvas, const SkPaint& paint) {
50 
51     canvas->clipRect(SkRect::MakeLTRB(-kRadius-kPad, -kRadius-kPad, kRadius+kPad, kRadius+kPad));
52 
53     SkScalar sin, cos, angle = 0.0f;
54     for (int i = 0; i < kNumSpokes/2; ++i, angle += SK_ScalarPI/(kNumSpokes/2)) {
55         sin = SkScalarSinCos(angle, &cos);
56         sin *= kRadius;
57         cos *= kRadius;
58 
59         // main spoke
60         SkPath p;
61         p.moveTo(-cos, -sin);
62         p.lineTo(cos, sin);
63         canvas->drawPath(p, paint);
64 
65         // fins on positive side
66         const SkPoint posOffset = SkPoint::Make(0.5f * cos, 0.5f * sin);
67         draw_fins(canvas, posOffset, angle, paint);
68 
69         // fins on negative side
70         const SkPoint negOffset = SkPoint::Make(-0.5f * cos, -0.5f * sin);
71         draw_fins(canvas, negOffset, angle+SK_ScalarPI, paint);
72     }
73 }
74 
draw_row(SkCanvas * canvas,const SkPaint & paint,const SkMatrix & localMatrix)75 static void draw_row(SkCanvas* canvas, const SkPaint& paint, const SkMatrix& localMatrix) {
76     canvas->translate(kRadius+kPad, 0.0f);
77 
78     for (auto cap : { SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap }) {
79         for (auto isAA : { true, false }) {
80             SkPaint tmp(paint);
81             tmp.setStrokeWidth(kStrokeWidth);
82             tmp.setStyle(SkPaint::kStroke_Style);
83             tmp.setStrokeCap(cap);
84             tmp.setAntiAlias(isAA);
85 
86             int saveCount = canvas->save();
87             canvas->concat(localMatrix);
88             draw_snowflake(canvas, tmp);
89             canvas->restoreToCount(saveCount);
90 
91             canvas->translate(2*(kRadius+kPad), 0.0f);
92         }
93     }
94 }
95 
96 namespace skiagm {
97 
98 // This GM exercises the special case of a stroked lines.
99 // Various shaders are applied to ensure the coordinate spaces work out right.
100 class StrokedLinesGM : public GM {
101 public:
StrokedLinesGM()102     StrokedLinesGM() {
103         this->setBGColor(sk_tool_utils::color_to_565(0xFF1A65D7));
104     }
105 
106 protected:
onShortName()107     SkString onShortName() override {
108         return SkString("strokedlines");
109     }
110 
onISize()111     SkISize onISize() override {
112         return SkISize::Make(kNumColumns * (2*kRadius+2*kPad), kNumRows * (2*kRadius+2*kPad));
113     }
114 
onOnceBeforeDraw()115     void onOnceBeforeDraw() override {
116         // paints
117         {
118             // basic white
119             SkPaint p;
120             p.setColor(SK_ColorWHITE);
121             fPaints.push_back(p);
122         }
123         {
124             // gradient
125             SkColor colors[] = { SK_ColorRED, SK_ColorGREEN };
126             SkPoint pts[] = { {-kRadius-kPad, -kRadius-kPad }, { kRadius+kPad, kRadius+kPad } };
127 
128             SkPaint p;
129             p.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2,
130                                                      SkShader::kClamp_TileMode, 0, nullptr));
131 
132             fPaints.push_back(p);
133         }
134         {
135             // dashing
136             SkScalar intervals[] = { kStrokeWidth, kStrokeWidth };
137             int intervalCount = (int) SK_ARRAY_COUNT(intervals);
138             SkPaint p;
139             p.setColor(SK_ColorWHITE);
140             p.setPathEffect(SkDashPathEffect::Make(intervals, intervalCount, kStrokeWidth));
141 
142             fPaints.push_back(p);
143         }
144         {
145             // Bitmap shader
146             SkBitmap bm;
147             bm.allocN32Pixels(2, 2);
148             *bm.getAddr32(0, 0) = *bm.getAddr32(1, 1) = 0xFFFFFFFF;
149             *bm.getAddr32(1, 0) = *bm.getAddr32(0, 1) = 0x0;
150 
151             SkMatrix m;
152             m.setRotate(12.0f);
153             m.preScale(3.0f, 3.0f);
154 
155             SkPaint p;
156             p.setShader(SkShader::MakeBitmapShader(bm,
157                                                    SkShader::kRepeat_TileMode,
158                                                    SkShader::kRepeat_TileMode,
159                                                    &m));
160             fPaints.push_back(p);
161         }
162         {
163             // blur
164             SkPaint p;
165             p.setColor(SK_ColorWHITE);
166             p.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle, 3.0f));
167             fPaints.push_back(p);
168         }
169 
170         // matrices
171         {
172             // rotation
173             SkMatrix m;
174             m.setRotate(12.0f);
175 
176             fMatrices.push_back(m);
177         }
178         {
179             // skew
180             SkMatrix m;
181             m.setSkew(0.3f, 0.5f);
182 
183             fMatrices.push_back(m);
184         }
185         {
186             // perspective
187             SkMatrix m;
188             m.reset();
189             m.setPerspX(-SK_Scalar1 / 300);
190             m.setPerspY(SK_Scalar1 / 300);
191 
192             fMatrices.push_back(m);
193         }
194 
195         SkASSERT(kNumRows == fPaints.count() + fMatrices.count());
196     }
197 
onDraw(SkCanvas * canvas)198     void onDraw(SkCanvas* canvas) override {
199         canvas->translate(0, kRadius+kPad);
200 
201         for (int i = 0; i < fPaints.count(); ++i) {
202             int saveCount = canvas->save();
203             draw_row(canvas, fPaints[i], SkMatrix::I());
204             canvas->restoreToCount(saveCount);
205 
206             canvas->translate(0, 2*(kRadius+kPad));
207         }
208 
209         for (int i = 0; i < fMatrices.count(); ++i) {
210             int saveCount = canvas->save();
211             draw_row(canvas, fPaints[0], fMatrices[i]);
212             canvas->restoreToCount(saveCount);
213 
214             canvas->translate(0, 2*(kRadius+kPad));
215         }
216     }
217 
218 private:
219     SkTArray<SkPaint> fPaints;
220     SkTArray<SkMatrix> fMatrices;
221 
222     typedef GM INHERITED;
223 };
224 
225 //////////////////////////////////////////////////////////////////////////////
226 
227 DEF_GM(return new StrokedLinesGM;)
228 }
229