xref: /aosp_15_r20/external/skia/tools/viewer/ClipSlide.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorPriv.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathBuilder.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathPriv.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "tools/DecodeUtils.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "tools/Resources.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "tools/viewer/ClickHandlerSlide.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "tools/viewer/Slide.h"
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker constexpr int W = 150;
24*c8dee2aaSAndroid Build Coastguard Worker constexpr int H = 200;
25*c8dee2aaSAndroid Build Coastguard Worker 
show_text(SkCanvas * canvas,bool doAA)26*c8dee2aaSAndroid Build Coastguard Worker static void show_text(SkCanvas* canvas, bool doAA) {
27*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
28*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
29*c8dee2aaSAndroid Build Coastguard Worker     SkFont font(ToolUtils::DefaultTypeface(), 20);
30*c8dee2aaSAndroid Build Coastguard Worker     font.setEdging(doAA ? SkFont::Edging::kSubpixelAntiAlias : SkFont::Edging::kAlias);
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 200; ++i) {
33*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor((SK_A32_MASK << SK_A32_SHIFT) | rand.nextU());
34*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawString("Hamburgefons", rand.nextSScalar1() * W, rand.nextSScalar1() * H + 20,
35*c8dee2aaSAndroid Build Coastguard Worker                            font, paint);
36*c8dee2aaSAndroid Build Coastguard Worker     }
37*c8dee2aaSAndroid Build Coastguard Worker }
38*c8dee2aaSAndroid Build Coastguard Worker 
show_fill(SkCanvas * canvas,bool doAA)39*c8dee2aaSAndroid Build Coastguard Worker static void show_fill(SkCanvas* canvas, bool doAA) {
40*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
41*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
42*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(doAA);
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 50; ++i) {
45*c8dee2aaSAndroid Build Coastguard Worker         SkRect r;
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker         r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
48*c8dee2aaSAndroid Build Coastguard Worker                   rand.nextUScalar1() * W, rand.nextUScalar1() * H);
49*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(rand.nextU());
50*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(r, paint);
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker         r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
53*c8dee2aaSAndroid Build Coastguard Worker                   rand.nextUScalar1() * W, rand.nextUScalar1() * H);
54*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(rand.nextU());
55*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawOval(r, paint);
56*c8dee2aaSAndroid Build Coastguard Worker     }
57*c8dee2aaSAndroid Build Coastguard Worker }
58*c8dee2aaSAndroid Build Coastguard Worker 
randRange(SkRandom & rand,SkScalar min,SkScalar max)59*c8dee2aaSAndroid Build Coastguard Worker static SkScalar randRange(SkRandom& rand, SkScalar min, SkScalar max) {
60*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(min <= max);
61*c8dee2aaSAndroid Build Coastguard Worker     return min + rand.nextUScalar1() * (max - min);
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker 
show_stroke(SkCanvas * canvas,bool doAA,SkScalar strokeWidth,int n)64*c8dee2aaSAndroid Build Coastguard Worker static void show_stroke(SkCanvas* canvas, bool doAA, SkScalar strokeWidth, int n) {
65*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
66*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
67*c8dee2aaSAndroid Build Coastguard Worker     paint.setAntiAlias(doAA);
68*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
69*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(strokeWidth);
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < n; ++i) {
72*c8dee2aaSAndroid Build Coastguard Worker         SkRect r;
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker         r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
75*c8dee2aaSAndroid Build Coastguard Worker                   rand.nextUScalar1() * W, rand.nextUScalar1() * H);
76*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(rand.nextU());
77*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(r, paint);
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker         r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
80*c8dee2aaSAndroid Build Coastguard Worker                   rand.nextUScalar1() * W, rand.nextUScalar1() * H);
81*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(rand.nextU());
82*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawOval(r, paint);
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker         const SkScalar minx = -SkIntToScalar(W)/4;
85*c8dee2aaSAndroid Build Coastguard Worker         const SkScalar maxx = 5*SkIntToScalar(W)/4;
86*c8dee2aaSAndroid Build Coastguard Worker         const SkScalar miny = -SkIntToScalar(H)/4;
87*c8dee2aaSAndroid Build Coastguard Worker         const SkScalar maxy = 5*SkIntToScalar(H)/4;
88*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(rand.nextU());
89*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawLine(randRange(rand, minx, maxx), randRange(rand, miny, maxy),
90*c8dee2aaSAndroid Build Coastguard Worker                          randRange(rand, minx, maxx), randRange(rand, miny, maxy),
91*c8dee2aaSAndroid Build Coastguard Worker                          paint);
92*c8dee2aaSAndroid Build Coastguard Worker     }
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker 
show_hair(SkCanvas * canvas,bool doAA)95*c8dee2aaSAndroid Build Coastguard Worker static void show_hair(SkCanvas* canvas, bool doAA) {
96*c8dee2aaSAndroid Build Coastguard Worker     show_stroke(canvas, doAA, 0, 150);
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker 
show_thick(SkCanvas * canvas,bool doAA)99*c8dee2aaSAndroid Build Coastguard Worker static void show_thick(SkCanvas* canvas, bool doAA) {
100*c8dee2aaSAndroid Build Coastguard Worker     show_stroke(canvas, doAA, SkIntToScalar(5), 50);
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker typedef void (*CanvasProc)(SkCanvas*, bool);
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker class ClipSlide : public Slide {
106*c8dee2aaSAndroid Build Coastguard Worker public:
ClipSlide()107*c8dee2aaSAndroid Build Coastguard Worker     ClipSlide() { fName = "Clip"; }
108*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas)109*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas) override {
110*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawColor(SK_ColorWHITE);
111*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker         static const CanvasProc gProc[] = {
114*c8dee2aaSAndroid Build Coastguard Worker             show_text, show_thick, show_hair, show_fill
115*c8dee2aaSAndroid Build Coastguard Worker         };
116*c8dee2aaSAndroid Build Coastguard Worker 
117*c8dee2aaSAndroid Build Coastguard Worker         SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
118*c8dee2aaSAndroid Build Coastguard Worker         r.inset(SK_Scalar1 / 4, SK_Scalar1 / 4);
119*c8dee2aaSAndroid Build Coastguard Worker         SkPath clipPath = SkPathBuilder().addRRect(SkRRect::MakeRectXY(r, 20, 20)).detach();
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker //        clipPath.toggleInverseFillType();
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker         for (int aa = 0; aa <= 1; ++aa) {
124*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
125*c8dee2aaSAndroid Build Coastguard Worker             for (size_t i = 0; i < std::size(gProc); ++i) {
126*c8dee2aaSAndroid Build Coastguard Worker                 canvas->save();
127*c8dee2aaSAndroid Build Coastguard Worker                 canvas->clipPath(clipPath, SkClipOp::kIntersect, SkToBool(aa));
128*c8dee2aaSAndroid Build Coastguard Worker //                canvas->drawColor(SK_ColorWHITE);
129*c8dee2aaSAndroid Build Coastguard Worker                 gProc[i](canvas, SkToBool(aa));
130*c8dee2aaSAndroid Build Coastguard Worker                 canvas->restore();
131*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(W * SK_Scalar1 * 8 / 7, 0);
132*c8dee2aaSAndroid Build Coastguard Worker             }
133*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
134*c8dee2aaSAndroid Build Coastguard Worker             canvas->translate(0, H * SK_Scalar1 * 8 / 7);
135*c8dee2aaSAndroid Build Coastguard Worker         }
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker };
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new ClipSlide(); )
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker struct SkHalfPlane {
144*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fA, fB, fC;
145*c8dee2aaSAndroid Build Coastguard Worker 
evalSkHalfPlane146*c8dee2aaSAndroid Build Coastguard Worker     SkScalar eval(SkScalar x, SkScalar y) const {
147*c8dee2aaSAndroid Build Coastguard Worker         return fA * x + fB * y + fC;
148*c8dee2aaSAndroid Build Coastguard Worker     }
operator ()SkHalfPlane149*c8dee2aaSAndroid Build Coastguard Worker     SkScalar operator()(SkScalar x, SkScalar y) const { return this->eval(x, y); }
150*c8dee2aaSAndroid Build Coastguard Worker 
twoPtsSkHalfPlane151*c8dee2aaSAndroid Build Coastguard Worker     bool twoPts(SkPoint pts[2]) const {
152*c8dee2aaSAndroid Build Coastguard Worker         // normalize plane to help with the perpendicular step, below
153*c8dee2aaSAndroid Build Coastguard Worker         SkScalar len = SkScalarSqrt(fA*fA + fB*fB);
154*c8dee2aaSAndroid Build Coastguard Worker         if (!len) {
155*c8dee2aaSAndroid Build Coastguard Worker             return false;
156*c8dee2aaSAndroid Build Coastguard Worker         }
157*c8dee2aaSAndroid Build Coastguard Worker         SkScalar denom = SkScalarInvert(len);
158*c8dee2aaSAndroid Build Coastguard Worker         SkScalar a = fA * denom;
159*c8dee2aaSAndroid Build Coastguard Worker         SkScalar b = fB * denom;
160*c8dee2aaSAndroid Build Coastguard Worker         SkScalar c = fC * denom;
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker         // We compute p0 on the half-plane by setting one of the components to 0
163*c8dee2aaSAndroid Build Coastguard Worker         // We compute p1 by stepping from p0 along a perpendicular to the normal
164*c8dee2aaSAndroid Build Coastguard Worker         if (b) {
165*c8dee2aaSAndroid Build Coastguard Worker             pts[0] = { 0, -c / b };
166*c8dee2aaSAndroid Build Coastguard Worker             pts[1] = { b, pts[0].fY - a};
167*c8dee2aaSAndroid Build Coastguard Worker         } else if (a) {
168*c8dee2aaSAndroid Build Coastguard Worker             pts[0] = { -c / a,        0 };
169*c8dee2aaSAndroid Build Coastguard Worker             pts[1] = { pts[0].fX + b, -a };
170*c8dee2aaSAndroid Build Coastguard Worker         } else {
171*c8dee2aaSAndroid Build Coastguard Worker             return false;
172*c8dee2aaSAndroid Build Coastguard Worker         }
173*c8dee2aaSAndroid Build Coastguard Worker 
174*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(SkScalarNearlyZero(this->operator()(pts[0].fX, pts[0].fY)));
175*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(SkScalarNearlyZero(this->operator()(pts[1].fX, pts[1].fY)));
176*c8dee2aaSAndroid Build Coastguard Worker         return true;
177*c8dee2aaSAndroid Build Coastguard Worker     }
178*c8dee2aaSAndroid Build Coastguard Worker 
179*c8dee2aaSAndroid Build Coastguard Worker     enum Result {
180*c8dee2aaSAndroid Build Coastguard Worker         kAllNegative,
181*c8dee2aaSAndroid Build Coastguard Worker         kAllPositive,
182*c8dee2aaSAndroid Build Coastguard Worker         kMixed
183*c8dee2aaSAndroid Build Coastguard Worker     };
testSkHalfPlane184*c8dee2aaSAndroid Build Coastguard Worker     Result test(const SkRect& bounds) const {
185*c8dee2aaSAndroid Build Coastguard Worker         SkPoint diagMin, diagMax;
186*c8dee2aaSAndroid Build Coastguard Worker         if (fA >= 0) {
187*c8dee2aaSAndroid Build Coastguard Worker             diagMin.fX = bounds.fLeft;
188*c8dee2aaSAndroid Build Coastguard Worker             diagMax.fX = bounds.fRight;
189*c8dee2aaSAndroid Build Coastguard Worker         } else {
190*c8dee2aaSAndroid Build Coastguard Worker             diagMin.fX = bounds.fRight;
191*c8dee2aaSAndroid Build Coastguard Worker             diagMax.fX = bounds.fLeft;
192*c8dee2aaSAndroid Build Coastguard Worker         }
193*c8dee2aaSAndroid Build Coastguard Worker         if (fB >= 0) {
194*c8dee2aaSAndroid Build Coastguard Worker             diagMin.fY = bounds.fTop;
195*c8dee2aaSAndroid Build Coastguard Worker             diagMax.fY = bounds.fBottom;
196*c8dee2aaSAndroid Build Coastguard Worker         } else {
197*c8dee2aaSAndroid Build Coastguard Worker             diagMin.fY = bounds.fBottom;
198*c8dee2aaSAndroid Build Coastguard Worker             diagMax.fY = bounds.fTop;
199*c8dee2aaSAndroid Build Coastguard Worker         }
200*c8dee2aaSAndroid Build Coastguard Worker         SkScalar test = this->eval(diagMin.fX, diagMin.fY);
201*c8dee2aaSAndroid Build Coastguard Worker         SkScalar sign = test*this->eval(diagMax.fX, diagMin.fY);
202*c8dee2aaSAndroid Build Coastguard Worker         if (sign > 0) {
203*c8dee2aaSAndroid Build Coastguard Worker             // the path is either all on one side of the half-plane or the other
204*c8dee2aaSAndroid Build Coastguard Worker             if (test < 0) {
205*c8dee2aaSAndroid Build Coastguard Worker                 return kAllNegative;
206*c8dee2aaSAndroid Build Coastguard Worker             } else {
207*c8dee2aaSAndroid Build Coastguard Worker                 return kAllPositive;
208*c8dee2aaSAndroid Build Coastguard Worker             }
209*c8dee2aaSAndroid Build Coastguard Worker         }
210*c8dee2aaSAndroid Build Coastguard Worker         return kMixed;
211*c8dee2aaSAndroid Build Coastguard Worker     }
212*c8dee2aaSAndroid Build Coastguard Worker };
213*c8dee2aaSAndroid Build Coastguard Worker 
214*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkEdgeClipper.h"
215*c8dee2aaSAndroid Build Coastguard Worker 
clip(const SkPath & path,SkPoint p0,SkPoint p1)216*c8dee2aaSAndroid Build Coastguard Worker static SkPath clip(const SkPath& path, SkPoint p0, SkPoint p1) {
217*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix mx, inv;
218*c8dee2aaSAndroid Build Coastguard Worker     SkVector v = p1 - p0;
219*c8dee2aaSAndroid Build Coastguard Worker     mx.setAll(v.fX, -v.fY, p0.fX,
220*c8dee2aaSAndroid Build Coastguard Worker               v.fY,  v.fX, p0.fY,
221*c8dee2aaSAndroid Build Coastguard Worker                  0,     0,     1);
222*c8dee2aaSAndroid Build Coastguard Worker     SkAssertResult(mx.invert(&inv));
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker     SkPath rotated;
225*c8dee2aaSAndroid Build Coastguard Worker     path.transform(inv, &rotated);
226*c8dee2aaSAndroid Build Coastguard Worker 
227*c8dee2aaSAndroid Build Coastguard Worker     SkScalar big = 1e28f;
228*c8dee2aaSAndroid Build Coastguard Worker     SkRect clip = {-big, 0, big, big };
229*c8dee2aaSAndroid Build Coastguard Worker 
230*c8dee2aaSAndroid Build Coastguard Worker     struct Rec {
231*c8dee2aaSAndroid Build Coastguard Worker         SkPathBuilder   fResult;
232*c8dee2aaSAndroid Build Coastguard Worker         SkPoint         fPrev = {0, 0};
233*c8dee2aaSAndroid Build Coastguard Worker     } rec;
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker     SkEdgeClipper::ClipPath(rotated, clip, false,
236*c8dee2aaSAndroid Build Coastguard Worker                             [](SkEdgeClipper* clipper, bool newCtr, void* ctx) {
237*c8dee2aaSAndroid Build Coastguard Worker         Rec* rec = (Rec*)ctx;
238*c8dee2aaSAndroid Build Coastguard Worker 
239*c8dee2aaSAndroid Build Coastguard Worker         bool addLineTo = false;
240*c8dee2aaSAndroid Build Coastguard Worker         SkPoint      pts[4];
241*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Verb verb;
242*c8dee2aaSAndroid Build Coastguard Worker         while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
243*c8dee2aaSAndroid Build Coastguard Worker             if (newCtr) {
244*c8dee2aaSAndroid Build Coastguard Worker                 rec->fResult.moveTo(pts[0]);
245*c8dee2aaSAndroid Build Coastguard Worker                 rec->fPrev = pts[0];
246*c8dee2aaSAndroid Build Coastguard Worker                 newCtr = false;
247*c8dee2aaSAndroid Build Coastguard Worker             }
248*c8dee2aaSAndroid Build Coastguard Worker 
249*c8dee2aaSAndroid Build Coastguard Worker             if (addLineTo || pts[0] != rec->fPrev) {
250*c8dee2aaSAndroid Build Coastguard Worker                 rec->fResult.lineTo(pts[0]);
251*c8dee2aaSAndroid Build Coastguard Worker             }
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker             switch (verb) {
254*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kLine_Verb:
255*c8dee2aaSAndroid Build Coastguard Worker                     rec->fResult.lineTo(pts[1]);
256*c8dee2aaSAndroid Build Coastguard Worker                     rec->fPrev = pts[1];
257*c8dee2aaSAndroid Build Coastguard Worker                     break;
258*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kQuad_Verb:
259*c8dee2aaSAndroid Build Coastguard Worker                     rec->fResult.quadTo(pts[1], pts[2]);
260*c8dee2aaSAndroid Build Coastguard Worker                     rec->fPrev = pts[2];
261*c8dee2aaSAndroid Build Coastguard Worker                     break;
262*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kCubic_Verb:
263*c8dee2aaSAndroid Build Coastguard Worker                     rec->fResult.cubicTo(pts[1], pts[2], pts[3]);
264*c8dee2aaSAndroid Build Coastguard Worker                     rec->fPrev = pts[3];
265*c8dee2aaSAndroid Build Coastguard Worker                     break;
266*c8dee2aaSAndroid Build Coastguard Worker                 default: break;
267*c8dee2aaSAndroid Build Coastguard Worker             }
268*c8dee2aaSAndroid Build Coastguard Worker             addLineTo = true;
269*c8dee2aaSAndroid Build Coastguard Worker         }
270*c8dee2aaSAndroid Build Coastguard Worker     }, &rec);
271*c8dee2aaSAndroid Build Coastguard Worker 
272*c8dee2aaSAndroid Build Coastguard Worker     return rec.fResult.detach().makeTransform(mx);
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker 
draw_halfplane(SkCanvas * canvas,SkPoint p0,SkPoint p1,SkColor c)275*c8dee2aaSAndroid Build Coastguard Worker static void draw_halfplane(SkCanvas* canvas, SkPoint p0, SkPoint p1, SkColor c) {
276*c8dee2aaSAndroid Build Coastguard Worker     SkVector v = p1 - p0;
277*c8dee2aaSAndroid Build Coastguard Worker     p0 = p0 - v * 1000;
278*c8dee2aaSAndroid Build Coastguard Worker     p1 = p1 + v * 1000;
279*c8dee2aaSAndroid Build Coastguard Worker 
280*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
281*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(c);
282*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawLine(p0, p1, paint);
283*c8dee2aaSAndroid Build Coastguard Worker }
284*c8dee2aaSAndroid Build Coastguard Worker 
make_path()285*c8dee2aaSAndroid Build Coastguard Worker static SkPath make_path() {
286*c8dee2aaSAndroid Build Coastguard Worker     SkRandom rand;
287*c8dee2aaSAndroid Build Coastguard Worker     auto rand_pt = [&rand]() {
288*c8dee2aaSAndroid Build Coastguard Worker         auto x = rand.nextF();
289*c8dee2aaSAndroid Build Coastguard Worker         auto y = rand.nextF();
290*c8dee2aaSAndroid Build Coastguard Worker         return SkPoint{x * 400, y * 400};
291*c8dee2aaSAndroid Build Coastguard Worker     };
292*c8dee2aaSAndroid Build Coastguard Worker 
293*c8dee2aaSAndroid Build Coastguard Worker     SkPathBuilder path;
294*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 4; ++i) {
295*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[6];
296*c8dee2aaSAndroid Build Coastguard Worker         for (auto& p : pts) {
297*c8dee2aaSAndroid Build Coastguard Worker             p = rand_pt();
298*c8dee2aaSAndroid Build Coastguard Worker         }
299*c8dee2aaSAndroid Build Coastguard Worker         path.moveTo(pts[0]).quadTo(pts[1], pts[2]).quadTo(pts[3], pts[4]).lineTo(pts[5]);
300*c8dee2aaSAndroid Build Coastguard Worker     }
301*c8dee2aaSAndroid Build Coastguard Worker     return path.detach();
302*c8dee2aaSAndroid Build Coastguard Worker }
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker class HalfPlaneSlide : public ClickHandlerSlide {
305*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fPts[2];
306*c8dee2aaSAndroid Build Coastguard Worker     SkPath fPath;
307*c8dee2aaSAndroid Build Coastguard Worker 
308*c8dee2aaSAndroid Build Coastguard Worker public:
HalfPlaneSlide()309*c8dee2aaSAndroid Build Coastguard Worker     HalfPlaneSlide() { fName = "halfplane"; }
310*c8dee2aaSAndroid Build Coastguard Worker 
load(SkScalar w,SkScalar h)311*c8dee2aaSAndroid Build Coastguard Worker     void load(SkScalar w, SkScalar h) override {
312*c8dee2aaSAndroid Build Coastguard Worker         fPts[0] = {0, 0};
313*c8dee2aaSAndroid Build Coastguard Worker         fPts[1] = {3, 2};
314*c8dee2aaSAndroid Build Coastguard Worker         fPath = make_path();
315*c8dee2aaSAndroid Build Coastguard Worker     }
316*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas)317*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas) override {
318*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
319*c8dee2aaSAndroid Build Coastguard Worker 
320*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor({0.5f, 0.5f, 0.5f, 1.0f}, nullptr);
321*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(fPath, paint);
322*c8dee2aaSAndroid Build Coastguard Worker 
323*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor({0, 0, 0, 1}, nullptr);
324*c8dee2aaSAndroid Build Coastguard Worker 
325*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(clip(fPath, fPts[0], fPts[1]), paint);
326*c8dee2aaSAndroid Build Coastguard Worker 
327*c8dee2aaSAndroid Build Coastguard Worker         draw_halfplane(canvas, fPts[0], fPts[1], SK_ColorRED);
328*c8dee2aaSAndroid Build Coastguard Worker     }
329*c8dee2aaSAndroid Build Coastguard Worker 
onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey modi)330*c8dee2aaSAndroid Build Coastguard Worker     Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
331*c8dee2aaSAndroid Build Coastguard Worker         return new Click;
332*c8dee2aaSAndroid Build Coastguard Worker     }
333*c8dee2aaSAndroid Build Coastguard Worker 
onClick(Click * click)334*c8dee2aaSAndroid Build Coastguard Worker     bool onClick(Click* click) override {
335*c8dee2aaSAndroid Build Coastguard Worker         fPts[0] = click->fCurr;
336*c8dee2aaSAndroid Build Coastguard Worker         fPts[1] = fPts[0] + SkPoint{3, 2};
337*c8dee2aaSAndroid Build Coastguard Worker         return true;
338*c8dee2aaSAndroid Build Coastguard Worker     }
339*c8dee2aaSAndroid Build Coastguard Worker };
DEF_SLIDE(return new HalfPlaneSlide ();)340*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new HalfPlaneSlide(); )
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker static void draw_halfplane(SkCanvas* canvas, const SkHalfPlane& p, SkColor c) {
343*c8dee2aaSAndroid Build Coastguard Worker     SkPoint pts[2];
344*c8dee2aaSAndroid Build Coastguard Worker     p.twoPts(pts);
345*c8dee2aaSAndroid Build Coastguard Worker     draw_halfplane(canvas, pts[0], pts[1], c);
346*c8dee2aaSAndroid Build Coastguard Worker }
347*c8dee2aaSAndroid Build Coastguard Worker 
compute_half_planes(const SkMatrix & mx,SkScalar width,SkScalar height,SkHalfPlane planes[4])348*c8dee2aaSAndroid Build Coastguard Worker static void compute_half_planes(const SkMatrix& mx, SkScalar width, SkScalar height,
349*c8dee2aaSAndroid Build Coastguard Worker                                 SkHalfPlane planes[4]) {
350*c8dee2aaSAndroid Build Coastguard Worker     SkScalar a = mx[0], b = mx[1], c = mx[2],
351*c8dee2aaSAndroid Build Coastguard Worker              d = mx[3], e = mx[4], f = mx[5],
352*c8dee2aaSAndroid Build Coastguard Worker              g = mx[6], h = mx[7], i = mx[8];
353*c8dee2aaSAndroid Build Coastguard Worker 
354*c8dee2aaSAndroid Build Coastguard Worker     planes[0] = { 2*g - 2*a/width,  2*h - 2*b/width,  2*i - 2*c/width };
355*c8dee2aaSAndroid Build Coastguard Worker     planes[1] = { 2*a/width,        2*b/width,        2*c/width };
356*c8dee2aaSAndroid Build Coastguard Worker     planes[2] = { 2*g - 2*d/height, 2*h - 2*e/height, 2*i - 2*f/height };
357*c8dee2aaSAndroid Build Coastguard Worker     planes[3] = { 2*d/height,       2*e/height,       2*f/height };
358*c8dee2aaSAndroid Build Coastguard Worker }
359*c8dee2aaSAndroid Build Coastguard Worker 
360*c8dee2aaSAndroid Build Coastguard Worker class HalfPlaneSlide2 : public ClickHandlerSlide {
361*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fPts[4];
362*c8dee2aaSAndroid Build Coastguard Worker     SkPath fPath;
363*c8dee2aaSAndroid Build Coastguard Worker 
364*c8dee2aaSAndroid Build Coastguard Worker public:
HalfPlaneSlide2()365*c8dee2aaSAndroid Build Coastguard Worker     HalfPlaneSlide2() { fName = "halfplane2"; }
366*c8dee2aaSAndroid Build Coastguard Worker 
load(SkScalar w,SkScalar h)367*c8dee2aaSAndroid Build Coastguard Worker     void load(SkScalar w, SkScalar h) override {
368*c8dee2aaSAndroid Build Coastguard Worker         fPath = make_path();
369*c8dee2aaSAndroid Build Coastguard Worker         SkRect r = fPath.getBounds();
370*c8dee2aaSAndroid Build Coastguard Worker         r.toQuad(fPts);
371*c8dee2aaSAndroid Build Coastguard Worker     }
372*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas)373*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas) override {
374*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix mx;
375*c8dee2aaSAndroid Build Coastguard Worker         {
376*c8dee2aaSAndroid Build Coastguard Worker             SkRect r = fPath.getBounds();
377*c8dee2aaSAndroid Build Coastguard Worker             SkPoint src[4];
378*c8dee2aaSAndroid Build Coastguard Worker             r.toQuad(src);
379*c8dee2aaSAndroid Build Coastguard Worker             mx.setPolyToPoly(src, fPts, 4);
380*c8dee2aaSAndroid Build Coastguard Worker         }
381*c8dee2aaSAndroid Build Coastguard Worker 
382*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
383*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(fPath, paint);
384*c8dee2aaSAndroid Build Coastguard Worker 
385*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
386*c8dee2aaSAndroid Build Coastguard Worker         canvas->concat(mx);
387*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0x40FF0000);
388*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(fPath, paint);
389*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
390*c8dee2aaSAndroid Build Coastguard Worker 
391*c8dee2aaSAndroid Build Coastguard Worker         // draw the frame
392*c8dee2aaSAndroid Build Coastguard Worker         paint.setStrokeWidth(10);
393*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(SK_ColorGREEN);
394*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPts, paint);
395*c8dee2aaSAndroid Build Coastguard Worker 
396*c8dee2aaSAndroid Build Coastguard Worker         // draw the half-planes
397*c8dee2aaSAndroid Build Coastguard Worker         SkHalfPlane planes[4];
398*c8dee2aaSAndroid Build Coastguard Worker         compute_half_planes(mx, 400, 400, planes);
399*c8dee2aaSAndroid Build Coastguard Worker         for (auto& p : planes) {
400*c8dee2aaSAndroid Build Coastguard Worker             draw_halfplane(canvas, p, SK_ColorRED);
401*c8dee2aaSAndroid Build Coastguard Worker         }
402*c8dee2aaSAndroid Build Coastguard Worker     }
403*c8dee2aaSAndroid Build Coastguard Worker 
onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey modi)404*c8dee2aaSAndroid Build Coastguard Worker     Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
405*c8dee2aaSAndroid Build Coastguard Worker         SkScalar r = 8;
406*c8dee2aaSAndroid Build Coastguard Worker         SkRect rect = SkRect::MakeXYWH(x - r, y - r, 2*r, 2*r);
407*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < 4; ++i) {
408*c8dee2aaSAndroid Build Coastguard Worker             if (rect.contains(fPts[i].fX, fPts[i].fY)) {
409*c8dee2aaSAndroid Build Coastguard Worker                 Click* c = new Click;
410*c8dee2aaSAndroid Build Coastguard Worker                 c->fMeta.setS32("index", i);
411*c8dee2aaSAndroid Build Coastguard Worker                 return c;
412*c8dee2aaSAndroid Build Coastguard Worker             }
413*c8dee2aaSAndroid Build Coastguard Worker         }
414*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
415*c8dee2aaSAndroid Build Coastguard Worker     }
416*c8dee2aaSAndroid Build Coastguard Worker 
onClick(Click * click)417*c8dee2aaSAndroid Build Coastguard Worker     bool onClick(Click* click) override {
418*c8dee2aaSAndroid Build Coastguard Worker         int32_t index;
419*c8dee2aaSAndroid Build Coastguard Worker         SkAssertResult(click->fMeta.findS32("index", &index));
420*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(index >= 0 && index < 4);
421*c8dee2aaSAndroid Build Coastguard Worker         fPts[index] = click->fCurr;
422*c8dee2aaSAndroid Build Coastguard Worker         return true;
423*c8dee2aaSAndroid Build Coastguard Worker     }
424*c8dee2aaSAndroid Build Coastguard Worker };
DEF_SLIDE(return new HalfPlaneSlide2 ();)425*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new HalfPlaneSlide2(); )
426*c8dee2aaSAndroid Build Coastguard Worker 
427*c8dee2aaSAndroid Build Coastguard Worker static SkM44 inv(const SkM44& m) {
428*c8dee2aaSAndroid Build Coastguard Worker     SkM44 inverse;
429*c8dee2aaSAndroid Build Coastguard Worker     SkAssertResult(m.invert(&inverse));
430*c8dee2aaSAndroid Build Coastguard Worker     return inverse;
431*c8dee2aaSAndroid Build Coastguard Worker }
432*c8dee2aaSAndroid Build Coastguard Worker 
half_plane_w0(const SkMatrix & m)433*c8dee2aaSAndroid Build Coastguard Worker static SkHalfPlane half_plane_w0(const SkMatrix& m) {
434*c8dee2aaSAndroid Build Coastguard Worker     return { m[SkMatrix::kMPersp0], m[SkMatrix::kMPersp1], m[SkMatrix::kMPersp2] - 0.05f };
435*c8dee2aaSAndroid Build Coastguard Worker }
436*c8dee2aaSAndroid Build Coastguard Worker 
437*c8dee2aaSAndroid Build Coastguard Worker class CameraSlide : public ClickHandlerSlide {
438*c8dee2aaSAndroid Build Coastguard Worker     float   fNear = 0.05f;
439*c8dee2aaSAndroid Build Coastguard Worker     float   fFar = 4;
440*c8dee2aaSAndroid Build Coastguard Worker     float   fAngle = SK_ScalarPI / 4;
441*c8dee2aaSAndroid Build Coastguard Worker 
442*c8dee2aaSAndroid Build Coastguard Worker     SkV3    fEye { 0, 0, 1.0f/std::tan(fAngle/2) - 1 };
443*c8dee2aaSAndroid Build Coastguard Worker     SkV3    fCOA { 0, 0, 0 };
444*c8dee2aaSAndroid Build Coastguard Worker     SkV3    fUp  { 0, 1, 0 };
445*c8dee2aaSAndroid Build Coastguard Worker 
446*c8dee2aaSAndroid Build Coastguard Worker     SkM44  fRot;
447*c8dee2aaSAndroid Build Coastguard Worker     SkV3   fTrans;
448*c8dee2aaSAndroid Build Coastguard Worker 
rotate(float x,float y,float z)449*c8dee2aaSAndroid Build Coastguard Worker     void rotate(float x, float y, float z) {
450*c8dee2aaSAndroid Build Coastguard Worker         SkM44 r;
451*c8dee2aaSAndroid Build Coastguard Worker         if (x) {
452*c8dee2aaSAndroid Build Coastguard Worker             r.setRotateUnit({1, 0, 0}, x);
453*c8dee2aaSAndroid Build Coastguard Worker         } else if (y) {
454*c8dee2aaSAndroid Build Coastguard Worker             r.setRotateUnit({0, 1, 0}, y);
455*c8dee2aaSAndroid Build Coastguard Worker         } else {
456*c8dee2aaSAndroid Build Coastguard Worker             r.setRotateUnit({0, 0, 1}, z);
457*c8dee2aaSAndroid Build Coastguard Worker         }
458*c8dee2aaSAndroid Build Coastguard Worker         fRot = r * fRot;
459*c8dee2aaSAndroid Build Coastguard Worker     }
460*c8dee2aaSAndroid Build Coastguard Worker 
461*c8dee2aaSAndroid Build Coastguard Worker public:
get44(const SkRect & r) const462*c8dee2aaSAndroid Build Coastguard Worker     SkM44 get44(const SkRect& r) const {
463*c8dee2aaSAndroid Build Coastguard Worker         SkScalar w = r.width();
464*c8dee2aaSAndroid Build Coastguard Worker         SkScalar h = r.height();
465*c8dee2aaSAndroid Build Coastguard Worker 
466*c8dee2aaSAndroid Build Coastguard Worker         SkM44 camera = SkM44::LookAt(fEye, fCOA, fUp),
467*c8dee2aaSAndroid Build Coastguard Worker               perspective = SkM44::Perspective(fNear, fFar, fAngle),
468*c8dee2aaSAndroid Build Coastguard Worker               translate = SkM44::Translate(fTrans.x, fTrans.y, fTrans.z),
469*c8dee2aaSAndroid Build Coastguard Worker               viewport = SkM44::Translate(r.centerX(), r.centerY(), 0) *
470*c8dee2aaSAndroid Build Coastguard Worker                          SkM44::Scale(w*0.5f, h*0.5f, 1);
471*c8dee2aaSAndroid Build Coastguard Worker 
472*c8dee2aaSAndroid Build Coastguard Worker         return viewport * perspective * camera * translate * fRot * inv(viewport);
473*c8dee2aaSAndroid Build Coastguard Worker     }
474*c8dee2aaSAndroid Build Coastguard Worker 
onChar(SkUnichar uni)475*c8dee2aaSAndroid Build Coastguard Worker     bool onChar(SkUnichar uni) override {
476*c8dee2aaSAndroid Build Coastguard Worker         float delta = SK_ScalarPI / 30;
477*c8dee2aaSAndroid Build Coastguard Worker         switch (uni) {
478*c8dee2aaSAndroid Build Coastguard Worker             case '8': this->rotate( delta, 0, 0); return true;
479*c8dee2aaSAndroid Build Coastguard Worker             case '2': this->rotate(-delta, 0, 0); return true;
480*c8dee2aaSAndroid Build Coastguard Worker             case '4': this->rotate(0,  delta, 0); return true;
481*c8dee2aaSAndroid Build Coastguard Worker             case '6': this->rotate(0, -delta, 0); return true;
482*c8dee2aaSAndroid Build Coastguard Worker             case '-': this->rotate(0, 0,  delta); return true;
483*c8dee2aaSAndroid Build Coastguard Worker             case '+': this->rotate(0, 0, -delta); return true;
484*c8dee2aaSAndroid Build Coastguard Worker 
485*c8dee2aaSAndroid Build Coastguard Worker             case 'i': fTrans.z += 0.1f; SkDebugf("z %g\n", fTrans.z); return true;
486*c8dee2aaSAndroid Build Coastguard Worker             case 'k': fTrans.z -= 0.1f; SkDebugf("z %g\n", fTrans.z); return true;
487*c8dee2aaSAndroid Build Coastguard Worker 
488*c8dee2aaSAndroid Build Coastguard Worker             case 'n': fNear += 0.1f; SkDebugf("near %g\n", fNear); return true;
489*c8dee2aaSAndroid Build Coastguard Worker             case 'N': fNear -= 0.1f; SkDebugf("near %g\n", fNear); return true;
490*c8dee2aaSAndroid Build Coastguard Worker             case 'f': fFar  += 0.1f; SkDebugf("far  %g\n", fFar); return true;
491*c8dee2aaSAndroid Build Coastguard Worker             case 'F': fFar  -= 0.1f; SkDebugf("far  %g\n", fFar); return true;
492*c8dee2aaSAndroid Build Coastguard Worker             default: break;
493*c8dee2aaSAndroid Build Coastguard Worker         }
494*c8dee2aaSAndroid Build Coastguard Worker         return false;
495*c8dee2aaSAndroid Build Coastguard Worker     }
496*c8dee2aaSAndroid Build Coastguard Worker };
497*c8dee2aaSAndroid Build Coastguard Worker 
498*c8dee2aaSAndroid Build Coastguard Worker class HalfPlaneSlide3 : public CameraSlide {
499*c8dee2aaSAndroid Build Coastguard Worker     SkPath fPath;
500*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
501*c8dee2aaSAndroid Build Coastguard Worker     bool fShowUnclipped = false;
502*c8dee2aaSAndroid Build Coastguard Worker 
503*c8dee2aaSAndroid Build Coastguard Worker public:
HalfPlaneSlide3()504*c8dee2aaSAndroid Build Coastguard Worker     HalfPlaneSlide3() { fName = "halfplane3"; }
505*c8dee2aaSAndroid Build Coastguard Worker 
load(SkScalar w,SkScalar h)506*c8dee2aaSAndroid Build Coastguard Worker     void load(SkScalar w, SkScalar h) override {
507*c8dee2aaSAndroid Build Coastguard Worker         fPath = make_path();
508*c8dee2aaSAndroid Build Coastguard Worker         fShader = ToolUtils::GetResourceAsImage("images/mandrill_128.png")
509*c8dee2aaSAndroid Build Coastguard Worker                           ->makeShader(SkSamplingOptions(), SkMatrix::Scale(3, 3));
510*c8dee2aaSAndroid Build Coastguard Worker     }
511*c8dee2aaSAndroid Build Coastguard Worker 
onChar(SkUnichar uni)512*c8dee2aaSAndroid Build Coastguard Worker     bool onChar(SkUnichar uni) override {
513*c8dee2aaSAndroid Build Coastguard Worker         switch (uni) {
514*c8dee2aaSAndroid Build Coastguard Worker             case 'u': fShowUnclipped = !fShowUnclipped; return true;
515*c8dee2aaSAndroid Build Coastguard Worker             default: break;
516*c8dee2aaSAndroid Build Coastguard Worker         }
517*c8dee2aaSAndroid Build Coastguard Worker         return this->CameraSlide::onChar(uni);
518*c8dee2aaSAndroid Build Coastguard Worker     }
519*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas)520*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas) override {
521*c8dee2aaSAndroid Build Coastguard Worker         SkM44 mx = this->get44({0, 0, 400, 400});
522*c8dee2aaSAndroid Build Coastguard Worker 
523*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
524*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor({0.75, 0.75, 0.75, 1});
525*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(fPath, paint);
526*c8dee2aaSAndroid Build Coastguard Worker 
527*c8dee2aaSAndroid Build Coastguard Worker         paint.setShader(fShader);
528*c8dee2aaSAndroid Build Coastguard Worker 
529*c8dee2aaSAndroid Build Coastguard Worker         if (fShowUnclipped) {
530*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
531*c8dee2aaSAndroid Build Coastguard Worker             canvas->concat(mx);
532*c8dee2aaSAndroid Build Coastguard Worker             paint.setAlphaf(0.33f);
533*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawPath(fPath, paint);
534*c8dee2aaSAndroid Build Coastguard Worker             paint.setAlphaf(1.f);
535*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
536*c8dee2aaSAndroid Build Coastguard Worker         }
537*c8dee2aaSAndroid Build Coastguard Worker 
538*c8dee2aaSAndroid Build Coastguard Worker 
539*c8dee2aaSAndroid Build Coastguard Worker         SkColor planeColor = SK_ColorBLUE;
540*c8dee2aaSAndroid Build Coastguard Worker         SkPath clippedPath, *path = &fPath;
541*c8dee2aaSAndroid Build Coastguard Worker         if (SkPathPriv::PerspectiveClip(fPath, mx.asM33(), &clippedPath)) {
542*c8dee2aaSAndroid Build Coastguard Worker             path = &clippedPath;
543*c8dee2aaSAndroid Build Coastguard Worker             planeColor = SK_ColorRED;
544*c8dee2aaSAndroid Build Coastguard Worker         }
545*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
546*c8dee2aaSAndroid Build Coastguard Worker         canvas->concat(mx);
547*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(*path, paint);
548*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
549*c8dee2aaSAndroid Build Coastguard Worker 
550*c8dee2aaSAndroid Build Coastguard Worker         SkHalfPlane hpw = half_plane_w0(mx.asM33());
551*c8dee2aaSAndroid Build Coastguard Worker         draw_halfplane(canvas, hpw, planeColor);
552*c8dee2aaSAndroid Build Coastguard Worker     }
553*c8dee2aaSAndroid Build Coastguard Worker 
554*c8dee2aaSAndroid Build Coastguard Worker protected:
onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey)555*c8dee2aaSAndroid Build Coastguard Worker     Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override {
556*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
557*c8dee2aaSAndroid Build Coastguard Worker     }
onClick(Click * click)558*c8dee2aaSAndroid Build Coastguard Worker     bool onClick(Click* click) override { return false; }
559*c8dee2aaSAndroid Build Coastguard Worker };
560*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new HalfPlaneSlide3(); )
561*c8dee2aaSAndroid Build Coastguard Worker 
562*c8dee2aaSAndroid Build Coastguard Worker class HalfPlaneCoonsSlide : public CameraSlide {
563*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fPatch[12];
564*c8dee2aaSAndroid Build Coastguard Worker     SkColor fColors[4] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK };
565*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fTex[4]    = {{0, 0}, {256, 0}, {256, 256}, {0, 256}};
566*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
567*c8dee2aaSAndroid Build Coastguard Worker 
568*c8dee2aaSAndroid Build Coastguard Worker     bool fShowHandles = false;
569*c8dee2aaSAndroid Build Coastguard Worker     bool fShowSkeleton = false;
570*c8dee2aaSAndroid Build Coastguard Worker     bool fShowTex = false;
571*c8dee2aaSAndroid Build Coastguard Worker 
572*c8dee2aaSAndroid Build Coastguard Worker public:
HalfPlaneCoonsSlide()573*c8dee2aaSAndroid Build Coastguard Worker     HalfPlaneCoonsSlide() { fName = "halfplane-coons"; }
574*c8dee2aaSAndroid Build Coastguard Worker 
load(SkScalar w,SkScalar h)575*c8dee2aaSAndroid Build Coastguard Worker     void load(SkScalar w, SkScalar h) override {
576*c8dee2aaSAndroid Build Coastguard Worker         fPatch[0] = {   0, 0 };
577*c8dee2aaSAndroid Build Coastguard Worker         fPatch[1] = { 100, 0 };
578*c8dee2aaSAndroid Build Coastguard Worker         fPatch[2] = { 200, 0 };
579*c8dee2aaSAndroid Build Coastguard Worker         fPatch[3] = { 300, 0 };
580*c8dee2aaSAndroid Build Coastguard Worker         fPatch[4] = { 300, 100 };
581*c8dee2aaSAndroid Build Coastguard Worker         fPatch[5] = { 300, 200 };
582*c8dee2aaSAndroid Build Coastguard Worker         fPatch[6] = { 300, 300 };
583*c8dee2aaSAndroid Build Coastguard Worker         fPatch[7] = { 200, 300 };
584*c8dee2aaSAndroid Build Coastguard Worker         fPatch[8] = { 100, 300 };
585*c8dee2aaSAndroid Build Coastguard Worker         fPatch[9] = {   0, 300 };
586*c8dee2aaSAndroid Build Coastguard Worker         fPatch[10] = {  0, 200 };
587*c8dee2aaSAndroid Build Coastguard Worker         fPatch[11] = {  0, 100 };
588*c8dee2aaSAndroid Build Coastguard Worker 
589*c8dee2aaSAndroid Build Coastguard Worker         fShader = ToolUtils::GetResourceAsImage("images/mandrill_256.png")
590*c8dee2aaSAndroid Build Coastguard Worker                           ->makeShader(SkSamplingOptions());
591*c8dee2aaSAndroid Build Coastguard Worker     }
592*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas)593*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas) override {
594*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
595*c8dee2aaSAndroid Build Coastguard Worker 
596*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
597*c8dee2aaSAndroid Build Coastguard Worker         canvas->concat(this->get44({0, 0, 300, 300}));
598*c8dee2aaSAndroid Build Coastguard Worker 
599*c8dee2aaSAndroid Build Coastguard Worker         const SkPoint* tex = nullptr;
600*c8dee2aaSAndroid Build Coastguard Worker         const SkColor* col = nullptr;
601*c8dee2aaSAndroid Build Coastguard Worker         if (!fShowSkeleton) {
602*c8dee2aaSAndroid Build Coastguard Worker             if (fShowTex) {
603*c8dee2aaSAndroid Build Coastguard Worker                 paint.setShader(fShader);
604*c8dee2aaSAndroid Build Coastguard Worker                 tex = fTex;
605*c8dee2aaSAndroid Build Coastguard Worker             } else {
606*c8dee2aaSAndroid Build Coastguard Worker                 col = fColors;
607*c8dee2aaSAndroid Build Coastguard Worker             }
608*c8dee2aaSAndroid Build Coastguard Worker         }
609*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPatch(fPatch, col, tex, SkBlendMode::kSrc, paint);
610*c8dee2aaSAndroid Build Coastguard Worker         paint.setShader(nullptr);
611*c8dee2aaSAndroid Build Coastguard Worker 
612*c8dee2aaSAndroid Build Coastguard Worker         if (fShowHandles) {
613*c8dee2aaSAndroid Build Coastguard Worker             paint.setAntiAlias(true);
614*c8dee2aaSAndroid Build Coastguard Worker             paint.setStrokeCap(SkPaint::kRound_Cap);
615*c8dee2aaSAndroid Build Coastguard Worker             paint.setStrokeWidth(8);
616*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawPoints(SkCanvas::kPoints_PointMode, 12, fPatch, paint);
617*c8dee2aaSAndroid Build Coastguard Worker             paint.setColor(SK_ColorWHITE);
618*c8dee2aaSAndroid Build Coastguard Worker             paint.setStrokeWidth(6);
619*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawPoints(SkCanvas::kPoints_PointMode, 12, fPatch, paint);
620*c8dee2aaSAndroid Build Coastguard Worker         }
621*c8dee2aaSAndroid Build Coastguard Worker 
622*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
623*c8dee2aaSAndroid Build Coastguard Worker     }
624*c8dee2aaSAndroid Build Coastguard Worker 
onChar(SkUnichar uni)625*c8dee2aaSAndroid Build Coastguard Worker     bool onChar(SkUnichar uni) override {
626*c8dee2aaSAndroid Build Coastguard Worker         switch (uni) {
627*c8dee2aaSAndroid Build Coastguard Worker             case 'h': fShowHandles = !fShowHandles; return true;
628*c8dee2aaSAndroid Build Coastguard Worker             case 'k': fShowSkeleton = !fShowSkeleton; return true;
629*c8dee2aaSAndroid Build Coastguard Worker             case 't': fShowTex = !fShowTex; return true;
630*c8dee2aaSAndroid Build Coastguard Worker             default: break;
631*c8dee2aaSAndroid Build Coastguard Worker         }
632*c8dee2aaSAndroid Build Coastguard Worker         return this->CameraSlide::onChar(uni);
633*c8dee2aaSAndroid Build Coastguard Worker     }
634*c8dee2aaSAndroid Build Coastguard Worker 
635*c8dee2aaSAndroid Build Coastguard Worker protected:
onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey modi)636*c8dee2aaSAndroid Build Coastguard Worker     Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
637*c8dee2aaSAndroid Build Coastguard Worker         auto dist = [](SkPoint a, SkPoint b) { return (b - a).length(); };
638*c8dee2aaSAndroid Build Coastguard Worker 
639*c8dee2aaSAndroid Build Coastguard Worker         const float tol = 15;
640*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < 12; ++i) {
641*c8dee2aaSAndroid Build Coastguard Worker             if (dist({x,y}, fPatch[i]) <= tol) {
642*c8dee2aaSAndroid Build Coastguard Worker                 return new Click([this, i](Click* c) {
643*c8dee2aaSAndroid Build Coastguard Worker                     fPatch[i] = c->fCurr;
644*c8dee2aaSAndroid Build Coastguard Worker                     return true;
645*c8dee2aaSAndroid Build Coastguard Worker                 });
646*c8dee2aaSAndroid Build Coastguard Worker             }
647*c8dee2aaSAndroid Build Coastguard Worker         }
648*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
649*c8dee2aaSAndroid Build Coastguard Worker     }
650*c8dee2aaSAndroid Build Coastguard Worker 
onClick(Click * click)651*c8dee2aaSAndroid Build Coastguard Worker     bool onClick(Click* click) override { return false; }
652*c8dee2aaSAndroid Build Coastguard Worker };
653*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new HalfPlaneCoonsSlide(); )
654