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