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 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 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 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: 102 StrokedLinesGM() { 103 this->setBGColor(sk_tool_utils::color_to_565(0xFF1A65D7)); 104 } 105 106 protected: 107 SkString onShortName() override { 108 return SkString("strokedlines"); 109 } 110 111 SkISize onISize() override { 112 return SkISize::Make(kNumColumns * (2*kRadius+2*kPad), kNumRows * (2*kRadius+2*kPad)); 113 } 114 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 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