| Index: src/gpu/GrAAConvexTessellator.h
|
| diff --git a/src/gpu/GrAAConvexTessellator.h b/src/gpu/GrAAConvexTessellator.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c2b751e5718c081510cc8c47cf43bde0bc0406c0
|
| --- /dev/null
|
| +++ b/src/gpu/GrAAConvexTessellator.h
|
| @@ -0,0 +1,244 @@
|
| +/*
|
| + * Copyright 2015 Google Inc.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +#ifndef GrAAConvexTessellator_DEFINED
|
| +#define GrAAConvexTessellator_DEFINED
|
| +
|
| +#include "SkColor.h"
|
| +#include "SkPoint.h"
|
| +#include "SkScalar.h"
|
| +#include "SkTDArray.h"
|
| +
|
| +class SkCanvas;
|
| +class SkMatrix;
|
| +class SkPath;
|
| +
|
| +//#define GR_AA_CONVEX_TESSELLATOR_VIZ 1
|
| +
|
| +class GrAAConvexTessellator;
|
| +
|
| +// The AAConvexTessellator holds the global pool of points and the triangulation
|
| +// that connects them. It also drives the tessellation process.
|
| +// The outward facing normals of the original polygon are stored (in 'fNorms') to service
|
| +// computeDepthFromEdge requests.
|
| +class GrAAConvexTessellator {
|
| +public:
|
| + GrAAConvexTessellator(SkScalar targetDepth = 0.5f)
|
| + : fSide(SkPoint::kOn_Side)
|
| + , fTargetDepth(targetDepth) {
|
| + }
|
| +
|
| + void setTargetDepth(SkScalar targetDepth) { fTargetDepth = targetDepth; }
|
| + SkScalar targetDepth() const { return fTargetDepth; }
|
| +
|
| + SkPoint::Side side() const { return fSide; }
|
| +
|
| + bool tessellate(const SkMatrix& m, const SkPath& path);
|
| +
|
| + // The next five should only be called after tessellate to extract the result
|
| + int numPts() const { return fPts.count(); }
|
| + int numIndices() const { return fIndices.count(); }
|
| +
|
| + const SkPoint& lastPoint() const { return fPts.top(); }
|
| + const SkPoint& point(int index) const { return fPts[index]; }
|
| + int index(int index) const { return fIndices[index]; }
|
| + SkScalar depth(int index) const {return fDepths[index]; }
|
| +
|
| +#if GR_AA_CONVEX_TESSELLATOR_VIZ
|
| + void draw(SkCanvas* canvas) const;
|
| +#endif
|
| +
|
| + // The tessellator can be reused for multiple paths by rewinding in between
|
| + void rewind();
|
| +
|
| +private:
|
| + // CandidateVerts holds the vertices for the next ring while they are
|
| + // being generated. Its main function is to de-dup the points.
|
| + class CandidateVerts {
|
| + public:
|
| + void setReserve(int numPts) { fPts.setReserve(numPts); }
|
| + void rewind() { fPts.rewind(); }
|
| +
|
| + int numPts() const { return fPts.count(); }
|
| +
|
| + const SkPoint& lastPoint() const { return fPts.top().fPt; }
|
| + const SkPoint& firstPoint() const { return fPts[0].fPt; }
|
| + const SkPoint& point(int index) const { return fPts[index].fPt; }
|
| +
|
| + int originatingIdx(int index) const { return fPts[index].fOriginatingIdx; }
|
| + int origEdge(int index) const { return fPts[index].fOrigEdgeId; }
|
| + bool needsToBeNew(int index) const { return fPts[index].fNeedsToBeNew; }
|
| +
|
| + int addNewPt(const SkPoint& newPt, int originatingIdx, int origEdge, bool needsToBeNew) {
|
| + struct PointData* pt = fPts.push();
|
| + pt->fPt = newPt;
|
| + pt->fOrigEdgeId = origEdge;
|
| + pt->fOriginatingIdx = originatingIdx;
|
| + pt->fNeedsToBeNew = needsToBeNew;
|
| + return fPts.count() - 1;
|
| + }
|
| +
|
| + int fuseWithPrior(int origEdgeId) {
|
| + fPts.top().fOrigEdgeId = origEdgeId;
|
| + fPts.top().fOriginatingIdx = -1;
|
| + fPts.top().fNeedsToBeNew = true;
|
| + return fPts.count() - 1;
|
| + }
|
| +
|
| + int fuseWithNext() {
|
| + fPts[0].fOriginatingIdx = -1;
|
| + fPts[0].fNeedsToBeNew = true;
|
| + return 0;
|
| + }
|
| +
|
| + int fuseWithBoth() {
|
| + if (fPts.count() > 1) {
|
| + fPts.pop();
|
| + }
|
| +
|
| + fPts[0].fOriginatingIdx = -1;
|
| + fPts[0].fNeedsToBeNew = true;
|
| + return 0;
|
| + }
|
| +
|
| + private:
|
| + struct PointData {
|
| + SkPoint fPt;
|
| + int fOriginatingIdx;
|
| + int fOrigEdgeId;
|
| + bool fNeedsToBeNew;
|
| + };
|
| +
|
| + SkTDArray<struct PointData> fPts;
|
| + };
|
| +
|
| + // The Ring holds a set of indices into the global pool that together define
|
| + // a single polygon inset.
|
| + class Ring {
|
| + public:
|
| + void setReserve(int numPts) { fPts.setReserve(numPts); }
|
| + void rewind() { fPts.rewind(); }
|
| +
|
| + int numPts() const { return fPts.count(); }
|
| +
|
| + void addIdx(int index, int origEdgeId) {
|
| + struct PointData* pt = fPts.push();
|
| + pt->fIndex = index;
|
| + pt->fOrigEdgeId = origEdgeId;
|
| + }
|
| +
|
| + // init should be called after all the indices have been added (via addIdx)
|
| + void init(const GrAAConvexTessellator& tess);
|
| + void init(const SkTDArray<SkVector>& norms, const SkTDArray<SkVector>& bisectors);
|
| +
|
| + const SkPoint& norm(int index) const { return fPts[index].fNorm; }
|
| + const SkPoint& bisector(int index) const { return fPts[index].fBisector; }
|
| + int index(int index) const { return fPts[index].fIndex; }
|
| + int origEdgeID(int index) const { return fPts[index].fOrigEdgeId; }
|
| +
|
| + #if GR_AA_CONVEX_TESSELLATOR_VIZ
|
| + void draw(SkCanvas* canvas, const GrAAConvexTessellator& tess) const;
|
| + #endif
|
| +
|
| + private:
|
| + void computeNormals(const GrAAConvexTessellator& result);
|
| + void computeBisectors();
|
| +
|
| + SkDEBUGCODE(bool isConvex(const GrAAConvexTessellator& tess) const;)
|
| +
|
| + struct PointData {
|
| + SkPoint fNorm;
|
| + SkPoint fBisector;
|
| + int fIndex;
|
| + int fOrigEdgeId;
|
| + };
|
| +
|
| + SkTDArray<PointData> fPts;
|
| + };
|
| +
|
| + bool movable(int index) const { return fMovable[index]; }
|
| +
|
| + // Movable points are those that can be slid along their bisector.
|
| + // Basically, a point is immovable if it is part of the original
|
| + // polygon or it results from the fusing of two bisectors.
|
| + int addPt(const SkPoint& pt, SkScalar depth, bool movable);
|
| + void popLastPt();
|
| + void popFirstPtShuffle();
|
| +
|
| + void updatePt(int index, const SkPoint& pt, SkScalar depth);
|
| +
|
| + void addTri(int i0, int i1, int i2);
|
| +
|
| + void reservePts(int count) {
|
| + fPts.setReserve(count);
|
| + fDepths.setReserve(count);
|
| + fMovable.setReserve(count);
|
| + }
|
| +
|
| + SkScalar computeDepthFromEdge(int edgeIdx, const SkPoint& p) const;
|
| +
|
| + bool computePtAlongBisector(int startIdx, const SkPoint& bisector,
|
| + int edgeIdx, SkScalar desiredDepth,
|
| + SkPoint* result) const;
|
| +
|
| + void terminate(const Ring& lastRing);
|
| +
|
| + // return false on failure/degenerate path
|
| + bool extractFromPath(const SkMatrix& m, const SkPath& path);
|
| + void computeBisectors();
|
| +
|
| + void fanRing(const Ring& ring);
|
| + void createOuterRing();
|
| +
|
| + Ring* getNextRing(Ring* lastRing);
|
| +
|
| + bool createInsetRing(const Ring& lastRing, Ring* nextRing);
|
| +
|
| + void validate() const;
|
| +
|
| +
|
| +#ifdef SK_DEBUG
|
| + SkScalar computeRealDepth(const SkPoint& p) const;
|
| + void checkAllDepths() const;
|
| +#endif
|
| +
|
| + // fPts, fWeights & fMovable should always have the same # of elements
|
| + SkTDArray<SkPoint> fPts;
|
| + SkTDArray<SkScalar> fDepths;
|
| + // movable points are those that can be slid further along their bisector
|
| + SkTDArray<bool> fMovable;
|
| +
|
| + // The outward facing normals for the original polygon
|
| + SkTDArray<SkVector> fNorms;
|
| + // The inward facing bisector at each point in the original polygon. Only
|
| + // needed for exterior ring creation and then handed off to the initial ring.
|
| + SkTDArray<SkVector> fBisectors;
|
| + SkPoint::Side fSide; // winding of the original polygon
|
| +
|
| + // The triangulation of the points
|
| + SkTDArray<int> fIndices;
|
| +
|
| + Ring fInitialRing;
|
| +#if GR_AA_CONVEX_TESSELLATOR_VIZ
|
| + // When visualizing save all the rings
|
| + SkTDArray<Ring*> fRings;
|
| +#else
|
| + Ring fRings[2];
|
| +#endif
|
| + CandidateVerts fCandidateVerts;
|
| +
|
| + SkScalar fTargetDepth;
|
| +
|
| + // If some goes wrong with the inset computation the tessellator will
|
| + // truncate the creation of the inset polygon. In this case the depth
|
| + // check will complain.
|
| + SkDEBUGCODE(bool fShouldCheckDepths;)
|
| +};
|
| +
|
| +
|
| +#endif
|
| +
|
|
|