blob: 0b355beeba886738eebc4580add4921c1d47615e [file] [log] [blame]
robertphillips84b00882015-05-06 05:15:57 -07001/*
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#ifndef GrAAConvexTessellator_DEFINED
9#define GrAAConvexTessellator_DEFINED
10
11#include "SkColor.h"
fmalitabd5d7e72015-06-26 07:18:24 -070012#include "SkPaint.h"
Cary Clarkdf429f32017-11-08 11:44:31 -050013#include "SkPointPriv.h"
robertphillips84b00882015-05-06 05:15:57 -070014#include "SkScalar.h"
robertphillips8c170972016-09-22 12:42:30 -070015#include "SkStrokeRec.h"
robertphillips84b00882015-05-06 05:15:57 -070016#include "SkTDArray.h"
17
18class SkCanvas;
19class SkMatrix;
20class SkPath;
21
22//#define GR_AA_CONVEX_TESSELLATOR_VIZ 1
23
fmalitabd5d7e72015-06-26 07:18:24 -070024// device space distance which we inset / outset points in order to create the soft antialiased edge
25static const SkScalar kAntialiasingRadius = 0.5f;
26
robertphillips84b00882015-05-06 05:15:57 -070027class GrAAConvexTessellator;
28
29// The AAConvexTessellator holds the global pool of points and the triangulation
30// that connects them. It also drives the tessellation process.
31// The outward facing normals of the original polygon are stored (in 'fNorms') to service
32// computeDepthFromEdge requests.
33class GrAAConvexTessellator {
34public:
robertphillips8c170972016-09-22 12:42:30 -070035 GrAAConvexTessellator(SkStrokeRec::Style style = SkStrokeRec::kFill_Style,
36 SkScalar strokeWidth = -1.0f,
halcanary9d524f22016-03-29 09:03:52 -070037 SkPaint::Join join = SkPaint::Join::kBevel_Join,
fmalitabd5d7e72015-06-26 07:18:24 -070038 SkScalar miterLimit = 0.0f)
Cary Clarkdf429f32017-11-08 11:44:31 -050039 : fSide(SkPointPriv::kOn_Side)
fmalitabd5d7e72015-06-26 07:18:24 -070040 , fStrokeWidth(strokeWidth)
robertphillips8c170972016-09-22 12:42:30 -070041 , fStyle(style)
fmalitabd5d7e72015-06-26 07:18:24 -070042 , fJoin(join)
43 , fMiterLimit(miterLimit) {
robertphillips84b00882015-05-06 05:15:57 -070044 }
45
Cary Clarkdf429f32017-11-08 11:44:31 -050046 SkPointPriv::Side side() const { return fSide; }
robertphillips84b00882015-05-06 05:15:57 -070047
48 bool tessellate(const SkMatrix& m, const SkPath& path);
49
50 // The next five should only be called after tessellate to extract the result
51 int numPts() const { return fPts.count(); }
52 int numIndices() const { return fIndices.count(); }
53
54 const SkPoint& lastPoint() const { return fPts.top(); }
55 const SkPoint& point(int index) const { return fPts[index]; }
56 int index(int index) const { return fIndices[index]; }
fmalitabd5d7e72015-06-26 07:18:24 -070057 SkScalar coverage(int index) const { return fCoverages[index]; }
robertphillips84b00882015-05-06 05:15:57 -070058
59#if GR_AA_CONVEX_TESSELLATOR_VIZ
60 void draw(SkCanvas* canvas) const;
61#endif
62
63 // The tessellator can be reused for multiple paths by rewinding in between
64 void rewind();
65
66private:
halcanary9d524f22016-03-29 09:03:52 -070067 // CandidateVerts holds the vertices for the next ring while they are
robertphillips84b00882015-05-06 05:15:57 -070068 // being generated. Its main function is to de-dup the points.
69 class CandidateVerts {
70 public:
71 void setReserve(int numPts) { fPts.setReserve(numPts); }
72 void rewind() { fPts.rewind(); }
73
74 int numPts() const { return fPts.count(); }
75
76 const SkPoint& lastPoint() const { return fPts.top().fPt; }
77 const SkPoint& firstPoint() const { return fPts[0].fPt; }
78 const SkPoint& point(int index) const { return fPts[index].fPt; }
79
80 int originatingIdx(int index) const { return fPts[index].fOriginatingIdx; }
81 int origEdge(int index) const { return fPts[index].fOrigEdgeId; }
82 bool needsToBeNew(int index) const { return fPts[index].fNeedsToBeNew; }
83
84 int addNewPt(const SkPoint& newPt, int originatingIdx, int origEdge, bool needsToBeNew) {
85 struct PointData* pt = fPts.push();
86 pt->fPt = newPt;
87 pt->fOrigEdgeId = origEdge;
88 pt->fOriginatingIdx = originatingIdx;
89 pt->fNeedsToBeNew = needsToBeNew;
90 return fPts.count() - 1;
91 }
92
93 int fuseWithPrior(int origEdgeId) {
94 fPts.top().fOrigEdgeId = origEdgeId;
95 fPts.top().fOriginatingIdx = -1;
96 fPts.top().fNeedsToBeNew = true;
97 return fPts.count() - 1;
98 }
99
100 int fuseWithNext() {
101 fPts[0].fOriginatingIdx = -1;
102 fPts[0].fNeedsToBeNew = true;
103 return 0;
104 }
105
106 int fuseWithBoth() {
107 if (fPts.count() > 1) {
108 fPts.pop();
109 }
110
111 fPts[0].fOriginatingIdx = -1;
112 fPts[0].fNeedsToBeNew = true;
113 return 0;
114 }
115
116 private:
117 struct PointData {
118 SkPoint fPt;
119 int fOriginatingIdx;
120 int fOrigEdgeId;
121 bool fNeedsToBeNew;
122 };
123
124 SkTDArray<struct PointData> fPts;
125 };
126
127 // The Ring holds a set of indices into the global pool that together define
128 // a single polygon inset.
129 class Ring {
130 public:
131 void setReserve(int numPts) { fPts.setReserve(numPts); }
132 void rewind() { fPts.rewind(); }
133
134 int numPts() const { return fPts.count(); }
135
136 void addIdx(int index, int origEdgeId) {
137 struct PointData* pt = fPts.push();
138 pt->fIndex = index;
139 pt->fOrigEdgeId = origEdgeId;
140 }
141
robertphillips8c170972016-09-22 12:42:30 -0700142 // Upgrade this ring so that it can behave like an originating ring
143 void makeOriginalRing() {
144 for (int i = 0; i < fPts.count(); ++i) {
145 fPts[i].fOrigEdgeId = fPts[i].fIndex;
Ben Wagner63fd7602017-10-09 15:45:33 -0400146 }
robertphillips8c170972016-09-22 12:42:30 -0700147 }
148
robertphillips84b00882015-05-06 05:15:57 -0700149 // init should be called after all the indices have been added (via addIdx)
150 void init(const GrAAConvexTessellator& tess);
151 void init(const SkTDArray<SkVector>& norms, const SkTDArray<SkVector>& bisectors);
152
153 const SkPoint& norm(int index) const { return fPts[index].fNorm; }
154 const SkPoint& bisector(int index) const { return fPts[index].fBisector; }
155 int index(int index) const { return fPts[index].fIndex; }
156 int origEdgeID(int index) const { return fPts[index].fOrigEdgeId; }
fmalitabd5d7e72015-06-26 07:18:24 -0700157 void setOrigEdgeId(int index, int id) { fPts[index].fOrigEdgeId = id; }
robertphillips84b00882015-05-06 05:15:57 -0700158
159 #if GR_AA_CONVEX_TESSELLATOR_VIZ
160 void draw(SkCanvas* canvas, const GrAAConvexTessellator& tess) const;
161 #endif
162
163 private:
164 void computeNormals(const GrAAConvexTessellator& result);
robertphillips364ad002015-05-20 11:49:55 -0700165 void computeBisectors(const GrAAConvexTessellator& tess);
robertphillips84b00882015-05-06 05:15:57 -0700166
167 SkDEBUGCODE(bool isConvex(const GrAAConvexTessellator& tess) const;)
168
169 struct PointData {
170 SkPoint fNorm;
171 SkPoint fBisector;
172 int fIndex;
173 int fOrigEdgeId;
174 };
175
176 SkTDArray<PointData> fPts;
177 };
178
ethannicholasfab4a9b2016-08-26 11:03:32 -0700179 // Represents whether a given point is within a curve. A point is inside a curve only if it is
180 // an interior point within a quad, cubic, or conic, or if it is the endpoint of a quad, cubic,
181 // or conic with another curve meeting it at (more or less) the same angle.
182 enum CurveState {
183 // point is a sharp vertex
184 kSharp_CurveState,
185 // endpoint of a curve with the other side's curvature not yet determined
186 kIndeterminate_CurveState,
187 // point is in the interior of a curve
188 kCurve_CurveState
189 };
190
robertphillips84b00882015-05-06 05:15:57 -0700191 bool movable(int index) const { return fMovable[index]; }
192
193 // Movable points are those that can be slid along their bisector.
194 // Basically, a point is immovable if it is part of the original
195 // polygon or it results from the fusing of two bisectors.
ethannicholasfab4a9b2016-08-26 11:03:32 -0700196 int addPt(const SkPoint& pt, SkScalar depth, SkScalar coverage, bool movable, CurveState curve);
robertphillips84b00882015-05-06 05:15:57 -0700197 void popLastPt();
198 void popFirstPtShuffle();
199
fmalitabd5d7e72015-06-26 07:18:24 -0700200 void updatePt(int index, const SkPoint& pt, SkScalar depth, SkScalar coverage);
robertphillips84b00882015-05-06 05:15:57 -0700201
202 void addTri(int i0, int i1, int i2);
203
204 void reservePts(int count) {
205 fPts.setReserve(count);
fmalitabd5d7e72015-06-26 07:18:24 -0700206 fCoverages.setReserve(count);
robertphillips84b00882015-05-06 05:15:57 -0700207 fMovable.setReserve(count);
208 }
209
210 SkScalar computeDepthFromEdge(int edgeIdx, const SkPoint& p) const;
211
212 bool computePtAlongBisector(int startIdx, const SkPoint& bisector,
213 int edgeIdx, SkScalar desiredDepth,
214 SkPoint* result) const;
215
Robert Phillips1d089982016-09-26 14:07:48 -0400216 void lineTo(const SkPoint& p, CurveState curve);
fmalitabd5d7e72015-06-26 07:18:24 -0700217
ethannicholasfab4a9b2016-08-26 11:03:32 -0700218 void lineTo(const SkMatrix& m, SkPoint p, CurveState curve);
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700219
Robert Phillips1d089982016-09-26 14:07:48 -0400220 void quadTo(const SkPoint pts[3]);
fmalitabd5d7e72015-06-26 07:18:24 -0700221
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700222 void quadTo(const SkMatrix& m, SkPoint pts[3]);
223
224 void cubicTo(const SkMatrix& m, SkPoint pts[4]);
225
226 void conicTo(const SkMatrix& m, SkPoint pts[3], SkScalar w);
227
robertphillips84b00882015-05-06 05:15:57 -0700228 void terminate(const Ring& lastRing);
229
230 // return false on failure/degenerate path
231 bool extractFromPath(const SkMatrix& m, const SkPath& path);
232 void computeBisectors();
Brian Salomon0235c642018-08-31 12:04:18 -0400233 void computeNormals();
robertphillips84b00882015-05-06 05:15:57 -0700234
235 void fanRing(const Ring& ring);
robertphillips84b00882015-05-06 05:15:57 -0700236
237 Ring* getNextRing(Ring* lastRing);
238
halcanary9d524f22016-03-29 09:03:52 -0700239 void createOuterRing(const Ring& previousRing, SkScalar outset, SkScalar coverage,
fmalitabd5d7e72015-06-26 07:18:24 -0700240 Ring* nextRing);
241
halcanary9d524f22016-03-29 09:03:52 -0700242 bool createInsetRings(Ring& previousRing, SkScalar initialDepth, SkScalar initialCoverage,
fmalitabd5d7e72015-06-26 07:18:24 -0700243 SkScalar targetDepth, SkScalar targetCoverage, Ring** finalRing);
244
halcanary9d524f22016-03-29 09:03:52 -0700245 bool createInsetRing(const Ring& lastRing, Ring* nextRing,
246 SkScalar initialDepth, SkScalar initialCoverage, SkScalar targetDepth,
fmalitabd5d7e72015-06-26 07:18:24 -0700247 SkScalar targetCoverage, bool forceNew);
robertphillips84b00882015-05-06 05:15:57 -0700248
249 void validate() const;
250
Robert Phillips1d089982016-09-26 14:07:48 -0400251 // fPts, fCoverages, fMovable & fCurveState should always have the same # of elements
ethannicholasfab4a9b2016-08-26 11:03:32 -0700252 SkTDArray<SkPoint> fPts;
253 SkTDArray<SkScalar> fCoverages;
robertphillips84b00882015-05-06 05:15:57 -0700254 // movable points are those that can be slid further along their bisector
ethannicholasfab4a9b2016-08-26 11:03:32 -0700255 SkTDArray<bool> fMovable;
Robert Phillips1d089982016-09-26 14:07:48 -0400256 // Tracks whether a given point is interior to a curve. Such points are
257 // assumed to have shallow curvature.
258 SkTDArray<CurveState> fCurveState;
robertphillips84b00882015-05-06 05:15:57 -0700259
260 // The outward facing normals for the original polygon
ethannicholasfab4a9b2016-08-26 11:03:32 -0700261 SkTDArray<SkVector> fNorms;
robertphillips84b00882015-05-06 05:15:57 -0700262 // The inward facing bisector at each point in the original polygon. Only
263 // needed for exterior ring creation and then handed off to the initial ring.
ethannicholasfab4a9b2016-08-26 11:03:32 -0700264 SkTDArray<SkVector> fBisectors;
ethannicholas1a1b3ac2015-06-10 12:11:17 -0700265
Cary Clarkdf429f32017-11-08 11:44:31 -0500266 SkPointPriv::Side fSide; // winding of the original polygon
robertphillips84b00882015-05-06 05:15:57 -0700267
268 // The triangulation of the points
ethannicholasfab4a9b2016-08-26 11:03:32 -0700269 SkTDArray<int> fIndices;
robertphillips84b00882015-05-06 05:15:57 -0700270
ethannicholasfab4a9b2016-08-26 11:03:32 -0700271 Ring fInitialRing;
robertphillips84b00882015-05-06 05:15:57 -0700272#if GR_AA_CONVEX_TESSELLATOR_VIZ
273 // When visualizing save all the rings
ethannicholasfab4a9b2016-08-26 11:03:32 -0700274 SkTDArray<Ring*> fRings;
robertphillips84b00882015-05-06 05:15:57 -0700275#else
ethannicholasfab4a9b2016-08-26 11:03:32 -0700276 Ring fRings[2];
robertphillips84b00882015-05-06 05:15:57 -0700277#endif
ethannicholasfab4a9b2016-08-26 11:03:32 -0700278 CandidateVerts fCandidateVerts;
robertphillips84b00882015-05-06 05:15:57 -0700279
robertphillips8c170972016-09-22 12:42:30 -0700280 // the stroke width is only used for stroke or stroke-and-fill styles
ethannicholasfab4a9b2016-08-26 11:03:32 -0700281 SkScalar fStrokeWidth;
robertphillips8c170972016-09-22 12:42:30 -0700282 SkStrokeRec::Style fStyle;
fmalitabd5d7e72015-06-26 07:18:24 -0700283
ethannicholasfab4a9b2016-08-26 11:03:32 -0700284 SkPaint::Join fJoin;
fmalitabd5d7e72015-06-26 07:18:24 -0700285
ethannicholasfab4a9b2016-08-26 11:03:32 -0700286 SkScalar fMiterLimit;
robertphillips84b00882015-05-06 05:15:57 -0700287
ethannicholasfab4a9b2016-08-26 11:03:32 -0700288 SkTDArray<SkPoint> fPointBuffer;
robertphillips84b00882015-05-06 05:15:57 -0700289};
290
291
292#endif