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 "SkPointPriv.h" 14 #include "SkScalar.h" 15 #include "SkStrokeRec.h" 16 #include "SkTDArray.h" 17 18 class SkCanvas; 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 class 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. 33 class GrAAConvexTessellator { 34 public: 35 GrAAConvexTessellator(SkStrokeRec::Style style = SkStrokeRec::kFill_Style, 36 SkScalar strokeWidth = -1.0f, 37 SkPaint::Join join = SkPaint::Join::kBevel_Join, 38 SkScalar miterLimit = 0.0f) fSide(SkPointPriv::kOn_Side)39 : fSide(SkPointPriv::kOn_Side) 40 , fStrokeWidth(strokeWidth) 41 , fStyle(style) 42 , fJoin(join) 43 , fMiterLimit(miterLimit) { 44 } 45 side()46 SkPointPriv::Side side() const { return fSide; } 47 48 bool tessellate(const SkMatrix& m, const SkPath& path); 49 50 // The next five should only be called after tessellate to extract the result numPts()51 int numPts() const { return fPts.count(); } numIndices()52 int numIndices() const { return fIndices.count(); } 53 lastPoint()54 const SkPoint& lastPoint() const { return fPts.top(); } point(int index)55 const SkPoint& point(int index) const { return fPts[index]; } index(int index)56 int index(int index) const { return fIndices[index]; } coverage(int index)57 SkScalar coverage(int index) const { return fCoverages[index]; } 58 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 66 private: 67 // CandidateVerts holds the vertices for the next ring while they are 68 // being generated. Its main function is to de-dup the points. 69 class CandidateVerts { 70 public: setReserve(int numPts)71 void setReserve(int numPts) { fPts.setReserve(numPts); } rewind()72 void rewind() { fPts.rewind(); } 73 numPts()74 int numPts() const { return fPts.count(); } 75 lastPoint()76 const SkPoint& lastPoint() const { return fPts.top().fPt; } firstPoint()77 const SkPoint& firstPoint() const { return fPts[0].fPt; } point(int index)78 const SkPoint& point(int index) const { return fPts[index].fPt; } 79 originatingIdx(int index)80 int originatingIdx(int index) const { return fPts[index].fOriginatingIdx; } origEdge(int index)81 int origEdge(int index) const { return fPts[index].fOrigEdgeId; } needsToBeNew(int index)82 bool needsToBeNew(int index) const { return fPts[index].fNeedsToBeNew; } 83 addNewPt(const SkPoint & newPt,int originatingIdx,int origEdge,bool needsToBeNew)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 fuseWithPrior(int origEdgeId)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 fuseWithNext()100 int fuseWithNext() { 101 fPts[0].fOriginatingIdx = -1; 102 fPts[0].fNeedsToBeNew = true; 103 return 0; 104 } 105 fuseWithBoth()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: setReserve(int numPts)131 void setReserve(int numPts) { fPts.setReserve(numPts); } rewind()132 void rewind() { fPts.rewind(); } 133 numPts()134 int numPts() const { return fPts.count(); } 135 addIdx(int index,int origEdgeId)136 void addIdx(int index, int origEdgeId) { 137 struct PointData* pt = fPts.push(); 138 pt->fIndex = index; 139 pt->fOrigEdgeId = origEdgeId; 140 } 141 142 // Upgrade this ring so that it can behave like an originating ring makeOriginalRing()143 void makeOriginalRing() { 144 for (int i = 0; i < fPts.count(); ++i) { 145 fPts[i].fOrigEdgeId = fPts[i].fIndex; 146 } 147 } 148 149 // 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 norm(int index)153 const SkPoint& norm(int index) const { return fPts[index].fNorm; } bisector(int index)154 const SkPoint& bisector(int index) const { return fPts[index].fBisector; } index(int index)155 int index(int index) const { return fPts[index].fIndex; } origEdgeID(int index)156 int origEdgeID(int index) const { return fPts[index].fOrigEdgeId; } setOrigEdgeId(int index,int id)157 void setOrigEdgeId(int index, int id) { fPts[index].fOrigEdgeId = id; } 158 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); 165 void computeBisectors(const GrAAConvexTessellator& tess); 166 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 179 // 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 movable(int index)191 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. 196 int addPt(const SkPoint& pt, SkScalar depth, SkScalar coverage, bool movable, CurveState curve); 197 void popLastPt(); 198 void popFirstPtShuffle(); 199 200 void updatePt(int index, const SkPoint& pt, SkScalar depth, SkScalar coverage); 201 202 void addTri(int i0, int i1, int i2); 203 reservePts(int count)204 void reservePts(int count) { 205 fPts.setReserve(count); 206 fCoverages.setReserve(count); 207 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 216 void lineTo(const SkPoint& p, CurveState curve); 217 218 void lineTo(const SkMatrix& m, SkPoint p, CurveState curve); 219 220 void quadTo(const SkPoint pts[3]); 221 222 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 228 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(); 233 void computeNormals(); 234 235 void fanRing(const Ring& ring); 236 237 Ring* getNextRing(Ring* lastRing); 238 239 void createOuterRing(const Ring& previousRing, SkScalar outset, SkScalar coverage, 240 Ring* nextRing); 241 242 bool createInsetRings(Ring& previousRing, SkScalar initialDepth, SkScalar initialCoverage, 243 SkScalar targetDepth, SkScalar targetCoverage, Ring** finalRing); 244 245 bool createInsetRing(const Ring& lastRing, Ring* nextRing, 246 SkScalar initialDepth, SkScalar initialCoverage, SkScalar targetDepth, 247 SkScalar targetCoverage, bool forceNew); 248 249 void validate() const; 250 251 // fPts, fCoverages, fMovable & fCurveState should always have the same # of elements 252 SkTDArray<SkPoint> fPts; 253 SkTDArray<SkScalar> fCoverages; 254 // movable points are those that can be slid further along their bisector 255 SkTDArray<bool> fMovable; 256 // Tracks whether a given point is interior to a curve. Such points are 257 // assumed to have shallow curvature. 258 SkTDArray<CurveState> fCurveState; 259 260 // The outward facing normals for the original polygon 261 SkTDArray<SkVector> fNorms; 262 // 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. 264 SkTDArray<SkVector> fBisectors; 265 266 SkPointPriv::Side fSide; // winding of the original polygon 267 268 // The triangulation of the points 269 SkTDArray<int> fIndices; 270 271 Ring fInitialRing; 272 #if GR_AA_CONVEX_TESSELLATOR_VIZ 273 // When visualizing save all the rings 274 SkTDArray<Ring*> fRings; 275 #else 276 Ring fRings[2]; 277 #endif 278 CandidateVerts fCandidateVerts; 279 280 // the stroke width is only used for stroke or stroke-and-fill styles 281 SkScalar fStrokeWidth; 282 SkStrokeRec::Style fStyle; 283 284 SkPaint::Join fJoin; 285 286 SkScalar fMiterLimit; 287 288 SkTDArray<SkPoint> fPointBuffer; 289 }; 290 291 292 #endif 293