зеркало из https://github.com/mozilla/moz-skia.git
Add convex path renderer (disabled)
Review URL: http://codereview.appspot.com/5533061/ git-svn-id: http://skia.googlecode.com/svn/trunk@3040 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
0eb7576c65
Коммит
69cc6ad20e
|
@ -0,0 +1,136 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "gm.h"
|
||||
#include "SkRandom.h"
|
||||
#include "SkTArray.h"
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
class ConvexPathsGM : public GM {
|
||||
public:
|
||||
ConvexPathsGM() {
|
||||
this->setBGColor(0xFFDDDDDD);
|
||||
this->makePaths();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual SkString onShortName() {
|
||||
return SkString("convexpaths");
|
||||
}
|
||||
|
||||
|
||||
virtual SkISize onISize() {
|
||||
return make_isize(1200, 900);
|
||||
}
|
||||
|
||||
void makePaths() {
|
||||
fPaths.push_back().addRect(0, 0,
|
||||
100 * SK_Scalar1, 100 * SK_Scalar1,
|
||||
SkPath::kCW_Direction);
|
||||
|
||||
fPaths.push_back().addRect(0, 0,
|
||||
100 * SK_Scalar1, 100 * SK_Scalar1,
|
||||
SkPath::kCCW_Direction);
|
||||
|
||||
fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
|
||||
50 * SK_Scalar1, SkPath::kCW_Direction);
|
||||
|
||||
fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
|
||||
40 * SK_Scalar1, SkPath::kCCW_Direction);
|
||||
|
||||
fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
|
||||
50 * SK_Scalar1,
|
||||
100 * SK_Scalar1),
|
||||
SkPath::kCW_Direction);
|
||||
|
||||
fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
|
||||
100 * SK_Scalar1,
|
||||
50 * SK_Scalar1),
|
||||
SkPath::kCCW_Direction);
|
||||
|
||||
fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
|
||||
100 * SK_Scalar1,
|
||||
5 * SK_Scalar1),
|
||||
SkPath::kCCW_Direction);
|
||||
|
||||
fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
|
||||
SK_Scalar1,
|
||||
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),
|
||||
40 * SK_Scalar1, 20 * SK_Scalar1,
|
||||
SkPath::kCW_Direction);
|
||||
|
||||
fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
|
||||
SK_Scalar1 * 100,
|
||||
SK_Scalar1 * 100),
|
||||
20 * SK_Scalar1, 40 * SK_Scalar1,
|
||||
SkPath::kCCW_Direction);
|
||||
/*
|
||||
fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
|
||||
50 * SK_Scalar1,
|
||||
100 * SK_Scalar1),
|
||||
25 * SK_Scalar1, 130 * SK_Scalar1, false);
|
||||
*/
|
||||
|
||||
// point degenerate
|
||||
fPaths.push_back().lineTo(0,0);
|
||||
fPaths.push_back().quadTo(0,0,0,0);
|
||||
fPaths.push_back().cubicTo(0,0,0,0,0,0);
|
||||
|
||||
// line degenerate
|
||||
fPaths.push_back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
|
||||
fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1, 0, 0);
|
||||
fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1,
|
||||
50 * SK_Scalar1, 50 * SK_Scalar1);
|
||||
fPaths.push_back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
|
||||
100 * SK_Scalar1, 100 * SK_Scalar1);
|
||||
fPaths.push_back().cubicTo(0, 0,
|
||||
0, 0,
|
||||
100 * SK_Scalar1, 100 * SK_Scalar1);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
SkRandom rand;
|
||||
canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
|
||||
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,
|
||||
SK_Scalar1 * 200 * (i / 5) + 3 * SK_Scalar1 / 4);
|
||||
SkColor color = rand.nextU();
|
||||
color |= 0xff000000;
|
||||
paint.setColor(color);
|
||||
SkASSERT(fPaths[i].isConvex());
|
||||
canvas->drawPath(fPaths[i], paint);
|
||||
canvas->restore();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GM INHERITED;
|
||||
SkTArray<SkPath> fPaths;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static GM* MyFactory(void*) { return new ConvexPathsGM; }
|
||||
static GMRegistry reg(MyFactory);
|
||||
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
'../gm/colormatrix.cpp',
|
||||
'../gm/complexclip.cpp',
|
||||
'../gm/complexclip2.cpp',
|
||||
'../gm/convexpaths.cpp',
|
||||
'../gm/cubicpaths.cpp',
|
||||
'../gm/degeneratesegments.cpp',
|
||||
'../gm/drawbitmaprect.cpp',
|
||||
|
|
|
@ -186,7 +186,9 @@
|
|||
|
||||
'../src/gpu/GrAAHairLinePathRenderer.cpp',
|
||||
'../src/gpu/GrAAHairLinePathRenderer.h',
|
||||
'../src/gpu/GrAddPathRenderers_aahairline.cpp',
|
||||
'../src/gpu/GrAAConvexPathRenderer.cpp',
|
||||
'../src/gpu/GrAAConvexPathRenderer.h',
|
||||
'../src/gpu/GrAddPathRenderers_default.cpp',
|
||||
'../src/gpu/GrAllocator.h',
|
||||
'../src/gpu/GrAllocPool.h',
|
||||
'../src/gpu/GrAllocPool.cpp',
|
||||
|
|
|
@ -0,0 +1,401 @@
|
|||
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrAAConvexPathRenderer.h"
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrDrawState.h"
|
||||
#include "GrPathUtils.h"
|
||||
#include "SkString.h"
|
||||
#include "SkTrace.h"
|
||||
|
||||
|
||||
GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
|
||||
}
|
||||
|
||||
bool GrAAConvexPathRenderer::canDrawPath(const GrDrawTarget::Caps& targetCaps,
|
||||
const SkPath& path,
|
||||
GrPathFill fill,
|
||||
bool antiAlias) const {
|
||||
return targetCaps.fShaderDerivativeSupport && antiAlias &&
|
||||
kHairLine_PathFill != fill && !GrIsFillInverted(fill) &&
|
||||
path.isConvex();
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
typedef SkTArray<Segment, true> SegmentArray;
|
||||
|
||||
bool is_path_degenerate(const GrPath& path) {
|
||||
int n = path.countPoints();
|
||||
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);
|
||||
bool foundLine = false;
|
||||
GrPoint firstPoint = path.getPoint(0);
|
||||
GrVec lineV;
|
||||
SkScalar lineC;
|
||||
int i = 1;
|
||||
|
||||
do {
|
||||
GrPoint pt = path.getPoint(i);
|
||||
if (!foundLine) {
|
||||
if (pt != firstPoint) {
|
||||
lineV = pt - firstPoint;
|
||||
lineV.normalize();
|
||||
lineV.setOrthog(lineV);
|
||||
lineC = lineV.dot(firstPoint);
|
||||
foundLine = true;
|
||||
}
|
||||
} else {
|
||||
if (SkScalarAbs(lineV.dot(pt) - lineC) > TOL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
} while (i < n);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_segments(const GrPath& path,
|
||||
SegmentArray* segments,
|
||||
int* quadCnt,
|
||||
int* lineCnt) {
|
||||
*quadCnt = 0;
|
||||
*lineCnt = 0;
|
||||
SkPath::Iter iter(path, true);
|
||||
// This renderer overemphasis very thin paths (every pixel intersected by
|
||||
// the path will be at least 1/2 on). When the path degenerates to a line
|
||||
// this makes the path draw as a hairline. This is a pretty glaring error
|
||||
// so we detect this case and will not draw.
|
||||
if (is_path_degenerate(path)) {
|
||||
return false;
|
||||
}
|
||||
for (;;) {
|
||||
GrPoint pts[4];
|
||||
GrPathCmd cmd = (GrPathCmd)iter.next(pts);
|
||||
switch (cmd) {
|
||||
case kLine_PathCmd: {
|
||||
segments->push_back();
|
||||
segments->back().fType = Segment::kLine;
|
||||
segments->back().fA = pts[1];
|
||||
++(*lineCnt);
|
||||
break;
|
||||
}
|
||||
case kQuadratic_PathCmd:
|
||||
segments->push_back();
|
||||
segments->back().fType = Segment::kQuad;
|
||||
segments->back().fA = pts[1];
|
||||
segments->back().fB = pts[2];
|
||||
++(*quadCnt);
|
||||
break;
|
||||
case kCubic_PathCmd: {
|
||||
SkSTArray<15, SkPoint, true> quads;
|
||||
GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, &quads);
|
||||
int count = quads.count();
|
||||
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);
|
||||
}
|
||||
break;
|
||||
};
|
||||
case kEnd_PathCmd:
|
||||
GrAssert(*quadCnt + *lineCnt == segments->count());
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct QuadVertex {
|
||||
GrPoint fPos;
|
||||
union {
|
||||
GrPoint fQuadUV;
|
||||
GrScalar fEdge[4];
|
||||
};
|
||||
};
|
||||
|
||||
void get_counts(int quadCount, int lineCount, int* vCount, int* iCount) {
|
||||
*vCount = 9 * lineCount + 11 * quadCount;
|
||||
*iCount = 15 * lineCount + 24 * quadCount;
|
||||
}
|
||||
|
||||
// for visual debugging, exagerate the AA smear at the edges
|
||||
// requires modifying the distance calc in the shader actually shade differently
|
||||
//#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;
|
||||
}
|
||||
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);
|
||||
|
||||
idxs[i + 0] = v + 0;
|
||||
idxs[i + 1] = v + 1;
|
||||
idxs[i + 2] = v + 2;
|
||||
idxs[i + 3] = v + 0;
|
||||
idxs[i + 4] = v + 2;
|
||||
idxs[i + 5] = v + 3;
|
||||
|
||||
v += 4;
|
||||
i += 6;
|
||||
|
||||
if (Segment::kLine == curr.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);
|
||||
|
||||
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 + 8] = v + 2;
|
||||
|
||||
i += 9;
|
||||
v += 5;
|
||||
|
||||
prevPt = curr.fA;
|
||||
prevNorm = curr.fANorm;
|
||||
} else {
|
||||
GrVec splitVec = curr.fANorm + curr.fBNorm;
|
||||
splitVec.normalize();
|
||||
#ifdef STRETCH_AA
|
||||
splitVec.scale(STRETCH_FACTOR);
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
i += 18;
|
||||
v += 7;
|
||||
prevPt = curr.fB;
|
||||
prevNorm = curr.fBNorm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GrAAConvexPathRenderer::drawPath(GrDrawState::StageMask stageMask) {
|
||||
GrAssert(fPath->isConvex());
|
||||
if (fPath->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
GrDrawState* drawState = fTarget->drawState();
|
||||
|
||||
GrDrawTarget::AutoStateRestore asr;
|
||||
GrMatrix vm = drawState->getViewMatrix();
|
||||
vm.postTranslate(fTranslate.fX, fTranslate.fY);
|
||||
asr.set(fTarget);
|
||||
GrMatrix ivm;
|
||||
if (vm.invert(&ivm)) {
|
||||
drawState->preConcatSamplerMatrices(stageMask, ivm);
|
||||
}
|
||||
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) {
|
||||
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
|
||||
}
|
||||
}
|
||||
layout |= GrDrawTarget::kEdge_VertexLayoutBit;
|
||||
|
||||
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);
|
||||
|
||||
if (!fTarget->reserveVertexSpace(layout,
|
||||
vCount,
|
||||
reinterpret_cast<void**>(&verts))) {
|
||||
return;
|
||||
}
|
||||
if (!fTarget->reserveIndexSpace(iCount, reinterpret_cast<void**>(&idxs))) {
|
||||
fTarget->resetVertexSource();
|
||||
return;
|
||||
}
|
||||
|
||||
create_vertices(&segments, fanPt, verts, idxs);
|
||||
|
||||
drawState->setVertexEdgeType(GrDrawState::kQuad_EdgeType);
|
||||
fTarget->drawIndexed(kTriangles_PrimitiveType,
|
||||
0, // start vertex
|
||||
0, // start index
|
||||
vCount,
|
||||
iCount);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrPathRenderer.h"
|
||||
|
||||
|
||||
class GrAAConvexPathRenderer : public GrPathRenderer {
|
||||
public:
|
||||
GrAAConvexPathRenderer();
|
||||
bool canDrawPath(const GrDrawTarget::Caps& targetCaps,
|
||||
const SkPath& path,
|
||||
GrPathFill fill,
|
||||
bool antiAlias) const;
|
||||
void drawPath(GrDrawState::StageMask stageMask);
|
||||
};
|
|
@ -140,65 +140,6 @@ typedef SkTArray<SkPoint, true> PtArray;
|
|||
#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
|
||||
typedef SkTArray<int, true> IntArray;
|
||||
|
||||
/**
|
||||
* We convert cubics to quadratics (for now).
|
||||
*/
|
||||
void convert_noninflect_cubic_to_quads(const SkPoint p[4],
|
||||
SkScalar tolScale,
|
||||
PtArray* quads,
|
||||
int sublevel = 0) {
|
||||
SkVector ab = p[1];
|
||||
ab -= p[0];
|
||||
SkVector dc = p[2];
|
||||
dc -= p[3];
|
||||
|
||||
static const SkScalar gLengthScale = 3 * SK_Scalar1 / 2;
|
||||
// base tolerance is 2 pixels in dev coords.
|
||||
const SkScalar distanceSqdTol = SkScalarMul(tolScale, 2 * SK_Scalar1);
|
||||
static const int kMaxSubdivs = 10;
|
||||
|
||||
ab.scale(gLengthScale);
|
||||
dc.scale(gLengthScale);
|
||||
|
||||
SkVector c0 = p[0];
|
||||
c0 += ab;
|
||||
SkVector c1 = p[3];
|
||||
c1 += dc;
|
||||
|
||||
SkScalar dSqd = c0.distanceToSqd(c1);
|
||||
if (sublevel > kMaxSubdivs || dSqd <= distanceSqdTol) {
|
||||
SkPoint cAvg = c0;
|
||||
cAvg += c1;
|
||||
cAvg.scale(SK_ScalarHalf);
|
||||
|
||||
SkPoint* pts = quads->push_back_n(3);
|
||||
pts[0] = p[0];
|
||||
pts[1] = cAvg;
|
||||
pts[2] = p[3];
|
||||
|
||||
return;
|
||||
} else {
|
||||
SkPoint choppedPts[7];
|
||||
SkChopCubicAtHalf(p, choppedPts);
|
||||
convert_noninflect_cubic_to_quads(choppedPts + 0, tolScale,
|
||||
quads, sublevel + 1);
|
||||
convert_noninflect_cubic_to_quads(choppedPts + 3, tolScale,
|
||||
quads, sublevel + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void convert_cubic_to_quads(const SkPoint p[4],
|
||||
SkScalar tolScale,
|
||||
PtArray* quads) {
|
||||
SkPoint chopped[13];
|
||||
int count = SkChopCubicAtInflections(p, chopped);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkPoint* cubic = chopped + 3*i;
|
||||
convert_noninflect_cubic_to_quads(cubic, tolScale, quads);
|
||||
}
|
||||
}
|
||||
|
||||
// Takes 178th time of logf on Z600 / VC2010
|
||||
int get_float_exp(float x) {
|
||||
GR_STATIC_ASSERT(sizeof(int) == sizeof(float));
|
||||
|
@ -350,14 +291,15 @@ int generate_lines_and_quads(const SkPath& path,
|
|||
bounds.roundOut(&ibounds);
|
||||
if (SkIRect::Intersects(clip, ibounds)) {
|
||||
PREALLOC_PTARRAY(32) q;
|
||||
// in perspective have to do conversion in src space
|
||||
// We convert cubics to quadratics (for now).
|
||||
// In perspective have to do conversion in src space.
|
||||
if (persp) {
|
||||
SkScalar tolScale =
|
||||
GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m,
|
||||
path.getBounds());
|
||||
convert_cubic_to_quads(pts, tolScale, &q);
|
||||
GrPathUtils::convertCubicToQuads(pts, tolScale, &q);
|
||||
} else {
|
||||
convert_cubic_to_quads(devPts, SK_Scalar1, &q);
|
||||
GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, &q);
|
||||
}
|
||||
for (int i = 0; i < q.count(); i += 3) {
|
||||
SkPoint* qInDevSpace;
|
||||
|
@ -447,24 +389,9 @@ void bloat_quad(const SkPoint qpts[3], const GrMatrix* toDevice,
|
|||
SkPoint b = qpts[1];
|
||||
SkPoint c = qpts[2];
|
||||
|
||||
// compute a matrix that goes from device coords to U,V quad params
|
||||
// this should be in the src space, not dev coords, when we have perspective
|
||||
SkMatrix DevToUV;
|
||||
DevToUV.setAll(a.fX, b.fX, c.fX,
|
||||
a.fY, b.fY, c.fY,
|
||||
SK_Scalar1, SK_Scalar1, SK_Scalar1);
|
||||
DevToUV.invert(&DevToUV);
|
||||
// can't make this static, no cons :(
|
||||
SkMatrix UVpts;
|
||||
UVpts.setAll(0, SK_ScalarHalf, SK_Scalar1,
|
||||
0, 0, SK_Scalar1,
|
||||
SK_Scalar1, SK_Scalar1, SK_Scalar1);
|
||||
DevToUV.postConcat(UVpts);
|
||||
|
||||
// We really want to avoid perspective matrix muls.
|
||||
// These may wind up really close to zero
|
||||
DevToUV.setPerspX(0);
|
||||
DevToUV.setPerspY(0);
|
||||
GrPathUtils::quadDesignSpaceToUVCoordsMatrix(qpts, &DevToUV);
|
||||
|
||||
if (toDevice) {
|
||||
toDevice->mapPoints(&a, 1);
|
||||
|
|
|
@ -1,20 +1,26 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "GrAAHairLinePathRenderer.h"
|
||||
#include "GrAAConvexPathRenderer.h"
|
||||
|
||||
void GrPathRenderer::AddPathRenderers(GrContext* ctx,
|
||||
GrPathRendererChain::UsageFlags flags,
|
||||
GrPathRendererChain* chain) {
|
||||
if (!(GrPathRendererChain::kNonAAOnly_UsageFlag & flags)) {
|
||||
|
||||
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.
|
||||
//chain->addPathRenderer(new GrAAConvexPathRenderer())->unref();
|
||||
}
|
||||
}
|
|
@ -489,9 +489,15 @@ struct GrDrawState {
|
|||
/* 1-pixel wide line
|
||||
2D implicit line eq (a*x + b*y +c = 0). 4th component unused */
|
||||
kHairLine_EdgeType,
|
||||
/* 1-pixel wide quadratic
|
||||
u^2-v canonical coords (only 2 components used) */
|
||||
kHairQuad_EdgeType
|
||||
/* Quadratic specified by u^2-v canonical coords (only 2
|
||||
components used). Coverage based on signed distance with negative
|
||||
being inside, positive outside.*/
|
||||
kQuad_EdgeType,
|
||||
/* Same as above but for hairline quadratics. Uses unsigned distance.
|
||||
Coverage is min(0, 1-distance). */
|
||||
kHairQuad_EdgeType,
|
||||
|
||||
kVertexEdgeTypeCnt
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -500,6 +506,7 @@ struct GrDrawState {
|
|||
* are not specified the value of this setting has no effect.
|
||||
*/
|
||||
void setVertexEdgeType(VertexEdgeType type) {
|
||||
GrAssert(type >=0 && type < kVertexEdgeTypeCnt);
|
||||
fVertexEdgeType = type;
|
||||
}
|
||||
|
||||
|
|
|
@ -526,21 +526,28 @@ void GrGLProgram::genEdgeCoverage(const GrGLInterface* gl,
|
|||
segments->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
|
||||
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 {
|
||||
GrAssert(GrDrawState::kHairQuad_EdgeType == fProgramDesc.fVertexEdgeType);
|
||||
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
|
||||
segments->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
|
||||
segments->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
|
||||
segments->fFSCode.appendf("\tfloat dfdx = 2.0*%s.x*duvdx.x - duvdx.y;\n", fsName);
|
||||
segments->fFSCode.appendf("\tfloat dfdy = 2.0*%s.x*duvdy.x - duvdy.y;\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);
|
||||
segments->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / (dfdx*dfdx + dfdy*dfdy));\n");
|
||||
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");
|
||||
}
|
||||
if (gl->supportsES2()) {
|
||||
segments->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
|
||||
}
|
||||
}
|
||||
segments->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
*coverageVar = "edgeAlpha";
|
||||
} else {
|
||||
coverageVar->reset();
|
||||
|
|
|
@ -219,9 +219,7 @@ bool GrGpuGLShaders::programUnitTest() {
|
|||
if (vertexEdgeAA) {
|
||||
pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
|
||||
if (this->getCaps().fShaderDerivativeSupport) {
|
||||
pdesc.fVertexEdgeType = random_bool(&random) ?
|
||||
GrDrawState::kHairQuad_EdgeType :
|
||||
GrDrawState::kHairLine_EdgeType;
|
||||
pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
|
||||
} else {
|
||||
pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
|
||||
#include "GrPathUtils.h"
|
||||
|
||||
#include "GrPoint.h"
|
||||
#include "SkGeometry.h"
|
||||
|
||||
GrScalar GrPathUtils::scaleToleranceToSrc(GrScalar devTol,
|
||||
const GrMatrix& viewM,
|
||||
|
@ -186,3 +186,107 @@ int GrPathUtils::worstCasePointCount(const GrPath& path, int* subpaths,
|
|||
}
|
||||
return pointCount;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// The matrix computed for quadDesignSpaceToUVCoordsMatrix should never really
|
||||
// have perspective and we really want to avoid perspective matrix muls.
|
||||
// However, the first two entries of the perspective row may be really close to
|
||||
// 0 and the third may not be 1 due to a scale on the entire matrix.
|
||||
inline void fixup_matrix(GrMatrix* mat) {
|
||||
GR_STATIC_ASSERT(SK_SCALAR_IS_FLOAT);
|
||||
static const GrScalar gTOL = 1.f / 100.f;
|
||||
GrAssert(GrScalarAbs(mat->get(SkMatrix::kMPersp0)) < gTOL);
|
||||
GrAssert(GrScalarAbs(mat->get(SkMatrix::kMPersp1)) < gTOL);
|
||||
float m33 = mat->get(SkMatrix::kMPersp2);
|
||||
if (1.f != m33) {
|
||||
m33 = 1.f / m33;
|
||||
mat->setAll(m33 * mat->get(SkMatrix::kMScaleX),
|
||||
m33 * mat->get(SkMatrix::kMSkewX),
|
||||
m33 * mat->get(SkMatrix::kMTransX),
|
||||
m33 * mat->get(SkMatrix::kMSkewY),
|
||||
m33 * mat->get(SkMatrix::kMScaleY),
|
||||
m33 * mat->get(SkMatrix::kMTransY),
|
||||
0.f, 0.f, 1.f);
|
||||
} else {
|
||||
mat->setPerspX(0);
|
||||
mat->setPerspY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute a matrix that goes from the 2d space coordinates to UV space where
|
||||
// u^2-v = 0 specifies the quad.
|
||||
void GrPathUtils::quadDesignSpaceToUVCoordsMatrix(const SkPoint qPts[3],
|
||||
GrMatrix* matrix) {
|
||||
// can't make this static, no cons :(
|
||||
SkMatrix UVpts;
|
||||
GR_STATIC_ASSERT(SK_SCALAR_IS_FLOAT);
|
||||
UVpts.setAll(0, 0.5f, 1.f,
|
||||
0, 0, 1.f,
|
||||
1.f, 1.f, 1.f);
|
||||
matrix->setAll(qPts[0].fX, qPts[1].fX, qPts[2].fX,
|
||||
qPts[0].fY, qPts[1].fY, qPts[2].fY,
|
||||
1.f, 1.f, 1.f);
|
||||
matrix->invert(matrix);
|
||||
matrix->postConcat(UVpts);
|
||||
fixup_matrix(matrix);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void convert_noninflect_cubic_to_quads(const SkPoint p[4],
|
||||
SkScalar tolScale,
|
||||
SkTArray<SkPoint, true>* quads,
|
||||
int sublevel = 0) {
|
||||
SkVector ab = p[1];
|
||||
ab -= p[0];
|
||||
SkVector dc = p[2];
|
||||
dc -= p[3];
|
||||
|
||||
static const SkScalar gLengthScale = 3 * SK_Scalar1 / 2;
|
||||
// base tolerance is 2 pixels in dev coords.
|
||||
const SkScalar distanceSqdTol = SkScalarMul(tolScale, 1 * SK_Scalar1);
|
||||
static const int kMaxSubdivs = 10;
|
||||
|
||||
ab.scale(gLengthScale);
|
||||
dc.scale(gLengthScale);
|
||||
|
||||
SkVector c0 = p[0];
|
||||
c0 += ab;
|
||||
SkVector c1 = p[3];
|
||||
c1 += dc;
|
||||
|
||||
SkScalar dSqd = c0.distanceToSqd(c1);
|
||||
if (sublevel > kMaxSubdivs || dSqd <= distanceSqdTol) {
|
||||
SkPoint cAvg = c0;
|
||||
cAvg += c1;
|
||||
cAvg.scale(SK_ScalarHalf);
|
||||
|
||||
SkPoint* pts = quads->push_back_n(3);
|
||||
pts[0] = p[0];
|
||||
pts[1] = cAvg;
|
||||
pts[2] = p[3];
|
||||
|
||||
return;
|
||||
} else {
|
||||
SkPoint choppedPts[7];
|
||||
SkChopCubicAtHalf(p, choppedPts);
|
||||
convert_noninflect_cubic_to_quads(choppedPts + 0, tolScale,
|
||||
quads, sublevel + 1);
|
||||
convert_noninflect_cubic_to_quads(choppedPts + 3, tolScale,
|
||||
quads, sublevel + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GrPathUtils::convertCubicToQuads(const GrPoint p[4],
|
||||
SkScalar tolScale,
|
||||
SkTArray<SkPoint, true>* quads) {
|
||||
SkPoint chopped[10];
|
||||
int count = SkChopCubicAtInflections(p, chopped);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkPoint* cubic = chopped + 3*i;
|
||||
convert_noninflect_cubic_to_quads(cubic, tolScale, quads);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "GrMatrix.h"
|
||||
#include "GrPath.h"
|
||||
#include "SkTArray.h"
|
||||
|
||||
/**
|
||||
* Utilities for evaluating paths.
|
||||
|
@ -45,6 +46,16 @@ namespace GrPathUtils {
|
|||
GrScalar tolSqd,
|
||||
GrPoint** points,
|
||||
uint32_t pointsLeft);
|
||||
|
||||
// Compute a matrix that goes from the 2d space coordinates to UV space
|
||||
// where u^2-v = 0 specifies the quad.
|
||||
void quadDesignSpaceToUVCoordsMatrix(const GrPoint qPts[3],
|
||||
GrMatrix* matrix);
|
||||
// Converts a cubic into a sequence of quads. If working in device space
|
||||
// use tolScale = 1, otherwise set based on stretchiness of the matrix. The
|
||||
// result is sets of 3 points in quads (TODO: share endpoints in returned
|
||||
// array)
|
||||
void convertCubicToQuads(const GrPoint p[4],
|
||||
SkScalar tolScale,
|
||||
SkTArray<SkPoint, true>* quads);
|
||||
};
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче