1 /*
2 * Copyright 2015 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/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkMatrix.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkPath.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkScalar.h"
21 #include "include/core/SkShader.h"
22 #include "include/core/SkSize.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkSurface.h"
25 #include "include/core/SkTileMode.h"
26 #include "include/core/SkTypes.h"
27 #include "include/effects/SkGradientShader.h"
28 #include "tools/DecodeUtils.h"
29 #include "tools/ToolUtils.h"
30
make_image(SkCanvas * origCanvas,int w,int h)31 static sk_sp<SkImage> make_image(SkCanvas* origCanvas, int w, int h) {
32 SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
33 auto surface(ToolUtils::makeSurface(origCanvas, info));
34 SkCanvas* canvas = surface->getCanvas();
35
36 ToolUtils::draw_checkerboard(canvas, SK_ColorRED, SK_ColorGREEN, w / 10);
37 return surface->makeImageSnapshot();
38 }
39
40 namespace skiagm {
41
42 class PerspShadersGM : public GM {
43 public:
PerspShadersGM(bool doAA)44 PerspShadersGM(bool doAA) : fDoAA(doAA) { }
45
46 protected:
getName() const47 SkString getName() const override {
48 SkString name;
49 name.printf("persp_shaders_%s",
50 fDoAA ? "aa" : "bw");
51 return name;
52 }
53
getISize()54 SkISize getISize() override {
55 return SkISize::Make(kCellSize*kNumCols, kCellSize*kNumRows);
56 }
57
onOnceBeforeDraw()58 void onOnceBeforeDraw() override {
59 fBitmapImage = ToolUtils::create_checkerboard_image(
60 kCellSize, kCellSize, SK_ColorBLUE, SK_ColorYELLOW, kCellSize / 10);
61
62 SkPoint pts1[] = {
63 { 0, 0 },
64 { SkIntToScalar(kCellSize), SkIntToScalar(kCellSize) }
65 };
66 SkPoint pts2[] = {
67 { 0, 0 },
68 { 0, SkIntToScalar(kCellSize) }
69 };
70 constexpr SkColor colors[] = {
71 SK_ColorRED, SK_ColorGREEN, SK_ColorRED, SK_ColorGREEN, SK_ColorRED
72 };
73 constexpr SkScalar pos[] = { 0, 0.25f, 0.5f, 0.75f, SK_Scalar1 };
74
75 fLinearGrad1 = SkGradientShader::MakeLinear(pts1, colors, pos, std::size(colors),
76 SkTileMode::kClamp);
77 fLinearGrad2 = SkGradientShader::MakeLinear(pts2, colors, pos, std::size(colors),
78 SkTileMode::kClamp);
79
80 fPerspMatrix.reset();
81 fPerspMatrix.setPerspY(SK_Scalar1 / 50);
82
83 fPath.moveTo(0, 0);
84 fPath.lineTo(0, SkIntToScalar(kCellSize));
85 fPath.lineTo(kCellSize/2.0f, kCellSize/2.0f);
86 fPath.lineTo(SkIntToScalar(kCellSize), SkIntToScalar(kCellSize));
87 fPath.lineTo(SkIntToScalar(kCellSize), 0);
88 fPath.close();
89 }
90
drawRow(SkCanvas * canvas,const SkSamplingOptions & sampling)91 void drawRow(SkCanvas* canvas, const SkSamplingOptions& sampling) {
92 SkPaint filterPaint;
93 filterPaint.setAntiAlias(fDoAA);
94
95 SkPaint pathPaint;
96 pathPaint.setShader(fBitmapImage->makeShader(sampling));
97 pathPaint.setAntiAlias(fDoAA);
98
99 SkPaint gradPaint1;
100 gradPaint1.setShader(fLinearGrad1);
101 gradPaint1.setAntiAlias(fDoAA);
102 SkPaint gradPaint2;
103 gradPaint2.setShader(fLinearGrad2);
104 gradPaint2.setAntiAlias(fDoAA);
105
106 SkRect r = SkRect::MakeWH(SkIntToScalar(kCellSize), SkIntToScalar(kCellSize));
107
108 canvas->save();
109
110 canvas->save();
111 canvas->concat(fPerspMatrix);
112 canvas->drawImageRect(fBitmapImage, r, sampling, &filterPaint);
113 canvas->restore();
114
115 canvas->translate(SkIntToScalar(kCellSize), 0);
116 canvas->save();
117 canvas->concat(fPerspMatrix);
118 canvas->drawImage(fImage.get(), 0, 0, sampling, &filterPaint);
119 canvas->restore();
120
121 canvas->translate(SkIntToScalar(kCellSize), 0);
122 canvas->save();
123 canvas->concat(fPerspMatrix);
124 canvas->drawRect(r, pathPaint);
125 canvas->restore();
126
127 canvas->translate(SkIntToScalar(kCellSize), 0);
128 canvas->save();
129 canvas->concat(fPerspMatrix);
130 canvas->drawPath(fPath, pathPaint);
131 canvas->restore();
132
133 canvas->translate(SkIntToScalar(kCellSize), 0);
134 canvas->save();
135 canvas->concat(fPerspMatrix);
136 canvas->drawRect(r, gradPaint1);
137 canvas->restore();
138
139 canvas->translate(SkIntToScalar(kCellSize), 0);
140 canvas->save();
141 canvas->concat(fPerspMatrix);
142 canvas->drawPath(fPath, gradPaint2);
143 canvas->restore();
144
145 canvas->restore();
146 }
147
onDraw(SkCanvas * canvas)148 void onDraw(SkCanvas* canvas) override {
149 if (!fImage || !fImage->isValid(canvas->recordingContext())) {
150 fImage = make_image(canvas, kCellSize, kCellSize);
151 }
152
153 this->drawRow(canvas, SkSamplingOptions(SkFilterMode::kNearest));
154 canvas->translate(0, SkIntToScalar(kCellSize));
155 this->drawRow(canvas, SkSamplingOptions(SkFilterMode::kLinear));
156 canvas->translate(0, SkIntToScalar(kCellSize));
157 this->drawRow(canvas, SkSamplingOptions(SkFilterMode::kLinear,
158 SkMipmapMode::kNearest));
159 canvas->translate(0, SkIntToScalar(kCellSize));
160 this->drawRow(canvas, SkSamplingOptions(SkCubicResampler::Mitchell()));
161 canvas->translate(0, SkIntToScalar(kCellSize));
162 this->drawRow(canvas, SkSamplingOptions::Aniso(16));
163 canvas->translate(0, SkIntToScalar(kCellSize));
164 }
165 private:
166 inline static constexpr int kCellSize = 50;
167 inline static constexpr int kNumRows = 5;
168 inline static constexpr int kNumCols = 6;
169
170 bool fDoAA;
171 SkPath fPath;
172 sk_sp<SkShader> fLinearGrad1;
173 sk_sp<SkShader> fLinearGrad2;
174 SkMatrix fPerspMatrix;
175 sk_sp<SkImage> fImage;
176 sk_sp<SkImage> fBitmapImage;
177
178 using INHERITED = GM;
179 };
180 DEF_GM(return new PerspShadersGM(true);)
181 DEF_GM(return new PerspShadersGM(false);)
182 } // namespace skiagm
183
184 //////////////////////////////////////////////////////////////////////////////
185
186 #include "tools/Resources.h"
187
make_path()188 static SkPath make_path() {
189 SkRandom rand;
190 auto rand_pt = [&rand]() {
191 auto x = rand.nextF();
192 auto y = rand.nextF();
193 return SkPoint{x * 400, y * 400};
194 };
195
196 SkPath path;
197 for (int i = 0; i < 4; ++i) {
198 SkPoint pts[6];
199 for (auto& p : pts) {
200 p = rand_pt();
201 }
202 path.moveTo(pts[0]).quadTo(pts[1], pts[2]).quadTo(pts[3], pts[4]).lineTo(pts[5]);
203 }
204 return path;
205 }
206
207 DEF_SIMPLE_GM(perspective_clip, canvas, 800, 800) {
208 SkPath path = make_path();
209 auto shader = ToolUtils::GetResourceAsImage("images/mandrill_128.png")
210 ->makeShader(SkSamplingOptions(), SkMatrix::Scale(3, 3));
211
212 SkPaint paint;
213 paint.setColor({0.75, 0.75, 0.75, 1});
214 canvas->drawPath(path, paint);
215
216 // This is a crazy perspective matrix, derived from halfplanes3, to draw a shape where
217 // part of it is "behind" the viewer, hence showing the need for "half-plane" clipping
218 // when in perspective.
219 SkMatrix mx;
220 const SkScalar array[] = {
221 -1.7866f, 1.3357f, 273.0295f,
222 -1.0820f, 1.3186f, 135.5196f,
223 -0.0047f, -0.0015f, 2.1485f,
224 };
225 mx.set9(array);
226
227 paint.setShader(shader);
228 canvas->concat(mx);
229 canvas->drawPath(path, paint);
230 }
231