blob: f6aaa88379867a42683871636fe19e792bdadd7a [file] [log] [blame]
Michael Ludwig69858532018-11-28 15:34:34 -05001/*
2 * Copyright 2018 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
10#include "GrClip.h"
11#include "GrContext.h"
12#include "GrRenderTargetContext.h"
13#include "GrSurfaceContextPriv.h"
14#include "SkGr.h"
15#include "SkGradientShader.h"
16
17static constexpr SkScalar kTileWidth = 40;
18static constexpr SkScalar kTileHeight = 30;
19
20static constexpr int kRowCount = 4;
21static constexpr int kColCount = 3;
22
23static void draw_text(SkCanvas* canvas, const char* text) {
Hal Canary6ac0df82019-01-07 16:01:22 -050024 canvas->drawString(text, 0, 0, SkFont(nullptr, 12), SkPaint());
Michael Ludwig69858532018-11-28 15:34:34 -050025}
26
27static void draw_gradient_tiles(GrRenderTargetContext* rtc, const SkMatrix& view,
28 bool adjustLocal) {
29 GrRenderTargetContext::QuadSetEntry quads[kRowCount * kColCount];
30
31 for (int i = 0; i < kRowCount; ++i) {
32 for (int j = 0; j < kColCount; ++j) {
33 SkRect tile = SkRect::MakeXYWH(j * kTileWidth, i * kTileHeight, kTileWidth, kTileHeight);
34
35 int q = i * kColCount + j;
36 quads[q].fRect = tile;
37 quads[q].fColor = {1.f, 1.f, 1.f, 1.f};
38
39 if (adjustLocal) {
40 quads[q].fLocalMatrix.setTranslate(-tile.fLeft, -tile.fTop);
41 } else {
42 quads[q].fLocalMatrix.setIdentity();
43 }
44
45 quads[q].fAAFlags = GrQuadAAFlags::kNone;
46 if (i == 0) {
47 quads[q].fAAFlags |= GrQuadAAFlags::kTop;
48 }
49 if (i == kRowCount - 1) {
50 quads[q].fAAFlags |= GrQuadAAFlags::kBottom;
51 }
52 if (j == 0) {
53 quads[q].fAAFlags |= GrQuadAAFlags::kLeft;
54 }
55 if (j == kColCount - 1) {
56 quads[q].fAAFlags |= GrQuadAAFlags::kRight;
57 }
58 }
59 }
60
61 // Make a shared gradient paint
62 static constexpr SkPoint pts[] = { {0.f, 0.f}, {0.25f * kTileWidth, 0.25f * kTileHeight} };
63 static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorWHITE };
64
65 auto gradient = SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
66 SkPaint paint;
67 paint.setShader(gradient);
68 GrPaint grPaint;
69 SkPaintToGrPaint(rtc->surfPriv().getContext(), rtc->colorSpaceInfo(), paint, view, &grPaint);
70 // And use private API to use GrFillRectOp
71 rtc->drawQuadSet(GrNoClip(), std::move(grPaint), GrAA::kYes, view, quads, SK_ARRAY_COUNT(quads));
72}
73
74static void draw_color_tiles(GrRenderTargetContext* rtc, const SkMatrix& view, bool multicolor) {
75 GrRenderTargetContext::QuadSetEntry quads[kRowCount * kColCount];
76
77 for (int i = 0; i < kRowCount; ++i) {
78 for (int j = 0; j < kColCount; ++j) {
79 SkRect tile = SkRect::MakeXYWH(j * kTileWidth, i * kTileHeight, kTileWidth, kTileHeight);
80
81 int q = i * kColCount + j;
82 quads[q].fRect = tile;
83 quads[q].fLocalMatrix.setIdentity();
84
85 if (multicolor) {
86 quads[q].fColor = {(i + 1.f) / kRowCount, (j + 1.f) / kColCount, .4f, 1.f};
87 } else {
88 quads[q].fColor = {.2f, .8f, .3f, 1.f};
89 }
90
91 quads[q].fAAFlags = GrQuadAAFlags::kNone;
92 if (i == 0) {
93 quads[q].fAAFlags |= GrQuadAAFlags::kTop;
94 }
95 if (i == kRowCount - 1) {
96 quads[q].fAAFlags |= GrQuadAAFlags::kBottom;
97 }
98 if (j == 0) {
99 quads[q].fAAFlags |= GrQuadAAFlags::kLeft;
100 }
101 if (j == kColCount - 1) {
102 quads[q].fAAFlags |= GrQuadAAFlags::kRight;
103 }
104 }
105 }
106
107 GrPaint grPaint;
108 // And use private API to use GrFillRectOp
109 rtc->drawQuadSet(GrNoClip(), std::move(grPaint), GrAA::kYes, view, quads, SK_ARRAY_COUNT(quads));
110}
111
112static void draw_tile_boundaries(SkCanvas* canvas, const SkMatrix& local) {
113 // Draw grid of red lines at interior tile boundaries.
114 static constexpr SkScalar kLineOutset = 10.f;
115 SkPaint paint;
116 paint.setAntiAlias(true);
117 paint.setColor(SK_ColorRED);
118 paint.setStyle(SkPaint::kStroke_Style);
119 paint.setStrokeWidth(0.f);
120 for (int x = 1; x < kColCount; ++x) {
121 SkPoint pts[] = {{x * kTileWidth, 0}, {x * kTileWidth, kRowCount * kTileHeight}};
122 local.mapPoints(pts, 2);
123 SkVector v = pts[1] - pts[0];
124 v.setLength(v.length() + kLineOutset);
125 canvas->drawLine(pts[1] - v, pts[0] + v, paint);
126 }
127 for (int y = 1; y < kRowCount; ++y) {
128 SkPoint pts[] = {{0, y * kTileHeight}, {kTileWidth * kColCount, y * kTileHeight}};
129 local.mapPoints(pts, 2);
130 SkVector v = pts[1] - pts[0];
131 v.setLength(v.length() + kLineOutset);
132 canvas->drawLine(pts[1] - v, pts[0] + v, paint);
133 }
134}
135
136// Tile renderers (column variation)
137typedef void (*TileRenderer)(GrRenderTargetContext*, const SkMatrix&);
138static TileRenderer kTileSets[] = {
139 [](GrRenderTargetContext* rtc, const SkMatrix& view) { draw_gradient_tiles(rtc, view, true); },
140 [](GrRenderTargetContext* rtc, const SkMatrix& view) { draw_gradient_tiles(rtc, view, false); },
141 [](GrRenderTargetContext* rtc, const SkMatrix& view) { draw_color_tiles(rtc, view, false); },
142 [](GrRenderTargetContext* rtc, const SkMatrix& view) { draw_color_tiles(rtc, view, true); },
143};
144static const char* kTileSetNames[] = { "Local", "Aligned", "Green", "Multicolor" };
145static_assert(SK_ARRAY_COUNT(kTileSets) == SK_ARRAY_COUNT(kTileSetNames), "Count mismatch");
146
147namespace skiagm {
148
149class DrawQuadSetGM : public GM {
150private:
151 SkString onShortName() final { return SkString("draw_quad_set"); }
152 SkISize onISize() override { return SkISize::Make(800, 800); }
153
154 void onDraw(SkCanvas* canvas) override {
155 GrContext* ctx = canvas->getGrContext();
156 if (!ctx) {
157 DrawGpuOnlyMessage(canvas);
158 return;
159 }
160 GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
161 SkASSERT(rtc);
162
163 SkMatrix rowMatrices[5];
164 // Identity
165 rowMatrices[0].setIdentity();
166 // Translate/scale
167 rowMatrices[1].setTranslate(5.5f, 20.25f);
168 rowMatrices[1].postScale(.9f, .7f);
169 // Rotation
170 rowMatrices[2].setRotate(20.0f);
171 rowMatrices[2].preTranslate(15.f, -20.f);
172 // Skew
173 rowMatrices[3].setSkew(.5f, .25f);
174 rowMatrices[3].preTranslate(-30.f, 0.f);
175 // Perspective
176 SkPoint src[4];
177 SkRect::MakeWH(kColCount * kTileWidth, kRowCount * kTileHeight).toQuad(src);
178 SkPoint dst[4] = {{0, 0},
179 {kColCount * kTileWidth + 10.f, 15.f},
180 {kColCount * kTileWidth - 28.f, kRowCount * kTileHeight + 40.f},
181 {25.f, kRowCount * kTileHeight - 15.f}};
182 SkAssertResult(rowMatrices[4].setPolyToPoly(src, dst, 4));
183 rowMatrices[4].preTranslate(0.f, +10.f);
184 static const char* matrixNames[] = { "Identity", "T+S", "Rotate", "Skew", "Perspective" };
185 static_assert(SK_ARRAY_COUNT(matrixNames) == SK_ARRAY_COUNT(rowMatrices), "Count mismatch");
186
187 // Print a column header
188 canvas->save();
189 canvas->translate(110.f, 20.f);
190 for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSetNames); ++j) {
191 draw_text(canvas, kTileSetNames[j]);
192 canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
193 }
194 canvas->restore();
195 canvas->translate(0.f, 40.f);
196
197 // Render all tile variations
198 for (size_t i = 0; i < SK_ARRAY_COUNT(rowMatrices); ++i) {
199 canvas->save();
200 canvas->translate(10.f, 0.5f * kRowCount * kTileHeight);
201 draw_text(canvas, matrixNames[i]);
202
203 canvas->translate(100.f, -0.5f * kRowCount * kTileHeight);
204 for (size_t j = 0; j < SK_ARRAY_COUNT(kTileSets); ++j) {
205 canvas->save();
206 draw_tile_boundaries(canvas, rowMatrices[i]);
207
208 canvas->concat(rowMatrices[i]);
209 kTileSets[j](rtc, canvas->getTotalMatrix());
210 // Undo the local transformation
211 canvas->restore();
212 // And advance to the next column
213 canvas->translate(kColCount * kTileWidth + 30.f, 0.f);
214 }
215 // Reset back to the left edge
216 canvas->restore();
217 // And advance to the next row
218 canvas->translate(0.f, kRowCount * kTileHeight + 20.f);
219 }
220 }
221};
222
223DEF_GM(return new DrawQuadSetGM();)
224
225} // namespace skiagm