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