blob: 72e3d1c54946e97586ad4df61bd0d63b9d5671eb [file] [log] [blame]
caryclarkb6474dd2016-01-19 08:07:49 -08001/*
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"
robertphillips651bb5f2016-04-08 13:35:14 -07009#include "SkAnimTimer.h"
caryclarkb6474dd2016-01-19 08:07:49 -080010#include "SkPath.h"
11#include "SkDashPathEffect.h"
12
13int dash1[] = { 1, 1 };
14int dash2[] = { 1, 3 };
15int dash3[] = { 1, 1, 3, 3 };
16int dash4[] = { 1, 3, 2, 4 };
17
18struct DashExample {
19 int* pattern;
20 int length;
21} dashExamples[] = {
22 { dash1, SK_ARRAY_COUNT(dash1) },
23 { dash2, SK_ARRAY_COUNT(dash2) },
24 { dash3, SK_ARRAY_COUNT(dash3) },
25 { dash4, SK_ARRAY_COUNT(dash4) }
26};
27
robertphillips651bb5f2016-04-08 13:35:14 -070028
29class DashCircleGM : public skiagm::GM {
30public:
31 DashCircleGM() : fRotation(0) { }
32
33protected:
34 SkString onShortName() override { return SkString("dashcircle"); }
35
36 SkISize onISize() override { return SkISize::Make(900, 1200); }
37
38 void onDraw(SkCanvas* canvas) override {
39 SkPaint refPaint;
40 refPaint.setAntiAlias(true);
41 refPaint.setColor(0xFFbf3f7f);
42 refPaint.setStyle(SkPaint::kStroke_Style);
43 refPaint.setStrokeWidth(1);
44 const SkScalar radius = 125;
45 SkRect oval = SkRect::MakeLTRB(-radius - 20, -radius - 20, radius + 20, radius + 20);
46 SkPath circle;
47 circle.addCircle(0, 0, radius);
48 SkScalar circumference = radius * SK_ScalarPI * 2;
49 int wedges[] = { 6, 12, 36 };
50 canvas->translate(radius+20, radius+20);
51 for (int wedge : wedges) {
52 SkScalar arcLength = 360.f / wedge;
53 canvas->save();
54 for (const DashExample& dashExample : dashExamples) {
55 SkPath refPath;
56 int dashUnits = 0;
57 for (int index = 0; index < dashExample.length; ++index) {
58 dashUnits += dashExample.pattern[index];
caryclarkb6474dd2016-01-19 08:07:49 -080059 }
robertphillips651bb5f2016-04-08 13:35:14 -070060 SkScalar unitLength = arcLength / dashUnits;
61 SkScalar angle = 0;
62 for (int index = 0; index < wedge; ++index) {
63 for (int i2 = 0; i2 < dashExample.length; i2 += 2) {
64 SkScalar span = dashExample.pattern[i2] * unitLength;
65 refPath.moveTo(0, 0);
66 refPath.arcTo(oval, angle, span, false);
67 refPath.close();
68 angle += span + (dashExample.pattern[i2 + 1]) * unitLength;
69 }
70 }
71 canvas->save();
72 canvas->rotate(fRotation);
73 canvas->drawPath(refPath, refPaint);
74 canvas->restore();
75 SkPaint p;
76 p.setAntiAlias(true);
77 p.setStyle(SkPaint::kStroke_Style);
78 p.setStrokeWidth(10);
79 SkScalar intervals[4];
80 int intervalCount = dashExample.length;
81 SkScalar dashLength = circumference / wedge / dashUnits;
82 for (int index = 0; index < dashExample.length; ++index) {
83 intervals[index] = dashExample.pattern[index] * dashLength;
84 }
85 p.setPathEffect(SkDashPathEffect::Make(intervals, intervalCount, 0));
86 canvas->save();
87 canvas->rotate(fRotation);
88 canvas->drawPath(circle, p);
89 canvas->restore();
90 canvas->translate(0, radius * 2 + 50);
caryclarkb6474dd2016-01-19 08:07:49 -080091 }
robertphillips651bb5f2016-04-08 13:35:14 -070092 canvas->restore();
93 canvas->translate(radius * 2 + 50, 0);
caryclarkb6474dd2016-01-19 08:07:49 -080094 }
caryclarkb6474dd2016-01-19 08:07:49 -080095 }
robertphillips651bb5f2016-04-08 13:35:14 -070096
97 bool onAnimate(const SkAnimTimer& timer) override {
mtkleindbfd7ab2016-09-01 11:24:54 -070098 constexpr SkScalar kDesiredDurationSecs = 100.0f;
robertphillips651bb5f2016-04-08 13:35:14 -070099
100 fRotation = timer.scaled(360.0f/kDesiredDurationSecs, 360.0f);
101 return true;
102 }
103
104private:
105 SkScalar fRotation;
106
107 typedef GM INHERITED;
108};
109
110DEF_GM(return new DashCircleGM; )
Brian Salomon62e4f3d2018-04-20 13:54:11 -0400111
112class DashCircle2GM : public skiagm::GM {
113public:
114 DashCircle2GM() {}
115
116protected:
117 SkString onShortName() override { return SkString("dashcircle2"); }
118
119 SkISize onISize() override { return SkISize::Make(635, 900); }
120
121 void onDraw(SkCanvas* canvas) override {
122 // These intervals are defined relative to tau.
123 static constexpr SkScalar kIntervals[][2]{
124 {0.333f, 0.333f},
125 {0.015f, 0.015f},
126 {0.01f , 0.09f },
127 {0.097f, 0.003f},
128 {0.02f , 0.04f },
129 {0.1f , 0.2f },
130 {0.25f , 0.25f },
131 {0.6f , 0.7f }, // adds to > 1
132 {1.2f , 0.8f }, // on is > 1
133 {0.1f , 1.1f }, // off is > 1*/
134 };
135
136 static constexpr int kN = SK_ARRAY_COUNT(kIntervals);
137 static constexpr SkScalar kRadius = 20.f;
138 static constexpr SkScalar kStrokeWidth = 15.f;
139 static constexpr SkScalar kPad = 5.f;
140 static constexpr SkRect kCircle = {-kRadius, -kRadius, kRadius, kRadius};
141
142 static constexpr SkScalar kThinRadius = kRadius * 1.5;
143 static constexpr SkRect kThinCircle = {-kThinRadius, -kThinRadius,
144 kThinRadius, kThinRadius};
145 static constexpr SkScalar kThinStrokeWidth = 0.4f;
146
147 sk_sp<SkPathEffect> deffects[SK_ARRAY_COUNT(kIntervals)];
148 sk_sp<SkPathEffect> thinDEffects[SK_ARRAY_COUNT(kIntervals)];
149 for (int i = 0; i < kN; ++i) {
150 static constexpr SkScalar kTau = 2 * SK_ScalarPI;
151 static constexpr SkScalar kCircumference = kRadius * kTau;
152 SkScalar scaledIntervals[2] = {kCircumference * kIntervals[i][0],
153 kCircumference * kIntervals[i][1]};
154 deffects[i] = SkDashPathEffect::Make(
155 scaledIntervals, 2, kCircumference * fPhaseDegrees * kTau / 360.f);
156 static constexpr SkScalar kThinCircumference = kThinRadius * kTau;
157 scaledIntervals[0] = kThinCircumference * kIntervals[i][0];
158 scaledIntervals[1] = kThinCircumference * kIntervals[i][1];
159 thinDEffects[i] = SkDashPathEffect::Make(
160 scaledIntervals, 2, kThinCircumference * fPhaseDegrees * kTau / 360.f);
161 }
162
163 SkMatrix rotate;
164 rotate.setRotate(25.f);
165 static const SkMatrix kMatrices[]{
166 SkMatrix::I(),
167 SkMatrix::MakeScale(1.2f),
168 SkMatrix::MakeAll(1, 0, 0, 0, -1, 0, 0, 0, 1), // y flipper
169 SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1), // x flipper
170 SkMatrix::MakeScale(0.7f),
171 rotate,
172 SkMatrix::Concat(
173 SkMatrix::Concat(SkMatrix::MakeAll(-1, 0, 0, 0, 1, 0, 0, 0, 1), rotate),
174 rotate)
175 };
176
177 SkPaint paint;
178 paint.setAntiAlias(true);
179 paint.setStrokeWidth(kStrokeWidth);
180 paint.setStyle(SkPaint::kStroke_Style);
181
182 // Compute the union of bounds of all of our test cases.
183 SkRect bounds = SkRect::MakeEmpty();
184 static const SkRect kBounds = kThinCircle.makeOutset(kThinStrokeWidth / 2.f,
185 kThinStrokeWidth / 2.f);
186 for (const auto& m : kMatrices) {
187 SkRect devBounds;
188 m.mapRect(&devBounds, kBounds);
189 bounds.join(devBounds);
190 }
191
192 canvas->save();
193 canvas->translate(-bounds.fLeft + kPad, -bounds.fTop + kPad);
194 for (size_t i = 0; i < SK_ARRAY_COUNT(deffects); ++i) {
195 canvas->save();
196 for (const auto& m : kMatrices) {
197 canvas->save();
198 canvas->concat(m);
199
200 paint.setPathEffect(deffects[i]);
201 paint.setStrokeWidth(kStrokeWidth);
202 canvas->drawOval(kCircle, paint);
203
204 paint.setPathEffect(thinDEffects[i]);
205 paint.setStrokeWidth(kThinStrokeWidth);
206 canvas->drawOval(kThinCircle, paint);
207
208 canvas->restore();
209 canvas->translate(bounds.width() + kPad, 0);
210 }
211 canvas->restore();
212 canvas->translate(0, bounds.height() + kPad);
213 }
214 canvas->restore();
215 }
216
217protected:
218 bool onAnimate(const SkAnimTimer& timer) override {
219 fPhaseDegrees = timer.secs();
220 return true;
221 }
222
223 // Init with a non-zero phase for when run as a non-animating GM.
224 SkScalar fPhaseDegrees = 12.f;
225};
226
227DEF_GM(return new DashCircle2GM;)