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