1 /* 2 * Copyright 2013 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 "SkCanvas.h" 10 #include "SkColorFilter.h" 11 #include "SkGradientShader.h" 12 #include "SkLocalMatrixShader.h" 13 #include "SkRandom.h" 14 #include "SkVertices.h" 15 16 static constexpr SkScalar kShaderSize = 40; 17 static sk_sp<SkShader> make_shader1(SkScalar shaderScale) { 18 const SkColor colors[] = { 19 SK_ColorRED, SK_ColorCYAN, SK_ColorGREEN, SK_ColorWHITE, 20 SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorYELLOW, 21 }; 22 const SkPoint pts[] = {{kShaderSize / 4, 0}, {3 * kShaderSize / 4, kShaderSize}}; 23 const SkMatrix localMatrix = SkMatrix::MakeScale(shaderScale, shaderScale); 24 25 sk_sp<SkShader> grad = SkGradientShader::MakeLinear(pts, colors, nullptr, 26 SK_ARRAY_COUNT(colors), 27 SkShader::kMirror_TileMode, 0, 28 &localMatrix); 29 // Throw in a couple of local matrix wrappers for good measure. 30 return shaderScale == 1 31 ? grad 32 : sk_make_sp<SkLocalMatrixShader>( 33 sk_make_sp<SkLocalMatrixShader>(std::move(grad), SkMatrix::MakeTrans(-10, 0)), 34 SkMatrix::MakeTrans(10, 0)); 35 } 36 37 static sk_sp<SkShader> make_shader2() { 38 return SkShader::MakeColorShader(SK_ColorBLUE); 39 } 40 41 static sk_sp<SkColorFilter> make_color_filter() { 42 return SkColorFilter::MakeModeFilter(0xFFAABBCC, SkBlendMode::kDarken); 43 } 44 45 static constexpr SkScalar kMeshSize = 30; 46 47 // start with the center of a 3x3 grid of vertices. 48 static constexpr uint16_t kMeshFan[] = { 49 4, 50 0, 1, 2, 5, 8, 7, 6, 3, 0 51 }; 52 53 static const int kMeshIndexCnt = (int)SK_ARRAY_COUNT(kMeshFan); 54 static const int kMeshVertexCnt = 9; 55 56 static void fill_mesh(SkPoint pts[kMeshVertexCnt], SkPoint texs[kMeshVertexCnt], 57 SkColor colors[kMeshVertexCnt], SkScalar shaderScale) { 58 pts[0].set(0, 0); 59 pts[1].set(kMeshSize / 2, 3); 60 pts[2].set(kMeshSize, 0); 61 pts[3].set(3, kMeshSize / 2); 62 pts[4].set(kMeshSize / 2, kMeshSize / 2); 63 pts[5].set(kMeshSize - 3, kMeshSize / 2); 64 pts[6].set(0, kMeshSize); 65 pts[7].set(kMeshSize / 2, kMeshSize - 3); 66 pts[8].set(kMeshSize, kMeshSize); 67 68 const auto shaderSize = kShaderSize * shaderScale; 69 texs[0].set(0, 0); 70 texs[1].set(shaderSize / 2, 0); 71 texs[2].set(shaderSize, 0); 72 texs[3].set(0, shaderSize / 2); 73 texs[4].set(shaderSize / 2, shaderSize / 2); 74 texs[5].set(shaderSize, shaderSize / 2); 75 texs[6].set(0, shaderSize); 76 texs[7].set(shaderSize / 2, shaderSize); 77 texs[8].set(shaderSize, shaderSize); 78 79 SkRandom rand; 80 for (size_t i = 0; i < kMeshVertexCnt; ++i) { 81 colors[i] = rand.nextU() | 0xFF000000; 82 } 83 } 84 85 class VerticesGM : public skiagm::GM { 86 SkPoint fPts[kMeshVertexCnt]; 87 SkPoint fTexs[kMeshVertexCnt]; 88 SkColor fColors[kMeshVertexCnt]; 89 sk_sp<SkShader> fShader1; 90 sk_sp<SkShader> fShader2; 91 sk_sp<SkColorFilter> fColorFilter; 92 SkScalar fShaderScale; 93 94 public: 95 VerticesGM(SkScalar shaderScale) : fShaderScale(shaderScale) {} 96 97 protected: 98 99 void onOnceBeforeDraw() override { 100 fill_mesh(fPts, fTexs, fColors, fShaderScale); 101 fShader1 = make_shader1(fShaderScale); 102 fShader2 = make_shader2(); 103 fColorFilter = make_color_filter(); 104 } 105 106 SkString onShortName() override { 107 SkString name("vertices"); 108 if (fShaderScale != 1) { 109 name.append("_scaled_shader"); 110 } 111 return name; 112 } 113 114 SkISize onISize() override { 115 return SkISize::Make(975, 1175); 116 } 117 118 void onDraw(SkCanvas* canvas) override { 119 const SkBlendMode modes[] = { 120 SkBlendMode::kClear, 121 SkBlendMode::kSrc, 122 SkBlendMode::kDst, 123 SkBlendMode::kSrcOver, 124 SkBlendMode::kDstOver, 125 SkBlendMode::kSrcIn, 126 SkBlendMode::kDstIn, 127 SkBlendMode::kSrcOut, 128 SkBlendMode::kDstOut, 129 SkBlendMode::kSrcATop, 130 SkBlendMode::kDstATop, 131 SkBlendMode::kXor, 132 SkBlendMode::kPlus, 133 SkBlendMode::kModulate, 134 SkBlendMode::kScreen, 135 SkBlendMode::kOverlay, 136 SkBlendMode::kDarken, 137 SkBlendMode::kLighten, 138 SkBlendMode::kColorDodge, 139 SkBlendMode::kColorBurn, 140 SkBlendMode::kHardLight, 141 SkBlendMode::kSoftLight, 142 SkBlendMode::kDifference, 143 SkBlendMode::kExclusion, 144 SkBlendMode::kMultiply, 145 SkBlendMode::kHue, 146 SkBlendMode::kSaturation, 147 SkBlendMode::kColor, 148 SkBlendMode::kLuminosity, 149 }; 150 151 SkPaint paint; 152 153 canvas->translate(4, 4); 154 int x = 0; 155 for (auto mode : modes) { 156 canvas->save(); 157 for (float alpha : {1.0f, 0.5f}) { 158 for (const auto& cf : {sk_sp<SkColorFilter>(nullptr), fColorFilter}) { 159 for (const auto& shader : {fShader1, fShader2}) { 160 static constexpr struct { 161 bool fHasColors; 162 bool fHasTexs; 163 } kAttrs[] = {{true, false}, {false, true}, {true, true}}; 164 for (auto attrs : kAttrs) { 165 paint.setShader(shader); 166 paint.setColorFilter(cf); 167 paint.setAlphaf(alpha); 168 169 const SkColor* colors = attrs.fHasColors ? fColors : nullptr; 170 const SkPoint* texs = attrs.fHasTexs ? fTexs : nullptr; 171 auto v = SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 172 kMeshVertexCnt, fPts, texs, colors, 173 kMeshIndexCnt, kMeshFan); 174 canvas->drawVertices(v, mode, paint); 175 canvas->translate(40, 0); 176 ++x; 177 } 178 } 179 } 180 } 181 canvas->restore(); 182 canvas->translate(0, 40); 183 } 184 } 185 186 private: 187 typedef skiagm::GM INHERITED; 188 }; 189 190 ///////////////////////////////////////////////////////////////////////////////////// 191 192 DEF_GM(return new VerticesGM(1);) 193 DEF_GM(return new VerticesGM(1 / kShaderSize);) 194 195 static void draw_batching(SkCanvas* canvas) { 196 // Triangle fans can't batch so we convert to regular triangles, 197 static constexpr int kNumTris = kMeshIndexCnt - 2; 198 SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, kMeshVertexCnt, 3 * kNumTris, 199 SkVertices::kHasColors_BuilderFlag | 200 SkVertices::kHasTexCoords_BuilderFlag); 201 202 SkPoint* pts = builder.positions(); 203 SkPoint* texs = builder.texCoords(); 204 SkColor* colors = builder.colors(); 205 fill_mesh(pts, texs, colors, 1); 206 207 SkTDArray<SkMatrix> matrices; 208 matrices.push()->reset(); 209 matrices.push()->setTranslate(0, 40); 210 SkMatrix* m = matrices.push(); 211 m->setRotate(45, kMeshSize / 2, kMeshSize / 2); 212 m->postScale(1.2f, .8f, kMeshSize / 2, kMeshSize / 2); 213 m->postTranslate(0, 80); 214 215 auto shader = make_shader1(1); 216 217 uint16_t* indices = builder.indices(); 218 for (size_t i = 0; i < kNumTris; ++i) { 219 indices[3 * i] = kMeshFan[0]; 220 indices[3 * i + 1] = kMeshFan[i + 1]; 221 indices[3 * i + 2] = kMeshFan[i + 2]; 222 223 } 224 225 canvas->save(); 226 canvas->translate(10, 10); 227 for (bool useShader : {false, true}) { 228 for (bool useTex : {false, true}) { 229 for (const auto& m : matrices) { 230 canvas->save(); 231 canvas->concat(m); 232 SkPaint paint; 233 paint.setShader(useShader ? shader : nullptr); 234 235 const SkPoint* t = useTex ? texs : nullptr; 236 auto v = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, kMeshVertexCnt, 237 pts, t, colors, kNumTris * 3, indices); 238 canvas->drawVertices(v, SkBlendMode::kModulate, paint); 239 canvas->restore(); 240 } 241 canvas->translate(0, 120); 242 } 243 } 244 canvas->restore(); 245 } 246 247 // This test exists to exercise batching in the gpu backend. 248 DEF_SIMPLE_GM(vertices_batching, canvas, 100, 500) { 249 draw_batching(canvas); 250 canvas->translate(50, 0); 251 draw_batching(canvas); 252 } 253