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