fix interior issues in convex path renderer
git-svn-id: http://skia.googlecode.com/svn/trunk@3078 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
13a847a82c
commit
495e210eb1
@ -14,7 +14,7 @@ namespace skiagm {
|
||||
class ConvexPathsGM : public GM {
|
||||
public:
|
||||
ConvexPathsGM() {
|
||||
this->setBGColor(0xFFDDDDDD);
|
||||
this->setBGColor(0xFFFFFFFF);
|
||||
this->makePaths();
|
||||
}
|
||||
|
||||
@ -63,10 +63,6 @@ protected:
|
||||
100 * SK_Scalar1),
|
||||
SkPath::kCCW_Direction);
|
||||
|
||||
fPaths.push_back().addRect(0, 0,
|
||||
100 * SK_Scalar1, 100 * SK_Scalar1,
|
||||
SkPath::kCCW_Direction);
|
||||
|
||||
fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
|
||||
SK_Scalar1 * 100,
|
||||
SK_Scalar1 * 100),
|
||||
@ -78,6 +74,12 @@ protected:
|
||||
SK_Scalar1 * 100),
|
||||
20 * SK_Scalar1, 40 * SK_Scalar1,
|
||||
SkPath::kCCW_Direction);
|
||||
|
||||
// shallow diagonals
|
||||
fPaths.push_back().lineTo(100 * SK_Scalar1, SK_Scalar1);
|
||||
fPaths.back().lineTo(98 * SK_Scalar1, 100 * SK_Scalar1);
|
||||
fPaths.back().lineTo(3 * SK_Scalar1, 96 * SK_Scalar1);
|
||||
|
||||
/*
|
||||
It turns out arcTos are not automatically marked as convex and they
|
||||
may in fact be ever so slightly concave.
|
||||
@ -87,6 +89,14 @@ protected:
|
||||
25 * SK_Scalar1, 130 * SK_Scalar1, false);
|
||||
*/
|
||||
|
||||
// cubics
|
||||
fPaths.push_back().cubicTo( 1 * SK_Scalar1, 1 * SK_Scalar1,
|
||||
10 * SK_Scalar1, 90 * SK_Scalar1,
|
||||
0 * SK_Scalar1, 100 * SK_Scalar1);
|
||||
fPaths.push_back().cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
|
||||
20 * SK_Scalar1, 100 * SK_Scalar1,
|
||||
0 * SK_Scalar1, 0 * SK_Scalar1);
|
||||
|
||||
// point degenerate
|
||||
fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
|
||||
fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
|
||||
@ -117,7 +127,7 @@ protected:
|
||||
paint.setAntiAlias(true);
|
||||
SkRandom rand;
|
||||
canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
|
||||
for (int i = 0 ; i < fPaths.count(); ++i) {
|
||||
for (int i = 0; i < fPaths.count(); ++i) {
|
||||
canvas->save();
|
||||
// position the path, and make it at off-integer coords.
|
||||
canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 4,
|
||||
|
@ -29,18 +29,28 @@ bool GrAAConvexPathRenderer::canDrawPath(const GrDrawTarget::Caps& targetCaps,
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
struct Segment {
|
||||
enum {
|
||||
kLine,
|
||||
kQuad
|
||||
} fType;
|
||||
// line uses a, quad uses a and b (first point comes from prev. segment)
|
||||
GrPoint fA, fB;
|
||||
// normal to edge ending at a and b
|
||||
GrVec fANorm, fBNorm;
|
||||
// mid vector at a that splits angle with previous edge
|
||||
GrVec fPrevMid;
|
||||
// line uses one pt, quad uses 2 pts
|
||||
GrPoint fPts[2];
|
||||
// normal to edge ending at each pt
|
||||
GrVec fNorms[2];
|
||||
// is the corner where the previous segment meets this segment
|
||||
// sharp. If so, fMid is a normalized bisector facing outward.
|
||||
GrVec fMid;
|
||||
|
||||
int countPoints() {
|
||||
return (kLine == fType) ? 1 : 2;
|
||||
}
|
||||
const SkPoint& endPt() const {
|
||||
return (kLine == fType) ? fPts[0] : fPts[1];
|
||||
};
|
||||
const SkPoint& endNorm() const {
|
||||
return (kLine == fType) ? fNorms[0] : fNorms[1];
|
||||
};
|
||||
};
|
||||
|
||||
typedef SkTArray<Segment, true> SegmentArray;
|
||||
@ -50,7 +60,6 @@ bool is_path_degenerate(const GrPath& path) {
|
||||
if (n < 3) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// compute a line from the first two points that are not equal, look for
|
||||
// a third pt that is off the line.
|
||||
static const SkScalar TOL = (SK_Scalar1 / 16);
|
||||
@ -80,12 +89,84 @@ bool is_path_degenerate(const GrPath& path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void center_of_mass(const SegmentArray& segments, SkPoint* c) {
|
||||
GrScalar area = 0;
|
||||
SkPoint center;
|
||||
center.set(0, 0);
|
||||
int count = segments.count();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const SkPoint& pi = segments[i].endPt();
|
||||
int j = (i + 1) % count;
|
||||
const SkPoint& pj = segments[j].endPt();
|
||||
GrScalar t = GrMul(pi.fX, pj.fY) - GrMul(pj.fX, pi.fY);
|
||||
area += t;
|
||||
center.fX += (pi.fX + pj.fX) * t;
|
||||
center.fY += (pi.fY + pj.fY) * t;
|
||||
}
|
||||
area *= 3;
|
||||
area = GrScalarDiv(GR_Scalar1, area);
|
||||
center.fX = GrScalarMul(center.fX, area);
|
||||
center.fY = GrScalarMul(center.fY, area);
|
||||
*c = center;
|
||||
}
|
||||
|
||||
void compute_vectors(SegmentArray* segments,
|
||||
SkPoint* fanPt,
|
||||
int* vCount,
|
||||
int* iCount) {
|
||||
center_of_mass(*segments, fanPt);
|
||||
int count = segments->count();
|
||||
|
||||
// figure out which way the normals should point
|
||||
GrPoint::Side normSide;
|
||||
fanPt->distanceToLineBetweenSqd((*segments)[0].endPt(),
|
||||
(*segments)[1].endPt(),
|
||||
&normSide);
|
||||
|
||||
*vCount = 0;
|
||||
*iCount = 0;
|
||||
// compute normals at all points
|
||||
for (int a = 0; a < count; ++a) {
|
||||
const Segment& sega = (*segments)[a];
|
||||
int b = (a + 1) % count;
|
||||
Segment& segb = (*segments)[b];
|
||||
|
||||
const GrPoint* prevPt = &sega.endPt();
|
||||
int n = segb.countPoints();
|
||||
for (int p = 0; p < n; ++p) {
|
||||
segb.fNorms[p] = segb.fPts[p] - *prevPt;
|
||||
segb.fNorms[p].normalize();
|
||||
segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
|
||||
prevPt = &segb.fPts[p];
|
||||
}
|
||||
if (Segment::kLine == segb.fType) {
|
||||
*vCount += 5;
|
||||
*iCount += 9;
|
||||
} else {
|
||||
*vCount += 6;
|
||||
*iCount += 12;
|
||||
}
|
||||
}
|
||||
|
||||
// compute mid-vectors where segments meet. TODO: Detect shallow corners
|
||||
// and leave out the wedges and close gaps by stitching segments together.
|
||||
for (int a = 0; a < count; ++a) {
|
||||
const Segment& sega = (*segments)[a];
|
||||
int b = (a + 1) % count;
|
||||
Segment& segb = (*segments)[b];
|
||||
segb.fMid = segb.fNorms[0] + sega.endNorm();
|
||||
segb.fMid.normalize();
|
||||
// corner wedges
|
||||
*vCount += 4;
|
||||
*iCount += 6;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_segments(const GrPath& path,
|
||||
SegmentArray* segments,
|
||||
int* quadCnt,
|
||||
int* lineCnt) {
|
||||
*quadCnt = 0;
|
||||
*lineCnt = 0;
|
||||
SkPoint* fanPt,
|
||||
int* vCount,
|
||||
int* iCount) {
|
||||
SkPath::Iter iter(path, true);
|
||||
// This renderer overemphasises very thin path regions. We use the distance
|
||||
// to the path from the sample to compute coverage. Every pixel intersected
|
||||
@ -104,16 +185,14 @@ bool get_segments(const GrPath& path,
|
||||
case kLine_PathCmd: {
|
||||
segments->push_back();
|
||||
segments->back().fType = Segment::kLine;
|
||||
segments->back().fA = pts[1];
|
||||
++(*lineCnt);
|
||||
segments->back().fPts[0] = pts[1];
|
||||
break;
|
||||
}
|
||||
case kQuadratic_PathCmd:
|
||||
segments->push_back();
|
||||
segments->back().fType = Segment::kQuad;
|
||||
segments->back().fA = pts[1];
|
||||
segments->back().fB = pts[2];
|
||||
++(*quadCnt);
|
||||
segments->back().fPts[0] = pts[1];
|
||||
segments->back().fPts[1] = pts[2];
|
||||
break;
|
||||
case kCubic_PathCmd: {
|
||||
SkSTArray<15, SkPoint, true> quads;
|
||||
@ -122,14 +201,13 @@ bool get_segments(const GrPath& path,
|
||||
for (int q = 0; q < count; q += 3) {
|
||||
segments->push_back();
|
||||
segments->back().fType = Segment::kQuad;
|
||||
segments->back().fA = quads[q + 1];
|
||||
segments->back().fB = quads[q + 2];
|
||||
++(*quadCnt);
|
||||
segments->back().fPts[0] = quads[q + 1];
|
||||
segments->back().fPts[1] = quads[q + 2];
|
||||
}
|
||||
break;
|
||||
};
|
||||
case kEnd_PathCmd:
|
||||
GrAssert(*quadCnt + *lineCnt == segments->count());
|
||||
compute_vectors(segments, fanPt, vCount, iCount);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
@ -139,201 +217,139 @@ bool get_segments(const GrPath& path,
|
||||
|
||||
struct QuadVertex {
|
||||
GrPoint fPos;
|
||||
union {
|
||||
GrPoint fQuadUV;
|
||||
GrScalar fEdge[4];
|
||||
};
|
||||
GrPoint fUV;
|
||||
GrScalar fD0;
|
||||
GrScalar fD1;
|
||||
};
|
||||
|
||||
void get_counts(int quadCount, int lineCount, int* vCount, int* iCount) {
|
||||
*vCount = 9 * lineCount + 11 * quadCount;
|
||||
*iCount = 15 * lineCount + 24 * quadCount;
|
||||
}
|
||||
|
||||
// This macro can be defined for visual debugging purposes. It exagerates the AA
|
||||
// smear at the edges by increasing the size of the extruded geometry used for
|
||||
// AA. However, the coverage value computed in the shader will still go to zero
|
||||
// at distance > .5 outside the curves. So, the shader code has be modified as
|
||||
// well to stretch out the AA smear.
|
||||
//#define STRETCH_AA
|
||||
#define STRETCH_FACTOR (20 * SK_Scalar1)
|
||||
|
||||
void create_vertices(SegmentArray* segments,
|
||||
const GrPoint& fanPt,
|
||||
QuadVertex* verts,
|
||||
uint16_t* idxs) {
|
||||
int count = segments->count();
|
||||
GrAssert(count > 1);
|
||||
int prevS = count - 1;
|
||||
const Segment& lastSeg = (*segments)[prevS];
|
||||
|
||||
// walk the segments and compute normals to each edge and
|
||||
// bisectors at vertices. The loop relies on having the end point and normal
|
||||
// from previous segment so we first compute that. Also, we determine
|
||||
// whether normals point left or right to face outside the path.
|
||||
GrVec prevPt;
|
||||
GrPoint prevPrevPt;
|
||||
GrVec prevNorm;
|
||||
if (Segment::kLine == lastSeg.fType) {
|
||||
prevPt = lastSeg.fA;
|
||||
const Segment& secondLastSeg = (*segments)[prevS - 1];
|
||||
prevPrevPt = (Segment::kLine == secondLastSeg.fType) ?
|
||||
secondLastSeg.fA :
|
||||
secondLastSeg.fB;
|
||||
} else {
|
||||
prevPt = lastSeg.fB;
|
||||
prevPrevPt = lastSeg.fA;
|
||||
}
|
||||
GrVec::Side outside;
|
||||
// we will compute our edge vectors so that they are pointing along the
|
||||
// direction in which we are iterating the path. So here we take an opposite
|
||||
// vector and get the side that the fan pt lies relative to it.
|
||||
fanPt.distanceToLineBetweenSqd(prevPrevPt, prevPt, &outside);
|
||||
prevNorm = prevPt - prevPrevPt;
|
||||
prevNorm.normalize();
|
||||
prevNorm.setOrthog(prevNorm, outside);
|
||||
#ifdef STRETCH_AA
|
||||
prevNorm.scale(STRETCH_FACTOR);
|
||||
#endif
|
||||
|
||||
// compute the normals and bisectors
|
||||
for (int s = 0; s < count; ++s, ++prevS) {
|
||||
Segment& curr = (*segments)[s];
|
||||
|
||||
GrVec currVec = curr.fA - prevPt;
|
||||
currVec.normalize();
|
||||
curr.fANorm.setOrthog(currVec, outside);
|
||||
#ifdef STRETCH_AA
|
||||
curr.fANorm.scale(STRETCH_FACTOR);
|
||||
#endif
|
||||
curr.fPrevMid = prevNorm + curr.fANorm;
|
||||
curr.fPrevMid.normalize();
|
||||
#ifdef STRETCH_AA
|
||||
curr.fPrevMid.scale(STRETCH_FACTOR);
|
||||
#endif
|
||||
if (Segment::kLine == curr.fType) {
|
||||
prevPt = curr.fA;
|
||||
prevNorm = curr.fANorm;
|
||||
} else {
|
||||
currVec = curr.fB - curr.fA;
|
||||
currVec.normalize();
|
||||
curr.fBNorm.setOrthog(currVec, outside);
|
||||
#ifdef STRETCH_AA
|
||||
curr.fBNorm.scale(STRETCH_FACTOR);
|
||||
#endif
|
||||
prevPt = curr.fB;
|
||||
prevNorm = curr.fBNorm;
|
||||
}
|
||||
}
|
||||
|
||||
// compute the vertices / indices
|
||||
if (Segment::kLine == lastSeg.fType) {
|
||||
prevPt = lastSeg.fA;
|
||||
prevNorm = lastSeg.fANorm;
|
||||
} else {
|
||||
prevPt = lastSeg.fB;
|
||||
prevNorm = lastSeg.fBNorm;
|
||||
}
|
||||
|
||||
void create_vertices(const SegmentArray& segments,
|
||||
const SkPoint& fanPt,
|
||||
QuadVertex* verts,
|
||||
uint16_t* idxs) {
|
||||
int v = 0;
|
||||
int i = 0;
|
||||
for (int s = 0; s < count; ++s, ++prevS) {
|
||||
Segment& curr = (*segments)[s];
|
||||
verts[v + 0].fPos = prevPt;
|
||||
verts[v + 1].fPos = prevPt + prevNorm;
|
||||
verts[v + 2].fPos = prevPt + curr.fPrevMid;
|
||||
verts[v + 3].fPos = prevPt + curr.fANorm;
|
||||
verts[v + 0].fQuadUV.set(0, 0);
|
||||
verts[v + 1].fQuadUV.set(0, -SK_Scalar1);
|
||||
verts[v + 2].fQuadUV.set(0, -SK_Scalar1);
|
||||
verts[v + 3].fQuadUV.set(0, -SK_Scalar1);
|
||||
|
||||
int count = segments.count();
|
||||
for (int a = 0; a < count; ++a) {
|
||||
const Segment& sega = segments[a];
|
||||
int b = (a + 1) % count;
|
||||
const Segment& segb = segments[b];
|
||||
|
||||
// FIXME: These tris are inset in the 1 unit arc around the corner
|
||||
verts[v + 0].fPos = sega.endPt();
|
||||
verts[v + 1].fPos = verts[v + 0].fPos + sega.endNorm();
|
||||
verts[v + 2].fPos = verts[v + 0].fPos + segb.fMid;
|
||||
verts[v + 3].fPos = verts[v + 0].fPos + segb.fNorms[0];
|
||||
verts[v + 0].fUV.set(0,0);
|
||||
verts[v + 1].fUV.set(0,-SK_Scalar1);
|
||||
verts[v + 2].fUV.set(0,-SK_Scalar1);
|
||||
verts[v + 3].fUV.set(0,-SK_Scalar1);
|
||||
verts[v + 0].fD0 = verts[v + 0].fD1 = -SK_Scalar1;
|
||||
verts[v + 1].fD0 = verts[v + 1].fD1 = -SK_Scalar1;
|
||||
verts[v + 2].fD0 = verts[v + 2].fD1 = -SK_Scalar1;
|
||||
verts[v + 3].fD0 = verts[v + 3].fD1 = -SK_Scalar1;
|
||||
|
||||
idxs[i + 0] = v + 0;
|
||||
idxs[i + 1] = v + 1;
|
||||
idxs[i + 2] = v + 2;
|
||||
idxs[i + 1] = v + 2;
|
||||
idxs[i + 2] = v + 1;
|
||||
idxs[i + 3] = v + 0;
|
||||
idxs[i + 4] = v + 2;
|
||||
idxs[i + 5] = v + 3;
|
||||
|
||||
idxs[i + 4] = v + 3;
|
||||
idxs[i + 5] = v + 2;
|
||||
|
||||
v += 4;
|
||||
i += 6;
|
||||
|
||||
if (Segment::kLine == curr.fType) {
|
||||
if (Segment::kLine == segb.fType) {
|
||||
verts[v + 0].fPos = fanPt;
|
||||
verts[v + 1].fPos = prevPt;
|
||||
verts[v + 2].fPos = curr.fA;
|
||||
verts[v + 3].fPos = prevPt + curr.fANorm;
|
||||
verts[v + 4].fPos = curr.fA + curr.fANorm;
|
||||
GrScalar lineC = -curr.fANorm.dot(curr.fA);
|
||||
GrScalar fanDist = curr.fANorm.dot(fanPt) - lineC;
|
||||
verts[v + 0].fQuadUV.set(0, SkScalarAbs(fanDist));
|
||||
verts[v + 1].fQuadUV.set(0, 0);
|
||||
verts[v + 2].fQuadUV.set(0, 0);
|
||||
verts[v + 3].fQuadUV.set(0, -GR_Scalar1);
|
||||
verts[v + 4].fQuadUV.set(0, -GR_Scalar1);
|
||||
verts[v + 1].fPos = sega.endPt();
|
||||
verts[v + 2].fPos = segb.fPts[0];
|
||||
|
||||
verts[v + 3].fPos = verts[v + 1].fPos + segb.fNorms[0];
|
||||
verts[v + 4].fPos = verts[v + 2].fPos + segb.fNorms[0];
|
||||
|
||||
// we draw the line edge as a degenerate quad (u is 0, v is the
|
||||
// signed distance to the edge)
|
||||
GrScalar dist = fanPt.distanceToLineBetween(verts[v + 1].fPos,
|
||||
verts[v + 2].fPos);
|
||||
verts[v + 0].fUV.set(0, dist);
|
||||
verts[v + 1].fUV.set(0, 0);
|
||||
verts[v + 2].fUV.set(0, 0);
|
||||
verts[v + 3].fUV.set(0, -SK_Scalar1);
|
||||
verts[v + 4].fUV.set(0, -SK_Scalar1);
|
||||
|
||||
verts[v + 0].fD0 = verts[v + 0].fD1 = -SK_Scalar1;
|
||||
verts[v + 1].fD0 = verts[v + 1].fD1 = -SK_Scalar1;
|
||||
verts[v + 2].fD0 = verts[v + 2].fD1 = -SK_Scalar1;
|
||||
verts[v + 3].fD0 = verts[v + 3].fD1 = -SK_Scalar1;
|
||||
verts[v + 4].fD0 = verts[v + 4].fD1 = -SK_Scalar1;
|
||||
|
||||
idxs[i + 0] = v + 0;
|
||||
idxs[i + 1] = v + 1;
|
||||
idxs[i + 2] = v + 2;
|
||||
idxs[i + 3] = v + 1;
|
||||
idxs[i + 4] = v + 3;
|
||||
idxs[i + 5] = v + 4;
|
||||
idxs[i + 6] = v + 1;
|
||||
idxs[i + 7] = v + 4;
|
||||
idxs[i + 1] = v + 2;
|
||||
idxs[i + 2] = v + 1;
|
||||
|
||||
idxs[i + 3] = v + 3;
|
||||
idxs[i + 4] = v + 1;
|
||||
idxs[i + 5] = v + 2;
|
||||
|
||||
idxs[i + 6] = v + 4;
|
||||
idxs[i + 7] = v + 3;
|
||||
idxs[i + 8] = v + 2;
|
||||
|
||||
i += 9;
|
||||
v += 5;
|
||||
|
||||
prevPt = curr.fA;
|
||||
prevNorm = curr.fANorm;
|
||||
i += 9;
|
||||
} else {
|
||||
GrVec splitVec = curr.fANorm + curr.fBNorm;
|
||||
splitVec.normalize();
|
||||
#ifdef STRETCH_AA
|
||||
splitVec.scale(STRETCH_FACTOR);
|
||||
#endif
|
||||
GrPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
|
||||
|
||||
verts[v + 0].fPos = prevPt;
|
||||
verts[v + 1].fPos = curr.fA;
|
||||
verts[v + 2].fPos = curr.fB;
|
||||
verts[v + 3].fPos = fanPt;
|
||||
verts[v + 4].fPos = prevPt + curr.fANorm;
|
||||
verts[v + 5].fPos = curr.fA + splitVec;
|
||||
verts[v + 6].fPos = curr.fB + curr.fBNorm;
|
||||
GrVec midVec = segb.fNorms[0] + segb.fNorms[1];
|
||||
midVec.normalize();
|
||||
|
||||
verts[v + 0].fPos = fanPt;
|
||||
verts[v + 1].fPos = qpts[0];
|
||||
verts[v + 2].fPos = qpts[2];
|
||||
verts[v + 3].fPos = qpts[0] + segb.fNorms[0];
|
||||
verts[v + 4].fPos = qpts[2] + segb.fNorms[1];
|
||||
verts[v + 5].fPos = qpts[1] + midVec;
|
||||
|
||||
GrScalar c = segb.fNorms[0].dot(qpts[0]);
|
||||
verts[v + 0].fD0 = -segb.fNorms[0].dot(fanPt) + c;
|
||||
verts[v + 1].fD0 = 0.f;
|
||||
verts[v + 2].fD0 = -segb.fNorms[0].dot(qpts[2]) + c;
|
||||
verts[v + 3].fD0 = -GR_ScalarMax/100;
|
||||
verts[v + 4].fD0 = -GR_ScalarMax/100;
|
||||
verts[v + 5].fD0 = -GR_ScalarMax/100;
|
||||
|
||||
c = segb.fNorms[1].dot(qpts[2]);
|
||||
verts[v + 0].fD1 = -segb.fNorms[1].dot(fanPt) + c;
|
||||
verts[v + 1].fD1 = -segb.fNorms[1].dot(qpts[0]) + c;
|
||||
verts[v + 2].fD1 = 0.f;
|
||||
verts[v + 3].fD1 = -GR_ScalarMax/100;
|
||||
verts[v + 4].fD1 = -GR_ScalarMax/100;
|
||||
verts[v + 5].fD1 = -GR_ScalarMax/100;
|
||||
|
||||
verts[v + 0].fQuadUV.set(0, 0);
|
||||
verts[v + 1].fQuadUV.set(GR_ScalarHalf, 0);
|
||||
verts[v + 2].fQuadUV.set(GR_Scalar1, GR_Scalar1);
|
||||
GrMatrix toUV;
|
||||
GrPoint pts[] = {prevPt, curr.fA, curr.fB};
|
||||
GrPathUtils::quadDesignSpaceToUVCoordsMatrix(pts, &toUV);
|
||||
toUV.mapPointsWithStride(&verts[v + 3].fQuadUV,
|
||||
&verts[v + 3].fPos,
|
||||
sizeof(QuadVertex), 4);
|
||||
GrPathUtils::quadDesignSpaceToUVCoordsMatrix(qpts, &toUV);
|
||||
toUV.mapPointsWithStride(&verts[v].fUV,
|
||||
&verts[v].fPos,
|
||||
sizeof(QuadVertex),
|
||||
6);
|
||||
|
||||
idxs[i + 0] = v + 3;
|
||||
idxs[i + 1] = v + 0;
|
||||
idxs[i + 2] = v + 1;
|
||||
idxs[i + 3] = v + 3;
|
||||
idxs[i + 4] = v + 1;
|
||||
idxs[i + 5] = v + 2;
|
||||
idxs[i + 6] = v + 0;
|
||||
idxs[i + 7] = v + 4;
|
||||
idxs[i + 8] = v + 1;
|
||||
idxs[i + 9] = v + 4;
|
||||
idxs[i + 10] = v + 1;
|
||||
idxs[i + 11] = v + 5;
|
||||
idxs[i + 12] = v + 5;
|
||||
idxs[i + 13] = v + 1;
|
||||
idxs[i + 14] = v + 2;
|
||||
idxs[i + 15] = v + 5;
|
||||
idxs[i + 16] = v + 2;
|
||||
idxs[i + 17] = v + 6;
|
||||
idxs[i + 0] = v + 3;
|
||||
idxs[i + 1] = v + 1;
|
||||
idxs[i + 2] = v + 2;
|
||||
idxs[i + 3] = v + 4;
|
||||
idxs[i + 4] = v + 3;
|
||||
idxs[i + 5] = v + 2;
|
||||
|
||||
i += 18;
|
||||
v += 7;
|
||||
prevPt = curr.fB;
|
||||
prevNorm = curr.fBNorm;
|
||||
idxs[i + 6] = v + 5;
|
||||
idxs[i + 7] = v + 3;
|
||||
idxs[i + 8] = v + 4;
|
||||
|
||||
idxs[i + 9] = v + 0;
|
||||
idxs[i + 10] = v + 2;
|
||||
idxs[i + 11] = v + 1;
|
||||
|
||||
v += 6;
|
||||
i += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -357,13 +373,9 @@ void GrAAConvexPathRenderer::drawPath(GrDrawState::StageMask stageMask) {
|
||||
}
|
||||
drawState->setViewMatrix(GrMatrix::I());
|
||||
|
||||
|
||||
SkPath path;
|
||||
fPath->transform(vm, &path);
|
||||
|
||||
SkPoint fanPt = {path.getBounds().centerX(),
|
||||
path.getBounds().centerY()};
|
||||
|
||||
GrVertexLayout layout = 0;
|
||||
for (int s = 0; s < GrDrawState::kNumStages; ++s) {
|
||||
if ((1 << s) & stageMask) {
|
||||
@ -375,15 +387,13 @@ void GrAAConvexPathRenderer::drawPath(GrDrawState::StageMask stageMask) {
|
||||
QuadVertex *verts;
|
||||
uint16_t* idxs;
|
||||
|
||||
int nQuads;
|
||||
int nLines;
|
||||
SegmentArray segments;
|
||||
if (!get_segments(path, &segments, &nQuads, &nLines)) {
|
||||
return;
|
||||
}
|
||||
int vCount;
|
||||
int iCount;
|
||||
get_counts(nQuads, nLines, &vCount, &iCount);
|
||||
SegmentArray segments;
|
||||
SkPoint fanPt;
|
||||
if (!get_segments(path, &segments, &fanPt, &vCount, &iCount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fTarget->reserveVertexSpace(layout,
|
||||
vCount,
|
||||
@ -395,7 +405,7 @@ void GrAAConvexPathRenderer::drawPath(GrDrawState::StageMask stageMask) {
|
||||
return;
|
||||
}
|
||||
|
||||
create_vertices(&segments, fanPt, verts, idxs);
|
||||
create_vertices(segments, fanPt, verts, idxs);
|
||||
|
||||
drawState->setVertexEdgeType(GrDrawState::kQuad_EdgeType);
|
||||
fTarget->drawIndexed(kTriangles_PrimitiveType,
|
||||
|
@ -18,9 +18,7 @@ void GrPathRenderer::AddPathRenderers(GrContext* ctx,
|
||||
if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
|
||||
chain->addPathRenderer(pr)->unref();
|
||||
}
|
||||
// Disabled for now. Need to fix issue where some hairlines don't
|
||||
// wind up going to the hairline renderer and get rendered by this
|
||||
// PR looking speckly.
|
||||
// Disabled for now.
|
||||
//chain->addPathRenderer(new GrAAConvexPathRenderer())->unref();
|
||||
}
|
||||
}
|
||||
|
@ -528,23 +528,34 @@ void GrGLProgram::genEdgeCoverage(const GrGLInterface* gl,
|
||||
if (GrDrawState::kHairLine_EdgeType == fProgramDesc.fVertexEdgeType) {
|
||||
segments->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(gl_FragCoord.xy,1), %s.xyz));\n", fsName);
|
||||
segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
} else if (GrDrawState::kQuad_EdgeType == fProgramDesc.fVertexEdgeType) {
|
||||
segments->fFSCode.appendf("\tfloat edgeAlpha;\n");
|
||||
// keep the derivative instructions outside the conditional
|
||||
segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
|
||||
segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
|
||||
segments->fFSCode.appendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
|
||||
// today we know z and w are in device space. We could use derivatives
|
||||
segments->fFSCode.appendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
|
||||
segments->fFSCode.append ("\t} else {\n");
|
||||
segments->fFSCode.appendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
|
||||
"\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
|
||||
fsName, fsName);
|
||||
segments->fFSCode.appendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
|
||||
segments->fFSCode.appendf("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
|
||||
"\t}\n");
|
||||
if (gl->supportsES2()) {
|
||||
segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
|
||||
}
|
||||
} else {
|
||||
GrAssert(GrDrawState::kHairQuad_EdgeType == fProgramDesc.fVertexEdgeType ||
|
||||
GrDrawState::kQuad_EdgeType == fProgramDesc.fVertexEdgeType);
|
||||
// for now we know we're not in perspective, so we could compute this
|
||||
// per-quadratic rather than per pixel
|
||||
GrAssert(GrDrawState::kHairQuad_EdgeType == fProgramDesc.fVertexEdgeType);
|
||||
segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
|
||||
segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
|
||||
segments->fFSCode.appendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
|
||||
"\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
|
||||
fsName, fsName);
|
||||
segments->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
|
||||
if (GrDrawState::kQuad_EdgeType == fProgramDesc.fVertexEdgeType) {
|
||||
segments->fFSCode.append("\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n");
|
||||
} else {
|
||||
segments->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
|
||||
segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
}
|
||||
segments->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
|
||||
segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
if (gl->supportsES2()) {
|
||||
segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user