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 "SkBlurMaskFilter.h" 11 #include "SkDashPathEffect.h" 12 #include "SkGradientShader.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(SkBlurMaskFilter::Make(kOuter_SkBlurStyle, 3.0f, 167 SkBlurMaskFilter::kHighQuality_BlurFlag)); 168 fPaints.push_back(p); 169 } 170 171 // matrices 172 { 173 // rotation 174 SkMatrix m; 175 m.setRotate(12.0f); 176 177 fMatrices.push_back(m); 178 } 179 { 180 // skew 181 SkMatrix m; 182 m.setSkew(0.3f, 0.5f); 183 184 fMatrices.push_back(m); 185 } 186 { 187 // perspective 188 SkMatrix m; 189 m.reset(); 190 m.setPerspX(-SK_Scalar1 / 300); 191 m.setPerspY(SK_Scalar1 / 300); 192 193 fMatrices.push_back(m); 194 } 195 196 SkASSERT(kNumRows == fPaints.count() + fMatrices.count()); 197 } 198 199 void onDraw(SkCanvas* canvas) override { 200 canvas->translate(0, kRadius+kPad); 201 202 for (int i = 0; i < fPaints.count(); ++i) { 203 int saveCount = canvas->save(); 204 draw_row(canvas, fPaints[i], SkMatrix::I()); 205 canvas->restoreToCount(saveCount); 206 207 canvas->translate(0, 2*(kRadius+kPad)); 208 } 209 210 for (int i = 0; i < fMatrices.count(); ++i) { 211 int saveCount = canvas->save(); 212 draw_row(canvas, fPaints[0], fMatrices[i]); 213 canvas->restoreToCount(saveCount); 214 215 canvas->translate(0, 2*(kRadius+kPad)); 216 } 217 } 218 219 private: 220 SkTArray<SkPaint> fPaints; 221 SkTArray<SkMatrix> fMatrices; 222 223 typedef GM INHERITED; 224 }; 225 226 ////////////////////////////////////////////////////////////////////////////// 227 228 DEF_GM(return new StrokedLinesGM;) 229 } 230