1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#ifndef GrAAConvexTessellator_DEFINED
9cb93a386Sopenharmony_ci#define GrAAConvexTessellator_DEFINED
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "include/core/SkColor.h"
12cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
13cb93a386Sopenharmony_ci#include "include/core/SkScalar.h"
14cb93a386Sopenharmony_ci#include "include/core/SkStrokeRec.h"
15cb93a386Sopenharmony_ci#include "include/private/SkTDArray.h"
16cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h"
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ciclass SkCanvas;
19cb93a386Sopenharmony_ciclass SkMatrix;
20cb93a386Sopenharmony_ciclass SkPath;
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci//#define GR_AA_CONVEX_TESSELLATOR_VIZ 1
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci// device space distance which we inset / outset points in order to create the soft antialiased edge
25cb93a386Sopenharmony_cistatic const SkScalar kAntialiasingRadius = 0.5f;
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ciclass GrAAConvexTessellator;
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci// The AAConvexTessellator holds the global pool of points and the triangulation
30cb93a386Sopenharmony_ci// that connects them. It also drives the tessellation process.
31cb93a386Sopenharmony_ci// The outward facing normals of the original polygon are stored (in 'fNorms') to service
32cb93a386Sopenharmony_ci// computeDepthFromEdge requests.
33cb93a386Sopenharmony_ciclass GrAAConvexTessellator {
34cb93a386Sopenharmony_cipublic:
35cb93a386Sopenharmony_ci    GrAAConvexTessellator(SkStrokeRec::Style style = SkStrokeRec::kFill_Style,
36cb93a386Sopenharmony_ci                          SkScalar strokeWidth = -1.0f,
37cb93a386Sopenharmony_ci                          SkPaint::Join join = SkPaint::Join::kBevel_Join,
38cb93a386Sopenharmony_ci                          SkScalar miterLimit = 0.0f)
39cb93a386Sopenharmony_ci        : fSide(SkPointPriv::kOn_Side)
40cb93a386Sopenharmony_ci        , fStrokeWidth(strokeWidth)
41cb93a386Sopenharmony_ci        , fStyle(style)
42cb93a386Sopenharmony_ci        , fJoin(join)
43cb93a386Sopenharmony_ci        , fMiterLimit(miterLimit) {
44cb93a386Sopenharmony_ci    }
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci    SkPointPriv::Side side() const { return fSide; }
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ci    bool tessellate(const SkMatrix& m, const SkPath& path);
49cb93a386Sopenharmony_ci
50cb93a386Sopenharmony_ci    // The next five should only be called after tessellate to extract the result
51cb93a386Sopenharmony_ci    int numPts() const { return fPts.count(); }
52cb93a386Sopenharmony_ci    int numIndices() const { return fIndices.count(); }
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci    const SkPoint& lastPoint() const { return fPts.top(); }
55cb93a386Sopenharmony_ci    const SkPoint& point(int index) const { return fPts[index]; }
56cb93a386Sopenharmony_ci    int index(int index) const { return fIndices[index]; }
57cb93a386Sopenharmony_ci    SkScalar coverage(int index) const { return fCoverages[index]; }
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci#if GR_AA_CONVEX_TESSELLATOR_VIZ
60cb93a386Sopenharmony_ci    void draw(SkCanvas* canvas) const;
61cb93a386Sopenharmony_ci#endif
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    // The tessellator can be reused for multiple paths by rewinding in between
64cb93a386Sopenharmony_ci    void rewind();
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ciprivate:
67cb93a386Sopenharmony_ci    // CandidateVerts holds the vertices for the next ring while they are
68cb93a386Sopenharmony_ci    // being generated. Its main function is to de-dup the points.
69cb93a386Sopenharmony_ci    class CandidateVerts {
70cb93a386Sopenharmony_ci    public:
71cb93a386Sopenharmony_ci        void setReserve(int numPts) { fPts.setReserve(numPts); }
72cb93a386Sopenharmony_ci        void rewind() { fPts.rewind(); }
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci        int numPts() const { return fPts.count(); }
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci        const SkPoint& lastPoint() const { return fPts.top().fPt; }
77cb93a386Sopenharmony_ci        const SkPoint& firstPoint() const { return fPts[0].fPt; }
78cb93a386Sopenharmony_ci        const SkPoint& point(int index) const { return fPts[index].fPt; }
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ci        int originatingIdx(int index) const { return fPts[index].fOriginatingIdx; }
81cb93a386Sopenharmony_ci        int origEdge(int index) const { return fPts[index].fOrigEdgeId; }
82cb93a386Sopenharmony_ci        bool needsToBeNew(int index) const { return fPts[index].fNeedsToBeNew; }
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci        int addNewPt(const SkPoint& newPt, int originatingIdx, int origEdge, bool needsToBeNew) {
85cb93a386Sopenharmony_ci            struct PointData* pt = fPts.push();
86cb93a386Sopenharmony_ci            pt->fPt = newPt;
87cb93a386Sopenharmony_ci            pt->fOrigEdgeId = origEdge;
88cb93a386Sopenharmony_ci            pt->fOriginatingIdx = originatingIdx;
89cb93a386Sopenharmony_ci            pt->fNeedsToBeNew = needsToBeNew;
90cb93a386Sopenharmony_ci            return fPts.count() - 1;
91cb93a386Sopenharmony_ci        }
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci        int fuseWithPrior(int origEdgeId) {
94cb93a386Sopenharmony_ci            fPts.top().fOrigEdgeId = origEdgeId;
95cb93a386Sopenharmony_ci            fPts.top().fOriginatingIdx = -1;
96cb93a386Sopenharmony_ci            fPts.top().fNeedsToBeNew = true;
97cb93a386Sopenharmony_ci            return fPts.count() - 1;
98cb93a386Sopenharmony_ci        }
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci        int fuseWithNext() {
101cb93a386Sopenharmony_ci            fPts[0].fOriginatingIdx = -1;
102cb93a386Sopenharmony_ci            fPts[0].fNeedsToBeNew = true;
103cb93a386Sopenharmony_ci            return 0;
104cb93a386Sopenharmony_ci        }
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci        int fuseWithBoth() {
107cb93a386Sopenharmony_ci            if (fPts.count() > 1) {
108cb93a386Sopenharmony_ci                fPts.pop();
109cb93a386Sopenharmony_ci            }
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ci            fPts[0].fOriginatingIdx = -1;
112cb93a386Sopenharmony_ci            fPts[0].fNeedsToBeNew = true;
113cb93a386Sopenharmony_ci            return 0;
114cb93a386Sopenharmony_ci        }
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci    private:
117cb93a386Sopenharmony_ci        struct PointData {
118cb93a386Sopenharmony_ci            SkPoint fPt;
119cb93a386Sopenharmony_ci            int     fOriginatingIdx;
120cb93a386Sopenharmony_ci            int     fOrigEdgeId;
121cb93a386Sopenharmony_ci            bool    fNeedsToBeNew;
122cb93a386Sopenharmony_ci        };
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ci        SkTDArray<struct PointData> fPts;
125cb93a386Sopenharmony_ci    };
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci    // The Ring holds a set of indices into the global pool that together define
128cb93a386Sopenharmony_ci    // a single polygon inset.
129cb93a386Sopenharmony_ci    class Ring {
130cb93a386Sopenharmony_ci    public:
131cb93a386Sopenharmony_ci        void setReserve(int numPts) { fPts.setReserve(numPts); }
132cb93a386Sopenharmony_ci        void rewind() { fPts.rewind(); }
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci        int numPts() const { return fPts.count(); }
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_ci        void addIdx(int index, int origEdgeId) {
137cb93a386Sopenharmony_ci            struct PointData* pt = fPts.push();
138cb93a386Sopenharmony_ci            pt->fIndex = index;
139cb93a386Sopenharmony_ci            pt->fOrigEdgeId = origEdgeId;
140cb93a386Sopenharmony_ci        }
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci        // Upgrade this ring so that it can behave like an originating ring
143cb93a386Sopenharmony_ci        void makeOriginalRing() {
144cb93a386Sopenharmony_ci            for (int i = 0; i < fPts.count(); ++i) {
145cb93a386Sopenharmony_ci                fPts[i].fOrigEdgeId = fPts[i].fIndex;
146cb93a386Sopenharmony_ci            }
147cb93a386Sopenharmony_ci        }
148cb93a386Sopenharmony_ci
149cb93a386Sopenharmony_ci        // init should be called after all the indices have been added (via addIdx)
150cb93a386Sopenharmony_ci        void init(const GrAAConvexTessellator& tess);
151cb93a386Sopenharmony_ci        void init(const SkTDArray<SkVector>& norms, const SkTDArray<SkVector>& bisectors);
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci        const SkPoint& norm(int index) const { return fPts[index].fNorm; }
154cb93a386Sopenharmony_ci        const SkPoint& bisector(int index) const { return fPts[index].fBisector; }
155cb93a386Sopenharmony_ci        int index(int index) const { return fPts[index].fIndex; }
156cb93a386Sopenharmony_ci        int origEdgeID(int index) const { return fPts[index].fOrigEdgeId; }
157cb93a386Sopenharmony_ci        void setOrigEdgeId(int index, int id) { fPts[index].fOrigEdgeId = id; }
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci    #if GR_AA_CONVEX_TESSELLATOR_VIZ
160cb93a386Sopenharmony_ci        void draw(SkCanvas* canvas, const GrAAConvexTessellator& tess) const;
161cb93a386Sopenharmony_ci    #endif
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_ci    private:
164cb93a386Sopenharmony_ci        void computeNormals(const GrAAConvexTessellator& result);
165cb93a386Sopenharmony_ci        void computeBisectors(const GrAAConvexTessellator& tess);
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci        SkDEBUGCODE(bool isConvex(const GrAAConvexTessellator& tess) const;)
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci        struct PointData {
170cb93a386Sopenharmony_ci            SkPoint fNorm;
171cb93a386Sopenharmony_ci            SkPoint fBisector;
172cb93a386Sopenharmony_ci            int     fIndex;
173cb93a386Sopenharmony_ci            int     fOrigEdgeId;
174cb93a386Sopenharmony_ci        };
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci        SkTDArray<PointData> fPts;
177cb93a386Sopenharmony_ci    };
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ci    // Represents whether a given point is within a curve. A point is inside a curve only if it is
180cb93a386Sopenharmony_ci    // an interior point within a quad, cubic, or conic, or if it is the endpoint of a quad, cubic,
181cb93a386Sopenharmony_ci    // or conic with another curve meeting it at (more or less) the same angle.
182cb93a386Sopenharmony_ci    enum CurveState {
183cb93a386Sopenharmony_ci        // point is a sharp vertex
184cb93a386Sopenharmony_ci        kSharp_CurveState,
185cb93a386Sopenharmony_ci        // endpoint of a curve with the other side's curvature not yet determined
186cb93a386Sopenharmony_ci        kIndeterminate_CurveState,
187cb93a386Sopenharmony_ci        // point is in the interior of a curve
188cb93a386Sopenharmony_ci        kCurve_CurveState
189cb93a386Sopenharmony_ci    };
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ci    bool movable(int index) const { return fMovable[index]; }
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci    // Movable points are those that can be slid along their bisector.
194cb93a386Sopenharmony_ci    // Basically, a point is immovable if it is part of the original
195cb93a386Sopenharmony_ci    // polygon or it results from the fusing of two bisectors.
196cb93a386Sopenharmony_ci    int addPt(const SkPoint& pt, SkScalar depth, SkScalar coverage, bool movable, CurveState curve);
197cb93a386Sopenharmony_ci    void popLastPt();
198cb93a386Sopenharmony_ci    void popFirstPtShuffle();
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ci    void updatePt(int index, const SkPoint& pt, SkScalar depth, SkScalar coverage);
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ci    void addTri(int i0, int i1, int i2);
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci    void reservePts(int count) {
205cb93a386Sopenharmony_ci        fPts.setReserve(count);
206cb93a386Sopenharmony_ci        fCoverages.setReserve(count);
207cb93a386Sopenharmony_ci        fMovable.setReserve(count);
208cb93a386Sopenharmony_ci    }
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ci    SkScalar computeDepthFromEdge(int edgeIdx, const SkPoint& p) const;
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ci    bool computePtAlongBisector(int startIdx, const SkPoint& bisector,
213cb93a386Sopenharmony_ci                                int edgeIdx, SkScalar desiredDepth,
214cb93a386Sopenharmony_ci                                SkPoint* result) const;
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci    void lineTo(const SkPoint& p, CurveState curve);
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci    void lineTo(const SkMatrix& m, const SkPoint& p, CurveState curve);
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ci    void quadTo(const SkPoint pts[3]);
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_ci    void quadTo(const SkMatrix& m, const SkPoint pts[3]);
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci    void cubicTo(const SkMatrix& m, const SkPoint pts[4]);
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_ci    void conicTo(const SkMatrix& m, const SkPoint pts[3], SkScalar w);
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci    void terminate(const Ring& lastRing);
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci    // return false on failure/degenerate path
231cb93a386Sopenharmony_ci    bool extractFromPath(const SkMatrix& m, const SkPath& path);
232cb93a386Sopenharmony_ci    void computeBisectors();
233cb93a386Sopenharmony_ci    void computeNormals();
234cb93a386Sopenharmony_ci
235cb93a386Sopenharmony_ci    void fanRing(const Ring& ring);
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci    Ring* getNextRing(Ring* lastRing);
238cb93a386Sopenharmony_ci
239cb93a386Sopenharmony_ci    void createOuterRing(const Ring& previousRing, SkScalar outset, SkScalar coverage,
240cb93a386Sopenharmony_ci                         Ring* nextRing);
241cb93a386Sopenharmony_ci
242cb93a386Sopenharmony_ci    bool createInsetRings(Ring& previousRing, SkScalar initialDepth, SkScalar initialCoverage,
243cb93a386Sopenharmony_ci                          SkScalar targetDepth, SkScalar targetCoverage, Ring** finalRing);
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci    bool createInsetRing(const Ring& lastRing, Ring* nextRing,
246cb93a386Sopenharmony_ci                         SkScalar initialDepth, SkScalar initialCoverage, SkScalar targetDepth,
247cb93a386Sopenharmony_ci                         SkScalar targetCoverage, bool forceNew);
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ci    void validate() const;
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_ci    // fPts, fCoverages, fMovable & fCurveState should always have the same # of elements
252cb93a386Sopenharmony_ci    SkTDArray<SkPoint>    fPts;
253cb93a386Sopenharmony_ci    SkTDArray<SkScalar>   fCoverages;
254cb93a386Sopenharmony_ci    // movable points are those that can be slid further along their bisector
255cb93a386Sopenharmony_ci    SkTDArray<bool>       fMovable;
256cb93a386Sopenharmony_ci    // Tracks whether a given point is interior to a curve. Such points are
257cb93a386Sopenharmony_ci    // assumed to have shallow curvature.
258cb93a386Sopenharmony_ci    SkTDArray<CurveState> fCurveState;
259cb93a386Sopenharmony_ci
260cb93a386Sopenharmony_ci    // The outward facing normals for the original polygon
261cb93a386Sopenharmony_ci    SkTDArray<SkVector>   fNorms;
262cb93a386Sopenharmony_ci    // The inward facing bisector at each point in the original polygon. Only
263cb93a386Sopenharmony_ci    // needed for exterior ring creation and then handed off to the initial ring.
264cb93a386Sopenharmony_ci    SkTDArray<SkVector>   fBisectors;
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci    SkPointPriv::Side     fSide;    // winding of the original polygon
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci    // The triangulation of the points
269cb93a386Sopenharmony_ci    SkTDArray<int>        fIndices;
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci    Ring                  fInitialRing;
272cb93a386Sopenharmony_ci#if GR_AA_CONVEX_TESSELLATOR_VIZ
273cb93a386Sopenharmony_ci    // When visualizing save all the rings
274cb93a386Sopenharmony_ci    SkTDArray<Ring*>      fRings;
275cb93a386Sopenharmony_ci#else
276cb93a386Sopenharmony_ci    Ring                  fRings[2];
277cb93a386Sopenharmony_ci#endif
278cb93a386Sopenharmony_ci    CandidateVerts        fCandidateVerts;
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci    // the stroke width is only used for stroke or stroke-and-fill styles
281cb93a386Sopenharmony_ci    SkScalar              fStrokeWidth;
282cb93a386Sopenharmony_ci    SkStrokeRec::Style    fStyle;
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci    SkPaint::Join         fJoin;
285cb93a386Sopenharmony_ci
286cb93a386Sopenharmony_ci    SkScalar              fMiterLimit;
287cb93a386Sopenharmony_ci
288cb93a386Sopenharmony_ci    // accumulated error when removing near colinear points to prevent an
289cb93a386Sopenharmony_ci    // overly greedy simplification
290cb93a386Sopenharmony_ci    SkScalar              fAccumLinearError;
291cb93a386Sopenharmony_ci
292cb93a386Sopenharmony_ci    SkTDArray<SkPoint>    fPointBuffer;
293cb93a386Sopenharmony_ci};
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci
296cb93a386Sopenharmony_ci#endif
297