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