blob: 014d03453c03bd2de6f4fb8447a762ceb7e59b22 [file] [log] [blame]
reed@google.com3bcf8d32011-10-10 15:42:36 +00001/*
2 * Copyright 2011 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 "include/core/SkCanvas.h"
9#include "include/core/SkColorPriv.h"
10#include "include/core/SkFont.h"
11#include "include/core/SkPaint.h"
12#include "include/core/SkPath.h"
13#include "include/utils/SkRandom.h"
14#include "samplecode/Sample.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/core/SkClipOpPriv.h"
Mike Reedfae46e42019-12-04 16:15:23 -050016#include "src/core/SkPathPriv.h"
Mike Reed00a97642020-01-25 18:42:23 -050017#include "tools/Resources.h"
reed@google.com3bcf8d32011-10-10 15:42:36 +000018
Ben Wagner8a1036c2016-11-09 15:00:49 -050019constexpr int W = 150;
20constexpr int H = 200;
reed@google.com3bcf8d32011-10-10 15:42:36 +000021
reed@google.com045e62d2011-10-24 12:19:46 +000022static void show_text(SkCanvas* canvas, bool doAA) {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000023 SkRandom rand;
reed@google.com3bcf8d32011-10-10 15:42:36 +000024 SkPaint paint;
Hal Canary4484b8f2019-01-08 14:00:08 -050025 SkFont font(nullptr, 20);
26 font.setEdging(doAA ? SkFont::Edging::kSubpixelAntiAlias : SkFont::Edging::kAlias);
rmistry@google.comae933ce2012-08-23 18:19:56 +000027
reed@google.com045e62d2011-10-24 12:19:46 +000028 for (int i = 0; i < 200; ++i) {
reed@google.com3bcf8d32011-10-10 15:42:36 +000029 paint.setColor((SK_A32_MASK << SK_A32_SHIFT) | rand.nextU());
Hal Canary4484b8f2019-01-08 14:00:08 -050030 canvas->drawString("Hamburgefons", rand.nextSScalar1() * W, rand.nextSScalar1() * H + 20,
31 font, paint);
reed@google.com3bcf8d32011-10-10 15:42:36 +000032 }
33}
34
reed@google.com045e62d2011-10-24 12:19:46 +000035static void show_fill(SkCanvas* canvas, bool doAA) {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000036 SkRandom rand;
reed@google.com3bcf8d32011-10-10 15:42:36 +000037 SkPaint paint;
reed@google.com045e62d2011-10-24 12:19:46 +000038 paint.setAntiAlias(doAA);
rmistry@google.comae933ce2012-08-23 18:19:56 +000039
reed@google.com045e62d2011-10-24 12:19:46 +000040 for (int i = 0; i < 50; ++i) {
reed@google.com3bcf8d32011-10-10 15:42:36 +000041 SkRect r;
42 SkPath p;
rmistry@google.comae933ce2012-08-23 18:19:56 +000043
reed@google.com3bcf8d32011-10-10 15:42:36 +000044 r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
45 rand.nextUScalar1() * W, rand.nextUScalar1() * H);
reed@google.com3bcf8d32011-10-10 15:42:36 +000046 paint.setColor(rand.nextU());
47 canvas->drawRect(r, paint);
rmistry@google.comae933ce2012-08-23 18:19:56 +000048
reed@google.com3bcf8d32011-10-10 15:42:36 +000049 r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
50 rand.nextUScalar1() * W, rand.nextUScalar1() * H);
reed@google.com3bcf8d32011-10-10 15:42:36 +000051 paint.setColor(rand.nextU());
52 p.addOval(r);
53 canvas->drawPath(p, paint);
54 }
55}
56
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000057static SkScalar randRange(SkRandom& rand, SkScalar min, SkScalar max) {
reed@google.com045e62d2011-10-24 12:19:46 +000058 SkASSERT(min <= max);
Mike Reeddf85c382017-02-14 10:59:19 -050059 return min + rand.nextUScalar1() * (max - min);
reed@google.com045e62d2011-10-24 12:19:46 +000060}
61
62static void show_stroke(SkCanvas* canvas, bool doAA, SkScalar strokeWidth, int n) {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000063 SkRandom rand;
reed@google.com045e62d2011-10-24 12:19:46 +000064 SkPaint paint;
65 paint.setAntiAlias(doAA);
66 paint.setStyle(SkPaint::kStroke_Style);
67 paint.setStrokeWidth(strokeWidth);
rmistry@google.comae933ce2012-08-23 18:19:56 +000068
reed@google.com045e62d2011-10-24 12:19:46 +000069 for (int i = 0; i < n; ++i) {
70 SkRect r;
71 SkPath p;
rmistry@google.comae933ce2012-08-23 18:19:56 +000072
reed@google.com045e62d2011-10-24 12:19:46 +000073 r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
74 rand.nextUScalar1() * W, rand.nextUScalar1() * H);
75 paint.setColor(rand.nextU());
76 canvas->drawRect(r, paint);
rmistry@google.comae933ce2012-08-23 18:19:56 +000077
reed@google.com045e62d2011-10-24 12:19:46 +000078 r.setXYWH(rand.nextSScalar1() * W, rand.nextSScalar1() * H,
79 rand.nextUScalar1() * W, rand.nextUScalar1() * H);
80 paint.setColor(rand.nextU());
81 p.addOval(r);
82 canvas->drawPath(p, paint);
83
84 const SkScalar minx = -SkIntToScalar(W)/4;
85 const SkScalar maxx = 5*SkIntToScalar(W)/4;
86 const SkScalar miny = -SkIntToScalar(H)/4;
87 const SkScalar maxy = 5*SkIntToScalar(H)/4;
88 paint.setColor(rand.nextU());
89 canvas->drawLine(randRange(rand, minx, maxx), randRange(rand, miny, maxy),
90 randRange(rand, minx, maxx), randRange(rand, miny, maxy),
91 paint);
92 }
93}
94
95static void show_hair(SkCanvas* canvas, bool doAA) {
96 show_stroke(canvas, doAA, 0, 150);
97}
98
99static void show_thick(SkCanvas* canvas, bool doAA) {
100 show_stroke(canvas, doAA, SkIntToScalar(5), 50);
101}
102
103typedef void (*CanvasProc)(SkCanvas*, bool);
104
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400105class ClipView : public Sample {
Hal Canaryd7639af2019-07-17 09:08:11 -0400106 SkString name() override { return SkString("Clip"); }
reed@google.com3bcf8d32011-10-10 15:42:36 +0000107
Hal Canaryd7639af2019-07-17 09:08:11 -0400108 void onDrawContent(SkCanvas* canvas) override {
reed@google.com045e62d2011-10-24 12:19:46 +0000109 canvas->drawColor(SK_ColorWHITE);
reed@google.com3bcf8d32011-10-10 15:42:36 +0000110 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
111
112 static const CanvasProc gProc[] = {
reed@google.com045e62d2011-10-24 12:19:46 +0000113 show_text, show_thick, show_hair, show_fill
reed@google.com3bcf8d32011-10-10 15:42:36 +0000114 };
rmistry@google.comae933ce2012-08-23 18:19:56 +0000115
reed@google.com3bcf8d32011-10-10 15:42:36 +0000116 SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
117 SkPath clipPath;
118 r.inset(SK_Scalar1 / 4, SK_Scalar1 / 4);
Mike Reed4241f5e2019-09-14 19:13:23 +0000119 clipPath.addRoundRect(r, SkIntToScalar(20), SkIntToScalar(20));
reed@google.com045e62d2011-10-24 12:19:46 +0000120
121// clipPath.toggleInverseFillType();
reed@google.com3bcf8d32011-10-10 15:42:36 +0000122
123 for (int aa = 0; aa <= 1; ++aa) {
124 canvas->save();
125 for (size_t i = 0; i < SK_ARRAY_COUNT(gProc); ++i) {
126 canvas->save();
Mike Reedc1f77742016-12-09 09:00:50 -0500127 canvas->clipPath(clipPath, kIntersect_SkClipOp, SkToBool(aa));
reed@google.com045e62d2011-10-24 12:19:46 +0000128// canvas->drawColor(SK_ColorWHITE);
129 gProc[i](canvas, SkToBool(aa));
reed@google.com3bcf8d32011-10-10 15:42:36 +0000130 canvas->restore();
131 canvas->translate(W * SK_Scalar1 * 8 / 7, 0);
132 }
133 canvas->restore();
134 canvas->translate(0, H * SK_Scalar1 * 8 / 7);
135 }
136 }
reed@google.com3bcf8d32011-10-10 15:42:36 +0000137};
138
Ben Wagnerb2c4ea62018-08-08 11:36:17 -0400139DEF_SAMPLE( return new ClipView(); )
Mike Reed63edc572019-11-15 21:58:01 -0500140
141///////////////////////////////////////////////////////////////////////////////
142
143struct SkHalfPlane {
144 SkScalar fA, fB, fC;
145
Mike Reed6344c292019-12-04 12:45:39 -0500146 SkScalar eval(SkScalar x, SkScalar y) const {
Mike Reed63edc572019-11-15 21:58:01 -0500147 return fA * x + fB * y + fC;
148 }
Mike Reed6344c292019-12-04 12:45:39 -0500149 SkScalar operator()(SkScalar x, SkScalar y) const { return this->eval(x, y); }
Mike Reed63edc572019-11-15 21:58:01 -0500150
151 bool twoPts(SkPoint pts[2]) const {
Jim Van Verthc3363152019-12-03 12:05:14 -0500152 // normalize plane to help with the perpendicular step, below
153 SkScalar len = SkScalarSqrt(fA*fA + fB*fB);
154 if (!len) {
155 return false;
156 }
157 SkScalar denom = SkScalarInvert(len);
158 SkScalar a = fA * denom;
159 SkScalar b = fB * denom;
160 SkScalar c = fC * denom;
161
162 // We compute p0 on the half-plane by setting one of the components to 0
163 // We compute p1 by stepping from p0 along a perpendicular to the normal
164 if (b) {
165 pts[0] = { 0, -c / b };
166 pts[1] = { b, pts[0].fY - a};
167 } else if (a) {
168 pts[0] = { -c / a, 0 };
169 pts[1] = { pts[0].fX + b, -a };
Mike Reed63edc572019-11-15 21:58:01 -0500170 } else {
171 return false;
172 }
Jim Van Verthc3363152019-12-03 12:05:14 -0500173
174 SkASSERT(SkScalarNearlyZero(this->operator()(pts[0].fX, pts[0].fY)));
175 SkASSERT(SkScalarNearlyZero(this->operator()(pts[1].fX, pts[1].fY)));
Mike Reed63edc572019-11-15 21:58:01 -0500176 return true;
177 }
Mike Reed6344c292019-12-04 12:45:39 -0500178
179 enum Result {
180 kAllNegative,
181 kAllPositive,
182 kMixed
183 };
184 Result test(const SkRect& bounds) const {
185 SkPoint diagMin, diagMax;
186 if (fA >= 0) {
187 diagMin.fX = bounds.fLeft;
188 diagMax.fX = bounds.fRight;
189 } else {
190 diagMin.fX = bounds.fRight;
191 diagMax.fX = bounds.fLeft;
192 }
193 if (fB >= 0) {
194 diagMin.fY = bounds.fTop;
195 diagMax.fY = bounds.fBottom;
196 } else {
197 diagMin.fY = bounds.fBottom;
198 diagMax.fY = bounds.fTop;
199 }
200 SkScalar test = this->eval(diagMin.fX, diagMin.fY);
201 SkScalar sign = test*this->eval(diagMax.fX, diagMin.fY);
202 if (sign > 0) {
203 // the path is either all on one side of the half-plane or the other
204 if (test < 0) {
205 return kAllNegative;
206 } else {
207 return kAllPositive;
208 }
209 }
210 return kMixed;
211 }
Mike Reed63edc572019-11-15 21:58:01 -0500212};
213
214#include "src/core/SkEdgeClipper.h"
215
Mike Reed6344c292019-12-04 12:45:39 -0500216static void clip(const SkPath& path, SkPoint p0, SkPoint p1, SkPath* clippedPath) {
Mike Reed63edc572019-11-15 21:58:01 -0500217 SkMatrix mx, inv;
218 SkVector v = p1 - p0;
219 mx.setAll(v.fX, -v.fY, p0.fX,
220 v.fY, v.fX, p0.fY,
221 0, 0, 1);
222 SkAssertResult(mx.invert(&inv));
223
224 SkPath rotated;
225 path.transform(inv, &rotated);
226
227 SkScalar big = 1e28f;
228 SkRect clip = {-big, 0, big, big };
229
230 struct Rec {
Mike Reed6344c292019-12-04 12:45:39 -0500231 SkPath* fResult;
Mike Reed63edc572019-11-15 21:58:01 -0500232 SkPoint fPrev;
Mike Reed6344c292019-12-04 12:45:39 -0500233 } rec = { clippedPath, {0, 0} };
Mike Reed63edc572019-11-15 21:58:01 -0500234
235 SkEdgeClipper::ClipPath(rotated, clip, false,
236 [](SkEdgeClipper* clipper, bool newCtr, void* ctx) {
237 Rec* rec = (Rec*)ctx;
238
239 bool addLineTo = false;
240 SkPoint pts[4];
241 SkPath::Verb verb;
242 while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
243 if (newCtr) {
Mike Reed6344c292019-12-04 12:45:39 -0500244 rec->fResult->moveTo(pts[0]);
Mike Reed63edc572019-11-15 21:58:01 -0500245 rec->fPrev = pts[0];
246 newCtr = false;
247 }
248
249 if (addLineTo || pts[0] != rec->fPrev) {
Mike Reed6344c292019-12-04 12:45:39 -0500250 rec->fResult->lineTo(pts[0]);
Mike Reed63edc572019-11-15 21:58:01 -0500251 }
252
253 switch (verb) {
254 case SkPath::kLine_Verb:
Mike Reed6344c292019-12-04 12:45:39 -0500255 rec->fResult->lineTo(pts[1]);
Mike Reed63edc572019-11-15 21:58:01 -0500256 rec->fPrev = pts[1];
257 break;
258 case SkPath::kQuad_Verb:
Mike Reed6344c292019-12-04 12:45:39 -0500259 rec->fResult->quadTo(pts[1], pts[2]);
Mike Reed63edc572019-11-15 21:58:01 -0500260 rec->fPrev = pts[2];
261 break;
262 case SkPath::kCubic_Verb:
Mike Reed6344c292019-12-04 12:45:39 -0500263 rec->fResult->cubicTo(pts[1], pts[2], pts[3]);
Mike Reed63edc572019-11-15 21:58:01 -0500264 rec->fPrev = pts[3];
265 break;
266 default: break;
267 }
268 addLineTo = true;
269 }
270 }, &rec);
271
Mike Reed6344c292019-12-04 12:45:39 -0500272 rec.fResult->transform(mx);
Mike Reed63edc572019-11-15 21:58:01 -0500273}
274
Mike Reed63edc572019-11-15 21:58:01 -0500275static void draw_halfplane(SkCanvas* canvas, SkPoint p0, SkPoint p1, SkColor c) {
276 SkVector v = p1 - p0;
277 p0 = p0 - v * 1000;
278 p1 = p1 + v * 1000;
279
280 SkPaint paint;
281 paint.setColor(c);
282 canvas->drawLine(p0, p1, paint);
283}
284
285static SkPath make_path() {
286 SkRandom rand;
Mike Reed0483b462019-12-05 17:29:45 -0500287 auto rand_pt = [&rand]() {
288 auto x = rand.nextF();
289 auto y = rand.nextF();
290 return SkPoint{x * 400, y * 400};
291 };
Mike Reed63edc572019-11-15 21:58:01 -0500292
293 SkPath path;
294 for (int i = 0; i < 4; ++i) {
Mike Reed0483b462019-12-05 17:29:45 -0500295 SkPoint pts[6];
296 for (auto& p : pts) {
297 p = rand_pt();
298 }
299 path.moveTo(pts[0]).quadTo(pts[1], pts[2]).quadTo(pts[3], pts[4]).lineTo(pts[5]);
Mike Reed63edc572019-11-15 21:58:01 -0500300 }
301 return path;
302}
303
304class HalfPlaneView : public Sample {
305 SkPoint fPts[2];
306 SkPath fPath;
307
308 SkString name() override { return SkString("halfplane"); }
309
310 void onOnceBeforeDraw() override {
311 fPts[0] = {0, 0};
312 fPts[1] = {3, 2};
313 fPath = make_path();
314 }
315
316 void onDrawContent(SkCanvas* canvas) override {
317 SkPaint paint;
318
319 paint.setColor({0.5f, 0.5f, 0.5f, 1.0f}, nullptr);
320 canvas->drawPath(fPath, paint);
321
322 paint.setColor({0, 0, 0, 1}, nullptr);
Mike Reed6344c292019-12-04 12:45:39 -0500323
324 SkPath clippedPath;
325 clip(fPath, fPts[0], fPts[1], &clippedPath);
326 canvas->drawPath(clippedPath, paint);
Mike Reed63edc572019-11-15 21:58:01 -0500327
328 draw_halfplane(canvas, fPts[0], fPts[1], SK_ColorRED);
329 }
330
331 Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
332 return new Click;
333 }
334
335 bool onClick(Click* click) override {
336 fPts[0] = click->fCurr;
337 fPts[1] = fPts[0] + SkPoint{3, 2};
338 return true;
339 }
340};
341DEF_SAMPLE( return new HalfPlaneView(); )
342
343static void draw_halfplane(SkCanvas* canvas, const SkHalfPlane& p, SkColor c) {
344 SkPoint pts[2];
345 p.twoPts(pts);
346 draw_halfplane(canvas, pts[0], pts[1], c);
347}
348
349static void compute_half_planes(const SkMatrix& mx, SkScalar W, SkScalar H,
350 SkHalfPlane planes[4]) {
351 SkScalar a = mx[0], b = mx[1], c = mx[2],
352 d = mx[3], e = mx[4], f = mx[5],
353 g = mx[6], h = mx[7], i = mx[8];
354
355 planes[0] = { 2*g - 2*a/W, 2*h - 2*b/W, 2*i - 2*c/W };
356 planes[1] = { 2*a/W, 2*b/W, 2*c/W };
357 planes[2] = { 2*g - 2*d/H, 2*h - 2*e/H, 2*i - 2*f/H };
358 planes[3] = { 2*d/H, 2*e/H, 2*f/H };
359}
360
361class HalfPlaneView2 : public Sample {
362 SkPoint fPts[4];
363 SkPath fPath;
364
365 SkString name() override { return SkString("halfplane2"); }
366
367 void onOnceBeforeDraw() override {
368 fPath = make_path();
369 SkRect r = fPath.getBounds();
370 r.toQuad(fPts);
371 }
372
373 void onDrawContent(SkCanvas* canvas) override {
374 SkMatrix mx;
375 {
376 SkRect r = fPath.getBounds();
377 SkPoint src[4];
378 r.toQuad(src);
379 mx.setPolyToPoly(src, fPts, 4);
380 }
381
382 SkPaint paint;
383 canvas->drawPath(fPath, paint);
384
385 canvas->save();
386 canvas->concat(mx);
387 paint.setColor(0x40FF0000);
388 canvas->drawPath(fPath, paint);
389 canvas->restore();
390
391 // draw the frame
392 paint.setStrokeWidth(10);
393 paint.setColor(SK_ColorGREEN);
394 canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPts, paint);
395
396 // draw the half-planes
397 SkHalfPlane planes[4];
398 compute_half_planes(mx, 400, 400, planes);
399 for (auto& p : planes) {
400 draw_halfplane(canvas, p, SK_ColorRED);
401 }
402 }
403
404 Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
405 SkScalar r = 8;
406 SkRect rect = SkRect::MakeXYWH(x - r, y - r, 2*r, 2*r);
407 for (int i = 0; i < 4; ++i) {
408 if (rect.contains(fPts[i].fX, fPts[i].fY)) {
409 Click* c = new Click;
410 c->fMeta.setS32("index", i);
411 return c;
412 }
413 }
414 return nullptr;
415 }
416
417 bool onClick(Click* click) override {
418 int32_t index;
419 SkAssertResult(click->fMeta.findS32("index", &index));
420 SkASSERT(index >= 0 && index < 4);
421 fPts[index] = click->fCurr;
422 return true;
423 }
424};
425DEF_SAMPLE( return new HalfPlaneView2(); )
426
Mike Reed00a97642020-01-25 18:42:23 -0500427static SkM44 inv(const SkM44& m) {
428 SkM44 inverse;
Mike Reed63edc572019-11-15 21:58:01 -0500429 SkAssertResult(m.invert(&inverse));
430 return inverse;
431}
432
Mike Reed6344c292019-12-04 12:45:39 -0500433static SkHalfPlane half_plane_w0(const SkMatrix& m) {
434 return { m[SkMatrix::kMPersp0], m[SkMatrix::kMPersp1], m[SkMatrix::kMPersp2] - 0.05f };
Jim Van Verthc3363152019-12-03 12:05:14 -0500435}
436
Mike Reedcbeabd92019-12-16 17:13:58 -0500437class SampleCameraView : public Sample {
Mike Reed63edc572019-11-15 21:58:01 -0500438 float fNear = 0.05f;
439 float fFar = 4;
440 float fAngle = SK_ScalarPI / 4;
441
Mike Reed00a97642020-01-25 18:42:23 -0500442 SkV3 fEye { 0, 0, 1.0f/tan(fAngle/2) - 1 };
443 SkV3 fCOA { 0, 0, 0 };
444 SkV3 fUp { 0, 1, 0 };
Mike Reed63edc572019-11-15 21:58:01 -0500445
Mike Reed00a97642020-01-25 18:42:23 -0500446 SkM44 fRot;
447 SkV3 fTrans;
Mike Reed63edc572019-11-15 21:58:01 -0500448
Mike Reed63edc572019-11-15 21:58:01 -0500449 void rotate(float x, float y, float z) {
Mike Reed00a97642020-01-25 18:42:23 -0500450 SkM44 r;
Mike Reed63edc572019-11-15 21:58:01 -0500451 if (x) {
Mike Reed00a97642020-01-25 18:42:23 -0500452 r.setRotateUnit({1, 0, 0}, x);
Mike Reed63edc572019-11-15 21:58:01 -0500453 } else if (y) {
Mike Reed00a97642020-01-25 18:42:23 -0500454 r.setRotateUnit({0, 1, 0}, y);
Mike Reed63edc572019-11-15 21:58:01 -0500455 } else {
Mike Reed00a97642020-01-25 18:42:23 -0500456 r.setRotateUnit({0, 0, 1}, z);
Mike Reed63edc572019-11-15 21:58:01 -0500457 }
Mike Reed00a97642020-01-25 18:42:23 -0500458 fRot = r * fRot;
Mike Reed63edc572019-11-15 21:58:01 -0500459 }
460
Mike Reedcbeabd92019-12-16 17:13:58 -0500461public:
Mike Reed00a97642020-01-25 18:42:23 -0500462 SkM44 get44(const SkRect& r) const {
Mike Reedcbeabd92019-12-16 17:13:58 -0500463 SkScalar w = r.width();
464 SkScalar h = r.height();
465
Mike Reed00a97642020-01-25 18:42:23 -0500466 SkM44 camera = Sk3LookAt(fEye, fCOA, fUp),
467 perspective = Sk3Perspective(fNear, fFar, fAngle),
468 translate = SkM44::Translate(fTrans.x, fTrans.y, fTrans.z),
469 viewport = SkM44::Translate(r.centerX(), r.centerY(), 0) *
470 SkM44::Scale(w*0.5f, h*0.5f, 1);
Mike Reed63edc572019-11-15 21:58:01 -0500471
Jim Van Verthc3363152019-12-03 12:05:14 -0500472 return viewport * perspective * camera * translate * fRot * inv(viewport);
Mike Reed63edc572019-11-15 21:58:01 -0500473 }
474
Mike Reedcbeabd92019-12-16 17:13:58 -0500475 bool onChar(SkUnichar uni) override {
476 float delta = SK_ScalarPI / 30;
477 switch (uni) {
478 case '8': this->rotate( delta, 0, 0); return true;
479 case '2': this->rotate(-delta, 0, 0); return true;
480 case '4': this->rotate(0, delta, 0); return true;
481 case '6': this->rotate(0, -delta, 0); return true;
482 case '-': this->rotate(0, 0, delta); return true;
483 case '+': this->rotate(0, 0, -delta); return true;
484
Mike Reed00a97642020-01-25 18:42:23 -0500485 case 'i': fTrans.z += 0.1f; SkDebugf("z %g\n", fTrans.z); return true;
486 case 'k': fTrans.z -= 0.1f; SkDebugf("z %g\n", fTrans.z); return true;
Mike Reedcbeabd92019-12-16 17:13:58 -0500487
488 case 'n': fNear += 0.1f; SkDebugf("near %g\n", fNear); return true;
489 case 'N': fNear -= 0.1f; SkDebugf("near %g\n", fNear); return true;
490 case 'f': fFar += 0.1f; SkDebugf("far %g\n", fFar); return true;
491 case 'F': fFar -= 0.1f; SkDebugf("far %g\n", fFar); return true;
492 default: break;
493 }
494 return false;
495 }
496};
497
498class HalfPlaneView3 : public SampleCameraView {
499 SkPath fPath;
500 sk_sp<SkShader> fShader;
501 bool fShowUnclipped = false;
502
503 SkString name() override { return SkString("halfplane3"); }
504
505 void onOnceBeforeDraw() override {
506 fPath = make_path();
507 fShader = GetResourceAsImage("images/mandrill_128.png")
Mike Reed1f607332020-05-21 12:11:27 -0400508 ->makeShader(SkMatrix::Scale(3, 3));
Mike Reedcbeabd92019-12-16 17:13:58 -0500509 }
510
511 bool onChar(SkUnichar uni) override {
512 switch (uni) {
513 case 'u': fShowUnclipped = !fShowUnclipped; return true;
514 default: break;
515 }
516 return this->SampleCameraView::onChar(uni);
517 }
518
Mike Reed63edc572019-11-15 21:58:01 -0500519 void onDrawContent(SkCanvas* canvas) override {
Mike Reed00a97642020-01-25 18:42:23 -0500520 SkM44 mx = this->get44({0, 0, 400, 400});
Mike Reed63edc572019-11-15 21:58:01 -0500521
522 SkPaint paint;
523 paint.setColor({0.75, 0.75, 0.75, 1});
524 canvas->drawPath(fPath, paint);
525
526 paint.setShader(fShader);
527
Mike Reed6344c292019-12-04 12:45:39 -0500528 if (fShowUnclipped) {
529 canvas->save();
Mike Reed3ef77dd2020-04-06 10:41:09 -0400530 canvas->concat(mx);
Mike Reed6344c292019-12-04 12:45:39 -0500531 paint.setAlphaf(0.33f);
532 canvas->drawPath(fPath, paint);
533 paint.setAlphaf(1.f);
534 canvas->restore();
535 }
536
Mike Reed6344c292019-12-04 12:45:39 -0500537
538 SkColor planeColor = SK_ColorBLUE;
539 SkPath clippedPath, *path = &fPath;
Mike Reed00a97642020-01-25 18:42:23 -0500540 if (SkPathPriv::PerspectiveClip(fPath, mx.asM33(), &clippedPath)) {
Mike Reed6344c292019-12-04 12:45:39 -0500541 path = &clippedPath;
542 planeColor = SK_ColorRED;
543 }
Mike Reed63edc572019-11-15 21:58:01 -0500544 canvas->save();
Mike Reed3ef77dd2020-04-06 10:41:09 -0400545 canvas->concat(mx);
Mike Reed6344c292019-12-04 12:45:39 -0500546 canvas->drawPath(*path, paint);
Mike Reed63edc572019-11-15 21:58:01 -0500547 canvas->restore();
548
Mike Reed00a97642020-01-25 18:42:23 -0500549 SkHalfPlane hpw = half_plane_w0(mx.asM33());
Mike Reed6344c292019-12-04 12:45:39 -0500550 draw_halfplane(canvas, hpw, planeColor);
Mike Reed63edc572019-11-15 21:58:01 -0500551 }
Mike Reed63edc572019-11-15 21:58:01 -0500552};
553DEF_SAMPLE( return new HalfPlaneView3(); )
Mike Reedcbeabd92019-12-16 17:13:58 -0500554
555class HalfPlaneCoons : public SampleCameraView {
556 SkPoint fPatch[12];
Mike Reed190b82d2019-12-17 17:25:27 -0500557 SkColor fColors[4] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK };
558 SkPoint fTex[4] = {{0, 0}, {256, 0}, {256, 256}, {0, 256}};
559 sk_sp<SkShader> fShader;
560
561 bool fShowHandles = false;
562 bool fShowSkeleton = false;
563 bool fShowTex = false;
Mike Reedcbeabd92019-12-16 17:13:58 -0500564
565 SkString name() override { return SkString("halfplane-coons"); }
566
567 void onOnceBeforeDraw() override {
568 fPatch[0] = { 0, 0 };
569 fPatch[1] = { 100, 0 };
570 fPatch[2] = { 200, 0 };
571 fPatch[3] = { 300, 0 };
572 fPatch[4] = { 300, 100 };
573 fPatch[5] = { 300, 200 };
574 fPatch[6] = { 300, 300 };
575 fPatch[7] = { 200, 300 };
576 fPatch[8] = { 100, 300 };
577 fPatch[9] = { 0, 300 };
578 fPatch[10] = { 0, 200 };
579 fPatch[11] = { 0, 100 };
Mike Reed190b82d2019-12-17 17:25:27 -0500580
581 fShader = GetResourceAsImage("images/mandrill_256.png")->makeShader();
Mike Reedcbeabd92019-12-16 17:13:58 -0500582 }
583
584 void onDrawContent(SkCanvas* canvas) override {
Mike Reedcbeabd92019-12-16 17:13:58 -0500585 SkPaint paint;
586
587 canvas->save();
Mike Reed3ef77dd2020-04-06 10:41:09 -0400588 canvas->concat(this->get44({0, 0, 300, 300}));
Mike Reed190b82d2019-12-17 17:25:27 -0500589
590 const SkPoint* tex = nullptr;
591 const SkColor* col = nullptr;
592 if (!fShowSkeleton) {
593 if (fShowTex) {
594 paint.setShader(fShader);
595 tex = fTex;
596 } else {
597 col = fColors;
598 }
599 }
600 canvas->drawPatch(fPatch, col, tex, SkBlendMode::kSrc, paint);
601 paint.setShader(nullptr);
602
603 if (fShowHandles) {
604 paint.setAntiAlias(true);
605 paint.setStrokeCap(SkPaint::kRound_Cap);
606 paint.setStrokeWidth(8);
607 canvas->drawPoints(SkCanvas::kPoints_PointMode, 12, fPatch, paint);
608 paint.setColor(SK_ColorWHITE);
609 paint.setStrokeWidth(6);
610 canvas->drawPoints(SkCanvas::kPoints_PointMode, 12, fPatch, paint);
611 }
612
Mike Reedcbeabd92019-12-16 17:13:58 -0500613 canvas->restore();
614 }
Mike Reed190b82d2019-12-17 17:25:27 -0500615
616 Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
617 auto dist = [](SkPoint a, SkPoint b) { return (b - a).length(); };
618
619 const float tol = 15;
620 for (int i = 0; i < 12; ++i) {
621 if (dist({x,y}, fPatch[i]) <= tol) {
Mike Reed0ce3e882020-04-22 11:09:30 -0400622 return new Click([this, i](Click* c) {
623 fPatch[i] = c->fCurr;
624 return true;
625 });
Mike Reed190b82d2019-12-17 17:25:27 -0500626 }
627 }
628 return nullptr;
629 }
630
Mike Reed190b82d2019-12-17 17:25:27 -0500631 bool onChar(SkUnichar uni) override {
632 switch (uni) {
633 case 'h': fShowHandles = !fShowHandles; return true;
Mike Reedc8803462019-12-18 13:34:15 -0500634 case 'k': fShowSkeleton = !fShowSkeleton; return true;
Mike Reed190b82d2019-12-17 17:25:27 -0500635 case 't': fShowTex = !fShowTex; return true;
636 default: break;
637 }
638 return this->SampleCameraView::onChar(uni);
639 }
640
Mike Reedcbeabd92019-12-16 17:13:58 -0500641};
642DEF_SAMPLE( return new HalfPlaneCoons(); )