Home | History | Annotate | Download | only in gpu
      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') to 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 result
     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, bool 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 addIdx)
    135         void init(const GrAAConvexTessellator& tess);
    136         void init(const SkTDArray<SkVector>& norms, const SkTDArray<SkVector>& bisectors);
    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 
    245