blob: 6465d75288e2248520546585a280cabcdb45d4ef [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
Robert Phillips30ebcf72020-07-09 13:25:17 -040015#include "include/gpu/GrRecordingContext.h"
Chris Daltonb832ce62020-01-06 19:49:37 -070016#include "src/gpu/GrClip.h"
Chris Daltonb832ce62020-01-06 19:49:37 -070017#include "src/gpu/GrMemoryPool.h"
Robert Phillips30ebcf72020-07-09 13:25:17 -040018#include "src/gpu/GrRecordingContextPriv.h"
Chris Daltonb832ce62020-01-06 19:49:37 -070019#include "src/gpu/GrRenderTargetContext.h"
20#include "src/gpu/GrRenderTargetContextPriv.h"
Chris Dalton078f8752020-07-30 19:50:46 -060021#include "src/gpu/tessellate/GrPathTessellateOp.h"
Chris Daltonb832ce62020-01-06 19:49:37 -070022
Chris Daltonb27f39c2020-11-23 09:30:24 -070023static float kConicWeight = .5;
24
Chris Daltonb832ce62020-01-06 19:49:37 -070025// This sample enables wireframe and visualizes the triangulation generated by
26// GrTessellateWedgeShader.
Chris Dalton0d0758e2020-05-29 10:51:08 -060027class TessellatedWedge : public Sample {
Chris Daltonb832ce62020-01-06 19:49:37 -070028public:
Chris Dalton0d0758e2020-05-29 10:51:08 -060029 TessellatedWedge() {
Chris Daltonf9aea7f2020-01-21 11:19:26 -070030#if 0
31 fPath.moveTo(1, 0);
32 int numSides = 32 * 3;
33 for (int i = 1; i < numSides; ++i) {
34 float theta = 2*3.1415926535897932384626433832785 * i / numSides;
35 fPath.lineTo(std::cos(theta), std::sin(theta));
36 }
Mike Reed1f607332020-05-21 12:11:27 -040037 fPath.transform(SkMatrix::Scale(200, 200));
38 fPath.transform(SkMatrix::Translate(300, 300));
Chris Daltonf9aea7f2020-01-21 11:19:26 -070039#else
Chris Daltonb27f39c2020-11-23 09:30:24 -070040 fPath.moveTo(100, 300);
41 fPath.conicTo(300, 100, 500, 300, kConicWeight);
42 fPath.cubicTo(433, 366, 366, 433, 300, 500);
Chris Daltonf9aea7f2020-01-21 11:19:26 -070043#endif
Chris Daltonb832ce62020-01-06 19:49:37 -070044 }
45
46private:
47 void onDrawContent(SkCanvas*) override;
48 Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override;
49 bool onClick(Sample::Click*) override;
50 bool onChar(SkUnichar) override;
51
52 SkString name() override { return SkString("TessellatedWedge"); }
53
54 SkMatrix fLastViewMatrix = SkMatrix::I();
55 SkPath fPath;
Chris Daltonb96995d2020-06-04 16:44:29 -060056 GrTessellationPathRenderer::OpFlags fOpFlags = GrTessellationPathRenderer::OpFlags::kWireframe;
Chris Daltonb832ce62020-01-06 19:49:37 -070057
58 class Click;
59};
60
Chris Dalton0d0758e2020-05-29 10:51:08 -060061void TessellatedWedge::onDrawContent(SkCanvas* canvas) {
Chris Daltonb832ce62020-01-06 19:49:37 -070062 canvas->clear(SK_ColorBLACK);
63
Robert Phillips30ebcf72020-07-09 13:25:17 -040064 auto ctx = canvas->recordingContext();
Chris Daltonb832ce62020-01-06 19:49:37 -070065 GrRenderTargetContext* rtc = canvas->internal_private_accessTopLayerRenderTargetContext();
66
67 SkString error;
68 if (!rtc || !ctx) {
69 error = "GPU Only.";
Chris Dalton0d0758e2020-05-29 10:51:08 -060070 } else if (!ctx->priv().caps()->drawInstancedSupport()) {
71 error = "Instanced rendering not supported.";
Chris Daltonb832ce62020-01-06 19:49:37 -070072 } else if (1 == rtc->numSamples() && !ctx->priv().caps()->mixedSamplesSupport()) {
73 error = "MSAA/mixed samples only.";
74 }
75 if (!error.isEmpty()) {
76 SkFont font(nullptr, 20);
77 SkPaint captionPaint;
78 captionPaint.setColor(SK_ColorWHITE);
79 canvas->drawString(error.c_str(), 10, 30, font, captionPaint);
80 return;
81 }
82
83 GrPaint paint;
84 paint.setColor4f({1,0,1,1});
85
86 GrAAType aa;
87 if (rtc->numSamples() > 1) {
88 aa = GrAAType::kMSAA;
89 } else if (rtc->asRenderTargetProxy()->canUseMixedSamples(*ctx->priv().caps())) {
90 aa = GrAAType::kCoverage;
91 } else {
92 aa = GrAAType::kNone;
93 }
94
Herb Derbyc76d4092020-10-07 16:46:15 -040095 rtc->priv().testingOnly_addDrawOp(GrOp::Make<GrPathTessellateOp>(
96 ctx, canvas->getTotalMatrix(), fPath, std::move(paint), aa, fOpFlags));
Chris Daltonb832ce62020-01-06 19:49:37 -070097
98 // Draw the path points.
99 SkPaint pointsPaint;
100 pointsPaint.setColor(SK_ColorBLUE);
101 pointsPaint.setStrokeWidth(8);
Chris Daltonf9aea7f2020-01-21 11:19:26 -0700102 SkPath devPath = fPath;
103 devPath.transform(canvas->getTotalMatrix());
104 {
105 SkAutoCanvasRestore acr(canvas, true);
106 canvas->setMatrix(SkMatrix::I());
107 canvas->drawPoints(SkCanvas::kPoints_PointMode, devPath.countPoints(),
108 SkPathPriv::PointData(devPath), pointsPaint);
109 }
Chris Daltonb832ce62020-01-06 19:49:37 -0700110
111 fLastViewMatrix = canvas->getTotalMatrix();
Chris Daltonb27f39c2020-11-23 09:30:24 -0700112
113
114 SkString caption;
115 caption.printf("w=%f (=/- and +/_ to change)", kConicWeight);
116 SkFont font(nullptr, 20);
117 SkPaint captionPaint;
118 captionPaint.setColor(SK_ColorWHITE);
119 canvas->drawString(caption, 10, 30, font, captionPaint);
Chris Daltonb832ce62020-01-06 19:49:37 -0700120}
121
Chris Dalton0d0758e2020-05-29 10:51:08 -0600122class TessellatedWedge::Click : public Sample::Click {
Chris Daltonb832ce62020-01-06 19:49:37 -0700123public:
124 Click(int ptIdx) : fPtIdx(ptIdx) {}
125
126 void doClick(SkPath* path) {
127 if (fPtIdx >= 0) {
128 SkPoint pt = path->getPoint(fPtIdx);
Chris Dalton8d3eb242020-05-04 10:43:33 -0600129 SkPathPriv::UpdatePathPoint(path, fPtIdx, pt + fCurr - fPrev);
Chris Daltonb832ce62020-01-06 19:49:37 -0700130 } else {
131 path->transform(
Mike Reed1f607332020-05-21 12:11:27 -0400132 SkMatrix::Translate(fCurr.x() - fPrev.x(), fCurr.y() - fPrev.y()), path);
Chris Daltonb832ce62020-01-06 19:49:37 -0700133 }
134 }
135
136private:
137 int fPtIdx;
138};
139
Chris Dalton0d0758e2020-05-29 10:51:08 -0600140Sample::Click* TessellatedWedge::onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) {
Chris Daltonb832ce62020-01-06 19:49:37 -0700141 const SkPoint* pts = SkPathPriv::PointData(fPath);
142 float fuzz = 20 / fLastViewMatrix.getMaxScale();
143 for (int i = 0; i < fPath.countPoints(); ++i) {
144 SkPoint screenPoint = pts[i];
145 if (fabs(x - screenPoint.x()) < fuzz && fabsf(y - screenPoint.y()) < fuzz) {
146 return new Click(i);
147 }
148 }
149 return new Click(-1);
150}
151
Chris Dalton0d0758e2020-05-29 10:51:08 -0600152bool TessellatedWedge::onClick(Sample::Click* click) {
Chris Daltonb832ce62020-01-06 19:49:37 -0700153 Click* myClick = (Click*)click;
154 myClick->doClick(&fPath);
155 return true;
156}
157
Chris Daltonb27f39c2020-11-23 09:30:24 -0700158static SkPath update_weight(const SkPath& path) {
159 SkPath path_;
160 for (auto [verb, pts, _] : SkPathPriv::Iterate(path)) {
161 switch (verb) {
162 case SkPathVerb::kMove:
163 path_.moveTo(pts[0]);
164 break;
165 case SkPathVerb::kLine:
166 path_.lineTo(pts[1]);
167 break;
168 case SkPathVerb::kQuad:
169 path_.quadTo(pts[1], pts[2]);
170 break;
171 case SkPathVerb::kCubic:
172 path_.cubicTo(pts[1], pts[2], pts[3]);
173 break;
174 case SkPathVerb::kConic:
175 path_.conicTo(pts[1], pts[2], (kConicWeight != 1) ? kConicWeight : .99f);
176 break;
177 default:
178 SkUNREACHABLE;
179 }
180 }
181 return path_;
182}
183
Chris Dalton0d0758e2020-05-29 10:51:08 -0600184bool TessellatedWedge::onChar(SkUnichar unichar) {
Chris Daltonb832ce62020-01-06 19:49:37 -0700185 switch (unichar) {
186 case 'w':
Chris Daltonb96995d2020-06-04 16:44:29 -0600187 fOpFlags = (GrTessellationPathRenderer::OpFlags)(
188 (int)fOpFlags ^ (int)GrTessellationPathRenderer::OpFlags::kWireframe);
Chris Daltonb832ce62020-01-06 19:49:37 -0700189 return true;
190 case 'D': {
191 fPath.dump();
192 return true;
193 }
Chris Daltonb27f39c2020-11-23 09:30:24 -0700194 case '+':
195 kConicWeight *= 2;
196 fPath = update_weight(fPath);
197 return true;
198 case '=':
199 kConicWeight *= 5/4.f;
200 fPath = update_weight(fPath);
201 return true;
202 case '_':
203 kConicWeight *= .5f;
204 fPath = update_weight(fPath);
205 return true;
206 case '-':
207 kConicWeight *= 4/5.f;
208 fPath = update_weight(fPath);
209 return true;
Chris Daltonb832ce62020-01-06 19:49:37 -0700210 }
211 return false;
212}
213
Chris Dalton0d0758e2020-05-29 10:51:08 -0600214Sample* MakeTessellatedWedgeSample() { return new TessellatedWedge; }
215static SampleRegistry gTessellatedWedgeSample(MakeTessellatedWedgeSample);
Chris Daltonb832ce62020-01-06 19:49:37 -0700216
217#endif // SK_SUPPORT_GPU