blob: dab1cd1966ac4a0a279ef5866554d9a352b83bf5 [file] [log] [blame]
Florin Malita325ea322018-04-04 14:17:30 -04001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Mike Reedac9f0c92020-12-23 10:11:33 -05009#include "include/core/SkBitmap.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040010#include "include/core/SkBlendMode.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040012#include "include/core/SkColor.h"
13#include "include/core/SkImage.h"
14#include "include/core/SkImageInfo.h"
15#include "include/core/SkMatrix.h"
16#include "include/core/SkPaint.h"
17#include "include/core/SkRect.h"
18#include "include/core/SkRefCnt.h"
19#include "include/core/SkScalar.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/core/SkShader.h"
21#include "include/core/SkSurface.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040022#include "include/core/SkTypes.h"
Michael Ludwig5c51f5f2020-06-02 12:55:10 -040023#include "include/effects/SkGradientShader.h"
24#include "tools/Resources.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "tools/ToolUtils.h"
Florin Malita325ea322018-04-04 14:17:30 -040026
27static sk_sp<SkImage> make_image(SkCanvas* rootCanvas) {
28 static constexpr SkScalar kSize = 50;
29 SkImageInfo info = SkImageInfo::MakeN32Premul(kSize, kSize);
Mike Kleinea3f0142019-03-20 11:12:10 -050030 auto surface = ToolUtils::makeSurface(rootCanvas, info);
Florin Malita325ea322018-04-04 14:17:30 -040031
32 SkPaint p;
33 p.setAntiAlias(true);
34 p.setColor(SK_ColorGREEN);
35
36 surface->getCanvas()->drawCircle(kSize / 2, kSize / 2, kSize / 2, p);
37
38 p.setStyle(SkPaint::kStroke_Style);
39 p.setColor(SK_ColorRED);
40 surface->getCanvas()->drawLine(kSize * .25f, kSize * .50f, kSize * .75f, kSize * .50f, p);
41 surface->getCanvas()->drawLine(kSize * .50f, kSize * .25f, kSize * .50f, kSize * .75f, p);
42
43 return surface->makeImageSnapshot();
44}
45
46DEF_SIMPLE_GM(localmatrixshader_nested, canvas, 450, 1200) {
47 auto image = make_image(canvas);
48
49 using FactoryT = sk_sp<SkShader> (*)(const sk_sp<SkImage>&,
50 const SkMatrix& inner,
51 const SkMatrix& outer);
52 static const FactoryT gFactories[] = {
53 // SkLocalMatrixShader(SkImageShader(inner), outer)
54 [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
Mike Reedb612b6c2020-12-08 21:58:35 -050055 return img->makeShader(SkSamplingOptions(), inner)->makeWithLocalMatrix(outer);
Florin Malita325ea322018-04-04 14:17:30 -040056 },
57
58 // SkLocalMatrixShader(SkLocalMatrixShader(SkImageShader(I), inner), outer)
59 [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
Mike Reedb612b6c2020-12-08 21:58:35 -050060 return img->makeShader(SkSamplingOptions())->makeWithLocalMatrix(inner)->makeWithLocalMatrix(outer);
Florin Malita325ea322018-04-04 14:17:30 -040061 },
62
63 // SkLocalMatrixShader(SkComposeShader(SkImageShader(inner)), outer)
64 [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
Mike Reedc8bea7d2019-04-09 13:55:36 -040065 return SkShaders::Blend(SkBlendMode::kSrcOver,
66 SkShaders::Color(SK_ColorTRANSPARENT),
Mike Reedb612b6c2020-12-08 21:58:35 -050067 img->makeShader(SkSamplingOptions(), inner))
Florin Malita325ea322018-04-04 14:17:30 -040068 ->makeWithLocalMatrix(outer);
69 },
70
71 // SkLocalMatrixShader(SkComposeShader(SkLocalMatrixShader(SkImageShader(I), inner)), outer)
72 [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
Mike Reedc8bea7d2019-04-09 13:55:36 -040073 return SkShaders::Blend(SkBlendMode::kSrcOver,
74 SkShaders::Color(SK_ColorTRANSPARENT),
Mike Reedb612b6c2020-12-08 21:58:35 -050075 img->makeShader(SkSamplingOptions())->makeWithLocalMatrix(inner))
Florin Malita325ea322018-04-04 14:17:30 -040076 ->makeWithLocalMatrix(outer);
77 },
78 };
79
Mike Reed1f607332020-05-21 12:11:27 -040080 static const auto inner = SkMatrix::Scale(2, 2),
81 outer = SkMatrix::Translate(20, 20);
Florin Malita325ea322018-04-04 14:17:30 -040082
83 SkPaint border;
84 border.setAntiAlias(true);
85 border.setStyle(SkPaint::kStroke_Style);
86
87 auto rect = SkRect::Make(image->bounds());
88 SkAssertResult(SkMatrix::Concat(inner, outer).mapRect(&rect));
89
90 const auto drawColumn = [&]() {
91 SkAutoCanvasRestore acr(canvas, true);
92 for (const auto& f : gFactories) {
93 SkPaint p;
94 p.setShader(f(image, inner, outer));
95
96 canvas->drawRect(rect, p);
97 canvas->drawRect(rect, border);
98
99 canvas->translate(0, rect.height() * 1.5f);
100 }
101 };
102
103 drawColumn();
104
105 {
106 SkAutoCanvasRestore acr(canvas, true);
107 canvas->translate(0, rect.height() * SK_ARRAY_COUNT(gFactories) * 1.5f);
108 drawColumn();
109 }
110
111 canvas->translate(rect.width() * 1.5f, 0);
112 canvas->scale(2, 2);
113 drawColumn();
114}
Michael Ludwig5c51f5f2020-06-02 12:55:10 -0400115
116DEF_SIMPLE_GM(localmatrixshader_persp, canvas, 542, 266) {
117 auto image = GetResourceAsImage("images/yellow_rose.png");
118
119 SkBitmap downsized;
120 downsized.allocPixels(image->imageInfo().makeWH(128, 128));
Mike Reed5ec22382021-01-14 21:59:01 -0500121 image->scalePixels(downsized.pixmap(), SkSamplingOptions(SkFilterMode::kLinear));
Mike Reedac9f0c92020-12-23 10:11:33 -0500122 image = downsized.asImage();
Michael Ludwig5c51f5f2020-06-02 12:55:10 -0400123 SkRect imgRect = SkRect::MakeIWH(image->width(), image->height());
124
125 // scale matrix
126 SkMatrix scale = SkMatrix::Scale(1.f / 5.f, 1.f / 5.f);
127
128 // perspective matrix
129 SkPoint src[4];
130 imgRect.toQuad(src);
131 SkPoint dst[4] = {{0, 10.f},
132 {image->width() + 28.f, -100.f},
133 {image->width() - 28.f, image->height() + 100.f},
134 {0.f, image->height() - 10.f}};
135 SkMatrix persp;
136 SkAssertResult(persp.setPolyToPoly(src, dst, 4));
137
138 // combined persp * scale
139 SkMatrix perspScale = SkMatrix::Concat(persp, scale);
140
141 auto draw = [&](sk_sp<SkShader> shader, bool applyPerspToCTM) {
142 canvas->save();
143 canvas->clipRect(imgRect);
144 if (applyPerspToCTM) {
145 canvas->concat(persp);
146 }
147 SkPaint imgShaderPaint;
148 imgShaderPaint.setShader(std::move(shader));
149 canvas->drawPaint(imgShaderPaint);
150 canvas->restore();
151
152 canvas->translate(10.f + image->width(), 0.f); // advance
153 };
154
155 // SkImageShader
156 canvas->save();
157 // 4 variants that all attempt to apply sample at persp * scale w/ an image shader
158 // 1. scale provided to SkImage::makeShader(...) but drawn with persp
Mike Reedb612b6c2020-12-08 21:58:35 -0500159 auto s1 = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
160 SkSamplingOptions(), &scale);
Michael Ludwig5c51f5f2020-06-02 12:55:10 -0400161 draw(s1, true);
162
163 // 2. persp provided to SkImage::makeShader, then wrapped in scale makeWithLocalMatrix
164 // These pre-concat, so it ends up as persp * scale.
Mike Reedb612b6c2020-12-08 21:58:35 -0500165 auto s2 = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
166 SkSamplingOptions(), &persp)
Michael Ludwig5c51f5f2020-06-02 12:55:10 -0400167 ->makeWithLocalMatrix(scale);
168 draw(s2, false);
169
170 // 3. Providing pre-computed persp*scale to SkImage::makeShader()
Mike Reedb612b6c2020-12-08 21:58:35 -0500171 auto s3 = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
172 SkSamplingOptions(), &perspScale);
Michael Ludwig5c51f5f2020-06-02 12:55:10 -0400173 draw(s3, false);
174
175 // 4. Providing pre-computed persp*scale to makeWithLocalMatrix
Mike Reedb612b6c2020-12-08 21:58:35 -0500176 auto s4 = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions())
Michael Ludwig5c51f5f2020-06-02 12:55:10 -0400177 ->makeWithLocalMatrix(perspScale);
178 draw(s4, false);
179 canvas->restore();
180
181 canvas->translate(0.f, 10.f + image->height()); // advance to next row
182
183 // SkGradientShader
184 const SkColor kGradColors[] = { SK_ColorBLACK, SK_ColorTRANSPARENT };
185 canvas->save();
186 // 1. scale provided to Make, drawn with persp
187 auto g1 = SkGradientShader::MakeRadial({imgRect.centerX(), imgRect.centerY()},
188 imgRect.width() / 2.f, kGradColors, nullptr, 2,
189 SkTileMode::kRepeat, 0, &scale);
190 draw(g1, true);
191
192 // 2. persp provided to Make, then wrapped with makeWithLocalMatrix (pre-concat as before).
193 auto g2 = SkGradientShader::MakeRadial({imgRect.centerX(), imgRect.centerY()},
194 imgRect.width() / 2.f, kGradColors, nullptr, 2,
195 SkTileMode::kRepeat, 0, &persp)
196 ->makeWithLocalMatrix(scale);
197 draw(g2, false);
198
199 // 3. Provide per-computed persp*scale to Make
200 auto g3 = SkGradientShader::MakeRadial({imgRect.centerX(), imgRect.centerY()},
201 imgRect.width() / 2.f, kGradColors, nullptr, 2,
202 SkTileMode::kRepeat, 0, &perspScale);
203 draw(g3, false);
204
205 // 4. Providing pre-computed persp*scale to makeWithLocalMatrix
206 auto g4 = SkGradientShader::MakeRadial({imgRect.centerX(), imgRect.centerY()},
207 imgRect.width() / 2.f, kGradColors, nullptr, 2,
208 SkTileMode::kRepeat)
209 ->makeWithLocalMatrix(perspScale);
210 draw(g4, false);
211 canvas->restore();
212}