blob: 8c502955a2fa2365f6d6aeaf793a7c2e2f92544f [file] [log] [blame]
robertphillips0ee62202016-05-31 06:59:18 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBitmap.h"
10#include "include/core/SkBlurTypes.h"
11#include "include/core/SkCanvas.h"
12#include "include/core/SkColor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkMaskFilter.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040014#include "include/core/SkMatrix.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "include/core/SkPaint.h"
16#include "include/core/SkPath.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040017#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050026#include "include/effects/SkDashPathEffect.h"
27#include "include/effects/SkGradientShader.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040028#include "include/private/SkTArray.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "tools/ToolUtils.h"
robertphillips0ee62202016-05-31 06:59:18 -070030
Ben Wagner7fde8e12019-05-01 17:28:53 -040031#include <initializer_list>
32
mtkleindbfd7ab2016-09-01 11:24:54 -070033constexpr int kNumColumns = 6;
34constexpr int kNumRows = 8;
35constexpr int kRadius = 40; // radius of the snowflake
36constexpr int kPad = 5; // padding on both sides of the snowflake
37constexpr int kNumSpokes = 6;
38constexpr SkScalar kStrokeWidth = 5.0f;
robertphillips0ee62202016-05-31 06:59:18 -070039
40static void draw_fins(SkCanvas* canvas, const SkPoint& offset, float angle, const SkPaint& paint) {
41 SkScalar cos, sin;
42
43 // first fin
Brian Osman4428f2c2019-04-02 10:59:28 -040044 sin = SkScalarSin(angle + (SK_ScalarPI/4));
45 cos = SkScalarCos(angle + (SK_ScalarPI/4));
robertphillips0ee62202016-05-31 06:59:18 -070046 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
Brian Osman4428f2c2019-04-02 10:59:28 -040055 sin = SkScalarSin(angle - (SK_ScalarPI/4));
56 cos = SkScalarCos(angle - (SK_ScalarPI/4));
robertphillips0ee62202016-05-31 06:59:18 -070057 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
67static 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)) {
Brian Osman4428f2c2019-04-02 10:59:28 -040073 sin = SkScalarSin(angle);
74 cos = SkScalarCos(angle);
robertphillips0ee62202016-05-31 06:59:18 -070075 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
94static 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
115namespace 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.
119class StrokedLinesGM : public GM {
120public:
Mike Kleinea3f0142019-03-20 11:12:10 -0500121 StrokedLinesGM() { this->setBGColor(ToolUtils::color_to_565(0xFF1A65D7)); }
robertphillips0ee62202016-05-31 06:59:18 -0700122
123protected:
124 SkString onShortName() override {
125 return SkString("strokedlines");
126 }
127
128 SkISize onISize() override {
129 return SkISize::Make(kNumColumns * (2*kRadius+2*kPad), kNumRows * (2*kRadius+2*kPad));
130 }
131
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;
Mike Reedfae8fce2019-04-03 10:27:45 -0400146 p.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kClamp));
robertphillips0ee62202016-05-31 06:59:18 -0700147
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);
Brian Salomon23356442018-11-30 15:33:19 -0500169 m.preScale(3.0f, 3.0f);
robertphillips0ee62202016-05-31 06:59:18 -0700170
171 SkPaint p;
Mike Reedb41bd152020-12-12 11:18:31 -0500172 p.setShader(bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
173 SkSamplingOptions(), m));
robertphillips0ee62202016-05-31 06:59:18 -0700174 fPaints.push_back(p);
175 }
176 {
177 // blur
178 SkPaint p;
179 p.setColor(SK_ColorWHITE);
Mike Reed1be1f8d2018-03-14 13:01:17 -0400180 p.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle, 3.0f));
robertphillips0ee62202016-05-31 06:59:18 -0700181 fPaints.push_back(p);
182 }
183
184 // matrices
185 {
186 // rotation
187 SkMatrix m;
188 m.setRotate(12.0f);
189
190 fMatrices.push_back(m);
191 }
192 {
193 // skew
194 SkMatrix m;
195 m.setSkew(0.3f, 0.5f);
196
197 fMatrices.push_back(m);
198 }
199 {
200 // perspective
201 SkMatrix m;
202 m.reset();
203 m.setPerspX(-SK_Scalar1 / 300);
204 m.setPerspY(SK_Scalar1 / 300);
205
206 fMatrices.push_back(m);
207 }
208
209 SkASSERT(kNumRows == fPaints.count() + fMatrices.count());
210 }
211
212 void onDraw(SkCanvas* canvas) override {
213 canvas->translate(0, kRadius+kPad);
214
215 for (int i = 0; i < fPaints.count(); ++i) {
216 int saveCount = canvas->save();
217 draw_row(canvas, fPaints[i], SkMatrix::I());
218 canvas->restoreToCount(saveCount);
219
220 canvas->translate(0, 2*(kRadius+kPad));
221 }
222
223 for (int i = 0; i < fMatrices.count(); ++i) {
224 int saveCount = canvas->save();
225 draw_row(canvas, fPaints[0], fMatrices[i]);
226 canvas->restoreToCount(saveCount);
227
228 canvas->translate(0, 2*(kRadius+kPad));
229 }
230 }
231
232private:
233 SkTArray<SkPaint> fPaints;
234 SkTArray<SkMatrix> fMatrices;
235
John Stiles7571f9e2020-09-02 22:42:33 -0400236 using INHERITED = GM;
robertphillips0ee62202016-05-31 06:59:18 -0700237};
238
239//////////////////////////////////////////////////////////////////////////////
240
241DEF_GM(return new StrokedLinesGM;)
John Stilesa6841be2020-08-06 14:11:56 -0400242} // namespace skiagm