blob: 92fe17728c1cc672b23f53f7f0bcf71689a7f5ff [file] [log] [blame]
Chris Daltonb832ce62020-01-06 19:49:37 -07001/*
2 * Copyright 2019 Google LLC.
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 "include/core/SkCanvas.h"
9#include "samplecode/Sample.h"
10#include "src/core/SkPathPriv.h"
11#include "tools/ToolUtils.h"
12
13#if SK_SUPPORT_GPU
14
15#include "include/gpu/GrContext.h"
16#include "src/gpu/GrClip.h"
17#include "src/gpu/GrContextPriv.h"
18#include "src/gpu/GrMemoryPool.h"
19#include "src/gpu/GrRenderTargetContext.h"
20#include "src/gpu/GrRenderTargetContextPriv.h"
21#include "src/gpu/tessellate/GrTessellatePathOp.h"
22
23// This sample enables wireframe and visualizes the triangulation generated by
24// GrTessellateWedgeShader.
25class TessellatedWedgeView : public Sample {
26public:
27 TessellatedWedgeView() {
Chris Daltonf9aea7f2020-01-21 11:19:26 -070028#if 0
29 fPath.moveTo(1, 0);
30 int numSides = 32 * 3;
31 for (int i = 1; i < numSides; ++i) {
32 float theta = 2*3.1415926535897932384626433832785 * i / numSides;
33 fPath.lineTo(std::cos(theta), std::sin(theta));
34 }
35 fPath.transform(SkMatrix::MakeScale(200, 200));
36 fPath.transform(SkMatrix::MakeTrans(300, 300));
37#else
Chris Daltonb832ce62020-01-06 19:49:37 -070038 fPath.moveTo(100, 200);
39 fPath.cubicTo(100, 100, 400, 100, 400, 200);
40 fPath.lineTo(250, 500);
Chris Daltonf9aea7f2020-01-21 11:19:26 -070041#endif
Chris Daltonb832ce62020-01-06 19:49:37 -070042 }
43
44private:
45 void onDrawContent(SkCanvas*) override;
46 Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
47 bool onClick(Sample::Click*) override;
48 bool onChar(SkUnichar) override;
49
50 SkString name() override { return SkString("TessellatedWedge"); }
51
52 SkMatrix fLastViewMatrix = SkMatrix::I();
53 SkPath fPath;
54 GrTessellatePathOp::Flags fFlags = GrTessellatePathOp::Flags::kWireframe;
55
56 class Click;
57};
58
59void TessellatedWedgeView::onDrawContent(SkCanvas* canvas) {
60 canvas->clear(SK_ColorBLACK);
61
62 GrContext* ctx = canvas->getGrContext();
63 GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
64
65 SkString error;
66 if (!rtc || !ctx) {
67 error = "GPU Only.";
68 } else if (!ctx->priv().caps()->shaderCaps()->tessellationSupport()) {
69 error = "GPU tessellation not supported.";
70 } else if (1 == rtc->numSamples() && !ctx->priv().caps()->mixedSamplesSupport()) {
71 error = "MSAA/mixed samples only.";
72 }
73 if (!error.isEmpty()) {
74 SkFont font(nullptr, 20);
75 SkPaint captionPaint;
76 captionPaint.setColor(SK_ColorWHITE);
77 canvas->drawString(error.c_str(), 10, 30, font, captionPaint);
78 return;
79 }
80
81 GrPaint paint;
82 paint.setColor4f({1,0,1,1});
83
84 GrAAType aa;
85 if (rtc->numSamples() > 1) {
86 aa = GrAAType::kMSAA;
87 } else if (rtc->asRenderTargetProxy()->canUseMixedSamples(*ctx->priv().caps())) {
88 aa = GrAAType::kCoverage;
89 } else {
90 aa = GrAAType::kNone;
91 }
92
93 GrOpMemoryPool* pool = ctx->priv().opMemoryPool();
94 rtc->priv().testingOnly_addDrawOp(pool->allocate<GrTessellatePathOp>(
95 canvas->getTotalMatrix(), fPath, std::move(paint), aa, fFlags));
96
97 // Draw the path points.
98 SkPaint pointsPaint;
99 pointsPaint.setColor(SK_ColorBLUE);
100 pointsPaint.setStrokeWidth(8);
Chris Daltonf9aea7f2020-01-21 11:19:26 -0700101 SkPath devPath = fPath;
102 devPath.transform(canvas->getTotalMatrix());
103 {
104 SkAutoCanvasRestore acr(canvas, true);
105 canvas->setMatrix(SkMatrix::I());
106 canvas->drawPoints(SkCanvas::kPoints_PointMode, devPath.countPoints(),
107 SkPathPriv::PointData(devPath), pointsPaint);
108 }
Chris Daltonb832ce62020-01-06 19:49:37 -0700109
110 fLastViewMatrix = canvas->getTotalMatrix();
111}
112
113class TessellatedWedgeView::Click : public Sample::Click {
114public:
115 Click(int ptIdx) : fPtIdx(ptIdx) {}
116
117 void doClick(SkPath* path) {
118 if (fPtIdx >= 0) {
119 SkPoint pt = path->getPoint(fPtIdx);
120 ToolUtils::set_path_pt(fPtIdx, pt + fCurr - fPrev, path);
121 } else {
122 path->transform(
123 SkMatrix::MakeTrans(fCurr.x() - fPrev.x(), fCurr.y() - fPrev.y()), path);
124 }
125 }
126
127private:
128 int fPtIdx;
129};
130
131Sample::Click* TessellatedWedgeView::onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) {
132 const SkPoint* pts = SkPathPriv::PointData(fPath);
133 float fuzz = 20 / fLastViewMatrix.getMaxScale();
134 for (int i = 0; i < fPath.countPoints(); ++i) {
135 SkPoint screenPoint = pts[i];
136 if (fabs(x - screenPoint.x()) < fuzz && fabsf(y - screenPoint.y()) < fuzz) {
137 return new Click(i);
138 }
139 }
140 return new Click(-1);
141}
142
143bool TessellatedWedgeView::onClick(Sample::Click* click) {
144 Click* myClick = (Click*)click;
145 myClick->doClick(&fPath);
146 return true;
147}
148
149bool TessellatedWedgeView::onChar(SkUnichar unichar) {
150 switch (unichar) {
151 case 'w':
152 fFlags = (GrTessellatePathOp::Flags)(
153 (int)fFlags ^ (int)GrTessellatePathOp::Flags::kWireframe);
154 return true;
155 case 'D': {
156 fPath.dump();
157 return true;
158 }
159 }
160 return false;
161}
162
163DEF_SAMPLE(return new TessellatedWedgeView;)
164
165#endif // SK_SUPPORT_GPU