xref: /aosp_15_r20/external/skia/src/gpu/ganesh/geometry/GrAAConvexTessellator.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
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 "include/core/SkPaint.h"
12 #include "include/core/SkPoint.h"
13 #include "include/core/SkScalar.h"
14 #include "include/core/SkStrokeRec.h"
15 #include "include/private/base/SkDebug.h"
16 #include "include/private/base/SkTDArray.h"
17 #include "src/core/SkPointPriv.h"
18 
19 class SkMatrix;
20 class SkPath;
21 
22 //#define GR_AA_CONVEX_TESSELLATOR_VIZ 1
23 
24 // device space distance which we inset / outset points in order to create the soft antialiased edge
25 static const SkScalar kAntialiasingRadius = 0.5f;
26 
27 // The AAConvexTessellator holds the global pool of points and the triangulation
28 // that connects them. It also drives the tessellation process.
29 // The outward facing normals of the original polygon are stored (in 'fNorms') to service
30 // computeDepthFromEdge requests.
31 class GrAAConvexTessellator {
32 public:
33     GrAAConvexTessellator(SkStrokeRec::Style style = SkStrokeRec::kFill_Style,
34                           SkScalar strokeWidth = -1.0f,
35                           SkPaint::Join join = SkPaint::Join::kBevel_Join,
36                           SkScalar miterLimit = 0.0f)
fSide(SkPointPriv::kOn_Side)37         : fSide(SkPointPriv::kOn_Side)
38         , fStrokeWidth(strokeWidth)
39         , fStyle(style)
40         , fJoin(join)
41         , fMiterLimit(miterLimit) {
42     }
43 
side()44     SkPointPriv::Side side() const { return fSide; }
45 
46     bool tessellate(const SkMatrix& m, const SkPath& path);
47 
48     // The next five should only be called after tessellate to extract the result
numPts()49     int numPts() const { return fPts.size(); }
numIndices()50     int numIndices() const { return fIndices.size(); }
51 
lastPoint()52     const SkPoint& lastPoint() const { return fPts.back(); }
point(int index)53     const SkPoint& point(int index) const { return fPts[index]; }
index(int index)54     int index(int index) const { return fIndices[index]; }
coverage(int index)55     SkScalar coverage(int index) const { return fCoverages[index]; }
56 
57 #if GR_AA_CONVEX_TESSELLATOR_VIZ
58     void draw(SkCanvas* canvas) const;
59 #endif
60 
61     // The tessellator can be reused for multiple paths by clearing in between
62     void rewind();
63 
64 private:
65     // CandidateVerts holds the vertices for the next ring while they are
66     // being generated. Its main function is to de-dup the points.
67     class CandidateVerts {
68     public:
setReserve(int numPts)69         void setReserve(int numPts) { fPts.reserve(numPts); }
rewind()70         void rewind() { fPts.clear(); }
71 
numPts()72         int numPts() const { return fPts.size(); }
73 
lastPoint()74         const SkPoint& lastPoint() const { return fPts.back().fPt; }
firstPoint()75         const SkPoint& firstPoint() const { return fPts[0].fPt; }
point(int index)76         const SkPoint& point(int index) const { return fPts[index].fPt; }
77 
originatingIdx(int index)78         int originatingIdx(int index) const { return fPts[index].fOriginatingIdx; }
origEdge(int index)79         int origEdge(int index) const { return fPts[index].fOrigEdgeId; }
needsToBeNew(int index)80         bool needsToBeNew(int index) const { return fPts[index].fNeedsToBeNew; }
81 
addNewPt(const SkPoint & newPt,int originatingIdx,int origEdge,bool needsToBeNew)82         int addNewPt(const SkPoint& newPt, int originatingIdx, int origEdge, bool needsToBeNew) {
83             struct PointData* pt = fPts.append();
84             pt->fPt = newPt;
85             pt->fOrigEdgeId = origEdge;
86             pt->fOriginatingIdx = originatingIdx;
87             pt->fNeedsToBeNew = needsToBeNew;
88             return fPts.size() - 1;
89         }
90 
fuseWithPrior(int origEdgeId)91         int fuseWithPrior(int origEdgeId) {
92             fPts.back().fOrigEdgeId = origEdgeId;
93             fPts.back().fOriginatingIdx = -1;
94             fPts.back().fNeedsToBeNew = true;
95             return fPts.size() - 1;
96         }
97 
fuseWithNext()98         int fuseWithNext() {
99             fPts[0].fOriginatingIdx = -1;
100             fPts[0].fNeedsToBeNew = true;
101             return 0;
102         }
103 
fuseWithBoth()104         int fuseWithBoth() {
105             if (fPts.size() > 1) {
106                 fPts.pop_back();
107             }
108 
109             fPts[0].fOriginatingIdx = -1;
110             fPts[0].fNeedsToBeNew = true;
111             return 0;
112         }
113 
114     private:
115         struct PointData {
116             SkPoint fPt;
117             int     fOriginatingIdx;
118             int     fOrigEdgeId;
119             bool    fNeedsToBeNew;
120         };
121 
122         SkTDArray<struct PointData> fPts;
123     };
124 
125     // The Ring holds a set of indices into the global pool that together define
126     // a single polygon inset.
127     class Ring {
128     public:
setReserve(int numPts)129         void setReserve(int numPts) { fPts.reserve(numPts); }
rewind()130         void rewind() { fPts.clear(); }
131 
numPts()132         int numPts() const { return fPts.size(); }
133 
addIdx(int index,int origEdgeId)134         void addIdx(int index, int origEdgeId) {
135             struct PointData* pt = fPts.append();
136             pt->fIndex = index;
137             pt->fOrigEdgeId = origEdgeId;
138         }
139 
140         // Upgrade this ring so that it can behave like an originating ring
makeOriginalRing()141         void makeOriginalRing() {
142             for (int i = 0; i < fPts.size(); ++i) {
143                 fPts[i].fOrigEdgeId = fPts[i].fIndex;
144             }
145         }
146 
147         // init should be called after all the indices have been added (via addIdx)
148         void init(const GrAAConvexTessellator& tess);
149         void init(const SkTDArray<SkVector>& norms, const SkTDArray<SkVector>& bisectors);
150 
norm(int index)151         const SkPoint& norm(int index) const { return fPts[index].fNorm; }
bisector(int index)152         const SkPoint& bisector(int index) const { return fPts[index].fBisector; }
index(int index)153         int index(int index) const { return fPts[index].fIndex; }
origEdgeID(int index)154         int origEdgeID(int index) const { return fPts[index].fOrigEdgeId; }
setOrigEdgeId(int index,int id)155         void setOrigEdgeId(int index, int id) { fPts[index].fOrigEdgeId = id; }
156 
157     #if GR_AA_CONVEX_TESSELLATOR_VIZ
158         void draw(SkCanvas* canvas, const GrAAConvexTessellator& tess) const;
159     #endif
160 
161     private:
162         void computeNormals(const GrAAConvexTessellator& result);
163         void computeBisectors(const GrAAConvexTessellator& tess);
164 
165         SkDEBUGCODE(bool isConvex(const GrAAConvexTessellator& tess) const;)
166 
167         struct PointData {
168             SkPoint fNorm;
169             SkPoint fBisector;
170             int     fIndex;
171             int     fOrigEdgeId;
172         };
173 
174         SkTDArray<PointData> fPts;
175     };
176 
177     // Represents whether a given point is within a curve. A point is inside a curve only if it is
178     // an interior point within a quad, cubic, or conic, or if it is the endpoint of a quad, cubic,
179     // or conic with another curve meeting it at (more or less) the same angle.
180     enum CurveState {
181         // point is a sharp vertex
182         kSharp_CurveState,
183         // endpoint of a curve with the other side's curvature not yet determined
184         kIndeterminate_CurveState,
185         // point is in the interior of a curve
186         kCurve_CurveState
187     };
188 
movable(int index)189     bool movable(int index) const { return fMovable[index]; }
190 
191     // Movable points are those that can be slid along their bisector.
192     // Basically, a point is immovable if it is part of the original
193     // polygon or it results from the fusing of two bisectors.
194     int addPt(const SkPoint& pt, SkScalar depth, SkScalar coverage, bool movable, CurveState curve);
195     void popLastPt();
196     void popFirstPtShuffle();
197 
198     void updatePt(int index, const SkPoint& pt, SkScalar depth, SkScalar coverage);
199 
200     void addTri(int i0, int i1, int i2);
201 
reservePts(int count)202     void reservePts(int count) {
203         fPts.reserve(count);
204         fCoverages.reserve(count);
205         fMovable.reserve(count);
206     }
207 
208     SkScalar computeDepthFromEdge(int edgeIdx, const SkPoint& p) const;
209 
210     bool computePtAlongBisector(int startIdx, const SkPoint& bisector,
211                                 int edgeIdx, SkScalar desiredDepth,
212                                 SkPoint* result) const;
213 
214     void lineTo(const SkPoint& p, CurveState curve);
215 
216     void lineTo(const SkMatrix& m, const SkPoint& p, CurveState curve);
217 
218     void quadTo(const SkPoint pts[3]);
219 
220     void quadTo(const SkMatrix& m, const SkPoint pts[3]);
221 
222     void cubicTo(const SkMatrix& m, const SkPoint pts[4]);
223 
224     void conicTo(const SkMatrix& m, const SkPoint pts[3], SkScalar w);
225 
226     void terminate(const Ring& lastRing);
227 
228     // return false on failure/degenerate path
229     bool extractFromPath(const SkMatrix& m, const SkPath& path);
230     void computeBisectors();
231     void computeNormals();
232 
233     void fanRing(const Ring& ring);
234 
235     Ring* getNextRing(Ring* lastRing);
236 
237     void createOuterRing(const Ring& previousRing, SkScalar outset, SkScalar coverage,
238                          Ring* nextRing);
239 
240     bool createInsetRings(Ring& previousRing, SkScalar initialDepth, SkScalar initialCoverage,
241                           SkScalar targetDepth, SkScalar targetCoverage, Ring** finalRing);
242 
243     bool createInsetRing(const Ring& lastRing, Ring* nextRing,
244                          SkScalar initialDepth, SkScalar initialCoverage, SkScalar targetDepth,
245                          SkScalar targetCoverage, bool forceNew);
246 
247     void validate() const;
248 
249     // fPts, fCoverages, fMovable & fCurveState should always have the same # of elements
250     SkTDArray<SkPoint>    fPts;
251     SkTDArray<SkScalar>   fCoverages;
252     // movable points are those that can be slid further along their bisector
253     SkTDArray<bool>       fMovable;
254     // Tracks whether a given point is interior to a curve. Such points are
255     // assumed to have shallow curvature.
256     SkTDArray<CurveState> fCurveState;
257 
258     // The outward facing normals for the original polygon
259     SkTDArray<SkVector>   fNorms;
260     // The inward facing bisector at each point in the original polygon. Only
261     // needed for exterior ring creation and then handed off to the initial ring.
262     SkTDArray<SkVector>   fBisectors;
263 
264     SkPointPriv::Side     fSide;    // winding of the original polygon
265 
266     // The triangulation of the points
267     SkTDArray<int>        fIndices;
268 
269     Ring                  fInitialRing;
270 #if GR_AA_CONVEX_TESSELLATOR_VIZ
271     // When visualizing save all the rings
272     SkTDArray<Ring*>      fRings;
273 #else
274     Ring                  fRings[2];
275 #endif
276     CandidateVerts        fCandidateVerts;
277 
278     // the stroke width is only used for stroke or stroke-and-fill styles
279     SkScalar              fStrokeWidth;
280     SkStrokeRec::Style    fStyle;
281 
282     SkPaint::Join         fJoin;
283 
284     SkScalar              fMiterLimit;
285 
286     // accumulated error when removing near colinear points to prevent an
287     // overly greedy simplification
288     SkScalar              fAccumLinearError;
289 
290     SkTDArray<SkPoint>    fPointBuffer;
291 };
292 
293 
294 #endif
295